diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart index 4186704277e6..fcb3230f8f62 100644 --- a/pkg/analysis_server/lib/src/context_manager.dart +++ b/pkg/analysis_server/lib/src/context_manager.dart @@ -446,10 +446,13 @@ class ContextManagerImpl implements ContextManager { var content = _readFile(path); var node = loadYamlNode(content); if (node is YamlMap) { - var validator = PubspecValidator( - resourceProvider, resourceProvider.getFile(path).createSource()); var lineInfo = LineInfo.fromContent(content); - var errors = validator.validate(node.nodes); + var errors = validatePubspec( + contents: node.nodes, + source: resourceProvider.getFile(path).createSource(), + provider: resourceProvider, + ); + var converter = AnalyzerConverter(); convertedErrors = converter.convertAnalysisErrors(errors, lineInfo: lineInfo, options: driver.analysisOptions); diff --git a/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart b/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart index a90a3b5896ed..79bbb8ea5e20 100644 --- a/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart +++ b/pkg/analysis_server/lib/src/handler/legacy/edit_get_fixes.dart @@ -219,9 +219,11 @@ error.errorCode: ${error.errorCode} if (yamlContent is! YamlMap) { yamlContent = YamlMap(); } - var validator = - PubspecValidator(resourceProvider, pubspecFile.createSource()); - var errors = validator.validate(yamlContent.nodes); + final errors = validatePubspec( + contents: yamlContent.nodes, + source: pubspecFile.createSource(), + provider: resourceProvider, + ); for (var error in errors) { var generator = PubspecFixGenerator(resourceProvider, error, content, document); diff --git a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart index c728c361388f..0b1378f378c9 100644 --- a/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart +++ b/pkg/analysis_server/lib/src/lsp/handlers/code_actions/pubspec.dart @@ -55,9 +55,11 @@ class PubspecCodeActionsProducer extends AbstractCodeActionsProducer { yamlContent = YamlMap(); } - final validator = - PubspecValidator(resourceProvider, pubspecFile.createSource()); - final errors = validator.validate(yamlContent.nodes); + final errors = validatePubspec( + contents: yamlContent.nodes, + source: pubspecFile.createSource(), + provider: resourceProvider, + ); final codeActions = []; for (final error in errors) { diff --git a/pkg/analysis_server/test/src/services/correction/fix/pubspec/test_support.dart b/pkg/analysis_server/test/src/services/correction/fix/pubspec/test_support.dart index e3161611c30c..aa094455e1b6 100644 --- a/pkg/analysis_server/test/src/services/correction/fix/pubspec/test_support.dart +++ b/pkg/analysis_server/test/src/services/correction/fix/pubspec/test_support.dart @@ -6,7 +6,8 @@ import 'package:analysis_server/plugin/edit/fix/fix_core.dart'; import 'package:analysis_server/src/protocol_server.dart' show SourceEdit; import 'package:analysis_server/src/services/correction/fix/pubspec/fix_generator.dart'; import 'package:analyzer/error/error.dart'; -import 'package:analyzer/src/pubspec/pubspec_validator.dart'; +import 'package:analyzer/src/pubspec/pubspec_validator.dart' + as pubspec_validator; import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; import 'package:analyzer_plugin/utilities/fixes/fixes.dart'; import 'package:test/test.dart'; @@ -49,9 +50,11 @@ abstract class PubspecFixTest with ResourceProviderMixin { if (yamlContent is! YamlMap) { yamlContent = YamlMap(); } - var validator = - PubspecValidator(resourceProvider, pubspecFile.createSource()); - var errors = validator.validate(yamlContent.nodes); + final errors = pubspec_validator.validatePubspec( + source: pubspecFile.createSource(), + contents: yamlContent.nodes, + provider: resourceProvider, + ); expect(errors.length, 1); error = errors[0]; } diff --git a/pkg/analyzer/doc/implementation/pub_diagnostics.md b/pkg/analyzer/doc/implementation/pub_diagnostics.md index 26d10830a273..f03f15c39645 100644 --- a/pkg/analyzer/doc/implementation/pub_diagnostics.md +++ b/pkg/analyzer/doc/implementation/pub_diagnostics.md @@ -18,7 +18,8 @@ The basic recipe for implementing a new pubspec diagnostic is as follows: 3. Add corresponding tests to a new test library in `test/src/pubspec/diagnostics`. 4. Implement analysis in a new validator in `lib/src/pubspec/validators` and - invoke it from PubspecValidator (or enhance an existing one). + add it to list of validators in `pubspec_validator.dart` + (or enhance an existing one). Once implemented, you’ll want to look for ecosystem breakages. Useful bots to watch: diff --git a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart index 6de97163396f..e43072192b15 100644 --- a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart @@ -12,39 +12,52 @@ import 'package:analyzer/src/pubspec/validators/flutter_validator.dart'; import 'package:analyzer/src/pubspec/validators/name_validator.dart'; import 'package:analyzer/src/pubspec/validators/platforms_validator.dart'; import 'package:analyzer/src/pubspec/validators/screenshot_validator.dart'; -import 'package:source_span/source_span.dart'; import 'package:yaml/yaml.dart'; -class BasePubspecValidator { - /// The resource provider used to access the file system. - final ResourceProvider provider; - - /// The source representing the file being validated. - final Source source; - - BasePubspecValidator(this.provider, this.source); +/// List of [PubspecValidator] implementations. +const _pubspecValidators = [ + dependencyValidator, + fieldValidator, + flutterValidator, + nameValidator, + screenshotsValidator, + platformsValidator, +]; + +/// Validate pubspec with given [contents]. +/// +/// The [source] argument must be the source of the file being validated. +/// The [provider] argument must provide access to the file-system. +List validatePubspec({ + // TODO(brianwilkerson) This method needs to take a `YamlDocument` rather + // than the contents of the document so that it can validate an empty file. + required Map contents, + required Source source, + required ResourceProvider provider, +}) { + final recorder = RecordingErrorListener(); + final ctx = PubspecValidationContext._( + contents: contents, + source: source, + reporter: ErrorReporter( + recorder, + source, + isNonNullableByDefault: false, + ), + provider: provider, + ); - String? asString(dynamic node) { - if (node is String) { - return node; - } - if (node is YamlScalar && node.value is String) { - return node.value as String; - } - return null; + for (final validator in _pubspecValidators) { + validator(ctx); } - /// Report an error for the given node. - void reportErrorForNode( - ErrorReporter reporter, YamlNode node, ErrorCode errorCode, - [List? arguments]) { - SourceSpan span = node.span; - reporter.reportErrorForOffset( - errorCode, span.start.offset, span.length, arguments); - } + return recorder.errors; } -class PubspecField { +/// A function that can validate a `pubspec.yaml`. +typedef PubspecValidator = void Function(PubspecValidationContext ctx); + +final class PubspecField { /// The name of the sub-field (under `flutter`) whose value is a list of /// assets available to Flutter apps at runtime. static const String ASSETS_FIELD = 'assets'; @@ -81,48 +94,49 @@ class PubspecField { static const String VERSION_FIELD = 'version'; } -class PubspecValidator { - /// The resource provider used to access the file system. - final ResourceProvider provider; +/// Context given to function that implement [PubspecValidator]. +final class PubspecValidationContext { + /// Yaml document being validated + final Map contents; /// The source representing the file being validated. final Source source; - final DependencyValidator _dependencyValidator; - final FieldValidator _fieldValidator; - final FlutterValidator _flutterValidator; - final NameValidator _nameValidator; - final ScreenshotsValidator _screenshotsValidator; - final PlatformsValidator _platformsValidator; - - /// Initialize a newly create validator to validate the content of the given - /// [source]. - PubspecValidator(this.provider, this.source) - : _dependencyValidator = DependencyValidator(provider, source), - _fieldValidator = FieldValidator(provider, source), - _flutterValidator = FlutterValidator(provider, source), - _nameValidator = NameValidator(provider, source), - _screenshotsValidator = ScreenshotsValidator(provider, source), - _platformsValidator = PlatformsValidator(provider, source); - - /// Validate the given [contents]. - List validate(Map contents) { - // TODO(brianwilkerson) This method needs to take a `YamlDocument` rather - // than the contents of the document so that it can validate an empty file. - RecordingErrorListener recorder = RecordingErrorListener(); - ErrorReporter reporter = ErrorReporter( - recorder, - source, - isNonNullableByDefault: false, - ); + /// The reporter to which errors should be reported. + final ErrorReporter reporter; - _dependencyValidator.validate(reporter, contents); - _fieldValidator.validate(reporter, contents); - _flutterValidator.validate(reporter, contents); - _nameValidator.validate(reporter, contents); - _screenshotsValidator.validate(reporter, contents); - _platformsValidator.validate(reporter, contents); + /// The resource provider used to access the file system. + final ResourceProvider provider; + + PubspecValidationContext._({ + required this.contents, + required this.source, + required this.reporter, + required this.provider, + }); + + String? asString(dynamic node) { + if (node is String) { + return node; + } + if (node is YamlScalar && node.value is String) { + return node.value as String; + } + return null; + } - return recorder.errors; + /// Report an error for the given node. + void reportErrorForNode( + YamlNode node, + ErrorCode errorCode, [ + List? arguments, + ]) { + final span = node.span; + reporter.reportErrorForOffset( + errorCode, + span.start.offset, + span.length, + arguments, + ); } } diff --git a/pkg/analyzer/lib/src/pubspec/validators/dependency_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/dependency_validator.dart index e23aa5cf4790..76be969c93ec 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/dependency_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/dependency_validator.dart @@ -2,7 +2,6 @@ // 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:analyzer/error/listener.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; import 'package:analyzer/src/util/file_paths.dart' as file_paths; @@ -10,55 +9,20 @@ import 'package:analyzer/src/util/yaml.dart'; import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart'; -class DependencyValidator extends BasePubspecValidator { - DependencyValidator(super.provider, super.source); - - /// Validate the value of the required `name` field. - void validate(ErrorReporter reporter, Map contents) { - Map declaredDependencies = _getDeclaredDependencies( - reporter, contents, PubspecField.DEPENDENCIES_FIELD); - Map declaredDevDependencies = _getDeclaredDependencies( - reporter, contents, PubspecField.DEV_DEPENDENCIES_FIELD); - - bool isPublishablePackage = false; - var version = contents[PubspecField.VERSION_FIELD]; - if (version != null) { - var publishTo = asString(contents[PubspecField.PUBLISH_TO_FIELD]); - if (publishTo != 'none') { - isPublishablePackage = true; - } - } - - for (var dependency in declaredDependencies.entries) { - _validatePathEntries(reporter, dependency.value, isPublishablePackage); - } - - for (var dependency in declaredDevDependencies.entries) { - var packageName = dependency.key as YamlNode; - if (declaredDependencies.containsKey(packageName)) { - reportErrorForNode( - reporter, - packageName, - PubspecWarningCode.UNNECESSARY_DEV_DEPENDENCY, - [packageName.valueOrThrow]); - } - _validatePathEntries(reporter, dependency.value, false); - } - } - +/// Validate the value of the required `name` field. +void dependencyValidator(PubspecValidationContext ctx) { /// Return a map whose keys are the names of declared dependencies and whose /// values are the specifications of those dependencies. The map is extracted /// from the given [contents] using the given [key]. - Map _getDeclaredDependencies( - ErrorReporter reporter, Map contents, String key) { - var field = contents[key]; + Map getDeclaredDependencies(String key) { + var field = ctx.contents[key]; if (field == null || (field is YamlScalar && field.value == null)) { return {}; } else if (field is YamlMap) { return field.nodes; } - reportErrorForNode( - reporter, field, PubspecWarningCode.DEPENDENCIES_FIELD_NOT_MAP, [key]); + ctx.reportErrorForNode( + field, PubspecWarningCode.DEPENDENCIES_FIELD_NOT_MAP, [key]); return {}; } @@ -71,46 +35,75 @@ class DependencyValidator extends BasePubspecValidator { /// /// If [checkForPathAndGitDeps] is true, `git` or `path` dependencies will /// be marked invalid. - void _validatePathEntries(ErrorReporter reporter, YamlNode dependency, - bool checkForPathAndGitDeps) { - if (dependency is YamlMap) { - var pathEntry = asString(dependency[PubspecField.PATH_FIELD]); - if (pathEntry != null) { - YamlNode pathKey() => dependency.getKey(PubspecField.PATH_FIELD)!; - YamlNode pathValue() => dependency.valueAt(PubspecField.PATH_FIELD)!; + void validatePathEntries(YamlNode dependency, bool checkForPathAndGitDeps) { + if (dependency is! YamlMap) { + return; + } + var pathEntry = ctx.asString(dependency[PubspecField.PATH_FIELD]); + if (pathEntry != null) { + YamlNode pathKey() => dependency.getKey(PubspecField.PATH_FIELD)!; + YamlNode pathValue() => dependency.valueAt(PubspecField.PATH_FIELD)!; - if (pathEntry.contains(r'\')) { - reportErrorForNode(reporter, pathValue(), - PubspecWarningCode.PATH_NOT_POSIX, [pathEntry]); - return; - } - var context = provider.pathContext; - var normalizedPath = context.joinAll(path.posix.split(pathEntry)); - var packageRoot = context.dirname(source.fullName); - var dependencyPath = context.join(packageRoot, normalizedPath); - dependencyPath = context.absolute(dependencyPath); - dependencyPath = context.normalize(dependencyPath); - var packageFolder = provider.getFolder(dependencyPath); - if (!packageFolder.exists) { - reportErrorForNode(reporter, pathValue(), - PubspecWarningCode.PATH_DOES_NOT_EXIST, [pathEntry]); - } else { - if (!packageFolder.getChild(file_paths.pubspecYaml).exists) { - reportErrorForNode(reporter, pathValue(), - PubspecWarningCode.PATH_PUBSPEC_DOES_NOT_EXIST, [pathEntry]); - } - } - if (checkForPathAndGitDeps) { - reportErrorForNode(reporter, pathKey(), - PubspecWarningCode.INVALID_DEPENDENCY, [PubspecField.PATH_FIELD]); + if (pathEntry.contains(r'\')) { + ctx.reportErrorForNode( + pathValue(), PubspecWarningCode.PATH_NOT_POSIX, [pathEntry]); + return; + } + var context = ctx.provider.pathContext; + var normalizedPath = context.joinAll(path.posix.split(pathEntry)); + var packageRoot = context.dirname(ctx.source.fullName); + var dependencyPath = context.join(packageRoot, normalizedPath); + dependencyPath = context.absolute(dependencyPath); + dependencyPath = context.normalize(dependencyPath); + var packageFolder = ctx.provider.getFolder(dependencyPath); + if (!packageFolder.exists) { + ctx.reportErrorForNode( + pathValue(), PubspecWarningCode.PATH_DOES_NOT_EXIST, [pathEntry]); + } else { + if (!packageFolder.getChild(file_paths.pubspecYaml).exists) { + ctx.reportErrorForNode(pathValue(), + PubspecWarningCode.PATH_PUBSPEC_DOES_NOT_EXIST, [pathEntry]); } } - - var gitEntry = dependency[PubspecField.GIT_FIELD]; - if (gitEntry != null && checkForPathAndGitDeps) { - reportErrorForNode(reporter, dependency.getKey(PubspecField.GIT_FIELD)!, - PubspecWarningCode.INVALID_DEPENDENCY, [PubspecField.GIT_FIELD]); + if (checkForPathAndGitDeps) { + ctx.reportErrorForNode(pathKey(), PubspecWarningCode.INVALID_DEPENDENCY, + [PubspecField.PATH_FIELD]); } } + + var gitEntry = dependency[PubspecField.GIT_FIELD]; + if (gitEntry != null && checkForPathAndGitDeps) { + ctx.reportErrorForNode(dependency.getKey(PubspecField.GIT_FIELD)!, + PubspecWarningCode.INVALID_DEPENDENCY, [PubspecField.GIT_FIELD]); + } + } + + final declaredDependencies = + getDeclaredDependencies(PubspecField.DEPENDENCIES_FIELD); + final declaredDevDependencies = + getDeclaredDependencies(PubspecField.DEV_DEPENDENCIES_FIELD); + + bool isPublishablePackage = false; + var version = ctx.contents[PubspecField.VERSION_FIELD]; + if (version != null) { + var publishTo = ctx.asString(ctx.contents[PubspecField.PUBLISH_TO_FIELD]); + if (publishTo != 'none') { + isPublishablePackage = true; + } + } + + for (var dependency in declaredDependencies.entries) { + validatePathEntries(dependency.value, isPublishablePackage); + } + + for (var dependency in declaredDevDependencies.entries) { + var packageName = dependency.key as YamlNode; + if (declaredDependencies.containsKey(packageName)) { + ctx.reportErrorForNode( + packageName, + PubspecWarningCode.UNNECESSARY_DEV_DEPENDENCY, + [packageName.valueOrThrow]); + } + validatePathEntries(dependency.value, false); } } diff --git a/pkg/analyzer/lib/src/pubspec/validators/field_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/field_validator.dart index 63a1113288aa..64ee783dcefc 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/field_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/field_validator.dart @@ -2,31 +2,24 @@ // 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:analyzer/error/listener.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; import 'package:yaml/yaml.dart'; -class FieldValidator extends BasePubspecValidator { - static const deprecatedFields = [ - 'author', - 'authors', - 'transformers', - 'web', - ]; +const _deprecatedFields = [ + 'author', + 'authors', + 'transformers', + 'web', +]; - FieldValidator(super.provider, super.source); - - /// Validate fields. - void validate(ErrorReporter reporter, Map contents) { - for (var field in contents.keys) { - var name = asString(field); - if (field is YamlNode && - name != null && - deprecatedFields.contains(name)) { - reportErrorForNode( - reporter, field, PubspecWarningCode.DEPRECATED_FIELD, [name]); - } +/// Validate fields. +void fieldValidator(PubspecValidationContext ctx) { + for (var field in ctx.contents.keys) { + var name = ctx.asString(field); + if (field is YamlNode && name != null && _deprecatedFields.contains(name)) { + ctx.reportErrorForNode( + field, PubspecWarningCode.DEPRECATED_FIELD, [name]); } } } diff --git a/pkg/analyzer/lib/src/pubspec/validators/flutter_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/flutter_validator.dart index 4c077899c7e0..bfc32fd39693 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/flutter_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/flutter_validator.dart @@ -3,7 +3,6 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/error/error.dart'; -import 'package:analyzer/error/listener.dart'; import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; @@ -11,76 +10,19 @@ import 'package:analyzer/src/util/yaml.dart'; import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart'; -class FlutterValidator extends BasePubspecValidator { - FlutterValidator(super.provider, super.source); - - /// Validate the value of the optional `flutter` field. - void validate(ErrorReporter reporter, Map contents) { - var flutterField = contents[PubspecField.FLUTTER_FIELD]; - if (flutterField is YamlMap) { - var assetsField = flutterField.nodes[PubspecField.ASSETS_FIELD]; - if (assetsField is YamlList) { - path.Context context = provider.pathContext; - String packageRoot = context.dirname(source.fullName); - for (YamlNode entryValue in assetsField.nodes) { - if (entryValue is YamlScalar) { - var entry = entryValue.valueOrThrow; - if (entry is String) { - if (entry.startsWith('packages/')) { - // TODO(brianwilkerson) Add validation of package references. - } else { - bool isDirectoryEntry = entry.endsWith("/"); - String normalizedEntry = - context.joinAll(path.posix.split(entry)); - String assetPath = context.join(packageRoot, normalizedEntry); - if (!_assetExistsAtPath(assetPath)) { - ErrorCode errorCode = isDirectoryEntry - ? PubspecWarningCode.ASSET_DIRECTORY_DOES_NOT_EXIST - : PubspecWarningCode.ASSET_DOES_NOT_EXIST; - reportErrorForNode(reporter, entryValue, errorCode, - [entryValue.valueOrThrow]); - } - } - } else { - reportErrorForNode( - reporter, entryValue, PubspecWarningCode.ASSET_NOT_STRING); - } - } else { - reportErrorForNode( - reporter, entryValue, PubspecWarningCode.ASSET_NOT_STRING); - } - } - } else if (assetsField != null) { - reportErrorForNode( - reporter, assetsField, PubspecWarningCode.ASSET_FIELD_NOT_LIST); - } - - if (flutterField.length > 1) { - // TODO(brianwilkerson) Should we report an error if `flutter` contains - // keys other than `assets`? - } - } else if (flutterField != null) { - if (flutterField.value == null) { - // allow an empty `flutter:` section; explicitly fail on a non-empty, - // non-map one - } else { - reportErrorForNode( - reporter, flutterField, PubspecWarningCode.FLUTTER_FIELD_NOT_MAP); - } - } - } - +/// Validate the value of the optional `flutter` field. +void flutterValidator(PubspecValidationContext ctx) { /// Return `true` if an asset (file) exists at the given absolute, normalized /// [assetPath] or in a subdirectory of the parent of the file. - bool _assetExistsAtPath(String assetPath) { + bool assetExistsAtPath(String assetPath) { // Check for asset directories. - Folder assetDirectory = provider.getFolder(assetPath); + Folder assetDirectory = ctx.provider.getFolder(assetPath); if (assetDirectory.exists) { return true; } // Else, check for an asset file. - File assetFile = provider.getFile(assetPath); + File assetFile = ctx.provider.getFile(assetPath); if (assetFile.exists) { return true; } @@ -99,4 +41,56 @@ class FlutterValidator extends BasePubspecValidator { } return false; } + + var flutterField = ctx.contents[PubspecField.FLUTTER_FIELD]; + if (flutterField is YamlMap) { + var assetsField = flutterField.nodes[PubspecField.ASSETS_FIELD]; + if (assetsField is YamlList) { + path.Context context = ctx.provider.pathContext; + String packageRoot = context.dirname(ctx.source.fullName); + for (YamlNode entryValue in assetsField.nodes) { + if (entryValue is YamlScalar) { + var entry = entryValue.valueOrThrow; + if (entry is String) { + if (entry.startsWith('packages/')) { + // TODO(brianwilkerson) Add validation of package references. + } else { + bool isDirectoryEntry = entry.endsWith("/"); + String normalizedEntry = context.joinAll(path.posix.split(entry)); + String assetPath = context.join(packageRoot, normalizedEntry); + if (!assetExistsAtPath(assetPath)) { + ErrorCode errorCode = isDirectoryEntry + ? PubspecWarningCode.ASSET_DIRECTORY_DOES_NOT_EXIST + : PubspecWarningCode.ASSET_DOES_NOT_EXIST; + ctx.reportErrorForNode( + entryValue, errorCode, [entryValue.valueOrThrow]); + } + } + } else { + ctx.reportErrorForNode( + entryValue, PubspecWarningCode.ASSET_NOT_STRING); + } + } else { + ctx.reportErrorForNode( + entryValue, PubspecWarningCode.ASSET_NOT_STRING); + } + } + } else if (assetsField != null) { + ctx.reportErrorForNode( + assetsField, PubspecWarningCode.ASSET_FIELD_NOT_LIST); + } + + if (flutterField.length > 1) { + // TODO(brianwilkerson) Should we report an error if `flutter` contains + // keys other than `assets`? + } + } else if (flutterField != null) { + if (flutterField.value == null) { + // allow an empty `flutter:` section; explicitly fail on a non-empty, + // non-map one + } else { + ctx.reportErrorForNode( + flutterField, PubspecWarningCode.FLUTTER_FIELD_NOT_MAP); + } + } } diff --git a/pkg/analyzer/lib/src/pubspec/validators/name_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/name_validator.dart index 921576e5ccc5..79cdd049e225 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/name_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/name_validator.dart @@ -2,22 +2,16 @@ // 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:analyzer/error/listener.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; import 'package:yaml/yaml.dart'; -class NameValidator extends BasePubspecValidator { - NameValidator(super.provider, super.source); - - /// Validate the value of the required `name` field. - void validate(ErrorReporter reporter, Map contents) { - var nameField = contents[PubspecField.NAME_FIELD]; - if (nameField == null) { - reporter.reportErrorForOffset(PubspecWarningCode.MISSING_NAME, 0, 0); - } else if (nameField is! YamlScalar || nameField.value is! String) { - reportErrorForNode( - reporter, nameField, PubspecWarningCode.NAME_NOT_STRING); - } +/// Validate the value of the required `name` field. +void nameValidator(PubspecValidationContext ctx) { + var nameField = ctx.contents[PubspecField.NAME_FIELD]; + if (nameField == null) { + ctx.reporter.reportErrorForOffset(PubspecWarningCode.MISSING_NAME, 0, 0); + } else if (nameField is! YamlScalar || nameField.value is! String) { + ctx.reportErrorForNode(nameField, PubspecWarningCode.NAME_NOT_STRING); } } diff --git a/pkg/analyzer/lib/src/pubspec/validators/platforms_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/platforms_validator.dart index 654394e669fd..feb04c2c3b87 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/platforms_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/platforms_validator.dart @@ -2,7 +2,6 @@ // 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:analyzer/error/listener.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; import 'package:analyzer/src/util/yaml.dart'; @@ -18,51 +17,43 @@ const _knownPlatforms = { 'windows', }; -final class PlatformsValidator extends BasePubspecValidator { - PlatformsValidator(super.provider, super.source); - - /// Validate platforms. - void validate(ErrorReporter reporter, Map contents) { - var platforms = contents[PubspecField.PLATFORMS_FIELD]; - if (platforms == null) { - return; - } - // The 'platforms' field must be a map - if (platforms is! YamlMap) { - reportErrorForNode( - reporter, - platforms, - PubspecWarningCode.INVALID_PLATFORMS_FIELD, +/// Validate platforms. +void platformsValidator(PubspecValidationContext ctx) { + final platforms = ctx.contents[PubspecField.PLATFORMS_FIELD]; + if (platforms == null) { + return; + } + // The 'platforms' field must be a map + if (platforms is! YamlMap) { + ctx.reportErrorForNode( + platforms, + PubspecWarningCode.INVALID_PLATFORMS_FIELD, + ); + return; + } + // Each key under 'platforms' must be a supported platform. + for (final platform in platforms.nodeMap.keys) { + if (platform is! YamlScalar || !_knownPlatforms.contains(platform.value)) { + ctx.reportErrorForNode( + platform, + PubspecWarningCode.UNKNOWN_PLATFORM, + [ + switch (platform.value) { + (String s) => s, + (num n) => n, + _ => platform.toString(), + }, + ], ); - return; } - // Each key under 'platforms' must be a supported platform. - for (final platform in platforms.nodeMap.keys) { - if (platform is! YamlScalar || - !_knownPlatforms.contains(platform.value)) { - reportErrorForNode( - reporter, - platform, - PubspecWarningCode.UNKNOWN_PLATFORM, - [ - switch (platform.value) { - (String s) => s, - (num n) => n, - _ => platform.toString(), - }, - ], - ); - } - } - // Values under the platforms keys are not allowed. - for (final v in platforms.nodeMap.values) { - if (v is! YamlScalar || v.value != null) { - reportErrorForNode( - reporter, - v, - PubspecWarningCode.PLATFORM_VALUE_DISALLOWED, - ); - } + } + // Values under the platforms keys are not allowed. + for (final v in platforms.nodeMap.values) { + if (v is! YamlScalar || v.value != null) { + ctx.reportErrorForNode( + v, + PubspecWarningCode.PLATFORM_VALUE_DISALLOWED, + ); } } } diff --git a/pkg/analyzer/lib/src/pubspec/validators/screenshot_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/screenshot_validator.dart index a41b8585fa79..e6fb3a3df01e 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/screenshot_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/screenshot_validator.dart @@ -2,38 +2,36 @@ // 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:analyzer/error/listener.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/pubspec/pubspec_warning_code.dart'; import 'package:analyzer/src/util/yaml.dart'; import 'package:path/path.dart' as p; import 'package:yaml/yaml.dart'; -class ScreenshotsValidator extends BasePubspecValidator { - ScreenshotsValidator(super.provider, super.source); - - /// Validate screenshots. - void validate(ErrorReporter reporter, Map contents) { - var screenshots = contents[PubspecField.SCREENSHOTS_FIELD]; - if (screenshots is! YamlList) return; - for (var entry in screenshots) { - if (entry is! YamlMap) continue; - var entryValue = entry.valueAt(PubspecField.PATH_FIELD); - if (entryValue is! YamlScalar) continue; - var path = entryValue.value; - if (path is String && !_fileExistsAtPath(path)) { - reportErrorForNode(reporter, entryValue, - PubspecWarningCode.PATH_DOES_NOT_EXIST, [entryValue.valueOrThrow]); - } - } +/// Validate screenshots. +void screenshotsValidator(PubspecValidationContext ctx) { + bool fileExistsAtPath(String filePath) { + final context = ctx.provider.pathContext; + final normalizedEntry = context.joinAll(p.posix.split(filePath)); + final directoryRoot = context.dirname(ctx.source.fullName); + final fullPath = context.join(directoryRoot, normalizedEntry); + final file = ctx.provider.getFile(fullPath); + return file.exists; } - bool _fileExistsAtPath(String filePath) { - var context = provider.pathContext; - var normalizedEntry = context.joinAll(p.posix.split(filePath)); - var directoryRoot = context.dirname(source.fullName); - var fullPath = context.join(directoryRoot, normalizedEntry); - var file = provider.getFile(fullPath); - return file.exists; + final screenshots = ctx.contents[PubspecField.SCREENSHOTS_FIELD]; + if (screenshots is! YamlList) return; + for (final entry in screenshots) { + if (entry is! YamlMap) continue; + final entryValue = entry.valueAt(PubspecField.PATH_FIELD); + if (entryValue is! YamlScalar) continue; + final path = entryValue.value; + if (path is String && !fileExistsAtPath(path)) { + ctx.reportErrorForNode( + entryValue, + PubspecWarningCode.PATH_DOES_NOT_EXIST, + [entryValue.valueOrThrow], + ); + } } } diff --git a/pkg/analyzer/test/src/pubspec/pubspec_test_support.dart b/pkg/analyzer/test/src/pubspec/pubspec_test_support.dart index ab9365f8c129..dd795196b644 100644 --- a/pkg/analyzer/test/src/pubspec/pubspec_test_support.dart +++ b/pkg/analyzer/test/src/pubspec/pubspec_test_support.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'package:analyzer/error/error.dart'; +import 'package:analyzer/src/generated/source.dart'; import 'package:analyzer/src/pubspec/pubspec_validator.dart'; import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; import 'package:meta/meta.dart'; @@ -11,7 +12,7 @@ import 'package:yaml/yaml.dart'; import '../../generated/test_support.dart'; class PubspecDiagnosticTest with ResourceProviderMixin { - late PubspecValidator validator; + late Source _source; /// Assert that when the validator is used on the given [content] the /// [expectedErrorCodes] are produced. @@ -21,9 +22,12 @@ class PubspecDiagnosticTest with ResourceProviderMixin { // The file is empty. node = YamlMap(); } - List errors = validator.validate(node.nodes); GatheringErrorListener listener = GatheringErrorListener(); - listener.addAll(errors); + listener.addAll(validatePubspec( + contents: node.nodes, + source: _source, + provider: resourceProvider, + )); listener.assertErrorsWithCodes(expectedErrorCodes); } @@ -35,8 +39,6 @@ class PubspecDiagnosticTest with ResourceProviderMixin { @mustCallSuper void setUp() { - var pubspecFile = getFile('/sample/pubspec.yaml'); - var source = pubspecFile.createSource(); - validator = PubspecValidator(resourceProvider, source); + _source = getFile('/sample/pubspec.yaml').createSource(); } } diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart index c2176f799da7..03d8e1f34947 100644 --- a/pkg/analyzer_cli/lib/src/driver.dart +++ b/pkg/analyzer_cli/lib/src/driver.dart @@ -279,9 +279,11 @@ class Driver implements CommandLineStarter { var content = file.readAsStringSync(); var node = loadYamlNode(content); if (node is YamlMap) { - var validator = - PubspecValidator(resourceProvider, file.createSource()); - errors.addAll(validator.validate(node.nodes)); + errors.addAll(validatePubspec( + contents: node.nodes, + source: file.createSource(), + provider: resourceProvider, + )); } if (analysisDriver.analysisOptions.lint) { diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart index a061a37bf27f..ffb1843a579b 100644 --- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart @@ -112,7 +112,6 @@ import '../problems.dart' show unexpected, unhandled; import '../scope.dart'; import '../util/helpers.dart'; import 'class_declaration.dart'; -import 'constructor_declaration.dart'; import 'name_scheme.dart'; import 'source_class_builder.dart' show SourceClassBuilder; import 'source_constructor_builder.dart'; @@ -4261,22 +4260,13 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { } } - void processSourceConstructorBuilder(SourceMemberBuilder member, + void processSourceConstructorBuilder(SourceFunctionBuilder member, {required bool inErrorRecovery}) { - List? formals; - if (member is SourceFactoryBuilder) { - assert(member.isFactory, - "Unexpected constructor member (${member.runtimeType})."); - count += computeDefaultTypesForVariables(member.typeVariables, - // Type variables are inherited from the class so if the class - // has issues, so does the factory constructors. - inErrorRecovery: inErrorRecovery); - formals = member.formals; - } else { - assert(member is ConstructorDeclaration, - "Unexpected constructor member (${member.runtimeType})."); - formals = (member as ConstructorDeclaration).formals; - } + count += computeDefaultTypesForVariables(member.typeVariables, + // Type variables are inherited from the enclosing declaration, so if + // it has issues, so do the constructors. + inErrorRecovery: inErrorRecovery); + List? formals = member.formals; if (formals != null && formals.isNotEmpty) { for (FormalParameterBuilder formal in formals) { List issues = @@ -4294,7 +4284,9 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { } else if (member is SourceFieldBuilder) { processSourceFieldBuilder(member); } else { - processSourceConstructorBuilder(member, + assert(member is SourceFactoryBuilder || + member is SourceConstructorBuilder); + processSourceConstructorBuilder(member as SourceFunctionBuilder, inErrorRecovery: inErrorRecovery); } } @@ -4359,6 +4351,14 @@ class SourceLibraryBuilder extends LibraryBuilderImpl { count += computeDefaultTypesForVariables(declaration.typeParameters, inErrorRecovery: issues.isNotEmpty); + Iterator iterator = declaration.constructorScope + .filteredIterator( + includeDuplicates: false, includeAugmentations: true); + while (iterator.moveNext()) { + processSourceMemberBuilder(iterator.current, + inErrorRecovery: issues.isNotEmpty); + } + declaration.forEach((String name, Builder member) { if (member is SourceMemberBuilder) { processSourceMemberBuilder(member, diff --git a/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart b/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart index 6c4ea11f3dde..e6d68a0ca5fe 100644 --- a/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart +++ b/pkg/front_end/lib/src/fasta/type_inference/closure_context.dart @@ -53,12 +53,16 @@ abstract class ClosureContext { if (isGenerator) { if (isAsync) { DartType yieldContext = inferrer.getTypeArgumentOf( - returnContext, inferrer.coreTypes.streamClass); + inferrer.typeSchemaEnvironment.getUnionFreeType(returnContext, + isNonNullableByDefault: inferrer.isNonNullableByDefault), + inferrer.coreTypes.streamClass); return new _AsyncStarClosureContext( inferrer, yieldContext, declaredReturnType, needToInferReturnType); } else { DartType yieldContext = inferrer.getTypeArgumentOf( - returnContext, inferrer.coreTypes.iterableClass); + inferrer.typeSchemaEnvironment.getUnionFreeType(returnContext, + isNonNullableByDefault: inferrer.isNonNullableByDefault), + inferrer.coreTypes.iterableClass); return new _SyncStarClosureContext( inferrer, yieldContext, declaredReturnType, needToInferReturnType); } diff --git a/pkg/front_end/testcases/general/issue53052.dart b/pkg/front_end/testcases/general/issue53052.dart new file mode 100644 index 000000000000..ba431f5901c4 --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart @@ -0,0 +1,45 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; + +FutureOr> f() sync* { + yield 'Hello!' as dynamic; +} + +FutureOr> g() async* { + yield* 'Hello!' as dynamic; +} + +main() async { + var iterable = f(); + if (iterable is Future) return; + expectThrows(() { int i = iterable.first; }); + + var stream = g(); + if (stream is Future) return; + await expectAsyncThrows(() async { int i = await stream.first; }); +} + +expectThrows(f) { + bool hasThrown = true; + try { + f(); + hasThrown = false; + } catch(e) {} + if (!hasThrown) { + throw "Expected the function to throw."; + } +} + +expectAsyncThrows(f) async { + bool hasThrown = true; + try { + await f(); + hasThrown = false; + } catch(e) {} + if (!hasThrown) { + throw "Expected the function to throw."; + } +} diff --git a/pkg/front_end/testcases/general/issue53052.dart.strong.expect b/pkg/front_end/testcases/general/issue53052.dart.strong.expect new file mode 100644 index 000000000000..50334072e79f --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.strong.expect @@ -0,0 +1,51 @@ +library; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +static method f() → FutureOr> sync* { + yield("Hello!" as dynamic) as{TypeError,ForDynamic} core::int; +} +static method g() → FutureOr> async* { + yield*("Hello!" as dynamic) as{TypeError,ForDynamic} asy::Stream; +} +static method main() → dynamic async /* futureValueType= dynamic */ { + FutureOr>iterable = self::f(); + if(iterable is asy::Future) + return; + self::expectThrows(() → Null { + core::int i = iterable{core::Iterable}.{core::Iterable::first}{core::int}; + }); + FutureOr>stream = self::g(); + if(stream is asy::Future) + return; + await self::expectAsyncThrows(() → asy::Future async /* futureValueType= Null */ { + core::int i = await stream{asy::Stream}.{asy::Stream::first}{asy::Future}; + }) /* runtimeCheckType= asy::Future */ ; +} +static method expectThrows(dynamic f) → dynamic { + core::bool hasThrown = true; + try { + f{dynamic}.call(); + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} +static method expectAsyncThrows(dynamic f) → dynamic async /* futureValueType= dynamic */ { + core::bool hasThrown = true; + try { + await f{dynamic}.call() /* runtimeCheckType= asy::Future */ ; + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} diff --git a/pkg/front_end/testcases/general/issue53052.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue53052.dart.strong.transformed.expect new file mode 100644 index 000000000000..1eec43e2e0e9 --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.strong.transformed.expect @@ -0,0 +1,57 @@ +library; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +static method f() → FutureOr> sync* { + yield("Hello!" as dynamic) as{TypeError,ForDynamic} core::int; +} +static method g() → FutureOr> async* { + yield*("Hello!" as dynamic) as{TypeError,ForDynamic} asy::Stream; +} +static method main() → dynamic async /* futureValueType= dynamic */ { + FutureOr>iterable = self::f(); + if(iterable is asy::Future) + return; + self::expectThrows(() → Null { + core::int i = iterable{core::Iterable}.{core::Iterable::first}{core::int}; + }); + FutureOr>stream = self::g(); + if(stream is asy::Future) + return; + await self::expectAsyncThrows(() → asy::Future async /* futureValueType= Null */ { + core::int i = await stream{asy::Stream}.{asy::Stream::first}{asy::Future}; + }) /* runtimeCheckType= asy::Future */ ; +} +static method expectThrows(dynamic f) → dynamic { + core::bool hasThrown = true; + try { + f{dynamic}.call(); + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} +static method expectAsyncThrows(dynamic f) → dynamic async /* futureValueType= dynamic */ { + core::bool hasThrown = true; + try { + await f{dynamic}.call() /* runtimeCheckType= asy::Future */ ; + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} + + +Extra constant evaluation status: +Evaluated: AsExpression @ org-dartlang-testcase:///issue53052.dart:8:18 -> StringConstant("Hello!") +Evaluated: AsExpression @ org-dartlang-testcase:///issue53052.dart:12:19 -> StringConstant("Hello!") +Extra constant evaluation: evaluated: 33, effectively constant: 2 diff --git a/pkg/front_end/testcases/general/issue53052.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue53052.dart.textual_outline.expect new file mode 100644 index 000000000000..a717b88ac967 --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.textual_outline.expect @@ -0,0 +1,7 @@ +import 'dart:async'; + +FutureOr> f() sync* {} +FutureOr> g() async* {} +main() async {} +expectThrows(f) {} +expectAsyncThrows(f) async {} diff --git a/pkg/front_end/testcases/general/issue53052.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue53052.dart.textual_outline_modelled.expect new file mode 100644 index 000000000000..3e68bada9039 --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.textual_outline_modelled.expect @@ -0,0 +1,7 @@ +import 'dart:async'; + +FutureOr> f() sync* {} +FutureOr> g() async* {} +expectAsyncThrows(f) async {} +expectThrows(f) {} +main() async {} diff --git a/pkg/front_end/testcases/general/issue53052.dart.weak.expect b/pkg/front_end/testcases/general/issue53052.dart.weak.expect new file mode 100644 index 000000000000..50334072e79f --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.weak.expect @@ -0,0 +1,51 @@ +library; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +static method f() → FutureOr> sync* { + yield("Hello!" as dynamic) as{TypeError,ForDynamic} core::int; +} +static method g() → FutureOr> async* { + yield*("Hello!" as dynamic) as{TypeError,ForDynamic} asy::Stream; +} +static method main() → dynamic async /* futureValueType= dynamic */ { + FutureOr>iterable = self::f(); + if(iterable is asy::Future) + return; + self::expectThrows(() → Null { + core::int i = iterable{core::Iterable}.{core::Iterable::first}{core::int}; + }); + FutureOr>stream = self::g(); + if(stream is asy::Future) + return; + await self::expectAsyncThrows(() → asy::Future async /* futureValueType= Null */ { + core::int i = await stream{asy::Stream}.{asy::Stream::first}{asy::Future}; + }) /* runtimeCheckType= asy::Future */ ; +} +static method expectThrows(dynamic f) → dynamic { + core::bool hasThrown = true; + try { + f{dynamic}.call(); + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} +static method expectAsyncThrows(dynamic f) → dynamic async /* futureValueType= dynamic */ { + core::bool hasThrown = true; + try { + await f{dynamic}.call() /* runtimeCheckType= asy::Future */ ; + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} diff --git a/pkg/front_end/testcases/general/issue53052.dart.weak.modular.expect b/pkg/front_end/testcases/general/issue53052.dart.weak.modular.expect new file mode 100644 index 000000000000..50334072e79f --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.weak.modular.expect @@ -0,0 +1,51 @@ +library; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +static method f() → FutureOr> sync* { + yield("Hello!" as dynamic) as{TypeError,ForDynamic} core::int; +} +static method g() → FutureOr> async* { + yield*("Hello!" as dynamic) as{TypeError,ForDynamic} asy::Stream; +} +static method main() → dynamic async /* futureValueType= dynamic */ { + FutureOr>iterable = self::f(); + if(iterable is asy::Future) + return; + self::expectThrows(() → Null { + core::int i = iterable{core::Iterable}.{core::Iterable::first}{core::int}; + }); + FutureOr>stream = self::g(); + if(stream is asy::Future) + return; + await self::expectAsyncThrows(() → asy::Future async /* futureValueType= Null */ { + core::int i = await stream{asy::Stream}.{asy::Stream::first}{asy::Future}; + }) /* runtimeCheckType= asy::Future */ ; +} +static method expectThrows(dynamic f) → dynamic { + core::bool hasThrown = true; + try { + f{dynamic}.call(); + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} +static method expectAsyncThrows(dynamic f) → dynamic async /* futureValueType= dynamic */ { + core::bool hasThrown = true; + try { + await f{dynamic}.call() /* runtimeCheckType= asy::Future */ ; + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} diff --git a/pkg/front_end/testcases/general/issue53052.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue53052.dart.weak.outline.expect new file mode 100644 index 000000000000..4f912c935a93 --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.weak.outline.expect @@ -0,0 +1,17 @@ +library; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +static method f() → FutureOr> sync* + ; +static method g() → FutureOr> async* + ; +static method main() → dynamic async + ; +static method expectThrows(dynamic f) → dynamic + ; +static method expectAsyncThrows(dynamic f) → dynamic async + ; diff --git a/pkg/front_end/testcases/general/issue53052.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue53052.dart.weak.transformed.expect new file mode 100644 index 000000000000..1eec43e2e0e9 --- /dev/null +++ b/pkg/front_end/testcases/general/issue53052.dart.weak.transformed.expect @@ -0,0 +1,57 @@ +library; +import self as self; +import "dart:core" as core; +import "dart:async" as asy; + +import "dart:async"; + +static method f() → FutureOr> sync* { + yield("Hello!" as dynamic) as{TypeError,ForDynamic} core::int; +} +static method g() → FutureOr> async* { + yield*("Hello!" as dynamic) as{TypeError,ForDynamic} asy::Stream; +} +static method main() → dynamic async /* futureValueType= dynamic */ { + FutureOr>iterable = self::f(); + if(iterable is asy::Future) + return; + self::expectThrows(() → Null { + core::int i = iterable{core::Iterable}.{core::Iterable::first}{core::int}; + }); + FutureOr>stream = self::g(); + if(stream is asy::Future) + return; + await self::expectAsyncThrows(() → asy::Future async /* futureValueType= Null */ { + core::int i = await stream{asy::Stream}.{asy::Stream::first}{asy::Future}; + }) /* runtimeCheckType= asy::Future */ ; +} +static method expectThrows(dynamic f) → dynamic { + core::bool hasThrown = true; + try { + f{dynamic}.call(); + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} +static method expectAsyncThrows(dynamic f) → dynamic async /* futureValueType= dynamic */ { + core::bool hasThrown = true; + try { + await f{dynamic}.call() /* runtimeCheckType= asy::Future */ ; + hasThrown = false; + } + on core::Object catch(final core::Object e) { + } + if(!hasThrown) { + throw "Expected the function to throw."; + } +} + + +Extra constant evaluation status: +Evaluated: AsExpression @ org-dartlang-testcase:///issue53052.dart:8:18 -> StringConstant("Hello!") +Evaluated: AsExpression @ org-dartlang-testcase:///issue53052.dart:12:19 -> StringConstant("Hello!") +Extra constant evaluation: evaluated: 33, effectively constant: 2 diff --git a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.expect b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.expect index ae387dd3454d..102ad3598e89 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.expect @@ -61,11 +61,11 @@ static inline-class-member method ExtensionType2|(core::int it) → self::Extens } static inline-class-member method ExtensionType2|_#new#tearOff(core::int it) → self::ExtensionType2 /* = core::int */ return self::ExtensionType2|(it); -static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { +static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { lowered final self::ExtensionType3 /* = self::ExtensionType3|::T */ #this = it; return #this; } -static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ +static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ return self::ExtensionType3|(it); static inline-class-member method ExtensionType4|(core::int it) → self::ExtensionType4 /* = core::int */ { lowered final self::ExtensionType4 /* = core::int */ #this = it; @@ -121,9 +121,9 @@ static inline-class-member method ExtensionType6|id(core::int it) → self::Exte } static inline-class-member method ExtensionType6|_#id#tearOff(core::int it) → self::ExtensionType6 /* = core::int */ return self::ExtensionType6|id(it); -static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { +static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { lowered final self::ExtensionType7 /* = core::int */ #this = it; return #this; } -static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ return self::ExtensionType7|id(it); diff --git a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.transformed.expect index ae387dd3454d..102ad3598e89 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.strong.transformed.expect @@ -61,11 +61,11 @@ static inline-class-member method ExtensionType2|(core::int it) → self::Extens } static inline-class-member method ExtensionType2|_#new#tearOff(core::int it) → self::ExtensionType2 /* = core::int */ return self::ExtensionType2|(it); -static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { +static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { lowered final self::ExtensionType3 /* = self::ExtensionType3|::T */ #this = it; return #this; } -static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ +static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ return self::ExtensionType3|(it); static inline-class-member method ExtensionType4|(core::int it) → self::ExtensionType4 /* = core::int */ { lowered final self::ExtensionType4 /* = core::int */ #this = it; @@ -121,9 +121,9 @@ static inline-class-member method ExtensionType6|id(core::int it) → self::Exte } static inline-class-member method ExtensionType6|_#id#tearOff(core::int it) → self::ExtensionType6 /* = core::int */ return self::ExtensionType6|id(it); -static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { +static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { lowered final self::ExtensionType7 /* = core::int */ #this = it; return #this; } -static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ return self::ExtensionType7|id(it); diff --git a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.expect b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.expect index ae387dd3454d..102ad3598e89 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.expect @@ -61,11 +61,11 @@ static inline-class-member method ExtensionType2|(core::int it) → self::Extens } static inline-class-member method ExtensionType2|_#new#tearOff(core::int it) → self::ExtensionType2 /* = core::int */ return self::ExtensionType2|(it); -static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { +static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { lowered final self::ExtensionType3 /* = self::ExtensionType3|::T */ #this = it; return #this; } -static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ +static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ return self::ExtensionType3|(it); static inline-class-member method ExtensionType4|(core::int it) → self::ExtensionType4 /* = core::int */ { lowered final self::ExtensionType4 /* = core::int */ #this = it; @@ -121,9 +121,9 @@ static inline-class-member method ExtensionType6|id(core::int it) → self::Exte } static inline-class-member method ExtensionType6|_#id#tearOff(core::int it) → self::ExtensionType6 /* = core::int */ return self::ExtensionType6|id(it); -static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { +static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { lowered final self::ExtensionType7 /* = core::int */ #this = it; return #this; } -static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ return self::ExtensionType7|id(it); diff --git a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.modular.expect b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.modular.expect index ae387dd3454d..102ad3598e89 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.modular.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.modular.expect @@ -61,11 +61,11 @@ static inline-class-member method ExtensionType2|(core::int it) → self::Extens } static inline-class-member method ExtensionType2|_#new#tearOff(core::int it) → self::ExtensionType2 /* = core::int */ return self::ExtensionType2|(it); -static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { +static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { lowered final self::ExtensionType3 /* = self::ExtensionType3|::T */ #this = it; return #this; } -static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ +static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ return self::ExtensionType3|(it); static inline-class-member method ExtensionType4|(core::int it) → self::ExtensionType4 /* = core::int */ { lowered final self::ExtensionType4 /* = core::int */ #this = it; @@ -121,9 +121,9 @@ static inline-class-member method ExtensionType6|id(core::int it) → self::Exte } static inline-class-member method ExtensionType6|_#id#tearOff(core::int it) → self::ExtensionType6 /* = core::int */ return self::ExtensionType6|id(it); -static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { +static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { lowered final self::ExtensionType7 /* = core::int */ #this = it; return #this; } -static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ return self::ExtensionType7|id(it); diff --git a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.outline.expect b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.outline.expect index 10f20f9c5647..6665ffcf64c1 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.outline.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.outline.expect @@ -57,9 +57,9 @@ static inline-class-member method ExtensionType2|(core::int it) → self::Extens ; static inline-class-member method ExtensionType2|_#new#tearOff(core::int it) → self::ExtensionType2 /* = core::int */ return self::ExtensionType2|(it); -static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ +static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ ; -static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ +static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ return self::ExtensionType3|(it); static inline-class-member method ExtensionType4|(core::int it) → self::ExtensionType4 /* = core::int */ ; @@ -107,7 +107,7 @@ static inline-class-member method ExtensionType6|id(core::int it) → self::Exte ; static inline-class-member method ExtensionType6|_#id#tearOff(core::int it) → self::ExtensionType6 /* = core::int */ return self::ExtensionType6|id(it); -static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ ; -static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ return self::ExtensionType7|id(it); diff --git a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.transformed.expect index ae387dd3454d..102ad3598e89 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/extension_type_declarations.dart.weak.transformed.expect @@ -61,11 +61,11 @@ static inline-class-member method ExtensionType2|(core::int it) → self::Extens } static inline-class-member method ExtensionType2|_#new#tearOff(core::int it) → self::ExtensionType2 /* = core::int */ return self::ExtensionType2|(it); -static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { +static inline-class-member method ExtensionType3|(self::ExtensionType3|::T it) → self::ExtensionType3 /* = self::ExtensionType3|::T */ { lowered final self::ExtensionType3 /* = self::ExtensionType3|::T */ #this = it; return #this; } -static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ +static inline-class-member method ExtensionType3|_#new#tearOff(self::ExtensionType3|_#new#tearOff::T it) → self::ExtensionType3 /* = self::ExtensionType3|_#new#tearOff::T */ return self::ExtensionType3|(it); static inline-class-member method ExtensionType4|(core::int it) → self::ExtensionType4 /* = core::int */ { lowered final self::ExtensionType4 /* = core::int */ #this = it; @@ -121,9 +121,9 @@ static inline-class-member method ExtensionType6|id(core::int it) → self::Exte } static inline-class-member method ExtensionType6|_#id#tearOff(core::int it) → self::ExtensionType6 /* = core::int */ return self::ExtensionType6|id(it); -static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { +static inline-class-member method ExtensionType7|id(core::int it) → self::ExtensionType7 /* = core::int */ { lowered final self::ExtensionType7 /* = core::int */ #this = it; return #this; } -static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ +static inline-class-member method ExtensionType7|_#id#tearOff(core::int it) → self::ExtensionType7 /* = core::int */ return self::ExtensionType7|id(it); diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.expect index 59fb6171ae0e..69f35c8f3036 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.expect @@ -25,11 +25,11 @@ extension type V /* = T */ = self::V /* = dynamic constructor • = self::V|; tearoff • = self::V|_#new#tearOff; } -static inline-class-member method V| /* = self::V|::T */ = dynamic>(self::V|::T id) → self::V /* = self::V|::T */ { +static inline-class-member method V| /* = self::V|::T */ = self::V /* = dynamic */>(self::V|::T id) → self::V /* = self::V|::T */ { lowered final self::V /* = self::V|::T */ #this = id; return #this; } -static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = dynamic>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ +static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = self::V /* = dynamic */>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ return self::V|(id); static method test(self::V /* = dynamic */> /* = dynamic */ v) → dynamic { core::List /* = dynamic */> /* = dynamic */> l = /* = dynamic */> /* = dynamic */>[v]; diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.transformed.expect index 9da68d610026..b58314e877b4 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.strong.transformed.expect @@ -25,11 +25,11 @@ extension type V /* = T */ = self::V /* = dynamic constructor • = self::V|; tearoff • = self::V|_#new#tearOff; } -static inline-class-member method V| /* = self::V|::T */ = dynamic>(self::V|::T id) → self::V /* = self::V|::T */ { +static inline-class-member method V| /* = self::V|::T */ = self::V /* = dynamic */>(self::V|::T id) → self::V /* = self::V|::T */ { lowered final self::V /* = self::V|::T */ #this = id; return #this; } -static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = dynamic>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ +static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = self::V /* = dynamic */>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ return self::V|(id); static method test(self::V /* = dynamic */> /* = dynamic */ v) → dynamic { core::List /* = dynamic */> /* = dynamic */> l = core::_GrowableList::_literal1 /* = dynamic */> /* = dynamic */>(v); diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.expect index 59fb6171ae0e..69f35c8f3036 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.expect @@ -25,11 +25,11 @@ extension type V /* = T */ = self::V /* = dynamic constructor • = self::V|; tearoff • = self::V|_#new#tearOff; } -static inline-class-member method V| /* = self::V|::T */ = dynamic>(self::V|::T id) → self::V /* = self::V|::T */ { +static inline-class-member method V| /* = self::V|::T */ = self::V /* = dynamic */>(self::V|::T id) → self::V /* = self::V|::T */ { lowered final self::V /* = self::V|::T */ #this = id; return #this; } -static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = dynamic>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ +static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = self::V /* = dynamic */>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ return self::V|(id); static method test(self::V /* = dynamic */> /* = dynamic */ v) → dynamic { core::List /* = dynamic */> /* = dynamic */> l = /* = dynamic */> /* = dynamic */>[v]; diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.modular.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.modular.expect index 59fb6171ae0e..69f35c8f3036 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.modular.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.modular.expect @@ -25,11 +25,11 @@ extension type V /* = T */ = self::V /* = dynamic constructor • = self::V|; tearoff • = self::V|_#new#tearOff; } -static inline-class-member method V| /* = self::V|::T */ = dynamic>(self::V|::T id) → self::V /* = self::V|::T */ { +static inline-class-member method V| /* = self::V|::T */ = self::V /* = dynamic */>(self::V|::T id) → self::V /* = self::V|::T */ { lowered final self::V /* = self::V|::T */ #this = id; return #this; } -static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = dynamic>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ +static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = self::V /* = dynamic */>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ return self::V|(id); static method test(self::V /* = dynamic */> /* = dynamic */ v) → dynamic { core::List /* = dynamic */> /* = dynamic */> l = /* = dynamic */> /* = dynamic */>[v]; diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.outline.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.outline.expect index d40d9395cc67..3dd72494d624 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.outline.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.outline.expect @@ -16,9 +16,9 @@ extension type V /* = T */ = self::V /* = dynamic constructor • = self::V|; tearoff • = self::V|_#new#tearOff; } -static inline-class-member method V| /* = self::V|::T */ = dynamic>(self::V|::T id) → self::V /* = self::V|::T */ +static inline-class-member method V| /* = self::V|::T */ = self::V /* = dynamic */>(self::V|::T id) → self::V /* = self::V|::T */ ; -static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = dynamic>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ +static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = self::V /* = dynamic */>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ return self::V|(id); static method test(self::V /* = dynamic */> /* = dynamic */ v) → dynamic ; diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.transformed.expect index 9da68d610026..b58314e877b4 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53123.dart.weak.transformed.expect @@ -25,11 +25,11 @@ extension type V /* = T */ = self::V /* = dynamic constructor • = self::V|; tearoff • = self::V|_#new#tearOff; } -static inline-class-member method V| /* = self::V|::T */ = dynamic>(self::V|::T id) → self::V /* = self::V|::T */ { +static inline-class-member method V| /* = self::V|::T */ = self::V /* = dynamic */>(self::V|::T id) → self::V /* = self::V|::T */ { lowered final self::V /* = self::V|::T */ #this = id; return #this; } -static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = dynamic>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ +static inline-class-member method V|_#new#tearOff /* = self::V|_#new#tearOff::T */ = self::V /* = dynamic */>(self::V|_#new#tearOff::T id) → self::V /* = self::V|_#new#tearOff::T */ return self::V|(id); static method test(self::V /* = dynamic */> /* = dynamic */ v) → dynamic { core::List /* = dynamic */> /* = dynamic */> l = core::_GrowableList::_literal1 /* = dynamic */> /* = dynamic */>(v); diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart new file mode 100644 index 000000000000..fb4a56a28c29 --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart @@ -0,0 +1,27 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +extension type V(X1 id) {} + +typedef V Foo>(V v); +typedef IntNumV = V; + +V foo>(T t) => t as V; + +class C> { + Foo f = foo>; +} + +main() { + IntNumV v = IntNumV(42); + expect(42, v.id); + + expect(v, foo(v)); + expect(V(0), C>().f(V(0))); + expect(V(1), C>().f(V(1))); +} + +expect(expected, actual) { + if (expected != actual) throw 'Expected $expected, actual $actual'; +} \ No newline at end of file diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.strong.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.strong.expect new file mode 100644 index 000000000000..bc7e88d4d6f1 --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.strong.expect @@ -0,0 +1,40 @@ +library; +import self as self; +import "dart:core" as core; + +typedef Foo /* = core::num */> = (self::V /* = core::int */) → self::V /* = core::int */; +typedef IntNumV = self::V /* = core::int */; +class C /* = core::num */> extends core::Object { + field (self::V /* = core::int */) → self::V /* = core::int */ f = #C2; + synthetic constructor •() → self::C + : super core::Object::•() + ; +} +extension type V(X1 id) { + constructor • = self::V|; + tearoff • = self::V|_#new#tearOff; +} +static inline-class-member method V|(self::V|::X1 id) → self::V /* = self::V|::X1 */ { + lowered final self::V /* = self::V|::X1 */ #this = id; + return #this; +} +static inline-class-member method V|_#new#tearOff(self::V|_#new#tearOff::X1 id) → self::V /* = self::V|_#new#tearOff::X1 */ + return self::V|(id); +static method foo /* = core::num */>(self::foo::T t) → self::V /* = core::int */ + return t as self::V /* = core::int */; +static method main() → dynamic { + self::V /* = core::int */ v = self::V|(42); + self::expect(42, v as{Unchecked} core::int); + self::expect(v, self::foo /* = core::int */>(v)); + self::expect(self::V|(0), let final self::C /* = core::int */> #t1 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t2 = self::V|(0) in #t1.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t2){(self::V /* = core::int */) → self::V /* = core::int */}); + self::expect(self::V|(1), let final self::C /* = core::int */> #t3 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t4 = self::V|(1) in #t3.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t4){(self::V /* = core::int */) → self::V /* = core::int */}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = static-tearoff self::foo + #C2 = instantiation #C1 /* = core::int */> +} diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.strong.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.strong.transformed.expect new file mode 100644 index 000000000000..bc7e88d4d6f1 --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.strong.transformed.expect @@ -0,0 +1,40 @@ +library; +import self as self; +import "dart:core" as core; + +typedef Foo /* = core::num */> = (self::V /* = core::int */) → self::V /* = core::int */; +typedef IntNumV = self::V /* = core::int */; +class C /* = core::num */> extends core::Object { + field (self::V /* = core::int */) → self::V /* = core::int */ f = #C2; + synthetic constructor •() → self::C + : super core::Object::•() + ; +} +extension type V(X1 id) { + constructor • = self::V|; + tearoff • = self::V|_#new#tearOff; +} +static inline-class-member method V|(self::V|::X1 id) → self::V /* = self::V|::X1 */ { + lowered final self::V /* = self::V|::X1 */ #this = id; + return #this; +} +static inline-class-member method V|_#new#tearOff(self::V|_#new#tearOff::X1 id) → self::V /* = self::V|_#new#tearOff::X1 */ + return self::V|(id); +static method foo /* = core::num */>(self::foo::T t) → self::V /* = core::int */ + return t as self::V /* = core::int */; +static method main() → dynamic { + self::V /* = core::int */ v = self::V|(42); + self::expect(42, v as{Unchecked} core::int); + self::expect(v, self::foo /* = core::int */>(v)); + self::expect(self::V|(0), let final self::C /* = core::int */> #t1 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t2 = self::V|(0) in #t1.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t2){(self::V /* = core::int */) → self::V /* = core::int */}); + self::expect(self::V|(1), let final self::C /* = core::int */> #t3 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t4 = self::V|(1) in #t3.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t4){(self::V /* = core::int */) → self::V /* = core::int */}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = static-tearoff self::foo + #C2 = instantiation #C1 /* = core::int */> +} diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.textual_outline.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.textual_outline.expect new file mode 100644 index 000000000000..bea722fa7952 --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.textual_outline.expect @@ -0,0 +1,9 @@ +extension type V(X1 id) {} +typedef V Foo>(V v); +typedef IntNumV = V; +V foo>(T t) => t as V; +class C> { + Foo f = foo>; +} +main() {} +expect(expected, actual) {} diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.textual_outline_modelled.expect new file mode 100644 index 000000000000..9ba94adf2a53 --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.textual_outline_modelled.expect @@ -0,0 +1,11 @@ +---- unknown chunk starts ---- +extension type V(X1 id) {} +---- unknown chunk ends ---- +V foo>(T t) => t as V; +class C> { + Foo f = foo>; +} +expect(expected, actual) {} +main() {} +typedef IntNumV = V; +typedef V Foo>(V v); diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.expect new file mode 100644 index 000000000000..ece3a33c1a8a --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.expect @@ -0,0 +1,40 @@ +library; +import self as self; +import "dart:core" as core; + +typedef Foo /* = core::num */> = (self::V /* = core::int */) → self::V /* = core::int */; +typedef IntNumV = self::V /* = core::int */; +class C /* = core::num */> extends core::Object { + field (self::V /* = core::int */) → self::V /* = core::int */ f = #C2; + synthetic constructor •() → self::C + : super core::Object::•() + ; +} +extension type V(X1 id) { + constructor • = self::V|; + tearoff • = self::V|_#new#tearOff; +} +static inline-class-member method V|(self::V|::X1 id) → self::V /* = self::V|::X1 */ { + lowered final self::V /* = self::V|::X1 */ #this = id; + return #this; +} +static inline-class-member method V|_#new#tearOff(self::V|_#new#tearOff::X1 id) → self::V /* = self::V|_#new#tearOff::X1 */ + return self::V|(id); +static method foo /* = core::num */>(self::foo::T t) → self::V /* = core::int */ + return t as self::V /* = core::int */; +static method main() → dynamic { + self::V /* = core::int */ v = self::V|(42); + self::expect(42, v as{Unchecked} core::int); + self::expect(v, self::foo /* = core::int */>(v)); + self::expect(self::V|(0), let final self::C /* = core::int */> #t1 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t2 = self::V|(0) in #t1.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t2){(self::V /* = core::int */) → self::V /* = core::int */}); + self::expect(self::V|(1), let final self::C /* = core::int */> #t3 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t4 = self::V|(1) in #t3.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t4){(self::V /* = core::int */) → self::V /* = core::int */}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = static-tearoff self::foo + #C2 = instantiation #C1 * /* = core::int* */> +} diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.modular.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.modular.expect new file mode 100644 index 000000000000..ece3a33c1a8a --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.modular.expect @@ -0,0 +1,40 @@ +library; +import self as self; +import "dart:core" as core; + +typedef Foo /* = core::num */> = (self::V /* = core::int */) → self::V /* = core::int */; +typedef IntNumV = self::V /* = core::int */; +class C /* = core::num */> extends core::Object { + field (self::V /* = core::int */) → self::V /* = core::int */ f = #C2; + synthetic constructor •() → self::C + : super core::Object::•() + ; +} +extension type V(X1 id) { + constructor • = self::V|; + tearoff • = self::V|_#new#tearOff; +} +static inline-class-member method V|(self::V|::X1 id) → self::V /* = self::V|::X1 */ { + lowered final self::V /* = self::V|::X1 */ #this = id; + return #this; +} +static inline-class-member method V|_#new#tearOff(self::V|_#new#tearOff::X1 id) → self::V /* = self::V|_#new#tearOff::X1 */ + return self::V|(id); +static method foo /* = core::num */>(self::foo::T t) → self::V /* = core::int */ + return t as self::V /* = core::int */; +static method main() → dynamic { + self::V /* = core::int */ v = self::V|(42); + self::expect(42, v as{Unchecked} core::int); + self::expect(v, self::foo /* = core::int */>(v)); + self::expect(self::V|(0), let final self::C /* = core::int */> #t1 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t2 = self::V|(0) in #t1.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t2){(self::V /* = core::int */) → self::V /* = core::int */}); + self::expect(self::V|(1), let final self::C /* = core::int */> #t3 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t4 = self::V|(1) in #t3.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t4){(self::V /* = core::int */) → self::V /* = core::int */}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = static-tearoff self::foo + #C2 = instantiation #C1 * /* = core::int* */> +} diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.outline.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.outline.expect new file mode 100644 index 000000000000..89e896e098d8 --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.outline.expect @@ -0,0 +1,25 @@ +library; +import self as self; +import "dart:core" as core; + +typedef Foo /* = core::num */> = (self::V /* = core::int */) → self::V /* = core::int */; +typedef IntNumV = self::V /* = core::int */; +class C /* = core::num */> extends core::Object { + field (self::V /* = core::int */) → self::V /* = core::int */ f; + synthetic constructor •() → self::C + ; +} +extension type V(X1 id) { + constructor • = self::V|; + tearoff • = self::V|_#new#tearOff; +} +static inline-class-member method V|(self::V|::X1 id) → self::V /* = self::V|::X1 */ + ; +static inline-class-member method V|_#new#tearOff(self::V|_#new#tearOff::X1 id) → self::V /* = self::V|_#new#tearOff::X1 */ + return self::V|(id); +static method foo /* = core::num */>(self::foo::T t) → self::V /* = core::int */ + ; +static method main() → dynamic + ; +static method expect(dynamic expected, dynamic actual) → dynamic + ; diff --git a/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.transformed.expect new file mode 100644 index 000000000000..ece3a33c1a8a --- /dev/null +++ b/pkg/front_end/testcases/inline_class/extension_types/issue53155.dart.weak.transformed.expect @@ -0,0 +1,40 @@ +library; +import self as self; +import "dart:core" as core; + +typedef Foo /* = core::num */> = (self::V /* = core::int */) → self::V /* = core::int */; +typedef IntNumV = self::V /* = core::int */; +class C /* = core::num */> extends core::Object { + field (self::V /* = core::int */) → self::V /* = core::int */ f = #C2; + synthetic constructor •() → self::C + : super core::Object::•() + ; +} +extension type V(X1 id) { + constructor • = self::V|; + tearoff • = self::V|_#new#tearOff; +} +static inline-class-member method V|(self::V|::X1 id) → self::V /* = self::V|::X1 */ { + lowered final self::V /* = self::V|::X1 */ #this = id; + return #this; +} +static inline-class-member method V|_#new#tearOff(self::V|_#new#tearOff::X1 id) → self::V /* = self::V|_#new#tearOff::X1 */ + return self::V|(id); +static method foo /* = core::num */>(self::foo::T t) → self::V /* = core::int */ + return t as self::V /* = core::int */; +static method main() → dynamic { + self::V /* = core::int */ v = self::V|(42); + self::expect(42, v as{Unchecked} core::int); + self::expect(v, self::foo /* = core::int */>(v)); + self::expect(self::V|(0), let final self::C /* = core::int */> #t1 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t2 = self::V|(0) in #t1.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t2){(self::V /* = core::int */) → self::V /* = core::int */}); + self::expect(self::V|(1), let final self::C /* = core::int */> #t3 = new self::C::• /* = core::int */>() in let final self::V /* = core::int */ #t4 = self::V|(1) in #t3.{self::C::f}{(self::V /* = core::int */) → self::V /* = core::int */}(#t4){(self::V /* = core::int */) → self::V /* = core::int */}); +} +static method expect(dynamic expected, dynamic actual) → dynamic { + if(!(expected =={core::Object::==}{(core::Object) → core::bool} actual)) + throw "Expected ${expected}, actual ${actual}"; +} + +constants { + #C1 = static-tearoff self::foo + #C2 = instantiation #C1 * /* = core::int* */> +} diff --git a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.expect b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.expect index a9197a16677d..52f60c90375e 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.expect @@ -166,41 +166,41 @@ static inline-class-member method Hc|(self::G } static inline-class-member method Hc|_#new#tearOff(self::G? /* = self::Hc|_#new#tearOff::T? */ it) → self::Hc /* = self::Hc|_#new#tearOff::T? */ return self::Hc|(it); -static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { +static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { lowered final self::I /* = self::I|::T */ #this = it; return #this; } -static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ +static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ return self::I|(it); -static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { +static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { lowered final self::Ja /* = self::Ja|::T */ #this = it; return #this; } -static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ +static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ return self::Ja|(it); -static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { +static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { lowered final self::Jc /* = self::Jc|::T? */ #this = it; return #this; } -static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ +static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ return self::Jc|(it); -static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { +static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { lowered final self::K /* = self::K|::T? */ #this = it; return #this; } -static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ +static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ return self::K|(it); -static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { +static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { lowered final self::La /* = self::La|::T? */ #this = it; return #this; } -static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ +static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ return self::La|(it); -static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { +static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { lowered final self::Lc /* = self::Lc|::T? */ #this = it; return #this; } -static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ +static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ return self::Lc|(it); static method testA(Never n) → dynamic { self::A /* = core::int */ a1 = n; diff --git a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.transformed.expect index a9197a16677d..52f60c90375e 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.strong.transformed.expect @@ -166,41 +166,41 @@ static inline-class-member method Hc|(self::G } static inline-class-member method Hc|_#new#tearOff(self::G? /* = self::Hc|_#new#tearOff::T? */ it) → self::Hc /* = self::Hc|_#new#tearOff::T? */ return self::Hc|(it); -static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { +static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { lowered final self::I /* = self::I|::T */ #this = it; return #this; } -static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ +static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ return self::I|(it); -static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { +static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { lowered final self::Ja /* = self::Ja|::T */ #this = it; return #this; } -static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ +static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ return self::Ja|(it); -static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { +static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { lowered final self::Jc /* = self::Jc|::T? */ #this = it; return #this; } -static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ +static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ return self::Jc|(it); -static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { +static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { lowered final self::K /* = self::K|::T? */ #this = it; return #this; } -static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ +static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ return self::K|(it); -static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { +static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { lowered final self::La /* = self::La|::T? */ #this = it; return #this; } -static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ +static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ return self::La|(it); -static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { +static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { lowered final self::Lc /* = self::Lc|::T? */ #this = it; return #this; } -static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ +static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ return self::Lc|(it); static method testA(Never n) → dynamic { self::A /* = core::int */ a1 = n; diff --git a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.expect b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.expect index aaaed2e3dbe3..41ad8a2ad241 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.expect @@ -167,41 +167,41 @@ static inline-class-member method Hc|(self::G } static inline-class-member method Hc|_#new#tearOff(self::G? /* = self::Hc|_#new#tearOff::T? */ it) → self::Hc /* = self::Hc|_#new#tearOff::T? */ return self::Hc|(it); -static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { +static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { lowered final self::I /* = self::I|::T */ #this = it; return #this; } -static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ +static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ return self::I|(it); -static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { +static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { lowered final self::Ja /* = self::Ja|::T */ #this = it; return #this; } -static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ +static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ return self::Ja|(it); -static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { +static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { lowered final self::Jc /* = self::Jc|::T? */ #this = it; return #this; } -static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ +static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ return self::Jc|(it); -static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { +static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { lowered final self::K /* = self::K|::T? */ #this = it; return #this; } -static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ +static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ return self::K|(it); -static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { +static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { lowered final self::La /* = self::La|::T? */ #this = it; return #this; } -static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ +static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ return self::La|(it); -static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { +static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { lowered final self::Lc /* = self::Lc|::T? */ #this = it; return #this; } -static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ +static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ return self::Lc|(it); static method testA(Never n) → dynamic { self::A /* = core::int */ a1 = let final Never #t1 = n in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); diff --git a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.modular.expect b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.modular.expect index aaaed2e3dbe3..41ad8a2ad241 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.modular.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.modular.expect @@ -167,41 +167,41 @@ static inline-class-member method Hc|(self::G } static inline-class-member method Hc|_#new#tearOff(self::G? /* = self::Hc|_#new#tearOff::T? */ it) → self::Hc /* = self::Hc|_#new#tearOff::T? */ return self::Hc|(it); -static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { +static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { lowered final self::I /* = self::I|::T */ #this = it; return #this; } -static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ +static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ return self::I|(it); -static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { +static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { lowered final self::Ja /* = self::Ja|::T */ #this = it; return #this; } -static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ +static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ return self::Ja|(it); -static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { +static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { lowered final self::Jc /* = self::Jc|::T? */ #this = it; return #this; } -static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ +static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ return self::Jc|(it); -static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { +static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { lowered final self::K /* = self::K|::T? */ #this = it; return #this; } -static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ +static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ return self::K|(it); -static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { +static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { lowered final self::La /* = self::La|::T? */ #this = it; return #this; } -static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ +static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ return self::La|(it); -static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { +static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { lowered final self::Lc /* = self::Lc|::T? */ #this = it; return #this; } -static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ +static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ return self::Lc|(it); static method testA(Never n) → dynamic { self::A /* = core::int */ a1 = let final Never #t1 = n in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); diff --git a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.outline.expect b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.outline.expect index 48f81d51635c..08de1ca7ac9e 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.outline.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.outline.expect @@ -138,29 +138,29 @@ static inline-class-member method Hc|(self::G ; static inline-class-member method Hc|_#new#tearOff(self::G? /* = self::Hc|_#new#tearOff::T? */ it) → self::Hc /* = self::Hc|_#new#tearOff::T? */ return self::Hc|(it); -static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ +static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ ; -static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ +static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ return self::I|(it); -static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ +static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ ; -static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ +static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ return self::Ja|(it); -static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ +static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ ; -static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ +static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ return self::Jc|(it); -static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ +static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ ; -static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ +static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ return self::K|(it); -static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ +static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ ; -static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ +static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ return self::La|(it); -static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ +static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ ; -static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ +static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ return self::Lc|(it); static method testA(Never n) → dynamic ; diff --git a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.transformed.expect b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.transformed.expect index aaaed2e3dbe3..41ad8a2ad241 100644 --- a/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/inline_class/extension_types/representation_type.dart.weak.transformed.expect @@ -167,41 +167,41 @@ static inline-class-member method Hc|(self::G } static inline-class-member method Hc|_#new#tearOff(self::G? /* = self::Hc|_#new#tearOff::T? */ it) → self::Hc /* = self::Hc|_#new#tearOff::T? */ return self::Hc|(it); -static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { +static inline-class-member method I|(self::I|::T it) → self::I /* = self::I|::T */ { lowered final self::I /* = self::I|::T */ #this = it; return #this; } -static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ +static inline-class-member method I|_#new#tearOff(self::I|_#new#tearOff::T it) → self::I /* = self::I|_#new#tearOff::T */ return self::I|(it); -static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { +static inline-class-member method Ja|(self::I /* = self::Ja|::T */ it) → self::Ja /* = self::Ja|::T */ { lowered final self::Ja /* = self::Ja|::T */ #this = it; return #this; } -static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ +static inline-class-member method Ja|_#new#tearOff(self::I /* = self::Ja|_#new#tearOff::T */ it) → self::Ja /* = self::Ja|_#new#tearOff::T */ return self::Ja|(it); -static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { +static inline-class-member method Jc|(self::I? /* = self::Jc|::T? */ it) → self::Jc /* = self::Jc|::T? */ { lowered final self::Jc /* = self::Jc|::T? */ #this = it; return #this; } -static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ +static inline-class-member method Jc|_#new#tearOff(self::I? /* = self::Jc|_#new#tearOff::T? */ it) → self::Jc /* = self::Jc|_#new#tearOff::T? */ return self::Jc|(it); -static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { +static inline-class-member method K|(self::K|::T? it) → self::K /* = self::K|::T? */ { lowered final self::K /* = self::K|::T? */ #this = it; return #this; } -static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ +static inline-class-member method K|_#new#tearOff(self::K|_#new#tearOff::T? it) → self::K /* = self::K|_#new#tearOff::T? */ return self::K|(it); -static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { +static inline-class-member method La|(self::K /* = self::La|::T? */ it) → self::La /* = self::La|::T? */ { lowered final self::La /* = self::La|::T? */ #this = it; return #this; } -static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ +static inline-class-member method La|_#new#tearOff(self::K /* = self::La|_#new#tearOff::T? */ it) → self::La /* = self::La|_#new#tearOff::T? */ return self::La|(it); -static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { +static inline-class-member method Lc|(self::K? /* = self::Lc|::T? */ it) → self::Lc /* = self::Lc|::T? */ { lowered final self::Lc /* = self::Lc|::T? */ #this = it; return #this; } -static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ +static inline-class-member method Lc|_#new#tearOff(self::K? /* = self::Lc|_#new#tearOff::T? */ it) → self::Lc /* = self::Lc|_#new#tearOff::T? */ return self::Lc|(it); static method testA(Never n) → dynamic { self::A /* = core::int */ a1 = let final Never #t1 = n in throw new _in::ReachabilityError::•("`null` encountered as the result from expression with type `Never`."); diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart index 4b1585feeea7..77e22534c969 100644 --- a/pkg/kernel/lib/type_environment.dart +++ b/pkg/kernel/lib/type_environment.dart @@ -162,6 +162,38 @@ abstract class TypeEnvironment extends Types { } } + /// Computes the underlying type of a union type + /// + /// Dart doesn't have generalized union types, but two specific ones: the + /// FutureOr type, which can be seen as a union of T and Future, and the + /// nullable type T?, which can be seen as the union of T and Null. In both + /// cases the union type can be seen as application of the corresponding type + /// constructor, FutureOr or ?, to the underlying type T. [getUnionFreeType] + /// computes the underlying type of the given union type, accounting for + /// potential nesting of the union types. + /// + /// The following are examples of the union-free types computed on for the + /// given types. + /// + /// getUnionFreeType(int) = int + /// getUnionFreeType(int?) = int + /// getUnionFreeType(FutureOr) = int + /// getUnionFreeType(FutureOr?) = int + DartType getUnionFreeType(DartType type, + {required bool isNonNullableByDefault}) { + if (isNullableTypeConstructorApplication(type)) { + return getUnionFreeType( + computeTypeWithoutNullabilityMarker(type, + isNonNullableByDefault: isNonNullableByDefault), + isNonNullableByDefault: isNonNullableByDefault); + } else if (type is FutureOrType) { + return getUnionFreeType(type.typeArgument, + isNonNullableByDefault: isNonNullableByDefault); + } else { + return type; + } + } + /// True if [member] is a binary operator whose return type is defined by /// the both operand types. bool isSpecialCasedBinaryOperator(Procedure member, diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart index 5ab639740f27..706e669aaf8c 100644 --- a/pkg/kernel/lib/verifier.dart +++ b/pkg/kernel/lib/verifier.dart @@ -1262,6 +1262,12 @@ class VerifyingVisitor extends RecursiveResultVisitor { @override void visitTypeParameter(TypeParameter node) { + if (identical(node.bound, TypeParameter.unsetBoundSentinel)) { + problem(node, "Unset bound on type parameter $node"); + } + if (identical(node.defaultType, TypeParameter.unsetDefaultTypeSentinel)) { + problem(node, "Unset default type on type parameter $node"); + } if (inConstant) { // Don't expect the type parameters to have the current parent as parent. node.visitChildren(this); diff --git a/pkg/kernel/test/verify_test.dart b/pkg/kernel/test/verify_test.dart index 5d371aa656bb..84843f7434a2 100644 --- a/pkg/kernel/test/verify_test.dart +++ b/pkg/kernel/test/verify_test.dart @@ -601,7 +601,8 @@ void main() { positiveTest( 'Valid typedef Foo = C', (TestHarness test) { - var param = new TypeParameter('T', test.otherLegacyRawType); + var param = new TypeParameter( + 'T', test.otherLegacyRawType, test.otherLegacyRawType); var foo = new Typedef( 'Foo', new InterfaceType(test.otherClass, Nullability.legacy, @@ -615,7 +616,8 @@ void main() { positiveTest( 'Valid typedef Foo> = C', (TestHarness test) { - var param = new TypeParameter('T', test.otherLegacyRawType); + var param = new TypeParameter( + 'T', test.otherLegacyRawType, test.otherLegacyRawType); param.bound = new InterfaceType(test.otherClass, Nullability.legacy, [new TypeParameterType(param, Nullability.legacy)]); var foo = new Typedef( @@ -638,6 +640,7 @@ void main() { var barParam = new TypeParameter('T', null); barParam.bound = new TypedefType(foo, Nullability.legacy, [new TypeParameterType(barParam, Nullability.legacy)]); + barParam.defaultType = const DynamicType(); var bar = new Typedef( 'Bar', new InterfaceType(test.otherClass, Nullability.legacy, @@ -659,6 +662,7 @@ void main() { var barParam = new TypeParameter('T', null); barParam.bound = new TypedefType(foo, Nullability.legacy, [new TypeParameterType(barParam, Nullability.legacy)]); + barParam.defaultType = const DynamicType(); var bar = new Typedef( 'Bar', new InterfaceType(test.otherClass, Nullability.legacy, @@ -667,6 +671,7 @@ void main() { fileUri: dummyUri); fooParam.bound = new TypedefType(bar, Nullability.legacy, [new TypeParameterType(fooParam, Nullability.legacy)]); + fooParam.defaultType = const DynamicType(); test.enclosingLibrary.addTypedef(foo); test.enclosingLibrary.addTypedef(bar); return foo; @@ -686,6 +691,7 @@ void main() { ..fileOffset = dummyFileOffset; param.bound = new TypedefType(foo, Nullability.legacy, [const DynamicType()]); + param.defaultType = const DynamicType(); test.addNode(foo); return foo; }, @@ -727,6 +733,34 @@ void main() { (Node? foo) => "${errorPrefix}Dangling reference to '$foo', parent is: 'null'", ); + negative1Test( + 'Unset bound typedef Foo = dynamic', + (TestHarness test) { + var param = new TypeParameter('T', null); + var foo = new Typedef('Foo', const DynamicType(), + typeParameters: [param], fileUri: dummyUri) + ..fileOffset = dummyFileOffset; + param.defaultType = const DynamicType(); + test.addNode(foo); + return foo; + }, + (Node? foo) => "${errorPrefix}" + "Unset bound on type parameter TypeParameter(T)", + ); + negative1Test( + 'Unset default type typedef Foo = dynamic', + (TestHarness test) { + var param = new TypeParameter('T', null); + var foo = new Typedef('Foo', const DynamicType(), + typeParameters: [param], fileUri: dummyUri) + ..fileOffset = dummyFileOffset; + param.bound = const DynamicType(); + test.addNode(foo); + return foo; + }, + (Node? foo) => "${errorPrefix}" + "Unset default type on type parameter TypeParameter(T)", + ); negative1Test( 'Non-static top-level field', (TestHarness test) { diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc index 1aee656f6bae..ed95b7241471 100644 --- a/runtime/vm/compiler/frontend/kernel_to_il.cc +++ b/runtime/vm/compiler/frontend/kernel_to_il.cc @@ -4141,7 +4141,7 @@ Fragment FlowGraphBuilder::AllocateHandle() { compiler::target::Thread::OffsetFromThread(&kAllocateHandleRuntimeEntry)); code += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr); // function address. - code += CCall(/*num_arguments=*/1); + code += CCall(/*num_arguments=*/1, kUnboxedIntPtr); return code; } diff --git a/tools/VERSION b/tools/VERSION index 3eadeb1407b3..073efa26b842 100644 --- a/tools/VERSION +++ b/tools/VERSION @@ -27,5 +27,5 @@ CHANNEL dev MAJOR 3 MINOR 2 PATCH 0 -PRERELEASE 77 +PRERELEASE 78 PRERELEASE_PATCH 0