From 364b36691ce75fd732034886d98e0569f30daea5 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Fri, 19 Dec 2025 12:53:22 -0800 Subject: [PATCH] Reland "[ DDC / CFE ] Add support for allowing imports of unsupported libraries" This reverts commit c616db31d2c8dcc41f1e917c2a1e6d2f2514c4bf. Reason for revert: Fix landed downstream in Flutter engine: https://github.com/flutter/flutter/pull/180127 Original change's description: > Revert "[ DDC / CFE ] Add support for allowing imports of unsupported libraries" > > This reverts commit b5e60be49d84eac6c0d98e9cf4753b6387d56c83. > > Reason for revert: broke Flutter web engine tests > > Original change's description: > > [ DDC / CFE ] Add support for allowing imports of unsupported libraries > > > > This change adds support for allowing for imports of unsupported > > platform-specific libraries when the > > `--include-unsupported-platform-library-stubs` flag is provided to the > > CFE. > > > > This flag sets the `includeUnsupportedPlatformLibraryStubs` property in > > `TargetFlags`, which `Target`s can use to conditionally return different > > `DartLibrarySupport` objects with different supported/unsupported > > library sets. > > > > A `checkForUnsupportedDartColonImports` function has been added to > > `Target` that uses the value of `dartLibrarySupport` to determine if > > there's any unsupported library imports. This function is called after > > the various transformation operations provided by the `Target` > > implementation, meaning the import of an unsupported library specified > > in `dartLibrarySupport` will now result in a compilation error (this > > includes `dart:mirrors` imports for VM targets when mirrors are > > disabled, which was previously handled by the VM itself). > > > > Related to https://github.com/dart-lang/sdk/issues/62125 > > > > TEST=Tests added / modified > > > > Change-Id: Ife819b2e1a6d28f67d80aab6701cd23a1724aa4d > > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/465760 > > Reviewed-by: Nicholas Shahan > > Reviewed-by: Johnni Winther > > Commit-Queue: Ben Konyi > > Change-Id: I0b59f00e55a2424f783351abd977eb38409ce01f > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/469100 > Reviewed-by: Nate Biggs > Commit-Queue: Alexander Markov > Bot-Commit: Rubber Stamper > Reviewed-by: Ben Konyi > Reviewed-by: Sigmund Cherem Change-Id: I1ae2eac675432286aebabea3c1f58caf35a27fbb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/469240 Commit-Queue: Ben Konyi Reviewed-by: Sigmund Cherem Bot-Commit: Rubber Stamper --- .../lib/src/util/libraries_specification.dart | 129 ++++++++++--- .../util/libraries_specification_test.dart | 170 +++++++++++++++--- pkg/dev_compiler/lib/src/kernel/target.dart | 7 +- .../expression_compiler_test.dart | 32 +++- .../lib/src/base/incremental_compiler.dart | 7 +- .../lib/src/base/uri_translator.dart | 12 +- .../lib/src/builder/compilation_unit.dart | 27 ++- .../lib/src/builder/library_builder.dart | 33 +++- .../lib/src/codes/cfe_codes_generated.dart | 25 +++ .../lib/src/dill/dill_library_builder.dart | 19 +- pkg/front_end/lib/src/kernel/benchmarker.dart | 1 + .../lib/src/kernel/constant_evaluator.dart | 2 +- .../lib/src/kernel/kernel_target.dart | 74 +++++++- .../src/source/source_compilation_unit.dart | 18 +- .../src/source/source_library_builder.dart | 17 +- .../lib/src/source/source_loader.dart | 18 +- pkg/front_end/messages.yaml | 9 + .../test/generator_to_string_test.dart | 7 +- .../test/spell_checking_list_code.txt | 2 + .../test/spell_checking_list_common.txt | 1 + .../test/spell_checking_list_messages.txt | 2 + .../test/static_types/cfe_allowed.json | 2 +- pkg/front_end/test/types/cfe_types_test.dart | 4 +- .../test/types/kernel_type_parser_test.dart | 21 +-- ...ted_platform_dart_library_import_test.dart | 85 +++++++++ .../patch_internal/main.dart.strong.expect | 2 +- .../main.dart.strong.modular.expect | 2 +- .../main.dart.strong.outline.expect | 2 +- .../main.dart.strong.transformed.expect | 2 +- ...import_unsupported.not.importable_lib.dart | 5 + .../supported_libraries/libraries.json | 11 +- .../general/supported_libraries/main.dart | 7 + .../main.dart.strong.expect | 24 ++- .../main.dart.strong.modular.expect | 24 ++- .../main.dart.strong.outline.expect | 19 +- .../main.dart.strong.transformed.expect | 24 ++- .../main.dart.textual_outline.expect | 5 + .../main.dart.textual_outline_modelled.expect | 4 + .../unsupported.not.importable_lib.dart | 7 + pkg/front_end/tool/dart_doctest_impl.dart | 5 +- pkg/frontend_server/lib/frontend_server.dart | 6 + pkg/kernel/lib/ast.dart | 2 + pkg/kernel/lib/src/ast/libraries.dart | 33 +++- pkg/kernel/lib/target/targets.dart | 16 +- .../lib/testing/type_parser_environment.dart | 11 +- pkg/kernel/lib/text/ast_to_text.dart | 5 +- pkg/vm/lib/kernel_front_end.dart | 3 + .../mixin_deduplication/generic.dart.expect | 2 +- .../generic_recursive_bounds.dart.expect | 2 +- .../multiple_libraries_main.dart.expect | 2 +- .../non_generic.dart.expect | 2 +- sdk/lib/libraries.json | 13 +- sdk/lib/libraries.yaml | 13 +- tests/co19/co19-kernel.status | 1 + .../disallowed_interop_libraries_test.dart | 4 +- 55 files changed, 834 insertions(+), 148 deletions(-) create mode 100644 pkg/front_end/test/unsupported_platform_dart_library_import_test.dart create mode 100644 pkg/front_end/testcases/general/supported_libraries/import_unsupported.not.importable_lib.dart create mode 100644 pkg/front_end/testcases/general/supported_libraries/unsupported.not.importable_lib.dart diff --git a/pkg/_fe_analyzer_shared/lib/src/util/libraries_specification.dart b/pkg/_fe_analyzer_shared/lib/src/util/libraries_specification.dart index 9f261a33ebb..3028c5f8f89 100644 --- a/pkg/_fe_analyzer_shared/lib/src/util/libraries_specification.dart +++ b/pkg/_fe_analyzer_shared/lib/src/util/libraries_specification.dart @@ -32,7 +32,7 @@ /// } /// "mirrors": { /// "uri": "mirrors/mirrors.dart", -/// "supported": false +/// "support_conditional_import": false /// } /// } /// } @@ -61,24 +61,46 @@ /// which will be resolved relative to the location of the library /// specification file. /// -/// - The "supported" entry on the library information is optional. The value -/// is a boolean indicating whether the library is supported in the -/// underlying target. However, since the libraries are assumed to be -/// supported by default, we only expect users to use `false`. +/// - The "support_conditional_import" entry on the library information is +/// optional. The value is a boolean indicating whether the library is +/// supported in the underlying target. However, since the libraries are +/// assumed to be supported by default, we only expect users to use +/// `false`. /// /// The purpose of this value is to configure conditional imports and /// environment constants. By default every platform library that is /// available in the "libraries" section implicitly defines an environment /// variable `dart.library.name` as `"true"`, to indicate that the library /// is supported. Some backends allow imports to an unsupported platform -/// library (turning a static error into a runtime error when the library is -/// eventually accessed). These backends can use `supported: false` to -/// report that such library is still not supported in conditional imports -/// and const `fromEnvironment` expressions. +/// library (turning a static error into a runtime error when the library +/// is eventually accessed). These backends can use +/// `support_conditional_import: false` to report that such library is +/// still not supported in conditional imports and const `fromEnvironment` +/// expressions. /// /// Internal libraries are never supported through conditional imports and /// const `fromEnvironment` expressions. /// +/// - The "support_direct_import" entry on the library information is +/// optional. The value is an enumerated type indicating whether the library +/// is allowed to be imported by the underlying target. This property can +/// take one of the following values: +/// +/// - "always": the library is supported by the underlying target and +/// can always be imported. This is the default. +/// - "never": the library is not supported by the underlying target and +/// imports of the library will be treated as compile time errors. +/// - "with_flag": the library is only supported when the +/// `--include-unsupported-platform-library-stubs` flag is set. If the +/// flag is not set, imports of the library will be treated as +/// compile time errors. Otherwise, the import will be allowed. +/// +/// Some backends allow imports to an unsupported platform library (turning +/// a static error into a runtime error when the library is eventually +/// accessed). These backends can use `support_direct_import: "with_flag"` +/// to control access to these libraries, allowing for developer tooling to +/// handle code which imports unsupported libraries for a given platform. +/// /// - The "include" entry is a list of maps, each containing either a "path" /// and a "target" entry, or only a "target" entry. /// @@ -314,17 +336,36 @@ class LibrariesSpecification { _reportError(messagePatchesMustBeListOrString(libraryName)); } - dynamic supported = data['supported'] ?? true; - if (supported is! bool) { - _reportError(messageSupportedIsNotABool(supported)); + final Object supportConditionalImport = + data['support_conditional_import'] ?? true; + if (supportConditionalImport is! bool) { + _reportError( + messagePropertyIsNotABool( + 'support_conditional_import', + supportConditionalImport, + ), + ); } + + final Object? supportDirectImportRaw = data['support_direct_import']; + final Importability? importability = supportDirectImportRaw == null + ? Importability.always + : Importability.fromJson(supportDirectImportRaw); + if (importability == null) { + _reportError( + messageSupportDirectImportIsNotValidValue(supportDirectImportRaw!), + ); + } + libraries[libraryName] = new LibraryInfo( libraryName, uri, patches, // Internal libraries are never supported through conditional // imports and const `fromEnvironment` expressions. - isSupported: supported && !libraryName.startsWith('_'), + supportConditionalImport: + supportConditionalImport && !libraryName.startsWith('_'), + importability: importability, ); }); currentTargets.remove(targetName); @@ -362,8 +403,11 @@ class LibrariesSpecification { 'uri': pathFor(lib.uri), 'patches': lib.patches.map(pathFor).toList(), }; - if (!lib.isSupported) { - libraries[name]['supported'] = false; + if (!lib.supportConditionalImport) { + libraries[name]['support_conditional_import'] = false; + } + if (lib.importability != Importability.always) { + libraries[name]['support_direct_import'] = lib.importability.value; } }); result[targetName] = {'libraries': libraries}; @@ -372,6 +416,32 @@ class LibrariesSpecification { } } +/// Determines whether or not a `dart:*` library is importable for a given +/// platform. +enum Importability { + /// This `dart:*` library is always importable on the target platform. + always(value: 'always'), + + /// This `dart:*` library is only importable on the target platform when + /// `--include-unsupported-platform-library-stubs` is provided to the CFE. + withFlag(value: 'with_flag'), + + /// This `dart:*` library is never importable on the target platform. + never(value: 'never'); + + const Importability({required this.value}); + + final String value; + + static Importability? fromJson(Object? value) { + if (value is! String) return null; + if (value == always.value) return always; + if (value == withFlag.value) return withFlag; + if (value == never.value) return never; + return null; + } +} + /// Specifies information about all libraries supported by a given target. class TargetLibrariesSpecification { /// Name of the target platform. @@ -404,13 +474,19 @@ class LibraryInfo { /// Whether the library is supported and thus `dart.library.name` is "true" /// for conditional imports and fromEnvironment constants. - final bool isSupported; + final bool supportConditionalImport; + + /// Whether the library is importable for a given target platform. + /// + /// If not explicitly provided, this field defaults to [Importability.always]. + final Importability importability; const LibraryInfo( this.name, this.uri, this.patches, { - this.isSupported = true, + this.supportConditionalImport = true, + this.importability = Importability.always, }); /// The import uri for the defined library. @@ -495,6 +571,19 @@ String messageUnsupportedUriScheme(String uriValue, Uri specUri) => String messagePatchesMustBeListOrString(String libraryName) => '"patches" entry for "$libraryName" is not a list or a string.'; -String messageSupportedIsNotABool(Object supportedValue) => - '"supported" entry: expected a `bool` but ' - 'got a `${supportedValue.runtimeType}` ("$supportedValue").'; +String messagePropertyIsNotABool(String key, Object value) => + '"$key" entry: expected a `bool` but ' + 'got a `${value.runtimeType}` ("$value").'; + +String messageOnlyOnePropertyCanBeDefined(List properties) { + return 'Only one of the following properties can be defined: ' + '${properties.map((e) => '`$e`').join(',')}.'; +} + +String messageSupportDirectImportIsNotValidValue(Object value) { + final String values = Importability.values + .map((e) => '`${e.value}`') + .join(','); + return '"support_direct_import" entry: expected one of $values but got a ' + '`${value.runtimeType}` ("$value").'; +} diff --git a/pkg/_fe_analyzer_shared/test/util/libraries_specification_test.dart b/pkg/_fe_analyzer_shared/test/util/libraries_specification_test.dart index 0be6f8c0466..d82474de972 100644 --- a/pkg/_fe_analyzer_shared/test/util/libraries_specification_test.dart +++ b/pkg/_fe_analyzer_shared/test/util/libraries_specification_test.dart @@ -278,28 +278,34 @@ void main() { ); }); - test('supported entry must be bool', () async { + test('support_conditional_import entry must be bool', () async { var jsonString = ''' { - "vm": + "vm": { - "libraries": + "libraries": { "core": { - "uri": "main.dart", - "supported": 3 + "uri": "main.dart", + "support_conditional_import": 3 } } } }'''; expect( () => LibrariesSpecification.load(specUri, read({specUri: jsonString})), - throwsA(checkException(messageSupportedIsNotABool(3))), + throwsA( + checkException( + messagePropertyIsNotABool('support_conditional_import', 3), + ), + ), ); }); - test('supported entry is copied correctly when parsing', () async { - var jsonString = ''' + test( + 'support_conditional_import entry is copied correctly when parsing', + () async { + var jsonString = ''' { "vm": { "libraries": { @@ -309,15 +315,14 @@ void main() { "a/p1.dart", "a/p2.dart" ], - "supported": false - + "support_conditional_import": false }, "bar" : { "uri": "b/main.dart", "patches": [ "b/p3.dart" ], - "supported": true + "support_conditional_import": true }, "baz" : { "uri": "b/main.dart", @@ -329,24 +334,117 @@ void main() { } } '''; - var uri = Uri.parse('org-dartlang-test:///one/two/f.json'); - var spec = await LibrariesSpecification.load( - uri, - read({uri: jsonString}), - ); + var uri = Uri.parse('org-dartlang-test:///one/two/f.json'); + var spec = await LibrariesSpecification.load( + uri, + read({uri: jsonString}), + ); + expect( + spec + .specificationFor('vm') + .libraryInfoFor('foo')! + .supportConditionalImport, + false, + ); + expect( + spec + .specificationFor('vm') + .libraryInfoFor('bar')! + .supportConditionalImport, + true, + ); + expect( + spec + .specificationFor('vm') + .libraryInfoFor('baz')! + .supportConditionalImport, + true, + ); + }, + ); + + test('support_direct_import entry must be Importable', () async { + var jsonString = ''' + { + "vm": + { + "libraries": + { + "core": { + "uri": "main.dart", + "support_direct_import": 3 + } + } + } + }'''; expect( - spec.specificationFor('vm').libraryInfoFor('foo')!.isSupported, - false, - ); - expect( - spec.specificationFor('vm').libraryInfoFor('bar')!.isSupported, - true, - ); - expect( - spec.specificationFor('vm').libraryInfoFor('baz')!.isSupported, - true, + () => LibrariesSpecification.load(specUri, read({specUri: jsonString})), + throwsA(checkException(messageSupportDirectImportIsNotValidValue(3))), ); }); + + test( + 'support_direct_import entry is copied correctly when parsing', + () async { + var jsonString = ''' + { + "vm": { + "libraries": { + "foo" : { + "uri": "a/main.dart", + "patches": [ + "a/p1.dart", + "a/p2.dart" + ], + "support_direct_import": "always" + }, + "bar" : { + "uri": "b/main.dart", + "patches": [ + "b/p3.dart" + ], + "support_direct_import": "with_flag" + }, + "baz" : { + "uri": "b/main.dart", + "patches": [ + "b/p3.dart" + ], + "support_direct_import": "never" + }, + "foobar" : { + "uri": "b/main.dart", + "patches": [ + "b/p3.dart" + ] + } + } + } + } + '''; + var uri = Uri.parse('org-dartlang-test:///one/two/f.json'); + var spec = await LibrariesSpecification.load( + uri, + read({uri: jsonString}), + ); + expect( + spec.specificationFor('vm').libraryInfoFor('foo')!.importability, + Importability.always, + ); + expect( + spec.specificationFor('vm').libraryInfoFor('bar')!.importability, + Importability.withFlag, + ); + expect( + spec.specificationFor('vm').libraryInfoFor('baz')!.importability, + Importability.never, + ); + expect( + spec.specificationFor('vm').libraryInfoFor('foobar')!.importability, + Importability.always, + ); + }, + ); }); group('nested', () { @@ -801,9 +899,27 @@ void main() { "a/p1.dart", "a/p2.dart" ], - "supported": false + "support_conditional_import": false }, "bar" : { + "uri": "a/main.dart", + "patches": [ + "a/p1.dart", + "a/p2.dart" + ], + "support_conditional_import": false, + "support_direct_import": "never" + }, + "baz" : { + "uri": "a/main.dart", + "patches": [ + "a/p1.dart", + "a/p2.dart" + ], + "support_conditional_import": false, + "support_direct_import": "with_flag" + }, + "foobaz" : { "uri": "b/main.dart", "patches": [ "b/p3.dart" diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart index 93c36ef799e..a64ac8988f4 100644 --- a/pkg/dev_compiler/lib/src/kernel/target.dart +++ b/pkg/dev_compiler/lib/src/kernel/target.dart @@ -55,7 +55,7 @@ class DevCompilerTarget extends Target { String get name => 'dartdevc'; @override - List get extraRequiredLibraries => const [ + List get extraRequiredLibraries => [ 'dart:_ddc_only', 'dart:_runtime', 'dart:_async_status_codes', @@ -78,7 +78,7 @@ class DevCompilerTarget extends Target { 'dart:collection', 'dart:convert', 'dart:developer', - 'dart:ffi', + if (flags.includeUnsupportedPlatformLibraryStubs) 'dart:ffi', 'dart:io', 'dart:isolate', 'dart:js', @@ -95,6 +95,9 @@ class DevCompilerTarget extends Target { 'dart:web_gl', ]; + @override + List get extraRequiredLibrariesPlatform => const ['dart:ffi']; + // The libraries required to be indexed via CoreTypes. @override List get extraIndexedLibraries => const [ diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart index 8a17cc9dd3f..8bc2eaab4c1 100644 --- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart +++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. import 'package:dev_compiler/src/compiler/module_builder.dart'; +import 'package:dev_compiler/src/kernel/target.dart'; +import 'package:kernel/target/targets.dart'; import 'package:test/test.dart'; import '../shared_test_options.dart'; @@ -97,13 +99,11 @@ void runTests(SetupCompilerOptions setup) { import 'dart:io' show Directory; import 'dart:io' as p; import 'dart:convert' as p; - import 'dart:ffi' as ffi; main() { print(Directory.systemTemp); print(p.Directory.systemTemp); print(p.utf8.decoder); - print(ffi.Abi.current()); } void foo() { @@ -147,6 +147,33 @@ void runTests(SetupCompilerOptions setup) { ); }, ); + }); + + group('Expression compiler dart: platform import tests', () { + var source = ''' + import 'dart:ffi' as ffi; + + main() { + print(ffi.Abi.current()); + } + + void foo() { + // Breakpoint + } + '''; + + late ExpressionCompilerTestDriver driver; + + setUp(() { + driver = ExpressionCompilerTestDriver(setup, source) + ..setup.options.target = DevCompilerTarget( + TargetFlags(includeUnsupportedPlatformLibraryStubs: true), + ); + }); + + tearDown(() { + driver.delete(); + }); test('expression referencing dart:ffi', () async { await driver.check( @@ -156,6 +183,7 @@ void runTests(SetupCompilerOptions setup) { ); }); }); + group('Expression compiler package: import tests', () { var source = ''' import 'package:a/a.dart' show topLevelMethod; diff --git a/pkg/front_end/lib/src/base/incremental_compiler.dart b/pkg/front_end/lib/src/base/incremental_compiler.dart index 230fe5321cd..f2f465e9cfd 100644 --- a/pkg/front_end/lib/src/base/incremental_compiler.dart +++ b/pkg/front_end/lib/src/base/incremental_compiler.dart @@ -2123,7 +2123,9 @@ class IncrementalCompiler implements IncrementalKernelGenerator { ), loader: lastGoodKernelTarget.loader, resolveInLibrary: libraryBuilder, - isUnsupported: libraryBuilder.isUnsupported, + conditionalImportSupported: + libraryBuilder.conditionalImportSupported, + importability: libraryBuilder.importability, forAugmentationLibrary: false, forPatchLibrary: false, referenceIsPartOwner: null, @@ -2188,7 +2190,8 @@ class IncrementalCompiler implements IncrementalKernelGenerator { resolveInLibrary: libraryBuilder, parentScope: debugCompilationUnit.compilationUnitScope, parentExtensionScope: debugCompilationUnit.extensionScope, - isUnsupported: libraryBuilder.isUnsupported, + conditionalImportSupported: libraryBuilder.conditionalImportSupported, + importability: libraryBuilder.importability, forAugmentationLibrary: false, forPatchLibrary: false, referenceIsPartOwner: null, diff --git a/pkg/front_end/lib/src/base/uri_translator.dart b/pkg/front_end/lib/src/base/uri_translator.dart index 8605497a487..4f066e66bed 100644 --- a/pkg/front_end/lib/src/base/uri_translator.dart +++ b/pkg/front_end/lib/src/base/uri_translator.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' - show TargetLibrariesSpecification; + show Importability, TargetLibrariesSpecification; import 'package:package_config/package_config.dart'; import '../codes/cfe_codes.dart'; @@ -48,7 +48,15 @@ class UriTranslator { } bool isLibrarySupported(String libraryName) { - return dartLibraries.libraryInfoFor(libraryName)?.isSupported ?? false; + return dartLibraries + .libraryInfoFor(libraryName) + ?.supportConditionalImport ?? + false; + } + + Importability isLibraryImportable(String libraryName) { + return dartLibraries.libraryInfoFor(libraryName)?.importability ?? + Importability.never; } Uri? _translateDartUri(Uri uri) { diff --git a/pkg/front_end/lib/src/builder/compilation_unit.dart b/pkg/front_end/lib/src/builder/compilation_unit.dart index 768980a68aa..1fd67b1e797 100644 --- a/pkg/front_end/lib/src/builder/compilation_unit.dart +++ b/pkg/front_end/lib/src/builder/compilation_unit.dart @@ -4,6 +4,8 @@ import 'package:_fe_analyzer_shared/src/messages/severity.dart' show CfeSeverity; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token; import 'package:kernel/ast.dart' show Annotatable, Library, Version; import 'package:kernel/reference_from_index.dart'; @@ -42,9 +44,22 @@ sealed class CompilationUnit { bool get isSynthetic; - /// If true, the library is not supported through the 'dart.library.*' value + /// If false, the library is not supported through the 'dart.library.*' value /// used in conditional imports and `bool.fromEnvironment` constants. - bool get isUnsupported; + bool get conditionalImportSupported; + + /// Specifies when the library is importable on the target platform. + /// + /// If [importability] is [Importability.always], or is + /// [Importability.withFlag] when the + /// `--include-unsupported-platform-library-stubs` flag is specified, the + /// library can be imported. + /// + /// If [importability] is [Importability.never], or is + /// [Importability.withFlag] when + /// `--include-unsupported-platform-library-stubs` is not specified, imports + /// of this library will result in a compilation error. + Importability get importability; Loader get loader; @@ -64,6 +79,12 @@ sealed class CompilationUnit { /// through import or export. Iterable get dependencies; + /// Returns the set of imports and exports of this library from other + /// libraries. + Iterable get accessors; + + /// Records the location of an import or export of this library from + /// [accessor]. void recordAccess( CompilationUnit accessor, int charOffset, @@ -275,8 +296,6 @@ abstract class SourceCompilationUnit /// unit. void addProblemAtAccessors(Message message); - Iterable get accessors; - /// Non-null if this library causes an error upon access, that is, there was /// an error reading its source. abstract Message? accessProblem; diff --git a/pkg/front_end/lib/src/builder/library_builder.dart b/pkg/front_end/lib/src/builder/library_builder.dart index 8aaf484e490..ec4cf08456f 100644 --- a/pkg/front_end/lib/src/builder/library_builder.dart +++ b/pkg/front_end/lib/src/builder/library_builder.dart @@ -4,6 +4,8 @@ import 'package:_fe_analyzer_shared/src/messages/severity.dart' show CfeSeverity; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:kernel/ast.dart' show Library, Version; import '../base/export.dart' show Export; @@ -22,6 +24,7 @@ import '../base/messages.dart' import '../base/name_space.dart'; import '../base/problems.dart' show internalProblem; import '../source/name_scheme.dart'; +import '../source/source_library_builder.dart'; import 'builder.dart'; import 'compilation_unit.dart'; import 'constructor_builder.dart'; @@ -40,6 +43,10 @@ abstract class LibraryBuilder implements Builder, ProblemReporting { List get exporters; + /// Returns the set of imports and exports of this library from other + /// libraries. + Iterable get accessors; + LibraryBuilder? get partOfLibrary; LibraryBuilder get nameOriginBuilder; @@ -70,9 +77,22 @@ abstract class LibraryBuilder implements Builder, ProblemReporting { /// Returns the language [Version] used for this library. Version get languageVersion; - /// If true, the library is not supported through the 'dart.library.*' value + /// If false, the library is not supported through the 'dart.library.*' value /// used in conditional imports and `bool.fromEnvironment` constants. - bool get isUnsupported; + bool get conditionalImportSupported; + + /// Specifies when the library is importable on the target platform. + /// + /// If [importability] is [Importability.always], or is + /// [Importability.withFlag] when the + /// `--include-unsupported-platform-library-stubs` flag is specified, the + /// library can be imported. + /// + /// If [importability] is [Importability.never], or is + /// [Importability.withFlag] when + /// `--include-unsupported-platform-library-stubs` is not specified, imports + /// of this library will result in a compilation error. + Importability get importability; /// [Iterator] for all declarations declared in this library of type [T]. /// @@ -105,6 +125,8 @@ abstract class LibraryBuilder implements Builder, ProblemReporting { /// If no member is found an internal problem is reported. NamedBuilder lookupRequiredLocalMember(String name); + /// Records the location of an import or export of this library from + /// [accessor]. void recordAccess( CompilationUnit accessor, int charOffset, @@ -162,6 +184,9 @@ abstract class LibraryBuilderImpl extends BuilderImpl @override Uri get importUri; + @override + final List accessors = []; + @override FormattedMessage? addProblem( Message message, @@ -265,7 +290,9 @@ abstract class LibraryBuilderImpl extends BuilderImpl int charOffset, int length, Uri fileUri, - ) {} + ) { + accessors.add(new LibraryAccess(accessor, fileUri, charOffset, length)); + } @override String toString() { diff --git a/pkg/front_end/lib/src/codes/cfe_codes_generated.dart b/pkg/front_end/lib/src/codes/cfe_codes_generated.dart index 274c7eb96b9..3d378fb833c 100644 --- a/pkg/front_end/lib/src/codes/cfe_codes_generated.dart +++ b/pkg/front_end/lib/src/codes/cfe_codes_generated.dart @@ -16168,6 +16168,31 @@ const MessageCode codeUnsupportedDartExt = const MessageCode( """Migrate to using FFI instead (https://dart.dev/guides/libraries/c-interop)""", ); +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +const Template +codeUnsupportedPlatformDartLibraryImport = const Template( + "UnsupportedPlatformDartLibraryImport", + withArgumentsOld: _withArgumentsOldUnsupportedPlatformDartLibraryImport, + withArguments: _withArgumentsUnsupportedPlatformDartLibraryImport, + severity: CfeSeverity.warning, +); + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +Message _withArgumentsUnsupportedPlatformDartLibraryImport({required Uri uri}) { + var uri_0 = conversions.relativizeUri(uri); + return new Message( + codeUnsupportedPlatformDartLibraryImport, + problemMessage: + """Using stub implementations for APIs in platform-specific Dart library +'${uri_0}', which will throw 'UnsupportedError' if invoked.""", + arguments: {'uri': uri}, + ); +} + +// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. +Message _withArgumentsOldUnsupportedPlatformDartLibraryImport(Uri uri) => + _withArgumentsUnsupportedPlatformDartLibraryImport(uri: uri); + // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE. const MessageCode codeUnterminatedToken = const MessageCode( "UnterminatedToken", diff --git a/pkg/front_end/lib/src/dill/dill_library_builder.dart b/pkg/front_end/lib/src/dill/dill_library_builder.dart index 173855c4777..a987a6641eb 100644 --- a/pkg/front_end/lib/src/dill/dill_library_builder.dart +++ b/pkg/front_end/lib/src/dill/dill_library_builder.dart @@ -4,6 +4,8 @@ import 'dart:convert' show jsonDecode; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:kernel/ast.dart'; import '../base/combinator.dart'; @@ -28,6 +30,7 @@ import '../codes/cfe_codes.dart' import '../kernel/constructor_tearoff_lowering.dart'; import '../kernel/utils.dart'; import '../source/name_scheme.dart'; +import '../source/source_library_builder.dart'; import '../util/reference_map.dart'; import 'dill_class_builder.dart' show DillClassBuilder; import 'dill_extension_builder.dart'; @@ -42,6 +45,9 @@ class DillCompilationUnitImpl extends DillCompilationUnit { @override final List exporters = []; + @override + Iterable get accessors => _dillLibraryBuilder.accessors; + DillCompilationUnitImpl(this._dillLibraryBuilder); @override @@ -96,7 +102,12 @@ class DillCompilationUnitImpl extends DillCompilationUnit { bool get isSynthetic => _dillLibraryBuilder.isSynthetic; @override - bool get isUnsupported => _dillLibraryBuilder.isUnsupported; + bool get conditionalImportSupported => + _dillLibraryBuilder.conditionalImportSupported; + + @override + // Coverage-ignore(suite): Not run. + Importability get importability => _dillLibraryBuilder.importability; @override LibraryBuilder get libraryBuilder => _dillLibraryBuilder; @@ -382,7 +393,11 @@ class DillLibraryBuilder extends LibraryBuilderImpl { } @override - bool get isUnsupported => library.isUnsupported; + bool get conditionalImportSupported => library.conditionalImportSupported; + + @override + // Coverage-ignore(suite): Not run. + Importability get importability => library.importability; @override bool get isSynthetic => library.isSynthetic; diff --git a/pkg/front_end/lib/src/kernel/benchmarker.dart b/pkg/front_end/lib/src/kernel/benchmarker.dart index f9bc8a0734d..aea5d288a46 100644 --- a/pkg/front_end/lib/src/kernel/benchmarker.dart +++ b/pkg/front_end/lib/src/kernel/benchmarker.dart @@ -219,6 +219,7 @@ enum BenchmarkPhases { body_finishAllConstructors, body_validateDynamicModule, body_runBuildTransformations, + body_checkForUnsupportedDartColonImports, body_verify, body_installAllComponentProblems, diff --git a/pkg/front_end/lib/src/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/kernel/constant_evaluator.dart index 41a1dbdcff2..ee993eab9a5 100644 --- a/pkg/front_end/lib/src/kernel/constant_evaluator.dart +++ b/pkg/front_end/lib/src/kernel/constant_evaluator.dart @@ -2571,7 +2571,7 @@ class ConstantEvaluator library.importUri.path, libraryExists: true, isSynthetic: library.isSynthetic, - isUnsupported: library.isUnsupported, + conditionalImportSupported: library.conditionalImportSupported, dartLibrarySupport: dartLibrarySupport, )) (DartLibrarySupport.dartLibraryPrefix + library.importUri.path): "true", diff --git a/pkg/front_end/lib/src/kernel/kernel_target.dart b/pkg/front_end/lib/src/kernel/kernel_target.dart index 26a5db49d31..f75a85ae08e 100644 --- a/pkg/front_end/lib/src/kernel/kernel_target.dart +++ b/pkg/front_end/lib/src/kernel/kernel_target.dart @@ -6,6 +6,8 @@ import 'dart:typed_data'; import 'package:_fe_analyzer_shared/src/messages/severity.dart' show CfeSeverity; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:kernel/ast.dart'; import 'package:kernel/class_hierarchy.dart' show ClassHierarchy; import 'package:kernel/core_types.dart'; @@ -13,7 +15,8 @@ import 'package:kernel/reference_from_index.dart' show IndexedContainer, IndexedClass; import 'package:kernel/target/changed_structure_notifier.dart' show ChangedStructureNotifier; -import 'package:kernel/target/targets.dart' show DiagnosticReporter, Target; +import 'package:kernel/target/targets.dart' + show DiagnosticReporter, Target, TargetFlags, DartLibrarySupport; import 'package:kernel/type_algebra.dart' show Substitution; import 'package:kernel/type_environment.dart' show TypeEnvironment; import 'package:kernel/verifier.dart' show VerificationStage; @@ -21,6 +24,12 @@ import 'package:package_config/package_config.dart' hide LanguageVersion; import '../api_prototype/experimental_flags.dart' show ExperimentalFlag, GlobalFeatures; +import '../api_prototype/codes.dart' + show + codeUnavailableDartLibrary, + noLength, + codeUnsupportedPlatformDartLibraryImport, + Message; import '../api_prototype/file_system.dart' show FileSystem; import '../base/compiler_context.dart' show CompilerContext; import '../base/crash.dart' show withCrashReporting; @@ -63,7 +72,8 @@ import '../source/source_class_builder.dart' show SourceClassBuilder; import '../source/source_constructor_builder.dart'; import '../source/source_declaration_builder.dart'; import '../source/source_extension_type_declaration_builder.dart'; -import '../source/source_library_builder.dart' show SourceLibraryBuilder; +import '../source/source_library_builder.dart' + show SourceLibraryBuilder, LibraryAccess; import '../source/source_loader.dart' show SourceLoader; import '../source/source_property_builder.dart'; import '../type_inference/type_schema.dart'; @@ -781,6 +791,11 @@ class KernelTarget { ?.enterPhase(BenchmarkPhases.body_runBuildTransformations); runBuildTransformations(); + benchmarker + // Coverage-ignore(suite): Not run. + ?.enterPhase(BenchmarkPhases.body_checkForUnsupportedDartColonImports); + checkForUnsupportedDartColonImports(); + if (verify) { benchmarker // Coverage-ignore(suite): Not run. @@ -1811,6 +1826,61 @@ class KernelTarget { ); } + /// Perform target-specific checks for imports of unsupported dart:* libraries + /// specified by [backendTarget.dartLibrarySupport]. + void checkForUnsupportedDartColonImports() { + final TargetFlags flags = backendTarget.flags; + final DartLibrarySupport dartLibrarySupport = + backendTarget.dartLibrarySupport; + + for (final CompilationUnit compilationUnit in loader.compilationUnits) { + final Uri importUri = compilationUnit.importUri; + // Only check for imports of unsupported dart:* libraries. + if (!importUri.isScheme('dart')) { + continue; + } + Message? diagnostic; + final Importability importability = compilationUnit.importability; + final bool importableWithFlag = + (importability == Importability.withFlag && + // Coverage-ignore(suite): Not run. + flags.includeUnsupportedPlatformLibraryStubs); + if (!dartLibrarySupport.computeDartLibrarySupport( + importUri.path, + isSupportedBySpec: + (importability == Importability.always || importableWithFlag), + )) { + // Coverage-ignore-block(suite): Not run. + diagnostic = codeUnavailableDartLibrary.withArguments(uri: importUri); + } else if (importableWithFlag) { + // Coverage-ignore-block(suite): Not run. + // Display a warning for each import of an unsupported library. + diagnostic = codeUnsupportedPlatformDartLibraryImport.withArguments( + uri: importUri, + ); + } + if (diagnostic == null) { + continue; + } + for (final LibraryAccess access in compilationUnit.accessors) { + final CompilationUnit accessor = access.accessor; + // dart:* libraries (and their patch files) are not restricted from + // importing other dart:* libraries. + if (accessor.importUri.isScheme('dart') || + (accessor is SourceCompilationUnit && + accessor.originImportUri.isScheme('dart'))) { + continue; + } + access.accessor.addProblem( + diagnostic, + access.charOffset, + access.length, + access.fileUri, + ); + } + } + } + ChangedStructureNotifier? get changedStructureNotifier => null; // Coverage-ignore(suite): Not run. diff --git a/pkg/front_end/lib/src/source/source_compilation_unit.dart b/pkg/front_end/lib/src/source/source_compilation_unit.dart index e8ae8eb203d..954e97c7de4 100644 --- a/pkg/front_end/lib/src/source/source_compilation_unit.dart +++ b/pkg/front_end/lib/src/source/source_compilation_unit.dart @@ -5,6 +5,8 @@ import 'package:_fe_analyzer_shared/src/parser/class_member_parser.dart' show ClassMemberParser; import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:kernel/ast.dart' hide Combinator, MapLiteralEntry; import 'package:kernel/reference_from_index.dart' show IndexedLibrary; @@ -167,7 +169,10 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit { final bool isAugmenting; @override - final bool isUnsupported; + final bool conditionalImportSupported; + + @override + final Importability importability; late final LookupScope _compilationUnitScope; @@ -194,7 +199,8 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit { required bool? referenceIsPartOwner, required bool forPatchLibrary, required bool isAugmenting, - required bool isUnsupported, + required bool conditionalImportSupported, + required Importability importability, required SourceLoader loader, required bool mayImplementRestrictedTypes, }) { @@ -220,7 +226,8 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit { referenceIsPartOwner: referenceIsPartOwner, forPatchLibrary: forPatchLibrary, isAugmenting: isAugmenting, - isUnsupported: isUnsupported, + conditionalImportSupported: conditionalImportSupported, + importability: importability, loader: loader, mayImplementRestrictedTypes: mayImplementRestrictedTypes, ); @@ -244,7 +251,8 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit { required bool? referenceIsPartOwner, required this.forPatchLibrary, required this.isAugmenting, - required this.isUnsupported, + required this.conditionalImportSupported, + required this.importability, required this.loader, required this.mayImplementRestrictedTypes, }) : _languageVersion = packageLanguageVersion, @@ -657,7 +665,7 @@ class SourceCompilationUnitImpl implements SourceCompilationUnit { target: library, indexedLibrary: indexedLibrary, referenceIsPartOwner: _referenceIsPartOwner, - isUnsupported: isUnsupported, + conditionalImportSupported: conditionalImportSupported, isAugmentation: forAugmentationLibrary, isPatch: forPatchLibrary, parentScope: _parentScope, diff --git a/pkg/front_end/lib/src/source/source_library_builder.dart b/pkg/front_end/lib/src/source/source_library_builder.dart index c0a4f80443e..a8eb84b1a70 100644 --- a/pkg/front_end/lib/src/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/source/source_library_builder.dart @@ -6,6 +6,8 @@ import 'dart:convert' show jsonEncode; import 'package:_fe_analyzer_shared/src/field_promotability.dart'; import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis_operations.dart'; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:kernel/ast.dart' hide Combinator, MapLiteralEntry; import 'package:kernel/class_hierarchy.dart' show ClassHierarchy; import 'package:kernel/clone.dart' show CloneVisitorNotMembers; @@ -204,7 +206,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { LibraryBuilder? nameOrigin, IndexedLibrary? indexedLibrary, bool? referenceIsPartOwner, - required bool isUnsupported, + required bool conditionalImportSupported, required bool isAugmentation, required bool isPatch, required NameSpace importNameSpace, @@ -238,7 +240,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { libraryName: libraryName, nameOrigin: nameOrigin, indexedLibrary: indexedLibrary, - isUnsupported: isUnsupported, + conditionalImportSupported: conditionalImportSupported, isAugmentation: isAugmentation, isPatch: isPatch, ); @@ -260,7 +262,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { required this.libraryName, required LibraryBuilder? nameOrigin, required IndexedLibrary? indexedLibrary, - required bool isUnsupported, + required bool conditionalImportSupported, required bool isAugmentation, required bool isPatch, }) : _packageUri = packageUri, @@ -342,7 +344,11 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { bool get isPatchLibrary => compilationUnit.forPatchLibrary; @override - bool get isUnsupported => compilationUnit.isUnsupported; + bool get conditionalImportSupported => + compilationUnit.conditionalImportSupported; + + @override + Importability get importability => compilationUnit.importability; /// Returns the state of the experimental features within this library. LibraryFeatures get libraryFeatures => compilationUnit.libraryFeatures; @@ -572,7 +578,8 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { state = SourceLibraryBuilderState.outlineNodesBuilt; library.isSynthetic = isSynthetic; - library.isUnsupported = isUnsupported; + library.conditionalImportSupported = conditionalImportSupported; + library.importability = importability; addDependencies(library, new Set()); library.name = compilationUnit.libraryDirective?.name; diff --git a/pkg/front_end/lib/src/source/source_loader.dart b/pkg/front_end/lib/src/source/source_loader.dart index 588ed28d61c..fc1b879f0ac 100644 --- a/pkg/front_end/lib/src/source/source_loader.dart +++ b/pkg/front_end/lib/src/source/source_loader.dart @@ -19,6 +19,8 @@ import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' ScannerResult, Token, scan; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:front_end/src/kernel/internal_ast.dart' show VariableDeclarationImpl; import 'package:kernel/ast.dart'; @@ -410,6 +412,7 @@ class SourceLoader extends Loader implements ProblemReportingHelper { bool isPatch = false, required bool mayImplementRestrictedTypes, }) { + final bool isDartLib = importUri.isScheme('dart'); return new SourceCompilationUnitImpl( importUri: importUri, fileUri: fileUri, @@ -421,10 +424,14 @@ class SourceLoader extends Loader implements ProblemReportingHelper { resolveInLibrary: null, indexedLibrary: referencesFromIndex, referenceIsPartOwner: referenceIsPartOwner, - isUnsupported: - origin?.isUnsupported ?? - importUri.isScheme('dart') && - !target.uriTranslator.isLibrarySupported(importUri.path), + conditionalImportSupported: + origin?.conditionalImportSupported ?? + isDartLib && target.uriTranslator.isLibrarySupported(importUri.path), + importability: + origin?.importability ?? + (isDartLib + ? target.uriTranslator.isLibraryImportable(importUri.path) + : Importability.always), isAugmenting: origin != null, forAugmentationLibrary: isAugmentation, forPatchLibrary: isPatch, @@ -460,7 +467,8 @@ class SourceLoader extends Loader implements ProblemReportingHelper { libraryName, libraryExists: compilationUnit != null, isSynthetic: compilationUnit?.isSynthetic ?? true, - isUnsupported: compilationUnit?.isUnsupported ?? true, + conditionalImportSupported: + compilationUnit?.conditionalImportSupported ?? false, dartLibrarySupport: target.backendTarget.dartLibrarySupport, ) ? "true" diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml index e05fe3aec6c..e061886efd0 100644 --- a/pkg/front_end/messages.yaml +++ b/pkg/front_end/messages.yaml @@ -4565,6 +4565,15 @@ unavailableDartLibrary: script: | import "dart:non_existing_library"; +unsupportedPlatformDartLibraryImport: + parameters: + Uri uri: undocumented + problemMessage: | + Using stub implementations for APIs in platform-specific Dart library + '#uri', which will throw 'UnsupportedError' if invoked. + severity: WARNING + external: test/unsupported_platform_dart_library_import_test.dart + importChainContext: parameters: Uri uri: undocumented diff --git a/pkg/front_end/test/generator_to_string_test.dart b/pkg/front_end/test/generator_to_string_test.dart index 3ee73802782..8e88567d04a 100644 --- a/pkg/front_end/test/generator_to_string_test.dart +++ b/pkg/front_end/test/generator_to_string_test.dart @@ -6,6 +6,8 @@ import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token, scanString; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:expect/expect.dart' show Expect; import 'package:front_end/src/base/compiler_context.dart' show CompilerContext; import 'package:front_end/src/base/constant_context.dart'; @@ -107,9 +109,10 @@ Future main() async { referenceIsPartOwner: null, forPatchLibrary: false, isAugmenting: false, - isUnsupported: false, + conditionalImportSupported: true, loader: loader, mayImplementRestrictedTypes: false, + importability: Importability.always, ); SourceLibraryBuilder libraryBuilder = new SourceLibraryBuilder( compilationUnit: compilationUnit, @@ -121,7 +124,7 @@ Future main() async { defaultLanguageVersion, ), loader: loader, - isUnsupported: false, + conditionalImportSupported: true, isAugmentation: false, isPatch: false, importNameSpace: new ComputedMutableNameSpace(), diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt index cddeb439cfc..d9eb0a5c4c4 100644 --- a/pkg/front_end/test/spell_checking_list_code.txt +++ b/pkg/front_end/test/spell_checking_list_code.txt @@ -866,6 +866,7 @@ implementers impls imply implying +importability importantly imprecise improperly @@ -1970,6 +1971,7 @@ tolerant tolerate tolerated tolerates +tooling toplevel topmost topological diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt index 8a38546dc3f..d16f3b1e023 100644 --- a/pkg/front_end/test/spell_checking_list_common.txt +++ b/pkg/front_end/test/spell_checking_list_common.txt @@ -1534,6 +1534,7 @@ implicitly implied implies import +importable important imported importer diff --git a/pkg/front_end/test/spell_checking_list_messages.txt b/pkg/front_end/test/spell_checking_list_messages.txt index 4fe3225b318..ca3fc3e1d89 100644 --- a/pkg/front_end/test/spell_checking_list_messages.txt +++ b/pkg/front_end/test/spell_checking_list_messages.txt @@ -138,6 +138,7 @@ strict stringokempty struct<#name structs +stub super.namedconstructor superinterface supermixin @@ -155,6 +156,7 @@ typeof u unavailable unsound +unsupportederror v wasm:export wasm:import diff --git a/pkg/front_end/test/static_types/cfe_allowed.json b/pkg/front_end/test/static_types/cfe_allowed.json index 3492d8b6e9b..64766ee5e56 100644 --- a/pkg/front_end/test/static_types/cfe_allowed.json +++ b/pkg/front_end/test/static_types/cfe_allowed.json @@ -5,6 +5,6 @@ "pkg/_fe_analyzer_shared/lib/src/util/libraries_specification.dart": { "Dynamic invocation of 'toList'.": 1, "Dynamic invocation of 'map'.": 1, - "Dynamic invocation of '[]='.": 1 + "Dynamic invocation of '[]='.": 2 } } \ No newline at end of file diff --git a/pkg/front_end/test/types/cfe_types_test.dart b/pkg/front_end/test/types/cfe_types_test.dart index ce898a6ff07..ee6047f5ed8 100644 --- a/pkg/front_end/test/types/cfe_types_test.dart +++ b/pkg/front_end/test/types/cfe_types_test.dart @@ -32,9 +32,7 @@ void main() { ..packagesFileUri = Uri.base.resolve(".dart_tool/package_config.json"), ), ); - final Uri uri = Uri.parse("dart:core"); - final TypeParserEnvironment environment = new TypeParserEnvironment(uri, uri); - final Component sdk = parseSdk(uri, environment); + final (Component sdk, TypeParserEnvironment environment) = parseSdk(); Future doIt(_) async { DillTarget target = new DillTarget( context, diff --git a/pkg/front_end/test/types/kernel_type_parser_test.dart b/pkg/front_end/test/types/kernel_type_parser_test.dart index d1ded0103aa..ac34a185beb 100644 --- a/pkg/front_end/test/types/kernel_type_parser_test.dart +++ b/pkg/front_end/test/types/kernel_type_parser_test.dart @@ -1,6 +1,8 @@ // Copyright (c) 2019, 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. +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import "package:expect/expect.dart" show Expect; import "package:kernel/ast.dart" show Component, DartType, Library; @@ -133,23 +135,22 @@ extension type NonNullableNestedGenericExtensionType(sel } """; -Component parseSdk(Uri uri, TypeParserEnvironment environment) { - Library library = parseLibrary( - uri, - mockSdk + testSdk, - environment: environment, - ); +(Component, TypeParserEnvironment) parseSdk() { + Uri uri = Uri.parse("dart:core"); + TypeParserEnvironment environment = new TypeParserEnvironment(uri, uri); + Library library = + parseLibrary(uri, mockSdk + testSdk, environment: environment) + ..conditionalImportSupported = true + ..importability = Importability.always; StringBuffer sb = new StringBuffer(); Printer printer = new Printer(sb); printer.writeLibraryFile(library); Expect.stringEquals(expectedSdk, "$sb"); - return new Component(libraries: [library]); + return (new Component(libraries: [library]), environment); } void main() { - Uri uri = Uri.parse("dart:core"); - TypeParserEnvironment environment = new TypeParserEnvironment(uri, uri); - Component component = parseSdk(uri, environment); + var (Component component, TypeParserEnvironment environment) = parseSdk(); CoreTypes coreTypes = new CoreTypes(component); ClassHierarchy hierarchy = new ClassHierarchy(component, coreTypes); new KernelSubtypeTest(coreTypes, hierarchy, environment).run(); diff --git a/pkg/front_end/test/unsupported_platform_dart_library_import_test.dart b/pkg/front_end/test/unsupported_platform_dart_library_import_test.dart new file mode 100644 index 00000000000..cc5357dfeb3 --- /dev/null +++ b/pkg/front_end/test/unsupported_platform_dart_library_import_test.dart @@ -0,0 +1,85 @@ +// Copyright (c) 2025, 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. + +import "package:_fe_analyzer_shared/src/messages/diagnostic_message.dart" + show CfeDiagnosticMessage, getMessageCodeObject, getMessageArguments; +import 'package:dev_compiler/dev_compiler.dart'; +import 'package:expect/async_helper.dart' show asyncTest; +import 'package:expect/expect.dart' show Expect; +import 'package:front_end/src/api_unstable/ddc.dart'; +import 'package:front_end/src/codes/cfe_codes.dart' + show codeUnsupportedPlatformDartLibraryImport, codeUnavailableDartLibrary; +import 'package:front_end/src/testing/compiler_common.dart' show compileScript; +import 'package:kernel/target/targets.dart'; + +const String testSource = ''' +import 'dart:async'; +import 'dart:ffi'; +import 'dart:html'; +import 'dart:io'; +import 'dart:isolate'; + +main() {} +'''; + +/// Check that a warning is reported for imports of platform-specific dart:* +/// libraries when includeUnsupportedPlatformLibraryStubs is true. +Future testUnsupportedPlatformImportWarning() async { + var unsupportedLibraryUris = []; + var options = new CompilerOptions() + ..sdkSummary = computePlatformBinariesLocation().resolve( + 'ddc_platform.dill', + ) + ..target = DevCompilerTarget( + TargetFlags(includeUnsupportedPlatformLibraryStubs: true), + ) + ..onDiagnostic = (CfeDiagnosticMessage message) { + Expect.equals(CfeSeverity.warning, message.severity); + Expect.identical( + codeUnsupportedPlatformDartLibraryImport, + getMessageCodeObject(message), + ); + Expect.isTrue(message.plainTextFormatted.length == 1); + unsupportedLibraryUris.add( + getMessageArguments(message)!['uri'].toString(), + ); + } + ..environmentDefines = {}; + await compileScript(testSource, options: options); + Expect.listEquals(unsupportedLibraryUris, ['dart:ffi']); +} + +/// Check that an error is reported for imports of platform-specific dart:* +/// libraries when includeUnsupportedPlatformLibraryStubs is false. +Future testUnsupportedPlatformImportError() async { + var unsupportedLibraryUris = []; + var options = new CompilerOptions() + ..sdkSummary = computePlatformBinariesLocation().resolve( + 'ddc_platform.dill', + ) + ..target = DevCompilerTarget(TargetFlags()) + ..onDiagnostic = (CfeDiagnosticMessage message) { + Expect.equals(CfeSeverity.error, message.severity); + Expect.identical( + codeUnavailableDartLibrary, + getMessageCodeObject(message), + ); + Expect.isTrue(message.plainTextFormatted.length == 1); + unsupportedLibraryUris.add( + getMessageArguments(message)!['uri'].toString(), + ); + } + ..environmentDefines = {}; + await compileScript(testSource, options: options); + Expect.listEquals(unsupportedLibraryUris, ['dart:ffi']); +} + +void main() { + asyncTest(() async { + await testUnsupportedPlatformImportWarning(); + }); + asyncTest(() async { + await testUnsupportedPlatformImportError(); + }); +} diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect index a0b52755ae0..d8f1ec7f0ee 100644 --- a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.expect @@ -24,7 +24,7 @@ class Class extends core::Object { return new _te::ClassImpl::•(); } -library /*isUnsupported*/; +library /*!conditionalImportSupported*/; import self as _te; import "dart:core" as core; import "dart:test" as self2; diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect index a0b52755ae0..d8f1ec7f0ee 100644 --- a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.modular.expect @@ -24,7 +24,7 @@ class Class extends core::Object { return new _te::ClassImpl::•(); } -library /*isUnsupported*/; +library /*!conditionalImportSupported*/; import self as _te; import "dart:core" as core; import "dart:test" as self2; diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect index df5c7e166da..384bbfff1d7 100644 --- a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.outline.expect @@ -22,7 +22,7 @@ class Class extends core::Object { return new _te::ClassImpl::•(); } -library /*isUnsupported*/; +library /*!conditionalImportSupported*/; import self as _te; import "dart:core" as core; import "dart:test" as self2; diff --git a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect index a0b52755ae0..d8f1ec7f0ee 100644 --- a/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/patch_internal/main.dart.strong.transformed.expect @@ -24,7 +24,7 @@ class Class extends core::Object { return new _te::ClassImpl::•(); } -library /*isUnsupported*/; +library /*!conditionalImportSupported*/; import self as _te; import "dart:core" as core; import "dart:test" as self2; diff --git a/pkg/front_end/testcases/general/supported_libraries/import_unsupported.not.importable_lib.dart b/pkg/front_end/testcases/general/supported_libraries/import_unsupported.not.importable_lib.dart new file mode 100644 index 00000000000..aeb7cd474f1 --- /dev/null +++ b/pkg/front_end/testcases/general/supported_libraries/import_unsupported.not.importable_lib.dart @@ -0,0 +1,5 @@ +// Copyright (c) 2025, 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. + +String field = 'unsupported.not.importable'; diff --git a/pkg/front_end/testcases/general/supported_libraries/libraries.json b/pkg/front_end/testcases/general/supported_libraries/libraries.json index 236dc8103c1..6916e6c2069 100644 --- a/pkg/front_end/testcases/general/supported_libraries/libraries.json +++ b/pkg/front_end/testcases/general/supported_libraries/libraries.json @@ -10,11 +10,18 @@ }, "unsupported.by.spec": { "uri": "unsupported.by.spec_lib.dart", - "supported": false + "support_conditional_import": false, + "support_direct_import": "always" }, "unsupported.by.target": { "uri": "unsupported.by.target_lib.dart", - "supported": true + "support_conditional_import": true, + "support_direct_import": "always" + }, + "unsupported.not.importable": { + "uri": "unsupported.not.importable_lib.dart", + "support_conditional_import": false, + "support_direct_import": "never" }, "_unsupported.by.spec_internal": { "uri": "unsupported.by.spec_internal_lib.dart" diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart b/pkg/front_end/testcases/general/supported_libraries/main.dart index 0677973621b..b7a47d27683 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart @@ -5,6 +5,7 @@ import 'dart:supported.by.spec'; import 'dart:unsupported.by.spec'; import 'dart:unsupported.by.target'; +import 'dart:unsupported.not.importable'; import 'import_default_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' @@ -12,6 +13,7 @@ import 'import_default_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' if (dart.library.unsupported.by.spec) 'import_unsupported.by.spec_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' as from_supported_by_spec_first; import 'import_default_lib.dart' @@ -20,12 +22,14 @@ import 'import_default_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' as from_supported_by_target; import 'import_default_lib.dart' if (dart.library.unsupported.by.spec) 'import_unsupported.by.spec_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' as from_supported_by_spec_last; @@ -56,6 +60,9 @@ main() { // supported by the libraries specification. expect(false, const bool.fromEnvironment('dart.library._unsupported.by.spec_internal')); + // `dart:unsupported.not.importable` is not supported by the spec or target. + expect(false, + const bool.fromEnvironment('dart.library.unsupported.not.importable')); } expect(expected, actual) { diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.expect b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.expect index f6a1f24334e..c095e7ed6f7 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.expect @@ -1,4 +1,15 @@ library; +// +// Problems in library: +// +// pkg/front_end/testcases/general/supported_libraries/main.dart:7:8: Error: Dart library 'dart:unsupported.by.target' is not available on this platform. +// import 'dart:unsupported.by.target'; +// ^ +// +// pkg/front_end/testcases/general/supported_libraries/main.dart:8:8: Error: Dart library 'dart:unsupported.not.importable' is not available on this platform. +// import 'dart:unsupported.not.importable'; +// ^ +// import self as self; import "dart:supported.by.spec" as spec; import "dart:_supported.by.target" as by_; @@ -12,6 +23,7 @@ import "dart:core" as core; import "dart:supported.by.spec"; import "dart:unsupported.by.spec"; import "dart:unsupported.by.target"; +import "dart:unsupported.not.importable"; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_first; import "org-dartlang-testcase:///import_supported.by.target_lib.dart" as from_supported_by_target; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_last; @@ -30,6 +42,7 @@ static method main() → dynamic { self::expect(false, #C2); self::expect(false, #C2); self::expect(false, #C2); + self::expect(false, #C2); } static method expect(dynamic expected, dynamic actual) → dynamic { if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) @@ -45,7 +58,7 @@ export "dart:_supported.by.target"; static method supportedBySpec() → void {} -library dart.unsupported.by.spec /*isUnsupported*/; +library dart.unsupported.by.spec /*!conditionalImportSupported*/; import self as spec2; import "dart:_unsupported.by.spec_internal" as spe; additionalExports = (spe::unsupportedBySpecInternal) @@ -59,6 +72,11 @@ import self as tar; static method unsupportedByTarget() → void {} +library dart.unsupported.not.importable /*!conditionalImportSupported*/; +import self as self2; + +static method unsupportedNotImportable() → void {} + library; import self as spe2; import "dart:core" as core; @@ -71,12 +89,12 @@ import "dart:core" as core; static field core::String field = "supported.by.target"; -library dart._supported.by_target /*isUnsupported*/; +library dart._supported.by_target /*!conditionalImportSupported*/; import self as by_; static method supportedByTarget() → void {} -library dart._unsupported.by.spec_internal /*isUnsupported*/; +library dart._unsupported.by.spec_internal /*!conditionalImportSupported*/; import self as spe; static method unsupportedBySpecInternal() → void {} diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.modular.expect index f6a1f24334e..c095e7ed6f7 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.modular.expect @@ -1,4 +1,15 @@ library; +// +// Problems in library: +// +// pkg/front_end/testcases/general/supported_libraries/main.dart:7:8: Error: Dart library 'dart:unsupported.by.target' is not available on this platform. +// import 'dart:unsupported.by.target'; +// ^ +// +// pkg/front_end/testcases/general/supported_libraries/main.dart:8:8: Error: Dart library 'dart:unsupported.not.importable' is not available on this platform. +// import 'dart:unsupported.not.importable'; +// ^ +// import self as self; import "dart:supported.by.spec" as spec; import "dart:_supported.by.target" as by_; @@ -12,6 +23,7 @@ import "dart:core" as core; import "dart:supported.by.spec"; import "dart:unsupported.by.spec"; import "dart:unsupported.by.target"; +import "dart:unsupported.not.importable"; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_first; import "org-dartlang-testcase:///import_supported.by.target_lib.dart" as from_supported_by_target; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_last; @@ -30,6 +42,7 @@ static method main() → dynamic { self::expect(false, #C2); self::expect(false, #C2); self::expect(false, #C2); + self::expect(false, #C2); } static method expect(dynamic expected, dynamic actual) → dynamic { if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) @@ -45,7 +58,7 @@ export "dart:_supported.by.target"; static method supportedBySpec() → void {} -library dart.unsupported.by.spec /*isUnsupported*/; +library dart.unsupported.by.spec /*!conditionalImportSupported*/; import self as spec2; import "dart:_unsupported.by.spec_internal" as spe; additionalExports = (spe::unsupportedBySpecInternal) @@ -59,6 +72,11 @@ import self as tar; static method unsupportedByTarget() → void {} +library dart.unsupported.not.importable /*!conditionalImportSupported*/; +import self as self2; + +static method unsupportedNotImportable() → void {} + library; import self as spe2; import "dart:core" as core; @@ -71,12 +89,12 @@ import "dart:core" as core; static field core::String field = "supported.by.target"; -library dart._supported.by_target /*isUnsupported*/; +library dart._supported.by_target /*!conditionalImportSupported*/; import self as by_; static method supportedByTarget() → void {} -library dart._unsupported.by.spec_internal /*isUnsupported*/; +library dart._unsupported.by.spec_internal /*!conditionalImportSupported*/; import self as spe; static method unsupportedBySpecInternal() → void {} diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.outline.expect index 5199b6617c0..bb2b03a8fa1 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.outline.expect @@ -4,6 +4,7 @@ import self as self; import "dart:supported.by.spec"; import "dart:unsupported.by.spec"; import "dart:unsupported.by.target"; +import "dart:unsupported.not.importable"; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_first; import "org-dartlang-testcase:///import_supported.by.target_lib.dart" as from_supported_by_target; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_last; @@ -23,7 +24,7 @@ export "dart:_supported.by.target"; static method supportedBySpec() → void ; -library dart.unsupported.by.spec /*isUnsupported*/; +library dart.unsupported.by.spec /*!conditionalImportSupported*/; import self as self3; import "dart:_unsupported.by.spec_internal" as spe; additionalExports = (spe::unsupportedBySpecInternal) @@ -39,11 +40,11 @@ import self as self4; static method unsupportedByTarget() → void ; -library; +library dart.unsupported.not.importable /*!conditionalImportSupported*/; import self as self5; -import "dart:core" as core; -static field core::String field; +static method unsupportedNotImportable() → void + ; library; import self as self6; @@ -51,13 +52,19 @@ import "dart:core" as core; static field core::String field; -library dart._supported.by_target /*isUnsupported*/; +library; +import self as self7; +import "dart:core" as core; + +static field core::String field; + +library dart._supported.by_target /*!conditionalImportSupported*/; import self as by_; static method supportedByTarget() → void ; -library dart._unsupported.by.spec_internal /*isUnsupported*/; +library dart._unsupported.by.spec_internal /*!conditionalImportSupported*/; import self as spe; static method unsupportedBySpecInternal() → void diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.transformed.expect index f6a1f24334e..c095e7ed6f7 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart.strong.transformed.expect @@ -1,4 +1,15 @@ library; +// +// Problems in library: +// +// pkg/front_end/testcases/general/supported_libraries/main.dart:7:8: Error: Dart library 'dart:unsupported.by.target' is not available on this platform. +// import 'dart:unsupported.by.target'; +// ^ +// +// pkg/front_end/testcases/general/supported_libraries/main.dart:8:8: Error: Dart library 'dart:unsupported.not.importable' is not available on this platform. +// import 'dart:unsupported.not.importable'; +// ^ +// import self as self; import "dart:supported.by.spec" as spec; import "dart:_supported.by.target" as by_; @@ -12,6 +23,7 @@ import "dart:core" as core; import "dart:supported.by.spec"; import "dart:unsupported.by.spec"; import "dart:unsupported.by.target"; +import "dart:unsupported.not.importable"; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_first; import "org-dartlang-testcase:///import_supported.by.target_lib.dart" as from_supported_by_target; import "org-dartlang-testcase:///import_supported.by.spec_lib.dart" as from_supported_by_spec_last; @@ -30,6 +42,7 @@ static method main() → dynamic { self::expect(false, #C2); self::expect(false, #C2); self::expect(false, #C2); + self::expect(false, #C2); } static method expect(dynamic expected, dynamic actual) → dynamic { if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) @@ -45,7 +58,7 @@ export "dart:_supported.by.target"; static method supportedBySpec() → void {} -library dart.unsupported.by.spec /*isUnsupported*/; +library dart.unsupported.by.spec /*!conditionalImportSupported*/; import self as spec2; import "dart:_unsupported.by.spec_internal" as spe; additionalExports = (spe::unsupportedBySpecInternal) @@ -59,6 +72,11 @@ import self as tar; static method unsupportedByTarget() → void {} +library dart.unsupported.not.importable /*!conditionalImportSupported*/; +import self as self2; + +static method unsupportedNotImportable() → void {} + library; import self as spe2; import "dart:core" as core; @@ -71,12 +89,12 @@ import "dart:core" as core; static field core::String field = "supported.by.target"; -library dart._supported.by_target /*isUnsupported*/; +library dart._supported.by_target /*!conditionalImportSupported*/; import self as by_; static method supportedByTarget() → void {} -library dart._unsupported.by.spec_internal /*isUnsupported*/; +library dart._unsupported.by.spec_internal /*!conditionalImportSupported*/; import self as spe; static method unsupportedBySpecInternal() → void {} diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline.expect b/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline.expect index 756dafe4e34..ac009421115 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline.expect +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline.expect @@ -4,12 +4,15 @@ import 'dart:unsupported.by.spec'; import 'dart:unsupported.by.target'; +import 'dart:unsupported.not.importable'; + import 'import_default_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' if (dart.library.unsupported.by.spec) 'import_unsupported.by.spec_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' as from_supported_by_spec_first; import 'import_default_lib.dart' @@ -18,12 +21,14 @@ import 'import_default_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' as from_supported_by_target; import 'import_default_lib.dart' if (dart.library.unsupported.by.spec) 'import_unsupported.by.spec_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' as from_supported_by_spec_last; diff --git a/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline_modelled.expect index eceda69d60b..a1de504a2c7 100644 --- a/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline_modelled.expect +++ b/pkg/front_end/testcases/general/supported_libraries/main.dart.textual_outline_modelled.expect @@ -1,12 +1,14 @@ import 'dart:supported.by.spec'; import 'dart:unsupported.by.spec'; import 'dart:unsupported.by.target'; +import 'dart:unsupported.not.importable'; import 'import_default_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' if (dart.library.unsupported.by.spec) 'import_unsupported.by.spec_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' as from_supported_by_spec_first; import 'import_default_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' @@ -14,11 +16,13 @@ import 'import_default_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' as from_supported_by_target; import 'import_default_lib.dart' if (dart.library.unsupported.by.spec) 'import_unsupported.by.spec_lib.dart' if (dart.library.unsupported.by.target) 'import_unsupported.by.target_lib.dart' if (dart.library._unsupported.by.spec_internal) 'import_unsupported.by.spec_internal_lib.dart' + if (dart.library.unsupported.not.importable) 'import_unsupported.not.importable_lib.dart' if (dart.library.supported.by.spec) 'import_supported.by.spec_lib.dart' if (dart.library._supported.by.target) 'import_supported.by.target_lib.dart' as from_supported_by_spec_last; diff --git a/pkg/front_end/testcases/general/supported_libraries/unsupported.not.importable_lib.dart b/pkg/front_end/testcases/general/supported_libraries/unsupported.not.importable_lib.dart new file mode 100644 index 00000000000..65639bed66a --- /dev/null +++ b/pkg/front_end/testcases/general/supported_libraries/unsupported.not.importable_lib.dart @@ -0,0 +1,7 @@ +// Copyright (c) 2025, 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. + +library dart.unsupported.not.importable; + +void unsupportedNotImportable() {} diff --git a/pkg/front_end/tool/dart_doctest_impl.dart b/pkg/front_end/tool/dart_doctest_impl.dart index 5dc5152a650..d57c98dcb4c 100644 --- a/pkg/front_end/tool/dart_doctest_impl.dart +++ b/pkg/front_end/tool/dart_doctest_impl.dart @@ -21,6 +21,8 @@ import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' import 'package:_fe_analyzer_shared/src/scanner/token.dart'; import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart' show Utf8BytesScanner; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'package:front_end/src/api_prototype/compiler_options.dart'; import 'package:front_end/src/api_prototype/file_system.dart'; import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart'; @@ -1116,7 +1118,7 @@ class DocTestIncrementalCompiler extends IncrementalCompiler { ), loader: loader, resolveInLibrary: libraryBuilder, - isUnsupported: false, + conditionalImportSupported: true, forAugmentationLibrary: false, isAugmenting: false, forPatchLibrary: false, @@ -1125,6 +1127,7 @@ class DocTestIncrementalCompiler extends IncrementalCompiler { indexedLibrary: null, augmentationRoot: null, mayImplementRestrictedTypes: false, + importability: Importability.always, ); if (libraryBuilder is DillLibraryBuilder) { diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart index 3247bbfe23f..246ecbdd53c 100644 --- a/pkg/frontend_server/lib/frontend_server.dart +++ b/pkg/frontend_server/lib/frontend_server.dart @@ -60,6 +60,10 @@ ArgParser argParser = new ArgParser(allowTrailingOptions: true) help: 'Whether dart:mirrors is supported. By default dart:mirrors is ' 'supported when --aot and --minimal-kernel are not used.', defaultsTo: null) + ..addFlag('include-unsupported-platform-library-stubs', + help: 'Whether platform specific dart:* libraries should be importable ' + 'from unsupported runtimes.', + hide: true) ..addFlag('compact-async', help: 'Obsolete, ignored.', hide: true) ..addFlag('tfa', help: 'Enable global type flow analysis and related transformations ' @@ -631,6 +635,8 @@ class FrontendCompiler implements CompilerInterface { options['target'], trackWidgetCreation: options['track-widget-creation'], supportMirrors: options['support-mirrors'] ?? !(aot || minimalKernel), + includeUnsupportedPlatformLibraryStubs: + options['include-unsupported-platform-library-stubs'], constKeepLocalsIndicator: !(aot || minimalKernel), ); if (compilerOptions.target == null) { diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart index d304b91209f..ac1ac2d4be5 100644 --- a/pkg/kernel/lib/ast.dart +++ b/pkg/kernel/lib/ast.dart @@ -83,6 +83,8 @@ import 'package:_fe_analyzer_shared/src/types/shared_type.dart' Variance; import 'package:_fe_analyzer_shared/src/messages/codes.dart' show demangleMixinApplicationName; +import 'package:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; import 'src/extension_type_erasure.dart'; import 'visitor.dart'; diff --git a/pkg/kernel/lib/src/ast/libraries.dart b/pkg/kernel/lib/src/ast/libraries.dart index 6a19042069d..687ac51381c 100644 --- a/pkg/kernel/lib/src/ast/libraries.dart +++ b/pkg/kernel/lib/src/ast/libraries.dart @@ -29,7 +29,9 @@ class Library extends NamedNode } static const int SyntheticFlag = 1 << 0; - static const int IsUnsupportedFlag = 1 << 1; + static const int SupportConditionalImportsFlag = 1 << 1; + static const int AlwaysImportableFlag = 1 << 2; + static const int ImportableWithFlagFlag = 1 << 3; int flags = 0; @@ -42,9 +44,32 @@ class Library extends NamedNode /// If true, the library is not supported through the 'dart.library.*' value /// used in conditional imports and `bool.fromEnvironment` constants. - bool get isUnsupported => flags & IsUnsupportedFlag != 0; - void set isUnsupported(bool value) { - flags = value ? (flags | IsUnsupportedFlag) : (flags & ~IsUnsupportedFlag); + bool get conditionalImportSupported => + flags & SupportConditionalImportsFlag != 0; + void set conditionalImportSupported(bool value) { + flags = value + ? (flags | SupportConditionalImportsFlag) + : (flags & ~SupportConditionalImportsFlag); + } + + /// Specifies if the library is importable on the target platform. + Importability get importability { + if (flags & AlwaysImportableFlag != 0) { + return Importability.always; + } + if (flags & ImportableWithFlagFlag != 0) { + return Importability.withFlag; + } + return Importability.never; + } + + void set importability(Importability value) { + flags = flags & ~(AlwaysImportableFlag | ImportableWithFlagFlag); + if (value == Importability.always) { + flags |= AlwaysImportableFlag; + } else if (value == Importability.withFlag) { + flags |= ImportableWithFlagFlag; + } } String? name; diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart index b01a10d1e8d..a54ce57fd2d 100644 --- a/pkg/kernel/lib/target/targets.dart +++ b/pkg/kernel/lib/target/targets.dart @@ -27,11 +27,16 @@ class TargetFlags { /// Targets can overwrite based on other things. final bool? constKeepLocalsIndicator; + /// Whether the backends should include stubs for core libraries not supported + /// by their target platform. + final bool includeUnsupportedPlatformLibraryStubs; + const TargetFlags( {this.trackWidgetCreation = false, this.supportMirrors = true, this.isClosureContextLoweringEnabled = false, - this.constKeepLocalsIndicator}); + this.constKeepLocalsIndicator, + this.includeUnsupportedPlatformLibraryStubs = false}); @override bool operator ==(other) { @@ -39,6 +44,8 @@ class TargetFlags { return other is TargetFlags && trackWidgetCreation == other.trackWidgetCreation && supportMirrors == other.supportMirrors && + includeUnsupportedPlatformLibraryStubs == + other.includeUnsupportedPlatformLibraryStubs && constKeepLocalsIndicator == other.constKeepLocalsIndicator; } @@ -47,6 +54,8 @@ class TargetFlags { int hash = 485786; hash = 0x3fffffff & (hash * 31 + (hash ^ trackWidgetCreation.hashCode)); hash = 0x3fffffff & (hash * 31 + (hash ^ supportMirrors.hashCode)); + hash = 0x3fffffff & + (hash * 31 + (hash ^ includeUnsupportedPlatformLibraryStubs.hashCode)); hash = 0x3fffffff & (hash * 31 + (hash ^ constKeepLocalsIndicator.hashCode)); return hash; @@ -203,7 +212,7 @@ abstract class DartLibrarySupport { static bool isDartLibrarySupported(String libraryName, {required bool libraryExists, required bool isSynthetic, - required bool isUnsupported, + required bool conditionalImportSupported, required DartLibrarySupport dartLibrarySupport}) { // A `dart:` library can be unsupported for several reasons: // * If the library doesn't exist from source or from dill, it is not @@ -219,7 +228,8 @@ abstract class DartLibrarySupport { // `dart:mirrors` as unsupported in AOT. The platform dill is shared with // JIT, so the library exists and is marked as supported, but for AOT // compilation it is still unsupported. - bool isSupported = libraryExists && !isSynthetic && !isUnsupported; + bool isSupported = + libraryExists && !isSynthetic && conditionalImportSupported; isSupported = dartLibrarySupport.computeDartLibrarySupport(libraryName, isSupportedBySpec: isSupported); return isSupported; diff --git a/pkg/kernel/lib/testing/type_parser_environment.dart b/pkg/kernel/lib/testing/type_parser_environment.dart index c4444ec3e42..3b7cbb61b54 100644 --- a/pkg/kernel/lib/testing/type_parser_environment.dart +++ b/pkg/kernel/lib/testing/type_parser_environment.dart @@ -2,6 +2,9 @@ // 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:_fe_analyzer_shared/src/util/libraries_specification.dart' + show Importability; + import "package:kernel/ast.dart" hide Visitor; import 'package:kernel/core_types.dart' show CoreTypes; @@ -20,7 +23,9 @@ Component parseComponent(String source, Uri uri) { TypeParserEnvironment coreEnvironment = new TypeParserEnvironment(coreUri, coreUri); Library coreLibrary = - parseLibrary(coreUri, mockSdk, environment: coreEnvironment); + parseLibrary(coreUri, mockSdk, environment: coreEnvironment) + ..conditionalImportSupported = true + ..importability = Importability.always; TypeParserEnvironment libraryEnvironment = new TypeParserEnvironment(uri, uri) ._extend(coreEnvironment._declarations); Library library = parseLibrary(uri, source, environment: libraryEnvironment); @@ -84,7 +89,9 @@ class Env { TypeParserEnvironment coreEnvironment = new TypeParserEnvironment(coreUri, coreUri); Library coreLibrary = - parseLibrary(coreUri, mockSdk, environment: coreEnvironment); + parseLibrary(coreUri, mockSdk, environment: coreEnvironment) + ..conditionalImportSupported = true + ..importability = Importability.always; _libraryEnvironment = new TypeParserEnvironment(libraryUri, libraryUri) ._extend(coreEnvironment._declarations); Library library = diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart index d747a69ceba..3849122a5d7 100644 --- a/pkg/kernel/lib/text/ast_to_text.dart +++ b/pkg/kernel/lib/text/ast_to_text.dart @@ -422,8 +422,9 @@ class Printer extends VisitorDefault with VisitorVoidMixin { writeWord(name); } List flags = []; - if (library.isUnsupported) { - flags.add('isUnsupported'); + if (!library.conditionalImportSupported && + library.importUri.isScheme('dart')) { + flags.add('!conditionalImportSupported'); } if (flags.isNotEmpty) { writeWord('/*${flags.join(',')}*/'); diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart index adc6700b6d7..b7f06247f70 100644 --- a/pkg/vm/lib/kernel_front_end.dart +++ b/pkg/vm/lib/kernel_front_end.dart @@ -986,6 +986,7 @@ Target? createFrontEndTarget( String targetName, { bool trackWidgetCreation = false, bool supportMirrors = true, + bool includeUnsupportedPlatformLibraryStubs = false, bool? constKeepLocalsIndicator, bool isClosureContextLoweringEnabled = false, }) { @@ -995,6 +996,8 @@ Target? createFrontEndTarget( final TargetFlags targetFlags = new TargetFlags( trackWidgetCreation: trackWidgetCreation, supportMirrors: supportMirrors, + includeUnsupportedPlatformLibraryStubs: + includeUnsupportedPlatformLibraryStubs, constKeepLocalsIndicator: constKeepLocalsIndicator, isClosureContextLoweringEnabled: isClosureContextLoweringEnabled, ); diff --git a/pkg/vm/testcases/transformations/mixin_deduplication/generic.dart.expect b/pkg/vm/testcases/transformations/mixin_deduplication/generic.dart.expect index cf71f136af5..971fed1766d 100644 --- a/pkg/vm/testcases/transformations/mixin_deduplication/generic.dart.expect +++ b/pkg/vm/testcases/transformations/mixin_deduplication/generic.dart.expect @@ -74,7 +74,7 @@ class SC3 extends mix::_MixinApplication5&B3&M2 static method main() → dynamic {} -library; +library /*!conditionalImportSupported*/; import self as self; import "dart:core" as core; import "file:pkg/vm/testcases/transformations/mixin_deduplication/generic_recursive_bounds.dart" as #lib; diff --git a/pkg/vm/testcases/transformations/mixin_deduplication/multiple_libraries_main.dart.expect b/pkg/vm/testcases/transformations/mixin_deduplication/multiple_libraries_main.dart.expect index ef7fcc6736b..43b6e0a2272 100644 --- a/pkg/vm/testcases/transformations/mixin_deduplication/multiple_libraries_main.dart.expect +++ b/pkg/vm/testcases/transformations/mixin_deduplication/multiple_libraries_main.dart.expect @@ -62,7 +62,7 @@ abstract class M1 extends core::Object /*isMi } -library; +library /*!conditionalImportSupported*/; import self as self; import "file:pkg/vm/testcases/transformations/mixin_deduplication/multiple_libraries_shared_helper.dart" as mul; import "dart:core" as core; diff --git a/pkg/vm/testcases/transformations/mixin_deduplication/non_generic.dart.expect b/pkg/vm/testcases/transformations/mixin_deduplication/non_generic.dart.expect index 590e273dc6f..07185a2890c 100644 --- a/pkg/vm/testcases/transformations/mixin_deduplication/non_generic.dart.expect +++ b/pkg/vm/testcases/transformations/mixin_deduplication/non_generic.dart.expect @@ -52,7 +52,7 @@ class SB3 extends mix::_MixinApplication3&B2&M2 { static method main() → dynamic {} -library; +library /*!conditionalImportSupported*/; import self as self; import "file:pkg/vm/testcases/transformations/mixin_deduplication/non_generic.dart" as #lib; import "dart:core" as core; diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json index 7417bcb7269..9cb8bd1f331 100644 --- a/sdk/lib/libraries.json +++ b/sdk/lib/libraries.json @@ -328,7 +328,7 @@ "io": { "uri": "io/io.dart", "patches": "_internal/wasm/lib/io_patch.dart", - "supported": false + "support_conditional_import": false }, "isolate": { "uri": "isolate/isolate.dart", @@ -434,12 +434,12 @@ "io": { "uri": "io/io.dart", "patches": "_internal/js_runtime/lib/io_patch.dart", - "supported": false + "support_conditional_import": false }, "isolate": { "uri": "isolate/isolate.dart", "patches": "_internal/js_runtime/lib/isolate_patch.dart", - "supported": false + "support_conditional_import": false }, "js": { "uri": "js/js.dart", @@ -614,17 +614,18 @@ "ffi": { "uri": "ffi/ffi.dart", "patches": "_internal/js_dev_runtime/patch/ffi_patch.dart", - "supported": false + "support_direct_import": "with_flag", + "support_conditional_import": false }, "io": { "uri": "io/io.dart", "patches": "_internal/js_dev_runtime/patch/io_patch.dart", - "supported": false + "support_conditional_import": false }, "isolate": { "uri": "isolate/isolate.dart", "patches": "_internal/js_dev_runtime/patch/isolate_patch.dart", - "supported": false + "support_conditional_import": false }, "math": { "uri": "math/math.dart", diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml index dc671032a63..b7f14879c0b 100644 --- a/sdk/lib/libraries.yaml +++ b/sdk/lib/libraries.yaml @@ -268,7 +268,7 @@ wasm_common: io: uri: io/io.dart patches: _internal/wasm/lib/io_patch.dart - supported: false + support_conditional_import: false isolate: uri: isolate/isolate.dart patches: @@ -355,12 +355,12 @@ _dart2js_common: io: uri: "io/io.dart" patches: "_internal/js_runtime/lib/io_patch.dart" - supported: false + support_conditional_import: false isolate: uri: "isolate/isolate.dart" patches: "_internal/js_runtime/lib/isolate_patch.dart" - supported: false + support_conditional_import: false js: uri: "js/js.dart" @@ -530,17 +530,18 @@ dartdevc: ffi: uri: "ffi/ffi.dart" patches: "_internal/js_dev_runtime/patch/ffi_patch.dart" - supported: false + support_direct_import: with_flag + support_conditional_import: false io: uri: "io/io.dart" patches: "_internal/js_dev_runtime/patch/io_patch.dart" - supported: false + support_conditional_import: false isolate: uri: "isolate/isolate.dart" patches: "_internal/js_dev_runtime/patch/isolate_patch.dart" - supported: false + support_conditional_import: false math: uri: "math/math.dart" diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status index 501363e5be0..8e48c51b0fe 100644 --- a/tests/co19/co19-kernel.status +++ b/tests/co19/co19-kernel.status @@ -28,6 +28,7 @@ LibTest/collection/ListMixin/ListMixin_class_A01_t01: SkipSlow # Issue 43036 [ $compiler == dart2bytecode || $runtime == dart_precompiled ] Language/Classes/Instance_Methods/Operators/unary_minus_t01: SkipByDesign # dart:mirrors is not supported. Language/Expressions/Constants/Constant_Contexts/constant_context_A02_t01: SkipByDesign # dart:mirrors is not supported. +LanguageFeatures/Constructor-tear-offs/unnamed_constructor_A06_t01: SkipByDesign # dart:mirrors is not supported. LibTest/mirrors/*: SkipByDesign # dart:mirrors is not supported. # It makes no sense to run any test that uses spawnURI under the simulator diff --git a/tests/lib/js/static_interop_test/disallowed_interop_libraries_test.dart b/tests/lib/js/static_interop_test/disallowed_interop_libraries_test.dart index 34aae2aa43e..b3ee43b3b2f 100644 --- a/tests/lib/js/static_interop_test/disallowed_interop_libraries_test.dart +++ b/tests/lib/js/static_interop_test/disallowed_interop_libraries_test.dart @@ -13,7 +13,9 @@ import 'dart:js_util'; // [web] Dart library 'dart:js_util' is not available on this platform. import 'dart:ffi'; -// [error column 1] +// [error line 15, column 1] // [web] 'dart:ffi' can't be imported when compiling to Wasm. +// [error line 15, column 8] +// [web] Dart library 'dart:ffi' is not available on this platform. void main() {}