Add preliminary NNBD support to the summary linker.

Change-Id: I256d66333d9715ed720bd6ea87d21fd00e17635a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101900
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 168e9cf..e5cf09c 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -187,7 +187,10 @@
     CompilationUnitElementInBuildUnit compilationUnit,
     TypeParameterSerializationContext typeParameterContext,
     {int slot}) {
-  EntityRefBuilder result = new EntityRefBuilder(slot: slot);
+  EntityRefBuilder result = new EntityRefBuilder(
+      slot: slot,
+      nullabilitySuffix:
+          encodeNullabilitySuffix((type as TypeImpl).nullabilitySuffix));
   if (type is InterfaceType) {
     ClassElementForLink element = type.element;
     result.reference = compilationUnit.addReference(element);
@@ -1413,11 +1416,12 @@
         return DynamicTypeImpl.instance;
       }
     }
+    DartType result;
     if (entity.paramReference != 0) {
-      return context.typeParameterContext
+      result = context.typeParameterContext
           .getTypeParameterType(entity.paramReference);
     } else if (entity.entityKind == EntityRefKind.genericFunctionType) {
-      return new GenericFunctionTypeElementForLink(
+      result = new GenericFunctionTypeElementForLink(
               this,
               context,
               entity.typeParameters,
@@ -1427,13 +1431,13 @@
     } else if (entity.syntheticReturnType != null) {
       FunctionElementImpl element =
           new FunctionElementForLink_Synthetic(this, context, entity);
-      return element.type;
+      result = element.type;
     } else if (entity.implicitFunctionTypeIndices.isNotEmpty) {
       DartType type = resolveRef(entity.reference).asStaticType;
       for (int index in entity.implicitFunctionTypeIndices) {
         type = (type as FunctionType).parameters[index].type;
       }
-      return type;
+      result = type;
     } else {
       ReferenceableElementForLink element = resolveRef(entity.reference);
       bool implicitTypeArgumentsInUse = false;
@@ -1452,13 +1456,18 @@
         }
       }
 
-      var type = element.buildType(
+      result = element.buildType(
           getTypeArgument, entity.implicitFunctionTypeIndices);
       if (implicitTypeArgumentsInUse) {
-        _typesWithImplicitArguments[type] = true;
+        _typesWithImplicitArguments[result] = true;
       }
-      return type;
     }
+    var nullabilitySuffix = decodeNullabilitySuffix(entity.nullabilitySuffix);
+    var resultAsImpl = result as TypeImpl;
+    if (resultAsImpl.nullabilitySuffix != nullabilitySuffix) {
+      result = resultAsImpl.withNullability(nullabilitySuffix);
+    }
+    return result;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index b364311..62665a9 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -31,6 +31,30 @@
  */
 final _typesWithImplicitTypeArguments = new Expando();
 
+NullabilitySuffix decodeNullabilitySuffix(EntityRefNullabilitySuffix suffix) {
+  switch (suffix) {
+    case EntityRefNullabilitySuffix.none:
+      return NullabilitySuffix.none;
+    case EntityRefNullabilitySuffix.question:
+      return NullabilitySuffix.question;
+    case EntityRefNullabilitySuffix.starOrIrrelevant:
+      return NullabilitySuffix.star;
+  }
+  throw new StateError('Unrecognized nullability suffix');
+}
+
+EntityRefNullabilitySuffix encodeNullabilitySuffix(NullabilitySuffix suffix) {
+  switch (suffix) {
+    case NullabilitySuffix.none:
+      return EntityRefNullabilitySuffix.none;
+    case NullabilitySuffix.question:
+      return EntityRefNullabilitySuffix.question;
+    case NullabilitySuffix.star:
+      return EntityRefNullabilitySuffix.starOrIrrelevant;
+  }
+  throw new StateError('Unrecognized nullability suffix');
+}
+
 /// An instance of [LibraryResynthesizer] is responsible for resynthesizing the
 /// elements in a single library from that library's summary.
 abstract class LibraryResynthesizer {
@@ -1376,7 +1400,7 @@
           getTypeArgument,
           type.implicitFunctionTypeIndices);
     }
