Support for 'nullabilitySuffix' in linked types.

R=brianwilkerson@google.com

Change-Id: I08853e2a699cc2270f120247424503a2c5a7cac3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100924
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index 8624b44..d73ab28 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -361,7 +361,12 @@
 
     if (this.useCounter == before) return type;
 
-    return FunctionTypeBuilder(typeFormals, parameters, returnType);
+    return FunctionTypeBuilder(
+      typeFormals,
+      parameters,
+      returnType,
+      type.nullabilitySuffix,
+    );
   }
 
   @override
@@ -391,7 +396,11 @@
       return type;
     }
 
-    return new NamedTypeBuilder(type.element, arguments);
+    return new NamedTypeBuilder(
+      type.element,
+      arguments,
+      type.nullabilitySuffix,
+    );
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index ff3d13e..8458072 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -19482,6 +19482,7 @@
   int _interfaceClass;
   List<LinkedNodeTypeBuilder> _interfaceTypeArguments;
   idl.LinkedNodeTypeKind _kind;
+  idl.EntityRefNullabilitySuffix _nullabilitySuffix;
   int _typeParameterElement;
   int _typeParameterId;
 
@@ -19550,6 +19551,14 @@
   }
 
   @override
+  idl.EntityRefNullabilitySuffix get nullabilitySuffix =>
+      _nullabilitySuffix ??= idl.EntityRefNullabilitySuffix.starOrIrrelevant;
+
+  set nullabilitySuffix(idl.EntityRefNullabilitySuffix value) {
+    this._nullabilitySuffix = value;
+  }
+
+  @override
   int get typeParameterElement => _typeParameterElement ??= 0;
 
   set typeParameterElement(int value) {
@@ -19574,6 +19583,7 @@
       int interfaceClass,
       List<LinkedNodeTypeBuilder> interfaceTypeArguments,
       idl.LinkedNodeTypeKind kind,
+      idl.EntityRefNullabilitySuffix nullabilitySuffix,
       int typeParameterElement,
       int typeParameterId})
       : _functionFormalParameters = functionFormalParameters,
@@ -19584,6 +19594,7 @@
         _interfaceClass = interfaceClass,
         _interfaceTypeArguments = interfaceTypeArguments,
         _kind = kind,
+        _nullabilitySuffix = nullabilitySuffix,
         _typeParameterElement = typeParameterElement,
         _typeParameterId = typeParameterId;
 
@@ -19637,6 +19648,8 @@
         x?.collectApiSignature(signature);
       }
     }
+    signature.addInt(
+        this._nullabilitySuffix == null ? 0 : this._nullabilitySuffix.index);
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
@@ -19693,6 +19706,10 @@
     if (_kind != null && _kind != idl.LinkedNodeTypeKind.bottom) {
       fbBuilder.addUint8(5, _kind.index);
     }
+    if (_nullabilitySuffix != null &&
+        _nullabilitySuffix != idl.EntityRefNullabilitySuffix.starOrIrrelevant) {
+      fbBuilder.addUint8(10, _nullabilitySuffix.index);
+    }
     if (_typeParameterElement != null && _typeParameterElement != 0) {
       fbBuilder.addUint32(6, _typeParameterElement);
     }
@@ -19727,6 +19744,7 @@
   int _interfaceClass;
   List<idl.LinkedNodeType> _interfaceTypeArguments;
   idl.LinkedNodeTypeKind _kind;
+  idl.EntityRefNullabilitySuffix _nullabilitySuffix;
   int _typeParameterElement;
   int _typeParameterId;
 
@@ -19794,6 +19812,13 @@
   }
 
   @override
+  idl.EntityRefNullabilitySuffix get nullabilitySuffix {
+    _nullabilitySuffix ??= const _EntityRefNullabilitySuffixReader().vTableGet(
+        _bc, _bcOffset, 10, idl.EntityRefNullabilitySuffix.starOrIrrelevant);
+    return _nullabilitySuffix;
+  }
+
+  @override
   int get typeParameterElement {
     _typeParameterElement ??=
         const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 6, 0);
