Skip to content

Commit ca25f56

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: add support for type inference of function types.
Change-Id: Ic0ebbc4d412e7273127564089431ebe9058ee790 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107516 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
1 parent a436c06 commit ca25f56

File tree

7 files changed

+398
-24
lines changed

7 files changed

+398
-24
lines changed

pkg/nnbd_migration/lib/src/edge_builder.dart

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType> {
332332
@override
333333
DecoratedType visitConstructorDeclaration(ConstructorDeclaration node) {
334334
_handleExecutableDeclaration(
335+
node,
335336
node.declaredElement,
336337
node.metadata,
337338
null,
@@ -552,7 +553,7 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType> {
552553
if (node.typeParameters != null) {
553554
_unimplemented(node, 'Generic method');
554555
}
555-
_handleExecutableDeclaration(node.declaredElement, node.metadata,
556+
_handleExecutableDeclaration(node, node.declaredElement, node.metadata,
556557
node.returnType, node.parameters, null, node.body, null);
557558
return null;
558559
}
@@ -861,16 +862,17 @@ $stackTrace''');
861862
}
862863

863864
/// Creates the necessary constraint(s) for an assignment from [source] to
864-
/// [destination]. [expressionChecks] tracks checks that might have to be
865-
/// done on the type of an expression. [hard] indicates whether a hard edge
866-
/// should be created.
867-
void _checkAssignment(ExpressionChecks expressionChecks,
865+
/// [destination]. [origin] should be used as the origin for any edges
866+
/// created. [hard] indicates whether a hard edge should be created.
867+
void _checkAssignment(EdgeOrigin origin,
868868
{@required DecoratedType source,
869869
@required DecoratedType destination,
870870
@required bool hard}) {
871-
var edge = _graph.connect(source.node, destination.node, expressionChecks,
871+
var edge = _graph.connect(source.node, destination.node, origin,
872872
guards: _guards, hard: hard);
873-
expressionChecks?.edges?.add(edge);
873+
if (origin is ExpressionChecks) {
874+
origin.edges.add(edge);
875+
}
874876
// TODO(paulberry): generalize this.
875877
if ((_isSimple(source) || destination.type.isObject) &&
876878
_isSimple(destination)) {
@@ -880,14 +882,14 @@ $stackTrace''');
880882
source.type.element == destination.type.element) {
881883
assert(source.typeArguments.length == destination.typeArguments.length);
882884
for (int i = 0; i < source.typeArguments.length; i++) {
883-
_checkAssignment(expressionChecks,
885+
_checkAssignment(origin,
884886
source: source.typeArguments[i],
885887
destination: destination.typeArguments[i],
886888
hard: false);
887889
}
888890
} else if (source.type is FunctionType &&
889891
destination.type is FunctionType) {
890-
_checkAssignment(expressionChecks,
892+
_checkAssignment(origin,
891893
source: source.returnType,
892894
destination: destination.returnType,
893895
hard: hard);
@@ -900,14 +902,14 @@ $stackTrace''');
900902
i < destination.positionalParameters.length;
901903
i++) {
902904
// Note: source and destination are swapped due to contravariance.
903-
_checkAssignment(expressionChecks,
905+
_checkAssignment(origin,
904906
source: destination.positionalParameters[i],
905907
destination: source.positionalParameters[i],
906908
hard: hard);
907909
}
908910
for (var entry in destination.namedParameters.entries) {
909911
// Note: source and destination are swapped due to contravariance.
910-
_checkAssignment(expressionChecks,
912+
_checkAssignment(origin,
911913
source: entry.value,
912914
destination: source.namedParameters[entry.key],
913915
hard: hard);
@@ -971,6 +973,7 @@ $stackTrace''');
971973
}
972974

973975
void _handleExecutableDeclaration(
976+
AstNode node,
974977
ExecutableElement declaredElement,
975978
NodeList<Annotation> metadata,
976979
TypeAnnotation returnType,
@@ -992,6 +995,7 @@ $stackTrace''');
992995
}
993996
if (declaredElement is! ConstructorElement) {
994997
var classElement = declaredElement.enclosingElement as ClassElement;
998+
var origin = InheritanceOrigin(_source, node.offset);
995999
for (var overridden in _inheritanceManager.getOverridden(
9961000
classElement.type,
9971001
Name(classElement.library.source.uri, declaredElement.name)) ??
@@ -1005,11 +1009,61 @@ $stackTrace''');
10051009
var decoratedSupertype = _decoratedClassHierarchy
10061010
.getDecoratedSupertype(classElement, overriddenClass);
10071011
var substitution = decoratedSupertype.asSubstitution;
1008-
_checkAssignment(null,
1009-
source: _currentFunctionType,
1010-
destination:
1011-
decoratedOverriddenFunctionType.substitute(substitution),
1012-
hard: true);
1012+
var overriddenFunctionType =
1013+
decoratedOverriddenFunctionType.substitute(substitution);
1014+
if (returnType == null) {
1015+
_unionDecoratedTypes(_currentFunctionType.returnType,
1016+
overriddenFunctionType.returnType, origin);
1017+
} else {
1018+
_checkAssignment(origin,
1019+
source: _currentFunctionType.returnType,
1020+
destination: overriddenFunctionType.returnType,
1021+
hard: true);
1022+
}
1023+
if (parameters != null) {
1024+
int positionalParameterCount = 0;
1025+
for (var parameter in parameters.parameters) {
1026+
NormalFormalParameter normalParameter;
1027+
if (parameter is NormalFormalParameter) {
1028+
normalParameter = parameter;
1029+
} else {
1030+
normalParameter =
1031+
(parameter as DefaultFormalParameter).parameter;
1032+
}
1033+
DecoratedType currentParameterType;
1034+
DecoratedType overriddenParameterType;
1035+
if (parameter.isNamed) {
1036+
var name = normalParameter.identifier.name;
1037+
currentParameterType =
1038+
_currentFunctionType.namedParameters[name];
1039+
overriddenParameterType =
1040+
overriddenFunctionType.namedParameters[name];
1041+
} else {
1042+
if (positionalParameterCount <
1043+
_currentFunctionType.positionalParameters.length) {
1044+
currentParameterType = _currentFunctionType
1045+
.positionalParameters[positionalParameterCount];
1046+
}
1047+
if (positionalParameterCount <
1048+
overriddenFunctionType.positionalParameters.length) {
1049+
overriddenParameterType = overriddenFunctionType
1050+
.positionalParameters[positionalParameterCount];
1051+
}
1052+
positionalParameterCount++;
1053+
}
1054+
if (overriddenParameterType != null) {
1055+
if (_isUntypedParameter(normalParameter)) {
1056+
_unionDecoratedTypes(
1057+
overriddenParameterType, currentParameterType, origin);
1058+
} else {
1059+
_checkAssignment(origin,
1060+
source: overriddenParameterType,
1061+
destination: currentParameterType,
1062+
hard: true);
1063+
}
1064+
}
1065+
}
1066+
}
10131067
}
10141068
}
10151069
} finally {
@@ -1157,6 +1211,16 @@ $stackTrace''');
11571211
return true;
11581212
}
11591213

1214+
bool _isUntypedParameter(NormalFormalParameter parameter) {
1215+
if (parameter is SimpleFormalParameter) {
1216+
return parameter.type == null;
1217+
} else if (parameter is FieldFormalParameter) {
1218+
return parameter.type == null;
1219+
} else {
1220+
return false;
1221+
}
1222+
}
1223+
11601224
bool _isVariableOrParameterReference(Expression expression) {
11611225
expression = expression.unParenthesized;
11621226
if (expression is SimpleIdentifier) {

pkg/nnbd_migration/lib/src/edge_origin.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ class ImplicitMixinSuperCallOrigin extends EdgeOriginWithLocation {
5757
: super(source, offset);
5858
}
5959

60+
/// Edge origin resulting from an inheritance relationship between two methods.
61+
class InheritanceOrigin extends EdgeOriginWithLocation {
62+
InheritanceOrigin(Source source, int offset) : super(source, offset);
63+
}
64+
6065
/// Edge origin resulting from a class that is instantiated to bounds.
6166
///
6267
/// For example, in the following code snippet:

pkg/nnbd_migration/lib/src/node_builder.dart

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,10 @@ $stackTrace''');
226226

