diff --git a/pkg/front_end/lib/src/fasta/builder/record_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/record_type_builder.dart index bdc5ddcdea3..91c447ecec5 100644 --- a/pkg/front_end/lib/src/fasta/builder/record_type_builder.dart +++ b/pkg/front_end/lib/src/fasta/builder/record_type_builder.dart @@ -149,6 +149,9 @@ abstract class RecordTypeBuilderImpl extends RecordTypeBuilder { positionalEntries.add(type); String? fieldName = field.name; if (fieldName != null) { + if (library is SourceLibraryBuilder && field.isWildcard) { + continue; + } if (fieldName.startsWith("_")) { library.addProblem(messageRecordFieldsCantBePrivate, field.charOffset, fieldName.length, fileUri); @@ -380,7 +383,10 @@ class RecordTypeFieldBuilder { final int charOffset; - RecordTypeFieldBuilder(this.metadata, this.type, this.name, this.charOffset); + final bool isWildcard; + + RecordTypeFieldBuilder(this.metadata, this.type, this.name, this.charOffset, + {this.isWildcard = false}); RecordTypeFieldBuilder clone( List newTypes, @@ -392,7 +398,8 @@ class RecordTypeFieldBuilder { metadata, type.clone(newTypes, contextLibrary, contextDeclaration), name, - charOffset); + charOffset, + isWildcard: isWildcard); } @override diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart index 15696f30997..4fc61287c2b 100644 --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart @@ -5213,13 +5213,17 @@ class BodyBuilder extends StackListenerImpl Object? type = pop(); // TODO(johnniwinther): How should we handle annotations? pop(NullValues.Metadata); // Annotations. + + String? fieldName = name is Identifier ? name.name : null; push(new RecordTypeFieldBuilder( [], type is ParserRecovery ? new InvalidTypeBuilderImpl(uri, type.charOffset) : type as TypeBuilder, - name is Identifier ? name.name : null, - name is Identifier ? name.nameOffset : TreeNode.noOffset)); + fieldName, + name is Identifier ? name.nameOffset : TreeNode.noOffset, + isWildcard: + libraryFeatures.wildcardVariables.isEnabled && fieldName == '_')); } @override diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart index f5871521a9a..0f33731244e 100644 --- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart +++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart @@ -3172,13 +3172,17 @@ class OutlineBuilder extends StackListenerImpl { Object? type = pop(); List? metadata = pop(NullValues.Metadata) as List?; + + String? fieldName = identifier is Identifier ? identifier.name : null; push(new RecordTypeFieldBuilder( metadata, type is ParserRecovery ? new InvalidTypeBuilderImpl(uri, type.charOffset) : type as TypeBuilder, - identifier is Identifier ? identifier.name : null, - identifier is Identifier ? identifier.nameOffset : -1)); + fieldName, + identifier is Identifier ? identifier.nameOffset : -1, + isWildcard: + libraryFeatures.wildcardVariables.isEnabled && fieldName == '_')); } @override diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart b/pkg/front_end/testcases/wildcard_variables/record_type.dart new file mode 100644 index 00000000000..11c162a494e --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart @@ -0,0 +1,12 @@ +// Copyright (c) 2024, 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. + +typedef R = (String _, String _); +(int _, int _) record = (1, 2); + +main() { + (int _, int _) localRecord = (1, 2); + print(localRecord.$1); + print(record.$1); +} diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.expect b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.expect new file mode 100644 index 00000000000..319bad06904 --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.expect @@ -0,0 +1,11 @@ +library; +import self as self; +import "dart:core" as core; + +typedef R = (core::String, core::String); +static field (core::int, core::int) record = (1, 2); +static method main() → dynamic { + (core::int, core::int) localRecord = (1, 2); + core::print(localRecord.$1{core::int}); + core::print(self::record.$1{core::int}); +} diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.modular.expect b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.modular.expect new file mode 100644 index 00000000000..319bad06904 --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.modular.expect @@ -0,0 +1,11 @@ +library; +import self as self; +import "dart:core" as core; + +typedef R = (core::String, core::String); +static field (core::int, core::int) record = (1, 2); +static method main() → dynamic { + (core::int, core::int) localRecord = (1, 2); + core::print(localRecord.$1{core::int}); + core::print(self::record.$1{core::int}); +} diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.outline.expect b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.outline.expect new file mode 100644 index 00000000000..d21550a0f42 --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.outline.expect @@ -0,0 +1,8 @@ +library; +import self as self; +import "dart:core" as core; + +typedef R = (core::String, core::String); +static field (core::int, core::int) record; +static method main() → dynamic + ; diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.transformed.expect b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.transformed.expect new file mode 100644 index 00000000000..172d79ceb99 --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart.strong.transformed.expect @@ -0,0 +1,17 @@ +library; +import self as self; +import "dart:core" as core; + +typedef R = (core::String, core::String); +static field (core::int, core::int) record = (1, 2); +static method main() → dynamic { + (core::int, core::int) localRecord = (1, 2); + core::print(localRecord.$1{core::int}); + core::print(self::record.$1{core::int}); +} + + +Extra constant evaluation status: +Evaluated: RecordLiteral @ org-dartlang-testcase:///record_type.dart:9:32 -> RecordConstant(const (1, 2)) +Evaluated: RecordLiteral @ org-dartlang-testcase:///record_type.dart:6:25 -> RecordConstant(const (1, 2)) +Extra constant evaluation: evaluated: 8, effectively constant: 2 diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart.textual_outline.expect b/pkg/front_end/testcases/wildcard_variables/record_type.dart.textual_outline.expect new file mode 100644 index 00000000000..2dac6a6fce3 --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart.textual_outline.expect @@ -0,0 +1,5 @@ +typedef R = (String _, String _); + +(int _, int _) record = (1, 2); + +main() {} diff --git a/pkg/front_end/testcases/wildcard_variables/record_type.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/wildcard_variables/record_type.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..7a28a04cc1d --- /dev/null +++ b/pkg/front_end/testcases/wildcard_variables/record_type.dart.textual_outline_modelled.expect @@ -0,0 +1,5 @@ +(int _, int _) record = (1, 2); + +main() {} + +typedef R = (String _, String _);