Resolve type names and set nullability for other types.

R=brianwilkerson@google.com, paulberry@google.com

Change-Id: I72965d0072cab7e19453616b8aef88604ff7812d
Reviewed-on: https://dart-review.googlesource.com/c/89080
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 7d7b531..050e255 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -7116,19 +7116,19 @@
       return;
     }
 
-    DartType type = null;
+    TypeImpl type = null;
     if (element == DynamicElementImpl.instance) {
       _setElement(typeName, element);
       type = DynamicTypeImpl.instance;
     } else if (element is FunctionTypeAliasElement) {
       _setElement(typeName, element);
-      type = element.type;
+      type = element.type as TypeImpl;
     } else if (element is TypeParameterElement) {
       _setElement(typeName, element);
-      type = element.type;
+      type = element.type as TypeImpl;
     } else if (element is MultiplyDefinedElement) {
       List<Element> elements = element.conflictingElements;
-      type = _getTypeWhenMultiplyDefined(elements);
+      type = _getTypeWhenMultiplyDefined(elements) as TypeImpl;
     } else {
       // The name does not represent a type.
       RedirectingConstructorKind redirectingConstructorKind;
@@ -7211,6 +7211,10 @@
         type = typeSystem.instantiateToBounds(type);
       }
     }
+
+    var nullability = _getNullability(node.question != null);
+    type = type.withNullability(nullability);
+
     typeName.staticType = type;
     node.type = type;
   }
@@ -7241,6 +7245,22 @@
     return StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS;
   }
 
+  Nullability _getNullability(bool hasQuestion) {
+    Nullability nullability;
+    if (analysisOptions.experimentStatus.non_nullable) {
+      if (hasQuestion) {
+        nullability = Nullability.nullable;
+      } else if (isNonNullableMigrated) {
+        nullability = Nullability.nonNullable;
+      } else {
+        nullability = Nullability.indeterminate;
+      }
+    } else {
+      nullability = Nullability.indeterminate;
+    }
+    return nullability;
+  }
+
   /// Checks if the given [typeName] is the target in a redirected constructor.
   RedirectingConstructorKind _getRedirectingConstructorKind(TypeName typeName) {
     AstNode parent = typeName.parent;
@@ -7417,24 +7437,23 @@
       }
     }
 
+    var parent = node.parent;
+
     Nullability nullability;
-    if (analysisOptions.experimentStatus.non_nullable) {
-      if (node.question != null) {
-        nullability = Nullability.nullable;
-      } else if (isNonNullableMigrated) {
-        nullability = Nullability.nonNullable;
-      } else {
-        nullability = Nullability.indeterminate;
-      }
+    if (parent is ClassTypeAlias ||
+        parent is ExtendsClause ||
+        parent is ImplementsClause ||
+        parent is OnClause ||
+        parent is WithClause) {
+      nullability = Nullability.nonNullable;
     } else {
-      nullability = Nullability.indeterminate;
+      nullability = _getNullability(node.question != null);
     }
 
     var type = InterfaceTypeImpl.explicit(element, typeArguments,
         nullability: nullability);
 
     if (shouldUseWithClauseInferredTypes) {
-      var parent = node.parent;
       if (parent is WithClause && parameterCount != 0) {
         // Get the (possibly inferred) mixin type from the element model.
         var grandParent = parent.parent;
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index 93dd292..e52ece7 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -7509,7 +7509,7 @@
       TypeName typeName = bDeclaration.fields.type;
       SimpleIdentifier typeIdentifier = typeName.name;
       expect(typeIdentifier.staticElement, same(tElement));
-      expect(typeIdentifier.staticType, same(tElement.type));
+      expect(typeIdentifier.staticType, tElement.type);
 
       VariableDeclaration bNode = bDeclaration.fields.variables[0];
       expect(bNode.declaredElement, same(bElement));
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
index b304369..0616164 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -25,6 +25,38 @@
   @override
   bool get typeToStringWithNullability => true;
 
+  test_class_hierarchy() async {
+    addTestFile('''
+class A {}
+
+class X1 extends A {} // 1
+class X2 implements A {} // 2
+class X3 with A {} // 3
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('A {} // 1'), 'A!');
+    assertType(findNode.typeName('A {} // 2'), 'A!');
+    assertType(findNode.typeName('A {} // 3'), 'A!');
+  }
+
+  test_classTypeAlias_hierarchy() async {
+    addTestFile('''
+class A {}
+class B {}
+class C {}
+
+class X = A with B implements C;
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('A with'), 'A!');
+    assertType(findNode.typeName('B implements'), 'B!');
+    assertType(findNode.typeName('C;'), 'C!');
+  }
+
   test_local_parameter_interfaceType() async {
     addTestFile('''
 $_migrated
@@ -54,6 +86,23 @@
     assertType(findNode.typeName('int g'), 'int!');
   }
 
+  @failingTest
+  test_local_variable_genericFunctionType() async {
+    addTestFile('''
+$_migrated
+main() {
+  int? Function(bool, String?)? a;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(
+      findNode.genericFunctionType('Function('),
+      '(bool!, String?) → int??',
+    );
+  }
+
   test_local_variable_interfaceType() async {
     addTestFile('''
 $_migrated
@@ -101,4 +150,71 @@
     assertType(findNode.typeName('int? a'), 'int?');
     assertType(findNode.typeName('int b'), 'int*');
   }
+
+  test_local_variable_typeParameter() async {
+    addTestFile('''
+$_migrated
+
+class A<T> {
+  main(T a) {
+    T? b;
+  }
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('T a'), 'T!');
+    assertType(findNode.typeName('T? b'), 'T?');
+  }
+
+  test_mixin_hierarchy() async {
+    addTestFile('''
+class A {}
+
+mixin X1 on A {} // 1
+mixin X2 implements A {} // 2
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('A {} // 1'), 'A!');
+    assertType(findNode.typeName('A {} // 2'), 'A!');
+  }
+
+  test_typedef_classic() async {
+    addTestFile('''
+$_migrated
+
+typedef int? F(bool a, String? b);
+
+main() {
+  F? a;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(findNode.typeName('F? a'), '(bool!, String?) → int??');
+  }
+
+  @failingTest
+  test_typedef_function() async {
+    addTestFile('''
+$_migrated
+
+typedef F<T> = int? Function(bool, T, T?);
+
+main() {
+  F<String>? a;
+}
+''');
+    await resolveTestFile();
+    assertNoTestErrors();
+
+    assertType(
+      findNode.typeName('F<String>'),
+      '(bool!, String!, String?) → int??',
+    );
+  }
 }