Version 2.14.0-370.0.dev
Merge commit 'b13dc22338bee08f38029de3afb5c21a2569bd58' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 2ccb299..01dd119 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -6237,14 +6237,14 @@
message: r"""This is the enclosing class.""");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Null> codeJsInteropExternalExtensionMemberNotOnJSClass =
- messageJsInteropExternalExtensionMemberNotOnJSClass;
+const Code<Null> codeJsInteropExternalExtensionMemberOnTypeInvalid =
+ messageJsInteropExternalExtensionMemberOnTypeInvalid;
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const MessageCode messageJsInteropExternalExtensionMemberNotOnJSClass =
- const MessageCode("JsInteropExternalExtensionMemberNotOnJSClass",
+const MessageCode messageJsInteropExternalExtensionMemberOnTypeInvalid =
+ const MessageCode("JsInteropExternalExtensionMemberOnTypeInvalid",
message:
- r"""JS interop class required for 'external' extension members.""",
+ r"""JS interop or Native class required for 'external' extension members.""",
tip:
r"""Try adding a JS interop annotation to the on type class of the extension.""");
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 7567930..975fca7 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -12,7 +12,7 @@
messageJsInteropAnonymousFactoryPositionalParameters,
messageJsInteropEnclosingClassJSAnnotation,
messageJsInteropEnclosingClassJSAnnotationContext,
- messageJsInteropExternalExtensionMemberNotOnJSClass,
+ messageJsInteropExternalExtensionMemberOnTypeInvalid,
messageJsInteropExternalMemberNotJSAnnotated,
messageJsInteropIndexNotSupported,
messageJsInteropNamedParameters,
@@ -282,13 +282,14 @@
/// [member] is `external` and not an allowed `external` usage.
void _checkDisallowedExternal(Member member) {
if (member.isExternal) {
- // TODO(rileyporter): Allow extension members on some Native classes.
if (member.isExtensionMember) {
- _diagnosticsReporter.report(
- messageJsInteropExternalExtensionMemberNotOnJSClass,
- member.fileOffset,
- member.name.text.length,
- member.fileUri);
+ if (!_isNativeExtensionMember(member)) {
+ _diagnosticsReporter.report(
+ messageJsInteropExternalExtensionMemberOnTypeInvalid,
+ member.fileOffset,
+ member.name.text.length,
+ member.fileUri);
+ }
} else if (!hasJSInteropAnnotation(member) &&
!_isAllowedExternalUsage(member)) {
// Member could be JS annotated and not considered a JS interop member
@@ -338,6 +339,18 @@
/// Returns whether given extension [member] is in an extension that is on a
/// JS interop class.
bool _isJSExtensionMember(Member member) {
+ return _checkExtensionMember(member, hasJSInteropAnnotation);
+ }
+
+ /// Returns whether given extension [member] is in an extension on a Native
+ /// class.
+ bool _isNativeExtensionMember(Member member) {
+ return _checkExtensionMember(member, _nativeClasses.containsValue);
+ }
+
+ /// Returns whether given extension [member] is on a class that passses the
+ /// given [validateExtensionClass].
+ bool _checkExtensionMember(Member member, Function validateExtensionClass) {
assert(member.isExtensionMember);
if (_libraryExtensionsIndex == null) {
_libraryExtensionsIndex = {};
@@ -347,6 +360,6 @@
}
var onType = _libraryExtensionsIndex![member.reference]!.onType;
- return onType is InterfaceType && hasJSInteropAnnotation(onType.classNode);
+ return onType is InterfaceType && validateExtensionClass(onType.classNode);
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
index 7f60edd..bd175b9 100644
--- a/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
+++ b/pkg/analysis_server/lib/src/services/completion/yaml/analysis_options_generator.dart
@@ -30,6 +30,7 @@
AnalyzerOptions.chromeOsManifestChecks: EmptyProducer(),
}),
AnalyzerOptions.plugins: EmptyProducer(),
+ AnalyzerOptions.propagateLinterExceptions: EmptyProducer(),
AnalyzerOptions.strong_mode: MapProducer({
AnalyzerOptions.declarationCasts: EmptyProducer(),
AnalyzerOptions.implicitCasts: EmptyProducer(),
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index aec3305..af4dab4 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/testing_data.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/constant/compute.dart';
import 'package:analyzer/src/dart/constant/constant_verifier.dart';
import 'package:analyzer/src/dart/constant/evaluation.dart';
@@ -351,7 +352,10 @@
}
// Run lints that handle specific node types.
- unit.accept(LinterVisitor(nodeRegistry));
+ unit.accept(LinterVisitor(
+ nodeRegistry,
+ LinterExceptionHandler(_analysisOptions.propagateLinterExceptions)
+ .logException));
}
void _computeVerifyErrors(FileState file, CompilationUnit unit) {
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index a068ad7..4387e37 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -1306,6 +1306,12 @@
///
/// Clients may not extend, implement or mix-in this class.
class LinterExceptionHandler {
+ /// Indicates whether linter exceptions should be propagated to the caller (by
+ /// re-throwing them)
+ final bool propagateLinterExceptions;
+
+ LinterExceptionHandler(this.propagateLinterExceptions);
+
/// A method that can be passed to the `LinterVisitor` constructor to handle
/// exceptions that occur during linting.
void logException(
@@ -1326,6 +1332,9 @@
// TODO(39284): should this exception be silent?
AnalysisEngine.instance.instrumentationService.logException(
SilentException(buffer.toString(), exception, stackTrace));
+ if (propagateLinterExceptions) {
+ throw exception;
+ }
}
}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 0b1635c..327af6e 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -348,7 +348,10 @@
}
// Run lints that handle specific node types.
- unit.accept(LinterVisitor(nodeRegistry));
+ unit.accept(LinterVisitor(
+ nodeRegistry,
+ LinterExceptionHandler(_analysisOptions.propagateLinterExceptions)
+ .logException));
}
void _computeVerifyErrors(FileState file, CompilationUnit unit) {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 7f04b64..c678842 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -281,6 +281,10 @@
/// This option is experimental and subject to change.
bool implicitDynamic = true;
+ /// Indicates whether linter exceptions should be propagated to the caller (by
+ /// re-throwing them)
+ bool propagateLinterExceptions = false;
+
/// A flag indicating whether inference failures are allowed, off by default.
///
/// This option is experimental and subject to change.
@@ -319,6 +323,7 @@
if (options is AnalysisOptionsImpl) {
implicitCasts = options.implicitCasts;
implicitDynamic = options.implicitDynamic;
+ propagateLinterExceptions = options.propagateLinterExceptions;
strictInference = options.strictInference;
strictRawTypes = options.strictRawTypes;
}
@@ -382,6 +387,7 @@
// Append boolean flags.
buffer.addBool(implicitCasts);
buffer.addBool(implicitDynamic);
+ buffer.addBool(propagateLinterExceptions);
buffer.addBool(strictInference);
buffer.addBool(strictRawTypes);
buffer.addBool(useFastaParser);
diff --git a/pkg/analyzer/lib/src/lint/linter_visitor.dart b/pkg/analyzer/lib/src/lint/linter_visitor.dart
index 25afec4..0794a4c 100644
--- a/pkg/analyzer/lib/src/lint/linter_visitor.dart
+++ b/pkg/analyzer/lib/src/lint/linter_visitor.dart
@@ -19,7 +19,7 @@
LinterVisitor(this.registry, [LintRuleExceptionHandler? exceptionHandler])
: exceptionHandler =
- exceptionHandler ?? LinterExceptionHandler().logException;
+ exceptionHandler ?? LinterExceptionHandler(true).logException;
@override
void visitAdjacentStrings(AdjacentStrings node) {
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 28b4452..2efaaa1 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -151,6 +151,8 @@
/// Ways to say `include`.
static const List<String> includeSynonyms = ['include', 'true'];
+ static const String propagateLinterExceptions = 'propagate-linter-exceptions';
+
/// Ways to say `true` or `false`.
static const List<String> trueOrFalse = ['true', 'false'];
@@ -163,6 +165,7 @@
language,
optionalChecks,
plugins,
+ propagateLinterExceptions,
strong_mode,
];
@@ -805,6 +808,9 @@
if (feature == AnalyzerOptions.implicitDynamic) {
options.implicitDynamic = boolValue;
}
+ if (feature == AnalyzerOptions.propagateLinterExceptions) {
+ options.propagateLinterExceptions = boolValue;
+ }
}
}
diff --git a/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart b/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart
index f0a3fd2..44a7634 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_builder_test.dart
@@ -236,6 +236,8 @@
);
expect(actual.implicitCasts, expected.implicitCasts);
expect(actual.implicitDynamic, expected.implicitDynamic);
+ expect(
+ actual.propagateLinterExceptions, expected.propagateLinterExceptions);
expect(actual.strictInference, expected.strictInference);
expect(actual.strictRawTypes, expected.strictRawTypes);
}
diff --git a/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart b/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
index 930fce7..54fd3b5 100644
--- a/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
+++ b/pkg/dev_compiler/lib/src/kernel/asset_file_system.dart
@@ -16,11 +16,18 @@
/// A wrapper around asset server that redirects file read requests
/// to http get requests to the asset server.
class AssetFileSystem implements FileSystem {
- FileSystem original;
+ final FileSystem original;
final String server;
final String port;
+ final RetryTimeoutClient client;
- AssetFileSystem(this.original, this.server, this.port);
+ AssetFileSystem(this.original, this.server, this.port)
+ : client = RetryTimeoutClient(
+ HttpClient()
+ ..maxConnectionsPerHost = 200
+ ..connectionTimeout = const Duration(seconds: 30)
+ ..idleTimeout = const Duration(seconds: 30),
+ retries: 4);
/// Convert the uri to a server uri.
Uri _resourceUri(Uri uri) => Uri.parse('http://$server:$port/${uri.path}');
@@ -34,6 +41,10 @@
// Pass the uri to the asset server in the debugger.
return AssetFileSystemEntity(this, _resourceUri(uri));
}
+
+ void close() {
+ client?.close(force: true);
+ }
}
class AssetFileSystemEntity implements FileSystemEntity {
@@ -85,20 +96,16 @@
});
}
- /// Execute the [body] with the new http client.
+ /// Execute the [body] with the http client created in [fileSystem].
///
/// Throws a [FileSystemException] on failure,
/// and cleans up the client on return or error.
Future<T> _runWithClient<T>(
Future<T> Function(RetryTimeoutClient httpClient) body) async {
- RetryTimeoutClient httpClient;
try {
- httpClient = RetryTimeoutClient(HttpClient(), retries: 5);
- return await body(httpClient);
+ return await body(fileSystem.client);
} on Exception catch (e, s) {
throw FileSystemException(uri, '$e:$s');
- } finally {
- httpClient?.close(force: true);
}
}
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 1cdbd66..86a0cc2 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -113,24 +113,30 @@
/// receive port corresponding to [sendPort].
static Future<void> createAndStart(List<String> args,
{SendPort sendPort}) async {
+ ExpressionCompilerWorker worker;
if (sendPort != null) {
var receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
try {
- var worker = await createFromArgs(args,
+ worker = await createFromArgs(args,
requestStream: receivePort.cast<Map<String, dynamic>>(),
sendResponse: sendPort.send);
- await worker.start();
+ await worker.run();
} catch (e, s) {
sendPort
.send({'exception': '$e', 'stackTrace': '$s', 'succeeded': false});
rethrow;
} finally {
receivePort.close();
+ worker?.close();
}
} else {
- var worker = await createFromArgs(args);
- await worker.start();
+ try {
+ worker = await createFromArgs(args);
+ await worker.run();
+ } finally {
+ worker?.close();
+ }
}
}
@@ -243,7 +249,7 @@
///
/// Completes when the [requestStream] closes and we finish handling the
/// requests.
- Future<void> start() async {
+ Future<void> run() async {
await for (var request in requestStream) {
try {
var command = request['command'] as String;
@@ -275,6 +281,11 @@
_processedOptions.ticker.logMs('Stopped expression compiler worker.');
}
+ void close() {
+ var fileSystem = _processedOptions?.fileSystem;
+ if (fileSystem != null && fileSystem is AssetFileSystem) fileSystem.close();
+ }
+
/// Handles a `CompileExpression` request.
Future<Map<String, dynamic>> _compileExpression(
CompileExpressionRequest request) async {
diff --git a/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart b/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
index 94a6543..ca481dc 100644
--- a/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/asset_file_system_test.dart
@@ -7,7 +7,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io' show HttpServer;
-import 'dart:math';
import 'package:browser_launcher/browser_launcher.dart';
import 'package:dev_compiler/src/kernel/asset_file_system.dart';
@@ -67,6 +66,7 @@
return Response.internalServerError();
}
+int _attempts = 0;
FutureOr<Response> unreliableHandler(Request request) {
final uri = request.requestedUri;
final headers = {
@@ -74,7 +74,7 @@
...request.headers,
};
- if (Random().nextInt(3) == 0) return Response.internalServerError();
+ if ((_attempts++) % 5 == 0) return Response.internalServerError();
if (request.method == 'HEAD') {
// 'exists'
@@ -112,6 +112,7 @@
tearDownAll(() async {
await expectLater(server.close(), completes);
+ fileSystem.close();
});
test('can tell if file exists', () async {
@@ -148,12 +149,10 @@
test('can read a lot of files concurrently', () async {
var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
var futures = [
- for (var i = 0; i < 512; i++) entity.readAsBytes(),
+ for (var i = 0; i < 512; i++)
+ _expectContents(entity, _smallFileContents),
];
- var results = await Future.wait(futures);
- for (var result in results) {
- expect(utf8.decode(result), _smallFileContents);
- }
+ await Future.wait(futures);
}, timeout: const Timeout.factor(2));
});
@@ -171,6 +170,7 @@
tearDownAll(() async {
await expectLater(server.close(), completes);
+ fileSystem.close();
});
test('can tell if file exists', () async {
@@ -225,15 +225,12 @@
});
test('can read a lot of files concurrently', () async {
+ var fileContents = _largeFileContents();
var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
var futures = [
- for (var i = 0; i < 512; i++) entity.readAsString(),
+ for (var i = 0; i < 512; i++) _expectContents(entity, fileContents),
];
- var results = await Future.wait(futures);
- var fileContents = _largeFileContents();
- for (var result in results) {
- expect(result, fileContents);
- }
+ await Future.wait(futures);
}, timeout: const Timeout.factor(2));
});
@@ -251,6 +248,7 @@
tearDownAll(() async {
await expectLater(server.close(), completes);
+ fileSystem.close();
});
test('can tell if file exists', () async {
@@ -287,12 +285,10 @@
test('can read a lot of files concurrently', () async {
var entity = fileSystem.entityForUri(Uri.parse(_existingFile));
var futures = [
- for (var i = 0; i < 512; i++) entity.readAsString(),
+ for (var i = 0; i < 512; i++)
+ _expectContents(entity, _smallFileContents),
];
- var results = await Future.wait(futures);
- for (var result in results) {
- expect(result, _smallFileContents);
- }
+ await Future.wait(futures);
}, timeout: const Timeout.factor(2));
});
@@ -310,6 +306,7 @@
tearDownAll(() async {
await expectLater(server.close(), completes);
+ fileSystem.close();
});
test('cannot tell if file exists', () async {
@@ -341,3 +338,11 @@
});
});
}
+
+// Read the response (and free the socket) as soon as we get it.
+// That allows some connection to buffer and wait for free sockets
+// when the limit if connections is reached.
+Future<void> _expectContents(FileSystemEntity entity, String contents) async {
+ var result = await entity.readAsString();
+ expect(result, contents);
+}
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
index 9a06c77..c54916b 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
@@ -836,13 +836,14 @@
soundNullSafety: soundNullSafety,
verbose: verbose,
);
- workerDone = worker.start();
+ workerDone = worker.run();
}
Future<void> tearDown() async {
unawaited(requestController.close());
await workerDone;
unawaited(responseController.close());
+ worker?.close();
}
}
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index ba2bc55..8eb1f8d 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -514,8 +514,8 @@
JsInteropDartClassExtendsJSClass/example: Fail # Web compiler specific
JsInteropEnclosingClassJSAnnotation/analyzerCode: Fail # Web compiler specific
JsInteropEnclosingClassJSAnnotation/example: Fail # Web compiler specific
-JsInteropExternalExtensionMemberNotOnJSClass/analyzerCode: Fail # Web compiler specific
-JsInteropExternalExtensionMemberNotOnJSClass/example: Fail # Web compiler specific
+JsInteropExternalExtensionMemberOnTypeInvalid/analyzerCode: Fail # Web compiler specific
+JsInteropExternalExtensionMemberOnTypeInvalid/example: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
JsInteropIndexNotSupported/analyzerCode: Fail # Web compiler specific
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 0873cba..e94eac1 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4914,8 +4914,8 @@
template: "This is the enclosing class."
severity: CONTEXT
-JsInteropExternalExtensionMemberNotOnJSClass:
- template: "JS interop class required for 'external' extension members."
+JsInteropExternalExtensionMemberOnTypeInvalid:
+ template: "JS interop or Native class required for 'external' extension members."
tip: "Try adding a JS interop annotation to the on type class of the extension."
JsInteropExternalMemberNotJSAnnotated:
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 7c958ce..2518fb5 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -10,8 +10,6 @@
constructor_tearoffs/call_instantiation: TypeCheckError
constructor_tearoffs/const_tear_off: RuntimeError
-constructor_tearoffs/inferred_constructor_tear_off: RuntimeError
-constructor_tearoffs/inferred_non_proper_rename: RuntimeError
constructor_tearoffs/redirecting_constructors: RuntimeError
constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 9f5f24a..7ea4ce0 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -8,8 +8,6 @@
constructor_tearoffs/call_instantiation: TypeCheckError
constructor_tearoffs/const_tear_off: RuntimeError
-constructor_tearoffs/inferred_constructor_tear_off: RuntimeError
-constructor_tearoffs/inferred_non_proper_rename: RuntimeError
constructor_tearoffs/redirecting_constructors: RuntimeError
constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 803d18f..8256003 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -13,8 +13,6 @@
constructor_tearoffs/call_instantiation: TypeCheckError
constructor_tearoffs/const_tear_off: RuntimeError
-constructor_tearoffs/inferred_constructor_tear_off: RuntimeError
-constructor_tearoffs/inferred_non_proper_rename: RuntimeError
constructor_tearoffs/redirecting_constructors: RuntimeError
constructor_tearoffs/redirecting_factory_tear_off: RuntimeError
extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index d2157f7..9905fcc 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -2479,6 +2479,15 @@
@override
Type visitStaticTearOffConstant(StaticTearOffConstant constant) {
+ final Procedure member = constant.target;
+ summaryCollector._entryPointsListener
+ .addRawCall(new DirectSelector(member));
+ summaryCollector._entryPointsListener.recordTearOff(member);
+ return _getStaticType(constant);
+ }
+
+ @override
+ Type visitConstructorTearOffConstant(ConstructorTearOffConstant constant) {
final Member member = constant.target;
summaryCollector._entryPointsListener
.addRawCall(new DirectSelector(member));
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 82bebec..e964f61 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -1939,6 +1939,11 @@
}
@override
+ visitConstructorTearOffConstant(ConstructorTearOffConstant constant) {
+ shaker.addUsedMember(constant.target);
+ }
+
+ @override
visitInstantiationConstant(InstantiationConstant constant) {
analyzeConstant(constant.tearOffConstant);
}
diff --git a/runtime/vm/compiler/frontend/constant_reader.cc b/runtime/vm/compiler/frontend/constant_reader.cc
index f2c7656..6040fb1 100644
--- a/runtime/vm/compiler/frontend/constant_reader.cc
+++ b/runtime/vm/compiler/frontend/constant_reader.cc
@@ -353,6 +353,18 @@
instance = function.ImplicitStaticClosure();
break;
}
+ case kConstructorTearOffConstant: {
+ const NameIndex index = reader.ReadCanonicalNameReference();
+ Function& function = Function::Handle(Z);
+ if (H.IsConstructor(index)) {
+ function = H.LookupConstructorByKernelConstructor(index);
+ } else {
+ function = H.LookupStaticMethodByKernelProcedure(index);
+ }
+ function = function.ImplicitClosureFunction();
+ instance = function.ImplicitStaticClosure();
+ break;
+ }
case kTypeLiteralConstant: {
// Build type from the raw bytes (needs temporary translator).
// Const canonical type erasure is not applied to constant type literals.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 9dd149c..257ee0e 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -5299,7 +5299,9 @@
if (!closure_owner_.IsNull()) {
function = Function::NewClosureFunctionWithKind(
UntaggedFunction::kClosureFunction, *name,
- parsed_function()->function(), position, closure_owner_);
+ parsed_function()->function(),
+ parsed_function()->function().is_static(), position,
+ closure_owner_);
} else {
function = Function::NewClosureFunction(
*name, parsed_function()->function(), position);
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index d35850e..06b2e7e 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -3425,13 +3425,45 @@
intptr_t type_args_len = 0;
if (function.IsGeneric()) {
- type_args_len = function.NumTypeParameters();
- ASSERT(parsed_function_->function_type_arguments() != NULL);
- closure += LoadLocal(parsed_function_->function_type_arguments());
+ if (target.IsConstructor()) {
+ const auto& result_type = AbstractType::Handle(Z, function.result_type());
+ ASSERT(result_type.IsFinalized());
+ // Instantiate a flattened type arguments vector which
+ // includes type arguments corresponding to superclasses.
+ // TranslateInstantiatedTypeArguments is smart enough to
+ // avoid instantiation and resuse passed function type arguments
+ // if there are no extra type arguments in the flattened vector.
+ const auto& instantiated_type_arguments =
+ TypeArguments::ZoneHandle(Z, result_type.arguments());
+ closure +=
+ TranslateInstantiatedTypeArguments(instantiated_type_arguments);
+ } else {
+ type_args_len = function.NumTypeParameters();
+ ASSERT(parsed_function_->function_type_arguments() != NULL);
+ closure += LoadLocal(parsed_function_->function_type_arguments());
+ }
+ } else if (target.IsFactory()) {
+ // Factories always take an extra implicit argument for
+ // type arguments even if their classes don't have type parameters.
+ closure += NullConstant();
}
// Push receiver.
- if (!target.is_static()) {
+ if (target.IsGenerativeConstructor()) {
+ const Class& cls = Class::Handle(Z, target.Owner());
+ if (cls.NumTypeArguments() > 0) {
+ if (!function.IsGeneric()) {
+ Type& cls_type = Type::Handle(Z, cls.DeclarationType());
+ closure += Constant(TypeArguments::ZoneHandle(Z, cls_type.arguments()));
+ }
+ closure += AllocateObject(function.token_pos(), cls, 1);
+ } else {
+ ASSERT(!function.IsGeneric());
+ closure += AllocateObject(function.token_pos(), cls, 0);
+ }
+ LocalVariable* receiver = MakeTemporary();
+ closure += LoadLocal(receiver);
+ } else if (!target.is_static()) {
// The context has a fixed shape: a single variable which is the
// closed-over receiver.
closure += LoadLocal(parsed_function_->ParameterVariable(0));
@@ -3445,7 +3477,7 @@
// Forward parameters to the target.
intptr_t argument_count = function.NumParameters() -
function.NumImplicitParameters() +
- (target.is_static() ? 0 : 1);
+ target.NumImplicitParameters();
ASSERT(argument_count == target.NumParameters());
Array& argument_names =
@@ -3455,6 +3487,12 @@
argument_names, ICData::kNoRebind,
/* result_type = */ NULL, type_args_len);
+ if (target.IsGenerativeConstructor()) {
+ // Drop result of constructor invocation, leave receiver
+ // instance on the stack.
+ closure += Drop();
+ }
+
// Return the result.
closure += Return(function.end_token_pos());
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 34249a3..0205fe4 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1452,9 +1452,6 @@
void ScopeBuilder::VisitTypeParameterType() {
Function& function = Function::Handle(Z, parsed_function_->function().ptr());
- while (function.IsClosureFunction()) {
- function = function.parent_function();
- }
helper_.ReadNullability(); // read nullability.
@@ -1465,19 +1462,25 @@
intptr_t index = helper_.ReadUInt(); // read index for parameter.
- if (function.IsFactory()) {
- // The type argument vector is passed as the very first argument to the
- // factory constructor function.
- HandleSpecialLoad(&result_->type_arguments_variable,
- Symbols::TypeArgumentsParameter());
- } else {
- // If the type parameter is a parameter to this or an enclosing function, we
- // can read it directly from the function type arguments vector later.
- // Otherwise, the type arguments vector we need is stored on the instance
- // object, so we need to capture 'this'.
- Class& parent_class = Class::Handle(Z, function.Owner());
- if (index < parent_class.NumTypeParameters()) {
- HandleLoadReceiver();
+ if (!function.IsImplicitStaticClosureFunction()) {
+ while (function.IsClosureFunction()) {
+ function = function.parent_function();
+ }
+
+ if (function.IsFactory()) {
+ // The type argument vector is passed as the very first argument to the
+ // factory constructor function.
+ HandleSpecialLoad(&result_->type_arguments_variable,
+ Symbols::TypeArgumentsParameter());
+ } else {
+ // If the type parameter is a parameter to this or an enclosing function,
+ // we can read it directly from the function type arguments vector later.
+ // Otherwise, the type arguments vector we need is stored on the instance
+ // object, so we need to capture 'this'.
+ Class& parent_class = Class::Handle(Z, function.Owner());
+ if (index < parent_class.NumTypeParameters()) {
+ HandleLoadReceiver();
+ }
}
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 3e1f788..0df5c45 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7519,7 +7519,7 @@
}
FunctionPtr Function::implicit_closure_function() const {
- if (IsClosureFunction() || IsFactory() || IsDispatcherOrImplicitAccessor() ||
+ if (IsClosureFunction() || IsDispatcherOrImplicitAccessor() ||
IsFieldInitializer() || IsFfiTrampoline()) {
return Function::null();
}
@@ -7689,6 +7689,7 @@
// native function: Array[0] = String native name
// Array[1] = Function implicit closure function
// regular function: Function for implicit closure function
+// constructor, factory: Function for implicit closure function
// ffi trampoline function: FfiTrampolineData (Dart->C)
// dyn inv forwarder: Array[0] = Function target
// Array[1] = TypeArguments default type args
@@ -9160,6 +9161,7 @@
FunctionPtr Function::NewClosureFunctionWithKind(UntaggedFunction::Kind kind,
const String& name,
const Function& parent,
+ bool is_static,
TokenPosition token_pos,
const Object& owner) {
ASSERT((kind == UntaggedFunction::kClosureFunction) ||
@@ -9171,7 +9173,7 @@
: 0));
const Function& result = Function::Handle(
Function::New(signature, name, kind,
- /* is_static = */ parent.is_static(),
+ /* is_static = */ is_static,
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
@@ -9186,7 +9188,8 @@
// Use the owner defining the parent function and not the class containing it.
const Object& parent_owner = Object::Handle(parent.RawOwner());
return NewClosureFunctionWithKind(UntaggedFunction::kClosureFunction, name,
- parent, token_pos, parent_owner);
+ parent, parent.is_static(), token_pos,
+ parent_owner);
}
FunctionPtr Function::NewImplicitClosureFunction(const String& name,
@@ -9194,8 +9197,9 @@
TokenPosition token_pos) {
// Use the owner defining the parent function and not the class containing it.
const Object& parent_owner = Object::Handle(parent.RawOwner());
- return NewClosureFunctionWithKind(UntaggedFunction::kImplicitClosureFunction,
- name, parent, token_pos, parent_owner);
+ return NewClosureFunctionWithKind(
+ UntaggedFunction::kImplicitClosureFunction, name, parent,
+ parent.is_static() || parent.IsConstructor(), token_pos, parent_owner);
}
bool Function::SafeToClosurize() const {
@@ -9241,7 +9245,7 @@
zone, NewImplicitClosureFunction(closure_name, *this, token_pos()));
// Set closure function's context scope.
- if (is_static()) {
+ if (is_static() || IsConstructor()) {
closure_function.set_context_scope(Object::empty_context_scope());
} else {
const ContextScope& context_scope = ContextScope::Handle(
@@ -9252,15 +9256,46 @@
FunctionType& closure_signature =
FunctionType::Handle(zone, closure_function.signature());
- // Set closure function's type parameters.
- // This function cannot be local, therefore it has no generic parent.
- // Its implicit closure function therefore has no generic parent function
- // either. That is why it is safe to simply copy the type parameters.
- closure_signature.SetTypeParameters(
- TypeParameters::Handle(zone, type_parameters()));
+ // Set closure function's type parameters and result type.
+ if (IsConstructor()) {
+ // Inherit type parameters from owner class.
+ const auto& cls = Class::Handle(zone, Owner());
+ closure_signature.SetTypeParameters(
+ TypeParameters::Handle(zone, cls.type_parameters()));
+ ASSERT(closure_signature.NumTypeParameters() == cls.NumTypeParameters());
- // Set closure function's result type to this result type.
- closure_signature.set_result_type(AbstractType::Handle(zone, result_type()));
+ Type& result_type = Type::Handle(zone);
+ const Nullability result_nullability =
+ (nnbd_mode() == NNBDMode::kOptedInLib) ? Nullability::kNonNullable
+ : Nullability::kLegacy;
+ if (cls.IsGeneric()) {
+ TypeArguments& type_args = TypeArguments::Handle(zone);
+ const intptr_t num_type_params = cls.NumTypeParameters();
+ ASSERT(num_type_params > 0);
+ type_args = TypeArguments::New(num_type_params);
+ TypeParameter& type_param = TypeParameter::Handle(zone);
+ for (intptr_t i = 0; i < num_type_params; i++) {
+ type_param = closure_signature.TypeParameterAt(i);
+ type_args.SetTypeAt(i, type_param);
+ }
+ result_type = Type::New(cls, type_args, result_nullability);
+ result_type ^= ClassFinalizer::FinalizeType(result_type);
+ } else {
+ result_type = cls.DeclarationType();
+ result_type = result_type.ToNullability(result_nullability, Heap::kOld);
+ }
+ closure_signature.set_result_type(result_type);
+ } else {
+ // This function cannot be local, therefore it has no generic parent.
+ // Its implicit closure function therefore has no generic parent function
+ // either. That is why it is safe to simply copy the type parameters.
+ closure_signature.SetTypeParameters(
+ TypeParameters::Handle(zone, type_parameters()));
+
+ // Set closure function's result type to this result type.
+ closure_signature.set_result_type(
+ AbstractType::Handle(zone, result_type()));
+ }
// Set closure function's end token to this end token.
closure_function.set_end_token_pos(end_token_pos());
@@ -9274,8 +9309,9 @@
// removing the receiver if this is an instance method and adding the closure
// object as first parameter.
const int kClosure = 1;
- const int has_receiver = is_static() ? 0 : 1;
- const int num_fixed_params = kClosure - has_receiver + num_fixed_parameters();
+ const int num_implicit_params = NumImplicitParameters();
+ const int num_fixed_params =
+ kClosure - num_implicit_params + num_fixed_parameters();
const int num_opt_params = NumOptionalParameters();
const bool has_opt_pos_params = HasOptionalPositionalParameters();
const int num_params = num_fixed_params + num_opt_params;
@@ -9294,19 +9330,19 @@
closure_signature.SetParameterTypeAt(0, param_type);
closure_function.SetParameterNameAt(0, Symbols::ClosureParameter());
for (int i = kClosure; i < num_pos_params; i++) {
- param_type = ParameterTypeAt(has_receiver - kClosure + i);
+ param_type = ParameterTypeAt(num_implicit_params - kClosure + i);
closure_signature.SetParameterTypeAt(i, param_type);
- param_name = ParameterNameAt(has_receiver - kClosure + i);
+ param_name = ParameterNameAt(num_implicit_params - kClosure + i);
// Set the name in the function for positional parameters.
closure_function.SetParameterNameAt(i, param_name);
}
for (int i = num_pos_params; i < num_params; i++) {
- param_type = ParameterTypeAt(has_receiver - kClosure + i);
+ param_type = ParameterTypeAt(num_implicit_params - kClosure + i);
closure_signature.SetParameterTypeAt(i, param_type);
- param_name = ParameterNameAt(has_receiver - kClosure + i);
+ param_name = ParameterNameAt(num_implicit_params - kClosure + i);
// Set the name in the signature for named parameters.
closure_signature.SetParameterNameAt(i, param_name);
- if (IsRequiredAt(has_receiver - kClosure + i)) {
+ if (IsRequiredAt(num_implicit_params - kClosure + i)) {
closure_signature.SetIsRequiredAt(i);
}
}
@@ -9315,7 +9351,7 @@
// Change covariant parameter types to either Object? for an opted-in implicit
// closure or to Object* for a legacy implicit closure.
- if (!is_static()) {
+ if (!is_static() && !IsConstructor()) {
BitVector is_covariant(zone, NumParameters());
BitVector is_generic_covariant_impl(zone, NumParameters());
kernel::ReadParameterCovariance(*this, &is_covariant,
@@ -9328,7 +9364,7 @@
: object_store->legacy_object_type();
ASSERT(object_type.IsCanonical());
for (intptr_t i = kClosure; i < num_params; ++i) {
- const intptr_t original_param_index = has_receiver - kClosure + i;
+ const intptr_t original_param_index = num_implicit_params - kClosure + i;
if (is_covariant.Contains(original_param_index) ||
is_generic_covariant_impl.Contains(original_param_index)) {
closure_signature.SetParameterTypeAt(i, object_type);
@@ -9340,6 +9376,7 @@
closure_function.SetSignature(closure_signature);
set_implicit_closure_function(closure_function);
ASSERT(closure_function.IsImplicitClosureFunction());
+ ASSERT(HasImplicitClosureFunction());
return closure_function.ptr();
#endif // defined(DART_PRECOMPILED_RUNTIME)
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 5f0f6dc..eb0d9e3 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2882,13 +2882,14 @@
static const char* KindToCString(UntaggedFunction::Kind kind);
+ bool IsConstructor() const {
+ return kind() == UntaggedFunction::kConstructor;
+ }
bool IsGenerativeConstructor() const {
- return (kind() == UntaggedFunction::kConstructor) && !is_static();
+ return IsConstructor() && !is_static();
}
bool IsImplicitConstructor() const;
- bool IsFactory() const {
- return (kind() == UntaggedFunction::kConstructor) && is_static();
- }
+ bool IsFactory() const { return IsConstructor() && is_static(); }
bool HasThisParameter() const {
return IsDynamicFunction(/*allow_abstract=*/true) ||
@@ -3549,6 +3550,7 @@
static FunctionPtr NewClosureFunctionWithKind(UntaggedFunction::Kind kind,
const String& name,
const Function& parent,
+ bool is_static,
TokenPosition token_pos,
const Object& owner);
diff --git a/tests/lib/js/external_nonjs_static_test.dart b/tests/lib/js/external_nonjs_static_test.dart
index 913d202..87c4615 100644
--- a/tests/lib/js/external_nonjs_static_test.dart
+++ b/tests/lib/js/external_nonjs_static_test.dart
@@ -7,6 +7,7 @@
library external_nonjs_static_test;
+import 'dart:html';
import 'package:js/js.dart';
external var topLevelField;
@@ -101,43 +102,43 @@
extension ExtensionNonJS on NonJSClass {
external var field;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external final finalField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static var staticField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static final staticFinalField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external get getter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external optionalParameterMethod([int? a, int b = 0]);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@@ -150,9 +151,29 @@
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
+extension ExtensionNative on HtmlElement {
+ external var field;
+ external final finalField;
+ external static var staticField;
+ external static final staticFinalField;
+
+ external get getter;
+ external set setter(_);
+
+ external static get staticGetter;
+ external static set staticSetter(_);
+
+ external method();
+ external static staticMethod();
+ external optionalParameterMethod([int? a, int b = 0]);
+
+ nonExternalMethod() => 1;
+ static nonExternalStaticMethod() => 2;
+}
+
main() {}
diff --git a/tests/lib/js/external_static_test.dart b/tests/lib/js/external_static_test.dart
index 0a1c8db..a455de0 100644
--- a/tests/lib/js/external_static_test.dart
+++ b/tests/lib/js/external_static_test.dart
@@ -8,6 +8,7 @@
@JS()
library external_static_test;
+import 'dart:html';
import 'package:js/js.dart';
// external top level members ok in @JS() library.
@@ -89,52 +90,52 @@
extension ExtensionNonJS on NonJSClass {
external var field;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external final finalField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static var staticField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static final staticFinalField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external get getter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external optionalParameterMethod([int? a, int b = 0]);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
@JS('fieldAnnotation')
external var annotatedField;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
@JS('memberAnnotation')
external annotatedMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@@ -147,7 +148,7 @@
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
@@ -229,4 +230,24 @@
@JS()
class _privateJSClass {}
+extension ExtensionNative on HtmlElement {
+ external var field;
+ external final finalField;
+ external static var staticField;
+ external static final staticFinalField;
+
+ external get getter;
+ external set setter(_);
+
+ external static get staticGetter;
+ external static set staticSetter(_);
+
+ external method();
+ external static staticMethod();
+ external optionalParameterMethod([int? a, int b = 0]);
+
+ nonExternalMethod() => 1;
+ static nonExternalStaticMethod() => 2;
+}
+
main() {}
diff --git a/tests/lib_2/js/external_nonjs_static_test.dart b/tests/lib_2/js/external_nonjs_static_test.dart
index 1de7e61..d0fa7df 100644
--- a/tests/lib_2/js/external_nonjs_static_test.dart
+++ b/tests/lib_2/js/external_nonjs_static_test.dart
@@ -9,6 +9,7 @@
library external_nonjs_static_test;
+import 'dart:html';
import 'package:js/js.dart';
external get topLevelGetter;
@@ -75,27 +76,30 @@
extension ExtensionNonJS on NonJSClass {
external get getter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
+ external optionalParameterMethod([int a, int b = 0]);
+ // ^
+ // [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@@ -108,9 +112,24 @@
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
+extension ExtensionNative on HtmlElement {
+ external get getter;
+ external set setter(_);
+
+ external static get staticGetter;
+ external static set staticSetter(_);
+
+ external method();
+ external static staticMethod();
+ external optionalParameterMethod([int a, int b = 0]);
+
+ nonExternalMethod() => 1;
+ static nonExternalStaticMethod() => 2;
+}
+
main() {}
diff --git a/tests/lib_2/js/external_static_test.dart b/tests/lib_2/js/external_static_test.dart
index 3f4c60b7..8084a72 100644
--- a/tests/lib_2/js/external_static_test.dart
+++ b/tests/lib_2/js/external_static_test.dart
@@ -10,6 +10,7 @@
@JS()
library external_static_test;
+import 'dart:html';
import 'package:js/js.dart';
// external top level members ok in @JS() library.
@@ -69,32 +70,35 @@
extension ExtensionNonJS on NonJSClass {
external get getter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external set setter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static get staticGetter;
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static set staticSetter(_);
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
external static staticMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
+ external optionalParameterMethod([int a, int b = 0]);
+ // ^
+ // [web] JS interop or Native class required for 'external' extension members.
external overridenMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
@JS('memberAnnotation')
external annotatedMethod();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
nonExternalMethod() => 1;
static nonExternalStaticMethod() => 2;
@@ -107,7 +111,7 @@
extension ExtensionGenericNonJS<T> on GenericNonJSClass<T> {
external T method();
// ^
- // [web] JS interop class required for 'external' extension members.
+ // [web] JS interop or Native class required for 'external' extension members.
}
class GenericNonJSClass<T> {}
@@ -121,6 +125,7 @@
external method();
external static staticMethod();
+ external optionalParameterMethod([int a, int b = 0]);
@JS('memberAnnotation')
external annotatedMethod();
@@ -176,4 +181,19 @@
@JS()
class _privateJSClass {}
+extension ExtensionNative on HtmlElement {
+ external get getter;
+ external set setter(_);
+
+ external static get staticGetter;
+ external static set staticSetter(_);
+
+ external method();
+ external static staticMethod();
+ external optionalParameterMethod([int a, int b = 0]);
+
+ nonExternalMethod() => 1;
+ static nonExternalStaticMethod() => 2;
+}
+
main() {}
diff --git a/tools/VERSION b/tools/VERSION
index 60bf783..d3f29b9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 369
+PRERELEASE 370
PRERELEASE_PATCH 0
\ No newline at end of file