mirror of
https://github.com/dart-lang/sdk
synced 2024-10-01 19:14:49 +00:00
[pkg:js] Disallow external extension members with type parameters
Bug: https://github.com/dart-lang/sdk/issues/49350 Checks to see that external extension members on `@staticInterop` types do not declare or use a type parameter. Change-Id: Id8646b599094b748c5490810b64d872065676014 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/254103 Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Srujan Gaddam <srujzs@google.com> Reviewed-by: Joshua Litt <joshualitt@google.com>
This commit is contained in:
parent
b6526beeab
commit
521cbcdd47
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -112,12 +112,17 @@
|
|||
|
||||
#### `package:js`
|
||||
|
||||
- **Breaking change**: Classes with the preview annotation `@staticInterop` are
|
||||
now disallowed from using `external` generative constructors. Use
|
||||
`external factory`s for these classes instead. See [#48730][] for more
|
||||
details.
|
||||
- **Breaking changes to the preview feature `@staticInterop`**:
|
||||
- Classes with this annotation are now disallowed from using `external`
|
||||
generative constructors. Use `external factory`s for these classes instead,
|
||||
and the behavior should be identical. See [#48730][] for more details.
|
||||
- Classes with this annotation's external extension members are now disallowed
|
||||
from using type parameters e.g. `external void method<T>(T t)`. Use a
|
||||
non-`external` extension method for type parameters instead. See [#49350][]
|
||||
for more details.
|
||||
|
||||
[#48730]: https://github.com/dart-lang/sdk/issues/48730
|
||||
[#49350]: https://github.com/dart-lang/sdk/issues/49350
|
||||
|
||||
### Tools
|
||||
|
||||
|
|
|
@ -7121,6 +7121,22 @@ 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>
|
||||
codeJsInteropStaticInteropExternalExtensionMembersWithTypeParameters =
|
||||
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters;
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const MessageCode
|
||||
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters =
|
||||
const MessageCode(
|
||||
"JsInteropStaticInteropExternalExtensionMembersWithTypeParameters",
|
||||
problemMessage:
|
||||
r"""`@staticInterop` classes cannot have external extension members with type parameters.""",
|
||||
correctionMessage:
|
||||
r"""Try using a Dart extension member if you need type parameters instead.""");
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Code<Null> codeJsInteropStaticInteropGenerativeConstructor =
|
||||
messageJsInteropStaticInteropGenerativeConstructor;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
|
|||
messageJsInteropNonExternalConstructor,
|
||||
messageJsInteropNonExternalMember,
|
||||
messageJsInteropOperatorsNotSupported,
|
||||
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters,
|
||||
messageJsInteropStaticInteropGenerativeConstructor,
|
||||
templateJsInteropDartClassExtendsJSClass,
|
||||
templateJsInteropStaticInteropWithInstanceMembers,
|
||||
|
@ -34,6 +35,7 @@ class JsInteropChecks extends RecursiveVisitor {
|
|||
final CoreTypes _coreTypes;
|
||||
final DiagnosticReporter<Message, LocatedMessage> _diagnosticsReporter;
|
||||
final Map<String, Class> _nativeClasses;
|
||||
final _TypeParameterVisitor _typeParameterVisitor = _TypeParameterVisitor();
|
||||
bool _classHasJSAnnotation = false;
|
||||
bool _classHasAnonymousAnnotation = false;
|
||||
bool _classHasStaticInteropAnnotation = false;
|
||||
|
@ -301,6 +303,26 @@ class JsInteropChecks extends RecursiveVisitor {
|
|||
procedure.name.text.length,
|
||||
procedure.fileUri);
|
||||
}
|
||||
|
||||
if (procedure.isExternal &&
|
||||
procedure.isExtensionMember &&
|
||||
_isStaticInteropExtensionMember(procedure)) {
|
||||
// If the extension has type parameters of its own, it copies those type
|
||||
// parameters to the procedure's type parameters (in the front) as well.
|
||||
// Ignore these for the analysis.
|
||||
var extensionTypeParams =
|
||||
_libraryExtensionsIndex![procedure.reference]!.typeParameters;
|
||||
var procedureTypeParams = List.from(procedure.function.typeParameters);
|
||||
procedureTypeParams.removeRange(0, extensionTypeParams.length);
|
||||
if (procedureTypeParams.isNotEmpty ||
|
||||
_typeParameterVisitor.usesTypeParameters(procedure)) {
|
||||
_diagnosticsReporter.report(
|
||||
messageJsInteropStaticInteropExternalExtensionMembersWithTypeParameters,
|
||||
procedure.fileOffset,
|
||||
procedure.name.text.length,
|
||||
procedure.fileUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -450,6 +472,12 @@ class JsInteropChecks extends RecursiveVisitor {
|
|||
return _checkExtensionMember(member, hasJSInteropAnnotation);
|
||||
}
|
||||
|
||||
/// Returns whether given extension [member] is in an extension that is on a
|
||||
/// `@staticInterop` class.
|
||||
bool _isStaticInteropExtensionMember(Member member) {
|
||||
return _checkExtensionMember(member, hasStaticInteropAnnotation);
|
||||
}
|
||||
|
||||
/// Returns whether given extension [member] is in an extension on a Native
|
||||
/// class.
|
||||
bool _isNativeExtensionMember(Member member) {
|
||||
|
@ -471,3 +499,18 @@ class JsInteropChecks extends RecursiveVisitor {
|
|||
return onType is InterfaceType && validateExtensionClass(onType.classNode);
|
||||
}
|
||||
}
|
||||
|
||||
class _TypeParameterVisitor extends RecursiveVisitor {
|
||||
bool _visitedTypeParameterType = false;
|
||||
|
||||
bool usesTypeParameters(Node node) {
|
||||
_visitedTypeParameterType = false;
|
||||
node.accept(this);
|
||||
return _visitedTypeParameterType;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTypeParameterType(TypeParameterType node) {
|
||||
_visitedTypeParameterType = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -579,6 +579,8 @@ JsInteropNonExternalMember/analyzerCode: Fail # Web compiler specific
|
|||
JsInteropNonExternalMember/example: Fail # Web compiler specific
|
||||
JsInteropOperatorsNotSupported/analyzerCode: Fail # Web compiler specific
|
||||
JsInteropOperatorsNotSupported/example: Fail # Web compiler specific
|
||||
JsInteropStaticInteropExternalExtensionMembersWithTypeParameters/analyzerCode: Fail # Web compiler specific
|
||||
JsInteropStaticInteropExternalExtensionMembersWithTypeParameters/example: Fail # Web compiler specific
|
||||
JsInteropStaticInteropGenerativeConstructor/analyzerCode: Fail # Web compiler specific
|
||||
JsInteropStaticInteropGenerativeConstructor/example: Fail # Web compiler specific
|
||||
JsInteropStaticInteropMockExternalExtensionMemberConflict/analyzerCode: Fail # Web compiler specific
|
||||
|
|
|
@ -5266,6 +5266,10 @@ JsInteropStaticInteropMockNotStaticInteropType:
|
|||
problemMessage: "First type argument '#type' is not a `@staticInterop` type."
|
||||
correctionMessage: "Use a `@staticInterop` class 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."
|
||||
|
||||
JsInteropStaticInteropWithInstanceMembers:
|
||||
problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
|
||||
correctionMessage: "Try moving the instance member to a static extension."
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2022, 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 external_extension_member_type_parameters_static_test;
|
||||
|
||||
import 'package:js/js.dart';
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class Uninstantiated {}
|
||||
|
||||
typedef TypedefT<T> = T Function();
|
||||
|
||||
extension E1<T> on Uninstantiated {
|
||||
// Test simple type parameters.
|
||||
external T fieldT;
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external T get getT;
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external set setT(T t);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external T returnT();
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void consumeT(T t);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
|
||||
// Test type parameters in a nested type context.
|
||||
external List<T> fieldNestedT;
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void Function(T) get getNestedT;
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external set setNestedT(TypedefT<T> nestedT);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external List<Map<T, T>> returnNestedT();
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void consumeNestedT(Set<TypedefT<T>> nestedT);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
|
||||
// Test type parameters that are declared by the member.
|
||||
external U returnU<U>();
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void consumeU<U>(U u);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
}
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class Instantiated {}
|
||||
|
||||
extension E2 on Instantiated {
|
||||
// Test generic types where there all the type parameters are instantiated.
|
||||
external List<int> fieldList;
|
||||
external List<int> get getList;
|
||||
external set setList(List<int> list);
|
||||
external List<int> returnList();
|
||||
external void consumeList(List<int> list);
|
||||
}
|
||||
|
||||
// Extension members that don't declare or use type parameters should not be
|
||||
// affected by whether their extension declares a type parameter.
|
||||
@JS()
|
||||
@staticInterop
|
||||
class ExtensionWithTypeParams {}
|
||||
|
||||
extension E3<T> on ExtensionWithTypeParams {
|
||||
external void noTypeParams();
|
||||
external void declareTypeParam<U>(U u);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void useTypeParam(T t);
|
||||
// ^
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
}
|
||||
|
||||
void main() {}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2022, 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 external_extension_member_type_parameters_static_test;
|
||||
|
||||
import 'package:js/js.dart';
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class Uninstantiated {}
|
||||
|
||||
typedef TypedefT<T> = T Function();
|
||||
|
||||
extension E1<T> on Uninstantiated {
|
||||
// Test simple type parameters.
|
||||
external T get getT;
|
||||
// [error column 18]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external set setT(T t);
|
||||
// [error column 16]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external T returnT();
|
||||
// [error column 14]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void consumeT(T t);
|
||||
// [error column 17]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
|
||||
// Test type parameters in a nested type context.
|
||||
external void Function(T) get getNestedT;
|
||||
// [error column 33]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external set setNestedT(TypedefT<T> nestedT);
|
||||
// [error column 16]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external List<Map<T, T>> returnNestedT();
|
||||
// [error column 28]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void consumeNestedT(Set<TypedefT<T>> nestedT);
|
||||
// [error column 17]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
|
||||
// Test type parameters that are declared by the member.
|
||||
external U returnU<U>();
|
||||
// [error column 14]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
external void consumeU<U>(U u);
|
||||
// [error column 17]
|
||||
// [web] `@staticInterop` classes cannot have external extension members with type parameters.
|
||||
}
|
||||
|
||||
@JS()
|
||||
@staticInterop
|
||||
class Instantiated {}
|
||||
|
||||
extension E2 on Instantiated {
|
||||
// Test generic types where there all the type parameters are instantiated.
|
||||
external List<int> get getList;
|
||||
external set setList(List<int> list);
|
||||
external List<int> returnList();
|
||||
external void consumeList(List<int> list);
|
||||
}
|
||||
|
||||
void main() {}
|
Loading…
Reference in a new issue