diff --git a/pkg/front_end/lib/src/fragment/declaration.dart b/pkg/front_end/lib/src/fragment/declaration.dart index ed803adc9fa..b61b5ec06a2 100644 --- a/pkg/front_end/lib/src/fragment/declaration.dart +++ b/pkg/front_end/lib/src/fragment/declaration.dart @@ -22,7 +22,10 @@ abstract class DeclarationFragmentImpl implements DeclarationFragment { final LookupScope enclosingScope; final LookupScope typeParameterScope; + + @override final DeclarationBuilderScope bodyScope; + final List _fragments = []; @override diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart index 147a0e29be9..7a32896e76c 100644 --- a/pkg/front_end/lib/src/fragment/fragment.dart +++ b/pkg/front_end/lib/src/fragment/fragment.dart @@ -146,4 +146,7 @@ abstract interface class DeclarationFragment { /// Type parameters declared on this declaration. List? get typeParameters; + + /// Returns the body scope for this declaration. + LookupScope get bodyScope; } diff --git a/pkg/front_end/lib/src/source/fragment_factory_impl.dart b/pkg/front_end/lib/src/source/fragment_factory_impl.dart index f145bf8af7f..72ec67f8160 100644 --- a/pkg/front_end/lib/src/source/fragment_factory_impl.dart +++ b/pkg/front_end/lib/src/source/fragment_factory_impl.dart @@ -1405,6 +1405,10 @@ class FragmentFactoryImpl implements FragmentFactory { DeclarationFragmentImpl enclosingDeclaration = _declarationFragments.current; + // The name space is, while initially empty, created to support the lowering + // of extension (type) constructors which clone the extension (type) type + // parameters into the nominal parameter name space of the primary + // constructor. NominalParameterNameSpace nominalParameterNameSpace = new NominalParameterNameSpace(); _nominalParameterNameSpaces.push(nominalParameterNameSpace); @@ -1412,7 +1416,15 @@ class FragmentFactoryImpl implements FragmentFactory { new TypeScope( TypeScopeKind.memberTypeParameters, new NominalParameterScope( - _typeScopes.current.lookupScope, + libraryFeatures.primaryConstructors.isEnabled + // Contrary to most other declarations, the type parameter scope + // of a primary constructor is _not_ the current type scope, which + // is the type parameter scope of the enclosing declaration, but + // instead the body scope of the enclosing declaration. + ? enclosingDeclaration.bodyScope + // Prior to the primary constructors feature, the enclosing scope + // was the current type scope. + : _typeScopes.current.lookupScope, nominalParameterNameSpace, ), _typeScopes.current, diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt index a90c5242732..010ccbfcdf5 100644 --- a/pkg/front_end/test/spell_checking_list_code.txt +++ b/pkg/front_end/test/spell_checking_list_code.txt @@ -364,6 +364,7 @@ containment contextually continuations contra +contrary contribute conveniently convention diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart new file mode 100644 index 00000000000..47049666c98 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart @@ -0,0 +1,57 @@ +// Copyright (c) 2026, 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. + +class C1 { + T b; + final T c; + T d; + T e; + T f; + Type g = T; + + C1(T a, this.b, this.c) : d = a, e = b, f = c, g = T { + print(T); + } +} + +class C2(T a, var T b, final T c) { + T d = a; + T e = b; + T f = c; + Type g = T; + + this { + print(T); + } +} + +enum E1 { + a(0, 1); + + final T b; + final T c; + final T d; + final Type f; + + const E1(T a, this.b) : c = a, d = b, f = T; +} + +enum E2(T a, final T b) { + a(0, 1); + final T d = a; + final T e = b; + final Type f = T; +} + +extension type ET1(T a) { + ET1.other(this.a) { + print(T); + } +} + +extension type ET2(T a) { + this { + print(T); + } +} diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.expect new file mode 100644 index 00000000000..e8a97b41759 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.expect @@ -0,0 +1,109 @@ +library; +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + covariant-by-class field self::C1::T% b; + final field self::C1::T% c; + covariant-by-class field self::C1::T% d; + covariant-by-class field self::C1::T% e; + covariant-by-class field self::C1::T% f; + field core::Type g = self::C1::T%; + constructor •(self::C1::T% a, self::C1::T% b, self::C1::T% c) → self::C1 + : self::C1::b = b, self::C1::c = c, self::C1::d = a, self::C1::e = b, self::C1::f = c, self::C1::g = self::C1::T%, super core::Object::•() { + core::print(self::C1::T%); + } +} +class C2 extends core::Object { + covariant-by-class field self::C2::T% b; + final field self::C2::T% c; + covariant-by-class field self::C2::T% d; + covariant-by-class field self::C2::T% e; + covariant-by-class field self::C2::T% f; + field core::Type g; + constructor •(self::C2::T% a, self::C2::T% b, final self::C2::T% c) → self::C2 + : self::C2::d = a, self::C2::e = b, self::C2::f = c, self::C2::g = self::C2::T%, self::C2::b = b, self::C2::c = c, super core::Object::•() { + core::print(self::C2::T%); + } +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = #C5; + final field self::E1::T% b; + final field self::E1::T% c; + final field self::E1::T% d; + final field core::Type f; + static const field core::List> values = #C6; + const constructor •(core::int #index, core::String #name, self::E1::T% a, self::E1::T% b) → self::E1 + : self::E1::b = b, self::E1::c = a, self::E1::d = b, self::E1::f = self::E1::T%, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + final field self::E2::T% b; + enum-element static const field self::E2 a = #C7; + final field self::E2::T% d; + final field self::E2::T% e; + final field core::Type f; + static const field core::List> values = #C8; + const constructor •(core::int #index, core::String #name, self::E2::T% a, final self::E2::T% b) → self::E2 + : self::E2::d = a, self::E2::e = b, self::E2::f = self::E2::T%, self::E2::b = b, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; + constructor other = self::ET1|constructor#other; + constructor tearoff other = self::ET1|constructor#_#other#tearOff; +} +extension type ET2(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static extension-type-member method ET1|constructor#(self::ET1|constructor#::T% a) → self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ { + lowered final self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ #this = a; + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#new#tearOff(self::ET1|constructor#_#new#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#new#tearOff::T%, declared=! */ + return self::ET1|constructor#(a); +static extension-type-member method ET1|constructor#other(self::ET1|constructor#other::T% a) → self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ { + lowered final self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ #this = a; + { + core::print(self::ET1|constructor#other::T%); + } + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#other#tearOff(self::ET1|constructor#_#other#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#other#tearOff::T%, declared=! */ + return self::ET1|constructor#other(a); +static extension-type-member method ET2|constructor#(self::ET2|constructor#::T% a) → self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ { + lowered final self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ #this = a; + { + core::print(self::ET2|constructor#::T%); + } + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(self::ET2|constructor#_#new#tearOff::T% a) → self::ET2% /* erasure=self::ET2|constructor#_#new#tearOff::T%, declared=! */ + return self::ET2|constructor#(a); + +constants { + #C1 = 1 + #C2 = 0 + #C3 = TypeLiteralConstant(core::int) + #C4 = "a" + #C5 = self::E1 {b:#C1, c:#C2, d:#C1, f:#C3, index:#C2, _name:#C4} + #C6 = >[#C5] + #C7 = self::E2 {b:#C1, d:#C2, e:#C1, f:#C3, index:#C2, _name:#C4} + #C8 = >[#C7] +} + + +Constructor coverage from constants: +org-dartlang-testcase:///generic_primary_constructor.dart: +- E1. (from org-dartlang-testcase:///generic_primary_constructor.dart:37:9) +- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- E2. (from org-dartlang-testcase:///generic_primary_constructor.dart:40:11) diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.modular.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.modular.expect new file mode 100644 index 00000000000..e8a97b41759 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.modular.expect @@ -0,0 +1,109 @@ +library; +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + covariant-by-class field self::C1::T% b; + final field self::C1::T% c; + covariant-by-class field self::C1::T% d; + covariant-by-class field self::C1::T% e; + covariant-by-class field self::C1::T% f; + field core::Type g = self::C1::T%; + constructor •(self::C1::T% a, self::C1::T% b, self::C1::T% c) → self::C1 + : self::C1::b = b, self::C1::c = c, self::C1::d = a, self::C1::e = b, self::C1::f = c, self::C1::g = self::C1::T%, super core::Object::•() { + core::print(self::C1::T%); + } +} +class C2 extends core::Object { + covariant-by-class field self::C2::T% b; + final field self::C2::T% c; + covariant-by-class field self::C2::T% d; + covariant-by-class field self::C2::T% e; + covariant-by-class field self::C2::T% f; + field core::Type g; + constructor •(self::C2::T% a, self::C2::T% b, final self::C2::T% c) → self::C2 + : self::C2::d = a, self::C2::e = b, self::C2::f = c, self::C2::g = self::C2::T%, self::C2::b = b, self::C2::c = c, super core::Object::•() { + core::print(self::C2::T%); + } +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = #C5; + final field self::E1::T% b; + final field self::E1::T% c; + final field self::E1::T% d; + final field core::Type f; + static const field core::List> values = #C6; + const constructor •(core::int #index, core::String #name, self::E1::T% a, self::E1::T% b) → self::E1 + : self::E1::b = b, self::E1::c = a, self::E1::d = b, self::E1::f = self::E1::T%, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + final field self::E2::T% b; + enum-element static const field self::E2 a = #C7; + final field self::E2::T% d; + final field self::E2::T% e; + final field core::Type f; + static const field core::List> values = #C8; + const constructor •(core::int #index, core::String #name, self::E2::T% a, final self::E2::T% b) → self::E2 + : self::E2::d = a, self::E2::e = b, self::E2::f = self::E2::T%, self::E2::b = b, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; + constructor other = self::ET1|constructor#other; + constructor tearoff other = self::ET1|constructor#_#other#tearOff; +} +extension type ET2(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static extension-type-member method ET1|constructor#(self::ET1|constructor#::T% a) → self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ { + lowered final self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ #this = a; + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#new#tearOff(self::ET1|constructor#_#new#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#new#tearOff::T%, declared=! */ + return self::ET1|constructor#(a); +static extension-type-member method ET1|constructor#other(self::ET1|constructor#other::T% a) → self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ { + lowered final self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ #this = a; + { + core::print(self::ET1|constructor#other::T%); + } + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#other#tearOff(self::ET1|constructor#_#other#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#other#tearOff::T%, declared=! */ + return self::ET1|constructor#other(a); +static extension-type-member method ET2|constructor#(self::ET2|constructor#::T% a) → self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ { + lowered final self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ #this = a; + { + core::print(self::ET2|constructor#::T%); + } + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(self::ET2|constructor#_#new#tearOff::T% a) → self::ET2% /* erasure=self::ET2|constructor#_#new#tearOff::T%, declared=! */ + return self::ET2|constructor#(a); + +constants { + #C1 = 1 + #C2 = 0 + #C3 = TypeLiteralConstant(core::int) + #C4 = "a" + #C5 = self::E1 {b:#C1, c:#C2, d:#C1, f:#C3, index:#C2, _name:#C4} + #C6 = >[#C5] + #C7 = self::E2 {b:#C1, d:#C2, e:#C1, f:#C3, index:#C2, _name:#C4} + #C8 = >[#C7] +} + + +Constructor coverage from constants: +org-dartlang-testcase:///generic_primary_constructor.dart: +- E1. (from org-dartlang-testcase:///generic_primary_constructor.dart:37:9) +- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- E2. (from org-dartlang-testcase:///generic_primary_constructor.dart:40:11) diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect new file mode 100644 index 00000000000..33e1d22abd6 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.outline.expect @@ -0,0 +1,82 @@ +library; +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + covariant-by-class field self::C1::T% b; + final field self::C1::T% c; + covariant-by-class field self::C1::T% d; + covariant-by-class field self::C1::T% e; + covariant-by-class field self::C1::T% f; + field core::Type g; + constructor •(self::C1::T% a, self::C1::T% b, self::C1::T% c) → self::C1 + ; +} +class C2 extends core::Object { + covariant-by-class field self::C2::T% b; + final field self::C2::T% c; + covariant-by-class field self::C2::T% d; + covariant-by-class field self::C2::T% e; + covariant-by-class field self::C2::T% f; + field core::Type g; + constructor •(self::C2::T% a, self::C2::T% b, final self::C2::T% c) → self::C2 + ; +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = const self::E1::•(0, "a", 0, 1); + final field self::E1::T% b; + final field self::E1::T% c; + final field self::E1::T% d; + final field core::Type f; + static const field core::List> values = const >[self::E1::a]; + const constructor •(core::int #index, core::String #name, self::E1::T% a, self::E1::T% b) → self::E1 + : self::E1::b = b, self::E1::c = a, self::E1::d = b, self::E1::f = self::E1::T%, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + final field self::E2::T% b; + enum-element static const field self::E2 a = const self::E2::•(0, "a", 0, 1); + final field self::E2::T% d; + final field self::E2::T% e; + final field core::Type f; + static const field core::List> values = const >[self::E2::a]; + const constructor •(core::int #index, core::String #name, self::E2::T% a, final self::E2::T% b) → self::E2 + : self::E2::b = b, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; + constructor other = self::ET1|constructor#other; + constructor tearoff other = self::ET1|constructor#_#other#tearOff; +} +extension type ET2(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static extension-type-member method ET1|constructor#(self::ET1|constructor#::T% a) → self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ + ; +static extension-type-member synthetic method ET1|constructor#_#new#tearOff(self::ET1|constructor#_#new#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#new#tearOff::T%, declared=! */ + return self::ET1|constructor#(a); +static extension-type-member method ET1|constructor#other(self::ET1|constructor#other::T% a) → self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ + ; +static extension-type-member synthetic method ET1|constructor#_#other#tearOff(self::ET1|constructor#_#other#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#other#tearOff::T%, declared=! */ + return self::ET1|constructor#other(a); +static extension-type-member method ET2|constructor#(self::ET2|constructor#::T% a) → self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ + ; +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(self::ET2|constructor#_#new#tearOff::T% a) → self::ET2% /* erasure=self::ET2|constructor#_#new#tearOff::T%, declared=! */ + return self::ET2|constructor#(a); + + +Extra constant evaluation status: +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///generic_primary_constructor.dart:30:3 -> InstanceConstant(const E1{E1.b: 1, E1.c: 0, E1.d: 1, E1.f: int, _Enum.index: 0, _Enum._name: "a"}) +Evaluated: ListLiteral @ org-dartlang-testcase:///generic_primary_constructor.dart:29:6 -> ListConstant(const >[const E1{E1.b: 1, E1.c: 0, E1.d: 1, E1.f: int, _Enum.index: 0, _Enum._name: "a"}]) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///generic_primary_constructor.dart:41:3 -> InstanceConstant(const E2{E2.b: 1, E2.d: null, E2.e: null, E2.f: null, _Enum.index: 0, _Enum._name: "a"}) +Evaluated: ListLiteral @ org-dartlang-testcase:///generic_primary_constructor.dart:40:6 -> ListConstant(const >[const E2{E2.b: 1, E2.d: null, E2.e: null, E2.f: null, _Enum.index: 0, _Enum._name: "a"}]) +Extra constant evaluation: evaluated: 25, effectively constant: 4 diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.transformed.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.transformed.expect new file mode 100644 index 00000000000..e8a97b41759 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.strong.transformed.expect @@ -0,0 +1,109 @@ +library; +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + covariant-by-class field self::C1::T% b; + final field self::C1::T% c; + covariant-by-class field self::C1::T% d; + covariant-by-class field self::C1::T% e; + covariant-by-class field self::C1::T% f; + field core::Type g = self::C1::T%; + constructor •(self::C1::T% a, self::C1::T% b, self::C1::T% c) → self::C1 + : self::C1::b = b, self::C1::c = c, self::C1::d = a, self::C1::e = b, self::C1::f = c, self::C1::g = self::C1::T%, super core::Object::•() { + core::print(self::C1::T%); + } +} +class C2 extends core::Object { + covariant-by-class field self::C2::T% b; + final field self::C2::T% c; + covariant-by-class field self::C2::T% d; + covariant-by-class field self::C2::T% e; + covariant-by-class field self::C2::T% f; + field core::Type g; + constructor •(self::C2::T% a, self::C2::T% b, final self::C2::T% c) → self::C2 + : self::C2::d = a, self::C2::e = b, self::C2::f = c, self::C2::g = self::C2::T%, self::C2::b = b, self::C2::c = c, super core::Object::•() { + core::print(self::C2::T%); + } +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = #C5; + final field self::E1::T% b; + final field self::E1::T% c; + final field self::E1::T% d; + final field core::Type f; + static const field core::List> values = #C6; + const constructor •(core::int #index, core::String #name, self::E1::T% a, self::E1::T% b) → self::E1 + : self::E1::b = b, self::E1::c = a, self::E1::d = b, self::E1::f = self::E1::T%, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + final field self::E2::T% b; + enum-element static const field self::E2 a = #C7; + final field self::E2::T% d; + final field self::E2::T% e; + final field core::Type f; + static const field core::List> values = #C8; + const constructor •(core::int #index, core::String #name, self::E2::T% a, final self::E2::T% b) → self::E2 + : self::E2::d = a, self::E2::e = b, self::E2::f = self::E2::T%, self::E2::b = b, super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; + constructor other = self::ET1|constructor#other; + constructor tearoff other = self::ET1|constructor#_#other#tearOff; +} +extension type ET2(T% a) { + abstract extension-type-member representation-field get a() → T%; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static extension-type-member method ET1|constructor#(self::ET1|constructor#::T% a) → self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ { + lowered final self::ET1% /* erasure=self::ET1|constructor#::T%, declared=! */ #this = a; + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#new#tearOff(self::ET1|constructor#_#new#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#new#tearOff::T%, declared=! */ + return self::ET1|constructor#(a); +static extension-type-member method ET1|constructor#other(self::ET1|constructor#other::T% a) → self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ { + lowered final self::ET1% /* erasure=self::ET1|constructor#other::T%, declared=! */ #this = a; + { + core::print(self::ET1|constructor#other::T%); + } + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#other#tearOff(self::ET1|constructor#_#other#tearOff::T% a) → self::ET1% /* erasure=self::ET1|constructor#_#other#tearOff::T%, declared=! */ + return self::ET1|constructor#other(a); +static extension-type-member method ET2|constructor#(self::ET2|constructor#::T% a) → self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ { + lowered final self::ET2% /* erasure=self::ET2|constructor#::T%, declared=! */ #this = a; + { + core::print(self::ET2|constructor#::T%); + } + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(self::ET2|constructor#_#new#tearOff::T% a) → self::ET2% /* erasure=self::ET2|constructor#_#new#tearOff::T%, declared=! */ + return self::ET2|constructor#(a); + +constants { + #C1 = 1 + #C2 = 0 + #C3 = TypeLiteralConstant(core::int) + #C4 = "a" + #C5 = self::E1 {b:#C1, c:#C2, d:#C1, f:#C3, index:#C2, _name:#C4} + #C6 = >[#C5] + #C7 = self::E2 {b:#C1, d:#C2, e:#C1, f:#C3, index:#C2, _name:#C4} + #C8 = >[#C7] +} + + +Constructor coverage from constants: +org-dartlang-testcase:///generic_primary_constructor.dart: +- E1. (from org-dartlang-testcase:///generic_primary_constructor.dart:37:9) +- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- E2. (from org-dartlang-testcase:///generic_primary_constructor.dart:40:11) diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.textual_outline.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.textual_outline.expect new file mode 100644 index 00000000000..95636f37a40 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.textual_outline.expect @@ -0,0 +1,29 @@ +class C1 { + T b; + final T c; + T d; + T e; + T f; + Type g = T; + C1(T a, this.b, this.c) : d = a, e = b, f = c, g = T {} +} + +class C2(T a, var T b, final T c) { + T d = a; + T e = b; + T f = c; + Type g = T; + this {} +} + +enum E1 { a(0, 1); final T b; final T c; final T d; final Type f; const E1(T a, this.b) : c = a, d = b, f = T; } + +enum E2(T a, final T b) { a(0, 1); final T d = a; final T e = b; final Type f = T; } + +extension type ET1(T a) { + ET1.other(this.a) {} +} + +extension type ET2(T a) { + this {} +} diff --git a/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..a345b78699b --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/generic_primary_constructor.dart.textual_outline_modelled.expect @@ -0,0 +1,29 @@ +class C1 { + C1(T a, this.b, this.c) : d = a, e = b, f = c, g = T {} + T b; + T d; + T e; + T f; + Type g = T; + final T c; +} + +class C2(T a, var T b, final T c) { + T d = a; + T e = b; + T f = c; + Type g = T; + this {} +} + +enum E1 { a(0, 1); final T b; final T c; final T d; final Type f; const E1(T a, this.b) : c = a, d = b, f = T; } + +enum E2(T a, final T b) { a(0, 1); final T d = a; final T e = b; final Type f = T; } + +extension type ET1(T a) { + ET1.other(this.a) {} +} + +extension type ET2(T a) { + this {} +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart new file mode 100644 index 00000000000..2a6c7ee1704 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2026, 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. + +class C1([@m int x = m]) { + static const int m = 42; +} + +class C2(int x) { // Error + static const String int = 'not a type'; +} + +enum E1([@a int x = m]) { + a(0); + static const int m = 42; +} + +enum E2(int x) { // Error + a(0); + static const String int = 'not a type'; +} + +extension type ET1([@m int x = m]) { + static const int m = 42; +} + +extension type ET2(int x) { // Error + static const String int = 'not a type'; +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.expect new file mode 100644 index 00000000000..aec5ec2e32a --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.expect @@ -0,0 +1,96 @@ +library; +// +// Problems in library: +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:9:10: Error: 'int' isn't a type. +// class C2(int x) { // Error +// ^^^ +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:18:9: Error: 'int' isn't a type. +// enum E2(int x) { // Error +// ^^^ +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:27:20: Error: 'int' isn't a type. +// extension type ET2(int x) { // Error +// ^^^ +// +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + static const field core::int m = #C1; + constructor •([@#C1 core::int x = #C1]) → self::C1 + : super core::Object::•() + ; +} +class C2 extends core::Object { + static const field core::String int = #C2; + constructor •(core::int x) → self::C2 + : super core::Object::•() + ; +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = #C5; + static const field core::int m = #C1; + static const field core::List values = #C6; + const constructor •(core::int #index, core::String #name, [@#C5 core::int x = #C1]) → self::E1 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E2 a = #C7; + static const field core::String int = #C2; + static const field core::List values = #C8; + const constructor •(core::int #index, core::String #name, core::int x) → self::E2 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field m = self::ET1|m; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; +} +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::int ET1|m = #C1; +static const field core::String ET2|int = #C2; +static extension-type-member method ET1|constructor#([@#C1 core::int x = #C1]) → self::ET1% /* erasure=core::int, declared=! */ { + lowered final self::ET1% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#new#tearOff([core::int x = #C1]) → self::ET1% /* erasure=core::int, declared=! */ + return self::ET1|constructor#(x); +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ { + lowered final self::ET2% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + +constants { + #C1 = 42 + #C2 = "not a type" + #C3 = 0 + #C4 = "a" + #C5 = self::E1 {index:#C3, _name:#C4} + #C6 = [#C5] + #C7 = self::E2 {index:#C3, _name:#C4} + #C8 = [#C7] +} + + +Constructor coverage from constants: +org-dartlang-testcase:///parameter_scope.dart: +- E1. (from org-dartlang-testcase:///parameter_scope.dart:13:8) +- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- E2. (from org-dartlang-testcase:///parameter_scope.dart:18:8) diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.modular.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.modular.expect new file mode 100644 index 00000000000..aec5ec2e32a --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.modular.expect @@ -0,0 +1,96 @@ +library; +// +// Problems in library: +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:9:10: Error: 'int' isn't a type. +// class C2(int x) { // Error +// ^^^ +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:18:9: Error: 'int' isn't a type. +// enum E2(int x) { // Error +// ^^^ +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:27:20: Error: 'int' isn't a type. +// extension type ET2(int x) { // Error +// ^^^ +// +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + static const field core::int m = #C1; + constructor •([@#C1 core::int x = #C1]) → self::C1 + : super core::Object::•() + ; +} +class C2 extends core::Object { + static const field core::String int = #C2; + constructor •(core::int x) → self::C2 + : super core::Object::•() + ; +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = #C5; + static const field core::int m = #C1; + static const field core::List values = #C6; + const constructor •(core::int #index, core::String #name, [@#C5 core::int x = #C1]) → self::E1 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E2 a = #C7; + static const field core::String int = #C2; + static const field core::List values = #C8; + const constructor •(core::int #index, core::String #name, core::int x) → self::E2 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field m = self::ET1|m; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; +} +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::int ET1|m = #C1; +static const field core::String ET2|int = #C2; +static extension-type-member method ET1|constructor#([@#C1 core::int x = #C1]) → self::ET1% /* erasure=core::int, declared=! */ { + lowered final self::ET1% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#new#tearOff([core::int x = #C1]) → self::ET1% /* erasure=core::int, declared=! */ + return self::ET1|constructor#(x); +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ { + lowered final self::ET2% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + +constants { + #C1 = 42 + #C2 = "not a type" + #C3 = 0 + #C4 = "a" + #C5 = self::E1 {index:#C3, _name:#C4} + #C6 = [#C5] + #C7 = self::E2 {index:#C3, _name:#C4} + #C8 = [#C7] +} + + +Constructor coverage from constants: +org-dartlang-testcase:///parameter_scope.dart: +- E1. (from org-dartlang-testcase:///parameter_scope.dart:13:8) +- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- E2. (from org-dartlang-testcase:///parameter_scope.dart:18:8) diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.outline.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.outline.expect new file mode 100644 index 00000000000..88ab7046ab8 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.outline.expect @@ -0,0 +1,67 @@ +library; +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + static const field core::int m = 42; + constructor •([core::int x = self::C1::m]) → self::C1 + ; +} +class C2 extends core::Object { + static const field core::String int = "not a type"; + constructor •(core::int x) → self::C2 + ; +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = const self::E1::•(0, "a", 0); + static const field core::int m = 42; + static const field core::List values = const [self::E1::a]; + const constructor •(core::int #index, core::String #name, [core::int x = self::E1::m]) → self::E1 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E2 a = const self::E2::•(0, "a", 0); + static const field core::String int = "not a type"; + static const field core::List values = const [self::E2::a]; + const constructor •(core::int #index, core::String #name, core::int x) → self::E2 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field m = self::ET1|m; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; +} +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::int ET1|m = 42; +static const field core::String ET2|int = "not a type"; +static extension-type-member method ET1|constructor#([core::int x = self::ET1|m]) → self::ET1% /* erasure=core::int, declared=! */ + ; +static extension-type-member synthetic method ET1|constructor#_#new#tearOff([has-declared-initializer core::int x]) → self::ET1% /* erasure=core::int, declared=! */ + return self::ET1|constructor#(x); +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + ; +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + + +Extra constant evaluation status: +Evaluated: StaticGet @ org-dartlang-testcase:///parameter_scope.dart:5:22 -> IntConstant(42) +Evaluated: StaticGet @ org-dartlang-testcase:///parameter_scope.dart:13:21 -> IntConstant(42) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///parameter_scope.dart:14:3 -> InstanceConstant(const E1{_Enum.index: 0, _Enum._name: "a"}) +Evaluated: ListLiteral @ org-dartlang-testcase:///parameter_scope.dart:13:6 -> ListConstant(const [const E1{_Enum.index: 0, _Enum._name: "a"}]) +Evaluated: ConstructorInvocation @ org-dartlang-testcase:///parameter_scope.dart:19:3 -> InstanceConstant(const E2{_Enum.index: 0, _Enum._name: "a"}) +Evaluated: ListLiteral @ org-dartlang-testcase:///parameter_scope.dart:18:6 -> ListConstant(const [const E2{_Enum.index: 0, _Enum._name: "a"}]) +Evaluated: StaticGet @ org-dartlang-testcase:///parameter_scope.dart:23:32 -> IntConstant(42) +Extra constant evaluation: evaluated: 21, effectively constant: 7 diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.transformed.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.transformed.expect new file mode 100644 index 00000000000..aec5ec2e32a --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.strong.transformed.expect @@ -0,0 +1,96 @@ +library; +// +// Problems in library: +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:9:10: Error: 'int' isn't a type. +// class C2(int x) { // Error +// ^^^ +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:18:9: Error: 'int' isn't a type. +// enum E2(int x) { // Error +// ^^^ +// +// pkg/front_end/testcases/primary_constructors/parameter_scope.dart:27:20: Error: 'int' isn't a type. +// extension type ET2(int x) { // Error +// ^^^ +// +import self as self; +import "dart:core" as core; + +class C1 extends core::Object { + static const field core::int m = #C1; + constructor •([@#C1 core::int x = #C1]) → self::C1 + : super core::Object::•() + ; +} +class C2 extends core::Object { + static const field core::String int = #C2; + constructor •(core::int x) → self::C2 + : super core::Object::•() + ; +} +class E1 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E1 a = #C5; + static const field core::int m = #C1; + static const field core::List values = #C6; + const constructor •(core::int #index, core::String #name, [@#C5 core::int x = #C1]) → self::E1 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E1.${this.{core::_Enum::_name}{core::String}}"; +} +class E2 extends core::_Enum /*isEnum*/ { + enum-element static const field self::E2 a = #C7; + static const field core::String int = #C2; + static const field core::List values = #C8; + const constructor •(core::int #index, core::String #name, core::int x) → self::E2 + : super core::_Enum::•(#index, #name) + ; + method core::_enumToString() → core::String + return "E2.${this.{core::_Enum::_name}{core::String}}"; +} +extension type ET1(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field m = self::ET1|m; + constructor • = self::ET1|constructor#; + constructor tearoff • = self::ET1|constructor#_#new#tearOff; +} +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::int ET1|m = #C1; +static const field core::String ET2|int = #C2; +static extension-type-member method ET1|constructor#([@#C1 core::int x = #C1]) → self::ET1% /* erasure=core::int, declared=! */ { + lowered final self::ET1% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET1|constructor#_#new#tearOff([core::int x = #C1]) → self::ET1% /* erasure=core::int, declared=! */ + return self::ET1|constructor#(x); +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ { + lowered final self::ET2% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + +constants { + #C1 = 42 + #C2 = "not a type" + #C3 = 0 + #C4 = "a" + #C5 = self::E1 {index:#C3, _name:#C4} + #C6 = [#C5] + #C7 = self::E2 {index:#C3, _name:#C4} + #C8 = [#C7] +} + + +Constructor coverage from constants: +org-dartlang-testcase:///parameter_scope.dart: +- E1. (from org-dartlang-testcase:///parameter_scope.dart:13:8) +- _Enum. (from org-dartlang-sdk:///sdk/lib/core/enum.dart) +- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart) +- E2. (from org-dartlang-testcase:///parameter_scope.dart:18:8) diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.textual_outline.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.textual_outline.expect new file mode 100644 index 00000000000..44728357dae --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.textual_outline.expect @@ -0,0 +1,19 @@ +class C1([@m int x = m]) { + static const int m = 42; +} + +class C2(int x) { + static const String int = 'not a type'; +} + +enum E1([@a int x = m]) { a(0); static const int m = 42; } + +enum E2(int x) { a(0); static const String int = 'not a type'; } + +extension type ET1([@m int x = m]) { + static const int m = 42; +} + +extension type ET2(int x) { + static const String int = 'not a type'; +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..44728357dae --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope.dart.textual_outline_modelled.expect @@ -0,0 +1,19 @@ +class C1([@m int x = m]) { + static const int m = 42; +} + +class C2(int x) { + static const String int = 'not a type'; +} + +enum E1([@a int x = m]) { a(0); static const int m = 42; } + +enum E2(int x) { a(0); static const String int = 'not a type'; } + +extension type ET1([@m int x = m]) { + static const int m = 42; +} + +extension type ET2(int x) { + static const String int = 'not a type'; +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart new file mode 100644 index 00000000000..830bd56c3b8 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart @@ -0,0 +1,9 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// @dart=3.10 + +extension type ET2(int x) /* Ok */ { + static const String int = 'not a type'; +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.expect new file mode 100644 index 00000000000..01c326b1d55 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.expect @@ -0,0 +1,21 @@ +library; +import self as self; +import "dart:core" as core; + +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::String ET2|int = #C1; +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ { + lowered final self::ET2% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + +constants { + #C1 = "not a type" +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.modular.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.modular.expect new file mode 100644 index 00000000000..01c326b1d55 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.modular.expect @@ -0,0 +1,21 @@ +library; +import self as self; +import "dart:core" as core; + +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::String ET2|int = #C1; +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ { + lowered final self::ET2% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + +constants { + #C1 = "not a type" +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.outline.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.outline.expect new file mode 100644 index 00000000000..4354604cfc0 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.outline.expect @@ -0,0 +1,15 @@ +library; +import self as self; +import "dart:core" as core; + +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::String ET2|int = "not a type"; +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + ; +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.transformed.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.transformed.expect new file mode 100644 index 00000000000..01c326b1d55 --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.strong.transformed.expect @@ -0,0 +1,21 @@ +library; +import self as self; +import "dart:core" as core; + +extension type ET2(core::int x) { + abstract extension-type-member representation-field get x() → core::int; + static field int = self::ET2|int; + constructor • = self::ET2|constructor#; + constructor tearoff • = self::ET2|constructor#_#new#tearOff; +} +static const field core::String ET2|int = #C1; +static extension-type-member method ET2|constructor#(core::int x) → self::ET2% /* erasure=core::int, declared=! */ { + lowered final self::ET2% /* erasure=core::int, declared=! */ #this = x; + return #this; +} +static extension-type-member synthetic method ET2|constructor#_#new#tearOff(core::int x) → self::ET2% /* erasure=core::int, declared=! */ + return self::ET2|constructor#(x); + +constants { + #C1 = "not a type" +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.textual_outline.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.textual_outline.expect new file mode 100644 index 00000000000..ec34091cf2e --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.textual_outline.expect @@ -0,0 +1,5 @@ +// @dart = 3.10 + +extension type ET2(int x) { + static const String int = 'not a type'; +} diff --git a/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..ec34091cf2e --- /dev/null +++ b/pkg/front_end/testcases/primary_constructors/parameter_scope_pre_feature.dart.textual_outline_modelled.expect @@ -0,0 +1,5 @@ +// @dart = 3.10 + +extension type ET2(int x) { + static const String int = 'not a type'; +} diff --git a/tests/language/primary_constructors/header/parameter_scope_error_test.dart b/tests/language/primary_constructors/header/parameter_scope_error_test.dart new file mode 100644 index 00000000000..f72aafc308a --- /dev/null +++ b/tests/language/primary_constructors/header/parameter_scope_error_test.dart @@ -0,0 +1,33 @@ +// Copyright (c) 2026, 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. + +// Formal parameter types of primary constructor are resolved within the body +// scope of the enclosing declaration. + +// SharedOptions=--enable-experiment=primary-constructors + +class C(int x) { +// ^ +// [analyzer] unspecified +// [cfe] 'int' isn't a type. + + static const String int = 'not a type'; +} + +enum E(int x) { +// ^ +// [cfe] 'int' isn't a type. +// [analyzer] unspecified + a(0); + + static const String int = 'not a type'; +} + +extension type ET(int x) { +// ^ +// [analyzer] unspecified +// [cfe] 'int' isn't a type. + + static const String int = 'not a type'; +} diff --git a/tests/language/primary_constructors/header/parameter_scope_pre_feature_test.dart b/tests/language/primary_constructors/header/parameter_scope_pre_feature_test.dart new file mode 100644 index 00000000000..d95f1c8d9b5 --- /dev/null +++ b/tests/language/primary_constructors/header/parameter_scope_pre_feature_test.dart @@ -0,0 +1,20 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// @dart=3.10 + +// Prior to the primary-constructors feature, formal parameter types of +// primary constructor were not resolved within the body scope of the +// enclosing declaration. + +// SharedOptions=--enable-experiment=primary-constructors + +extension type ET(int x) { + static const String int = 'not a type'; +} + +main() { + print(ET(0)); + print(ET.int); +}