[dart:js_interop] Disallow tear-offs of external members

Disallows tear-offs for all interop members when using
dart:js_interop, and disallow tear-offs of @staticInterop and
extension external members. Creates tear-off indexes in
InlineExtensionIndex to keep track of tear-off methods that
the CFE generates.

Modifies the CHANGELOG to communicate the breaking change.

Change-Id: I900fdfd6ee6b198f2f34e9d9fd5f3d9c964680e3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/299800
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
This commit is contained in:
Srujan Gaddam 2023-05-09 23:12:58 +00:00 committed by Commit Queue
parent bd48058fe1
commit 8cbd946338
34 changed files with 393 additions and 304 deletions

View file

@ -12,6 +12,15 @@
[#51486]: https://github.com/dart-lang/sdk/issues/51486
### Other libraries
#### `package:js`
- **Breaking change to `@staticInterop` and `external` extension members**:
`external` `@staticInterop` members and `external` extension members can no
longer be used as tear-offs. Declare a closure or a non-`external` method that
calls these members, and use that instead.
### Tools
## 3.0.0 - 2023-05-10

View file

@ -8127,18 +8127,6 @@ const MessageCode messageJsInteropOperatorsNotSupported = const MessageCode(
problemMessage: r"""JS interop classes do not support operator methods.""",
correctionMessage: r"""Try replacing this with a normal method.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropStaticInteropAnonymousFactoryTearoff =
messageJsInteropStaticInteropAnonymousFactoryTearoff;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropStaticInteropAnonymousFactoryTearoff =
const MessageCode("JsInteropStaticInteropAnonymousFactoryTearoff",
problemMessage:
r"""Factories of `@anonymous` `@staticInterop` classes can not be torn off.""",
correctionMessage:
r"""Declare a closure that forwards to this factory instead.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null>
codeJsInteropStaticInteropExternalExtensionMembersWithTypeParameters =
@ -8292,6 +8280,37 @@ const MessageCode messageJsInteropStaticInteropSyntheticConstructor = const Mess
correctionMessage:
r"""Declare an external factory constructor for this `@staticInterop` class and use that instead.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String string, String name)>
templateJsInteropStaticInteropTearOffsDisallowed =
const Template<Message Function(String string, String name)>(
problemMessageTemplate:
r"""Tear-offs of external #string '#name' are disallowed.""",
correctionMessageTemplate:
r"""Declare a closure that calls this member instead.""",
withArguments: _withArgumentsJsInteropStaticInteropTearOffsDisallowed);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(String string, String name)>
codeJsInteropStaticInteropTearOffsDisallowed =
const Code<Message Function(String string, String name)>(
"JsInteropStaticInteropTearOffsDisallowed",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsJsInteropStaticInteropTearOffsDisallowed(
String string, String name) {
if (string.isEmpty) throw 'No string provided';
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
return new Message(codeJsInteropStaticInteropTearOffsDisallowed,
problemMessage:
"""Tear-offs of external ${string} '${name}' are disallowed.""",
correctionMessage:
"""Declare a closure that calls this member instead.""",
arguments: {'string': string, 'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)>
templateJsInteropStaticInteropTrustTypesUsageNotAllowed =

View file

@ -20,7 +20,6 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageJsInteropNonExternalConstructor,
messageJsInteropNonExternalMember,
messageJsInteropOperatorsNotSupported,
messageJsInteropStaticInteropAnonymousFactoryTearoff,
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters,
messageJsInteropStaticInteropGenerativeConstructor,
messageJsInteropStaticInteropSyntheticConstructor,
@ -31,6 +30,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
templateJsInteropStaticInteropWithNonStaticSupertype,
templateJsInteropJSClassExtendsDartClass,
templateJsInteropNativeClassInAnnotation,
templateJsInteropStaticInteropTearOffsDisallowed,
templateJsInteropStaticInteropTrustTypesUsageNotAllowed,
templateJsInteropStaticInteropTrustTypesUsedWithoutStaticInterop,
templateJsInteropStrictModeForbiddenLibrary;
@ -522,7 +522,8 @@ class JsInteropChecks extends RecursiveVisitor {
@override
void visitStaticInvocation(StaticInvocation node) {
if (node.target == _functionToJSTarget) {
final target = node.target;
if (target == _functionToJSTarget) {
final argument = node.arguments.positional.single;
final functionType = argument.getStaticType(_staticTypeContext);
if (functionType is! FunctionType) {
@ -538,6 +539,10 @@ class JsInteropChecks extends RecursiveVisitor {
_reportStaticInvocationIfNotJSType(parameter, node);
}
}
} else {
// Only check generated tear-offs in StaticInvocations.
final tornOff = _getTornOffFromGeneratedTearOff(target);
if (tornOff != null) _checkDisallowedTearoff(tornOff, node);
}
super.visitStaticInvocation(node);
}
@ -606,7 +611,8 @@ class JsInteropChecks extends RecursiveVisitor {
@override
void visitStaticTearOff(StaticTearOff node) {
_checkDisallowedConstructorTearoff(node.target, node);
_checkDisallowedTearoff(
_getTornOffFromGeneratedTearOff(node.target) ?? node.target, node);
}
@override
@ -619,8 +625,9 @@ class JsInteropChecks extends RecursiveVisitor {
@override
void visitStaticTearOffConstantReference(StaticTearOffConstant node) {
if (_constantCache.contains(node)) return;
if (_checkDisallowedConstructorTearoff(
node.target, _lastConstantExpression)) {
if (_checkDisallowedTearoff(
_getTornOffFromGeneratedTearOff(node.target) ?? node.target,
_lastConstantExpression)) {
return;
}
// Only add to the cache if we don't find an error. This is to make sure
@ -739,8 +746,7 @@ class JsInteropChecks extends RecursiveVisitor {
return annotatable != null && hasJSInteropAnnotation(annotatable);
}
if (member.isInlineClassMember) {
final cls = _inlineExtensionIndex.getInlineClass(member);
return cls != null && hasJSInteropAnnotation(cls);
return _inlineExtensionIndex.getInlineClass(member) != null;
}
if (member.enclosingClass == null) {
return hasJSInteropAnnotation(member) || _libraryHasJSAnnotation;
@ -751,51 +757,104 @@ class JsInteropChecks extends RecursiveVisitor {
return false;
}
/// Checks whether [procedure] is a disallowed constructor or factory
/// tear-off.
/// If [procedure] is a generated procedure that represents a relevant
/// tear-off, return the torn-off member.
///
/// [context] is used to report an error location if the procedure is a
/// tear-off that is disallowed. Note that constructor and factory tear-offs
/// are lowered using a static method, so we only check `StaticTearOff`s and
/// `StaticTearOffConstant`s. Returns whether the given procedure is
/// disallowed.
bool _checkDisallowedConstructorTearoff(
Procedure procedure, TreeNode? context) {
var enclosingClass = procedure.enclosingClass;
if (enclosingClass == null) return false;
if (!procedure.isStatic || !hasStaticInteropAnnotation(enclosingClass)) {
return false;
}
/// Otherwise, return null.
Member? _getTornOffFromGeneratedTearOff(Procedure procedure) {
var tornOff = _inlineExtensionIndex.getInlineMemberForTearOff(procedure) ??
_inlineExtensionIndex.getExtensionMemberForTearOff(procedure);
if (tornOff != null) return tornOff.asMember;
var name = extractConstructorNameFromTearOff(procedure.name);
if (name == null) return false;
if (name.isEmpty &&
enclosingClass.constructors.any((constructor) =>
constructor.isSynthetic && constructor.name.text.isEmpty)) {
// Use of a synthetic generative constructor on `@staticInterop` class.
if (context != null && context.location != null) {
_diagnosticsReporter.report(
messageJsInteropStaticInteropSyntheticConstructor,
context.fileOffset,
1,
context.location!.file);
}
return true;
if (name == null) return null;
final enclosingClass = procedure.enclosingClass;
// To avoid processing every class' constructors again, we only check for
// constructor tear-offs on relevant classes a.k.a. @staticInterop classes.
if (enclosingClass == null || !hasStaticInteropAnnotation(enclosingClass)) {
return null;
}
if (hasAnonymousAnnotation(enclosingClass) &&
enclosingClass.procedures.any((procedure) =>
procedure.isExternal &&
procedure.isFactory &&
procedure.name.text == name)) {
// Tear-offs of an `@anonymous` `@staticInterop` external factory are
// disallowed.
if (context != null && context.location != null) {
_diagnosticsReporter.report(
messageJsInteropStaticInteropAnonymousFactoryTearoff,
context.fileOffset,
1,
context.location!.file);
for (final constructor in enclosingClass.constructors) {
if (constructor.name.text == name) {
return constructor;
}
}
for (final procedure in enclosingClass.procedures) {
if (procedure.isFactory && procedure.name.text == name) {
return procedure;
}
}
return null;
}
/// Given a [member] and the [context] in which the use of it occurs,
/// determines whether a tear-off of [member] can be used.
///
/// Tear-offs of the following are disallowed when using dart:js_interop:
///
/// - External inline class constructors and factories (TODO(srujzs): Add
/// checks for factories once they're added.)
/// - External factories of @staticInterop classes
/// - External interop inline methods
/// - External interop extension methods on @staticInterop or inline classes
/// - Synthetic generative @staticInterop constructors
/// - External top-level methods
///
/// Returns whether an error was triggered.
bool _checkDisallowedTearoff(Member member, TreeNode? context) {
if (context == null || context.location == null) return false;
if (member.isExternal) {
var memberKind = '';
var memberName = '';
if (member.isInlineClassMember) {
// Inline class interop members can not be torn off.
if (_inlineExtensionIndex.getInlineClass(member) == null) {
return false;
}
memberKind = 'inline class interop member';
memberName =
_inlineExtensionIndex.getInlineDescriptor(member)!.name.text;
if (memberName.isEmpty) memberName = 'new';
} else if (member.isExtensionMember) {
// JS interop members can not be torn off.
if (_inlineExtensionIndex.getExtensionAnnotatable(member) == null) {
return false;
}
memberKind = 'extension interop member';
memberName =
_inlineExtensionIndex.getExtensionDescriptor(member)!.name.text;
} else if (member.enclosingClass != null) {
// @staticInterop members can not be torn off.
final enclosingClass = member.enclosingClass!;
if (!hasStaticInteropAnnotation(enclosingClass)) return false;
memberKind = '@staticInterop member';
memberName = member.name.text;
if (memberName.isEmpty) memberName = 'new';
} else {
// Top-levels with dart:js_interop can not be torn off.
if (!hasDartJSInteropAnnotation(member) &&
!hasDartJSInteropAnnotation(member.enclosingLibrary)) {
return false;
}
memberKind = 'top-level member';
memberName = member.name.text;
}
_diagnosticsReporter.report(
templateJsInteropStaticInteropTearOffsDisallowed.withArguments(
memberKind, memberName),
context.fileOffset,
1,
context.location!.file);
return true;
} else if (member is Constructor &&
member.isSynthetic &&
hasStaticInteropAnnotation(member.enclosingClass)) {
// Use of a synthetic generative constructor on @staticInterop class is
// disallowed.
_diagnosticsReporter.report(
messageJsInteropStaticInteropSyntheticConstructor,
context.fileOffset,
1,
context.location!.file);
return true;
}
return false;

View file

@ -700,13 +700,16 @@ class JsUtilOptimizer extends Transformer {
/// Lazily-initialized indexes for extension and inline class interop members.
///
/// As the query APIs are called, we process the enclosing libraries of the
/// member in question if needed.
/// member in question if needed. We only process JS interop inline classes and
/// extensions on either JS interop or @Native classes.
class InlineExtensionIndex {
final Map<Reference, Annotatable> _extensionAnnotatableIndex = {};
final Map<Reference, Extension> _extensionIndex = {};
final Map<Reference, ExtensionMemberDescriptor> _extensionMemberIndex = {};
final Map<Reference, Reference> _extensionTearOffIndex = {};
final Map<Reference, InlineClass> _inlineClassIndex = {};
final Map<Reference, InlineClassMemberDescriptor> _inlineMemberIndex = {};
final Map<Reference, Reference> _inlineTearOffIndex = {};
final Set<Library> _processedExtensionLibraries = {};
final Set<Library> _processedInlineLibraries = {};
final Set<Reference> _shouldTrustType = {};
@ -719,9 +722,14 @@ class InlineExtensionIndex {
/// - Maps the member to its descriptor in `_extensionMemberIndex`.
/// - Adds the member to `_shouldTrustTypes` if the on-type has a
/// `@trustTypes` annotation.
/// - Maps the tear-off member to the member it tears off in
/// `extensionTearOffIndex`.
void _indexExtensions(Library library) {
if (_processedExtensionLibraries.contains(library)) return;
for (var extension in library.extensions) {
// Descriptors of tear-offs have the same name as the member they tear
// off. This is used to find the tear-offs and their associated member.
final descriptorNames = <String, ExtensionMemberDescriptor>{};
for (var descriptor in extension.members) {
var reference = descriptor.member;
var onType = extension.onType;
@ -742,6 +750,20 @@ class InlineExtensionIndex {
_extensionAnnotatableIndex[reference] = cls;
_extensionIndex[reference] = extension;
}
if (descriptor.kind == ExtensionMemberKind.Method ||
descriptor.kind == ExtensionMemberKind.TearOff) {
final descriptorName = descriptor.name.text;
if (descriptorNames.containsKey(descriptorName)) {
final previousDesc = descriptorNames[descriptorName]!;
if (previousDesc.kind == ExtensionMemberKind.TearOff) {
_extensionTearOffIndex[previousDesc.member] = descriptor.member;
} else {
_extensionTearOffIndex[descriptor.member] = previousDesc.member;
}
} else {
descriptorNames[descriptorName] = descriptor;
}
}
}
}
_processedExtensionLibraries.add(library);
@ -771,19 +793,43 @@ class InlineExtensionIndex {
return _shouldTrustType.contains(member.reference);
}
Reference? getExtensionMemberForTearOff(Member member) {
if (!member.isExtensionMember) return null;
_indexExtensions(member.enclosingLibrary);
return _extensionTearOffIndex[member.reference];
}
/// If unprocessed, for all inline class members in [library] whose inline
/// class has a `@JS` annotation, does the following:
///
/// - Maps the member to its inline class in `_inlineClassIndex`.
/// - Maps the member to its descriptor in `_inlineMemberIndex`.
/// - Maps the tear-off member to the member it tears off in
/// `inlineTearOffIndex`.
void _indexInlineClasses(Library library) {
if (_processedInlineLibraries.contains(library)) return;
final descriptorNames = <String, InlineClassMemberDescriptor>{};
for (var inlineClass in library.inlineClasses) {
if (hasJSInteropAnnotation(inlineClass)) {
for (var descriptor in inlineClass.members) {
var reference = descriptor.member;
final reference = descriptor.member;
_inlineMemberIndex[reference] = descriptor;
_inlineClassIndex[reference] = inlineClass;
if (descriptor.kind == InlineClassMemberKind.Method ||
descriptor.kind == InlineClassMemberKind.Constructor ||
descriptor.kind == InlineClassMemberKind.TearOff) {
final descriptorName = descriptor.name.text;
if (descriptorNames.containsKey(descriptorName)) {
final previousDesc = descriptorNames[descriptorName]!;
if (previousDesc.kind == InlineClassMemberKind.TearOff) {
_inlineTearOffIndex[previousDesc.member] = descriptor.member;
} else {
_inlineTearOffIndex[descriptor.member] = previousDesc.member;
}
} else {
descriptorNames[descriptorName] = descriptor;
}
}
}
}
}
@ -802,6 +848,13 @@ class InlineExtensionIndex {
return _inlineClassIndex[member.reference];
}
Reference? getInlineMemberForTearOff(Member member) {
// Constructor tear-offs are not marked as inline members, so we don't check
// if [member] is an inline class member.
_indexInlineClasses(member.enclosingLibrary);
return _inlineTearOffIndex[member.reference];
}
/// Return whether [node] is either an extension member that's declared as
/// non-`static` or an inline class member that's declared as non-`static`
/// and is not a factory or constructor.

View file

@ -610,8 +610,6 @@ JsInteropNonStaticWithStaticInteropSupertype/analyzerCode: Fail # Web compiler s
JsInteropNonStaticWithStaticInteropSupertype/example: Fail # Web compiler specific
JsInteropOperatorsNotSupported/analyzerCode: Fail # Web compiler specific
JsInteropOperatorsNotSupported/example: Fail # Web compiler specific
JsInteropStaticInteropAnonymousFactoryTearoff/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropAnonymousFactoryTearoff/example: Fail # Web compiler specific
JsInteropStaticInteropExternalExtensionMembersWithTypeParameters/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropExternalExtensionMembersWithTypeParameters/example: Fail # Web compiler specific
JsInteropStaticInteropGenerativeConstructor/analyzerCode: Fail # Web compiler specific
@ -626,6 +624,8 @@ JsInteropStaticInteropNoJSAnnotation/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropNoJSAnnotation/example: Fail # Web compiler specific
JsInteropStaticInteropSyntheticConstructor/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropSyntheticConstructor/example: Fail # Web compiler specific
JsInteropStaticInteropTearOffsDisallowed/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropTearOffsDisallowed/example: Fail # Web compiler specific
JsInteropStaticInteropTrustTypesUsageNotAllowed/analyzerCode: Fail # Web compiler specific
JsInteropStaticInteropTrustTypesUsageNotAllowed/example: Fail # Web compiler specific
JsInteropStaticInteropTrustTypesUsedWithoutStaticInterop/analyzerCode: Fail # Web compiler specific

View file

@ -5531,10 +5531,6 @@ JsInteropNonStaticWithStaticInteropSupertype:
problemMessage: "Class '#name' does not have an `@staticInterop` annotation, but has supertype '#name2', which does."
correctionMessage: "Try marking '#name' as a `@staticInterop` class, or don't inherit '#name2'."
JsInteropStaticInteropAnonymousFactoryTearoff:
problemMessage: "Factories of `@anonymous` `@staticInterop` classes can not be torn off."
correctionMessage: "Declare a closure that forwards to this factory instead."
JsInteropStaticInteropExternalExtensionMembersWithTypeParameters:
problemMessage: "`@staticInterop` classes cannot have external extension members with type parameters."
correctionMessage: "Try using a Dart extension member if you need type parameters instead."
@ -5563,13 +5559,9 @@ JsInteropStaticInteropSyntheticConstructor:
problemMessage: "Synthetic constructors on `@staticInterop` classes can not be used."
correctionMessage: "Declare an external factory constructor for this `@staticInterop` class and use that instead."
JsInteropStaticInteropWithInstanceMembers:
problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
correctionMessage: "Try moving the instance member to a static extension."
JsInteropStaticInteropWithNonStaticSupertype:
problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which does not."
correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
JsInteropStaticInteropTearOffsDisallowed:
problemMessage: "Tear-offs of external #string '#name' are disallowed."
correctionMessage: "Declare a closure that calls this member instead."
JsInteropStaticInteropTrustTypesUsedWithoutStaticInterop:
problemMessage: "JS interop class '#name' has an `@trustTypes` annotation, but no `@staticInterop` annotation."
@ -5579,6 +5571,14 @@ JsInteropStaticInteropTrustTypesUsageNotAllowed:
problemMessage: "JS interop class '#name' has an `@trustTypes` annotation, but `@trustTypes` is only supported within the sdk."
correctionMessage: "Try removing the `@trustTypes` annotation."
JsInteropStaticInteropWithInstanceMembers:
problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
correctionMessage: "Try moving the instance member to a static extension."
JsInteropStaticInteropWithNonStaticSupertype:
problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which does not."
correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
JsInteropStrictModeViolation:
problemMessage: "JS interop requires JS types when strict mode is enabled, but Type '#type' is not a type or subtype of a type from `dart:js_interop`."
correctionMessage: "Use a JS type instead."

View file

@ -44,19 +44,13 @@ void method(A a) {
a = b1.field;
b1.field = a;
a = b1.method();
var f1 = b1.method;
b2 = b2.genericMethod(b2);
var f2 = b2.genericMethod;
int Function(int) f3 = b2.genericMethod;
b1 = b2.getter;
b1.setter = b2;
a = B.staticField;
B.staticField = a;
a = B.staticMethod();
var f4 = B.staticMethod;
b2 = B.staticGenericMethod(b2);
var f5 = B.staticGenericMethod;
String Function(String) f6 = B.staticGenericMethod;
b1 = B.staticGetter;
B.staticSetter = b2;
}

View file

@ -60,19 +60,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -80,9 +74,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String>
}

View file

@ -75,19 +75,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -95,9 +89,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String>
}

View file

@ -60,19 +60,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -80,9 +74,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String*>
}

View file

@ -60,19 +60,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -80,9 +74,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String*>
}

View file

@ -75,19 +75,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -95,9 +89,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String*>
}

View file

@ -45,19 +45,13 @@ void method(A a) {
a = b1.field;
b1.field = a;
a = b1.method();
var f1 = b1.method;
b2 = b2.genericMethod(b2);
var f2 = b2.genericMethod;
int Function(int) f3 = b2.genericMethod;
b1 = b2.getter;
b1.setter = b2;
a = B.staticField;
B.staticField = a;
a = B.staticMethod();
var f4 = B.staticMethod;
b2 = B.staticGenericMethod(b2);
var f5 = B.staticGenericMethod;
String Function(String) f6 = B.staticGenericMethod;
b1 = B.staticGetter;
B.staticSetter = b2;
}

View file

@ -60,19 +60,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -80,9 +74,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String>
}

View file

@ -75,19 +75,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -95,9 +89,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String>
}

View file

@ -60,19 +60,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -80,9 +74,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String*>
}

View file

@ -60,19 +60,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -80,9 +74,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String*>
}

View file

@ -75,19 +75,13 @@ static method method(self::A a) → void {
a = self::B|get#field(b1);
self::B|set#field(b1, a);
a = self::B|method(b1);
() → self::A f1 = self::B|get#method(b1);
b2 = self::B|genericMethod<self::B>(b2, b2);
<T extends core::Object? = dynamic>(T%) → T% f2 = self::B|get#genericMethod(b2);
(core::int) → core::int f3 = self::B|get#genericMethod(b2)<core::int>;
b1 = self::B|get#getter(b2);
self::B|set#setter(b1, b2);
a = self::B|staticField;
self::B|staticField = a;
a = self::B|staticMethod();
() → self::A f4 = #C3;
b2 = self::B|staticGenericMethod<self::B>(b2);
<T extends core::Object? = dynamic>(T%) → T% f5 = #C4;
(core::String) → core::String f6 = #C5;
b1 = self::B|staticGetter;
self::B|staticSetter = b2;
}
@ -95,9 +89,6 @@ static method method(self::A a) → void {
constants {
#C1 = null
#C2 = js_::JS {name:#C1}
#C3 = static-tearoff self::B|staticMethod
#C4 = static-tearoff self::B|staticGenericMethod
#C5 = instantiation #C4 <core::String*>
}

View file

@ -142,13 +142,6 @@ void main() {
expect(foo.field, equals(10));
foo.setField10(6);
expect(foo.field, equals(6));
// Test using tearoffs
var setF = foo.setField10;
setF();
expect(foo.field, equals(10));
setF(6);
expect(foo.field, equals(6));
});
test('module class', () {

View file

@ -1,9 +1,9 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// Copyright (c) 2023, 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.
@JS()
library disallowed_constructor_static_test;
library disallowed_generative_constructor_static_test;
import 'package:js/js.dart';
@ -22,14 +22,6 @@ class JSClass {
@staticInterop
class SyntheticConstructor {}
@JS()
@staticInterop
@anonymous
class Anonymous {
external factory Anonymous({String? a});
external factory Anonymous.named({String? a});
}
void main() {
SyntheticConstructor();
//^
@ -44,15 +36,4 @@ void main() {
const [SyntheticConstructor.new];
//^
// [web] Synthetic constructors on `@staticInterop` classes can not be used.
Anonymous.new;
//^
// [web] Factories of `@anonymous` `@staticInterop` classes can not be torn off.
Anonymous.named;
//^
// [web] Factories of `@anonymous` `@staticInterop` classes can not be torn off.
const [Anonymous.new, Anonymous.named];
//^
// [web] Factories of `@anonymous` `@staticInterop` classes can not be torn off.
}

View file

@ -0,0 +1,149 @@
// Copyright (c) 2023, 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.
// SharedOptions=--enable-experiment=inline-class
import 'dart:js_interop';
@JS()
external void topLevel();
@JS()
inline class Inline {
final JSObject obj;
external Inline();
external Inline.named();
@ObjectLiteral()
external Inline.literal({JSNumber? a});
Inline.nonExternal(this.obj);
// TODO(srujzs): Once we have inline class factories, test these.
// external factory Inline.fact();
// @ObjectLiteral()
// external factory Inline.literalFact({JSNumber? a});
// factory Inline.nonExternalFact() => Inline();
external static void externalStatic();
static void nonExternalStatic() {}
external void externalMethod();
void nonExternalMethod() {}
}
extension on Inline {
external void externalExtensionMethod();
void nonExternalExtensionMethod() {}
}
@JS()
@staticInterop
class StaticInterop {
external factory StaticInterop();
external factory StaticInterop.named();
factory StaticInterop.nonExternalFact() => StaticInterop();
external static void externalStatic();
static void nonExternalStatic() {}
}
extension on StaticInterop {
external void externalExtensionMethod();
void nonExternalExtensionMethod() {}
}
@JS()
@staticInterop
@anonymous
class Anonymous {
external factory Anonymous({String? a});
external factory Anonymous.named({String? a});
factory Anonymous.nonExternalFact() => Anonymous.named(a: '');
}
void testMethods() {
topLevel;
//^
// [web] Tear-offs of external top-level member 'topLevel' are disallowed.
const [topLevel];
//^
// [web] Tear-offs of external top-level member 'topLevel' are disallowed.
Inline.externalStatic;
// ^
// [web] Tear-offs of external inline class interop member 'externalStatic' are disallowed.
const [Inline.externalStatic];
//^
// [web] Tear-offs of external inline class interop member 'externalStatic' are disallowed.
Inline.nonExternalStatic;
final inline = Inline();
inline.externalMethod;
// ^
// [web] Tear-offs of external inline class interop member 'externalMethod' are disallowed.
inline.nonExternalMethod;
inline.externalExtensionMethod;
// ^
// [web] Tear-offs of external extension interop member 'externalExtensionMethod' are disallowed.
inline.nonExternalExtensionMethod;
StaticInterop.externalStatic;
// ^
// [web] Tear-offs of external @staticInterop member 'externalStatic' are disallowed.
const [StaticInterop.externalStatic];
//^
// [web] Tear-offs of external @staticInterop member 'externalStatic' are disallowed.
StaticInterop.nonExternalStatic;
final staticInterop = StaticInterop();
staticInterop.externalExtensionMethod;
// ^
// [web] Tear-offs of external extension interop member 'externalExtensionMethod' are disallowed.
staticInterop.nonExternalExtensionMethod;
}
void testConstructors() {
Inline.new;
//^
// [web] Tear-offs of external inline class interop member 'new' are disallowed.
Inline.named;
//^
// [web] Tear-offs of external inline class interop member 'named' are disallowed.
Inline.literal;
//^
// [web] Tear-offs of external inline class interop member 'literal' are disallowed.
Inline.nonExternal;
const [Inline.new];
//^
// [web] Tear-offs of external inline class interop member 'new' are disallowed.
// TODO(srujzs): Once we have factories available, test these.
// Inline.fact;
// Inline.literalFact;
// Inline.nonExternalFact;
// const [Inline.fact];
StaticInterop.new;
//^
// [web] Tear-offs of external @staticInterop member 'new' are disallowed.
StaticInterop.named;
//^
// [web] Tear-offs of external @staticInterop member 'named' are disallowed.
StaticInterop.nonExternalFact;
const [StaticInterop.new];
//^
// [web] Tear-offs of external @staticInterop member 'new' are disallowed.
Anonymous.new;
//^
// [web] Tear-offs of external @staticInterop member 'new' are disallowed.
Anonymous.named;
//^
// [web] Tear-offs of external @staticInterop member 'named' are disallowed.
Anonymous.nonExternalFact;
const [Anonymous.new];
//^
// [web] Tear-offs of external @staticInterop member 'new' are disallowed.
}
void main() {
testMethods();
testConstructors();
}

View file

@ -8,7 +8,6 @@ library external_static_member_lowerings_test;
import 'dart:js_interop';
import 'package:expect/minitest.dart';
import 'package:js/js.dart' show staticInterop;
@JS()
external dynamic eval(String code);
@ -117,14 +116,10 @@ void testClassStaticMembers() {
ExternalStatic.renamedGetSet = 'renamedGetSet';
expect(ExternalStatic.renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(ExternalStatic.method(), 'method');
expect((ExternalStatic.method)(), 'method');
expect(ExternalStatic.differentArgsMethod('method'), 'methodundefined');
expect((ExternalStatic.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(ExternalStatic.renamedMethod(), 'method');
expect((ExternalStatic.renamedMethod)(), 'method');
}
void testTopLevelMembers() {
@ -145,26 +140,18 @@ void testTopLevelMembers() {
renamedGetSet = 'renamedGetSet';
expect(renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(method(), 'method');
expect((method)(), 'method');
expect(differentArgsMethod('method'), 'methodundefined');
expect((differentArgsMethod)('optional', 'method'), 'optionalmethod');
expect(renamedMethod(), 'method');
expect((renamedMethod)(), 'method');
}
void testFactories() {
// Non-object literal factories and their tear-offs.
// Non-object literal factories.
var initialized = 'initialized';
var externalStatic = ExternalStatic(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = ExternalStatic.named();
expect(externalStatic.initialValue, null);
externalStatic = (ExternalStatic.new)(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = (ExternalStatic.named)(initialized);
expect(externalStatic.initialValue, initialized);
}

View file

@ -8,7 +8,7 @@ library external_static_member_lowerings_trusttypes_test;
import 'dart:js_interop';
import 'package:expect/minitest.dart';
import 'package:js/js.dart' show trustTypes, staticInterop;
import 'package:js/js.dart' show trustTypes;
@JS()
external dynamic eval(String code);
@ -47,5 +47,4 @@ void main() {
expect(confuse(ExternalStaticTrustType.getSet), 'getSet');
expect(confuse(ExternalStaticTrustType.method()), 'method');
expect(confuse((ExternalStaticTrustType.method)()), 'method');
}

View file

@ -12,7 +12,6 @@ import 'dart:js_interop';
import 'dart:js_util' as js_util;
import 'package:expect/minitest.dart';
import 'package:js/js.dart' show staticInterop;
@JS('library3.ExternalStatic')
@staticInterop
@ -132,14 +131,10 @@ void testClassStaticMembers() {
ExternalStatic.renamedGetSet = 'renamedGetSet';
expect(ExternalStatic.renamedGetSet, 'renamedGetSet');
// Methods and tearoffs.
// Methods.
expect(ExternalStatic.method(), 'method');
expect((ExternalStatic.method)(), 'method');
expect(ExternalStatic.differentArgsMethod('method'), 'methodundefined');
expect((ExternalStatic.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(ExternalStatic.renamedMethod(), 'method');
expect((ExternalStatic.renamedMethod)(), 'method');
}
void testTopLevelMembers() {
@ -162,26 +157,18 @@ void testTopLevelMembers() {
namespacedGetSet = 'modified';
expect(namespacedGetSet, 'modified');
// Methods and tear-offs.
// Methods.
expect(method(), 'method');
expect((method)(), 'method');
expect(differentArgsMethod('method'), 'methodundefined');
expect((differentArgsMethod)('optional', 'method'), 'optionalmethod');
expect(namespacedMethod(), 'namespacedMethod');
expect((namespacedMethod)(), 'namespacedMethod');
}
void testFactories() {
// Non-object literal factories and their tear-offs.
// Non-object literal factories.
var initialized = 'initialized';
var externalStatic = ExternalStatic(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = ExternalStatic.named();
expect(externalStatic.initialValue, null);
externalStatic = (ExternalStatic.new)(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = (ExternalStatic.named)(initialized);
expect(externalStatic.initialValue, initialized);
}

View file

@ -72,12 +72,8 @@ void main() {
extension.renamedGetSet = 'renamedGetSet';
expect(extension.renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(extension.method(), 'method');
expect((extension.method)(), 'method');
expect(extension.differentArgsMethod('method'), 'methodundefined');
expect((extension.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(extension.renamedMethod(), 'method');
expect((extension.renamedMethod)(), 'method');
}
}

View file

@ -73,12 +73,8 @@ void main() {
// external.renamedGetSet = 'renamedGetSet';
// expect(external.renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(external.method(), 'method');
expect((external.method)(), 'method');
expect(external.differentArgsMethod('method'), 'methodundefined');
expect(
(external.differentArgsMethod)('optional', 'method'), 'optionalmethod');
expect(external.renamedMethod(), 'method');
expect((external.renamedMethod)(), 'method');
}

View file

@ -67,6 +67,7 @@ void main() {
expect(js_util.getProperty(externalStatic, 'a'), 0);
expect(js_util.getProperty(externalStatic, 'b'), '');
}
testExternalConstructorCall(ExternalStatic());
// testExternalConstructorCall(ExternalStatic.factory());
testExternalConstructorCall(ExternalStatic.multipleArgs(0, ''));
@ -90,12 +91,8 @@ void main() {
ExternalStatic.renamedGetSet = 'renamedGetSet';
expect(ExternalStatic.renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(ExternalStatic.method(), 'method');
expect((ExternalStatic.method)(), 'method');
expect(ExternalStatic.differentArgsMethod('method'), 'methodundefined');
expect((ExternalStatic.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(ExternalStatic.renamedMethod(), 'method');
expect((ExternalStatic.renamedMethod)(), 'method');
}
}

View file

@ -68,13 +68,15 @@ void main() {
library3.ExternalStatic.field = 'field';
library3.ExternalStatic.finalField = 'finalField';
library3.ExternalStatic.getSet = 'getSet';
''']);
'''
]);
// Constructors.
void testExternalConstructorCall(ExternalStatic externalStatic) {
expect(js_util.getProperty(externalStatic, 'a'), 0);
expect(js_util.getProperty(externalStatic, 'b'), '');
}
testExternalConstructorCall(ExternalStatic());
// testExternalConstructorCall(ExternalStatic.factory());
testExternalConstructorCall(ExternalStatic.multipleArgs(0, ''));
@ -98,12 +100,8 @@ void main() {
ExternalStatic.renamedGetSet = 'renamedGetSet';
expect(ExternalStatic.renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(ExternalStatic.method(), 'method');
expect((ExternalStatic.method)(), 'method');
expect(ExternalStatic.differentArgsMethod('method'), 'methodundefined');
expect((ExternalStatic.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(ExternalStatic.renamedMethod(), 'method');
expect((ExternalStatic.renamedMethod)(), 'method');
}
}

View file

@ -56,4 +56,4 @@ void main() {
testProperties(Literal(a: 0.0, b: '', c: true), a: 0.0, b: '', c: true);
// Test that passing in a different order doesn't change the values.
testProperties(Literal(c: true, a: 0.0, b: ''), a: 0.0, b: '', c: true);
}
}

View file

@ -124,13 +124,6 @@ void main() {
expect(foo.getField(), equals(10));
foo.setField10(6);
expect(foo.getField(), equals(6));
// Test using tearoffs
var setF = foo.setField10;
setF();
expect(foo.getField(), equals(10));
setF(6);
expect(foo.getField(), equals(6));
});
test('module class', () {

View file

@ -1,11 +1,11 @@
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// Copyright (c) 2023, 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.
// @dart = 2.9
@JS()
library generative_constructor_static_test;
library disallowed_generative_constructor_static_test;
import 'package:js/js.dart';

View file

@ -117,14 +117,10 @@ void testClassStaticMembers() {
ExternalStatic.renamedGetSet = 'renamedGetSet';
expect(ExternalStatic.renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(ExternalStatic.method(), 'method');
expect((ExternalStatic.method)(), 'method');
expect(ExternalStatic.differentArgsMethod('method'), 'methodundefined');
expect((ExternalStatic.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(ExternalStatic.renamedMethod(), 'method');
expect((ExternalStatic.renamedMethod)(), 'method');
}
void testTopLevelMembers() {
@ -145,26 +141,18 @@ void testTopLevelMembers() {
renamedGetSet = 'renamedGetSet';
expect(renamedGetSet, 'renamedGetSet');
// Methods and tear-offs.
// Methods.
expect(method(), 'method');
expect((method)(), 'method');
expect(differentArgsMethod('method'), 'methodundefined');
expect((differentArgsMethod)('optional', 'method'), 'optionalmethod');
expect(renamedMethod(), 'method');
expect((renamedMethod)(), 'method');
}
void testFactories() {
// Non-object literal factories and their tear-offs.
// Non-object literal factories.
var initialized = 'initialized';
var externalStatic = ExternalStatic(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = ExternalStatic.named();
expect(externalStatic.initialValue, null);
externalStatic = (ExternalStatic.new)(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = (ExternalStatic.named)(initialized);
expect(externalStatic.initialValue, initialized);
}

View file

@ -47,5 +47,4 @@ void main() {
expect(confuse(ExternalStaticTrustType.getSet), 'getSet');
expect(confuse(ExternalStaticTrustType.method()), 'method');
expect(confuse((ExternalStaticTrustType.method)()), 'method');
}

View file

@ -132,14 +132,10 @@ void testClassStaticMembers() {
ExternalStatic.renamedGetSet = 'renamedGetSet';
expect(ExternalStatic.renamedGetSet, 'renamedGetSet');
// Methods and tearoffs.
// Methods.
expect(ExternalStatic.method(), 'method');
expect((ExternalStatic.method)(), 'method');
expect(ExternalStatic.differentArgsMethod('method'), 'methodundefined');
expect((ExternalStatic.differentArgsMethod)('optional', 'method'),
'optionalmethod');
expect(ExternalStatic.renamedMethod(), 'method');
expect((ExternalStatic.renamedMethod)(), 'method');
}
void testTopLevelMembers() {
@ -162,26 +158,18 @@ void testTopLevelMembers() {
namespacedGetSet = 'modified';
expect(namespacedGetSet, 'modified');
// Methods and tear-offs.
// Methods.
expect(method(), 'method');
expect((method)(), 'method');
expect(differentArgsMethod('method'), 'methodundefined');
expect((differentArgsMethod)('optional', 'method'), 'optionalmethod');
expect(namespacedMethod(), 'namespacedMethod');
expect((namespacedMethod)(), 'namespacedMethod');
}
void testFactories() {
// Non-object literal factories and their tear-offs.
// Non-object literal factories.
var initialized = 'initialized';
var externalStatic = ExternalStatic(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = ExternalStatic.named();
expect(externalStatic.initialValue, null);
externalStatic = (ExternalStatic.new)(initialized);
expect(externalStatic.initialValue, initialized);
externalStatic = (ExternalStatic.named)(initialized);
expect(externalStatic.initialValue, initialized);
}