Skip to content

Commit 43840be

Browse files
chloestefantsovaCommit Bot
authored and
Commit Bot
committed
[cfe] Check types of super parameters for assignability
The CL enables both the checks of the super parameter relative to the corresponding parameter of the super constructor and the types of the copied default values. Part of #47525 Change-Id: I92dfa22c108bf07a69e1f8b5a210f6268ddfaa2e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/235080 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent b63550c commit 43840be

32 files changed

+497
-84
lines changed

pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4111,6 +4111,42 @@ Message _withArgumentsOptionalNonNullableWithoutInitializerError(
41114111
arguments: {'name': name, 'type': _type});
41124112
}
41134113

4114+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
4115+
const Template<
4116+
Message Function(
4117+
DartType _type, String name, bool isNonNullableByDefault)>
4118+
templateOptionalSuperParameterWithoutInitializer = const Template<
4119+
Message Function(
4120+
DartType _type, String name, bool isNonNullableByDefault)>(
4121+
problemMessageTemplate:
4122+
r"""Type '#type' of the optional super-initializer parameter '#name' doesn't allow 'null', but the parameter doesn't have a default value, and the default value can't be copied from the corresponding parameter of the super constructor.""",
4123+
withArguments: _withArgumentsOptionalSuperParameterWithoutInitializer);
4124+
4125+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
4126+
const Code<
4127+
Message Function(
4128+
DartType _type, String name, bool isNonNullableByDefault)>
4129+
codeOptionalSuperParameterWithoutInitializer = const Code<
4130+
Message Function(
4131+
DartType _type, String name, bool isNonNullableByDefault)>(
4132+
"OptionalSuperParameterWithoutInitializer",
4133+
);
4134+
4135+
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
4136+
Message _withArgumentsOptionalSuperParameterWithoutInitializer(
4137+
DartType _type, String name, bool isNonNullableByDefault) {
4138+
TypeLabeler labeler = new TypeLabeler(isNonNullableByDefault);
4139+
List<Object> typeParts = labeler.labelType(_type);
4140+
if (name.isEmpty) throw 'No name provided';
4141+
name = demangleMixinApplicationName(name);
4142+
String type = typeParts.join();
4143+
return new Message(codeOptionalSuperParameterWithoutInitializer,
4144+
problemMessage:
4145+
"""Type '${type}' of the optional super-initializer parameter '${name}' doesn't allow 'null', but the parameter doesn't have a default value, and the default value can't be copied from the corresponding parameter of the super constructor.""" +
4146+
labeler.originMessages,
4147+
arguments: {'type': _type, 'name': name});
4148+
}
4149+
41144150
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
41154151
const Template<
41164152
Message Function(String name, String name2, DartType _type,

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,8 +1965,10 @@ class BodyBuilder extends StackListenerImpl
19651965
constructor.function.positionalParameters[0].name == "index" &&
19661966
constructor.function.positionalParameters[1].name == "name");
19671967
(positionalArguments ??= <Expression>[]).insertAll(0, [
1968-
new VariableGet(constructor.function.positionalParameters[0]),
1969-
new VariableGet(constructor.function.positionalParameters[1])
1968+
new VariableGetImpl(constructor.function.positionalParameters[0],
1969+
forNullGuardedAccess: false),
1970+
new VariableGetImpl(constructor.function.positionalParameters[1],
1971+
forNullGuardedAccess: false)
19701972
]);
19711973
}
19721974
if (positionalArguments != null || namedArguments != null) {
@@ -1997,7 +1999,14 @@ class BodyBuilder extends StackListenerImpl
19971999
initializer = buildSuperInitializer(
19982000
true, superTarget, arguments, builder.charOffset);
19992001
}
2000-
constructor.initializers.add(initializer);
2002+
if (libraryBuilder.enableSuperParametersInLibrary) {
2003+
InitializerInferenceResult inferenceResult =
2004+
typeInferrer.inferInitializer(this, initializer);
2005+
builder.addInitializer(initializer, this,
2006+
inferenceResult: inferenceResult);
2007+
} else {
2008+
constructor.initializers.add(initializer);
2009+
}
20012010
}
20022011
setParents(constructor.initializers, constructor);
20032012
libraryBuilder.loader.transformListPostInference(constructor.initializers,

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:kernel/ast.dart';
66
import 'package:kernel/type_algebra.dart';
77

8+
import '../builder/library_builder.dart';
89
import '../source/source_library_builder.dart';
910
import '../source/source_member_builder.dart';
1011
import 'kernel_helper.dart';
@@ -279,7 +280,8 @@ SynthesizedFunctionNode buildRedirectingFactoryTearOffBody(
279280
Procedure tearOff,
280281
Member target,
281282
List<DartType> typeArguments,
282-
FreshTypeParameters freshTypeParameters) {
283+
FreshTypeParameters freshTypeParameters,
284+
LibraryBuilder libraryBuilder) {
283285
int fileOffset = tearOff.fileOffset;
284286

285287
List<TypeParameter> typeParameters;
@@ -318,7 +320,7 @@ SynthesizedFunctionNode buildRedirectingFactoryTearOffBody(
318320
_createTearOffBody(tearOff, target, arguments);
319321
return new SynthesizedFunctionNode(
320322
substitutionMap, target.function!, tearOff.function,
321-
identicalSignatures: false);
323+
identicalSignatures: false, libraryBuilder: libraryBuilder);
322324
}
323325

324326
/// Creates the synthesized [Procedure] node for a tear off lowering by the

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

Lines changed: 83 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ library fasta.kernel_target;
77
import 'package:kernel/ast.dart';
88
import 'package:kernel/clone.dart' show CloneVisitorNotMembers;
99
import 'package:kernel/type_algebra.dart' show Substitution;
10+
import 'package:kernel/type_environment.dart';
11+
12+
import '../builder/library_builder.dart';
13+
import '../messages.dart';
1014

1115
/// Data for clone default values for synthesized function nodes once the
1216
/// original default values have been computed.
@@ -35,32 +39,45 @@ class SynthesizedFunctionNode {
3539
/// named parameters.
3640
final bool identicalSignatures;
3741

38-
final List<int>? _positionalSuperParameters;
42+
final List<int?>? _positionalSuperParameters;
3943

4044
final List<String>? _namedSuperParameters;
4145

4246
bool isOutlineNode;
4347

48+
final LibraryBuilder _libraryBuilder;
49+
50+
CloneVisitorNotMembers? _cloner;
51+
4452
SynthesizedFunctionNode(
4553
this._typeSubstitution, this._original, this._synthesized,
4654
{this.identicalSignatures: true,
47-
List<int>? positionalSuperParameters: null,
55+
List<int?>? positionalSuperParameters: null,
4856
List<String>? namedSuperParameters: null,
49-
this.isOutlineNode: false})
57+
this.isOutlineNode: false,
58+
required LibraryBuilder libraryBuilder})
5059
: _positionalSuperParameters = positionalSuperParameters,
5160
_namedSuperParameters = namedSuperParameters,
61+
_libraryBuilder = libraryBuilder,
5262
// Check that [positionalSuperParameters] and [namedSuperParameters] are
5363
// provided or omitted together.
5464
assert((positionalSuperParameters == null) ==
5565
(namedSuperParameters == null)),
5666
assert(positionalSuperParameters == null ||
5767
() {
5868
// Check that [positionalSuperParameters] is sorted if it's
59-
// provided.
60-
for (int i = 1; i < positionalSuperParameters.length; i++) {
61-
if (positionalSuperParameters[i] <
62-
positionalSuperParameters[i - 1]) {
63-
return false;
69+
// provided. The `null` values are allowed in-between the sorted
70+
// values.
71+
for (int i = -1, j = 0;
72+
j < positionalSuperParameters.length;
73+
j++) {
74+
int? currentValue = positionalSuperParameters[j];
75+
if (currentValue != null) {
76+
if (i == -1 || positionalSuperParameters[i]! < currentValue) {
77+
i = j;
78+
} else {
79+
return false;
80+
}
6481
}
6582
}
6683
return true;
@@ -82,23 +99,11 @@ class SynthesizedFunctionNode {
8299
return superParameterIndex == namedSuperParameters.length;
83100
}());
84101

85-
void cloneDefaultValues() {
102+
void cloneDefaultValues(TypeEnvironment typeEnvironment) {
86103
// TODO(ahe): It is unclear if it is legal to use type variables in
87104
// default values, but Fasta is currently allowing it, and the VM
88105
// accepts it. If it isn't legal, the we can speed this up by using a
89106
// single cloner without substitution.
90-
CloneVisitorNotMembers? cloner;
91-
92-
void cloneInitializer(VariableDeclaration originalParameter,
93-
VariableDeclaration clonedParameter) {
94-
if (originalParameter.initializer != null) {
95-
cloner ??=
96-
new CloneVisitorNotMembers(typeSubstitution: _typeSubstitution);
97-
clonedParameter.initializer = cloner!
98-
.clone(originalParameter.initializer!)
99-
..parent = clonedParameter;
100-
}
101-
}
102107

103108
// For mixin application constructors, the argument count is the same, but
104109
// for redirecting tear off lowerings, the argument count of the tear off
@@ -109,14 +114,21 @@ class SynthesizedFunctionNode {
109114
assert(_positionalSuperParameters != null ||
110115
_synthesized.positionalParameters.length ==
111116
_original.positionalParameters.length);
112-
List<int>? positionalSuperParameters = _positionalSuperParameters;
117+
List<int?>? positionalSuperParameters = _positionalSuperParameters;
113118
for (int i = 0; i < _original.positionalParameters.length; i++) {
114119
if (positionalSuperParameters == null) {
115-
cloneInitializer(_original.positionalParameters[i],
120+
_cloneInitializer(_original.positionalParameters[i],
116121
_synthesized.positionalParameters[i]);
117122
} else if (i < positionalSuperParameters.length) {
118-
cloneInitializer(_original.positionalParameters[i],
119-
_synthesized.positionalParameters[positionalSuperParameters[i]]);
123+
int? superParameterIndex = positionalSuperParameters[i];
124+
if (superParameterIndex != null) {
125+
VariableDeclaration originalParameter =
126+
_original.positionalParameters[i];
127+
VariableDeclaration synthesizedParameter =
128+
_synthesized.positionalParameters[superParameterIndex];
129+
_cloneDefaultValueForSuperParameters(
130+
originalParameter, synthesizedParameter, typeEnvironment);
131+
}
120132
}
121133
}
122134

@@ -131,7 +143,7 @@ class SynthesizedFunctionNode {
131143
}
132144
for (int i = 0; i < _synthesized.namedParameters.length; i++) {
133145
if (namedSuperParameters == null) {
134-
cloneInitializer(
146+
_cloneInitializer(
135147
_original.namedParameters[i], _synthesized.namedParameters[i]);
136148
} else if (superParameterNameIndex < namedSuperParameters.length &&
137149
namedSuperParameters[superParameterNameIndex] ==
@@ -141,9 +153,12 @@ class SynthesizedFunctionNode {
141153
int? originalNamedParameterIndex =
142154
originalNamedParameterIndices[superParameterName];
143155
if (originalNamedParameterIndex != null) {
144-
cloneInitializer(
145-
_original.namedParameters[originalNamedParameterIndex],
146-
_synthesized.namedParameters[i]);
156+
VariableDeclaration originalParameter =
157+
_original.namedParameters[originalNamedParameterIndex];
158+
VariableDeclaration synthesizedParameter =
159+
_synthesized.namedParameters[i];
160+
_cloneDefaultValueForSuperParameters(
161+
originalParameter, synthesizedParameter, typeEnvironment);
147162
} else {
148163
// TODO(cstefantsova): Handle the erroneous case of missing names.
149164
}
@@ -155,7 +170,7 @@ class SynthesizedFunctionNode {
155170
VariableDeclaration synthesizedParameter =
156171
_synthesized.positionalParameters[i];
157172
if (i < _original.positionalParameters.length) {
158-
cloneInitializer(
173+
_cloneInitializer(
159174
_original.positionalParameters[i], synthesizedParameter);
160175
} else {
161176
// Error case: use `null` as initializer.
@@ -175,7 +190,7 @@ class SynthesizedFunctionNode {
175190
VariableDeclaration? originalParameter =
176191
originalParameters[synthesizedParameter.name!];
177192
if (originalParameter != null) {
178-
cloneInitializer(originalParameter, synthesizedParameter);
193+
_cloneInitializer(originalParameter, synthesizedParameter);
179194
} else {
180195
// Error case: use `null` as initializer.
181196
synthesizedParameter.initializer = new NullLiteral()
@@ -186,6 +201,43 @@ class SynthesizedFunctionNode {
186201
}
187202
}
188203

204+
void _cloneInitializer(VariableDeclaration originalParameter,
205+
VariableDeclaration clonedParameter) {
206+
if (originalParameter.initializer != null) {
207+
CloneVisitorNotMembers cloner = _cloner ??=
208+
new CloneVisitorNotMembers(typeSubstitution: _typeSubstitution);
209+
clonedParameter.initializer = cloner.clone(originalParameter.initializer!)
210+
..parent = clonedParameter;
211+
}
212+
}
213+
214+
void _cloneDefaultValueForSuperParameters(
215+
VariableDeclaration originalParameter,
216+
VariableDeclaration synthesizedParameter,
217+
TypeEnvironment typeEnvironment) {
218+
Member member = _synthesized.parent as Member;
219+
Expression? originalParameterInitializer = originalParameter.initializer;
220+
DartType? originalParameterInitializerType = originalParameterInitializer
221+
?.getStaticType(new StaticTypeContext(member, typeEnvironment));
222+
DartType synthesizedParameterType = synthesizedParameter.type;
223+
if (originalParameterInitializerType != null &&
224+
typeEnvironment.isSubtypeOf(originalParameterInitializerType,
225+
synthesizedParameterType, SubtypeCheckMode.withNullabilities)) {
226+
_cloneInitializer(originalParameter, synthesizedParameter);
227+
} else {
228+
if (synthesizedParameterType.isPotentiallyNonNullable) {
229+
_libraryBuilder.addProblem(
230+
templateOptionalSuperParameterWithoutInitializer.withArguments(
231+
synthesizedParameter.type,
232+
synthesizedParameter.name!,
233+
_libraryBuilder.isNonNullableByDefault),
234+
synthesizedParameter.fileOffset,
235+
synthesizedParameter.name?.length ?? 1,
236+
_libraryBuilder.fileUri);
237+
}
238+
}
239+
}
240+
189241
@override
190242
String toString() {
191243
return "SynthesizedFunctionNode(original=${_original.parent}, "

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,8 @@ class KernelTarget extends TargetImplementation {
10861086
superConstructor, new Arguments(positional, named: named));
10871087
SynthesizedFunctionNode synthesizedFunctionNode =
10881088
new SynthesizedFunctionNode(
1089-
substitutionMap, superConstructor.function, function);
1089+
substitutionMap, superConstructor.function, function,
1090+
libraryBuilder: classBuilder.library);
10901091
if (!isConst) {
10911092
// For constant constructors default values are computed and cloned part
10921093
// of the outline expression and therefore passed to the
@@ -1144,7 +1145,7 @@ class KernelTarget extends TargetImplementation {
11441145
for (SynthesizedFunctionNode synthesizedFunctionNode
11451146
in synthesizedFunctionNodes) {
11461147
if (!forOutline || synthesizedFunctionNode.isOutlineNode) {
1147-
synthesizedFunctionNode.cloneDefaultValues();
1148+
synthesizedFunctionNode.cloneDefaultValues(loader.typeEnvironment);
11481149
}
11491150
}
11501151
if (!forOutline) {

0 commit comments

Comments
 (0)