use the current language version for spawnHybridCode (#1454)

Fixes https://github.com/dart-lang/test/issues/1363
diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml
index 983fff9..c821d17 100644
--- a/.github/workflows/dart.yml
+++ b/.github/workflows/dart.yml
@@ -38,16 +38,16 @@
       - name: mono_repo self validate
         run: pub global run mono_repo generate --validate
   job_002:
-    name: "analyze_and_format; Dart dev; PKGS: pkgs/test, pkgs/test_api, pkgs/test_core; `dartfmt -n --set-exit-if-changed .`, `dartanalyzer --fatal-infos --fatal-warnings .`"
+    name: "analyze_and_format; Dart dev; PKGS: integration_tests/nnbd_opted_out, pkgs/test, pkgs/test_api, pkgs/test_core; `dartfmt -n --set-exit-if-changed .`, `dartanalyzer --fatal-infos --fatal-warnings .`"
     runs-on: ubuntu-latest
     steps:
       - name: Cache Pub hosted dependencies
         uses: actions/cache@v2
         with:
           path: "~/.pub-cache/hosted"
-          key: "os:ubuntu-latest;pub-cache-hosted;dart:dev;packages:pkgs/test-pkgs/test_api-pkgs/test_core;commands:dartfmt-dartanalyzer"
+          key: "os:ubuntu-latest;pub-cache-hosted;dart:dev;packages:integration_tests/nnbd_opted_out-pkgs/test-pkgs/test_api-pkgs/test_core;commands:dartfmt-dartanalyzer"
           restore-keys: |
-            os:ubuntu-latest;pub-cache-hosted;dart:dev;packages:pkgs/test-pkgs/test_api-pkgs/test_core
+            os:ubuntu-latest;pub-cache-hosted;dart:dev;packages:integration_tests/nnbd_opted_out-pkgs/test-pkgs/test_api-pkgs/test_core
             os:ubuntu-latest;pub-cache-hosted;dart:dev
             os:ubuntu-latest;pub-cache-hosted
             os:ubuntu-latest
@@ -56,6 +56,19 @@
           sdk: dev
       - id: checkout
         uses: actions/checkout@v2
+      - id: integration_tests_nnbd_opted_out_pub_upgrade
+        name: "integration_tests/nnbd_opted_out; pub upgrade --no-precompile"
+        if: "always() && steps.checkout.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: pub upgrade --no-precompile
+      - name: "integration_tests/nnbd_opted_out; dartfmt -n --set-exit-if-changed ."
+        if: "always() && steps.integration_tests_nnbd_opted_out_pub_upgrade.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: dartfmt -n --set-exit-if-changed .
+      - name: "integration_tests/nnbd_opted_out; dartanalyzer --fatal-infos --fatal-warnings ."
+        if: "always() && steps.integration_tests_nnbd_opted_out_pub_upgrade.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: dartanalyzer --fatal-infos --fatal-warnings .
       - id: pkgs_test_pub_upgrade
         name: "pkgs/test; pub upgrade --no-precompile"
         if: "always() && steps.checkout.conclusion == 'success'"
@@ -96,6 +109,68 @@
         working-directory: pkgs/test_core
         run: dartanalyzer --fatal-infos --fatal-warnings .
   job_003:
+    name: "unit_test; Dart dev; PKG: integration_tests/nnbd_opted_out; `pub run test -p chrome,vm,node`"
+    runs-on: ubuntu-latest
+    steps:
+      - name: Cache Pub hosted dependencies
+        uses: actions/cache@v2
+        with:
+          path: "~/.pub-cache/hosted"
+          key: "os:ubuntu-latest;pub-cache-hosted;dart:dev;packages:integration_tests/nnbd_opted_out;commands:test"
+          restore-keys: |
+            os:ubuntu-latest;pub-cache-hosted;dart:dev;packages:integration_tests/nnbd_opted_out
+            os:ubuntu-latest;pub-cache-hosted;dart:dev
+            os:ubuntu-latest;pub-cache-hosted
+            os:ubuntu-latest
+      - uses: dart-lang/setup-dart@v1.0
+        with:
+          sdk: dev
+      - id: checkout
+        uses: actions/checkout@v2
+      - id: integration_tests_nnbd_opted_out_pub_upgrade
+        name: "integration_tests/nnbd_opted_out; pub upgrade --no-precompile"
+        if: "always() && steps.checkout.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: pub upgrade --no-precompile
+      - name: "integration_tests/nnbd_opted_out; pub run test -p chrome,vm,node"
+        if: "always() && steps.integration_tests_nnbd_opted_out_pub_upgrade.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: "pub run test -p chrome,vm,node"
+    needs:
+      - job_001
+      - job_002
+  job_004:
+    name: "unit_test; Dart stable; PKG: integration_tests/nnbd_opted_out; `pub run test -p chrome,vm,node`"
+    runs-on: ubuntu-latest
+    steps:
+      - name: Cache Pub hosted dependencies
+        uses: actions/cache@v2
+        with:
+          path: "~/.pub-cache/hosted"
+          key: "os:ubuntu-latest;pub-cache-hosted;dart:stable;packages:integration_tests/nnbd_opted_out;commands:test"
+          restore-keys: |
+            os:ubuntu-latest;pub-cache-hosted;dart:stable;packages:integration_tests/nnbd_opted_out
+            os:ubuntu-latest;pub-cache-hosted;dart:stable
+            os:ubuntu-latest;pub-cache-hosted
+            os:ubuntu-latest
+      - uses: dart-lang/setup-dart@v1.0
+        with:
+          sdk: stable
+      - id: checkout
+        uses: actions/checkout@v2
+      - id: integration_tests_nnbd_opted_out_pub_upgrade
+        name: "integration_tests/nnbd_opted_out; pub upgrade --no-precompile"
+        if: "always() && steps.checkout.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: pub upgrade --no-precompile
+      - name: "integration_tests/nnbd_opted_out; pub run test -p chrome,vm,node"
+        if: "always() && steps.integration_tests_nnbd_opted_out_pub_upgrade.conclusion == 'success'"
+        working-directory: integration_tests/nnbd_opted_out
+        run: "pub run test -p chrome,vm,node"
+    needs:
+      - job_001
+      - job_002
+  job_005:
     name: "unit_test; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 0`"
     runs-on: ubuntu-latest
     steps:
@@ -126,7 +201,7 @@
     needs:
       - job_001
       - job_002
-  job_004:
+  job_006:
     name: "unit_test; Dart stable; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 0`"
     runs-on: ubuntu-latest
     steps:
@@ -157,7 +232,7 @@
     needs:
       - job_001
       - job_002
-  job_005:
+  job_007:
     name: "unit_test; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 1`"
     runs-on: ubuntu-latest
     steps:
@@ -188,7 +263,7 @@
     needs:
       - job_001
       - job_002
-  job_006:
+  job_008:
     name: "unit_test; Dart stable; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 1`"
     runs-on: ubuntu-latest
     steps:
@@ -219,7 +294,7 @@
     needs:
       - job_001
       - job_002
-  job_007:
+  job_009:
     name: "unit_test; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 2`"
     runs-on: ubuntu-latest
     steps:
@@ -250,7 +325,7 @@
     needs:
       - job_001
       - job_002
-  job_008:
+  job_010:
     name: "unit_test; Dart stable; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 2`"
     runs-on: ubuntu-latest
     steps:
@@ -281,7 +356,7 @@
     needs:
       - job_001
       - job_002
-  job_009:
+  job_011:
     name: "unit_test; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 3`"
     runs-on: ubuntu-latest
     steps:
@@ -312,7 +387,7 @@
     needs:
       - job_001
       - job_002
-  job_010:
+  job_012:
     name: "unit_test; Dart stable; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 3`"
     runs-on: ubuntu-latest
     steps:
@@ -343,7 +418,7 @@
     needs:
       - job_001
       - job_002
-  job_011:
+  job_013:
     name: "unit_test; Dart dev; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 4`"
     runs-on: ubuntu-latest
     steps:
@@ -374,7 +449,7 @@
     needs:
       - job_001
       - job_002
-  job_012:
+  job_014:
     name: "unit_test; Dart stable; PKG: pkgs/test; `xvfb-run -s \"-screen 0 1024x768x24\" pub run test --preset travis -x phantomjs --total-shards 5 --shard-index 4`"
     runs-on: ubuntu-latest
     steps:
@@ -405,7 +480,7 @@
     needs:
       - job_001
       - job_002
-  job_013:
+  job_015:
     name: "unit_test; Dart dev; PKG: pkgs/test_api; `pub run test --preset travis -x browser`"
     runs-on: ubuntu-latest
     steps:
@@ -436,7 +511,7 @@
     needs:
       - job_001
       - job_002
-  job_014:
+  job_016:
     name: "unit_test; Dart stable; PKG: pkgs/test_api; `pub run test --preset travis -x browser`"
     runs-on: ubuntu-latest
     steps:
@@ -467,7 +542,7 @@
     needs:
       - job_001
       - job_002
-  job_015:
+  job_017:
     name: Notify failure
     runs-on: ubuntu-latest
     if: "(github.event_name == 'push' || github.event_name == 'schedule') && failure()"
@@ -493,3 +568,5 @@
       - job_012
       - job_013
       - job_014
+      - job_015
+      - job_016
diff --git a/integration_tests/nnbd_opted_out/mono_pkg.yaml b/integration_tests/nnbd_opted_out/mono_pkg.yaml
new file mode 100644
index 0000000..b79bf54
--- /dev/null
+++ b/integration_tests/nnbd_opted_out/mono_pkg.yaml
@@ -0,0 +1,13 @@
+dart:
+  - dev
+  - stable
+
+stages:
+    - analyze_and_format:
+      - group:
+        - dartfmt: sdk
+        - dartanalyzer: --fatal-infos --fatal-warnings .
+        dart:
+        - dev
+    - unit_test:
+      - test: -p chrome,vm,node
diff --git a/integration_tests/nnbd_opted_out/pubspec.yaml b/integration_tests/nnbd_opted_out/pubspec.yaml
new file mode 100644
index 0000000..ad693de
--- /dev/null
+++ b/integration_tests/nnbd_opted_out/pubspec.yaml
@@ -0,0 +1,12 @@
+name: nnbd_opted_out
+environment:
+  sdk: '>=2.11.0 <3.0.0'
+dev_dependencies:
+  test: any
+dependency_overrides:
+  test:
+    path: ../../pkgs/test
+  test_api:
+    path: ../../pkgs/test_api
+  test_core:
+    path: ../../pkgs/test_core
diff --git a/integration_tests/nnbd_opted_out/test/spawn_hybrid_code_test.dart b/integration_tests/nnbd_opted_out/test/spawn_hybrid_code_test.dart
new file mode 100644
index 0000000..46829cc
--- /dev/null
+++ b/integration_tests/nnbd_opted_out/test/spawn_hybrid_code_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// 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:test/test.dart';
+
+void main() {
+  group('spawnHybridCode', () {
+    test('uses the current package language version by default', () async {
+      final channel = spawnHybridCode(_hybridMain);
+      expect(await channel.stream.single, equals(false));
+    });
+
+    test('can set the language version with a marker', () async {
+      final channel = spawnHybridCode('// @dart=2.12\n$_hybridMain');
+      expect(await channel.stream.single, equals(true));
+    });
+  });
+}
+
+const _hybridMain = '''
+bool runningWithNullSafety() {
+  try {
+    null as String;
+    return false;
+  } catch (_) {
+    return true;
+  }
+}
+
+void hybridMain(dynamic channel) async {
+  channel.sink.add(runningWithNullSafety());
+  channel.sink.close();
+}
+''';
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 3f38ac8..100e634 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.18-dev
+
+* Update `spawnHybridCode` to default to the current packages language version.
+
 ## 0.3.17
 
 * Complete the null safety migration.
diff --git a/pkgs/test_core/lib/src/runner/spawn_hybrid.dart b/pkgs/test_core/lib/src/runner/spawn_hybrid.dart
index 6202446..2ec757c 100644
--- a/pkgs/test_core/lib/src/runner/spawn_hybrid.dart
+++ b/pkgs/test_core/lib/src/runner/spawn_hybrid.dart
@@ -13,6 +13,7 @@
 
 import '../util/dart.dart' as dart;
 import '../util/package_config.dart';
+import 'package_version.dart';
 
 import 'package:test_api/src/backend/suite.dart'; // ignore: implementation_imports
 import 'package:test_api/src/util/remote_exception.dart'; // ignore: implementation_imports
@@ -110,11 +111,14 @@
 ///
 /// If there is a language version comment in the file, that is returned.
 ///
+/// If the URI has a `data` scheme, a comment representing the language version of
+/// the current package is returned.
+///
 /// Otherwise a comment representing the default version from the
 /// [currentPackageConfig] is returned.
 ///
-/// If no default language version is known (data: uri for instance), then
-/// an empty string is returned.
+/// If no default language version is known (the URI scheme is not recognized
+/// for instance), then an empty string is returned.
 Future<String> _languageVersionCommentFor(String url) async {
   var parsedUri = Uri.parse(url);
 
@@ -134,6 +138,12 @@
     if (version != null) return '// @dart=$version';
   }
 
+  // Returns the root package language version for `data` URIs. These are
+  // assumed to be from `spawnHybridCode` calls.
+  if (parsedUri.scheme == 'data') {
+    return await rootPackageLanguageVersionComment;
+  }
+
   // Fall back on no language comment.
   return '';
 }
diff --git a/pkgs/test_core/pubspec.yaml b/pkgs/test_core/pubspec.yaml
index 2f6fcf6..1627215 100644
--- a/pkgs/test_core/pubspec.yaml
+++ b/pkgs/test_core/pubspec.yaml
@@ -1,5 +1,5 @@
 name: test_core
-version: 0.3.17
+version: 0.3.18-dev
 description: A basic library for writing tests and running them on the VM.
 homepage: https://github.com/dart-lang/test/blob/master/pkgs/test_core
 
diff --git a/tool/ci.sh b/tool/ci.sh
index 1e1b9e5..588b95d 100755
--- a/tool/ci.sh
+++ b/tool/ci.sh
@@ -90,6 +90,10 @@
         echo 'dartfmt -n --set-exit-if-changed .'
         dartfmt -n --set-exit-if-changed . || EXIT_CODE=$?
         ;;
+      test)
+        echo 'pub run test -p chrome,vm,node'
+        pub run test -p chrome,vm,node || EXIT_CODE=$?
+        ;;
       *)
         echo -e "\033[31mUnknown TASK '${TASK}' - TERMINATING JOB\033[0m"
         exit 64