37e351db10
Discarding the nullability caused us to assume that interop checks were always needed below. Bug: b/353690007 Fixes: b/353690007 Change-Id: I085f98c06d2e91412c5c6e795359eb2df4d84d5b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/376124 Reviewed-by: Nate Biggs <natebiggs@google.com> Commit-Queue: Mayank Patke <fishythefish@google.com>
1148 lines
42 KiB
Dart
1148 lines
42 KiB
Dart
// Copyright (c) 2024, 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:expect/expect.dart';
|
|
import 'package:js/js.dart';
|
|
|
|
const dart2js = const bool.fromEnvironment('dart.library._dart2js_only');
|
|
const ddc = const bool.fromEnvironment('dart.library._ddc_only');
|
|
|
|
dynamic obj;
|
|
|
|
@JS()
|
|
external dynamic eval(String code);
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external String returnsNull();
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external String returnsNullInlined();
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external String returnsUndefined();
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external String returnsUndefinedInlined();
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external int get getsNull;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external int get getsNullInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external int get undefinedGetter;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external int get undefinedGetterInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external double Function() get getterFunctionReturnsNull;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external double Function() get getterFunctionReturnsNullInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external double Function() get getterFunctionReturnsUndefined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external double Function() get getterFunctionReturnsUndefinedInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external bool nullField;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external bool nullFieldInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external bool undefinedField;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external bool undefinedFieldInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external int? nullableFunction();
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? nullableFunctionInlined();
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external int? get nullableGetter;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? get nullableGetterInlined;
|
|
|
|
@JS()
|
|
@pragma('dart2js:never-inline')
|
|
external int? nullableField;
|
|
|
|
@JS()
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? nullableFieldInlined;
|
|
|
|
@JS()
|
|
@anonymous
|
|
class SomeClass {
|
|
@pragma('dart2js:never-inline')
|
|
external String returnsNull();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external String returnsNullInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external String returnsUndefined();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external String returnsUndefinedInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int get getsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int get getsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int get undefinedGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int get undefinedGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external double Function() get getterFunctionReturnsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external double Function() get getterFunctionReturnsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external double Function() get getterFunctionReturnsUndefined;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external double Function() get getterFunctionReturnsUndefinedInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external bool nullField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external bool nullFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external bool undefinedField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external bool undefinedFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int? nullableFunction();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? nullableFunctionInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int? get nullableGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? get nullableGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int? nullableField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? nullableFieldInlined;
|
|
}
|
|
|
|
@JS()
|
|
@anonymous
|
|
class AnotherClass {
|
|
@pragma('dart2js:never-inline')
|
|
external static String staticReturnsNull();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static String staticReturnsNullInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static String staticReturnsUndefined();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static String staticReturnsUndefinedInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int get staticGetsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int get staticGetsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int get staticUndefinedGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int get staticUndefinedGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static double Function() get staticGetterFunctionReturnsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static double Function() get staticGetterFunctionReturnsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static double Function() get staticGetterFunctionReturnsUndefined;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static double Function()
|
|
get staticGetterFunctionReturnsUndefinedInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static bool staticNullField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static bool staticNullFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static bool staticUndefinedField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static bool staticUndefinedFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int? staticNullableFunction();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int? staticNullableFunctionInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int? get staticNullableGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int? get staticNullableGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int? staticNullableField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int? staticNullableFieldInlined;
|
|
}
|
|
|
|
@JS()
|
|
class NamedClass {
|
|
@pragma('dart2js:never-inline')
|
|
external String returnsNull();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external String returnsNullInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external String returnsUndefined();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external String returnsUndefinedInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static String staticReturnsNull();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static String staticReturnsNullInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static String staticReturnsUndefined();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static String staticReturnsUndefinedInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int get getsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int get getsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int get undefinedGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int get undefinedGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int get staticGetsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int get staticGetsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int get staticUndefinedGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int get staticUndefinedGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external double Function() get getterFunctionReturnsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external double Function() get getterFunctionReturnsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external double Function() get getterFunctionReturnsUndefined;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external double Function() get getterFunctionReturnsUndefinedInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static double Function() get staticGetterFunctionReturnsNull;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static double Function() get staticGetterFunctionReturnsNullInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static double Function() get staticGetterFunctionReturnsUndefined;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static double Function()
|
|
get staticGetterFunctionReturnsUndefinedInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external bool nullField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external bool nullFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external bool undefinedField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external bool undefinedFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int? nullableFunction();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? nullableFunctionInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int? get nullableGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? get nullableGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external int? nullableField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external int? nullableFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static bool staticNullField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static bool staticNullFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static bool staticUndefinedField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static bool staticUndefinedFieldInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int? staticNullableFunction();
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int? staticNullableFunctionInlined();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int? get staticNullableGetter;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int? get staticNullableGetterInlined;
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external static int? staticNullableField;
|
|
|
|
@pragma('dart2js:prefer-inline')
|
|
external static int? staticNullableFieldInlined;
|
|
|
|
external factory NamedClass.createNamedClass();
|
|
}
|
|
|
|
@JS()
|
|
external SomeClass createSomeClass();
|
|
|
|
void topLevelMemberTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
eval(r'self.returnsNull = function() { return null; }');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => returnsNull());
|
|
|
|
eval(r'self.returnsUndefined = function() { return void 0; }');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => returnsUndefined());
|
|
|
|
var functionTearoff = returnsNull;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
functionTearoff = returnsUndefined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
|
|
eval(r'self.getsNull = null;');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => getsNull);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => undefinedGetter);
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
eval(r'self.getterFunctionReturnsNull = function() { return null; };');
|
|
Expect.isNull(getterFunctionReturnsNull());
|
|
var getterFunction = getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
|
|
eval(r'self.getterFunctionReturnsUndefined = function() { '
|
|
'return void 0; };');
|
|
Expect.isNull(getterFunctionReturnsUndefined());
|
|
getterFunction = getterFunctionReturnsUndefined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
eval(r'self.nullField = null;');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => nullField);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => undefinedField);
|
|
|
|
eval(r'self.nullableFunction = function() { return null; };');
|
|
Expect.isNull(nullableFunction());
|
|
|
|
eval(r'self.nullableGetter = null;');
|
|
Expect.isNull(nullableGetter);
|
|
|
|
eval(r'self.nullableField = null;');
|
|
Expect.isNull(nullableField);
|
|
}
|
|
|
|
void inlinedTopLevelMemberTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
eval(r'self.returnsNullInlined = function() { return null; }');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => returnsNullInlined());
|
|
|
|
eval(r'self.returnsUndefinedInlined = function() { return void 0; }');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => returnsUndefinedInlined());
|
|
|
|
var functionTearoff = returnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
functionTearoff = returnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
|
|
eval(r'self.getsNullInlined = null;');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => getsNullInlined);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => undefinedGetterInlined);
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
eval(r'self.getterFunctionReturnsNullInlined = function() { return null; };');
|
|
Expect.isNull(getterFunctionReturnsNullInlined());
|
|
var getterFunction = getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
eval(r'self.getterFunctionReturnsUndefinedInlined = function() { '
|
|
'return void 0; };');
|
|
Expect.isNull(getterFunctionReturnsUndefinedInlined());
|
|
getterFunction = getterFunctionReturnsUndefinedInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
eval(r'self.nullFieldInlined = null;');
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => nullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => undefinedFieldInlined);
|
|
|
|
eval(r'self.nullableFunctionInlined = function() { return null; };');
|
|
Expect.isNull(nullableFunctionInlined());
|
|
|
|
eval(r'self.nullableGetterInlined = null;');
|
|
Expect.isNull(nullableGetterInlined);
|
|
|
|
eval(r'self.nullableFieldInlined = null;');
|
|
Expect.isNull(nullableFieldInlined);
|
|
}
|
|
|
|
void anonymousClassSetup() {
|
|
eval(r'''self.createSomeClass = function() {
|
|
return {
|
|
"returnsNull": function() { return null; },
|
|
"returnsNullInlined": function() { return null; },
|
|
"returnsUndefined": function() { return void 0; },
|
|
"returnsUndefinedInlined": function() { return void 0; },
|
|
"getsNull" : null,
|
|
"getsNullInlined" : null,
|
|
"jsGetsNull": { get: function() { return null; } },
|
|
"jsGetsNullInlined": { get: function() { return null; } },
|
|
"jsGetsUndefined": { get: function() { return void 0; } },
|
|
"jsGetsUndefinedInlined": { get: function() { return void 0; } },
|
|
"getterFunctionReturnsNull": function() { return null; },
|
|
"getterFunctionReturnsNullInlined": function() { return null; },
|
|
"getterFunctionReturnsUndefined": function() { return void 0; },
|
|
"getterFunctionReturnsUndefinedInlined": function() { return void 0; },
|
|
"nullField" : null,
|
|
"nullFieldInlined" : null,
|
|
"nullableFunction": function() { return null; },
|
|
"nullableFunctionInlined": function() { return null; },
|
|
"nullableGetter": null,
|
|
"nullableGetterInlined": null,
|
|
"nullableField": null,
|
|
"nullableFieldInlined": null,
|
|
};
|
|
};
|
|
''');
|
|
|
|
eval(r'''self.AnotherClass = class AnotherClass {
|
|
static staticReturnsNull() { return null; }
|
|
static staticReturnsNullInlined() { return null; }
|
|
static staticReturnsUndefined() { return void 0; }
|
|
static staticReturnsUndefinedInlined() { return void 0; }
|
|
static get staticGetsNull() { return null; }
|
|
static get staticGetsNullInlined() { return null; }
|
|
static get staticGetterFunctionReturnsNull() {
|
|
return function() { return null; };
|
|
}
|
|
static get staticGetterFunctionReturnsNullInlined() {
|
|
return function() { return null; };
|
|
}
|
|
static get staticGetterFunctionReturnsUndefined() {
|
|
return function() { return void 0; };
|
|
}
|
|
static get staticGetterFunctionReturnsUndefinedInlined() {
|
|
return function() { return void 0; };
|
|
}
|
|
static staticNullableFunction() { return null; }
|
|
static staticNullableFunctionInlined() { return null; }
|
|
static get staticNullableGetter() { return null; }
|
|
static get staticNullableGetterInlined() { return null; }
|
|
static staticNullableField = null;
|
|
static staticNullableFieldInlined = null;
|
|
};''');
|
|
}
|
|
|
|
void anonymousClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
var x = createSomeClass();
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.returnsNull());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.returnsUndefined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = x.returnsNull;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
functionTearoff = x.returnsUndefined;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.getsNull);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.undefinedGetter);
|
|
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => x.getterFunctionReturnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => x.getterFunctionReturnsUndefined());
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = x.getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = x.getterFunctionReturnsUndefined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.nullField);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.undefinedField);
|
|
|
|
Expect.isNull(x.nullableFunction());
|
|
Expect.isNull(x.nullableGetter);
|
|
Expect.isNull(x.nullableField);
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticReturnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticReturnsUndefined());
|
|
functionTearoff = AnotherClass.staticReturnsNull;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
functionTearoff = AnotherClass.staticReturnsUndefined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => AnotherClass.staticGetsNull);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticUndefinedGetter);
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
Expect.isNull(AnotherClass.staticGetterFunctionReturnsNull());
|
|
Expect.isNull(AnotherClass.staticGetterFunctionReturnsUndefined());
|
|
getterFunction = AnotherClass.staticGetterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = AnotherClass.staticGetterFunctionReturnsUndefined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => AnotherClass.staticNullField);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticUndefinedField);
|
|
|
|
Expect.isNull(AnotherClass.staticNullableFunction());
|
|
Expect.isNull(AnotherClass.staticNullableGetter);
|
|
Expect.isNull(AnotherClass.staticNullableField);
|
|
}
|
|
|
|
void inlinedAnonymousClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
var x = createSomeClass();
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.returnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.returnsUndefinedInlined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = x.returnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
functionTearoff = x.returnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.getsNullInlined);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.undefinedGetterInlined);
|
|
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => x.getterFunctionReturnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => x.getterFunctionReturnsUndefinedInlined());
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = x.getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = x.getterFunctionReturnsUndefinedInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.nullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => x.undefinedFieldInlined);
|
|
|
|
Expect.isNull(x.nullableFunctionInlined());
|
|
Expect.isNull(x.nullableGetterInlined);
|
|
Expect.isNull(x.nullableFieldInlined);
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticReturnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticReturnsUndefinedInlined());
|
|
functionTearoff = AnotherClass.staticReturnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
functionTearoff = AnotherClass.staticReturnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticGetsNullInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticUndefinedGetterInlined);
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
Expect.isNull(AnotherClass.staticGetterFunctionReturnsNullInlined());
|
|
Expect.isNull(AnotherClass.staticGetterFunctionReturnsUndefinedInlined());
|
|
getterFunction = AnotherClass.staticGetterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = AnotherClass.staticGetterFunctionReturnsUndefinedInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticNullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => AnotherClass.staticUndefinedFieldInlined);
|
|
|
|
Expect.isNull(AnotherClass.staticNullableFunctionInlined());
|
|
Expect.isNull(AnotherClass.staticNullableGetterInlined);
|
|
Expect.isNull(AnotherClass.staticNullableFieldInlined);
|
|
}
|
|
|
|
// DDC does not perform checks for dynamic invocations.
|
|
void dynamicAnonymousClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
obj = createSomeClass();
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled, () => obj.returnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.returnsUndefined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = obj.returnsNull;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
functionTearoff = obj.returnsUndefined;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled, () => obj.getsNull);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedGetter);
|
|
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getterFunctionReturnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getterFunctionReturnsUndefined());
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = obj.getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = obj.getterFunctionReturnsUndefined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled, () => obj.nullField);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedField);
|
|
|
|
Expect.isNull(obj.nullableFunction());
|
|
Expect.isNull(obj.nullableGetter);
|
|
Expect.isNull(obj.nullableField);
|
|
}
|
|
|
|
// DDC does not perform checks for dynamic invocations.
|
|
void dynamicInlinedAnonymousClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
obj = createSomeClass();
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.returnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.returnsUndefinedInlined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = obj.returnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
functionTearoff = obj.returnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getsNullInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedGetterInlined);
|
|
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getterFunctionReturnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled,
|
|
() => obj.getterFunctionReturnsUndefinedInlined());
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = obj.getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = obj.getterFunctionReturnsUndefinedInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.nullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedFieldInlined);
|
|
|
|
Expect.isNull(obj.nullableFunctionInlined());
|
|
Expect.isNull(obj.nullableGetterInlined);
|
|
Expect.isNull(obj.nullableFieldInlined);
|
|
}
|
|
|
|
void namedClassSetup() {
|
|
eval(r'''self.NamedClass = class NamedClass {
|
|
returnsNull() { return null; }
|
|
returnsNullInlined() { return null; }
|
|
returnsUndefined() { return void 0; }
|
|
returnsUndefinedInlined() { return void 0; }
|
|
static staticReturnsNull() { return null; }
|
|
static staticReturnsNullInlined() { return null; }
|
|
static staticReturnsUndefined() { return void 0; }
|
|
static staticReturnsUndefinedInlined() { return void 0; }
|
|
get getsNull() { return null; }
|
|
get getsNullInlined() { return null; }
|
|
static get staticGetsNull() { return null; }
|
|
static get staticGetsNullInlined() { return null; }
|
|
get getterFunctionReturnsNull() {
|
|
return function() { return null; };
|
|
}
|
|
get getterFunctionReturnsNullInlined() {
|
|
return function() { return null; };
|
|
}
|
|
get getterFunctionReturnsUndefined() {
|
|
return function() { return void 0; };
|
|
}
|
|
get getterFunctionReturnsUndefinedInlined() {
|
|
return function() { return void 0; };
|
|
}
|
|
static get staticGetterFunctionReturnsNull() {
|
|
return function() { return null; };
|
|
}
|
|
static get staticGetterFunctionReturnsNullInlined() {
|
|
return function() { return null; };
|
|
}
|
|
static get staticGetterFunctionReturnsUndefined() {
|
|
return function() { return void 0; };
|
|
}
|
|
static get staticGetterFunctionReturnsUndefinedInlined() {
|
|
return function() { return void 0; };
|
|
}
|
|
nullableFunction() { return null; }
|
|
nullableFunctionInlined() { return null; }
|
|
get nullableGetter() { return null; }
|
|
get nullableGetterInlined() { return null; }
|
|
nullableField = null;
|
|
nullableFieldInlined = null;
|
|
static staticNullableFunction() { return null; }
|
|
static staticNullableFunctionInlined() { return null; }
|
|
static get staticNullableGetter() { return null; }
|
|
static get staticNullableGetterInlined() { return null; }
|
|
static staticNullableField = null;
|
|
static staticNullableFieldInlined = null;
|
|
static createNamedClass() { return new NamedClass(); }
|
|
};''');
|
|
}
|
|
|
|
void namedClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
var y = NamedClass.createNamedClass();
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.returnsNull());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.returnsUndefined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = y.returnsNull;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
functionTearoff = y.returnsUndefined;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticReturnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticReturnsUndefined());
|
|
functionTearoff = NamedClass.staticReturnsNull;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
functionTearoff = NamedClass.staticReturnsUndefined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.getsNull);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.undefinedGetter);
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => y.getterFunctionReturnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => y.getterFunctionReturnsUndefined());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => NamedClass.staticGetsNull);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticUndefinedGetter);
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = y.getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = y.getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
Expect.isNull(NamedClass.staticGetterFunctionReturnsNull());
|
|
Expect.isNull(NamedClass.staticGetterFunctionReturnsUndefined());
|
|
getterFunction = NamedClass.staticGetterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = NamedClass.staticGetterFunctionReturnsUndefined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.nullField);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.undefinedField);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => NamedClass.staticNullField);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticUndefinedField);
|
|
|
|
Expect.isNull(y.nullableFunction());
|
|
Expect.isNull(y.nullableGetter);
|
|
Expect.isNull(y.nullableField);
|
|
Expect.isNull(NamedClass.staticNullableFunction());
|
|
Expect.isNull(NamedClass.staticNullableGetter);
|
|
Expect.isNull(NamedClass.staticNullableField);
|
|
}
|
|
|
|
void inlinedNamedClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
var y = NamedClass.createNamedClass();
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.returnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.returnsUndefinedInlined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = y.returnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
functionTearoff = y.returnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(ddc && checksEnabled, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticReturnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticReturnsUndefinedInlined());
|
|
functionTearoff = NamedClass.staticReturnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
functionTearoff = NamedClass.staticReturnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => functionTearoff());
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.getsNullInlined);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.undefinedGetterInlined);
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => y.getterFunctionReturnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => y.getterFunctionReturnsUndefinedInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticGetsNullInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticUndefinedGetterInlined);
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = y.getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = y.getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
Expect.isNull(NamedClass.staticGetterFunctionReturnsNullInlined());
|
|
Expect.isNull(NamedClass.staticGetterFunctionReturnsUndefinedInlined());
|
|
getterFunction = NamedClass.staticGetterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = NamedClass.staticGetterFunctionReturnsUndefinedInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.nullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => y.undefinedFieldInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticNullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
checksEnabled, () => NamedClass.staticUndefinedFieldInlined);
|
|
|
|
Expect.isNull(y.nullableFunctionInlined());
|
|
Expect.isNull(y.nullableGetterInlined);
|
|
Expect.isNull(y.nullableFieldInlined);
|
|
Expect.isNull(NamedClass.staticNullableFunctionInlined());
|
|
Expect.isNull(NamedClass.staticNullableGetterInlined);
|
|
Expect.isNull(NamedClass.staticNullableFieldInlined);
|
|
}
|
|
|
|
// DDC does not perform checks for dynamic invocations.
|
|
void dynamicNamedClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
obj = NamedClass.createNamedClass();
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled, () => obj.returnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.returnsUndefined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = obj.returnsNull;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
functionTearoff = obj.returnsUndefined;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled, () => obj.getsNull);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedGetter);
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getterFunctionReturnsNull());
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getterFunctionReturnsUndefined());
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = obj.getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = obj.getterFunctionReturnsNull;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled, () => obj.nullField);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedField);
|
|
|
|
Expect.isNull(obj.nullableFunction());
|
|
Expect.isNull(obj.nullableGetter);
|
|
Expect.isNull(obj.nullableField);
|
|
}
|
|
|
|
// DDC does not perform checks for dynamic invocations.
|
|
void dynamicInlinedNamedClassTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
obj = NamedClass.createNamedClass();
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.returnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.returnsUndefinedInlined());
|
|
|
|
// In dart2js, a tearoff of an interop method is indistinguishable from a
|
|
// getter returning the underlying function.
|
|
var functionTearoff = obj.returnsNullInlined;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
functionTearoff = obj.returnsUndefinedInlined;
|
|
Expect.throwsTypeErrorWhen(false, () => functionTearoff());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getsNullInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedGetterInlined);
|
|
// Immediate invocations of instance getters are seen as function calls so
|
|
// the results get checked.
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.getterFunctionReturnsNullInlined());
|
|
Expect.throwsTypeErrorWhen(dart2js && checksEnabled,
|
|
() => obj.getterFunctionReturnsUndefinedInlined());
|
|
|
|
// At the time this test was written, getters that return function types don't
|
|
// get the same wrappers as function tearoffs so there isn't an opportunity to
|
|
// check the return values so they can still leak null or undefined through
|
|
// from the JavaScript side.
|
|
var getterFunction = obj.getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
getterFunction = obj.getterFunctionReturnsNullInlined;
|
|
Expect.isNull(getterFunction());
|
|
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.nullFieldInlined);
|
|
Expect.throwsTypeErrorWhen(
|
|
dart2js && checksEnabled, () => obj.undefinedFieldInlined);
|
|
|
|
Expect.isNull(obj.nullableFunctionInlined());
|
|
Expect.isNull(obj.nullableGetterInlined);
|
|
Expect.isNull(obj.nullableFieldInlined);
|
|
}
|
|
|
|
@JS()
|
|
class CollisionA {
|
|
@pragma('dart2js:prefer-inline')
|
|
external String foo([int? x]);
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external String bar([int? x]);
|
|
|
|
external factory CollisionA.create();
|
|
}
|
|
|
|
@JS()
|
|
class CollisionB {
|
|
@pragma('dart2js:prefer-inline')
|
|
external String? foo();
|
|
|
|
@pragma('dart2js:never-inline')
|
|
external String? bar();
|
|
|
|
external factory CollisionB.create();
|
|
}
|
|
|
|
void collisionClassSetup() {
|
|
eval(r'''
|
|
self.CollisionA = class CollisionA {
|
|
foo(x) { return null; }
|
|
bar(x) { return null; }
|
|
static create() { return new CollisionA(); }
|
|
};
|
|
|
|
self.CollisionB = class CollisionB {
|
|
foo() { return null; }
|
|
bar() { return null; }
|
|
static create() { return new CollisionB(); }
|
|
};''');
|
|
}
|
|
|
|
void collisionTests({required bool checksEnabled}) {
|
|
// Provide at least one nullable value to [Expect.isNull] so that dart2js
|
|
// doesn't discard the branch.
|
|
Expect.isNull(null);
|
|
|
|
var a = CollisionA.create();
|
|
var b = CollisionB.create();
|
|
|
|
// In dart2js, the receiver type is erased to `LegacyJavaScriptObject`, so we
|
|
// cannot identify which class's method is being invoked and cannot emit a
|
|
// null check. DDC is able to identify the member being invoked.
|
|
Expect.throwsTypeErrorWhen(checksEnabled && ddc, () => a.foo());
|
|
Expect.throwsTypeErrorWhen(checksEnabled && ddc, () => a.bar());
|
|
|
|
Expect.isNull(b.foo());
|
|
Expect.isNull(b.bar());
|
|
|
|
// Because `foo$1` and `bar$1` only exist for [CollisionA] and not
|
|
// [CollisionB], dart2js still emits these checks in the callee.
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => a.foo(42));
|
|
Expect.throwsTypeErrorWhen(checksEnabled, () => a.bar(42));
|
|
}
|
|
|
|
void runTests({required bool checksEnabled}) {
|
|
topLevelMemberTests(checksEnabled: checksEnabled);
|
|
inlinedTopLevelMemberTests(checksEnabled: checksEnabled);
|
|
|
|
anonymousClassSetup();
|
|
anonymousClassTests(checksEnabled: checksEnabled);
|
|
inlinedAnonymousClassTests(checksEnabled: checksEnabled);
|
|
dynamicAnonymousClassTests(checksEnabled: checksEnabled);
|
|
dynamicInlinedAnonymousClassTests(checksEnabled: checksEnabled);
|
|
|
|
namedClassSetup();
|
|
namedClassTests(checksEnabled: checksEnabled);
|
|
inlinedNamedClassTests(checksEnabled: checksEnabled);
|
|
dynamicNamedClassTests(checksEnabled: checksEnabled);
|
|
dynamicInlinedNamedClassTests(checksEnabled: checksEnabled);
|
|
|
|
collisionClassSetup();
|
|
collisionTests(checksEnabled: checksEnabled);
|
|
}
|