Skip to content

Commit 8e07d49

Browse files
johnniwintherCommit Queue
authored and
Commit Queue
committed
[cfe] Support generic inline class constructors
Change-Id: Ibd12b14e1e8a1811734b4773c842e72a7fcb300c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/277684 Commit-Queue: Johnni Winther <[email protected]> Reviewed-by: Chloe Stefantsova <[email protected]>
1 parent 2083db9 commit 8e07d49

24 files changed

+453
-158
lines changed

pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ library fasta.formal_parameter_builder;
77
import 'package:_fe_analyzer_shared/src/parser/formal_parameter_kind.dart'
88
show FormalParameterKind, FormalParameterKindExtension;
99
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
10+
import 'package:front_end/src/fasta/source/constructor_declaration.dart';
1011
import 'package:kernel/ast.dart'
1112
show DartType, DynamicType, Expression, NullLiteral, VariableDeclaration;
1213
import 'package:kernel/class_hierarchy.dart';
@@ -221,10 +222,14 @@ class FormalParameterBuilder extends ModifierBuilderImpl
221222
}
222223

223224
void finalizeInitializingFormal(
224-
DeclarationBuilder declarationBuilder, ClassHierarchyBase hierarchy) {
225+
DeclarationBuilder declarationBuilder,
226+
ConstructorDeclaration constructorDeclaration,
227+
ClassHierarchyBase hierarchy) {
225228
Builder? fieldBuilder = declarationBuilder.lookupLocalMember(name);
226229
if (fieldBuilder is SourceFieldBuilder) {
227-
type.registerInferredType(fieldBuilder.inferType(hierarchy));
230+
DartType fieldType = fieldBuilder.inferType(hierarchy);
231+
fieldType = constructorDeclaration.substituteFieldType(fieldType);
232+
type.registerInferredType(fieldType);
228233
} else {
229234
type.registerInferredType(const DynamicType());
230235
}

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,14 +1887,14 @@ class BodyBuilder extends StackListenerImpl
18871887
return arguments;
18881888
}
18891889