@@ -19832,6 +19857,8 @@
           interfaceTypeArguments.map((_value) => _value.toJson()).toList();
     if (kind != idl.LinkedNodeTypeKind.bottom)
       _result["kind"] = kind.toString().split('.')[1];
+    if (nullabilitySuffix != idl.EntityRefNullabilitySuffix.starOrIrrelevant)
+      _result["nullabilitySuffix"] = nullabilitySuffix.toString().split('.')[1];
     if (typeParameterElement != 0)
       _result["typeParameterElement"] = typeParameterElement;
     if (typeParameterId != 0) _result["typeParameterId"] = typeParameterId;
@@ -19848,6 +19875,7 @@
         "interfaceClass": interfaceClass,
         "interfaceTypeArguments": interfaceTypeArguments,
         "kind": kind,
+        "nullabilitySuffix": nullabilitySuffix,
         "typeParameterElement": typeParameterElement,
         "typeParameterId": typeParameterId,
       };
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 9afbf14..ad1b299 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -2003,6 +2003,8 @@
 
   kind:LinkedNodeTypeKind (id: 5);
 
+  nullabilitySuffix:EntityRefNullabilitySuffix (id: 10);
+
   typeParameterElement:uint (id: 6);
 
   typeParameterId:uint (id: 7);
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 73bba33..171389f 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -2614,6 +2614,9 @@
   @Id(5)
   LinkedNodeTypeKind get kind;
 
+  @Id(10)
+  EntityRefNullabilitySuffix get nullabilitySuffix;
+
   @Id(6)
   int get typeParameterElement;
 
diff --git a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart b/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
index 4abe8d6..17c0845 100644
--- a/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/builder/source_library_builder.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart' as ast;
 import 'package:analyzer/src/dart/ast/mixin_super_invoked_names.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -330,6 +331,7 @@
         linker.elementFactory,
         element,
         unitReference,
+        linker.contextFeatures.isEnabled(Feature.non_nullable),
         libraryScope,
       );
       unitContext.unit.accept(resolver);
diff --git a/pkg/analyzer/lib/src/summary2/function_type_builder.dart b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
index 608e192..39425e6 100644
--- a/pkg/analyzer/lib/src/summary2/function_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/function_type_builder.dart
@@ -18,6 +18,7 @@
   final List<TypeParameterElement> typeFormals;
   final List<ParameterElement> parameters;
   final DartType returnType;
+  final NullabilitySuffix nullabilitySuffix;
 
   /// The node for which this builder is created, or `null` if the builder
   /// was detached from its node, e.g. during computing default types for
@@ -33,11 +34,15 @@
   FunctionTypeBuilder(
     this.typeFormals,
     this.parameters,
-    this.returnType, {
+    this.returnType,
+    this.nullabilitySuffix, {
     this.node,
   });
 
-  factory FunctionTypeBuilder.of(GenericFunctionType node) {
+  factory FunctionTypeBuilder.of(
+    GenericFunctionType node,
+    NullabilitySuffix nullabilitySuffix,
+  ) {
     return FunctionTypeBuilder(
       node.typeParameters?.typeParameters
               ?.map((n) => n.declaredElement as TypeParameterElement)
@@ -52,6 +57,7 @@
         );
       }).toList(),
       _getNodeType(node.returnType),
+      nullabilitySuffix,
       node: node,
     );
   }
@@ -77,6 +83,7 @@
           e.parameterKind,
         );
       }).toList(),
+      nullabilitySuffix: nullabilitySuffix,
     );
 
     if (node != null) {
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 66b6e74..b2958f6 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
 import 'package:analyzer/dart/element/element.dart';
@@ -84,6 +85,10 @@
     );
   }
 
