Migration: start adding support for assignment of function types.
So far we only handle zero-parameter non-generic functions. Support
for positional parameters, named parameters, and type parameters will
be added in future CLs.
Change-Id: I5a5907ba595da40352193e0193f908bca4d1bf1c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/106040
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/nnbd_migration/lib/src/graph_builder.dart b/pkg/nnbd_migration/lib/src/graph_builder.dart
index 96097494..aee7dcf 100644
--- a/pkg/nnbd_migration/lib/src/graph_builder.dart
+++ b/pkg/nnbd_migration/lib/src/graph_builder.dart
@@ -686,7 +686,8 @@
DecoratedType visitSimpleIdentifier(SimpleIdentifier node) {
var staticElement = node.staticElement;
if (staticElement is ParameterElement ||
- staticElement is LocalVariableElement) {
+ staticElement is LocalVariableElement ||
+ staticElement is FunctionElement) {
return getOrComputeElementType(staticElement);
} else if (staticElement is PropertyAccessorElement) {
var elementType = getOrComputeElementType(staticElement);
@@ -804,6 +805,23 @@
sourceType.typeArguments[i], expressionChecks,
hard: false);
}
+ } else if (sourceType.type is FunctionType &&
+ destinationType.type is FunctionType) {
+ _checkAssignment(
+ destinationType.returnType, sourceType.returnType, expressionChecks,
+ hard: hard);
+ if (sourceType.typeArguments.isNotEmpty ||
+ destinationType.typeArguments.isNotEmpty) {
+ throw UnimplementedError('TODO(paulberry)');
+ }
+ if (sourceType.positionalParameters.isNotEmpty ||
+ destinationType.positionalParameters.isNotEmpty) {
+ throw UnimplementedError('TODO(paulberry)');
+ }
+ if (sourceType.namedParameters.isNotEmpty ||
+ destinationType.namedParameters.isNotEmpty) {
+ throw UnimplementedError('TODO(paulberry)');
+ }
} else if (destinationType.type.isDynamic || sourceType.type.isDynamic) {
// ok; nothing further to do.
} else {
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 92d776d..41dd341 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -332,6 +332,24 @@
await _checkSingleFileChanges(content, expected);
}
+ test_data_flow_function_return_type() async {
+ var content = '''
+int Function() f(int Function() x) => x;
+int g() => null;
+main() {
+ f(g);
+}
+''';
+ var expected = '''
+int? Function() f(int? Function() x) => x;
+int? g() => null;
+main() {
+ f(g);
+}
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
test_data_flow_generic_contravariant_inward() async {
var content = '''
class C<T> {
diff --git a/pkg/nnbd_migration/test/graph_builder_test.dart b/pkg/nnbd_migration/test/graph_builder_test.dart
index 9d6d8b7..3bd2a82 100644
--- a/pkg/nnbd_migration/test/graph_builder_test.dart
+++ b/pkg/nnbd_migration/test/graph_builder_test.dart
@@ -1450,6 +1450,15 @@
assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true));
}
+ test_return_function_type_simple() async {
+ await analyze('''
+int/*1*/ Function() f(int/*2*/ Function() x) => x;
+''');
+ var int1 = decoratedTypeAnnotation('int/*1*/');
+ var int2 = decoratedTypeAnnotation('int/*2*/');
+ assertEdge(int2.node, int1.node, hard: true);
+ }
+
test_return_implicit_null() async {
verifyNoTestUnitErrors = false;
await analyze('''
@@ -1646,6 +1655,19 @@
assertEdge(always, decoratedTypeAnnotation('String>{').node, hard: false);
}
+ test_simpleIdentifier_function() async {
+ await analyze('''
+int f() => null;
+main() {
+ int Function() g = f;
+}
+''');
+
+ assertEdge(decoratedTypeAnnotation('int f').node,
+ decoratedTypeAnnotation('int Function').node,
+ hard: false);
+ }
+
test_simpleIdentifier_local() async {
await analyze('''
main() {