Migration: preliminary support for interface types without type parameters.

I'll build on this in future CLs to address more complex cases, where
the type is instantiated to a bound.

Fixes #37213.

Change-Id: I1e23c5599557ef17177483222f15b1a7985b9ca8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105726
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 88991e5..51548fd 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -153,9 +153,13 @@
     var namedParameters = const <String, DecoratedType>{};
     if (type is InterfaceType && type.typeParameters.isNotEmpty) {
       if (node is TypeName) {
-        assert(node.typeArguments != null);
-        typeArguments =
-            node.typeArguments.arguments.map((t) => t.accept(this)).toList();
+        if (node.typeArguments == null) {
+          typeArguments =
+              type.typeArguments.map(_decorateImplicitTypeArgument).toList();
+        } else {
+          typeArguments =
+              node.typeArguments.arguments.map((t) => t.accept(this)).toList();
+        }
       } else {
         assert(false); // TODO(paulberry): is this possible?
       }
@@ -227,6 +231,16 @@
     return _NullabilityComment.none;
   }
 
+  /// Creates a DecoratedType corresponding to [type], with fresh nullability
+  /// nodes everywhere that don't correspond to any source location.  These
+  /// nodes can later be unioned with other nodes.
+  DecoratedType _decorateImplicitTypeArgument(DartType type) {
+    if (type.isDynamic) {
+      return DecoratedType(type, _graph.always);
+    }
+    throw UnimplementedError('TODO(paulberry): ${type.runtimeType}');
+  }
+
   /// Common handling of function and method declarations.
   void _handleExecutableDeclaration(
       ExecutableElement declaredElement,
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 8f3e7d7..07bb061 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -645,6 +645,18 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_genericType_noTypeArguments() async {
+    var content = '''
+void f(C c) {}
+class C<E> {}
+''';
+    var expected = '''
+void f(C c) {}
+class C<E> {}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_getter_topLevel() async {
     var content = '''
 int get g => 0;
diff --git a/pkg/nnbd_migration/test/migration_visitor_test.dart b/pkg/nnbd_migration/test/migration_visitor_test.dart
index 2edc2a0..0b96814 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test.dart
@@ -1339,6 +1339,19 @@
     expect(decoratedIntType.node, isNot(never));
   }
 
+  test_interfaceType_generic_instantiate_to_dynamic() async {
+    await analyze('''
+void f(List x) {}
+''');
+    var decoratedListType = decoratedTypeAnnotation('List');
+    expect(decoratedFunctionType('f').positionalParameters[0],
+        same(decoratedListType));
+    expect(decoratedListType.node, isNotNull);
+    expect(decoratedListType.node, isNot(never));
+    var decoratedArgType = decoratedListType.typeArguments[0];
+    expect(decoratedArgType.node, same(always));
+  }
+
   test_interfaceType_typeParameter() async {
     await analyze('''
 void f(List<int> x) {}