+  FeatureSet get contextFeatures {
+    return analysisContext.analysisOptions.contextFeatures;
+  }
+
   void link(List<LinkedNodeBundle> inputBundles,
       List<LinkInputLibrary> inputLibraries) {
     for (var input in inputBundles) {
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index bc93069..35cdd00 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -947,28 +947,33 @@
         _typeParameters.remove(--_nextSyntheticTypeParameterId);
       }
 
+      var nullabilitySuffix = _nullabilitySuffix(linkedType.nullabilitySuffix);
+
       return FunctionTypeImpl.synthetic(
         returnType,
         typeParameters,
         formalParameters,
-      );
+      ).withNullability(nullabilitySuffix);
     } else if (kind == LinkedNodeTypeKind.interface) {
       var element = bundleContext.elementOfIndex(linkedType.interfaceClass);
+      var nullabilitySuffix = _nullabilitySuffix(linkedType.nullabilitySuffix);
       return InterfaceTypeImpl.explicit(
         element,
         linkedType.interfaceTypeArguments.map(readType).toList(),
+        nullabilitySuffix: nullabilitySuffix,
       );
     } else if (kind == LinkedNodeTypeKind.typeParameter) {
+      TypeParameterElement element;
       var id = linkedType.typeParameterId;
       if (id != 0) {
-        var element = _typeParameters[id];
+        element = _typeParameters[id];
         assert(element != null);
-        return TypeParameterTypeImpl(element);
       } else {
         var index = linkedType.typeParameterElement;
-        var element = bundleContext.elementOfIndex(index);
-        return TypeParameterTypeImpl(element);
+        element = bundleContext.elementOfIndex(index);
       }
+      var nullabilitySuffix = _nullabilitySuffix(linkedType.nullabilitySuffix);
+      return TypeParameterTypeImpl(element).withNullability(nullabilitySuffix);
     } else if (kind == LinkedNodeTypeKind.void_) {
       return VoidTypeImpl.instance;
     } else {
@@ -1145,6 +1150,19 @@
     }
     return typeParameterList?.typeParameterList_typeParameters;
   }
+
+  static NullabilitySuffix _nullabilitySuffix(EntityRefNullabilitySuffix data) {
+    switch (data) {
+      case EntityRefNullabilitySuffix.starOrIrrelevant:
+        return NullabilitySuffix.star;
+      case EntityRefNullabilitySuffix.question:
+        return NullabilitySuffix.question;
+      case EntityRefNullabilitySuffix.none:
+        return NullabilitySuffix.none;
+      default:
+        throw StateError('$data');
+    }
+  }
 }
 
 /// Ensure that all [GenericFunctionType] and [TypeParameter] nodes are read,
diff --git a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
index c151916..75e6617 100644
--- a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
@@ -94,6 +94,7 @@
         kind: LinkedNodeTypeKind.interface,
         interfaceClass: indexOfElement(type.element),
         interfaceTypeArguments: type.typeArguments.map(writeType).toList(),
+        nullabilitySuffix: _nullabilitySuffix(type),
       );
     } else if (type is TypeParameterType) {
       TypeParameterElementImpl element = type.element;
@@ -101,12 +102,14 @@
       if (id != null) {
         return LinkedNodeTypeBuilder(
           kind: LinkedNodeTypeKind.typeParameter,
+          nullabilitySuffix: _nullabilitySuffix(type),
           typeParameterId: id,
         );
       } else {
         var index = indexOfElement(element);
         return LinkedNodeTypeBuilder(
           kind: LinkedNodeTypeKind.typeParameter,
+          nullabilitySuffix: _nullabilitySuffix(type),
           typeParameterElement: index,
         );
       }
@@ -177,6 +180,7 @@
           .toList(),
       functionReturnType: writeType(type.returnType),
       functionTypeParameters: typeParameterBuilders,
+      nullabilitySuffix: _nullabilitySuffix(type),
     );
 
     for (var typeParameter in typeParameters) {
@@ -186,4 +190,18 @@
 
     return result;
   }
+
+  static EntityRefNullabilitySuffix _nullabilitySuffix(DartType type) {
+    var nullabilitySuffix = (type as TypeImpl).nullabilitySuffix;
+    switch (nullabilitySuffix) {
+      case NullabilitySuffix.question:
+        return EntityRefNullabilitySuffix.question;
+      case NullabilitySuffix.star:
+        return EntityRefNullabilitySuffix.starOrIrrelevant;
+      case NullabilitySuffix.none:
+        return EntityRefNullabilitySuffix.none;
+      default:
+        throw StateError('$nullabilitySuffix');
+    }
+  }
 }
