[pkg:js] Add subtyping tests with liveness

Adds tests for subtyping between pkg:js types. Also runs tests
for both when types are made live and for when they are not.

Also adds these tests to lib_2.

Change-Id: I25fdc293e422eb21fa8a80dea66ae5d492c5aafd
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205601
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Riley Porter <rileyporter@google.com>
Commit-Queue: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
Srujan Gaddam 2021-07-13 18:51:34 +00:00 committed by commit-bot@chromium.org
parent 44ffad59d2
commit 0fc2d929e3
7 changed files with 230 additions and 88 deletions

View file

@ -1,88 +0,0 @@
// Copyright (c) 2020, 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.
// Tests subtyping relationships between JS and anonymous classes.
@JS()
library subtyping_test;
import 'package:js/js.dart';
import 'package:expect/expect.dart' show hasUnsoundNullSafety;
import 'package:expect/minitest.dart';
@JS()
class JSClassA {}
@JS()
class JSClassB {}
@JS()
@anonymous
class AnonymousClassA {}
@JS()
@anonymous
class AnonymousClassB {}
class DartClass {}
void useJSClassA(JSClassA _) {}
void useAnonymousClassA(AnonymousClassA _) {}
void useDartClass(DartClass _) {}
void useNullableJSClassA(JSClassA? _) {}
void useNullableAnonymousClassA(AnonymousClassA? _) {}
// Avoid static type optimization by running all tests using this.
@pragma('dart2js:noInline')
@pragma('dart2js:assumeDynamic')
confuse(x) => x;
void main() {
// Checks subtyping with the same type and nullability subtyping.
expect(useJSClassA is void Function(JSClassA), true);
expect(useAnonymousClassA is void Function(AnonymousClassA), true);
expect(useJSClassA is void Function(JSClassA?), hasUnsoundNullSafety);
expect(useAnonymousClassA is void Function(AnonymousClassA?),
hasUnsoundNullSafety);
expect(useNullableJSClassA is void Function(JSClassA?), true);
expect(useNullableAnonymousClassA is void Function(AnonymousClassA?), true);
expect(useNullableJSClassA is void Function(JSClassA), true);
expect(useNullableAnonymousClassA is void Function(AnonymousClassA), true);
expect(confuse(useJSClassA) is void Function(JSClassA), true);
expect(confuse(useAnonymousClassA) is void Function(AnonymousClassA), true);
expect(
confuse(useJSClassA) is void Function(JSClassA?), hasUnsoundNullSafety);
expect(confuse(useAnonymousClassA) is void Function(AnonymousClassA?),
hasUnsoundNullSafety);
expect(confuse(useNullableJSClassA) is void Function(JSClassA?), true);
expect(confuse(useNullableAnonymousClassA) is void Function(AnonymousClassA?),
true);
expect(confuse(useNullableJSClassA) is void Function(JSClassA), true);
expect(confuse(useNullableAnonymousClassA) is void Function(AnonymousClassA),
true);
// No subtyping between JS and anonymous classes.
expect(useJSClassA is void Function(AnonymousClassA), false);
expect(useAnonymousClassA is void Function(JSClassA), false);
expect(confuse(useJSClassA) is void Function(AnonymousClassA), false);
expect(confuse(useAnonymousClassA) is void Function(JSClassA), false);
// No subtyping between separate classes even if they're both JS classes or
// anonymous classes.
expect(useJSClassA is void Function(JSClassB), false);
expect(useAnonymousClassA is void Function(AnonymousClassB), false);
expect(confuse(useJSClassA) is void Function(JSClassB), false);
expect(confuse(useAnonymousClassA) is void Function(AnonymousClassB), false);
// No subtyping between JS/anonymous classes and Dart classes.
expect(useJSClassA is void Function(DartClass), false);
expect(useAnonymousClassA is void Function(DartClass), false);
expect(confuse(useJSClassA) is void Function(DartClass), false);
expect(confuse(useAnonymousClassA) is void Function(DartClass), false);
}

View file

@ -0,0 +1,20 @@
// 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.
// Tests subtyping relationships after making package:js types live.
@JS()
library subtyping_live_test;
import 'package:js/js.dart';
import 'subtyping_test_util.dart';
@JS()
external dynamic get externalGetter;
void main() {
// Call to foreign function should trigger dart2js to assume types are live.
externalGetter;
testSubtyping();
}

View file

@ -0,0 +1,12 @@
// 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.
// Tests subtyping relationships without making package:js types live.
import 'package:js/js.dart';
import 'subtyping_test_util.dart';
void main() {
testSubtyping();
}

View file

