[dart:js_interop/ddc/dart2wasm] Refactor inline class to extension types

Does several refactorings now that inline class -> extension type:
- InlineExtensionIndex becomes ExtensionIndex
- Comments mentioning inline classes now reference extension types
- Tests are moved to extension types
- Errors now reference extension types instead of inline classes

Change-Id: I26ede8e3aaf6bba5f73847238edeed266fc6a043
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/317805
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Srujan Gaddam 2023-08-15 18:24:43 +00:00 committed by Commit Queue
parent 38d30c57e6
commit d485ef46ce
27 changed files with 378 additions and 447 deletions

View file

@ -7734,9 +7734,9 @@ const Code<Null> codeJsInteropDartJsInteropAnnotationForStaticInteropOnly =
const MessageCode messageJsInteropDartJsInteropAnnotationForStaticInteropOnly =
const MessageCode("JsInteropDartJsInteropAnnotationForStaticInteropOnly",
problemMessage:
r"""The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through inline classes or '@staticInterop'.""",
r"""The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through extension types or '@staticInterop' classes.""",
correctionMessage:
r"""Try making this class an inline class or marking it as '@staticInterop'.""");
r"""Try making this class an extension type or marking it as '@staticInterop'.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropEnclosingClassJSAnnotation =
@ -7909,6 +7909,30 @@ Message _withArgumentsJsInteropExportNoExportableMembers(String name) {
arguments: {'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropExtensionTypeMemberNotInterop =
messageJsInteropExtensionTypeMemberNotInterop;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropExtensionTypeMemberNotInterop = const MessageCode(
"JsInteropExtensionTypeMemberNotInterop",
problemMessage:
r"""Extension type member is marked 'external', but the representation type of its extension type is not a valid JS interop type.""",
correctionMessage:
r"""Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop extension types.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropExtensionTypeUsedWithWrongJsAnnotation =
messageJsInteropExtensionTypeUsedWithWrongJsAnnotation;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropExtensionTypeUsedWithWrongJsAnnotation =
const MessageCode("JsInteropExtensionTypeUsedWithWrongJsAnnotation",
problemMessage:
r"""Extension types should use the '@JS' annotation from 'dart:js_interop' and not from 'package:js'.""",
correctionMessage:
r"""Try using the '@JS' annotation from 'dart:js_interop' annotation on this extension type instead.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropExternalExtensionMemberOnTypeInvalid =
messageJsInteropExternalExtensionMemberOnTypeInvalid;
@ -7944,30 +7968,6 @@ const MessageCode messageJsInteropExternalMemberNotJSAnnotated = const MessageCo
correctionMessage:
r"""Try removing the 'external' keyword or adding a JS interop annotation.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropInlineClassMemberNotInterop =
messageJsInteropInlineClassMemberNotInterop;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropInlineClassMemberNotInterop = const MessageCode(
"JsInteropInlineClassMemberNotInterop",
problemMessage:
r"""Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type.""",
correctionMessage:
r"""Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop inline types.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropInlineClassUsedWithWrongJsAnnotation =
messageJsInteropInlineClassUsedWithWrongJsAnnotation;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageJsInteropInlineClassUsedWithWrongJsAnnotation =
const MessageCode("JsInteropInlineClassUsedWithWrongJsAnnotation",
problemMessage:
r"""Inline classes should use the '@JS' annotation from 'dart:js_interop' and not from 'package:js'.""",
correctionMessage:
r"""Try using the '@JS' annotation from 'dart:js_interop' annotation on this inline class instead.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeJsInteropInvalidStaticClassMemberName =
messageJsInteropInvalidStaticClassMemberName;

View file

@ -11,11 +11,11 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageJsInteropDartJsInteropAnnotationForStaticInteropOnly,
messageJsInteropEnclosingClassJSAnnotation,
messageJsInteropEnclosingClassJSAnnotationContext,
messageJsInteropExtensionTypeMemberNotInterop,
messageJsInteropExtensionTypeUsedWithWrongJsAnnotation,
messageJsInteropExternalExtensionMemberOnTypeInvalid,
messageJsInteropExternalExtensionMemberWithStaticDisallowed,
messageJsInteropExternalMemberNotJSAnnotated,
messageJsInteropInlineClassMemberNotInterop,
messageJsInteropInlineClassUsedWithWrongJsAnnotation,
messageJsInteropInvalidStaticClassMemberName,
messageJsInteropNamedParameters,
messageJsInteropNonExternalConstructor,
@ -46,8 +46,8 @@ import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart';
import 'package:front_end/src/api_prototype/lowering_predicates.dart';
import 'package:front_end/src/fasta/fasta_codes.dart'
show
templateJsInteropExtensionTypeNotInterop,
templateJsInteropFunctionToJSRequiresStaticType,
templateJsInteropInlineClassNotInterop,
templateJsInteropStrictModeViolation;
import 'package:kernel/class_hierarchy.dart';
@ -61,8 +61,8 @@ import 'src/js_interop.dart';
class JsInteropChecks extends RecursiveVisitor {
final Set<Constant> _constantCache = {};
final CoreTypes _coreTypes;
late final ExtensionIndex _extensionIndex;
final Procedure _functionToJSTarget;
late final InlineExtensionIndex _inlineExtensionIndex;
// Errors on constants need source information, so we use the surrounding
// `ConstantExpression` as the source.
ConstantExpression? _lastConstantExpression;
@ -150,10 +150,9 @@ class JsInteropChecks extends RecursiveVisitor {
'dart:js_interop', 'FunctionToJSExportedDartFunction|get#toJS'),
_staticTypeContext = StatefulStaticTypeContext.stacked(
TypeEnvironment(_coreTypes, hierarchy)) {
_inlineExtensionIndex =
InlineExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
_typeParameterBoundChecker =
_TypeParameterBoundChecker(_inlineExtensionIndex);
_extensionIndex =
ExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
_typeParameterBoundChecker = _TypeParameterBoundChecker(_extensionIndex);
}
/// Verifies given [member] is an external extension member on a static
@ -197,13 +196,13 @@ class JsInteropChecks extends RecursiveVisitor {
@override
void visitExtensionTypeDeclaration(ExtensionTypeDeclaration node) {
if (hasPackageJSAnnotation(node)) {
_reporter.report(messageJsInteropInlineClassUsedWithWrongJsAnnotation,
_reporter.report(messageJsInteropExtensionTypeUsedWithWrongJsAnnotation,
node.fileOffset, node.name.length, node.fileUri);
}
if (hasDartJSInteropAnnotation(node) &&
!_inlineExtensionIndex.isInteropInlineClass(node)) {
!_extensionIndex.isInteropExtensionType(node)) {
_reporter.report(
templateJsInteropInlineClassNotInterop.withArguments(
templateJsInteropExtensionTypeNotInterop.withArguments(
node.name, node.declaredRepresentationType, true),
node.fileOffset,
node.name.length,
@ -257,8 +256,8 @@ class JsInteropChecks extends RecursiveVisitor {
_checkSuperclassOfStaticInteropClass(node, supertype.classNode);
}
} else {
// For non-inline classes, `dart:js_interop`'s `@JS` can only be used
// with `@staticInterop`.
// For classes, `dart:js_interop`'s `@JS` can only be used with
// `@staticInterop`.
if (hasDartJSInteropAnnotation(node)) {
report(messageJsInteropDartJsInteropAnnotationForStaticInteropOnly);
}
@ -324,7 +323,7 @@ class JsInteropChecks extends RecursiveVisitor {
message, node.fileOffset, node.name.text.length, node.fileUri);
// TODO(joshualitt): Add a check that only supported operators are allowed
// in external extension members / inline classes.
// in external extension members and extension types.
_checkInstanceMemberJSAnnotation(node);
if (_classHasJSAnnotation &&
!node.isExternal &&
@ -345,9 +344,9 @@ class JsInteropChecks extends RecursiveVisitor {
// can only have named parameters, and every other interop member can only
// have positional parameters.
final isObjectLiteralConstructor = node.isExtensionTypeMember &&
(_inlineExtensionIndex.getInlineDescriptor(node)!.kind ==
(_extensionIndex.getExtensionTypeDescriptor(node)!.kind ==
ExtensionTypeMemberKind.Constructor ||
_inlineExtensionIndex.getInlineDescriptor(node)!.kind ==
_extensionIndex.getExtensionTypeDescriptor(node)!.kind ==
ExtensionTypeMemberKind.Factory) &&
node.function.namedParameters.isNotEmpty;
final isAnonymousFactory = _classHasAnonymousAnnotation && node.isFactory;
@ -386,13 +385,13 @@ class JsInteropChecks extends RecursiveVisitor {
_checkNoParamInitializersForStaticInterop(node.function);
late Annotatable? annotatable;
if (node.isExtensionTypeMember) {
annotatable = _inlineExtensionIndex.getInlineClass(node);
annotatable = _extensionIndex.getExtensionType(node);
} else if (node.isExtensionMember) {
annotatable = _inlineExtensionIndex.getExtensionAnnotatable(node);
annotatable = _extensionIndex.getExtensionAnnotatable(node);
if (annotatable != null) {
// We do not support external extension members with the 'static'
// keyword currently.
if (_inlineExtensionIndex.getExtensionDescriptor(node)!.isStatic) {
if (_extensionIndex.getExtensionDescriptor(node)!.isStatic) {
report(
messageJsInteropExternalExtensionMemberWithStaticDisallowed);
}
@ -633,16 +632,15 @@ class JsInteropChecks extends RecursiveVisitor {
if (member.isExternal) {
if (_isAllowedExternalUsage(member)) return;
if (member.isExtensionMember) {
final annotatable =
_inlineExtensionIndex.getExtensionAnnotatable(member);
final annotatable = _extensionIndex.getExtensionAnnotatable(member);
if (annotatable == null) {
_reporter.report(messageJsInteropExternalExtensionMemberOnTypeInvalid,
member.fileOffset, member.name.text.length, member.fileUri);
}
} else if (member.isExtensionTypeMember) {
final inlineClass = _inlineExtensionIndex.getInlineClass(member);
if (inlineClass == null) {
_reporter.report(messageJsInteropInlineClassMemberNotInterop,
final extensionType = _extensionIndex.getExtensionType(member);
if (extensionType == null) {
_reporter.report(messageJsInteropExtensionTypeMemberNotInterop,
member.fileOffset, member.name.text.length, member.fileUri);
}
} else if (!hasJSInteropAnnotation(member)) {
@ -660,11 +658,11 @@ class JsInteropChecks extends RecursiveVisitor {
///
/// Tear-offs of the following are disallowed when using dart:js_interop:
///
/// - External inline class constructors and factories (TODO(srujzs): Add
/// - External extension type 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
/// - External interop extension type methods
/// - External interop extension methods on @staticInterop or extension types
/// - Synthetic generative @staticInterop constructors
/// - External top-level methods
///
@ -675,22 +673,21 @@ class JsInteropChecks extends RecursiveVisitor {
var memberKind = '';
var memberName = '';
if (member.isExtensionTypeMember) {
// Inline class interop members can not be torn off.
if (_inlineExtensionIndex.getInlineClass(member) == null) {
// Extension type interop members can not be torn off.
if (_extensionIndex.getExtensionType(member) == null) {
return false;
}
memberKind = 'inline class interop member';
memberKind = 'extension type interop member';
memberName =
_inlineExtensionIndex.getInlineDescriptor(member)!.name.text;
_extensionIndex.getExtensionTypeDescriptor(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) {
if (_extensionIndex.getExtensionAnnotatable(member) == null) {
return false;
}
memberKind = 'extension interop member';
memberName =
_inlineExtensionIndex.getExtensionDescriptor(member)!.name.text;
memberName = _extensionIndex.getExtensionDescriptor(member)!.name.text;
} else if (member.enclosingClass != null) {
// @staticInterop members can not be torn off.
final enclosingClass = member.enclosingClass!;
@ -775,14 +772,14 @@ class JsInteropChecks extends RecursiveVisitor {
var isInvalidOperator = false;
var operatorHasRenaming = false;
if ((node.isExtensionTypeMember &&
_inlineExtensionIndex.getInlineDescriptor(node)?.kind ==
_extensionIndex.getExtensionTypeDescriptor(node)?.kind ==
ExtensionTypeMemberKind.Operator) ||
(node.isExtensionMember &&
_inlineExtensionIndex.getExtensionDescriptor(node)?.kind ==
_extensionIndex.getExtensionDescriptor(node)?.kind ==
ExtensionMemberKind.Operator)) {
final operator =
_inlineExtensionIndex.getInlineDescriptor(node)?.name.text ??
_inlineExtensionIndex.getExtensionDescriptor(node)?.name.text;
_extensionIndex.getExtensionTypeDescriptor(node)?.name.text ??
_extensionIndex.getExtensionDescriptor(node)?.name.text;
isInvalidOperator = operator != '[]' && operator != '[]=';
operatorHasRenaming = getJSName(node).isNotEmpty;
} else if (!node.isStatic && node.kind == ProcedureKind.Operator) {
@ -893,8 +890,8 @@ class JsInteropChecks extends RecursiveVisitor {
/// Otherwise, return null.
Member? _getTornOffFromGeneratedTearOff(Procedure procedure) {
final tornOff =
_inlineExtensionIndex.getInlineMemberForTearOff(procedure) ??
_inlineExtensionIndex.getExtensionMemberForTearOff(procedure);
_extensionIndex.getExtensionTypeMemberForTearOff(procedure) ??
_extensionIndex.getExtensionMemberForTearOff(procedure);
if (tornOff != null) return tornOff.asMember;
final name = extractConstructorNameFromTearOff(procedure.name);
if (name == null) return null;
@ -923,17 +920,17 @@ class JsInteropChecks extends RecursiveVisitor {
/// which can be:
/// - inside a JS interop class
/// - inside an extension on a JS interop or @Native annotatable
/// - inside a JS interop inline class
/// - inside a JS interop extension type
/// - a top level member that is JS interop annotated or in a package:js JS
/// interop library
bool _isJSInteropMember(Member member) {
if (member.isExternal) {
if (_classHasJSAnnotation) return true;
if (member.isExtensionMember) {
return _inlineExtensionIndex.getExtensionAnnotatable(member) != null;
return _extensionIndex.getExtensionAnnotatable(member) != null;
}
if (member.isExtensionTypeMember) {
return _inlineExtensionIndex.getInlineClass(member) != null;
return _extensionIndex.getExtensionType(member) != null;
}
if (member.enclosingClass == null) {
// dart:js_interop requires top-levels to be @JS-annotated. package:js
@ -965,8 +962,8 @@ class JsInteropChecks extends RecursiveVisitor {
(type is InterfaceType &&
hasStaticInteropAnnotation(type.classNode)) ||
(type is ExtensionType &&
_inlineExtensionIndex
.isInteropInlineClass(type.extensionTypeDeclaration)))) {
_extensionIndex
.isInteropExtensionType(type.extensionTypeDeclaration)))) {
_reporter.report(
templateJsInteropStrictModeViolation.withArguments(type, true),
node.fileOffset,
@ -986,9 +983,9 @@ class JsInteropChecks extends RecursiveVisitor {
/// Visitor used to check that all usages of type parameter types of an external
/// static interop member is a valid static interop type.
class _TypeParameterBoundChecker extends RecursiveVisitor {
final InlineExtensionIndex _inlineExtensionIndex;
final ExtensionIndex _extensionIndex;
_TypeParameterBoundChecker(this._inlineExtensionIndex);
_TypeParameterBoundChecker(this._extensionIndex);
bool _containsInvalidTypeBound = false;
@ -1011,8 +1008,9 @@ class _TypeParameterBoundChecker extends RecursiveVisitor {
@override
void visitExtensionType(ExtensionType node) {
if (_inlineExtensionIndex
.isInteropInlineClass(node.extensionTypeDeclaration)) return;
if (_extensionIndex.isInteropExtensionType(node.extensionTypeDeclaration)) {
return;
}
super.visitExtensionType(node);
}
@ -1020,8 +1018,8 @@ class _TypeParameterBoundChecker extends RecursiveVisitor {
void visitTypeParameterType(TypeParameterType node) {
final bound = node.bound;
if (bound is ExtensionType &&
!_inlineExtensionIndex
.isInteropInlineClass(bound.extensionTypeDeclaration)) {
!_extensionIndex
.isInteropExtensionType(bound.extensionTypeDeclaration)) {
_containsInvalidTypeBound = true;
}
if (bound is InterfaceType &&

View file

@ -65,7 +65,7 @@ class JsUtilOptimizer extends Transformer {
final CoreTypes _coreTypes;
final StatefulStaticTypeContext _staticTypeContext;
late final InlineExtensionIndex _inlineExtensionIndex;
late final ExtensionIndex _extensionIndex;
JsUtilOptimizer(this._coreTypes, ClassHierarchy hierarchy)
: _callMethodTarget =
@ -108,8 +108,8 @@ class JsUtilOptimizer extends Transformer {
_coreTypes.index.getProcedure('dart:core', 'List', 'empty'),
_staticTypeContext = StatefulStaticTypeContext.stacked(
TypeEnvironment(_coreTypes, hierarchy)) {
_inlineExtensionIndex =
InlineExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
_extensionIndex =
ExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
}
@override
@ -136,15 +136,15 @@ class JsUtilOptimizer extends Transformer {
/// returns null.
_InvocationBuilder? _getExternalInvocationBuilder(Procedure node) {
if (node.isExternal) {
if (_inlineExtensionIndex.isInstanceInteropMember(node)) {
var shouldTrustType = _inlineExtensionIndex.isTrustTypesMember(node);
if (_inlineExtensionIndex.isGetter(node)) {
if (_extensionIndex.isInstanceInteropMember(node)) {
var shouldTrustType = _extensionIndex.isTrustTypesMember(node);
if (_extensionIndex.isGetter(node)) {
return _getExternalGetterInvocationBuilder(node, shouldTrustType);
} else if (_inlineExtensionIndex.isSetter(node)) {
} else if (_extensionIndex.isSetter(node)) {
return _getExternalSetterInvocationBuilder(node);
} else if (_inlineExtensionIndex.isMethod(node)) {
} else if (_extensionIndex.isMethod(node)) {
return _getExternalMethodInvocationBuilder(node, shouldTrustType);
} else if (_inlineExtensionIndex.isOperator(node)) {
} else if (_extensionIndex.isOperator(node)) {
return _getExternalOperatorInvocationBuilder(node, shouldTrustType);
}
} else {
@ -156,15 +156,15 @@ class JsUtilOptimizer extends Transformer {
node, dottedPrefix.isEmpty ? [] : dottedPrefix.split('.'));
var shouldTrustType = node.enclosingClass != null &&
hasTrustTypesAnnotation(node.enclosingClass!);
if (_inlineExtensionIndex.isGetter(node)) {
if (_extensionIndex.isGetter(node)) {
return _getExternalGetterInvocationBuilder(
node, shouldTrustType, receiver);
} else if (_inlineExtensionIndex.isSetter(node)) {
} else if (_extensionIndex.isSetter(node)) {
return _getExternalSetterInvocationBuilder(node, receiver);
} else if (_inlineExtensionIndex.isMethod(node)) {
} else if (_extensionIndex.isMethod(node)) {
return _getExternalMethodInvocationBuilder(
node, shouldTrustType, receiver);
} else if (_inlineExtensionIndex.isNonLiteralConstructor(node)) {
} else if (_extensionIndex.isNonLiteralConstructor(node)) {
// Get the constructor object using the class name.
return _getExternalConstructorInvocationBuilder(
node, _getObjectOffGlobalThis(node, dottedPrefix.split('.')));
@ -182,8 +182,8 @@ class JsUtilOptimizer extends Transformer {
/// 1. A top-level member
/// 2. A `@staticInterop` factory
/// 3. A `@staticInterop` static member
/// 4. A `@JS` inline class constructor
/// 5. A `@JS` inline class static member
/// 4. A `@JS` extension type constructor
/// 5. A `@JS` extension type static member
String? _getDottedPrefixForStaticallyResolvableMember(Procedure node) {
if (!node.isExternal || node.isExtensionMember) return null;
@ -206,14 +206,14 @@ class JsUtilOptimizer extends Transformer {
} else {
Annotatable enclosingClass;
if (node.isExtensionTypeMember) {
var descriptor = _inlineExtensionIndex.getInlineDescriptor(node);
var descriptor = _extensionIndex.getExtensionTypeDescriptor(node);
if (descriptor == null ||
(!descriptor.isStatic &&
descriptor.kind != ExtensionTypeMemberKind.Constructor &&
descriptor.kind != ExtensionTypeMemberKind.Factory)) {
return null;
}
enclosingClass = _inlineExtensionIndex.getInlineClass(node)!;
enclosingClass = _extensionIndex.getExtensionType(node)!;
} else if (node.enclosingClass != null &&
hasStaticInteropAnnotation(node.enclosingClass!)) {
if (!node.isFactory && !node.isStatic) return null;
@ -221,7 +221,7 @@ class JsUtilOptimizer extends Transformer {
} else {
return null;
}
// `@staticInterop` or `@JS` inline class
// `@staticInterop` or `@JS` extension type
// factory/constructor/static member, use the class name as part of the
// dotted prefix.
var className = getJSName(enclosingClass);
@ -273,13 +273,13 @@ class JsUtilOptimizer extends Transformer {
[Expression? maybeReceiver]) {
final target =
shouldTrustType ? _getPropertyTrustTypeTarget : _getPropertyTarget;
final isOperator = _inlineExtensionIndex.isOperator(node);
final isOperator = _extensionIndex.isOperator(node);
final isInstanceInteropMember =
_inlineExtensionIndex.isInstanceInteropMember(node);
_extensionIndex.isInstanceInteropMember(node);
final name = _getMemberJSName(node);
return (Arguments arguments, Expression invocation) {
// Parameter `this` only exists for inline and extension instance members.
// Operators take a `this` and an index.
// Parameter `this` only exists for extension and extension type instance
// members. Operators take a `this` and an index.
final positionalArgs = arguments.positional;
assert(positionalArgs.length ==
(isOperator
@ -310,13 +310,13 @@ class JsUtilOptimizer extends Transformer {
/// positional argument as the receiver for `js_util.setProperty`.
_InvocationBuilder _getExternalSetterInvocationBuilder(Procedure node,
[Expression? maybeReceiver]) {
final isOperator = _inlineExtensionIndex.isOperator(node);
final isOperator = _extensionIndex.isOperator(node);
final isInstanceInteropMember =
_inlineExtensionIndex.isInstanceInteropMember(node);
_extensionIndex.isInstanceInteropMember(node);
final name = _getMemberJSName(node);
return (Arguments arguments, Expression invocation) {
// Parameter `this` only exists for inline and extension instance members.
// Operators take a `this`, an index, and a value.
// Parameter `this` only exists for extension and extension type instance
// members. Operators take a `this`, an index, and a value.
final positionalArgs = arguments.positional;
assert(positionalArgs.length ==
(isOperator
@ -353,7 +353,7 @@ class JsUtilOptimizer extends Transformer {
final target =
shouldTrustType ? _callMethodTrustTypeTarget : _callMethodTarget;
final isInstanceInteropMember =
_inlineExtensionIndex.isInstanceInteropMember(node);
_extensionIndex.isInstanceInteropMember(node);
final name = _getMemberJSName(node);
return (Arguments arguments, Expression invocation) {
var positional = arguments.positional;
@ -361,7 +361,7 @@ class JsUtilOptimizer extends Transformer {
? positional.first
: _cloner.clone(maybeReceiver);
if (isInstanceInteropMember) {
// Ignore `this` for inline and extension members.
// Ignore `this` for extension and extension type members.
positional = positional.sublist(1);
}
final callMethodInvocation = StaticInvocation(
@ -386,8 +386,8 @@ class JsUtilOptimizer extends Transformer {
_InvocationBuilder? _getExternalOperatorInvocationBuilder(
Procedure node, bool shouldTrustType) {
final operator =
_inlineExtensionIndex.getInlineDescriptor(node)?.name.text ??
_inlineExtensionIndex.getExtensionDescriptor(node)?.name.text;
_extensionIndex.getExtensionTypeDescriptor(node)?.name.text ??
_extensionIndex.getExtensionDescriptor(node)?.name.text;
switch (operator) {
case '[]':
return _getExternalGetterInvocationBuilder(node, shouldTrustType);
@ -423,7 +423,7 @@ class JsUtilOptimizer extends Transformer {
/// Returns the underlying JS name.
///
/// Returns either the name from the `@JS` annotation if non-empty, or the
/// declared name of the member. In the case of an extension or inline class
/// declared name of the member. In the case of an extension or extension type
/// member, this does not return the CFE generated name for the top level
/// member, but rather the name of the original member.
String _getMemberJSName(Procedure node) {
@ -434,9 +434,9 @@ class JsUtilOptimizer extends Transformer {
// receiver to the lowerings. Here, we just take the final identifier.
return jsAnnotationName.split('.').last;
} else if (node.isExtensionMember) {
return _inlineExtensionIndex.getExtensionDescriptor(node)!.name.text;
return _extensionIndex.getExtensionDescriptor(node)!.name.text;
} else if (node.isExtensionTypeMember) {
return _inlineExtensionIndex.getInlineDescriptor(node)!.name.text;
return _extensionIndex.getExtensionTypeDescriptor(node)!.name.text;
} else {
return node.name.text;
}
@ -678,27 +678,28 @@ class JsUtilOptimizer extends Transformer {
}
}
/// Lazily-initialized indexes for extension and inline class interop members.
/// Lazily-initialized indexes for extension and extension type interop members.
///
/// As the query APIs are called, we process the enclosing libraries of the
/// member in question if needed. We only process JS interop inline classes and
/// member in question if needed. We only process JS interop extension types and
/// extensions on either JS interop or @Native classes.
class InlineExtensionIndex {
class ExtensionIndex {
final CoreTypes _coreTypes;
final Map<Reference, Annotatable> _extensionAnnotatableIndex = {};
final Map<Reference, Extension> _extensionIndex = {};
final Map<Reference, ExtensionMemberDescriptor> _extensionMemberIndex = {};
final Map<Reference, Reference> _extensionTearOffIndex = {};
final Map<Reference, ExtensionTypeDeclaration> _inlineClassIndex = {};
final Map<Reference, ExtensionTypeMemberDescriptor> _inlineMemberIndex = {};
final Map<Reference, Reference> _inlineTearOffIndex = {};
final Map<Reference, bool> _interopInlineClassIndex = {};
final Map<Reference, ExtensionTypeDeclaration> _extensionTypeIndex = {};
final Map<Reference, ExtensionTypeMemberDescriptor>
_extensionTypeMemberIndex = {};
final Map<Reference, Reference> _extensionTypeTearOffIndex = {};
final Map<Reference, bool> _interopExtensionTypeIndex = {};
final Set<Library> _processedExtensionLibraries = {};
final Set<Library> _processedInlineLibraries = {};
final Set<Library> _processedExtensionTypeLibraries = {};
final Set<Reference> _shouldTrustType = {};
final TypeEnvironment _typeEnvironment;
InlineExtensionIndex(this._coreTypes, this._typeEnvironment);
ExtensionIndex(this._coreTypes, this._typeEnvironment);
/// If unprocessed, for all extension members in [library] whose on-type is a
/// JS interop or `@Native` class, does the following:
@ -723,17 +724,17 @@ class InlineExtensionIndex {
Annotatable? cls;
if (onType is InterfaceType) {
cls = onType.classNode;
// For now, `@trustTypes` can only be used on non-inline
// classes.
// For now, `@trustTypes` can only be used on classes and not
// extension types.
if (hasTrustTypesAnnotation(cls)) {
_shouldTrustType.add(reference);
}
isInteropOnType =
hasJSInteropAnnotation(cls) || hasNativeAnnotation(cls);
} else if (onType is ExtensionType) {
final inlineClass = onType.extensionTypeDeclaration;
cls = inlineClass;
isInteropOnType = isInteropInlineClass(inlineClass);
final extensionType = onType.extensionTypeDeclaration;
cls = extensionType;
isInteropOnType = isInteropExtensionType(extensionType);
}
if (!isInteropOnType) continue;
_extensionMemberIndex[reference] = descriptor;
@ -789,19 +790,19 @@ class InlineExtensionIndex {
}
/// Caches and returns whether the ultimate representation type that
/// corresponds to [inlineClass]' representation type is an interop type that
/// can be statically interoperable.
/// corresponds to [extensionType]'s representation type is an interop type
/// that can be statically interoperable.
///
/// This currently allows the interface type to be:
/// - all package:js classes
/// - dart:js_types types
/// - @Native types that implement JavaScriptObject
bool isInteropInlineClass(ExtensionTypeDeclaration inlineClass) {
final reference = inlineClass.reference;
if (_interopInlineClassIndex.containsKey(reference)) {
return _interopInlineClassIndex[reference]!;
bool isInteropExtensionType(ExtensionTypeDeclaration extensionType) {
final reference = extensionType.reference;
if (_interopExtensionTypeIndex.containsKey(reference)) {
return _interopExtensionTypeIndex[reference]!;
}
DartType repType = inlineClass.declaredRepresentationType;
DartType repType = extensionType.declaredRepresentationType;
// TODO(srujzs): This iteration is currently needed since
// `instantiatedRepresentationType` doesn't do this for us. Remove this
// iteration when the CFE changes this getter.
@ -823,31 +824,31 @@ class InlineExtensionIndex {
repType,
InterfaceType(javaScriptObject, Nullability.nullable),
SubtypeCheckMode.withNullabilities))) {
_interopInlineClassIndex[reference] = true;
_interopExtensionTypeIndex[reference] = true;
return true;
}
}
_interopInlineClassIndex[reference] = false;
_interopExtensionTypeIndex[reference] = false;
return false;
}
/// If unprocessed, for all inline class members in [library] whose inline
/// class is static interop, does the following:
/// If unprocessed, for all extension type members in [library] whose
/// extension type is static interop, does the following:
///
/// - Maps the inline class to its interop type
/// - Maps the member to its inline class in `_inlineClassIndex`.
/// - Maps the member to its descriptor in `_inlineMemberIndex`.
/// - Maps the extension type to its interop type
/// - Maps the member to its extension type in `_extensionTypeIndex`.
/// - Maps the member to its descriptor in `_extensionTypeMemberIndex`.
/// - Maps the tear-off member to the member it tears off in
/// `inlineTearOffIndex`.
void _indexInlineClasses(Library library) {
if (_processedInlineLibraries.contains(library)) return;
for (var inlineClass in library.extensionTypeDeclarations) {
if (isInteropInlineClass(inlineClass)) {
/// `_extensionTearOffIndex`.
void _indexExtensionTypes(Library library) {
if (_processedExtensionTypeLibraries.contains(library)) return;
for (var extensionType in library.extensionTypeDeclarations) {
if (isInteropExtensionType(extensionType)) {
final descriptorNames = <String, ExtensionTypeMemberDescriptor>{};
for (var descriptor in inlineClass.members) {
for (var descriptor in extensionType.members) {
final reference = descriptor.member;
_inlineMemberIndex[reference] = descriptor;
_inlineClassIndex[reference] = inlineClass;
_extensionTypeMemberIndex[reference] = descriptor;
_extensionTypeIndex[reference] = extensionType;
if (descriptor.kind == ExtensionTypeMemberKind.Method ||
descriptor.kind == ExtensionTypeMemberKind.Constructor ||
descriptor.kind == ExtensionTypeMemberKind.TearOff) {
@ -855,9 +856,11 @@ class InlineExtensionIndex {
if (descriptorNames.containsKey(descriptorName)) {
final previousDesc = descriptorNames[descriptorName]!;
if (previousDesc.kind == ExtensionTypeMemberKind.TearOff) {
_inlineTearOffIndex[previousDesc.member] = descriptor.member;
_extensionTypeTearOffIndex[previousDesc.member] =
descriptor.member;
} else {
_inlineTearOffIndex[descriptor.member] = previousDesc.member;
_extensionTypeTearOffIndex[descriptor.member] =
previousDesc.member;
}
} else {
descriptorNames[descriptorName] = descriptor;
@ -866,36 +869,36 @@ class InlineExtensionIndex {
}
}
}
_processedInlineLibraries.add(library);
_processedExtensionTypeLibraries.add(library);
}
ExtensionTypeMemberDescriptor? getInlineDescriptor(Member member) {
ExtensionTypeMemberDescriptor? getExtensionTypeDescriptor(Member member) {
if (!member.isExtensionTypeMember) return null;
_indexInlineClasses(member.enclosingLibrary);
return _inlineMemberIndex[member.reference];
_indexExtensionTypes(member.enclosingLibrary);
return _extensionTypeMemberIndex[member.reference];
}
ExtensionTypeDeclaration? getInlineClass(Member member) {
ExtensionTypeDeclaration? getExtensionType(Member member) {
if (!member.isExtensionTypeMember) return null;
_indexInlineClasses(member.enclosingLibrary);
return _inlineClassIndex[member.reference];
_indexExtensionTypes(member.enclosingLibrary);
return _extensionTypeIndex[member.reference];
}
Reference? getInlineMemberForTearOff(Member member) {
Reference? getExtensionTypeMemberForTearOff(Member member) {
if (!member.isExtensionTypeMember) return null;
_indexInlineClasses(member.enclosingLibrary);
return _inlineTearOffIndex[member.reference];
_indexExtensionTypes(member.enclosingLibrary);
return _extensionTypeTearOffIndex[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`
/// non-`static` or an extension type member that's declared as non-`static`
/// and is not a factory or constructor.
bool isInstanceInteropMember(Member node) {
if (node.isExtensionMember) {
var descriptor = getExtensionDescriptor(node);
return descriptor != null && !descriptor.isStatic;
} else if (node.isExtensionTypeMember) {
var descriptor = getInlineDescriptor(node);
var descriptor = getExtensionTypeDescriptor(node);
return descriptor != null &&
!descriptor.isStatic &&
descriptor.kind != ExtensionTypeMemberKind.Constructor &&
@ -904,10 +907,10 @@ class InlineExtensionIndex {
return false;
}
bool _isOneOfKinds(Procedure node, ExtensionTypeMemberKind inlineKind,
bool _isOneOfKinds(Procedure node, ExtensionTypeMemberKind extensionTypeKind,
ExtensionMemberKind extensionKind, ProcedureKind procedureKind) {
if (node.isExtensionTypeMember) {
return getInlineDescriptor(node)?.kind == inlineKind;
return getExtensionTypeDescriptor(node)?.kind == extensionTypeKind;
} else if (node.isExtensionMember) {
return getExtensionDescriptor(node)?.kind == extensionKind;
} else {
@ -946,7 +949,7 @@ class InlineExtensionIndex {
bool _isStaticInteropConstructor(Procedure node, {required bool literal}) {
if (!node.isExternal) return false;
if (node.isExtensionTypeMember) {
final kind = getInlineDescriptor(node)?.kind;
final kind = getExtensionTypeDescriptor(node)?.kind;
final namedParams = node.function.namedParameters;
return (kind == ExtensionTypeMemberKind.Constructor ||
kind == ExtensionTypeMemberKind.Factory) &&
@ -972,7 +975,7 @@ class InlineExtensionIndex {
if (type is InterfaceType) {
return hasStaticInteropAnnotation(type.classNode);
} else if (type is ExtensionType) {
return isInteropInlineClass(type.extensionTypeDeclaration);
return isInteropExtensionType(type.extensionTypeDeclaration);
} else if (type is TypeParameterType) {
return isStaticInteropType(type.bound);
}

View file

@ -65,10 +65,10 @@ class StaticInteropMockValidator {
/// even more complex when you have to account for extensions and supertypes
/// having their own type parameters too. In order to properly handle all
/// these cases, we'd have to keep constraints around and see what extensions
/// apply and what extensions don't. This may be simpler to do for inline
/// classes/extension types, as all the members are in the class and not in an
/// extension, but for now, we require that users must implement members with
/// type parameters based on their bounds.
/// apply and what extensions don't. This may be simpler to do for extension
/// types, as all the members are in the class and not in an extension, but
/// for now, we require that users must implement members with type parameters
/// based on their bounds.
///
/// Returns whether the validation passed.
bool _validateNoTypeParametersInTypeArgument(

View file

@ -2,7 +2,7 @@
// 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:_js_interop_checks/src/transformations/js_util_optimizer.dart'
show InlineExtensionIndex;
show ExtensionIndex;
import 'package:dart2wasm/js/method_collector.dart';
import 'package:dart2wasm/js/util.dart';
import 'package:kernel/ast.dart';
@ -13,10 +13,10 @@ class CallbackSpecializer {
final StatefulStaticTypeContext _staticTypeContext;
final MethodCollector _methodCollector;
final CoreTypesUtil _util;
final InlineExtensionIndex _inlineExtensionIndex;
final ExtensionIndex _extensionIndex;
CallbackSpecializer(this._staticTypeContext, this._util,
this._methodCollector, this._inlineExtensionIndex) {}
this._methodCollector, this._extensionIndex) {}
bool _needsArgumentsLength(FunctionType type) =>
type.requiredParameterCount < type.positionalParameters.length;
@ -32,7 +32,7 @@ class CallbackSpecializer {
DartType callbackParameterType = function.positionalParameters[i];
Expression expression;
VariableGet v = VariableGet(positionalParameters[i]);
if (_inlineExtensionIndex.isStaticInteropType(callbackParameterType) &&
if (_extensionIndex.isStaticInteropType(callbackParameterType) &&
boxExternRef) {
expression = _createJSValue(v);
} else {

View file

@ -5,7 +5,7 @@
import 'package:_js_interop_checks/src/js_interop.dart'
show getJSName, hasAnonymousAnnotation, hasJSInteropAnnotation;
import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart'
show InlineExtensionIndex;
show ExtensionIndex;
import 'package:dart2wasm/js/method_collector.dart';
import 'package:dart2wasm/js/util.dart';
import 'package:kernel/ast.dart';
@ -21,7 +21,7 @@ abstract class _Specializer {
final Procedure interopMethod;
final String jsString;
late final bool firstParameterIsObject =
factory._inlineExtensionIndex.isInstanceInteropMember(interopMethod);
factory._extensionIndex.isInstanceInteropMember(interopMethod);
_Specializer(this.factory, this.interopMethod, this.jsString);
@ -330,8 +330,7 @@ class _ObjectLiteralSpecializer extends _InvocationSpecializer {
_util.jsifyTarget(expr.getStaticType(_staticTypeContext)),
Arguments([expr])))
.toList();
assert(
factory._inlineExtensionIndex.isStaticInteropType(function.returnType));
assert(factory._extensionIndex.isStaticInteropType(function.returnType));
return invokeOneArg(_util.jsValueBoxTarget,
StaticInvocation(interopProcedure, Arguments(positionalArgs)));
}
@ -344,10 +343,10 @@ class InteropSpecializerFactory {
final Map<Procedure, Map<int, Procedure>> _overloadedProcedures = {};
final Map<Procedure, Map<String, Procedure>> _jsObjectLiteralMethods = {};
late String _libraryJSString;
late final InlineExtensionIndex _inlineExtensionIndex;
late final ExtensionIndex _extensionIndex;
InteropSpecializerFactory(this._staticTypeContext, this._util,
this._methodCollector, this._inlineExtensionIndex);
this._methodCollector, this._extensionIndex);
void enterLibrary(Library library) {
_libraryJSString = getJSName(library);
@ -373,17 +372,17 @@ class InteropSpecializerFactory {
_Specializer? _getSpecializerForMember(Procedure node, String jsString,
[StaticInvocation? invocation]) {
if (invocation == null) {
if (_inlineExtensionIndex.isGetter(node)) {
if (_extensionIndex.isGetter(node)) {
return _GetterSpecializer(this, node, jsString);
} else if (_inlineExtensionIndex.isSetter(node)) {
} else if (_extensionIndex.isSetter(node)) {
return _SetterSpecializer(this, node, jsString);
} else if (_inlineExtensionIndex.isOperator(node)) {
} else if (_extensionIndex.isOperator(node)) {
return _OperatorSpecializer(this, node, jsString);
} else if (_inlineExtensionIndex.isMethod(node)) {
} else if (_extensionIndex.isMethod(node)) {
return _MethodSpecializer(this, node, jsString);
}
} else {
if (_inlineExtensionIndex.isMethod(node)) {
if (_extensionIndex.isMethod(node)) {
return _MethodInvocationSpecializer(this, node, jsString, invocation);
}
}
@ -432,15 +431,15 @@ class InteropSpecializerFactory {
node, '$clsString.$memberSelectorString', invocation);
}
} else if (node.isExtensionTypeMember) {
final nodeDescriptor = _inlineExtensionIndex.getInlineDescriptor(node);
final nodeDescriptor = _extensionIndex.getExtensionTypeDescriptor(node);
if (nodeDescriptor != null) {
final cls = _inlineExtensionIndex.getInlineClass(node)!;
final cls = _extensionIndex.getExtensionType(node)!;
final clsString = _getTopLevelJSString(cls, cls.name);
final kind = nodeDescriptor.kind;
if ((kind == ExtensionTypeMemberKind.Constructor ||
kind == ExtensionTypeMemberKind.Factory)) {
return _getSpecializerForConstructor(
_inlineExtensionIndex.isLiteralConstructor(node),
_extensionIndex.isLiteralConstructor(node),
node,
clsString,
invocation);
@ -457,7 +456,7 @@ class InteropSpecializerFactory {
}
}
} else if (node.isExtensionMember) {
final nodeDescriptor = _inlineExtensionIndex.getExtensionDescriptor(node);
final nodeDescriptor = _extensionIndex.getExtensionDescriptor(node);
if (nodeDescriptor != null && !nodeDescriptor.isStatic) {
return _getSpecializerForMember(
node, _getJSString(node, nodeDescriptor.name.text), invocation);

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart'
show InlineExtensionIndex;
show ExtensionIndex;
import 'package:dart2wasm/js/callback_specializer.dart';
import 'package:dart2wasm/js/inline_expander.dart';
import 'package:dart2wasm/js/interop_specializer.dart';
@ -34,27 +34,23 @@ class InteropTransformer extends Transformer {
final CoreTypesUtil _util;
InteropTransformer._(this._staticTypeContext, this._util,
this._methodCollector, inlineExtensionIndex)
this._methodCollector, extensionIndex)
: _callbackSpecializer = CallbackSpecializer(
_staticTypeContext, _util, _methodCollector, inlineExtensionIndex),
_staticTypeContext, _util, _methodCollector, extensionIndex),
_inlineExpander =
InlineExpander(_staticTypeContext, _util, _methodCollector),
_interopSpecializerFactory = InteropSpecializerFactory(
_staticTypeContext,
_util,
_methodCollector,
inlineExtensionIndex) {}
_staticTypeContext, _util, _methodCollector, extensionIndex) {}
factory InteropTransformer(CoreTypes coreTypes, ClassHierarchy hierarchy) {
final typeEnvironment = TypeEnvironment(coreTypes, hierarchy);
final inlineExtensionIndex =
InlineExtensionIndex(coreTypes, typeEnvironment);
final util = CoreTypesUtil(coreTypes, inlineExtensionIndex);
final extensionIndex = ExtensionIndex(coreTypes, typeEnvironment);
final util = CoreTypesUtil(coreTypes, extensionIndex);
return InteropTransformer._(
StatefulStaticTypeContext.stacked(typeEnvironment),
util,
MethodCollector(util),
inlineExtensionIndex);
extensionIndex);
}
@override

View file

@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart'
show InlineExtensionIndex;
show ExtensionIndex;
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
@ -11,7 +11,7 @@ enum AnnotationType { import, export }
/// A utility wrapper for [CoreTypes].
class CoreTypesUtil {
final InlineExtensionIndex _inlineExtensionIndex;
final ExtensionIndex _extensionIndex;
final CoreTypes coreTypes;
final Procedure allowInteropTarget;
final Procedure dartifyRawTarget;
@ -27,7 +27,7 @@ class CoreTypesUtil {
final Class wasmExternRefClass;
final Procedure wrapDartFunctionTarget;
CoreTypesUtil(this.coreTypes, this._inlineExtensionIndex)
CoreTypesUtil(this.coreTypes, this._extensionIndex)
: allowInteropTarget = coreTypes.index
.getTopLevelProcedure('dart:js_util', 'allowInterop'),
dartifyRawTarget = coreTypes.index
@ -73,7 +73,7 @@ class CoreTypesUtil {
wasmExternRefClass.getThisType(coreTypes, Nullability.nullable);
Procedure jsifyTarget(DartType type) =>
_inlineExtensionIndex.isStaticInteropType(type)
_extensionIndex.isStaticInteropType(type)
? jsValueUnboxTarget
: jsifyRawTarget;
@ -112,7 +112,7 @@ class CoreTypesUtil {
return invokeOneArg(dartifyRawTarget, invocation);
} else {
Expression expression;
if (_inlineExtensionIndex.isStaticInteropType(returnType)) {
if (_extensionIndex.isStaticInteropType(returnType)) {
// TODO(joshualitt): Expose boxed `JSNull` and `JSUndefined` to Dart
// code after migrating existing users of js interop on Dart2Wasm.
// expression = _createJSValue(invocation);

View file

@ -8,7 +8,7 @@ import 'dart:io' as io;
import 'dart:math' show max, min;
import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart'
show InlineExtensionIndex;
show ExtensionIndex;
import 'package:_js_interop_checks/src/transformations/static_interop_class_eraser.dart'
show eraseStaticInteropTypesForJSCompilers;
import 'package:collection/collection.dart'
@ -275,11 +275,11 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
/// Maps uri strings in asserts and elsewhere to hoisted identifiers.
var _uriContainer = ModuleItemContainer<String>.asArray('I');
/// Index of inline and extension members in order to filter static interop
/// members.
/// Index of extension and extension type members in order to filter static
/// interop members.
// TODO(srujzs): Is there some way to share this from the js_util_optimizer to
// avoid having to recompute?
final InlineExtensionIndex _inlineExtensionIndex;
final ExtensionIndex _extensionIndex;
final Class _jsArrayClass;
final Class _privateSymbolClass;
@ -368,8 +368,8 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
'dart:_runtime', 'assertInterop') as Procedure,
_futureOrNormalizer = FutureOrNormalizer(_coreTypes),
_typeRecipeGenerator = TypeRecipeGenerator(_coreTypes, _hierarchy),
_inlineExtensionIndex = InlineExtensionIndex(
_coreTypes, _staticTypeContext.typeEnvironment);
_extensionIndex =
ExtensionIndex(_coreTypes, _staticTypeContext.typeEnvironment);
@override
Library? get currentLibrary => _currentLibrary;
@ -3089,13 +3089,14 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
/// Users are disallowed from using these tear-offs, so we should avoid
/// emitting them.
bool _isStaticInteropTearOff(Procedure p) {
final extensionMember =
_inlineExtensionIndex.getExtensionMemberForTearOff(p);
final extensionMember = _extensionIndex.getExtensionMemberForTearOff(p);
if (extensionMember != null && extensionMember.asProcedure.isExternal) {
return true;
}
final inlineMember = _inlineExtensionIndex.getInlineMemberForTearOff(p);
if (inlineMember != null && inlineMember.asProcedure.isExternal) {
final extensionTypeMember =
_extensionIndex.getExtensionTypeMemberForTearOff(p);
if (extensionTypeMember != null &&
extensionTypeMember.asProcedure.isExternal) {
return true;
}
final enclosingClass = p.enclosingClass;
@ -6380,9 +6381,8 @@ class ProgramCompiler extends ComputeOnceConstantVisitor<js_ast.Expression>
if (target.isExternal &&
target.isExtensionTypeMember &&
target.function.namedParameters.isNotEmpty) {
// JS interop checks assert that only external inline class factories have
// named parameters. We could do a more robust check by visiting all
// inline classes and recording descriptors, but that's expensive.
// JS interop checks assert that only external extension type constructors
// and factories have named parameters.
assert(target.function.positionalParameters.isEmpty);
return _emitObjectLiteral(
Arguments(node.arguments.positional,

View file

@ -3836,6 +3836,45 @@ Message _withArgumentsJsInteropExportInvalidTypeArgument(
arguments: {'type': _type});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>
templateJsInteropExtensionTypeNotInterop = const Template<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>(
problemMessageTemplate:
r"""Extension type '#name' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: '#type'.""",
correctionMessageTemplate:
r"""Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop extension types.""",
withArguments: _withArgumentsJsInteropExtensionTypeNotInterop);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>
codeJsInteropExtensionTypeNotInterop = const Code<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>(
"JsInteropExtensionTypeNotInterop",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsJsInteropExtensionTypeNotInterop(
String name, DartType _type, bool isNonNullableByDefault) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
List<Object> typeParts = labeler.labelType(_type);
String type = typeParts.join();
return new Message(codeJsInteropExtensionTypeNotInterop,
problemMessage:
"""Extension type '${name}' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: '${type}'.""" +
labeler.originMessages,
correctionMessage: """Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop extension types.""",
arguments: {'name': name, 'type': _type});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(DartType _type, bool isNonNullableByDefault)>
templateJsInteropFunctionToJSRequiresStaticType = const Template<
@ -3867,45 +3906,6 @@ Message _withArgumentsJsInteropFunctionToJSRequiresStaticType(
arguments: {'type': _type});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>
templateJsInteropInlineClassNotInterop = const Template<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>(
problemMessageTemplate:
r"""Inline class '#name' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: '#type'.""",
correctionMessageTemplate:
r"""Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop inline types.""",
withArguments: _withArgumentsJsInteropInlineClassNotInterop);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>
codeJsInteropInlineClassNotInterop = const Code<
Message Function(
String name, DartType _type, bool isNonNullableByDefault)>(
"JsInteropInlineClassNotInterop",
);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsJsInteropInlineClassNotInterop(
String name, DartType _type, bool isNonNullableByDefault) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
List<Object> typeParts = labeler.labelType(_type);
String type = typeParts.join();
return new Message(codeJsInteropInlineClassNotInterop,
problemMessage:
"""Inline class '${name}' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: '${type}'.""" +
labeler.originMessages,
correctionMessage: """Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop inline types.""",
arguments: {'name': name, 'type': _type});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(DartType _type, bool isNonNullableByDefault)>
templateJsInteropStaticInteropMockNotStaticInteropType = const Template<

View file

@ -588,18 +588,18 @@ JsInteropExportMemberCollision/analyzerCode: Fail # Web compiler specific
JsInteropExportMemberCollision/example: Fail # Web compiler specific
JsInteropExportNoExportableMembers/analyzerCode: Fail # Web compiler specific
JsInteropExportNoExportableMembers/example: Fail # Web compiler specific
JsInteropExtensionTypeNotInterop/analyzerCode: Fail # Web compiler specific
JsInteropExtensionTypeNotInterop/example: Fail # Web compiler specific
JsInteropExtensionTypeMemberNotInterop/analyzerCode: Fail # Web compiler specific
JsInteropExtensionTypeMemberNotInterop/example: Fail # Web compiler specific
JsInteropExtensionTypeUsedWithWrongJsAnnotation/analyzerCode: Fail # Web compiler specific
JsInteropExtensionTypeUsedWithWrongJsAnnotation/example: Fail # Web compiler specific
JsInteropExternalExtensionMemberOnTypeInvalid/analyzerCode: Fail # Web compiler specific
JsInteropExternalExtensionMemberOnTypeInvalid/example: Fail # Web compiler specific
JsInteropExternalExtensionMemberWithStaticDisallowed/analyzerCode: Fail # Web compiler specific
JsInteropExternalExtensionMemberWithStaticDisallowed/example: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
JsInteropInlineClassNotInterop/analyzerCode: Fail # Web compiler specific
JsInteropInlineClassNotInterop/example: Fail # Web compiler specific
JsInteropInlineClassMemberNotInterop/analyzerCode: Fail # Web compiler specific
JsInteropInlineClassMemberNotInterop/example: Fail # Web compiler specific
JsInteropInlineClassUsedWithWrongJsAnnotation/analyzerCode: Fail # Web compiler specific
JsInteropInlineClassUsedWithWrongJsAnnotation/example: Fail # Web compiler specific
JsInteropInvalidStaticClassMemberName/analyzerCode: Fail
JsInteropInvalidStaticClassMemberName/example: Fail
JsInteropJSClassExtendsDartClass/analyzerCode: Fail # Web compiler specific

View file

@ -5474,8 +5474,8 @@ JsInteropDartClassExtendsJSClass:
correctionMessage: "Try adding the JS interop annotation or removing it from the parent class."
JsInteropDartJsInteropAnnotationForStaticInteropOnly:
problemMessage: "The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through inline classes or '@staticInterop'."
correctionMessage: "Try making this class an inline class or marking it as '@staticInterop'."
problemMessage: "The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through extension types or '@staticInterop' classes."
correctionMessage: "Try making this class an extension type or marking it as '@staticInterop'."
JsInteropEnclosingClassJSAnnotation:
problemMessage: "Member has a JS interop annotation but the enclosing class does not."
@ -5514,6 +5514,18 @@ JsInteropExportNoExportableMembers:
problemMessage: "Class '#name' has no exportable members in the class or the inheritance chain."
correctionMessage: "Using `@JSExport`, annotate at least one instance member with a body or annotate a class that has such a member in the inheritance chain."
JsInteropExtensionTypeNotInterop:
problemMessage: "Extension type '#name' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: '#type'."
correctionMessage: "Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop extension types."
JsInteropExtensionTypeMemberNotInterop:
problemMessage: "Extension type member is marked 'external', but the representation type of its extension type is not a valid JS interop type."
correctionMessage: "Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop extension types."
JsInteropExtensionTypeUsedWithWrongJsAnnotation:
problemMessage: "Extension types should use the '@JS' annotation from 'dart:js_interop' and not from 'package:js'."
correctionMessage: "Try using the '@JS' annotation from 'dart:js_interop' annotation on this extension type instead."
JsInteropExternalExtensionMemberOnTypeInvalid:
problemMessage: "JS interop or Native class required for 'external' extension members."
correctionMessage: "Try adding a JS interop annotation to the on type class of the extension."
@ -5526,18 +5538,6 @@ JsInteropExternalMemberNotJSAnnotated:
problemMessage: "Only JS interop members may be 'external'."
correctionMessage: "Try removing the 'external' keyword or adding a JS interop annotation."
JsInteropInlineClassNotInterop:
problemMessage: "Inline class '#name' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: '#type'."
correctionMessage: "Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop inline types."
JsInteropInlineClassMemberNotInterop:
problemMessage: "Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type."
correctionMessage: "Try declaring a valid JS interop representation type, which may include 'dart:js_interop' types, '@staticInterop' types, 'dart:html' types, or other interop inline types."
JsInteropInlineClassUsedWithWrongJsAnnotation:
problemMessage: "Inline classes should use the '@JS' annotation from 'dart:js_interop' and not from 'package:js'."
correctionMessage: "Try using the '@JS' annotation from 'dart:js_interop' annotation on this inline class instead."
JsInteropInvalidStaticClassMemberName:
problemMessage: "JS interop static class members cannot have '.' in their JS name."

View file

@ -10,16 +10,14 @@ import 'dart:js_interop';
external void topLevel();
@JS()
inline class Inline {
final JSObject obj;
external Inline();
external Inline.named();
external Inline.literal({JSNumber? a});
Inline.nonExternal(this.obj);
// TODO(srujzs): Once we have inline class factories, test these.
// external factory Inline.fact();
// external factory Inline.literalFact({JSNumber? a});
// factory Inline.nonExternalFact() => Inline();
extension type ExtensionType.nonExternal(JSObject _) {
external ExtensionType();
external ExtensionType.named();
external ExtensionType.literal({JSNumber? a});
// TODO(srujzs): Once we have extension type factories, test these.
// external factory ExtensionType.fact();
// external factory ExtensionType.literalFact({JSNumber? a});
// factory ExtensionType.nonExternalFact() => ExtensionType();
external static void externalStatic();
static void nonExternalStatic() {}
@ -28,7 +26,7 @@ inline class Inline {
void nonExternalMethod() {}
}
extension on Inline {
extension on ExtensionType {
external void externalExtensionMethod();
void nonExternalExtensionMethod() {}
}
@ -66,22 +64,22 @@ void testMethods() {
//^
// [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];
ExtensionType.externalStatic;
// ^
// [web] Tear-offs of external extension type interop member 'externalStatic' are disallowed.
const [ExtensionType.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 type interop member 'externalStatic' are disallowed.
ExtensionType.nonExternalStatic;
final extensionType = ExtensionType();
extensionType.externalMethod;
// ^
// [web] Tear-offs of external extension type interop member 'externalMethod' are disallowed.
extensionType.nonExternalMethod;
extensionType.externalExtensionMethod;
// ^
// [web] Tear-offs of external extension interop member 'externalExtensionMethod' are disallowed.
inline.nonExternalExtensionMethod;
extensionType.nonExternalExtensionMethod;
StaticInterop.externalStatic;
// ^
@ -98,25 +96,25 @@ void testMethods() {
}
void testConstructors() {
Inline.new;
ExtensionType.new;
//^
// [web] Tear-offs of external inline class interop member 'new' are disallowed.
Inline.named;
// [web] Tear-offs of external extension type interop member 'new' are disallowed.
ExtensionType.named;
//^
// [web] Tear-offs of external inline class interop member 'named' are disallowed.
Inline.literal;
// [web] Tear-offs of external extension type interop member 'named' are disallowed.
ExtensionType.literal;
//^
// [web] Tear-offs of external inline class interop member 'literal' are disallowed.
Inline.nonExternal;
const [Inline.new];
// [web] Tear-offs of external extension type interop member 'literal' are disallowed.
ExtensionType.nonExternal;
const [ExtensionType.new];
//^
// [web] Tear-offs of external inline class interop member 'new' are disallowed.
// [web] Tear-offs of external extension type interop member 'new' are disallowed.
// TODO(srujzs): Once we have factories available, test these.
// Inline.fact;
// Inline.literalFact;
// Inline.nonExternalFact;
// const [Inline.fact];
// ExtensionType.fact;
// ExtensionType.literalFact;
// ExtensionType.nonExternalFact;
// const [ExtensionType.fact];
StaticInterop.new;
//^

View file

@ -83,13 +83,12 @@ extension UninstantiatedExtension<T, U extends JSAny?, V extends Instantiated>
external X returnX<X extends JSArray>();
}
inline class UninstantiatedInline<T, U extends JSAny?,
V extends InstantiatedInline> {
final JSObject obj;
external UninstantiatedInline(T t);
extension type UninstantiatedExtensionType<T, U extends JSAny?,
V extends InstantiatedExtensionType>._(JSObject _) {
external UninstantiatedExtensionType(T t);
// ^
// [web] External static interop members can only use type parameters that extend either a static interop type or one of the 'dart:js_interop' types.
external factory UninstantiatedInline.named(U u);
external factory UninstantiatedExtensionType.fact(U u);
// Test simple type parameters.
external T fieldT;
@ -142,8 +141,8 @@ inline class UninstantiatedInline<T, U extends JSAny?,
external X returnX<X extends JSArray>();
}
extension UninstantiatedInlineExtension<T, U extends JSAny?,
V extends InstantiatedInline> on UninstantiatedInline<T, U, V> {
extension UninstantiatedExtensionTypeExtension<T, U extends JSAny?,
V extends InstantiatedExtensionType> on UninstantiatedExtensionType<T, U, V> {
external T get extensionGetT;
// ^
// [web] External static interop members can only use type parameters that extend either a static interop type or one of the 'dart:js_interop' types.
@ -190,15 +189,14 @@ extension InstantiatedExtension on Instantiated {
external void consumeList(List<Instantiated> list);
}
inline class InstantiatedInline {
final JSObject obj;
extension type InstantiatedExtensionType._(JSObject _) {
// Test generic types where all the type parameters are instantiated.
external InstantiatedInline(List<JSNumber> list);
external List<InstantiatedInline> fieldList;
external List<InstantiatedInline> get getList;
external set setList(List<InstantiatedInline> list);
external List<InstantiatedInline> returnList();
external void consumeList(List<InstantiatedInline> list);
external InstantiatedExtensionType(List<JSNumber> list);
external List<InstantiatedExtensionType> fieldList;
external List<InstantiatedExtensionType> get getList;
external set setList(List<InstantiatedExtensionType> list);
external List<InstantiatedExtensionType> returnList();
external void consumeList(List<InstantiatedExtensionType> list);
}
void main() {}

View file

@ -9,7 +9,6 @@ library external_operator_test;
import 'dart:js_interop';
import 'package:expect/minitest.dart';
import 'package:js/js.dart' hide JS;
@JS()
external void eval(String code);
@ -30,10 +29,7 @@ external Indexable get indexableArr;
external Indexable get indexableObj;
@JS()
inline class Indexable2 {
final JSObject obj;
external Indexable2();
extension type Indexable2(JSObject _) {
external JSAny? operator [](JSNumber index);
external void operator []=(JSNumber index, JSAny? value);
}

View file

@ -14,12 +14,11 @@ import 'package:expect/minitest.dart';
@JS()
external dynamic eval(String code);
inline class Extension {
final JSObject obj;
external Extension();
extension type ExtensionType._(JSObject _) {
external ExtensionType();
}
extension E on Extension {
extension E on ExtensionType {
external String field;
@JS('field')
external String renamedField;
@ -40,7 +39,7 @@ extension E on Extension {
void main() {
eval('''
globalThis.Extension = function Extension() {
globalThis.ExtensionType = function ExtensionType() {
this.field = 'field';
this.finalField = 'finalField';
this.getSet = 'getSet';
@ -52,7 +51,7 @@ void main() {
}
}
''');
var extension = Extension();
var extension = ExtensionType();
// Fields.
expect(extension.field, 'field');

View file

@ -15,8 +15,7 @@ import 'package:expect/minitest.dart';
@JS()
external dynamic eval(String code);
inline class External<T extends JSAny?, U extends Nested> {
final JSObject obj;
extension type External<T extends JSAny?, U extends Nested>._(JSObject _) {
external External();
external String field;
@ -54,8 +53,7 @@ inline class External<T extends JSAny?, U extends Nested> {
external R combineNestedGeneric<R extends Nested>(R a, [R b]);
}
inline class Nested<T extends JSAny?> {
final JSObject obj;
extension type Nested<T extends JSAny?>._(JSObject _) {
external Nested(T value);
external T get value;

View file

@ -16,8 +16,7 @@ import 'package:expect/minitest.dart';
external dynamic eval(String code);
@JS()
inline class ExternalStatic {
final JSObject obj;
extension type ExternalStatic._(JSObject obj) {
external ExternalStatic();
// TODO(srujzs): Uncomment the external factory test once the CFE supports
// them.

View file

@ -16,8 +16,7 @@ import 'package:expect/minitest.dart';
external dynamic eval(String code);
@JS('library3.ExternalStatic')
inline class ExternalStatic {
final JSObject obj;
extension type ExternalStatic._(JSObject obj) {
external ExternalStatic();
// TODO(srujzs): Uncomment the external factory test once the CFE supports
// them.

View file

@ -20,23 +20,17 @@ external jsi.JSVoid jsiTopLevel();
external jsi.JSVoid pkgJsTopLevel();
@jsi.JS()
inline class JsiInlineClass {
final jsi.JSObject obj;
external JsiInlineClass();
}
extension type JsiExtensionType._(jsi.JSObject _) {}
@pkgJs.JS()
inline class PkgJsInlineClass {
// ^
// [web] Inline classes should use the '@JS' annotation from 'dart:js_interop' and not from 'package:js'.
final jsi.JSObject obj;
external PkgJsInlineClass();
}
extension type PkgJsExtensionType._(jsi.JSObject _) {}
// ^
// [web] Extension types should use the '@JS' annotation from 'dart:js_interop' and not from 'package:js'.
@jsi.JS()
class JsiClass {}
// ^
// [web] The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through inline classes or '@staticInterop'.
// [web] The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through extension types or '@staticInterop' classes.
@pkgJs.JS()
class PkgJsClass {}
@ -45,7 +39,7 @@ class PkgJsClass {}
@jsi.anonymous
class JsiAnonymousClass {}
// ^
// [web] The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through inline classes or '@staticInterop'.
// [web] The '@JS' annotation from 'dart:js_interop' can only be used for static interop, either through extension types or '@staticInterop' classes.
@pkgJs.JS()
@pkgJs.anonymous

View file

@ -22,9 +22,8 @@ external set topLevelSetter(JSNumber _);
external void topLevelMethod();
@JS()
inline class InlineClass {
final JSObject obj;
external InlineClass();
extension type ExtensionType._(JSObject _) {
external ExtensionType();
external JSNumber field;
external JSNumber get getter;
@ -55,7 +54,7 @@ inline class InlineClass {
external static JSVoid annotatedStaticMethod();
}
extension InlineClassExtension on InlineClass {
extension ExtensionTypeExtension on ExtensionType {
external JSNumber extensionField;
external JSNumber get extensionGetter;
external set extensionSetter(JSNumber _);

View file

@ -4,7 +4,7 @@
// SharedOptions=--enable-experiment=inline-class
// Test that interop inline classes can only work on interop types.
// Test that interop extension types can only work on interop types.
import 'dart:html';
import 'dart:js_interop';
@ -13,45 +13,32 @@ import 'package:js/js.dart' as pkgJs;
// General non-interop types.
@JS()
inline class IObject {
// ^
// [web] Inline class 'IObject' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: 'Object'.
final Object obj;
external IObject();
// ^
// [web] Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type.
}
extension type EObject(Object _) {}
// ^
// [web] Extension type 'EObject' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: 'Object'.
inline class IList {
final List<JSAny?> obj;
external IList();
extension type EList._(List<JSAny?> _) {
external EList();
// ^
// [web] Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type.
// [web] Extension type member is marked 'external', but the representation type of its extension type is not a valid JS interop type.
}
// dart:js_interop types.
inline class IJSObject {
final JSObject obj;
external IJSObject();
}
extension type EJSObject(JSObject _) {}
@JS()
inline class IJSString {
final JSString obj;
external IJSString();
}
extension type EJSString(JSString _) {}
// package:js types.
@pkgJs.JS()
class PkgJs {}
inline class IPkgJs {
final PkgJs obj;
extension type EPkgJs._(PkgJs _) {
external IPkgJs();
// ^
// [web] Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type.
// [web] Extension type member is marked 'external', but the representation type of its extension type is not a valid JS interop type.
}
@pkgJs.JS()
@ -59,65 +46,44 @@ inline class IPkgJs {
class Anonymous {}
@JS()
inline class IAnonymous {
// ^
// [web] Inline class 'IAnonymous' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: 'Anonymous'.
final Anonymous obj;
external IAnonymous();
extension type EAnonymous._(Anonymous _) {
// ^
// [web] Extension type 'EAnonymous' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: 'Anonymous'.
external EAnonymous();
// ^
// [web] Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type.
// [web] Extension type member is marked 'external', but the representation type of its extension type is not a valid JS interop type.
}
@pkgJs.JS()
@staticInterop
class PkgJsStaticInterop {}
inline class IPkgJsStaticInterop {
final PkgJsStaticInterop obj;
external IPkgJsStaticInterop();
}
extension type EPkgJsStaticInterop(PkgJsStaticInterop _) {}
@JS()
@staticInterop
class StaticInterop {}
inline class IStaticInterop {
final StaticInterop obj;
external IStaticInterop();
}
extension type EStaticInterop(StaticInterop _) {}
// @Native types.
inline class IWindow {
final Window obj;
external IWindow();
}
extension type EWindow(Window _) {}
@JS()
inline class IDocument {
final Document obj;
external IDocument();
}
extension type EDocument(Document _) {}
// Inline types.
// Extension types.
inline class IInlineInterop {
final IJSObject obj;
external IInlineInterop();
}
extension type EExtensionType(EJSObject _) {}
@JS()
inline class IInlineInterop2 {
final IInlineInterop obj;
external IInlineInterop2();
}
extension type EExtensionType2(EExtensionType _) {}
@JS()
inline class IInlineNonInterop {
// ^
// [web] Inline class 'IInlineNonInterop' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: 'IObject'.
final IObject obj;
external IInlineNonInterop();
extension type ENonInterop._(EObject _) {
// ^
// [web] Extension type 'ENonInterop' is marked with a '@JS' annotation, but its representation type is not a valid JS interop type: 'EObject'.
external ENonInterop();
// ^
// [web] Inline class member is marked 'external', but the representation type of its inline class is not a valid JS interop type.
// [web] Extension type member is marked 'external', but the representation type of its extension type is not a valid JS interop type.
}

View file

@ -13,8 +13,7 @@ import 'dart:js_util';
import 'package:expect/minitest.dart';
@JS()
inline class Literal {
final JSObject obj;
extension type Literal._(JSObject _) {
external Literal({double? a, String b, bool? c});
}

View file

@ -12,10 +12,9 @@ external void topLevel({JSNumber named});
// [web] Named parameters for JS interop functions are only allowed in object literal constructors or @anonymous factories.
@JS()
inline class Inline {
final JSObject obj;
external Inline.positionalNamed(JSNumber positional, {JSNumber named});
// ^
extension type ExtensionType(JSObject _) {
external ExtensionType.positionalNamed(JSNumber positional, {JSNumber named});
// ^
// [web] Object literal constructors should not contain any positional parameters.
external static void staticMethod({JSNumber named});
// ^
@ -25,7 +24,7 @@ inline class Inline {
// [web] Named parameters for JS interop functions are only allowed in object literal constructors or @anonymous factories.
}
extension on Inline {
extension on ExtensionType {
external void extensionMethod({JSNumber named});
// ^
// [web] Named parameters for JS interop functions are only allowed in object literal constructors or @anonymous factories.

View file

@ -80,10 +80,7 @@ extension _ on StaticInterop {
}
@JS()
inline class Inline {
final JSObject obj;
external Inline();
extension type ExtensionType(JSObject _) {
external void operator <(_);
// ^
// [web] JS interop classes do not support operator methods, with the exception of '[]' and '[]=' using static interop.

View file

@ -80,12 +80,9 @@ extension on StaticInterop {
}
@JS()
inline class InlineClass {
final JSObject obj;
external InlineClass();
}
extension type ExtensionType(JSObject _) {}
extension on InlineClass {
extension on ExtensionType {
external static JSNumber field;
// ^
// [web] External extension members with the keyword 'static' on JS interop and @Native types are disallowed.

View file

@ -79,10 +79,7 @@ extension JSClassExtension on JSClass {
}
@JS()
inline class Inline {
final JSObject obj;
external Inline();
}
extension type ExtensionType(JSObject _) {}
@JS()
external void jsFunctionTest(JSFunction foo);
@ -91,7 +88,7 @@ external void jsFunctionTest(JSFunction foo);
external void useStaticInteropClass(JSClass foo);
@JS()
external void useStaticInteropInlineClass(Inline foo);
external void useStaticInteropExtensionType(ExtensionType foo);
void main() {
jsFunctionTest(((double foo) => 4.0.toJS).toJS);
@ -105,4 +102,4 @@ void main() {
jsFunctionTest(((((JSNumber foo) => 4.0) as dynamic) as Function).toJS);
// ^
// [web] `Function.toJS` requires a statically known function type, but Type 'Function' is not a function type, e.g., `void Function()`.
}
}