Skip to content

Commit 60ee2c0

Browse files
Fix #30858, generic function types not serializable when const.
Previously declaring for instance const lists (or even final lists) of generic function types ie `final x = <void Function()>[]` would throw errors during summarization. The type parameters don't seem correctly stored yet, but that is an edge case. Left a TODO, for now this should go in to prevent the analyzer crash. One thing I changed as well is that `serializeType` assumed it was getting a type name, and `serializeTypeName` accepted types but threw when it didn't get a type name. I flipped the names so that `serializeTypeName` accepts a type name and `serializeType` accepts a type in general and decides whether its a type name or a generic function type to proceed with specialization. Bug: 30858 Change-Id: Id128f8625cbf03bb94d05ff0efdbac3b158e637e Reviewed-on: https://dart-review.googlesource.com/20481 Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]>
1 parent bd6cbd1 commit 60ee2c0

File tree

10 files changed

+172
-89
lines changed

10 files changed

+172
-89
lines changed

pkg/analyzer/lib/src/dart/element/type.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,14 +418,17 @@ class FunctionTypeImpl extends TypeImpl implements FunctionType {
418418
* Initialize a newly created function type that is semantically the same as
419419
* [original], but which has been syntactically renamed with fresh type
420420
* parameters at its outer binding site (if any).
421+
*
422+
* If type formals is empty, this returns the original unless [force] is set
423+
* to [true].
421424
*/
422-
factory FunctionTypeImpl.fresh(FunctionType original) {
425+
factory FunctionTypeImpl.fresh(FunctionType original, {bool force = false}) {
423426
// We build up a substitution for the type parameters,
424427
// {variablesFresh/variables} then apply it.
425428

426429
var originalFormals = original.typeFormals;
427430
var formalCount = originalFormals.length;
428-
if (formalCount == 0) return original;
431+
if (formalCount == 0 && !force) return original;
429432

430433
// Allocate fresh type variables
431434
var typeVars = <DartType>[];

pkg/analyzer/lib/src/summary/format.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,12 @@ class EntityRefBuilder extends Object
23072307
_implicitFunctionTypeIndices ??= <int>[];
23082308

23092309
/**
2310+
* Notice: This will be deprecated. However, its not deprecated yet, as we're
2311+
* keeping it for backwards compatibilty, and marking it deprecated makes it
2312+
* unreadable.
2313+
*
2314+
* TODO(mfairhurst) mark this deprecated, and remove its logic.
2315+
*
23102316
* If this is a reference to a function type implicitly defined by a
23112317
* function-typed parameter, a list of zero-based indices indicating the path
23122318
* from the entity referred to by [reference] to the appropriate type

pkg/analyzer/lib/src/summary/format.fbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,12 @@ table EntityRef {
12151215
entityKind:EntityRefKind (id: 8);
12161216

12171217
/**
1218+
* Notice: This will be deprecated. However, its not deprecated yet, as we're
1219+
* keeping it for backwards compatibilty, and marking it deprecated makes it
1220+
* unreadable.
1221+
*
1222+
* TODO(mfairhurst) mark this deprecated, and remove its logic.
1223+
*
12181224
* If this is a reference to a function type implicitly defined by a
12191225
* function-typed parameter, a list of zero-based indices indicating the path
12201226
* from the entity referred to by [reference] to the appropriate type

pkg/analyzer/lib/src/summary/idl.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,12 @@ abstract class EntityRef extends base.SummaryClass {
405405
EntityRefKind get entityKind;
406406

407407
/**
408+
* Notice: This will be deprecated. However, its not deprecated yet, as we're
409+
* keeping it for backwards compatibilty, and marking it deprecated makes it
410+
* unreadable.
411+
*
412+
* TODO(mfairhurst) mark this deprecated, and remove its logic.
413+
*
408414
* If this is a reference to a function type implicitly defined by a
409415
* function-typed parameter, a list of zero-based indices indicating the path
410416
* from the entity referred to by [reference] to the appropriate type

pkg/analyzer/lib/src/summary/link.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,18 @@ EntityRefBuilder _createLinkedType(
229229
// TODO(paulberry): do I need to store type arguments?
230230
return result;
231231
}
232-
if (element is GenericFunctionTypeElement) {
232+
if (element is GenericFunctionTypeElementForLink) {
233+
// Function types are their own type parameter context
234+
typeParameterContext = element;
233235
result.entityKind = EntityRefKind.genericFunctionType;
234236
result.syntheticReturnType = _createLinkedType(
235237
type.returnType, compilationUnit, typeParameterContext);
236238
result.syntheticParams = type.parameters
237239
.map((ParameterElement param) => _serializeSyntheticParam(
238240
param, compilationUnit, typeParameterContext))
239241
.toList();
242+
_storeTypeArguments(
243+
type.typeArguments, result, compilationUnit, typeParameterContext);
240244
return result;
241245
}
242246
// TODO(paulberry): implement other cases.

pkg/analyzer/lib/src/summary/summarize_ast.dart

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ class _ConstExprSerializer extends AbstractConstExprSerializer {
7474
@override
7575
EntityRefBuilder serializeConstructorRef(DartType type, Identifier typeName,
7676
TypeArgumentList typeArguments, SimpleIdentifier name) {
77-
EntityRefBuilder typeBuilder = serializeType(type, typeName, typeArguments);
77+
EntityRefBuilder typeBuilder =
78+
serializeTypeName(type, typeName, typeArguments);
7879
if (name == null) {
7980
return typeBuilder;
8081
} else {
@@ -143,10 +144,14 @@ class _ConstExprSerializer extends AbstractConstExprSerializer {
143144
}
144145

145146
@override
146-
EntityRefBuilder serializeType(
147+
EntityRefBuilder serializeTypeName(
147148
DartType type, Identifier name, TypeArgumentList arguments) {
148-
return visitor.serializeType(name, arguments);
149+
return visitor.serializeTypeName(name, arguments);
149150
}
151+
152+
@override
153+
EntityRefBuilder serializeGenericFunctionType(GenericFunctionType node) =>
154+
visitor.serializeGenericFunctionType(node);
150155
}
151156

152157
/**
@@ -449,16 +454,15 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
449454
b.typeParameters =
450455
serializeTypeParameters(typeParameters, typeParameterScope);
451456
if (superclass != null) {
452-
b.supertype = serializeTypeName(superclass);
457+
b.supertype = serializeType(superclass);
453458
} else {
454459
b.hasNoSupertype = isCoreLibrary && name == 'Object';
455460
}
456461
if (withClause != null) {
457-
b.mixins = withClause.mixinTypes.map(serializeTypeName).toList();
462+
b.mixins = withClause.mixinTypes.map(serializeType).toList();
458463
}
459464
if (implementsClause != null) {
460-
b.interfaces =
461-
implementsClause.interfaces.map(serializeTypeName).toList();
465+
b.interfaces = implementsClause.interfaces.map(serializeType).toList();
462466
}
463467
if (members != null) {
464468
scopes.add(buildClassMemberScope(name, members));
@@ -624,7 +628,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
624628
if (!isTopLevel) {
625629
b.isStatic = isDeclaredStatic;
626630
}
627-
b.returnType = serializeTypeName(returnType);
631+
b.returnType = serializeType(returnType);
628632
bool isSemanticallyStatic = isTopLevel || isDeclaredStatic;
629633
if (formalParameters != null) {
630634
bool oldMayInheritCovariance = _parametersMayInheritCovariance;
@@ -735,7 +739,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
735739
*/
736740
void serializeFunctionTypedParameterDetails(UnlinkedParamBuilder b,
737741
TypeAnnotation returnType, FormalParameterList parameters) {
738-
EntityRefBuilder serializedReturnType = serializeTypeName(returnType);
742+
EntityRefBuilder serializedReturnType = serializeType(returnType);
739743
if (serializedReturnType != null) {
740744
b.type = serializedReturnType;
741745
}
@@ -759,7 +763,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
759763
serializeTypeParameters(node.typeParameters, typeParameterScope);
760764
b.syntheticReturnType = node.returnType == null
761765
? serializeDynamic()
762-
: serializeTypeName(node.returnType);
766+
: serializeType(node.returnType);
763767
b.syntheticParams = node.parameters.parameters
764768
.map((FormalParameter p) => p.accept(this) as UnlinkedParamBuilder)
765769
.toList();
@@ -866,7 +870,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
866870
* a [EntityRef]. Note that this method does the right thing if the
867871
* name doesn't refer to an entity other than a type (e.g. a class member).
868872
*/
869-
EntityRefBuilder serializeType(
873+
EntityRefBuilder serializeTypeName(
870874
Identifier identifier, TypeArgumentList typeArguments) {
871875
if (identifier == null) {
872876
return null;
@@ -911,8 +915,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
911915
'Unexpected identifier type: ${identifier.runtimeType}');
912916
}
913917
if (typeArguments != null) {
914-
b.typeArguments =
915-
typeArguments.arguments.map(serializeTypeName).toList();
918+
b.typeArguments = typeArguments.arguments.map(serializeType).toList();
916919
}
917920
return b;
918921
}
@@ -924,9 +927,9 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
924927
* a [EntityRef]. Note that this method does the right thing if the
925928
* name doesn't refer to an entity other than a type (e.g. a class member).
926929
*/
927-
EntityRefBuilder serializeTypeName(TypeAnnotation node) {
930+
EntityRefBuilder serializeType(TypeAnnotation node) {
928931
if (node is TypeName) {
929-
return serializeType(node?.name, node?.typeArguments);
932+
return serializeTypeName(node?.name, node?.typeArguments);
930933
} else if (node is GenericFunctionType) {
931934
return serializeGenericFunctionType(node);
932935
} else if (node != null) {
@@ -974,7 +977,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
974977
b.isStatic = isDeclaredStatic;
975978
b.name = variable.name.name;
976979
b.nameOffset = variable.name.offset;
977-
b.type = serializeTypeName(variables.type);
980+
b.type = serializeType(variables.type);
978981
b.documentationComment = serializeDocumentation(documentationComment);
979982
b.annotations = serializeAnnotations(annotations);
980983
b.codeRange = serializeCodeRange(variables.parent);
@@ -1158,7 +1161,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
11581161
if (node.parameters != null) {
11591162
serializeFunctionTypedParameterDetails(b, node.type, node.parameters);
11601163
} else {
1161-
b.type = serializeTypeName(node.type);
1164+
b.type = serializeType(node.type);
11621165
}
11631166
}
11641167
return b;
@@ -1222,7 +1225,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
12221225
b.nameOffset = node.name.offset;
12231226
b.typeParameters =
12241227
serializeTypeParameters(node.typeParameters, typeParameterScope);
1225-
EntityRefBuilder serializedReturnType = serializeTypeName(node.returnType);
1228+
EntityRefBuilder serializedReturnType = serializeType(node.returnType);
12261229
if (serializedReturnType != null) {
12271230
b.returnType = serializedReturnType;
12281231
}
@@ -1345,7 +1348,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
13451348
@override
13461349
UnlinkedParamBuilder visitSimpleFormalParameter(SimpleFormalParameter node) {
13471350
UnlinkedParamBuilder b = serializeParameter(node);
1348-
b.type = serializeTypeName(node.type);
1351+
b.type = serializeType(node.type);
13491352
return b;
13501353
}
13511354

@@ -1361,7 +1364,7 @@ class _SummarizeAstVisitor extends RecursiveAstVisitor {
13611364
b.name = node.name.name;
13621365
b.nameOffset = node.name.offset;
13631366
if (node.bound != null) {
1364-
b.bound = serializeTypeName(node.bound);
1367+
b.bound = serializeType(node.bound);
13651368
}
13661369
b.annotations = serializeAnnotations(node.metadata);
13671370
b.codeRange = serializeCodeRange(node);

pkg/analyzer/lib/src/summary/summarize_const_expr.dart

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,25 @@ abstract class AbstractConstExprSerializer {
198198
* given [name] and [arguments]. The parameter [type] might be `null` if the
199199
* type is not resolved.
200200
*/
201-
EntityRefBuilder serializeType(
201+
EntityRefBuilder serializeTypeName(
202202
DartType type, Identifier name, TypeArgumentList arguments);
203203

204+
/**
205+
* Return [EntityRefBuilder] that corresponds to the [type], which is defined
206+
* using generic function type syntax. These may appear as the type arguments
207+
* of a const list, etc.
208+
*/
209+
EntityRefBuilder serializeGenericFunctionType(GenericFunctionType type);
210+
204211
/**
205212
* Return [EntityRefBuilder] that corresponds to the given [type].
206213
*/
207-
EntityRefBuilder serializeTypeName(TypeAnnotation type) {
214+
EntityRefBuilder serializeType(TypeAnnotation type) {
208215
if (type is TypeName) {
209-
return serializeType(type?.type, type?.name, type?.typeArguments);
216+
return serializeTypeName(type?.type, type?.name, type?.typeArguments);
217+
}
218+
if (type is GenericFunctionType) {
219+
return serializeGenericFunctionType(type);
210220
}
211221
throw new ArgumentError(
212222
'Cannot serialize an instance of ${type.runtimeType}');
@@ -407,12 +417,12 @@ abstract class AbstractConstExprSerializer {
407417
} else if (expr is AsExpression) {
408418
isValidConst = false;
409419
_serialize(expr.expression);
410-
references.add(serializeTypeName(expr.type));
420+
references.add(serializeType(expr.type));
411421
operations.add(UnlinkedExprOperation.typeCast);
412422
} else if (expr is IsExpression) {
413423
isValidConst = false;
414424
_serialize(expr.expression);
415-
references.add(serializeTypeName(expr.type));
425+
references.add(serializeType(expr.type));
416426
operations.add(UnlinkedExprOperation.typeCheck);
417427
} else if (expr is SuperExpression) {
418428
operations.add(UnlinkedExprOperation.pushSuper);
@@ -554,7 +564,7 @@ abstract class AbstractConstExprSerializer {
554564
}
555565
if (expr.typeArguments != null &&
556566
expr.typeArguments.arguments.length == 1) {
557-
references.add(serializeTypeName(expr.typeArguments.arguments[0]));
567+
references.add(serializeType(expr.typeArguments.arguments[0]));
558568
operations.add(UnlinkedExprOperation.makeTypedList);
559569
} else {
560570
operations.add(UnlinkedExprOperation.makeUntypedList);
@@ -573,8 +583,8 @@ abstract class AbstractConstExprSerializer {
573583
}
574584
if (expr.typeArguments != null &&
575585
expr.typeArguments.arguments.length == 2) {
576-
references.add(serializeTypeName(expr.typeArguments.arguments[0]));
577-
references.add(serializeTypeName(expr.typeArguments.arguments[1]));
586+
references.add(serializeType(expr.typeArguments.arguments[0]));
587+
references.add(serializeType(expr.typeArguments.arguments[1]));
578588
operations.add(UnlinkedExprOperation.makeTypedMap);
579589
} else {
580590
operations.add(UnlinkedExprOperation.makeUntypedMap);
@@ -698,7 +708,7 @@ abstract class AbstractConstExprSerializer {
698708
} else {
699709
ints.add(typeArguments.arguments.length);
700710
for (TypeAnnotation type in typeArguments.arguments) {
701-
references.add(serializeTypeName(type));
711+
references.add(serializeType(type));
702712
}
703713
}
704714
}

pkg/analyzer/lib/src/task/strong_mode.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,16 @@ class InstanceMemberInferrer {
169169
parameter, index, overriddenTypes[i].parameters);
170170
DartType type = matchingParameter?.type ?? typeProvider.dynamicType;
171171
if (parameterType == null) {
172-
parameterType = type;
172+
if (type is FunctionType) {
173+
// The resulting parameter's type element has an `enclosingElement` of
174+
// the overridden parameter. Change it to the overriding parameter.
175+
parameterType = new FunctionTypeImpl.fresh(type, force: true);
176+
(parameterType.element as ElementImpl).enclosingElement = parameter;
177+
// TODO(mfairhurst) handle cases where non-functions contain functions
178+
// See test_inferredType_parameter_genericFunctionType_asTypeArgument
179+
} else {
180+
parameterType = type;
181+
}
173182
} else if (parameterType != type) {
174183
if (parameter is ParameterElementForLink) {
175184
parameter.setInferenceError(new TopLevelInferenceErrorBuilder(

pkg/analyzer/test/src/summary/linker_test.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,33 @@ class C extends A<int> {
467467
expect(fType.parameters[0].type.toString(), 'int');
468468
}
469469

470+
@failingTest
471+
void test_inferredType_parameter_genericFunctionType_asTypeArgument() {
472+
var bundle = createPackageBundle('''
473+
class A<T> {
474+
A<R> map<R>(List<R Function(T)> fs) => null;
475+
}
476+
''', path: '/a.dart');
477+
addBundle('/a.ds', bundle);
478+
createLinker('''
479+
import 'a.dart';
480+
class C extends A<int> {
481+
map<R2>(fs) => null;
482+
}
483+
''');
484+
LibraryElementForLink library = linker.getLibrary(linkerInputs.testDartUri);
485+
library.libraryCycleForLink.ensureLinked();
486+
ClassElementForLink_Class c = library.getContainedName('C');
487+
expect(c.methods, hasLength(1));
488+
MethodElementForLink map = c.methods[0];
489+
expect(map.parameters, hasLength(1));
490+
InterfaceType iType = map.parameters[0].type;
491+
expect(iType.typeArguments, hasLength(1));
492+
FunctionType fType = iType.typeArguments[0];
493+
expect(fType.returnType.toString(), 'R2');
494+
expect(fType.parameters[0].type.toString(), 'int');
495+
}
496+
470497
void test_inferredType_staticField_dynamic() {
471498
createLinker('''
472499
dynamic x = null;

0 commit comments

Comments
 (0)