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??',
+ );
+ }
}