Store compilation unit NNBD status in unlinked summary.

This is needed for two reasons:

1. Summary linking, because type inference needs to behave differently
for opted-in vs. opted-out libraries.

2. Summary resynthesis, because TypeParameterElement.type needs to
behave differently for opted-in vs. opted-out libraries.

Note that reason 1 won't apply to the summary2 mechanism, because it
has access to full ASTs when doing type inference.  But it will still
need to record compilation unit NNBD status for reason 2.

This CL merely stores the correct data in the summary; it doesn't
address resynthesis, linking, or summary2.

Change-Id: I1aa2226e5865ef76747267de6198223997d6ad0d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101920
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/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 617ad57..80a9ed3 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -28565,6 +28565,7 @@
   List<UnlinkedExecutableBuilder> _executables;
   List<UnlinkedExportNonPublicBuilder> _exports;
   List<UnlinkedImportBuilder> _imports;
+  bool _isNNBD;
   bool _isPartOf;
   List<UnlinkedExprBuilder> _libraryAnnotations;
   UnlinkedDocumentationCommentBuilder _libraryDocumentationComment;
@@ -28648,6 +28649,14 @@
   }
 
   @override
+  bool get isNNBD => _isNNBD ??= false;
+
+  /// Indicates whether this compilation unit is opted into NNBD.
+  set isNNBD(bool value) {
+    this._isNNBD = value;
+  }
+
+  @override
   bool get isPartOf => _isPartOf ??= false;
 
   /// Indicates whether the unit contains a "part of" declaration.
@@ -28775,6 +28784,7 @@
       List<UnlinkedExecutableBuilder> executables,
       List<UnlinkedExportNonPublicBuilder> exports,
       List<UnlinkedImportBuilder> imports,
+      bool isNNBD,
       bool isPartOf,
       List<UnlinkedExprBuilder> libraryAnnotations,
       UnlinkedDocumentationCommentBuilder libraryDocumentationComment,
@@ -28795,6 +28805,7 @@
         _executables = executables,
         _exports = exports,
         _imports = imports,
+        _isNNBD = isNNBD,
         _isPartOf = isPartOf,
         _libraryAnnotations = libraryAnnotations,
         _libraryDocumentationComment = libraryDocumentationComment,
@@ -28932,6 +28943,7 @@
         x?.collectApiSignature(signature);
       }
     }
+    signature.addBool(this._isNNBD == true);
   }
 
   List<int> toBuffer() {
@@ -29042,6 +29054,9 @@
     if (offset_imports != null) {
       fbBuilder.addOffset(5, offset_imports);
     }
+    if (_isNNBD == true) {
+      fbBuilder.addBool(21, true);
+    }
     if (_isPartOf == true) {
       fbBuilder.addBool(18, true);
     }
@@ -29113,6 +29128,7 @@
   List<idl.UnlinkedExecutable> _executables;
   List<idl.UnlinkedExportNonPublic> _exports;
   List<idl.UnlinkedImport> _imports;
+  bool _isNNBD;
   bool _isPartOf;
   List<idl.UnlinkedExpr> _libraryAnnotations;
   idl.UnlinkedDocumentationComment _libraryDocumentationComment;
@@ -29185,6 +29201,12 @@
   }
 
   @override
+  bool get isNNBD {
+    _isNNBD ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 21, false);
+    return _isNNBD;
+  }
+
+  @override
   bool get isPartOf {
     _isPartOf ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 18, false);
     return _isPartOf;
@@ -29297,6 +29319,7 @@
       _result["exports"] = exports.map((_value) => _value.toJson()).toList();
     if (imports.isNotEmpty)
       _result["imports"] = imports.map((_value) => _value.toJson()).toList();
+    if (isNNBD != false) _result["isNNBD"] = isNNBD;
     if (isPartOf != false) _result["isPartOf"] = isPartOf;
     if (libraryAnnotations.isNotEmpty)
       _result["libraryAnnotations"] =
@@ -29336,6 +29359,7 @@
         "executables": executables,
         "exports": exports,
         "imports": imports,
+        "isNNBD": isNNBD,
         "isPartOf": isPartOf,
         "libraryAnnotations": libraryAnnotations,
         "libraryDocumentationComment": libraryDocumentationComment,
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 47e6bb9..b124216 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -3033,6 +3033,9 @@
   /// Import declarations in the compilation unit.
   imports:[UnlinkedImport] (id: 5);
 
+  /// Indicates whether this compilation unit is opted into NNBD.
+  isNNBD:bool (id: 21);
+
   /// Indicates whether the unit contains a "part of" declaration.
   isPartOf:bool (id: 18);
 
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index b9bac17..9e938ec 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -4783,6 +4783,10 @@
   @Id(5)
   List<UnlinkedImport> get imports;
 
+  /// Indicates whether this compilation unit is opted into NNBD.
+  @Id(21)
+  bool get isNNBD;
+
   /// Indicates whether the unit contains a "part of" declaration.
   @Id(18)
   bool get isPartOf;
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index b50d8cd..3608b07 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -491,7 +491,8 @@
       unlinkedImports.add(new UnlinkedImportBuilder(isImplicit: true));
     }
     compilationUnit.declarations.accept(this);
-    UnlinkedUnitBuilder b = new UnlinkedUnitBuilder();
+    UnlinkedUnitBuilder b = new UnlinkedUnitBuilder(
+        isNNBD: compilationUnit.featureSet.isEnabled(Feature.non_nullable));
     b.lineStarts = compilationUnit.lineInfo?.lineStarts;
     b.isPartOf = isPartOf;
     b.libraryName = libraryName;
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 2d41129..10f6ccd 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -1604,6 +1604,26 @@
     }
   }
 
+  test_compilationUnit_nnbd_disabled_via_dart_directive() {
+    featureSet = enableNnbd;
+    serializeLibraryText('''
+// @dart=2.2
+''');
+    expect(unlinkedUnits[0].isNNBD, false);
+  }
+
+  test_compilationUnit_nnbd_disabled_via_feature_set() {
+    featureSet = disableNnbd;
+    serializeLibraryText('');
+    expect(unlinkedUnits[0].isNNBD, false);
+  }
+
+  test_compilationUnit_nnbd_enabled() {
+    featureSet = enableNnbd;
+    serializeLibraryText('');
+    expect(unlinkedUnits[0].isNNBD, true);
+  }
+
   test_constExpr_binary_add() {
     UnlinkedVariable variable = serializeVariableText('const v = 1 + 2;');
     assertUnlinkedConst(variable.initializer.bodyExpr, '1 + 2', operators: [
diff --git a/pkg/analyzer/test/src/summary/test_strategies.dart b/pkg/analyzer/test/src/summary/test_strategies.dart
index e27b403..7f0aa49 100644
--- a/pkg/analyzer/test/src/summary/test_strategies.dart
+++ b/pkg/analyzer/test/src/summary/test_strategies.dart
@@ -45,9 +45,12 @@
       new Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER)
         ..configureFeatures(featureSet);
   Token token = scanner.tokenize();
+  // Pass the feature set from the scanner to the parser
+  // because the scanner may have detected a language version comment
+  // and downgraded the feature set it holds.
   Parser parser = new Parser(
       NonExistingSource.unknown, AnalysisErrorListener.NULL_LISTENER,
-      featureSet: featureSet);
+      featureSet: scanner.featureSet);
   CompilationUnit unit = parser.parseCompilationUnit(token);
   unit.lineInfo = new LineInfo(scanner.lineStarts);
   return unit;