227227
@override
228228
DecoratedType visitSimpleFormalParameter(SimpleFormalParameter node) {
229-
var type = decorateType(node.type, node);
230229
var declaredElement = node.declaredElement;
230+
var type = node.type != null
231+
? node.type.accept(this)
232+
: DecoratedType.forImplicitType(declaredElement.type, _graph);
231233
_variables.recordDecoratedElementType(declaredElement, type);
232234
if (declaredElement.isNamed) {
233235
_namedParameters[declaredElement.name] = type;
@@ -376,33 +378,39 @@ $stackTrace''');
376378
FunctionBody body,
377379
ConstructorName redirectedConstructor,
378380
AstNode enclosingNode) {
381+
var functionType = declaredElement.type;
379382
DecoratedType decoratedReturnType;
380-
if (returnType == null && declaredElement is ConstructorElement) {
383+
if (returnType != null) {
384+
decoratedReturnType = returnType.accept(this);
385+
} else if (declaredElement is ConstructorElement) {
381386
// Constructors have no explicit return type annotation, so use the
382387
// implicit return type.
383388
decoratedReturnType = _createDecoratedTypeForClass(
384389
declaredElement.enclosingElement, parameters.parent);
385390
} else {
386-
decoratedReturnType = decorateType(returnType, enclosingNode);
391+
// Inferred return type.
392+
decoratedReturnType =
393+
DecoratedType.forImplicitType(functionType.returnType, _graph);
387394
}
388395
var previousPositionalParameters = _positionalParameters;
389396
var previousNamedParameters = _namedParameters;
390397
_positionalParameters = [];
391398
_namedParameters = {};
392-
DecoratedType functionType;
399+
DecoratedType decoratedFunctionType;
393400
try {
394401
parameters?.accept(this);
395402
body?.accept(this);
396403
redirectedConstructor?.accept(this);
397-
functionType = DecoratedType(declaredElement.type, _graph.never,
404+
decoratedFunctionType = DecoratedType(functionType, _graph.never,
398405
returnType: decoratedReturnType,
399406
positionalParameters: _positionalParameters,
400407
namedParameters: _namedParameters);
401408
} finally {
402409
_positionalParameters = previousPositionalParameters;
403410
_namedParameters = previousNamedParameters;
404411
}
405-
_variables.recordDecoratedElementType(declaredElement, functionType);
412+
_variables.recordDecoratedElementType(
413+
declaredElement, decoratedFunctionType);
406414
}
407415

408416
void _handleSupertypeClauses(

0 commit comments

Comments
 (0)