Skip to content

Commit 40d52d5

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[model] Enable checks in redirecting factories of extension types
This CL enables the same checks in the redirecting factories of extension types as in redirecting factories of classes. Additionally, this CL marks all of those erroneous constructors, in classes and in extension type declarations, as erroneous. Change-Id: Ic270324f05b6a8424c1ab9fbe9fe4f1d0b22a3fc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425860 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 2f0cbeb commit 40d52d5

25 files changed

+571
-58
lines changed

pkg/front_end/lib/src/fragment/field/encoding.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,7 @@ class RepresentationFieldEncoding implements FieldEncoding {
12051205
{required bool isSynthetic}) {
12061206
return <Initializer>[
12071207
new ExtensionTypeRepresentationFieldInitializer(_getter, value)
1208+
..fileOffset = fileOffset
12081209
];
12091210
}
12101211

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ import '../codes/cfe_codes.dart' as cfe;
9898
import '../dill/dill_library_builder.dart' show DillLibraryBuilder;
9999
import '../dill/dill_type_parameter_builder.dart';
100100
import '../fragment/fragment.dart';
101+
import '../source/constructor_declaration.dart';
101102
import '../source/diet_parser.dart';
102103
import '../source/offset_map.dart';
103104
import '../source/source_library_builder.dart';
@@ -9302,6 +9303,9 @@ class BodyBuilder extends StackListenerImpl
93029303
cfe.messageUnexpectedSuperParametersInGenerativeConstructors,
93039304
formal.fileOffset,
93049305
noLength);
9306+
if (constructorBuilder is ConstructorDeclarationBuilder) {
9307+
constructorBuilder.markAsErroneous();
9308+
}
93059309
}
93069310
}
93079311
}

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

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,15 @@ class SourceConstructorBuilderImpl extends SourceMemberBuilderImpl
456456
_initializers.add(initializer..parent = parent);
457457
}
458458
}
459-
} else if (initializer is RedirectingInitializer) {
459+
} else if (initializer
460+
case RedirectingInitializer(
461+
target: Member initializerTarget,
462+
arguments: var initializerArguments
463+
) ||
464+
ExtensionTypeRedirectingInitializer(
465+
target: Member initializerTarget,
466+
arguments: var initializerArguments
467+
)) {
460468
if (superInitializer != null) {
461469
// Point to the existing super initializer.
462470
_injectInvalidInitializer(
@@ -465,13 +473,15 @@ class SourceConstructorBuilderImpl extends SourceMemberBuilderImpl
465473
"super".length,
466474
helper,
467475
parent);
476+
markAsErroneous();
468477
} else if (redirectingInitializer != null) {
469478
_injectInvalidInitializer(
470479
messageRedirectingConstructorWithMultipleRedirectInitializers,
471480
initializer.fileOffset,
472481
noLength,
473482
helper,
474483
parent);
484+
markAsErroneous();
475485
} else if (_initializers.isNotEmpty) {
476486
// Error on all previous ones.
477487
for (int i = 0; i < _initializers.length; i++) {
@@ -488,22 +498,30 @@ class SourceConstructorBuilderImpl extends SourceMemberBuilderImpl
488498
}
489499
inferenceResult?.applyResult(_initializers, parent);
490500
_initializers.add(initializer..parent = parent);
491-
redirectingInitializer = initializer;
501+
if (initializer is RedirectingInitializer) {
502+
redirectingInitializer = initializer;
503+
}
504+
markAsErroneous();
492505
} else {
493506
inferenceResult?.applyResult(_initializers, parent);
494-
redirectingInitializer = initializer;
507+
if (initializer is RedirectingInitializer) {
508+
redirectingInitializer = initializer;
509+
}
495510

496511
LocatedMessage? message = helper.checkArgumentsForFunction(
497-
initializer.target.function,
498-
initializer.arguments,
499-
initializer.arguments.fileOffset, const <TypeParameter>[]);
512+
initializerTarget.function!,
513+
initializerArguments,
514+
initializerArguments.fileOffset,
515+
initializer is ExtensionTypeRedirectingInitializer
516+
? initializerTarget.function!.typeParameters
517+
: const <TypeParameter>[]);
500518
if (message != null) {
501519
_initializers.add(helper.buildInvalidInitializer(
502520
helper.buildUnresolvedError(
503521
helper.constructorNameForDiagnostics(
504-
initializer.target.name.text),
522+
initializerTarget.name.text),
505523
initializer.fileOffset,
506-
arguments: initializer.arguments,
524+
arguments: initializerArguments,
507525
isSuper: false,
508526
message: message,
509527
kind: UnresolvedKind.Constructor))
@@ -522,9 +540,11 @@ class SourceConstructorBuilderImpl extends SourceMemberBuilderImpl
522540
length,
523541
helper,
524542
parent);
543+
markAsErroneous();
525544
} else if (superInitializer != null) {
526545
_injectInvalidInitializer(messageSuperInitializerNotLast,
527546
initializer.fileOffset, noLength, helper, parent);
547+
markAsErroneous();
528548
} else {
529549
inferenceResult?.applyResult(_initializers, parent);
530550
_initializers.add(initializer..parent = parent);

pkg/front_end/test/predicates/data/extension_type.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
/*member: ExtensionType|constructor#:extensionName=ExtensionType.new*/
6-
extension type ExtensionType(int it) {
6+
extension type ExtensionType(int /*
7+
extensionThis,
8+
name=this
9+
*/it) {
710
/*member: ExtensionType|constructor#constructor:extensionName=ExtensionType.constructor*/
8-
ExtensionType.constructor(this.it);
11+
ExtensionType.constructor(this./*
12+
extensionThis,
13+
name=this
14+
*/it);
915

1016
/*member: ExtensionType|constructor#factory:extensionName=ExtensionType.factory*/
1117
factory ExtensionType.factory(int value) => ExtensionType(value);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by b
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
extension type E1(dynamic it) {
6+
E1.named(dynamic value) : this(value, value);
7+
}
8+
9+
extension type E2(num it) {
10+
E2.named(super.it) : this(it);
11+
}
12+
13+
extension type E3(String it) {
14+
E3.named(String it1, String it2) : this(it1), this(it2);
15+
}
16+
17+
extension type E4(bool it) {
18+
E4.named(bool it) : it = false, this(it);
19+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:10:18: Error: Extension type constructors can't declare super formal parameters.
6+
// E2.named(super.it) : this(it);
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:10:18: Error: Super parameters can only be used in non-redirecting generative constructors.
10+
// E2.named(super.it) : this(it);
11+
// ^
12+
//
13+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:6:33: Error: Too many positional arguments: 1 allowed, but 2 found.
14+
// Try removing the extra positional arguments.
15+
// E1.named(dynamic value) : this(value, value);
16+
// ^
17+
//
18+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:14:38: Error: A redirecting constructor can't have other initializers.
19+
// E3.named(String it1, String it2) : this(it1), this(it2);
20+
// ^
21+
//
22+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:18:26: Error: A redirecting constructor can't have other initializers.
23+
// E4.named(bool it) : it = false, this(it);
24+
// ^
25+
//
26+
import self as self;
27+
import "dart:core" as core;
28+
29+
extension type E1(dynamic it) {
30+
abstract extension-type-member representation-field get it() → dynamic;
31+
constructor • = self::E1|constructor#;
32+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
33+
constructor named = self::E1|constructor#named;
34+
constructor tearoff named = self::E1|constructor#_#named#tearOff;
35+
}
36+
extension type E2(core::num it) {
37+
abstract extension-type-member representation-field get it() → core::num;
38+
constructor • = self::E2|constructor#;
39+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
40+
constructor named = self::E2|constructor#named;
41+
constructor tearoff named = self::E2|constructor#_#named#tearOff;
42+
}
43+
extension type E3(core::String it) {
44+
abstract extension-type-member representation-field get it() → core::String;
45+
constructor • = self::E3|constructor#;
46+
constructor tearoff • = self::E3|constructor#_#new#tearOff;
47+
constructor named = self::E3|constructor#named;
48+
constructor tearoff named = self::E3|constructor#_#named#tearOff;
49+
}
50+
extension type E4(core::bool it) {
51+
abstract extension-type-member representation-field get it() → core::bool;
52+
constructor • = self::E4|constructor#;
53+
constructor tearoff • = self::E4|constructor#_#new#tearOff;
54+
constructor named = self::E4|constructor#named;
55+
constructor tearoff named = self::E4|constructor#_#named#tearOff;
56+
}
57+
static extension-type-member method E1|constructor#(dynamic it) → self::E1% /* erasure=dynamic, declared=! */ {
58+
lowered final self::E1% /* erasure=dynamic, declared=! */ #this = it;
59+
return #this;
60+
}
61+
static extension-type-member synthetic method E1|constructor#_#new#tearOff(dynamic it) → self::E1% /* erasure=dynamic, declared=! */
62+
return self::E1|constructor#(it);
63+
static extension-type-member erroneous method E1|constructor#named(dynamic value) → self::E1% /* erasure=dynamic, declared=! */ {
64+
lowered final self::E1% /* erasure=dynamic, declared=! */ #this;
65+
final dynamic #t1 = invalid-expression "pkg/front_end/testcases/extension_types/erroneous_constructors.dart:6:33: Error: Too many positional arguments: 1 allowed, but 2 found.
66+
Try removing the extra positional arguments.
67+
E1.named(dynamic value) : this(value, value);
68+
^";
69+
return #this;
70+
}
71+
static extension-type-member synthetic method E1|constructor#_#named#tearOff(dynamic value) → self::E1% /* erasure=dynamic, declared=! */
72+
return self::E1|constructor#named(value);
73+
static extension-type-member erroneous method E2|constructor#(core::num it) → self::E2% /* erasure=core::num, declared=! */ {
74+
lowered final self::E2% /* erasure=core::num, declared=! */ #this = it;
75+
return #this;
76+
}
77+
static extension-type-member synthetic method E2|constructor#_#new#tearOff(core::num it) → self::E2% /* erasure=core::num, declared=! */
78+
return self::E2|constructor#(it);
79+
static extension-type-member method E2|constructor#named(invalid-type it) → self::E2% /* erasure=core::num, declared=! */ {
80+
lowered final self::E2% /* erasure=core::num, declared=! */ #this;
81+
return #this;
82+
}
83+
static extension-type-member synthetic method E2|constructor#_#named#tearOff(invalid-type it) → self::E2% /* erasure=core::num, declared=! */
84+
return self::E2|constructor#named(it);
85+
static extension-type-member method E3|constructor#(core::String it) → self::E3% /* erasure=core::String, declared=! */ {
86+
lowered final self::E3% /* erasure=core::String, declared=! */ #this = it;
87+
return #this;
88+
}
89+
static extension-type-member synthetic method E3|constructor#_#new#tearOff(core::String it) → self::E3% /* erasure=core::String, declared=! */
90+
return self::E3|constructor#(it);
91+
static extension-type-member erroneous method E3|constructor#named(core::String it1, core::String it2) → self::E3% /* erasure=core::String, declared=! */ {
92+
lowered final self::E3% /* erasure=core::String, declared=! */ #this;
93+
final dynamic #t2 = invalid-expression "pkg/front_end/testcases/extension_types/erroneous_constructors.dart:14:38: Error: A redirecting constructor can't have other initializers.
94+
E3.named(String it1, String it2) : this(it1), this(it2);
95+
^";
96+
#this = self::E3|constructor#(it2);
97+
return #this;
98+
}
99+
static extension-type-member synthetic method E3|constructor#_#named#tearOff(core::String it1, core::String it2) → self::E3% /* erasure=core::String, declared=! */
100+
return self::E3|constructor#named(it1, it2);
101+
static extension-type-member method E4|constructor#(core::bool it) → self::E4% /* erasure=core::bool, declared=! */ {
102+
lowered final self::E4% /* erasure=core::bool, declared=! */ #this = it;
103+
return #this;
104+
}
105+
static extension-type-member synthetic method E4|constructor#_#new#tearOff(core::bool it) → self::E4% /* erasure=core::bool, declared=! */
106+
return self::E4|constructor#(it);
107+
static extension-type-member erroneous method E4|constructor#named(core::bool it) → self::E4% /* erasure=core::bool, declared=! */ {
108+
lowered final self::E4% /* erasure=core::bool, declared=! */ #this;
109+
final dynamic #t3 = invalid-expression "pkg/front_end/testcases/extension_types/erroneous_constructors.dart:18:26: Error: A redirecting constructor can't have other initializers.
110+
E4.named(bool it) : it = false, this(it);
111+
^";
112+
#this = self::E4|constructor#(it);
113+
return #this;
114+
}
115+
static extension-type-member synthetic method E4|constructor#_#named#tearOff(core::bool it) → self::E4% /* erasure=core::bool, declared=! */
116+
return self::E4|constructor#named(it);
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:10:18: Error: Extension type constructors can't declare super formal parameters.
6+
// E2.named(super.it) : this(it);
7+
// ^^
8+
//
9+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:10:18: Error: Super parameters can only be used in non-redirecting generative constructors.
10+
// E2.named(super.it) : this(it);
11+
// ^
12+
//
13+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:6:33: Error: Too many positional arguments: 1 allowed, but 2 found.
14+
// Try removing the extra positional arguments.
15+
// E1.named(dynamic value) : this(value, value);
16+
// ^
17+
//
18+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:14:38: Error: A redirecting constructor can't have other initializers.
19+
// E3.named(String it1, String it2) : this(it1), this(it2);
20+
// ^
21+
//
22+
// pkg/front_end/testcases/extension_types/erroneous_constructors.dart:18:26: Error: A redirecting constructor can't have other initializers.
23+
// E4.named(bool it) : it = false, this(it);
24+
// ^
25+
//
26+
import self as self;
27+
import "dart:core" as core;
28+
29+
extension type E1(dynamic it) {
30+
abstract extension-type-member representation-field get it() → dynamic;
31+
constructor • = self::E1|constructor#;
32+
constructor tearoff • = self::E1|constructor#_#new#tearOff;
33+
constructor named = self::E1|constructor#named;
34+
constructor tearoff named = self::E1|constructor#_#named#tearOff;
35+
}
36+
extension type E2(core::num it) {
37+
abstract extension-type-member representation-field get it() → core::num;
38+
constructor • = self::E2|constructor#;
39+
constructor tearoff • = self::E2|constructor#_#new#tearOff;
40+
constructor named = self::E2|constructor#named;
41+
constructor tearoff named = self::E2|constructor#_#named#tearOff;
42+
}
43+
extension type E3(core::String it) {
44+
abstract extension-type-member representation-field get it() → core::String;
45+
constructor • = self::E3|constructor#;
46+
constructor tearoff • = self::E3|constructor#_#new#tearOff;
47+
constructor named = self::E3|constructor#named;
48+
constructor tearoff named = self::E3|constructor#_#named#tearOff;
49+
}
50+
extension type E4(core::bool it) {
51+
abstract extension-type-member representation-field get it() → core::bool;
52+
constructor • = self::E4|constructor#;
53+
constructor tearoff • = self::E4|constructor#_#new#tearOff;
54+
constructor named = self::E4|constructor#named;
55+
constructor tearoff named = self::E4|constructor#_#named#tearOff;
56+
}
57+
static extension-type-member method E1|constructor#(dynamic it) → self::E1% /* erasure=dynamic, declared=! */ {
58+
lowered final self::E1% /* erasure=dynamic, declared=! */ #this = it;
59+
return #this;
60+
}
61+
static extension-type-member synthetic method E1|constructor#_#new#tearOff(dynamic it) → self::E1% /* erasure=dynamic, declared=! */
62+
return self::E1|constructor#(it);
63+
static extension-type-member erroneous method E1|constructor#named(dynamic value) → self::E1% /* erasure=dynamic, declared=! */ {
64+
lowered final self::E1% /* erasure=dynamic, declared=! */ #this;
65+
final dynamic #t1 = invalid-expression "pkg/front_end/testcases/extension_types/erroneous_constructors.dart:6:33: Error: Too many positional arguments: 1 allowed, but 2 found.
66+
Try removing the extra positional arguments.
67+
E1.named(dynamic value) : this(value, value);
68+
^";
69+
return #this;
70+
}
71+
static extension-type-member synthetic method E1|constructor#_#named#tearOff(dynamic value) → self::E1% /* erasure=dynamic, declared=! */
72+
return self::E1|constructor#named(value);
73+
static extension-type-member erroneous method E2|constructor#(core::num it) → self::E2% /* erasure=core::num, declared=! */ {
74+
lowered final self::E2% /* erasure=core::num, declared=! */ #this = it;
75+
return #this;
76+
}
77+
static extension-type-member synthetic method E2|constructor#_#new#tearOff(core::num it) → self::E2% /* erasure=core::num, declared=! */
78+
return self::E2|constructor#(it);
79+
static extension-type-member method E2|constructor#named(invalid-type it) → self::E2% /* erasure=core::num, declared=! */ {
80+
lowered final self::E2% /* erasure=core::num, declared=! */ #this;
81+
return #this;
82+
}
83+
static extension-type-member synthetic method E2|constructor#_#named#tearOff(invalid-type it) → self::E2% /* erasure=core::num, declared=! */
84+
return self::E2|constructor#named(it);
85+
static extension-type-member method E3|constructor#(core::String it) → self::E3% /* erasure=core::String, declared=! */ {
86+
lowered final self::E3% /* erasure=core::String, declared=! */ #this = it;
87+
return #this;
88+
}
89+
static extension-type-member synthetic method E3|constructor#_#new#tearOff(core::String it) → self::E3% /* erasure=core::String, declared=! */
90+
return self::E3|constructor#(it);
91+
static extension-type-member erroneous method E3|constructor#named(core::String it1, core::String it2) → self::E3% /* erasure=core::String, declared=! */ {
92+
lowered final self::E3% /* erasure=core::String, declared=! */ #this;
93+
final dynamic #t2 = invalid-expression "pkg/front_end/testcases/extension_types/erroneous_constructors.dart:14:38: Error: A redirecting constructor can't have other initializers.
94+
E3.named(String it1, String it2) : this(it1), this(it2);
95+
^";
96+
#this = self::E3|constructor#(it2);
97+
return #this;
98+
}
99+
static extension-type-member synthetic method E3|constructor#_#named#tearOff(core::String it1, core::String it2) → self::E3% /* erasure=core::String, declared=! */
100+
return self::E3|constructor#named(it1, it2);
101+
static extension-type-member method E4|constructor#(core::bool it) → self::E4% /* erasure=core::bool, declared=! */ {
102+
lowered final self::E4% /* erasure=core::bool, declared=! */ #this = it;
103+
return #this;
104+
}
105+
static extension-type-member synthetic method E4|constructor#_#new#tearOff(core::bool it) → self::E4% /* erasure=core::bool, declared=! */
106+
return self::E4|constructor#(it);
107+
static extension-type-member erroneous method E4|constructor#named(core::bool it) → self::E4% /* erasure=core::bool, declared=! */ {
108+
lowered final self::E4% /* erasure=core::bool, declared=! */ #this;
109+
final dynamic #t3 = invalid-expression "pkg/front_end/testcases/extension_types/erroneous_constructors.dart:18:26: Error: A redirecting constructor can't have other initializers.
110+
E4.named(bool it) : it = false, this(it);
111+
^";
112+
#this = self::E4|constructor#(it);
113+
return #this;
114+
}
115+
static extension-type-member synthetic method E4|constructor#_#named#tearOff(core::bool it) → self::E4% /* erasure=core::bool, declared=! */
116+
return self::E4|constructor#named(it);

0 commit comments

Comments
 (0)