@ -0,0 +1,92 @@
// 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.
// Tests subtyping relationships between JS and anonymous classes.
@JS()
library subtyping_test_util;
import 'package:js/js.dart';
import 'package:expect/expect.dart' show hasUnsoundNullSafety;
import 'package:expect/minitest.dart';
@JS()
class JSClassA {}
@JS()
class JSClassB {}
@JS()
@anonymous
class AnonymousClassA {}
@JS()
@anonymous
class AnonymousClassB {}
class DartClass {}
JSClassA returnJS() => throw '';
JSClassA? returnNullableJS() => throw '';
AnonymousClassA returnAnon() => throw '';
AnonymousClassA? returnNullableAnon() => throw '';
DartClass returnDartClass() => throw '';
// Avoid static type optimization by running all tests using this.
@pragma('dart2js:noInline')
@pragma('dart2js:assumeDynamic')
confuse(x) => x;
void testSubtyping() {
// Checks subtyping with the same type and nullability subtyping.
expect(returnJS is JSClassA Function(), true);
expect(returnAnon is AnonymousClassA Function(), true);
expect(returnJS is JSClassA? Function(), true);
expect(returnAnon is AnonymousClassA? Function(), true);
expect(returnNullableJS is JSClassA? Function(), true);
expect(returnNullableAnon is AnonymousClassA? Function(), true);
expect(returnNullableJS is JSClassA Function(), hasUnsoundNullSafety);
expect(
returnNullableAnon is AnonymousClassA Function(), hasUnsoundNullSafety);
// Subtyping between JS and anonymous classes.
expect(returnJS is AnonymousClassA Function(), true);
expect(returnAnon is JSClassA Function(), true);
// Subtyping between same type of package:js classes.
expect(returnJS is JSClassB Function(), true);
expect(returnAnon is AnonymousClassB Function(), true);
// No subtyping between JS/anonymous classes and Dart classes.
expect(returnJS is DartClass Function(), false);
expect(returnDartClass is JSClassA Function(), false);
expect(returnAnon is DartClass Function(), false);
expect(returnDartClass is AnonymousClassA Function(), false);
// Repeat the checks but using `confuse` to coerce runtime checks instead of
// compile-time like above.
expect(confuse(returnJS) is JSClassA Function(), true);
expect(confuse(returnAnon) is AnonymousClassA Function(), true);
expect(confuse(returnJS) is JSClassA? Function(), true);
expect(confuse(returnAnon) is AnonymousClassA? Function(), true);
expect(confuse(returnNullableJS) is JSClassA? Function(), true);
expect(confuse(returnNullableAnon) is AnonymousClassA? Function(), true);
expect(
confuse(returnNullableJS) is JSClassA Function(), hasUnsoundNullSafety);
expect(confuse(returnNullableAnon) is AnonymousClassA Function(),
hasUnsoundNullSafety);
expect(confuse(returnJS) is AnonymousClassA Function(), true);
expect(confuse(returnAnon) is JSClassA Function(), true);
expect(confuse(returnJS) is JSClassB Function(), true);
expect(confuse(returnAnon) is AnonymousClassB Function(), true);
expect(confuse(returnJS) is DartClass Function(), false);
expect(confuse(returnDartClass) is JSClassA Function(), false);
expect(confuse(returnAnon) is DartClass Function(), false);
expect(confuse(returnDartClass) is AnonymousClassA Function(), false);
}

View file

@ -0,0 +1,20 @@
// 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.
// Tests subtyping relationships after making package:js types live.
@JS()
library subtyping_live_test;
import 'package:js/js.dart';
import 'subtyping_test_util.dart';
@JS()
external dynamic get externalGetter;
void main() {
// Call to foreign function should trigger dart2js to assume types are live.
externalGetter;
testSubtyping();
}

View file

@ -0,0 +1,12 @@
// 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.
// Tests subtyping relationships without making package:js types live.
import 'package:js/js.dart';
import 'subtyping_test_util.dart';
void main() {
testSubtyping();
}

View file

@ -0,0 +1,74 @@
// 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.
// Tests subtyping relationships between JS and anonymous classes.
@JS()
library subtyping_test_util;
import 'package:js/js.dart';
import 'package:expect/minitest.dart';
@JS()
class JSClassA {}
@JS()
class JSClassB {}
@JS()
@anonymous
class AnonymousClassA {}
@JS()
@anonymous
class AnonymousClassB {}
class DartClass {}
JSClassA returnJS() => throw '';
AnonymousClassA returnAnon() => throw '';
DartClass returnDartClass() => throw '';
// Avoid static type optimization by running all tests using this.
@pragma('dart2js:noInline')
@pragma('dart2js:assumeDynamic')
confuse(x) => x;
void testSubtyping() {
// Checks subtyping with the same type.
expect(returnJS is JSClassA Function(), true);
expect(returnAnon is AnonymousClassA Function(), true);
// Subtyping between JS and anonymous classes.
expect(returnJS is AnonymousClassA Function(), true);
expect(returnAnon is JSClassA Function(), true);
// Subtyping between same type of package:js classes.
expect(returnJS is JSClassB Function(), true);
expect(returnAnon is AnonymousClassB Function(), true);
// No subtyping between JS/anonymous classes and Dart classes.
expect(returnJS is DartClass Function(), false);
expect(returnDartClass is JSClassA Function(), false);
expect(returnAnon is DartClass Function(), false);
expect(returnDartClass is AnonymousClassA Function(), false);
// Repeat the checks but using `confuse` to coerce runtime checks instead of
// compile-time like above.
expect(confuse(returnJS) is JSClassA Function(), true);
expect(confuse(returnAnon) is AnonymousClassA Function(), true);
expect(confuse(returnJS) is AnonymousClassA Function(), true);
expect(confuse(returnAnon) is JSClassA Function(), true);
expect(confuse(returnJS) is JSClassB Function(), true);
expect(confuse(returnAnon) is AnonymousClassB Function(), true);
expect(confuse(returnJS) is DartClass Function(), false);
expect(confuse(returnDartClass) is JSClassA Function(), false);
expect(confuse(returnAnon) is DartClass Function(), false);
expect(confuse(returnDartClass) is AnonymousClassA Function(), false);
}