Resynthesize typedef types properly from kernel.
I broke this functionality when I refactored FunctionTypeImpl into
lazy and strict variants; this CL restores it and simplifies it.
This CL also adds a new method to the analyzer API:
FunctionTypeAliasElement.instantiate(), to allow a client to supply
type arguments to a typedef (as one would at a site where the typedef
is used), to produce a type. Putting the method in
FunctionTypeAliasElement helps move us toward an API that
distinguishes type "constructors" from types (a generic typedef
defines not just one type but a family of types; to obtain a type one
must instantiate the typedef by supplying type arguments).
Change-Id: I722db2befe2d54fd53d625ddba0dec856a555a7b
Reviewed-on: https://dart-review.googlesource.com/62282
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 60afc67..62593e5 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1369,6 +1369,17 @@
@override
TypeAlias computeNode();
+
+ /// Produces the function type resulting from instantiating this typedef with
+ /// the given type arguments.
+ ///
+ /// Note that for a generic typedef, this instantiates the typedef, not the
+ /// generic function type associated with it. So, for example, if the typedef
+ /// is:
+ /// typedef F<T> = void Function<U>(T, U);
+ /// then a single type argument should be provided, and it will be substituted
+ /// for T.
+ FunctionType instantiate(List<DartType> argumentTypes);
}
/**
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index fc04719..ae458d7 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -5656,6 +5656,15 @@
return null;
}
+ @override
+ FunctionType instantiate(List<DartType> argumentTypes) {
+ if (argumentTypes.length != typeParameters.length) {
+ throw new ArgumentError('Wrong number of type arguments supplied');
+ }
+ if (typeParameters.isEmpty) return type;
+ return typeAfterSubstitution(argumentTypes);
+ }
+
/**
* Return the type of the function defined by this typedef after substituting
* the given [typeArguments] for the type parameters defined for this typedef
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index c3a659d..9695ed3c 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -693,6 +693,10 @@
@override
FunctionTypeAlias computeNode() => actualElement.computeNode();
+
+ @override
+ FunctionType instantiate(List<DartType> argumentTypes) =>
+ actualElement.instantiate(argumentTypes);
}
/**
@@ -732,6 +736,10 @@
@override
FunctionTypeAlias computeNode() => actualElement.computeNode();
+
+ @override
+ FunctionType instantiate(List<DartType> argumentTypes) =>
+ actualElement.instantiate(argumentTypes);
}
/**
diff --git a/pkg/analyzer/lib/src/fasta/resolution_applier.dart b/pkg/analyzer/lib/src/fasta/resolution_applier.dart
index 6e81aec..8f85c98 100644
--- a/pkg/analyzer/lib/src/fasta/resolution_applier.dart
+++ b/pkg/analyzer/lib/src/fasta/resolution_applier.dart
@@ -361,7 +361,7 @@
node.staticInvokeType = invokeType;
List<DartType> typeArguments = data.argumentTypes;
- if (node.typeArguments != null && typeArguments is TypeArgumentsDartType) {
+ if (node.typeArguments != null && typeArguments != null) {
_applyTypeArgumentsToList(
_enclosingLibraryElement,
new TypeArgumentsDartType(typeArguments),
diff --git a/pkg/analyzer/lib/src/kernel/resynthesize.dart b/pkg/analyzer/lib/src/kernel/resynthesize.dart
index 876f47d..a370739 100644
--- a/pkg/analyzer/lib/src/kernel/resynthesize.dart
+++ b/pkg/analyzer/lib/src/kernel/resynthesize.dart
@@ -260,7 +260,8 @@
FunctionType _getFunctionType(
ElementImpl context, kernel.FunctionType kernelType) {
if (kernelType.typedef != null) {
- return _getTypedefType(context, kernelType);
+ var translatedType = _getTypedefType(context, kernelType);
+ if (translatedType != null) return translatedType;
}
var element = new FunctionElementImpl('', -1);
@@ -329,51 +330,35 @@
GenericTypeAliasElementImpl typedefElement =
getElementFromCanonicalName(typedef.canonicalName);
- GenericFunctionTypeElementImpl functionElement = typedefElement.function;
kernel.FunctionType typedefType = typedef.type;
- var kernelTypeParameters = typedef.typeParameters.toList();
- kernelTypeParameters.addAll(typedefType.typeParameters);
- // If no type parameters, the raw type of the element will do.
- FunctionTypeImpl rawType = functionElement.type;
- if (kernelTypeParameters.isEmpty) {
- return rawType;
+ if (kernelType.typeParameters.length != typedefType.typeParameters.length) {
+ // Type parameters don't match; just resynthesize as a synthetic function
+ // type.
+ return null;
}
- // Compute type arguments for kernel type parameters.
- var kernelMap = kernel.unifyTypes(typedefType.withoutTypeParameters,
- kernelType.withoutTypeParameters, kernelTypeParameters.toSet());
-
- // Prepare Analyzer type parameters, in the same order as kernel ones.
- var astTypeParameters = typedefElement.typeParameters.toList();
- astTypeParameters.addAll(functionElement.typeParameters);
+ // In the general case imagine the typedef is:
+ // typedef F<T, U> = ... Function<V, W>(...);
+ // And kernelType is:
+ // ... Function<X, Y>(...);
+ // So the outer type parameters of the typedef have been instantiated (or
+ // there were none); the inner type parameters have not been instantiated
+ // (or there were none).
+ //
+ // Now we have to figure out what substitution was used to instantiate
+ // the typedef, since the kernel doesn't track that information.
+ var substitution = kernel.unifyTypes(
+ typedefType, kernelType, typedef.typeParameters.toSet());
// Convert kernel type arguments into Analyzer types.
- int length = astTypeParameters.length;
- var usedTypeParameters = <TypeParameterElement>[];
- var usedTypeArguments = <DartType>[];
- for (var i = 0; i < length; i++) {
- var kernelParameter = kernelTypeParameters[i];
- var kernelArgument = kernelMap[kernelParameter];
- if (kernelArgument == null ||
- kernelArgument is kernel.TypeParameterType &&
- kernelArgument.parameter.parent == null) {
- continue;
- }
- TypeParameterElement astParameter = astTypeParameters[i];
- DartType astArgument = getType(context, kernelArgument);
- usedTypeParameters.add(astParameter);
- usedTypeArguments.add(astArgument);
- }
-
- if (usedTypeParameters.isEmpty) {
- return rawType;
- }
-
- // Replace Analyzer type parameters with type arguments.
- throw new UnimplementedError(
- 'TODO(paulberry): resynthesize generic typedef');
+ var typeArguments = typedef.typeParameters
+ .map((t) => substitution.containsKey(t)
+ ? getType(context, substitution[t])
+ : _typeProvider.nullType)
+ .toList();
+ return typedefElement.instantiate(typeArguments);
}
/// Return the [TypeParameterElement] for the given [kernelTypeParameter].
diff --git a/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart b/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
index 122b4bb..f7ef2eb 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
@@ -48,13 +48,6 @@
@override
@failingTest
- test_argumentTypeNotAssignable_invocation_typedef_generic() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_argumentTypeNotAssignable_invocation_typedef_generic();
- }
-
- @override
- @failingTest
@FastaProblem('https://github.com/dart-lang/sdk/issues/31604')
test_commentReference_beforeConstructor() async {
return super.test_commentReference_beforeConstructor();
@@ -214,57 +207,6 @@
return super.test_functionTypeAlias_scope_signature();
}
- @override
- @failingTest
- test_genericTypeAlias_castsAndTypeChecks_hasTypeParameters() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_genericTypeAlias_castsAndTypeChecks_hasTypeParameters();
- }
-
- @override
- @failingTest
- test_genericTypeAlias_castsAndTypeChecks_noTypeParameters() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_genericTypeAlias_castsAndTypeChecks_noTypeParameters();
- }
-
- @override
- @failingTest
- test_genericTypeAlias_fieldAndReturnType_noTypeParameters() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_genericTypeAlias_fieldAndReturnType_noTypeParameters();
- }
-
- @override
- @failingTest
- test_genericTypeAlias_fieldAndReturnType_typeParameters_arguments() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super
- .test_genericTypeAlias_fieldAndReturnType_typeParameters_arguments();
- }
-
- @override
- @failingTest
- test_genericTypeAlias_fieldAndReturnType_typeParameters_noArguments() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super
- .test_genericTypeAlias_fieldAndReturnType_typeParameters_noArguments();
- }
-
- @override
- @failingTest
- test_genericTypeAlias_noTypeParameters() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_genericTypeAlias_noTypeParameters();
- }
-
- @override
- @failingTest
- test_genericTypeAlias_typeParameters() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_genericTypeAlias_typeParameters();
- }
-
@override // passes with kernel
test_infer_mixin() => super.test_infer_mixin();
@@ -322,13 +264,6 @@
@override
@failingTest
- test_invocationOfNonFunction_functionTypeTypeParameter() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_invocationOfNonFunction_functionTypeTypeParameter();
- }
-
- @override
- @failingTest
@FastaProblem('https://github.com/dart-lang/sdk/issues/31758')
test_invocationOfNonFunction_Object() async {
return super.test_invocationOfNonFunction_Object();
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_kernel_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_kernel_test.dart
index 9d14b39..a493d63 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_kernel_test.dart
@@ -64,13 +64,6 @@
@override
@failingTest
- test_bug21912() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_bug21912();
- }
-
- @override
- @failingTest
test_expectedOneListTypeArgument() async {
// Bad state: Found 1 argument types for 2 type arguments
await super.test_expectedOneListTypeArgument();
diff --git a/pkg/analyzer/test/generated/strong_mode_kernel_test.dart b/pkg/analyzer/test/generated/strong_mode_kernel_test.dart
index 0e94294..2981fd6 100644
--- a/pkg/analyzer/test/generated/strong_mode_kernel_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_kernel_test.dart
@@ -65,13 +65,6 @@
@override
@failingTest
- test_constrainedByBounds4() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_constrainedByBounds4();
- }
-
- @override
- @failingTest
test_constrainedByBounds5() async {
// Bad state: Expected a type for 4 at 119; got one for kernel offset 118
await super.test_constrainedByBounds5();
@@ -107,41 +100,6 @@
@override
@failingTest
- test_functionDeclaration_body_propagation() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_functionDeclaration_body_propagation();
- }
-
- @override
- @failingTest
- test_functionLiteral_assignment_typedArguments() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_functionLiteral_assignment_typedArguments();
- }
-
- @override
- @failingTest
- test_functionLiteral_assignment_unTypedArguments() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_functionLiteral_assignment_unTypedArguments();
- }
-
- @override
- @failingTest
- test_functionLiteral_body_propagation() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_functionLiteral_body_propagation();
- }
-
- @override
- @failingTest
- test_functionLiteral_unTypedArgument_propagation() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_functionLiteral_unTypedArgument_propagation();
- }
-
- @override
- @failingTest
test_futureOr_downwards8() async {
// type 'BottomTypeImpl' is not a subtype of type 'InterfaceType' in type cast where
await super.test_futureOr_downwards8();
@@ -273,13 +231,6 @@
@override
@failingTest
- test_partialTypes1() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_partialTypes1();
- }
-
- @override
- @failingTest
test_pinning_multipleConstraints1() async {
// Expected 1 errors of type StrongModeCode.STRONG_MODE_INVALID_CAST_LITERAL, found 0
await super.test_pinning_multipleConstraints1();
@@ -294,34 +245,6 @@
@override
@failingTest
- test_pinning_multipleConstraints_contravariant1() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_pinning_multipleConstraints_contravariant1();
- }
-
- @override
- @failingTest
- test_pinning_multipleConstraints_contravariant2() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_pinning_multipleConstraints_contravariant2();
- }
-
- @override
- @failingTest
- test_pinning_multipleConstraints_contravariant3() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_pinning_multipleConstraints_contravariant3();
- }
-
- @override
- @failingTest
- test_pinning_multipleConstraints_contravariant4() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_pinning_multipleConstraints_contravariant4();
- }
-
- @override
- @failingTest
test_redirectedConstructor_named() {
// Expected: 'A<T2, U2>'; Actual: 'A<T, U>'
return super.test_redirectedConstructor_named();
@@ -342,48 +265,6 @@
// TODO(brianwilkerson) Figure out why this test is flaky.
fail('Flaky test');
}
-
- @override
- @failingTest
- test_returnType_variance1() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_returnType_variance1();
- }
-
- @override
- @failingTest
- test_returnType_variance2() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_returnType_variance2();
- }
-
- @override
- @failingTest
- test_returnType_variance3() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_returnType_variance3();
- }
-
- @override
- @failingTest
- test_returnType_variance4() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_returnType_variance4();
- }
-
- @override
- @failingTest
- test_returnType_variance5() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_returnType_variance5();
- }
-
- @override
- @failingTest
- test_returnType_variance6() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_returnType_variance6();
- }
}
@reflectiveTest
@@ -413,13 +294,6 @@
@override
@failingTest
- test_genericFunction_typedef() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_genericFunction_typedef();
- }
-
- @override
- @failingTest
test_genericMethod_explicitTypeParams() async {
// Bad state: Found 2 argument types for 1 type arguments
await super.test_genericMethod_explicitTypeParams();
@@ -573,9 +447,9 @@
@override
@failingTest
- test_instantiateToBounds_class_error_typedef() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_instantiateToBounds_class_error_typedef();
+ test_inferClosureType_parameters() {
+ // See dartbug.com/33641
+ return super.test_inferClosureType_parameters();
}
@override
@@ -653,13 +527,6 @@
@override
@failingTest
- test_objectMethodOnFunctions_Typedef() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super.test_objectMethodOnFunctions_Typedef();
- }
-
- @override
- @failingTest
test_returnOfInvalidType_object_void() async {
await super.test_returnOfInvalidType_object_void();
}
@@ -697,12 +564,4 @@
@override
bool get useCFE => true;
-
- @override
- @failingTest
- test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef() {
- // UnimplementedError: TODO(paulberry): resynthesize generic typedef
- return super
- .test_inconsistentMethodInheritance_inferFunctionTypeFromTypedef();
- }
}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_kernel_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_kernel_test.dart
index 2422f69..96d8327 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_kernel_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_kernel_test.dart
@@ -63,14 +63,6 @@
@override
@failingTest
@potentialAnalyzerProblem
- test_functionExpressionInvocation() {
- // TODO(paulberry): broken because of in-progress FunctionTypeImpl rework
- return super.test_functionExpressionInvocation();
- }
-
- @override
- @failingTest
- @potentialAnalyzerProblem
test_instanceCreation_prefixed() {
// TODO(paulberry): broken because prefixes are not working properly
return super.test_instanceCreation_prefixed();
@@ -93,14 +85,6 @@
// parameters from the kernel representation.
return super.test_local_function_generic();
}
-
- @override
- @failingTest
- @potentialAnalyzerProblem
- test_type_functionTypeAlias() {
- // TODO(paulberry): broken because of in-progress FunctionTypeImpl rework
- return super.test_type_functionTypeAlias();
- }
}
/// Tests marked with this annotation fail because of a Fasta problem.
diff --git a/pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart b/pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart
index 5f08aa7..b23f4b7 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_kernel_test.dart
@@ -147,6 +147,20 @@
test_const_constructor_inferred_args() =>
super.test_const_constructor_inferred_args();
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_const_reference_type_functionType() {
+ return super.test_const_reference_type_functionType();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_const_topLevel_typedList_typedefArgument() {
+ return super.test_const_topLevel_typedList_typedefArgument();
+ }
+
@failingTest
@FastaProblem('https://github.com/dart-lang/sdk/issues/30258')
test_constructor_redirected_factory_named_generic() async {
@@ -183,6 +197,13 @@
await super.test_constructor_redirected_factory_unnamed_prefixed_generic();
}
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_executable_parameter_type_typedef() {
+ return super.test_executable_parameter_type_typedef();
+ }
+
@failingTest
@notForDart2
test_export_configurations_useFirst() async {
@@ -251,10 +272,25 @@
await super.test_import_invalidUri_metadata();
}
+ @override
@failingTest
@potentialAnalyzerProblem
- test_instantiateToBounds_functionTypeAlias_simple() async {
- await super.test_instantiateToBounds_functionTypeAlias_simple();
+ test_infer_generic_typedef_simple() {
+ return super.test_infer_generic_typedef_simple();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_inferred_type_is_typedef() {
+ return super.test_inferred_type_is_typedef();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_inferred_type_refers_to_function_typed_param_of_typedef() {
+ return super.test_inferred_type_refers_to_function_typed_param_of_typedef();
}
@override
@@ -367,22 +403,102 @@
await super.test_type_inference_based_on_loadLibrary();
}
+ @override
@failingTest
@potentialAnalyzerProblem
- test_type_reference_to_typedef_with_type_arguments() async {
- await super.test_type_reference_to_typedef_with_type_arguments();
+ test_type_reference_lib_to_lib() {
+ return super.test_type_reference_lib_to_lib();
}
+ @override
@failingTest
@potentialAnalyzerProblem
- test_type_reference_to_typedef_with_type_arguments_implicit() async {
- await super.test_type_reference_to_typedef_with_type_arguments_implicit();
+ test_type_reference_lib_to_part() {
+ return super.test_type_reference_lib_to_part();
}
+ @override
@failingTest
- @FastaProblem('https://github.com/dart-lang/sdk/issues/31711')
- test_typedef_generic_asFieldType() async {
- await super.test_typedef_generic_asFieldType();
+ @potentialAnalyzerProblem
+ test_type_reference_part_to_lib() {
+ return super.test_type_reference_part_to_lib();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_part_to_other_part() {
+ return super.test_type_reference_part_to_other_part();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_part_to_part() {
+ return super.test_type_reference_part_to_part();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import() {
+ return super.test_type_reference_to_import();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_export() {
+ return super.test_type_reference_to_import_export();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_export_export() {
+ return super.test_type_reference_to_import_export_export();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_export_export_in_subdirs() {
+ return super.test_type_reference_to_import_export_export_in_subdirs();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_export_in_subdirs() {
+ return super.test_type_reference_to_import_export_in_subdirs();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_part() {
+ return super.test_type_reference_to_import_part();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_part_in_subdir() {
+ return super.test_type_reference_to_import_part_in_subdir();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_import_relative() {
+ return super.test_type_reference_to_import_relative();
+ }
+
+ @override
+ @failingTest
+ @potentialAnalyzerProblem
+ test_type_reference_to_typedef() {
+ return super.test_type_reference_to_typedef();
}
@failingTest