Version 2.14.0-250.0.dev
Merge commit '58ad941a5a146e476e0279049d5e7ee81444807e' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 94b1829..85e4d97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,14 +2,6 @@
### Core libraries
-### `dart:html`
-
-* [#44319][]: `convertNativeToDart_Dictionary()` now converts objects
- recursively, this fixes APIs like MediaStreamTrack.getCapabilities
- that convert between Maps and browser Dictionaries.
-
-[44319]: (https://github.com/dart-lang/sdk/issues/44319)
-
#### `dart:async`
* The uncaught error handlers of `Zone`s are now run in the parent zone
@@ -38,6 +30,14 @@
* Adds the `DynamicLibrary.providesSymbol` function to check whether a symbol
is available in a dynamic library.
+#### `dart:html`
+
+* `convertNativeToDart_Dictionary()` now converts objects
+ recursively, this fixes APIs like MediaStreamTrack.getCapabilities
+ that convert between Maps and browser Dictionaries. [#44319]
+
+[#44319]: https://github.com/dart-lang/sdk/issues/44319
+
#### `dart:io`
* BREAKING CHANGE (for pre-migrated null safe code):
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index 12c88aa..25cd71f 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -300,7 +300,7 @@
return isIntercepted
? function(receiver) {
if (cache === null) cache = #createTearOffClass(parameters);
- return new cache(this, receiver);
+ return new cache(receiver, this);
}
: function() {
if (cache === null) cache = #createTearOffClass(parameters);
@@ -339,7 +339,7 @@
return new Function("parameters, createTearOffClass, cache",
"return function tearOff_" + name + (functionCounter++) + "(receiver) {" +
"if (cache === null) cache = createTearOffClass(parameters);" +
- "return new cache(this, receiver);" +
+ "return new cache(receiver, this);" +
"}")(parameters, #createTearOffClass, null);
else
return new Function("parameters, createTearOffClass, cache",
diff --git a/pkg/compiler/test/codegen/use_strict_test.dart b/pkg/compiler/test/codegen/use_strict_test.dart
index 4407f33..d6cbaf4 100644
--- a/pkg/compiler/test/codegen/use_strict_test.dart
+++ b/pkg/compiler/test/codegen/use_strict_test.dart
@@ -65,7 +65,7 @@
List<RegExp> filters = [
RegExp(r' *//'), // skip comments
RegExp(r'"Intercepted function with no arguments."'),
- RegExp(r'f.apply\(s\(this\), arguments\)'),
+ RegExp(r'f.apply\(receiverOf\(this\), arguments\)'),
RegExp(r'Array.prototype.push.apply\(a, arguments\)'),
];
String filtered = lines
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index ab31327..0a4ddd9 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -844,6 +844,7 @@
Command computeAssembleCommand(String tempDir, List arguments,
Map<String, String> environmentOverrides) {
String cc, shared, ldFlags;
+ List<String> target;
if (_isAndroid) {
cc = "$ndkPath/toolchains/$abiTriple-4.9/prebuilt/"
"$host-x86_64/bin/$abiTriple-gcc";
@@ -862,6 +863,10 @@
shared = '-dynamiclib';
// Tell Mac linker to give up generating eh_frame from dwarf.
ldFlags = '-Wl,-no_compact_unwind';
+ if ({Architecture.arm64, Architecture.arm64c}
+ .contains(_configuration.architecture)) {
+ target = ['-arch', 'arm64'];
+ }
} else {
throw "Platform not supported: ${Platform.operatingSystem}";
}
@@ -887,6 +892,7 @@
}
var args = [
+ if (target != null) ...target,
if (ccFlags != null) ccFlags,
if (ldFlags != null) ldFlags,
shared,
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index cb46dfa..fa79c12 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -1843,15 +1843,6 @@
/// All static, tear-off, function declaration and function expression closures
/// extend this class.
abstract class Closure implements Function {
- // TODO(ahe): These constants must be in sync with
- // reflection_data_parser.dart.
- static const FUNCTION_INDEX = 0;
- static const NAME_INDEX = 1;
- static const CALL_NAME_INDEX = 2;
- static const REQUIRED_PARAMETER_INDEX = 3;
- static const OPTIONAL_PARAMETER_INDEX = 4;
- static const DEFAULT_ARGUMENTS_INDEX = 5;
-
/// Global counter to prevent reusing function code objects.
///
/// V8 will share the underlying function code objects when the same string is
@@ -1881,8 +1872,7 @@
var aBoundClosure = JS('BoundClosure', '0');
var aString = JS('String', '0');
BoundClosure.receiverOf(aBoundClosure);
- BoundClosure.selfOf(aBoundClosure);
- BoundClosure.evalRecipeIntercepted(aBoundClosure, aString);
+ BoundClosure.interceptorOf(aBoundClosure);
BoundClosure.evalRecipe(aBoundClosure, aString);
getType(JS('int', '0'));
});
@@ -2037,19 +2027,8 @@
static _computeSignatureFunctionNewRti(
Object functionType, bool isStatic, bool isIntercepted) {
if (JS('bool', 'typeof # == "number"', functionType)) {
- // Index into types table.
- //
- // We cannot call [getTypeFromTypesTable] here, since the types-metadata
- // might not be set yet. This is, because fromTearOff might be called for
- // constants when the program isn't completely set up yet. We also want to
- // avoid creating lots of types at startup.
- return JS(
- '',
- '''(function(getType, t) {
- return function(){ return getType(t); };
- })(#, #)''',
- RAW_DART_FUNCTION_REF(newRti.getTypeFromTypesTable),
- functionType);
+ // Index into types table. Handled in rti.dart.
+ return functionType;
}
if (JS('bool', 'typeof # == "string"', functionType)) {
// A recipe to evaluate against the instance type.
@@ -2057,9 +2036,7 @@
// TODO(sra): Recipe for static tearoff.
throw 'Cannot compute signature for static tearoff.';
}
- var typeEvalMethod = isIntercepted
- ? RAW_DART_FUNCTION_REF(BoundClosure.evalRecipeIntercepted)
- : RAW_DART_FUNCTION_REF(BoundClosure.evalRecipe);
+ final typeEvalMethod = RAW_DART_FUNCTION_REF(BoundClosure.evalRecipe);
return JS(
'',
' function(recipe, evalOnReceiver) {'
@@ -2075,7 +2052,7 @@
static cspForwardCall(
int arity, bool needsDirectAccess, String? stubName, function) {
- var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ var getReceiver = RAW_DART_FUNCTION_REF(BoundClosure.receiverOf);
// We have the target method (or an arity stub for the method) in
// [function]. These fixed-arity forwarding stubs could use
@@ -2094,74 +2071,74 @@
case 0:
return JS(
'',
- 'function(n,S){'
+ 'function(entry, receiverOf){'
'return function(){'
- 'return S(this)[n]()'
+ 'return receiverOf(this)[entry]()'
'}'
'}(#,#)',
stubName,
- getSelf);
+ getReceiver);
case 1:
return JS(
'',
- 'function(n,S){'
+ 'function(entry, receiverOf){'
'return function(a){'
- 'return S(this)[n](a)'
+ 'return receiverOf(this)[entry](a)'
'}'
'}(#,#)',
stubName,
- getSelf);
+ getReceiver);
case 2:
return JS(
'',
- 'function(n,S){'
- 'return function(a,b){'
- 'return S(this)[n](a,b)'
+ 'function(entry, receiverOf){'
+ 'return function(a, b){'
+ 'return receiverOf(this)[entry](a, b)'
'}'
'}(#,#)',
stubName,
- getSelf);
+ getReceiver);
case 3:
return JS(
'',
- 'function(n,S){'
- 'return function(a,b,c){'
- 'return S(this)[n](a,b,c)'
+ 'function(entry, receiverOf){'
+ 'return function(a, b, c){'
+ 'return receiverOf(this)[entry](a, b, c)'
'}'
'}(#,#)',
stubName,
- getSelf);
+ getReceiver);
case 4:
return JS(
'',
- 'function(n,S){'
- 'return function(a,b,c,d){'
- 'return S(this)[n](a,b,c,d)'
+ 'function(entry, receiverOf){'
+ 'return function(a, b, c, d){'
+ 'return receiverOf(this)[entry](a, b, c, d)'
'}'
'}(#,#)',
stubName,
- getSelf);
+ getReceiver);
case 5:
return JS(
'',
- 'function(n,S){'
- 'return function(a,b,c,d,e){'
- 'return S(this)[n](a,b,c,d,e)'
+ 'function(entry, receiverOf){'
+ 'return function(a, b, c, d, e){'
+ 'return receiverOf(this)[entry](a, b, c, d, e)'
'}'
'}(#,#)',
stubName,
- getSelf);
+ getReceiver);
default:
// Here we use `Function.prototype.apply`.
return JS(
'',
- 'function(f,s){'
+ 'function(f, receiverOf){'
'return function(){'
- 'return f.apply(s(this),arguments)'
+ 'return f.apply(receiverOf(this), arguments)'
'}'
'}(#,#)',
function,
- getSelf);
+ getReceiver);
}
}
@@ -2184,7 +2161,7 @@
'',
'(new Function(#))()',
'return function(){'
- 'var $selfName = this.${BoundClosure.selfFieldName()};'
+ 'var $selfName = this.${BoundClosure.receiverFieldName()};'
'return $selfName.$stubName();'
'}');
}
@@ -2196,106 +2173,106 @@
'',
'(new Function(#))()',
'return function($arguments){'
- 'return this.${BoundClosure.selfFieldName()}.$stubName($arguments);'
+ 'return this.${BoundClosure.receiverFieldName()}.$stubName($arguments);'
'}');
}
static cspForwardInterceptedCall(
- int arity, bool needsDirectAccess, String? name, function) {
- var getSelf = RAW_DART_FUNCTION_REF(BoundClosure.selfOf);
+ int arity, bool needsDirectAccess, String? stubName, function) {
var getReceiver = RAW_DART_FUNCTION_REF(BoundClosure.receiverOf);
+ var getInterceptor = RAW_DART_FUNCTION_REF(BoundClosure.interceptorOf);
// Handle intercepted stub-names with the default slow case.
if (needsDirectAccess) arity = -1;
switch (arity) {
case 0:
// Intercepted functions always takes at least one argument (the
// receiver).
- throw new RuntimeError('Intercepted function with no arguments.');
+ throw RuntimeError('Intercepted function with no arguments.');
case 1:
return JS(
'',
- 'function(n,s,r){'
+ 'function(entry, interceptorOf, receiverOf){'
'return function(){'
- 'return s(this)[n](r(this))'
+ 'return interceptorOf(this)[entry](receiverOf(this))'
'}'
'}(#,#,#)',
- name,
- getSelf,
+ stubName,
+ getInterceptor,
getReceiver);
case 2:
return JS(
'',
- 'function(n,s,r){'
+ 'function(entry, interceptorOf, receiverOf){'
'return function(a){'
- 'return s(this)[n](r(this),a)'
+ 'return interceptorOf(this)[entry](receiverOf(this), a)'
'}'
'}(#,#,#)',
- name,
- getSelf,
+ stubName,
+ getInterceptor,
getReceiver);
case 3:
return JS(
'',
- 'function(n,s,r){'
- 'return function(a,b){'
- 'return s(this)[n](r(this),a,b)'
+ 'function(entry, interceptorOf, receiverOf){'
+ 'return function(a, b){'
+ 'return interceptorOf(this)[entry](receiverOf(this), a, b)'
'}'
'}(#,#,#)',
- name,
- getSelf,
+ stubName,
+ getInterceptor,
getReceiver);
case 4:
return JS(
'',
- 'function(n,s,r){'
- 'return function(a,b,c){'
- 'return s(this)[n](r(this),a,b,c)'
+ 'function(entry, interceptorOf, receiverOf){'
+ 'return function(a, b, c){'
+ 'return interceptorOf(this)[entry](receiverOf(this), a, b, c)'
'}'
'}(#,#,#)',
- name,
- getSelf,
+ stubName,
+ getInterceptor,
getReceiver);
case 5:
return JS(
'',
- 'function(n,s,r){'
- 'return function(a,b,c,d){'
- 'return s(this)[n](r(this),a,b,c,d)'
+ 'function(entry, interceptorOf, receiverOf){'
+ 'return function(a, b, c, d){'
+ 'return interceptorOf(this)[entry](receiverOf(this), a, b, c, d)'
'}'
'}(#,#,#)',
- name,
- getSelf,
+ stubName,
+ getInterceptor,
getReceiver);
case 6:
return JS(
'',
- 'function(n,s,r){'
- 'return function(a,b,c,d,e){'
- 'return s(this)[n](r(this),a,b,c,d,e)'
+ 'function(entry, interceptorOf, receiverOf){'
+ 'return function(a, b, c, d, e){'
+ 'return interceptorOf(this)[entry](receiverOf(this), a, b, c, d, e)'
'}'
'}(#,#,#)',
- name,
- getSelf,
+ stubName,
+ getInterceptor,
getReceiver);
default:
return JS(
'',
- 'function(f,s,r,a){'
+ 'function(f, interceptorOf, receiverOf){'
'return function(){'
- 'a=[r(this)];'
- 'Array.prototype.push.apply(a,arguments);'
- 'return f.apply(s(this),a)'
+ 'var a = [receiverOf(this)];'
+ 'Array.prototype.push.apply(a, arguments);'
+ 'return f.apply(interceptorOf(this), a)'
'}'
'}(#,#,#)',
function,
- getSelf,
+ getInterceptor,
getReceiver);
}
}
static forwardInterceptedCallTo(
String stubName, function, bool needsDirectAccess) {
- String selfField = BoundClosure.selfFieldName();
+ String interceptorField = BoundClosure.interceptorFieldName();
String receiverField = BoundClosure.receiverFieldName();
int arity = JS('int', '#.length', function);
bool isCsp = JS_GET_FLAG('USE_CONTENT_SECURITY_POLICY');
@@ -2309,7 +2286,7 @@
'',
'(new Function(#))()',
'return function(){'
- 'return this.$selfField.$stubName(this.$receiverField);'
+ 'return this.$interceptorField.$stubName(this.$receiverField);'
'${functionCounter++}'
'}');
}
@@ -2322,7 +2299,7 @@
'',
'(new Function(#))()',
'return function($arguments){'
- 'return this.$selfField.$stubName(this.$receiverField, $arguments);'
+ 'return this.$interceptorField.$stubName(this.$receiverField, $arguments);'
'${functionCounter++}'
'}');
}
@@ -2375,13 +2352,12 @@
/// This is a base class that is extended to create a separate closure class for
/// each instance method. The subclass is created at run time.
class BoundClosure extends TearOffClosure {
- /// The JavaScript receiver, which is the Dart receiver or the interceptor.
- final _self;
-
- /// The Dart receiver if [_target] is an intercepted method (in which case
- /// [_self] is the interceptor), otherwise `null`.
+ /// The Dart receiver.
final _receiver;
+ /// The JavaScript receiver when using the interceptor calling convention.
+ final _interceptor;
+
/// The [_name] and [_target] of the bound closure are stored in the prototype
/// of the closure class (i.e. the subclass of BoundClosure).
static const nameProperty = r'$_name';
@@ -2393,72 +2369,55 @@
/// The primary entry point for the instance method, used by `==`/`hashCode`.
Object get _target => JS('', '#.#', this, targetProperty);
- BoundClosure(this._self, this._receiver);
+ BoundClosure(this._receiver, this._interceptor);
- bool operator ==(other) {
+ @override
+ bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! BoundClosure) return false;
- return JS('bool', '# === #', _self, other._self) &&
- JS('bool', '# === #', _target, other._target) &&
+ return JS('bool', '# === #', _target, other._target) &&
JS('bool', '# === #', _receiver, other._receiver);
}
+ @override
int get hashCode {
- int receiverHashCode;
- if (_receiver == null) {
- // A bound closure on a regular Dart object, just use the
- // identity hash code.
- receiverHashCode = Primitives.objectHashCode(_self);
- } else if (JS('String', 'typeof #', _receiver) != 'object') {
- // A bound closure on a primitive JavaScript type. We
- // use the hashCode method we define for those primitive types.
- receiverHashCode = _receiver.hashCode;
- } else {
- // A bound closure on an intercepted native class, just use the
- // identity hash code.
- receiverHashCode = Primitives.objectHashCode(_receiver);
- }
+ int receiverHashCode = objectHashCode(_receiver);
return receiverHashCode ^ Primitives.objectHashCode(_target);
}
- toString() {
- var receiver = _receiver == null ? _self : _receiver;
+ @override
+ String toString() {
// TODO(sra): When minified, mark [_name] with a tag,
// e.g. 'minified-property:' so that it can be unminified.
return "Closure '$_name' of "
- "${Primitives.objectToHumanReadableString(receiver)}";
+ "${Primitives.objectToHumanReadableString(_receiver)}";
}
@pragma('dart2js:parameter:trust')
static evalRecipe(BoundClosure closure, String recipe) {
- return newRti.evalInInstance(closure._self, recipe);
- }
-
- @pragma('dart2js:parameter:trust')
- static evalRecipeIntercepted(BoundClosure closure, String recipe) {
return newRti.evalInInstance(closure._receiver, recipe);
}
@pragma('dart2js:noInline')
@pragma('dart2js:parameter:trust')
- static selfOf(BoundClosure closure) => closure._self;
+ static receiverOf(BoundClosure closure) => closure._receiver;
@pragma('dart2js:noInline')
@pragma('dart2js:parameter:trust')
- static receiverOf(BoundClosure closure) => closure._receiver;
-
- static String? _selfFieldNameCache;
- static String selfFieldName() =>
- _selfFieldNameCache ??= _computeFieldNamed('self');
+ static interceptorOf(BoundClosure closure) => closure._interceptor;
static String? _receiverFieldNameCache;
static String receiverFieldName() =>
_receiverFieldNameCache ??= _computeFieldNamed('receiver');
+ static String? _interceptorFieldNameCache;
+ static String interceptorFieldName() =>
+ _interceptorFieldNameCache ??= _computeFieldNamed('interceptor');
+
@pragma('dart2js:noInline')
@pragma('dart2js:noSideEffects')
static String _computeFieldNamed(String fieldName) {
- var template = new BoundClosure('self', 'receiver');
+ var template = new BoundClosure('receiver', 'interceptor');
var names = JSArray.markFixedList(
JS('', 'Object.getOwnPropertyNames(#)', template));
for (int i = 0; i < names.length; i++) {
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 96fc0a8..694bc1d 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -334,7 +334,7 @@
}
static Rti allocate() {
- return new Rti();
+ return Rti();
}
Object? _canonicalRecipe;
@@ -2974,86 +2974,94 @@
String sName = Rti._getInterfaceName(s);
String tName = Rti._getInterfaceName(t);
- // Interface Compositionality:
- if (sName == tName) {
- var sArgs = Rti._getInterfaceTypeArguments(s);
- var tArgs = Rti._getInterfaceTypeArguments(t);
- int length = _Utils.arrayLength(sArgs);
- assert(length == _Utils.arrayLength(tArgs));
+ while (sName != tName) {
+ // The Super-Interface rule says that if [s] has superinterfaces C0,...,Cn,
+ // then we need to check if for some i, Ci <: [t]. However, this requires us
+ // to iterate over the superinterfaces. Instead, we can perform case
+ // analysis on [t]. By this point, [t] can only be Never, a type variable,
+ // or an interface type. (Bindings do not participate in subtype checks and
+ // all other cases have been eliminated.) If [t] is not an interface, then
+ // [s] </: [t]. Therefore, the only remaining case is that [t] is an
+ // interface, so rather than iterating over the Ci, we can instead look up
+ // [t] in our ruleset.
+ // TODO(fishythefish): Handle variance correctly.
- var sVariances;
- bool? hasVariances;
- if (JS_GET_FLAG("VARIANCE")) {
- sVariances = _Universe.findTypeParameterVariances(universe, sName);
- hasVariances = sVariances != null;
- assert(!hasVariances || length == _Utils.arrayLength(sVariances));
+ var rule = _Universe._findRule(universe, sName);
+ if (rule == null) return false;
+ if (_Utils.isString(rule)) {
+ sName = _Utils.asString(rule);
+ continue;
}
+ var recipes = TypeRule.lookupSupertype(rule, tName);
+ if (recipes == null) return false;
+ int length = _Utils.arrayLength(recipes);
+ Object? supertypeArgs = length > 0 ? JS('', 'new Array(#)', length) : null;
for (int i = 0; i < length; i++) {
- Rti sArg = _Utils.asRti(_Utils.arrayAt(sArgs, i));
- Rti tArg = _Utils.asRti(_Utils.arrayAt(tArgs, i));
- if (JS_GET_FLAG("VARIANCE")) {
- int sVariance = hasVariances != null
- ? _Utils.asInt(_Utils.arrayAt(sVariances, i))
- : Variance.legacyCovariant;
- switch (sVariance) {
- case Variance.legacyCovariant:
- case Variance.covariant:
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) {
- return false;
- }
- break;
- case Variance.contravariant:
- if (!_isSubtype(universe, tArg, tEnv, sArg, sEnv)) {
- return false;
- }
- break;
- case Variance.invariant:
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv) ||
- !_isSubtype(universe, tArg, tEnv, sArg, sEnv)) {
- return false;
- }
- break;
- default:
- throw StateError(
- "Unknown variance given for subtype check: $sVariance");
- }
- } else {
- if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) {
- return false;
- }
- }
+ String recipe = _Utils.asString(_Utils.arrayAt(recipes, i));
+ Rti supertypeArg = _Universe.evalInEnvironment(universe, s, recipe);
+ _Utils.arraySetAt(supertypeArgs, i, supertypeArg);
}
- return true;
+ var tArgs = Rti._getInterfaceTypeArguments(t);
+ return _areArgumentsSubtypes(
+ universe, supertypeArgs, null, sEnv, tArgs, tEnv);
}
- // The Super-Interface rule says that if [s] has superinterfaces C0,...,Cn,
- // then we need to check if for some i, Ci <: [t]. However, this requires us
- // to iterate over the superinterfaces. Instead, we can perform case
- // analysis on [t]. By this point, [t] can only be Never, a type variable,
- // or an interface type. (Bindings do not participate in subtype checks and
- // all other cases have been eliminated.) If [t] is not an interface, then
- // [s] </: [t]. Therefore, the only remaining case is that [t] is an
- // interface, so rather than iterating over the Ci, we can instead look up
- // [t] in our ruleset.
- // TODO(fishythefish): Handle variance correctly.
-
- // We don't list Object explicitly as a supertype of each interface, so check
- // this trivial case first.
- if (isObjectType(t)) return true;
- var rule = _Universe.findRule(universe, sName);
- if (rule == null) return false;
- var supertypeArgs = TypeRule.lookupSupertype(rule, tName);
- if (supertypeArgs == null) return false;
- int length = _Utils.arrayLength(supertypeArgs);
+ // Interface Compositionality:
+ assert(sName == tName);
+ var sArgs = Rti._getInterfaceTypeArguments(s);
var tArgs = Rti._getInterfaceTypeArguments(t);
+ var sVariances;
+ if (JS_GET_FLAG("VARIANCE")) {
+ sVariances = _Universe.findTypeParameterVariances(universe, sName);
+ }
+ return _areArgumentsSubtypes(universe, sArgs, sVariances, sEnv, tArgs, tEnv);
+}
+
+bool _areArgumentsSubtypes(Object? universe, Object? sArgs, Object? sVariances,
+ Object? sEnv, Object? tArgs, Object? tEnv) {
+ int length = sArgs != null ? _Utils.arrayLength(sArgs) : 0;
assert(length == _Utils.arrayLength(tArgs));
+ bool hasVariances = sVariances != null;
+ if (JS_GET_FLAG("VARIANCE")) {
+ assert(!hasVariances || length == _Utils.arrayLength(sVariances));
+ } else {
+ assert(!hasVariances);
+ }
+
for (int i = 0; i < length; i++) {
- String recipe = _Utils.asString(_Utils.arrayAt(supertypeArgs, i));
- Rti supertypeArg = _Universe.evalInEnvironment(universe, s, recipe);
+ Rti sArg = _Utils.asRti(_Utils.arrayAt(sArgs, i));
Rti tArg = _Utils.asRti(_Utils.arrayAt(tArgs, i));
- if (!_isSubtype(universe, supertypeArg, sEnv, tArg, tEnv)) {
- return false;
+ if (JS_GET_FLAG("VARIANCE")) {
+ int sVariance = hasVariances
+ ? _Utils.asInt(_Utils.arrayAt(sVariances, i))
+ : Variance.legacyCovariant;
+ switch (sVariance) {
+ case Variance.legacyCovariant:
+ case Variance.covariant:
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) {
+ return false;
+ }
+ break;
+ case Variance.contravariant:
+ if (!_isSubtype(universe, tArg, tEnv, sArg, sEnv)) {
+ return false;
+ }
+ break;
+ case Variance.invariant:
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv) ||
+ !_isSubtype(universe, tArg, tEnv, sArg, sEnv)) {
+ return false;
+ }
+ break;
+ default:
+ throw StateError(
+ "Unknown variance given for subtype check: $sVariance");
+ }
+ } else {
+ if (!_isSubtype(universe, sArg, sEnv, tArg, tEnv)) {
+ return false;
+ }
}
}
return true;
diff --git a/tests/web/internal/rti/js_interop_subtype_test.dart b/tests/web/internal/rti/js_interop_subtype_test.dart
new file mode 100644
index 0000000..66010da
--- /dev/null
+++ b/tests/web/internal/rti/js_interop_subtype_test.dart
@@ -0,0 +1,22 @@
+// 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 'dart:_interceptors';
+
+import 'package:expect/expect.dart';
+import 'package:js/js.dart';
+
+@JS()
+class JSClass {}
+
+@JS()
+external void eval(String code);
+
+void main() {
+ eval(r'''
+ function JSClass() {}
+ ''');
+ Expect.type<JavaScriptObject>(JSClass());
+ Expect.type<List<JavaScriptObject>>(<JSClass>[]);
+}
diff --git a/tests/web_2/internal/rti/js_interop_subtype_test.dart b/tests/web_2/internal/rti/js_interop_subtype_test.dart
new file mode 100644
index 0000000..66010da
--- /dev/null
+++ b/tests/web_2/internal/rti/js_interop_subtype_test.dart
@@ -0,0 +1,22 @@
+// 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 'dart:_interceptors';
+
+import 'package:expect/expect.dart';
+import 'package:js/js.dart';
+
+@JS()
+class JSClass {}
+
+@JS()
+external void eval(String code);
+
+void main() {
+ eval(r'''
+ function JSClass() {}
+ ''');
+ Expect.type<JavaScriptObject>(JSClass());
+ Expect.type<List<JavaScriptObject>>(<JSClass>[]);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 54a920f..37cbba7 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 249
+PRERELEASE 250
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index b2b13ea..5ed68a5 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -1320,12 +1320,61 @@
},
{
"builders": [
+ "vm-kernel-precomp-nnbd-mac-release-arm64"
+ ],
+ "meta": {
+ "description": "This configuration is for the macOS arm64 VM AOT nnbd builder group."
+ },
+ "steps": [
+ {
+ "name": "build dart",
+ "script": "tools/build.py",
+ "arguments": [
+ "runtime_kernel",
+ "dart_precompiled_runtime",
+ "gen_snapshot"
+ ]
+ },
+ {
+ "name": "vm nnbd tests in weak mode with asserts",
+ "arguments": [
+ "-ndartkp-weak-asserts-${system}-${mode}-${arch}",
+ "benchmark_smoke",
+ "corelib",
+ "ffi",
+ "language",
+ "lib",
+ "samples",
+ "service",
+ "standalone",
+ "utils",
+ "vm"
+ ]
+ },
+ {
+ "name": "vm nnbd tests in strong mode",
+ "arguments": [
+ "-ndartkp-strong-${system}-${mode}-${arch}",
+ "benchmark_smoke",
+ "corelib",
+ "ffi",
+ "language",
+ "lib",
+ "samples",
+ "standalone",
+ "utils",
+ "vm"
+ ]
+ }
+ ]
+ },
+ {
+ "builders": [
"vm-kernel-precomp-nnbd-linux-debug-x64",
"vm-kernel-precomp-nnbd-linux-release-simarm64",
"vm-kernel-precomp-nnbd-linux-release-simarm64c",
"vm-kernel-precomp-nnbd-linux-release-x64",
"vm-kernel-precomp-nnbd-linux-release-x64c",
- "vm-kernel-precomp-nnbd-mac-release-arm64",
"vm-kernel-precomp-nnbd-mac-release-simarm64",
"vm-kernel-precomp-nnbd-mac-release-simarm64c",
"vm-kernel-precomp-nnbd-win-release-x64",