-    var nullabilitySuffix = _translateNullabilitySuffix(type.nullabilitySuffix);
+    var nullabilitySuffix = decodeNullabilitySuffix(type.nullabilitySuffix);
     var resultAsImpl = result as TypeImpl;
     if (resultAsImpl.nullabilitySuffix != nullabilitySuffix) {
       result = resultAsImpl.withNullability(nullabilitySuffix);
@@ -1628,19 +1652,6 @@
     return null;
   }
 
-  NullabilitySuffix _translateNullabilitySuffix(
-      EntityRefNullabilitySuffix suffix) {
-    switch (suffix) {
-      case EntityRefNullabilitySuffix.none:
-        return NullabilitySuffix.none;
-      case EntityRefNullabilitySuffix.question:
-        return NullabilitySuffix.question;
-      case EntityRefNullabilitySuffix.starOrIrrelevant:
-        return NullabilitySuffix.star;
-    }
-    throw new StateError('Unrecognized nullability suffix');
-  }
-
   /**
    * If the given [kind] is a top-level or class member property accessor, and
    * the given [name] does not end with `=`, i.e. does not denote a setter,
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index 352acf3..14add4a 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -133,6 +133,26 @@
 
   @override
   @failingTest
+  test_inferred_type_nullability_class_ref_none() =>
+      super.test_inferred_type_nullability_class_ref_none();
+
+  @override
+  @failingTest
+  test_inferred_type_nullability_class_ref_question() =>
+      super.test_inferred_type_nullability_class_ref_question();
+
+  @override
+  @failingTest
+  test_inferred_type_nullability_function_type_none() =>
+      super.test_inferred_type_nullability_function_type_none();
+
+  @override
+  @failingTest
+  test_inferred_type_nullability_function_type_question() =>
+      super.test_inferred_type_nullability_function_type_question();
+
+  @override
+  @failingTest
   test_syntheticFunctionType_genericClosure() async {
     // TODO(scheglov) Bug in TypeSystem.getLeastUpperBound().
     // LUB(<T>(T) → int, <T>(T) → int) gives `(T) → int`, note absence of `<T>`.
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index c2d13b7..85bcfd2 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -6815,6 +6815,70 @@
 ''');
   }
 
+  test_inferred_type_nullability_class_ref_none() async {
+    featureSet = enableNnbd;
+    addSource('/a.dart', 'int f() => 0;');
+    var library = await checkLibrary('''
+import 'a.dart';
+var x = f();
+''');
+    checkElementText(
+        library,
+        r'''
+import 'a.dart';
+int x;
+''',
+        annotateNullability: true);
+  }
+
+  test_inferred_type_nullability_class_ref_question() async {
+    featureSet = enableNnbd;
+    addSource('/a.dart', 'int? f() => 0;');
+    var library = await checkLibrary('''
+import 'a.dart';
+var x = f();
+''');
+    checkElementText(
+        library,
+        r'''
+import 'a.dart';
+int? x;
+''',
+        annotateNullability: true);
+  }
+
+  test_inferred_type_nullability_function_type_none() async {
+    featureSet = enableNnbd;
+    addSource('/a.dart', 'void Function() f() => () {};');
+    var library = await checkLibrary('''
+import 'a.dart';
+var x = f();
+''');
+    checkElementText(
+        library,
+        r'''
+import 'a.dart';
+void Function() x;
+''',
+        annotateNullability: true);
+  }
+
+  test_inferred_type_nullability_function_type_question() async {
+    featureSet = enableNnbd;
+    addSource('/a.dart', 'void Function()? f() => () {};');
+    var library = await checkLibrary('''
+import 'a.dart';
+var x = f();
+''');
+    checkElementText(
+        library,
+        r'''
+import 'a.dart';
+void Function()? x;
+''',
+        annotateNullability: true);
+  }
+
   test_inferred_type_refers_to_bound_type_param() async {
     var library = await checkLibrary('''
 class C<T> extends D<int, T> {