diff --git a/pkg/analyzer/lib/src/summary2/named_type_builder.dart b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
index 44d637a..683e7c9 100644
--- a/pkg/analyzer/lib/src/summary2/named_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/named_type_builder.dart
@@ -16,6 +16,7 @@
 
   final Element element;
   final List<DartType> arguments;
+  final NullabilitySuffix nullabilitySuffix;
 
   /// The node for which this builder is created, or `null` if the builder
   /// was detached from its node, e.g. during computing default types for
@@ -28,9 +29,14 @@
   /// and set for the [node].
   DartType _type;
 
-  NamedTypeBuilder(this.element, this.arguments, {this.node});
+  NamedTypeBuilder(this.element, this.arguments, this.nullabilitySuffix,
+      {this.node});
 
-  factory NamedTypeBuilder.of(Element element, TypeName node) {
+  factory NamedTypeBuilder.of(
+    TypeName node,
+    Element element,
+    NullabilitySuffix nullabilitySuffix,
+  ) {
     List<DartType> arguments;
     var argumentList = node.typeArguments;
     if (argumentList != null) {
@@ -39,7 +45,7 @@
       arguments = <DartType>[];
     }
 
-    return NamedTypeBuilder(element, arguments, node: node);
+    return NamedTypeBuilder(element, arguments, nullabilitySuffix, node: node);
   }
 
   @override
@@ -52,10 +58,15 @@
     if (element is ClassElement) {
       var parameters = element.typeParameters;
       if (parameters.isEmpty) {
-        _type = element.type;
+        var rawType = element.type;
+        _type = (rawType as TypeImpl).withNullability(nullabilitySuffix);
       } else {
         var arguments = _buildArguments(parameters);
-        _type = InterfaceTypeImpl.explicit(element, arguments);
+        _type = InterfaceTypeImpl.explicit(
+          element,
+          arguments,
+          nullabilitySuffix: nullabilitySuffix,
+        );
       }
     } else if (element is GenericTypeAliasElement) {
       // Break a possible recursion.
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 83b68c8..4b7cd9f 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -520,6 +520,7 @@
   final LinkedElementFactory elementFactory;
   final LibraryElement _libraryElement;
   final Reference unitReference;
+  final bool nnbd;
 
   Reference reference;
   Scope scope;
@@ -530,6 +531,7 @@
     this.elementFactory,
     this._libraryElement,
     this.unitReference,
+    this.nnbd,
     this.scope,
   ) : reference = unitReference;
 
@@ -771,7 +773,8 @@
     node.typeParameters?.accept(this);
     node.parameters.accept(this);
 
-    var builder = FunctionTypeBuilder.of(node);
+    var nullabilitySuffix = _getNullabilitySuffix(node.question != null);
+    var builder = FunctionTypeBuilder.of(node, nullabilitySuffix);
     (node as GenericFunctionTypeImpl).type = builder;
     nodesToBuildType.addTypeBuilder(builder);
 
@@ -905,10 +908,18 @@
 
     node.typeArguments?.accept(this);
 
+    var nullabilitySuffix = _getNullabilitySuffix(node.question != null);
     if (element is TypeParameterElement) {
-      node.type = TypeParameterTypeImpl(element);
+      node.type = TypeParameterTypeImpl(
+        element,
+        nullabilitySuffix: nullabilitySuffix,
+      );
     } else {
-      var builder = NamedTypeBuilder.of(element, node);
+      var builder = NamedTypeBuilder.of(
+        node,
+        element,
+        nullabilitySuffix,
+      );
       node.type = builder;
       nodesToBuildType.addTypeBuilder(builder);
     }
@@ -956,4 +967,16 @@
       _createTypeParameterElement(typeParameter);
     }
   }
+
+  NullabilitySuffix _getNullabilitySuffix(bool hasQuestion) {
+    if (nnbd) {
+      if (hasQuestion) {
+        return NullabilitySuffix.question;
+      } else {
+        return NullabilitySuffix.none;
+      }
+    } else {
+      return NullabilitySuffix.star;
+    }
+  }
 }