Skip to content

Commit ce0406d

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Fix crash on erroneous setter in extension and extension type
Change-Id: I2a52ea40d476fb144d72ca84206023b61f816dad Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396580 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent 4ef1fd4 commit ce0406d

9 files changed

+435
-1
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,14 @@ class BodyBuilder extends StackListenerImpl
13051305
// Illegal parameters were removed by the function builder.
13061306
// Add them as local variable to put them in scope of the body.
13071307
List<Statement> statements = <Statement>[];
1308-
for (FormalParameterBuilder parameter in _context.formals!) {
1308+
List<FormalParameterBuilder> formals = _context.formals!;
1309+
for (int i = 0; i < formals.length; i++) {
1310+
FormalParameterBuilder parameter = formals[i];
1311+
VariableDeclaration variable = parameter.variable!;
1312+
// #this should not be redeclared.
1313+
if (i == 0 && identical(variable, thisVariable)) {
1314+
continue;
1315+
}
13091316
statements.add(parameter.variable!);
13101317
}
13111318
statements.add(body);

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,20 @@ abstract class SourceFunctionBuilderImpl extends SourceMemberBuilderImpl
384384
parameter.parent = function;
385385
function.namedParameters.clear();
386386
function.requiredParameterCount = 1;
387+
} else if ((isExtensionInstanceMember || isExtensionTypeInstanceMember) &&
388+
isSetter &&
389+
(formals?.length != 2 || formals![1].isOptionalPositional)) {
390+
// Replace illegal parameters by single dummy parameter (after #this).
391+
// Do this after building the parameters, since the diet listener
392+
// assumes that parameters are built, even if illegal in number.
393+
VariableDeclaration thisParameter = function.positionalParameters[0];
394+
VariableDeclaration parameter = new VariableDeclarationImpl("#synthetic");
395+
function.positionalParameters.clear();
396+
function.positionalParameters.add(thisParameter);
397+
function.positionalParameters.add(parameter);
398+
parameter.parent = function;
399+
function.namedParameters.clear();
400+
function.requiredParameterCount = 2;
387401
}
388402
if (returnType is! InferableTypeBuilder) {
389403
function.returnType =
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
extension Foo on int {
6+
set foo({final newFoo}) {
7+
print(foo);
8+
}
9+
10+
int get foo => 42;
11+
12+
void bar() {
13+
--foo;
14+
}
15+
}
16+
17+
extension type Bar(int i) {
18+
set foo({final newFoo}) {
19+
print(foo);
20+
}
21+
22+
int get foo => 42;
23+
24+
void bar() {
25+
--foo;
26+
}
27+
}
28+
29+
class Baz {
30+
set foo({final newFoo}) {
31+
print(foo);
32+
}
33+
34+
int get foo => 42;
35+
36+
void bar() {
37+
--foo;
38+
}
39+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/erroneous_setter.dart:6:10: Error: A setter should have exactly one formal parameter.
6+
// set foo({final newFoo}) {
7+
// ^
8+
//
9+
// pkg/front_end/testcases/regress/erroneous_setter.dart:18:10: Error: A setter should have exactly one formal parameter.
10+
// set foo({final newFoo}) {
11+
// ^
12+
//
13+
// pkg/front_end/testcases/regress/erroneous_setter.dart:30:10: Error: A setter should have exactly one formal parameter.
14+
// set foo({final newFoo}) {
15+
// ^
16+
//
17+
import self as self;
18+
import "dart:core" as core;
19+
20+
class Baz extends core::Object {
21+
synthetic constructor •() → self::Baz
22+
: super core::Object::•()
23+
;
24+
set foo(dynamic #synthetic) → void {
25+
invalid-expression "pkg/front_end/testcases/regress/erroneous_setter.dart:30:10: Error: A setter should have exactly one formal parameter.
26+
set foo({final newFoo}) {
27+
^";
28+
{
29+
final dynamic newFoo = null;
30+
{
31+
core::print(this.{self::Baz::foo}{core::int});
32+
}
33+
}
34+
}
35+
get foo() → core::int
36+
return 42;
37+
method bar() → void {
38+
this.{self::Baz::foo} = this.{self::Baz::foo}{core::int}.{core::num::-}(1){(core::num) → core::int};
39+
}
40+
}
41+
extension Foo on core::int {
42+
get foo = self::Foo|get#foo;
43+
method bar = self::Foo|bar;
44+
method tearoff bar = self::Foo|get#bar;
45+
set foo = self::Foo|set#foo;
46+
}
47+
extension type Bar(core::int i) {
48+
abstract extension-type-member representation-field get i() → core::int;
49+
get foo = self::Bar|get#foo;
50+
method bar = self::Bar|bar;
51+
method tearoff bar = self::Bar|get#bar;
52+
set foo = self::Bar|set#foo;
53+
constructor • = self::Bar|constructor#;
54+
constructor tearoff • = self::Bar|constructor#_#new#tearOff;
55+
}
56+
static extension-member method Foo|set#foo(lowered final core::int #this, dynamic #synthetic) → void {
57+
invalid-expression "pkg/front_end/testcases/regress/erroneous_setter.dart:6:10: Error: A setter should have exactly one formal parameter.
58+
set foo({final newFoo}) {
59+
^";
60+
{
61+
final dynamic newFoo = null;
62+
{
63+
core::print(self::Foo|get#foo(#this));
64+
}
65+
}
66+
}
67+
static extension-member method Foo|get#foo(lowered final core::int #this) → core::int
68+
return 42;
69+
static extension-member method Foo|bar(lowered final core::int #this) → void {
70+
let final core::int #t1 = self::Foo|get#foo(#this).{core::num::-}(1){(core::num) → core::int} in let final void #t2 = self::Foo|set#foo(#this, #t1) in #t1;
71+
}
72+
static extension-member method Foo|get#bar(lowered final core::int #this) → () → void
73+
return () → void => self::Foo|bar(#this);
74+
static extension-type-member method Bar|constructor#(core::int i) → self::Bar% /* erasure=core::int, declared=! */ {
75+
lowered final self::Bar% /* erasure=core::int, declared=! */ #this = i;
76+
return #this;
77+
}
78+
static extension-type-member method Bar|constructor#_#new#tearOff(core::int i) → self::Bar% /* erasure=core::int, declared=! */
79+
return self::Bar|constructor#(i);
80+
static extension-type-member method Bar|set#foo(lowered final self::Bar% /* erasure=core::int, declared=! */ #this, dynamic #synthetic) → void {
81+
invalid-expression "pkg/front_end/testcases/regress/erroneous_setter.dart:18:10: Error: A setter should have exactly one formal parameter.
82+
set foo({final newFoo}) {
83+
^";
84+
{
85+
final dynamic newFoo = null;
86+
{
87+
core::print(self::Bar|get#foo(#this));
88+
}
89+
}
90+
}
91+
static extension-type-member method Bar|get#foo(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → core::int
92+
return 42;
93+
static extension-type-member method Bar|bar(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → void {
94+
let final core::int #t3 = self::Bar|get#foo(#this).{core::num::-}(1){(core::num) → core::int} in let final void #t4 = self::Bar|set#foo(#this, #t3) in #t3;
95+
}
96+
static extension-type-member method Bar|get#bar(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → () → void
97+
return () → void => self::Bar|bar(#this);
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/erroneous_setter.dart:6:10: Error: A setter should have exactly one formal parameter.
6+
// set foo({final newFoo}) {
7+
// ^
8+
//
9+
// pkg/front_end/testcases/regress/erroneous_setter.dart:18:10: Error: A setter should have exactly one formal parameter.
10+
// set foo({final newFoo}) {
11+
// ^
12+
//
13+
// pkg/front_end/testcases/regress/erroneous_setter.dart:30:10: Error: A setter should have exactly one formal parameter.
14+
// set foo({final newFoo}) {
15+
// ^
16+
//
17+
import self as self;
18+
import "dart:core" as core;
19+
20+
class Baz extends core::Object {
21+
synthetic constructor •() → self::Baz
22+
: super core::Object::•()
23+
;
24+
set foo(dynamic #synthetic) → void {
25+
invalid-expression "pkg/front_end/testcases/regress/erroneous_setter.dart:30:10: Error: A setter should have exactly one formal parameter.
26+
set foo({final newFoo}) {
27+
^";
28+
{
29+
final dynamic newFoo = null;
30+
{
31+
core::print(this.{self::Baz::foo}{core::int});
32+
}
33+
}
34+
}
35+
get foo() → core::int
36+
return 42;
37+
method bar() → void {
38+
this.{self::Baz::foo} = this.{self::Baz::foo}{core::int}.{core::num::-}(1){(core::num) → core::int};
39+
}
40+
}
41+
extension Foo on core::int {
42+
get foo = self::Foo|get#foo;
43+
method bar = self::Foo|bar;
44+
method tearoff bar = self::Foo|get#bar;
45+
set foo = self::Foo|set#foo;
46+
}
47+
extension type Bar(core::int i) {
48+
abstract extension-type-member representation-field get i() → core::int;
49+
get foo = self::Bar|get#foo;
50+
method bar = self::Bar|bar;
51+
method tearoff bar = self::Bar|get#bar;
52+
set foo = self::Bar|set#foo;
53+
constructor • = self::Bar|constructor#;
54+
constructor tearoff • = self::Bar|constructor#_#new#tearOff;
55+
}
56+
static extension-member method Foo|set#foo(lowered final core::int #this, dynamic #synthetic) → void {
57+
invalid-expression "pkg/front_end/testcases/regress/erroneous_setter.dart:6:10: Error: A setter should have exactly one formal parameter.
58+
set foo({final newFoo}) {
59+
^";
60+
{
61+
final dynamic newFoo = null;
62+
{
63+
core::print(self::Foo|get#foo(#this));
64+
}
65+
}
66+
}
67+
static extension-member method Foo|get#foo(lowered final core::int #this) → core::int
68+
return 42;
69+
static extension-member method Foo|bar(lowered final core::int #this) → void {
70+
let final core::int #t1 = self::Foo|get#foo(#this).{core::num::-}(1){(core::num) → core::int} in let final void #t2 = self::Foo|set#foo(#this, #t1) in #t1;
71+
}
72+
static extension-member method Foo|get#bar(lowered final core::int #this) → () → void
73+
return () → void => self::Foo|bar(#this);
74+
static extension-type-member method Bar|constructor#(core::int i) → self::Bar% /* erasure=core::int, declared=! */ {
75+
lowered final self::Bar% /* erasure=core::int, declared=! */ #this = i;
76+
return #this;
77+
}
78+
static extension-type-member method Bar|constructor#_#new#tearOff(core::int i) → self::Bar% /* erasure=core::int, declared=! */
79+
return self::Bar|constructor#(i);
80+
static extension-type-member method Bar|set#foo(lowered final self::Bar% /* erasure=core::int, declared=! */ #this, dynamic #synthetic) → void {
81+
invalid-expression "pkg/front_end/testcases/regress/erroneous_setter.dart:18:10: Error: A setter should have exactly one formal parameter.
82+
set foo({final newFoo}) {
83+
^";
84+
{
85+
final dynamic newFoo = null;
86+
{
87+
core::print(self::Bar|get#foo(#this));
88+
}
89+
}
90+
}
91+
static extension-type-member method Bar|get#foo(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → core::int
92+
return 42;
93+
static extension-type-member method Bar|bar(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → void {
94+
let final core::int #t3 = self::Bar|get#foo(#this).{core::num::-}(1){(core::num) → core::int} in let final void #t4 = self::Bar|set#foo(#this, #t3) in #t3;
95+
}
96+
static extension-type-member method Bar|get#bar(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → () → void
97+
return () → void => self::Bar|bar(#this);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
class Baz extends core::Object {
6+
synthetic constructor •() → self::Baz
7+
;
8+
set foo(dynamic #synthetic) → void
9+
;
10+
get foo() → core::int
11+
;
12+
method bar() → void
13+
;
14+
}
15+
extension Foo on core::int {
16+
get foo = self::Foo|get#foo;
17+
method bar = self::Foo|bar;
18+
method tearoff bar = self::Foo|get#bar;
19+
set foo = self::Foo|set#foo;
20+
}
21+
extension type Bar(core::int i) {
22+
abstract extension-type-member representation-field get i() → core::int;
23+
get foo = self::Bar|get#foo;
24+
method bar = self::Bar|bar;
25+
method tearoff bar = self::Bar|get#bar;
26+
set foo = self::Bar|set#foo;
27+
constructor • = self::Bar|constructor#;
28+
constructor tearoff • = self::Bar|constructor#_#new#tearOff;
29+
}
30+
static extension-member method Foo|set#foo(lowered final core::int #this, dynamic #synthetic) → void
31+
;
32+
static extension-member method Foo|get#foo(lowered final core::int #this) → core::int
33+
;
34+
static extension-member method Foo|bar(lowered final core::int #this) → void
35+
;
36+
static extension-member method Foo|get#bar(lowered final core::int #this) → () → void
37+
return () → void => self::Foo|bar(#this);
38+
static extension-type-member method Bar|constructor#(core::int i) → self::Bar% /* erasure=core::int, declared=! */
39+
;
40+
static extension-type-member method Bar|constructor#_#new#tearOff(core::int i) → self::Bar% /* erasure=core::int, declared=! */
41+
return self::Bar|constructor#(i);
42+
static extension-type-member method Bar|set#foo(lowered final self::Bar% /* erasure=core::int, declared=! */ #this, dynamic #synthetic) → void
43+
;
44+
static extension-type-member method Bar|get#foo(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → core::int
45+
;
46+
static extension-type-member method Bar|bar(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → void
47+
;
48+
static extension-type-member method Bar|get#bar(lowered final self::Bar% /* erasure=core::int, declared=! */ #this) → () → void
49+
return () → void => self::Bar|bar(#this);

0 commit comments

Comments
 (0)