1890-
void finishConstructor(ConstructorDeclaration builder,
1890+
void finishConstructor(ConstructorDeclaration constructorDeclaration,
18911891
AsyncMarker asyncModifier, Statement? body,
18921892
{required List<Object /* Expression | NamedExpression */ >?
18931893
superParametersAsArguments}) {
18941894
/// Quotes below are from [Dart Programming Language Specification, 4th
18951895
/// Edition](
18961896
/// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
1897-
assert(builder == this.member);
1897+
assert(constructorDeclaration == this.member);
18981898
assert(() {
18991899
if (superParametersAsArguments == null) {
19001900
return true;
@@ -1933,9 +1933,9 @@ class BodyBuilder extends StackListenerImpl
19331933
"Expected 'superParametersAsArguments' "
19341934
"to be sorted by occurrence in file.");
19351935

1936-
Member member = builder.member;
1937-
FunctionNode function = builder.function;
1938-
List<FormalParameterBuilder>? formals = builder.formals;
1936+
Member member = constructorDeclaration.member;
1937+
FunctionNode function = constructorDeclaration.function;
1938+
List<FormalParameterBuilder>? formals = constructorDeclaration.formals;
19391939
if (formals != null) {
19401940
for (int i = 0; i < formals.length; i++) {
19411941
FormalParameterBuilder parameter = formals[i];
@@ -1992,7 +1992,7 @@ class BodyBuilder extends StackListenerImpl
19921992
if (initializers.last is SuperInitializer) {
19931993
SuperInitializer superInitializer =
19941994
initializers.last as SuperInitializer;
1995-
if (builder.classDeclaration.isEnum) {
1995+
if (constructorDeclaration.classDeclaration.isEnum) {
19961996
initializers[initializers.length - 1] = buildInvalidInitializer(
19971997
buildProblem(fasta.messageEnumConstructorSuperInitializer,
19981998
superInitializer.fileOffset, noLength))
@@ -2054,19 +2054,19 @@ class BodyBuilder extends StackListenerImpl
20542054
List<InitializerInferenceResult> inferenceResults =
20552055
new List<InitializerInferenceResult>.generate(
20562056
initializers.length,
2057-
(index) =>
2058-
typeInferrer.inferInitializer(this, initializers[index]),
2057+
(index) => typeInferrer.inferInitializer(
2058+
this, constructorDeclaration, initializers[index]),
20592059
growable: false);
20602060

2061-
if (!builder.isExternal) {
2061+
if (!constructorDeclaration.isExternal) {
20622062
for (int i = 0; i < initializers.length; i++) {
2063-
builder.addInitializer(initializers[i], this,
2063+
constructorDeclaration.addInitializer(initializers[i], this,
20642064
inferenceResult: inferenceResults[i]);
20652065
}
20662066
}
20672067
}
20682068

2069-
List<Initializer> builtInitializers = builder.initializers;
2069+
List<Initializer> builtInitializers = constructorDeclaration.initializers;
20702070
if (asyncModifier != AsyncMarker.Sync) {
20712071
builtInitializers.add(buildInvalidInitializer(buildProblem(
20722072
fasta.messageConstructorNotSync, body!.fileOffset, noLength)));
@@ -2110,29 +2110,29 @@ class BodyBuilder extends StackListenerImpl
21102110

21112111
if (superTarget == null ||
21122112
checkArgumentsForFunction(superTarget.function, arguments,
2113-
builder.charOffset, const <TypeParameter>[]) !=
2113+
constructorDeclaration.charOffset, const <TypeParameter>[]) !=
21142114
null) {
21152115
String superclass =
21162116
sourceClassBuilder!.supertypeBuilder!.fullNameForErrors;
2117-
int length = builder.name.length;
2117+
int length = constructorDeclaration.name.length;
21182118
if (length == 0) {
21192119
length = sourceClassBuilder!.cls.name.length;
21202120
}
21212121
initializer = buildInvalidInitializer(
21222122
buildProblem(
21232123
fasta.templateSuperclassHasNoDefaultConstructor
21242124
.withArguments(superclass),
2125-
builder.charOffset,
2125+
constructorDeclaration.charOffset,
21262126
length),
2127-
builder.charOffset);
2127+
constructorDeclaration.charOffset);
21282128
} else {
21292129
initializer = buildSuperInitializer(
2130-
true, superTarget, arguments, builder.charOffset);
2130+
true, superTarget, arguments, constructorDeclaration.charOffset);
21312131
}
21322132
if (libraryFeatures.superParameters.isEnabled) {
2133-
InitializerInferenceResult inferenceResult =
2134-
typeInferrer.inferInitializer(this, initializer);
2135-
builder.addInitializer(initializer, this,
2133+
InitializerInferenceResult inferenceResult = typeInferrer
2134+
.inferInitializer(this, constructorDeclaration, initializer);
2135+
constructorDeclaration.addInitializer(initializer, this,
21362136
inferenceResult: inferenceResult);
21372137
} else {
21382138
builtInitializers.add(initializer);
@@ -7895,10 +7895,14 @@ class BodyBuilder extends StackListenerImpl
78957895
..fileOffset = assignmentOffset
78967896
];
78977897
} else {
7898+
ConstructorDeclaration constructorBuilder =
7899+
member as ConstructorDeclaration;
78987900
if (formal != null && formal.type is! OmittedTypeBuilder) {
78997901
DartType formalType = formal.variable!.type;
7900-
if (!typeEnvironment.isSubtypeOf(formalType, builder.fieldType,
7901-
SubtypeCheckMode.withNullabilities)) {
7902+
DartType fieldType =
7903+
constructorBuilder.substituteFieldType(builder.fieldType);
7904+
if (!typeEnvironment.isSubtypeOf(
7905+
formalType, fieldType, SubtypeCheckMode.withNullabilities)) {
79027906
libraryBuilder.addProblem(
79037907
fasta.templateInitializingFormalTypeMismatch.withArguments(
79047908
name,
@@ -7914,8 +7918,6 @@ class BodyBuilder extends StackListenerImpl
79147918
]);
79157919
}
79167920
}
7917-
ConstructorDeclaration constructorBuilder =
7918-
member as ConstructorDeclaration;
79197921
constructorBuilder.registerInitializedField(builder);
79207922
return builder.buildInitializer(assignmentOffset, expression,
79217923
isSynthetic: formal != null);

pkg/front_end/lib/src/fasta/source/constructor_declaration.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,12 @@ abstract class ConstructorDeclaration implements SourceFunctionBuilder {
5454
/// [registerInitializedField] and passes on the ownership of the collection
5555
/// to the caller.
5656
Set<SourceFieldBuilder>? takeInitializedFields();
57+
58+
/// Substitute [fieldType] from the context of the enclosing class or
59+
/// inline class to this constructor.
60+
///
61+
/// This is used for generic inline class constructors where the type
62+
/// variable referring to the class type variables must be substituted for
63+
/// the synthesized constructor type variables.
64+
DartType substituteFieldType(DartType fieldType);
5765
}

pkg/front_end/lib/src/fasta/source/outline_builder.dart

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1966,8 +1966,8 @@ class OutlineBuilder extends StackListenerImpl {
19661966
break;
19671967
}
19681968
bool isStatic = (modifiers & staticMask) != 0;
1969-
if (constructorName == null &&
1970-
!isStatic &&
1969+
bool isConstructor = constructorName != null;
1970+
if (!isStatic &&
19711971
(libraryBuilder.currentTypeParameterScopeBuilder.kind ==
19721972
TypeParameterScopeKind.extensionDeclaration ||
19731973
libraryBuilder.currentTypeParameterScopeBuilder.kind ==
@@ -1997,53 +1997,56 @@ class OutlineBuilder extends StackListenerImpl {
19971997
typeVariables = synthesizedTypeVariables;
19981998
}
19991999
}
2000-
List<FormalParameterBuilder> synthesizedFormals = [];
2001-
TypeBuilder thisType;
2002-
if (declaration.kind == TypeParameterScopeKind.extensionDeclaration) {
2003-
thisType = declaration.extensionThisType;
2004-
} else {
2005-
thisType = libraryBuilder.addNamedType(
2006-
declaration.name,
2007-
const NullabilityBuilder.omitted(),
2008-
declaration.typeVariables != null
2009-
? new List<TypeBuilder>.generate(
2010-
declaration.typeVariables!.length,
2011-
(int index) =>
2012-
new NamedTypeBuilder.fromTypeDeclarationBuilder(
2013-
typeVariables![index],
2014-
const NullabilityBuilder.omitted(),
2015-
instanceTypeVariableAccess:
2016-
InstanceTypeVariableAccessState.Allowed))
2017-
: null,
2000+
if (!isConstructor) {
2001+
List<FormalParameterBuilder> synthesizedFormals = [];
2002+
TypeBuilder thisType;
2003+
if (declaration.kind == TypeParameterScopeKind.extensionDeclaration) {
2004+
thisType = declaration.extensionThisType;
2005+
} else {
2006+
thisType = libraryBuilder.addNamedType(
2007+
declaration.name,
2008+
const NullabilityBuilder.omitted(),
2009+
declaration.typeVariables != null
2010+
? new List<TypeBuilder>.generate(
2011+
declaration.typeVariables!.length,
2012+
(int index) =>
2013+
new NamedTypeBuilder.fromTypeDeclarationBuilder(
2014+
typeVariables![index],
2015+
const NullabilityBuilder.omitted(),
2016+
instanceTypeVariableAccess:
2017+
InstanceTypeVariableAccessState.Allowed))
2018+
: null,
2019+
charOffset,
2020+
instanceTypeVariableAccess:
2021+
InstanceTypeVariableAccessState.Allowed);
2022+
}
2023+
if (substitution != null) {
2024+
List<NamedTypeBuilder> unboundTypes = [];
2025+
List<TypeVariableBuilder> unboundTypeVariables = [];
2026+
thisType = substitute(thisType, substitution,
2027+
unboundTypes: unboundTypes,
2028+
unboundTypeVariables: unboundTypeVariables);
2029+
for (NamedTypeBuilder unboundType in unboundTypes) {
2030+
declaration.registerUnresolvedNamedType(unboundType);
2031+
}
2032+
libraryBuilder.unboundTypeVariables.addAll(unboundTypeVariables);
2033+
}
2034+
synthesizedFormals.add(new FormalParameterBuilder(
2035+
/* metadata = */
2036+
null,
2037+
FormalParameterKind.requiredPositional,
2038+
finalMask,
2039+
thisType,
2040+
syntheticThisName,
2041+
null,
20182042
charOffset,
2019-
instanceTypeVariableAccess:
2020-
InstanceTypeVariableAccessState.Allowed);
2021-
}
2022-
if (substitution != null) {
2023-
List<NamedTypeBuilder> unboundTypes = [];
2024-
List<TypeVariableBuilder> unboundTypeVariables = [];
2025-
thisType = substitute(thisType, substitution,
2026-
unboundTypes: unboundTypes,
2027-
unboundTypeVariables: unboundTypeVariables);
2028-
for (NamedTypeBuilder unboundType in unboundTypes) {
2029-
declaration.registerUnresolvedNamedType(unboundType);
2043+
fileUri: uri,
2044+
isExtensionThis: true));
2045+
if (formals != null) {
2046+
synthesizedFormals.addAll(formals);
20302047
}
2031-
libraryBuilder.unboundTypeVariables.addAll(unboundTypeVariables);
2032-
}
2033-
synthesizedFormals.add(new FormalParameterBuilder(
2034-
/* metadata = */ null,
2035-
FormalParameterKind.requiredPositional,
2036-
finalMask,
2037-
thisType,
2038-
syntheticThisName,
2039-
null,
2040-
charOffset,
2041-
fileUri: uri,
2042-
isExtensionThis: true));
2043-
if (formals != null) {
2044-
synthesizedFormals.addAll(formals);
2048+
formals = synthesizedFormals;
20452049
}
2046-
formals = synthesizedFormals;
20472050
}
20482051

20492052
declarationBuilder.resolveNamedTypes(typeVariables, libraryBuilder);

pkg/front_end/lib/src/fasta/source/source_constructor_builder.dart

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ abstract class AbstractSourceConstructorBuilder
137137
for (FormalParameterBuilder formal in formals!) {
138138
if (formal.type is InferableTypeBuilder) {
139139
if (formal.isInitializingFormal) {
140-
formal.finalizeInitializingFormal(declarationBuilder, hierarchy);
140+
formal.finalizeInitializingFormal(
141+
declarationBuilder, this, hierarchy);
141142
}
142143
}
143144
}
@@ -903,6 +904,13 @@ class DeclaredSourceConstructorBuilder
903904
}
904905
}
905906
}
907+
908+
@override
909+
DartType substituteFieldType(DartType fieldType) {
910+
// Nothing to do. Regular generative constructors don't have their own
911+
// type variables.
912+
return fieldType;
913+
}
906914
}
907915

908916
class SyntheticSourceConstructorBuilder extends DillConstructorBuilder
@@ -1150,8 +1158,8 @@ class SourceInlineClassConstructorBuilder
11501158

11511159
InlineClass inlineClass = inlineClassBuilder.inlineClass;
11521160
List<DartType> typeParameterTypes = <DartType>[];
1153-
for (int i = 0; i < inlineClass.typeParameters.length; i++) {
1154-
TypeParameter typeParameter = inlineClass.typeParameters[i];
1161+
for (int i = 0; i < function.typeParameters.length; i++) {
1162+
TypeParameter typeParameter = function.typeParameters[i];
11551163
typeParameterTypes.add(
11561164
new TypeParameterType.withDefaultNullabilityForLibrary(
11571165
typeParameter, libraryBuilder.library));
@@ -1166,7 +1174,6 @@ class SourceInlineClassConstructorBuilder
11661174
buildFunction();
11671175
_constructor.function.fileOffset = charOpenParenOffset;
11681176
_constructor.function.fileEndOffset = _constructor.fileEndOffset;
1169-
_constructor.function.typeParameters = const <TypeParameter>[];
11701177
_constructor.isConst = isConst;
11711178
_constructor.isExternal = isExternal;
11721179

@@ -1224,7 +1231,30 @@ class SourceInlineClassConstructorBuilder
12241231
@override
12251232
bool get isEffectivelyRedirecting => isRedirecting;
12261233

1227-
// TODO(johnniwinther): Generate initializers and return statement.
1234+
Substitution? _substitutionCache;
1235+
1236+
Substitution get _substitution {
1237+
if (typeVariables != null) {
1238+
assert(
1239+
inlineClassBuilder.typeParameters!.length == typeVariables?.length);
1240+
_substitutionCache = Substitution.fromPairs(
1241+
inlineClassBuilder.inlineClass.typeParameters,
1242+
new List<DartType>.generate(
1243+
inlineClassBuilder.typeParameters!.length,
1244+
(int index) =>
1245+
new TypeParameterType.withDefaultNullabilityForLibrary(
1246+
function.typeParameters[index],
1247+
libraryBuilder.origin.library)));
1248+
} else {
1249+
_substitutionCache = Substitution.empty;
1250+
}
1251+
return _substitutionCache!;
1252+
}
1253+
1254+
@override
1255+
DartType substituteFieldType(DartType fieldType) {
1256+
return _substitution.substituteType(fieldType);
1257+
}
12281258
}
12291259

12301260
class _InitializerToStatementConverter implements InitializerVisitor<void> {

0 commit comments

Comments
 (0)