Skip to content

Commit 77aa5f0

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Migration: Add support for function-typed formal parameters.
Change-Id: Iae4ba1c052e854bc832fdba7a2e2f53635d5033d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107749 Reviewed-by: Dan Rubel <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 326e970 commit 77aa5f0

4 files changed

Lines changed: 289 additions & 14 deletions

File tree

‎pkg/nnbd_migration/lib/src/node_builder.dart‎

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
134134

135135
@override
136136
DecoratedType visitFieldFormalParameter(FieldFormalParameter node) {
137-
return _handleFormalParameter(node.declaredElement, node.metadata,
138-
node.type, node.typeParameters, node.parameters);
137+
return _handleFormalParameter(
138+
node, node.type, node.typeParameters, node.parameters);
139139
}
140140

141141
@override
@@ -159,8 +159,8 @@ class NodeBuilder extends GeneralizingAstVisitor<DecoratedType> {
159159
@override
160160
DecoratedType visitFunctionTypedFormalParameter(
161161
FunctionTypedFormalParameter node) {
162-
return _handleFormalParameter(node.declaredElement, node.metadata,
163-
node.returnType, node.typeParameters, node.parameters);
162+
return _handleFormalParameter(
163+
node, node.returnType, node.typeParameters, node.parameters);
164164
}
165165

166166
@override
@@ -200,8 +200,7 @@ $stackTrace''');
200200

201201
@override
202202
DecoratedType visitSimpleFormalParameter(SimpleFormalParameter node) {
203-
return _handleFormalParameter(
204-
node.declaredElement, node.metadata, node.type, null, null);
203+
return _handleFormalParameter(node, node.type, null, null);
205204
}
206205

207206
@override
@@ -388,18 +387,44 @@ $stackTrace''');
388387
}
389388

390389
DecoratedType _handleFormalParameter(
391-
ParameterElement declaredElement,
392-
NodeList<Annotation> metadata,
390+
FormalParameter node,
393391
TypeAnnotation type,
394392
TypeParameterList typeParameters,
395393
FormalParameterList parameters) {
396-
if (typeParameters != null || parameters != null) {
397-
_unimplemented(parameters, 'FunctionTypedFormalParameter');
394+
var declaredElement = node.declaredElement;
395+
node.metadata?.accept(this);
396+
DecoratedType decoratedType;
397+
if (parameters == null) {
398+
decoratedType = type != null
399+
? type.accept(this)
400+
: DecoratedType.forImplicitType(declaredElement.type, _graph);
401+
} else {
402+
var decoratedReturnType = type == null
403+
? DecoratedType.forImplicitType(DynamicTypeImpl.instance, _graph)
404+
: type.accept(this);
405+
if (typeParameters != null) {
406+
// TODO(paulberry)
407+
_unimplemented(
408+
typeParameters, 'Function-typed parameter with type parameters');
409+
}
410+
var positionalParameters = <DecoratedType>[];
411+
var namedParameters = <String, DecoratedType>{};
412+
var previousPositionalParameters = _positionalParameters;
413+
var previousNamedParameters = _namedParameters;
414+
try {
415+
_positionalParameters = positionalParameters;
416+
_namedParameters = namedParameters;
417+
parameters.accept(this);
418+
} finally {
419+
_positionalParameters = previousPositionalParameters;
420+
_namedParameters = previousNamedParameters;
421+
}
422+
decoratedType = DecoratedTypeAnnotation(declaredElement.type,
423+
NullabilityNode.forTypeAnnotation(node.end), node.end,
424+
returnType: decoratedReturnType,
425+
positionalParameters: positionalParameters,
426+
namedParameters: namedParameters);
398427
}
399-
metadata?.accept(this);
400-
var decoratedType = type != null
401-
? type.accept(this)
402-
: DecoratedType.forImplicitType(declaredElement.type, _graph);
403428
_variables.recordDecoratedElementType(declaredElement, decoratedType);
404429
if (declaredElement.isNamed) {
405430
_namedParameters[declaredElement.name] = decoratedType;

‎pkg/nnbd_migration/test/api_test.dart‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,52 @@ int? test(C c) {
962962
await _checkSingleFileChanges(content, expected);
963963
}
964964

965+
test_function_typed_field_formal_param() async {
966+
var content = '''
967+
class C {
968+
int Function(int) f;
969+
C(int this.f(int i));
970+
}
971+
int g(int i) => i;
972+
int test(int i) => C(g).f(i);
973+
main() {
974+
test(null);
975+
}
976+
''';
977+
var expected = '''
978+
class C {
979+
int? Function(int?) f;
980+
C(int? this.f(int? i));
981+
}
982+
int? g(int? i) => i;
983+
int? test(int? i) => C(g).f(i);
984+
main() {
985+
test(null);
986+
}
987+
''';
988+
await _checkSingleFileChanges(content, expected);
989+
}
990+
991+
test_function_typed_formal_param() async {
992+
var content = '''
993+
int f(int callback(int i), int j) => callback(j);
994+
int g(int i) => i;
995+
int test(int i) => f(g, i);
996+
main() {
997+
test(null);
998+
}
999+
''';
1000+
var expected = '''
1001+
int? f(int? callback(int? i), int? j) => callback(j);
1002+
int? g(int? i) => i;
1003+
int? test(int? i) => f(g, i);
1004+
main() {
1005+
test(null);
1006+
}
1007+
''';
1008+
await _checkSingleFileChanges(content, expected);
1009+
}
1010+
9651011
test_generic_function_type_syntax_inferred_dynamic_return() async {
9661012
var content = '''
9671013
abstract class C {

‎pkg/nnbd_migration/test/edge_builder_test.dart‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,28 @@ class C {
811811
assertUnion(xType.node, decoratedTypeAnnotation('int').node);
812812
}
813813

814+
test_fieldFormalParameter_function_typed() async {
815+
await analyze('''
816+
class C {
817+
int Function(int, {int j}) f;
818+
C(int this.f(int i, {int j}));
819+
}
820+
''');
821+
var ctorParamType = variables
822+
.decoratedElementType(findElement.unnamedConstructor('C'))
823+
.positionalParameters[0];
824+
var fieldType = variables.decoratedElementType(findElement.field('f'));
825+
assertEdge(ctorParamType.node, fieldType.node, hard: true);
826+
assertEdge(ctorParamType.returnType.node, fieldType.returnType.node,
827+
hard: true);
828+
assertEdge(fieldType.positionalParameters[0].node,
829+
ctorParamType.positionalParameters[0].node,
830+
hard: true);
831+
assertEdge(fieldType.namedParameters['j'].node,
832+
ctorParamType.namedParameters['j'].node,
833+
hard: true);
834+
}
835+
814836
test_fieldFormalParameter_typed() async {
815837
await analyze('''
816838
class C {

‎pkg/nnbd_migration/test/node_builder_test.dart‎

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,107 @@ class C {
410410
same(decoratedType));
411411
}
412412

413+
test_fieldFormalParameter_function_namedParameter_typed() async {
414+
await analyze('''
415+
class C {
416+
Object f;
417+
C(void this.f({int i}));
418+
}
419+
''');
420+
var ctor = findElement.unnamedConstructor('C');
421+
var ctorParam = ctor.parameters[0];
422+
var ctorType = variables.decoratedElementType(ctor);
423+
var ctorParamType = variables.decoratedElementType(ctorParam);
424+
expect(ctorType.positionalParameters[0], same(ctorParamType));
425+
expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
426+
expect(ctorParamType.namedParameters['i'],
427+
same(decoratedTypeAnnotation('int')));
428+
}
429+
430+
test_fieldFormalParameter_function_namedParameter_untyped() async {
431+
await analyze('''
432+
class C {
433+
Object f;
434+
C(void this.f({i}));
435+
}
436+
''');
437+
var ctor = findElement.unnamedConstructor('C');
438+
var ctorParam = ctor.parameters[0];
439+
var ctorType = variables.decoratedElementType(ctor);
440+
var ctorParamType = variables.decoratedElementType(ctorParam);
441+
expect(ctorType.positionalParameters[0], same(ctorParamType));
442+
expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
443+
expect(ctorParamType.namedParameters['i'].type.toString(), 'dynamic');
444+
expect(ctorParamType.namedParameters['i'].node, same(always));
445+
}
446+
447+
test_fieldFormalParameter_function_positionalParameter_typed() async {
448+
await analyze('''
449+
class C {
450+
Object f;
451+
C(void this.f(int i));
452+
}
453+
''');
454+
var ctor = findElement.unnamedConstructor('C');
455+
var ctorParam = ctor.parameters[0];
456+
var ctorType = variables.decoratedElementType(ctor);
457+
var ctorParamType = variables.decoratedElementType(ctorParam);
458+
expect(ctorType.positionalParameters[0], same(ctorParamType));
459+
expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
460+
expect(ctorParamType.positionalParameters[0],
461+
same(decoratedTypeAnnotation('int')));
462+
}
463+
464+
test_fieldFormalParameter_function_positionalParameter_untyped() async {
465+
await analyze('''
466+
class C {
467+
Object f;
468+
C(void this.f(i));
469+
}
470+
''');
471+
var ctor = findElement.unnamedConstructor('C');
472+
var ctorParam = ctor.parameters[0];
473+
var ctorType = variables.decoratedElementType(ctor);
474+
var ctorParamType = variables.decoratedElementType(ctorParam);
475+
expect(ctorType.positionalParameters[0], same(ctorParamType));
476+
expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
477+
expect(ctorParamType.positionalParameters[0].type.toString(), 'dynamic');
478+
expect(ctorParamType.positionalParameters[0].node, same(always));
479+
}
480+
481+
test_fieldFormalParameter_function_return_typed() async {
482+
await analyze('''
483+
class C {
484+
Object f;
485+
C(int this.f());
486+
}
487+
''');
488+
var ctor = findElement.unnamedConstructor('C');
489+
var ctorParam = ctor.parameters[0];
490+
var ctorType = variables.decoratedElementType(ctor);
491+
var ctorParamType = variables.decoratedElementType(ctorParam);
492+
expect(ctorType.positionalParameters[0], same(ctorParamType));
493+
expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
494+
expect(ctorParamType.returnType, same(decoratedTypeAnnotation('int')));
495+
}
496+
497+
test_fieldFormalParameter_function_return_untyped() async {
498+
await analyze('''
499+
class C {
500+
Object f;
501+
C(this.f()) {}
502+
}
503+
''');
504+
var ctor = findElement.unnamedConstructor('C');
505+
var ctorParam = ctor.parameters[0];
506+
var ctorType = variables.decoratedElementType(ctor);
507+
var ctorParamType = variables.decoratedElementType(ctorParam);
508+
expect(ctorType.positionalParameters[0], same(ctorParamType));
509+
expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
510+
expect(ctorParamType.returnType.type.toString(), 'dynamic');
511+
expect(ctorParamType.returnType.node, same(always));
512+
}
513+
413514
test_fieldFormalParameter_typed() async {
414515
await analyze('''
415516
class C {
@@ -444,6 +545,87 @@ class C {
444545
// field.
445546
}
446547

548+
test_functionTypedFormalParameter_namedParameter_typed() async {
549+
await analyze('''
550+
void f(void g({int i})) {}
551+
''');
552+
var f = findElement.function('f');
553+
var g = f.parameters[0];
554+
var fType = variables.decoratedElementType(f);
555+
var gType = variables.decoratedElementType(g);
556+
expect(fType.positionalParameters[0], same(gType));
557+
expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
558+
expect(gType.namedParameters['i'], same(decoratedTypeAnnotation('int')));
559+
}
560+
561+
test_functionTypedFormalParameter_namedParameter_untyped() async {
562+
await analyze('''
563+
void f(void g({i})) {}
564+
''');
565+
var f = findElement.function('f');
566+
var g = f.parameters[0];
567+
var fType = variables.decoratedElementType(f);
568+
var gType = variables.decoratedElementType(g);
569+
expect(fType.positionalParameters[0], same(gType));
570+
expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
571+
expect(gType.namedParameters['i'].type.toString(), 'dynamic');
572+
expect(gType.namedParameters['i'].node, same(always));
573+
}
574+
575+
test_functionTypedFormalParameter_positionalParameter_typed() async {
576+
await analyze('''
577+
void f(void g(int i)) {}
578+
''');
579+
var f = findElement.function('f');
580+
var g = f.parameters[0];
581+
var fType = variables.decoratedElementType(f);
582+
var gType = variables.decoratedElementType(g);
583+
expect(fType.positionalParameters[0], same(gType));
584+
expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
585+
expect(gType.positionalParameters[0], same(decoratedTypeAnnotation('int')));
586+
}
587+
588+
test_functionTypedFormalParameter_positionalParameter_untyped() async {
589+
await analyze('''
590+
void f(void g(i)) {}
591+
''');
592+
var f = findElement.function('f');
593+
var g = f.parameters[0];
594+
var fType = variables.decoratedElementType(f);
595+
var gType = variables.decoratedElementType(g);
596+
expect(fType.positionalParameters[0], same(gType));
597+
expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
598+
expect(gType.positionalParameters[0].type.toString(), 'dynamic');
599+
expect(gType.positionalParameters[0].node, same(always));
600+
}
601+
602+
test_functionTypedFormalParameter_return_typed() async {
603+
await analyze('''
604+
void f(int g()) {}
605+
''');
606+
var f = findElement.function('f');
607+
var g = f.parameters[0];
608+
var fType = variables.decoratedElementType(f);
609+
var gType = variables.decoratedElementType(g);
610+
expect(fType.positionalParameters[0], same(gType));
611+
expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
612+
expect(gType.returnType, same(decoratedTypeAnnotation('int')));
613+
}
614+
615+
test_functionTypedFormalParameter_return_untyped() async {
616+
await analyze('''
617+
void f(g()) {}
618+
''');
619+
var f = findElement.function('f');
620+
var g = f.parameters[0];
621+
var fType = variables.decoratedElementType(f);
622+
var gType = variables.decoratedElementType(g);
623+
expect(fType.positionalParameters[0], same(gType));
624+
expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
625+
expect(gType.returnType.type.toString(), 'dynamic');
626+
expect(gType.returnType.node, same(always));
627+
}
628+
447629
test_generic_function_type_syntax_inferred_dynamic_return() async {
448630
await analyze('''
449631
abstract class C {

0 commit comments

Comments
 (0)