Skip to content

Commit 4ef1fd4

Browse files
jensjohaCommit Queue
authored andcommitted
[CFE] Fix even more crashes on invalid this references
Change-Id: Id7d594f52b0344dd5d3e41e683594cbd213e96b9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396001 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent 3b8e8df commit 4ef1fd4

File tree

47 files changed

+1354
-12
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1354
-12
lines changed

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3198,7 +3198,10 @@ class BodyBuilder extends StackListenerImpl
31983198
}
31993199
if (declaration != null &&
32003200
declaration.isDeclarationInstanceMember &&
3201-
(inFieldInitializer && !inLateFieldInitializer) &&
3201+
(inFieldInitializer &&
3202+
(!inLateFieldInitializer ||
3203+
_context.isExtensionDeclaration ||
3204+
_context.isExtensionTypeDeclaration)) &&
32023205
!inInitializerLeftHandSide) {
32033206
// We cannot access a class instance member in an initializer of a
32043207
// field.
@@ -3210,6 +3213,8 @@ class BodyBuilder extends StackListenerImpl
32103213
// int bar;
32113214
// }
32123215
//
3216+
// We can if it's late, but not if we're in an extension (type), even if
3217+
// it's late.
32133218
return new IncompleteErrorGenerator(this, nameToken,
32143219
cfe.templateThisAccessInFieldInitializer.withArguments(name));
32153220
}
@@ -3232,6 +3237,11 @@ class BodyBuilder extends StackListenerImpl
32323237
// implicit access on the 'this' parameter.
32333238
return PropertyAccessGenerator.make(this, nameToken,
32343239
createVariableGet(thisVariable!, nameOffset), n, false);
3240+
} else if (_context.isExtensionDeclaration ||
3241+
_context.isExtensionTypeDeclaration) {
3242+
// In an extension (type) without a this variable.
3243+
return new UnresolvedNameGenerator(this, nameToken, n,
3244+
unresolvedReadKind: UnresolvedKind.Unknown);
32353245
} else {
32363246
// This is an implicit access on 'this'.
32373247
return new ThisPropertyAccessGenerator(this, nameToken, n,
@@ -3305,9 +3315,16 @@ class BodyBuilder extends StackListenerImpl
33053315
thisVariable: inConstructorInitializer ? null : thisVariable);
33063316
} else if (declaration.isExtensionInstanceMember) {
33073317
// TODO(johnniwinther): Better check for constantContext like below/above?
3318+
// Possibly if the is a non-none constant context it's just a no without
3319+
// additional checks?
33083320
if (constantContext != ConstantContext.none && thisVariable == null) {
33093321
return new IncompleteErrorGenerator(
33103322
this, nameToken, cfe.messageNotAConstantExpression);
3323+
} else if (constantContext != ConstantContext.none &&
3324+
!inInitializerLeftHandSide &&
3325+
!_context.isConstructor) {
3326+
return new IncompleteErrorGenerator(
3327+
this, nameToken, cfe.messageNotAConstantExpression);
33113328
}
33123329
ExtensionBuilder extensionBuilder =
33133330
declaration.parent as ExtensionBuilder;
@@ -7190,6 +7207,12 @@ class BodyBuilder extends StackListenerImpl
71907207
push(_createReadOnlyVariableAccess(thisVariable!, token,
71917208
offsetForToken(token), 'this', ReadOnlyAccessKind.ExtensionThis));
71927209
}
7210+
} else if ((!inConstructorInitializer || !inInitializerLeftHandSide) &&
7211+
(_context.isExtensionDeclaration ||
7212+
_context.isExtensionTypeDeclaration)) {
7213+
// In an extension (type) where we don't (here) have a "this" variable.
7214+
push(new IncompleteErrorGenerator(
7215+
this, token, cfe.messageThisAsIdentifier));
71937216
} else {
71947217
push(new ThisAccessGenerator(this, token, inInitializerLeftHandSide,
71957218
inFieldInitializer, inLateFieldInitializer));

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ abstract class BodyBuilderContext {
115115
/// Returns `true` if the enclosing class in an augmenting class.
116116
bool get isAugmentationClass => _declarationContext.isAugmentationClass;
117117

118+
/// Returns `true` if the enclosing entity is an extension type.
119+
bool get isExtensionTypeDeclaration =>
120+
_declarationContext.isExtensionTypeDeclaration;
121+
122+
/// Returns `true` if the enclosing entity is an extension.
123+
bool get isExtensionDeclaration => _declarationContext.isExtensionDeclaration;
124+
118125
/// Looks up the static member by the given [name] in the origin of the
119126
/// enclosing declaration.
120127
Builder? lookupStaticOriginMember(String name, int fileOffset, Uri fileUri) {
@@ -409,6 +416,11 @@ abstract class BodyBuilderDeclarationContext {
409416

410417
bool get isAugmentationClass => false;
411418

419+
bool get isExtensionTypeDeclaration => false;
420+
421+
// Coverage-ignore(suite): Not run.
422+
bool get isExtensionDeclaration => false;
423+
412424
Builder? lookupStaticOriginMember(String name, int fileOffset, Uri fileUri) {
413425
throw new UnsupportedError('${runtimeType}.lookupStaticOriginMember');
414426
}
@@ -449,6 +461,9 @@ mixin _DeclarationBodyBuilderDeclarationContextMixin
449461

450462
@override
451463
InterfaceType? get thisType => _declarationBuilder.thisType;
464+
465+
@override
466+
bool get isExtensionDeclaration => _declarationBuilder.isExtension;
452467
}
453468

454469
class _SourceClassBodyBuilderDeclarationContext
@@ -606,6 +621,9 @@ class _SourceExtensionTypeDeclarationBodyBuilderDeclarationContext
606621
String get className {
607622
return _sourceExtensionTypeDeclarationBuilder.fullNameForErrors;
608623
}
624+
625+
@override
626+
bool get isExtensionTypeDeclaration => true;
609627
}
610628

611629
class _DeclarationBodyBuilderDeclarationContext

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3479,7 +3479,6 @@ class OutlineBuilder extends StackListenerImpl {
34793479
}
34803480

34813481
if (inConstructorName) {
3482-
// Coverage-ignore-block(suite): Not run.
34833482
addProblem(messageConstructorWithTypeParameters,
34843483
offsetForToken(beginToken), lengthOfSpan(beginToken, endToken));
34853484
inConstructorName = false;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2138,7 +2138,6 @@ class RepresentationFieldEncoding implements FieldEncoding {
21382138
const <ClassMember>[];
21392139

21402140
@override
2141-
// Coverage-ignore(suite): Not run.
21422141
void buildImplicitDefaultValue() {
21432142
// Not needed.
21442143
}

pkg/front_end/test/coverage_suite_expected.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
205205
),
206206
// 100.0%.
207207
"package:front_end/src/base/processed_options.dart": (
208-
hitCount: 261,
208+
hitCount: 260,
209209
missCount: 0,
210210
),
211211
// 100.0%.
@@ -290,7 +290,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
290290
),
291291
// 100.0%.
292292
"package:front_end/src/builder/formal_parameter_builder.dart": (
293-
hitCount: 186,
293+
hitCount: 188,
294294
missCount: 0,
295295
),
296296
// 100.0%.
@@ -560,12 +560,12 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
560560
),
561561
// 100.0%.
562562
"package:front_end/src/kernel/body_builder.dart": (
563-
hitCount: 7147,
563+
hitCount: 7173,
564564
missCount: 0,
565565
),
566566
// 100.0%.
567567
"package:front_end/src/kernel/body_builder_context.dart": (
568-
hitCount: 346,
568+
hitCount: 357,
569569
missCount: 0,
570570
),
571571
// 100.0%.
@@ -870,7 +870,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
870870
),
871871
// 100.0%.
872872
"package:front_end/src/source/outline_builder.dart": (
873-
hitCount: 2122,
873+
hitCount: 2126,
874874
missCount: 0,
875875
),
876876
// 100.0%.
@@ -900,7 +900,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
900900
),
901901
// 100.0%.
902902
"package:front_end/src/source/source_constructor_builder.dart": (
903-
hitCount: 894,
903+
hitCount: 895,
904904
missCount: 0,
905905
),
906906
// 100.0%.
@@ -926,12 +926,12 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
926926
),
927927
// 100.0%.
928928
"package:front_end/src/source/source_field_builder.dart": (
929-
hitCount: 1245,
929+
hitCount: 1246,
930930
missCount: 0,
931931
),
932932
// 100.0%.
933933
"package:front_end/src/source/source_function_builder.dart": (
934-
hitCount: 314,
934+
hitCount: 316,
935935
missCount: 0,
936936
),
937937
// 100.0%.
@@ -941,7 +941,7 @@ const Map<String, ({int hitCount, int missCount})> _expect = {
941941
),
942942
// 100.0%.
943943
"package:front_end/src/source/source_loader.dart": (
944-
hitCount: 1855,
944+
hitCount: 1857,
945945
missCount: 0,
946946
),
947947
// 100.0%.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 type Foo(dynamic d) {
6+
// Bad
7+
var foo = this();
8+
9+
bar() {
10+
// OK
11+
return this;
12+
}
13+
}
14+
15+
class FooClass {
16+
// Bad
17+
var foo = this();
18+
19+
bar() {
20+
// OK
21+
return this;
22+
}
23+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:7:7: Error: Extension types can't declare instance fields
6+
// Try removing the field declaration or making it a static field
7+
// var foo = this();
8+
// ^^^
9+
//
10+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:7:13: Error: Expected identifier, but got 'this'.
11+
// var foo = this();
12+
// ^^^^
13+
//
14+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:17:13: Error: The method 'call' isn't defined for the class 'FooClass'.
15+
// - 'FooClass' is from 'pkg/front_end/testcases/regress/invalid_this_reference_07.dart'.
16+
// Try correcting the name to the name of an existing method, or defining a method named 'call'.
17+
// var foo = this();
18+
// ^
19+
//
20+
import self as self;
21+
import "dart:core" as core;
22+
23+
class FooClass extends core::Object {
24+
field dynamic foo = invalid-expression "pkg/front_end/testcases/regress/invalid_this_reference_07.dart:17:13: Error: The method 'call' isn't defined for the class 'FooClass'.
25+
- 'FooClass' is from 'pkg/front_end/testcases/regress/invalid_this_reference_07.dart'.
26+
Try correcting the name to the name of an existing method, or defining a method named 'call'.
27+
var foo = this();
28+
^" in this{<unresolved>}.call();
29+
synthetic constructor •() → self::FooClass
30+
: super core::Object::•()
31+
;
32+
method bar() → dynamic {
33+
return this;
34+
}
35+
}
36+
extension type Foo(dynamic d) {
37+
abstract extension-type-member representation-field get d() → dynamic;
38+
abstract extension-type-member representation-field get foo() → invalid-type;
39+
method bar = self::Foo|bar;
40+
method tearoff bar = self::Foo|get#bar;
41+
constructor • = self::Foo|constructor#;
42+
constructor tearoff • = self::Foo|constructor#_#new#tearOff;
43+
}
44+
static extension-type-member method Foo|constructor#(dynamic d) → self::Foo% /* erasure=dynamic, declared=! */ {
45+
lowered final self::Foo% /* erasure=dynamic, declared=! */ #this = d;
46+
return #this;
47+
}
48+
static extension-type-member method Foo|constructor#_#new#tearOff(dynamic d) → self::Foo% /* erasure=dynamic, declared=! */
49+
return self::Foo|constructor#(d);
50+
static extension-type-member method Foo|bar(lowered final self::Foo% /* erasure=dynamic, declared=! */ #this) → dynamic {
51+
return #this;
52+
}
53+
static extension-type-member method Foo|get#bar(lowered final self::Foo% /* erasure=dynamic, declared=! */ #this) → () → dynamic
54+
return () → dynamic => self::Foo|bar(#this);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:7:7: Error: Extension types can't declare instance fields
6+
// Try removing the field declaration or making it a static field
7+
// var foo = this();
8+
// ^^^
9+
//
10+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:7:13: Error: Expected identifier, but got 'this'.
11+
// var foo = this();
12+
// ^^^^
13+
//
14+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:17:13: Error: The method 'call' isn't defined for the class 'FooClass'.
15+
// - 'FooClass' is from 'pkg/front_end/testcases/regress/invalid_this_reference_07.dart'.
16+
// Try correcting the name to the name of an existing method, or defining a method named 'call'.
17+
// var foo = this();
18+
// ^
19+
//
20+
import self as self;
21+
import "dart:core" as core;
22+
23+
class FooClass extends core::Object {
24+
field dynamic foo = invalid-expression "pkg/front_end/testcases/regress/invalid_this_reference_07.dart:17:13: Error: The method 'call' isn't defined for the class 'FooClass'.
25+
- 'FooClass' is from 'pkg/front_end/testcases/regress/invalid_this_reference_07.dart'.
26+
Try correcting the name to the name of an existing method, or defining a method named 'call'.
27+
var foo = this();
28+
^" in this{<unresolved>}.call();
29+
synthetic constructor •() → self::FooClass
30+
: super core::Object::•()
31+
;
32+
method bar() → dynamic {
33+
return this;
34+
}
35+
}
36+
extension type Foo(dynamic d) {
37+
abstract extension-type-member representation-field get d() → dynamic;
38+
abstract extension-type-member representation-field get foo() → invalid-type;
39+
method bar = self::Foo|bar;
40+
method tearoff bar = self::Foo|get#bar;
41+
constructor • = self::Foo|constructor#;
42+
constructor tearoff • = self::Foo|constructor#_#new#tearOff;
43+
}
44+
static extension-type-member method Foo|constructor#(dynamic d) → self::Foo% /* erasure=dynamic, declared=! */ {
45+
lowered final self::Foo% /* erasure=dynamic, declared=! */ #this = d;
46+
return #this;
47+
}
48+
static extension-type-member method Foo|constructor#_#new#tearOff(dynamic d) → self::Foo% /* erasure=dynamic, declared=! */
49+
return self::Foo|constructor#(d);
50+
static extension-type-member method Foo|bar(lowered final self::Foo% /* erasure=dynamic, declared=! */ #this) → dynamic {
51+
return #this;
52+
}
53+
static extension-type-member method Foo|get#bar(lowered final self::Foo% /* erasure=dynamic, declared=! */ #this) → () → dynamic
54+
return () → dynamic => self::Foo|bar(#this);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
library;
2+
//
3+
// Problems in library:
4+
//
5+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:7:7: Error: Extension types can't declare instance fields
6+
// Try removing the field declaration or making it a static field
7+
// var foo = this();
8+
// ^^^
9+
//
10+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:7:13: Error: Expected identifier, but got 'this'.
11+
// var foo = this();
12+
// ^^^^
13+
//
14+
// pkg/front_end/testcases/regress/invalid_this_reference_07.dart:17:13: Error: The method 'call' isn't defined for the class 'FooClass'.
15+
// - 'FooClass' is from 'pkg/front_end/testcases/regress/invalid_this_reference_07.dart'.
16+
// Try correcting the name to the name of an existing method, or defining a method named 'call'.
17+
// var foo = this();
18+
// ^
19+
//
20+
import self as self;
21+
import "dart:core" as core;
22+
23+
class FooClass extends core::Object {
24+
field dynamic foo;
25+
synthetic constructor •() → self::FooClass
26+
;
27+
method bar() → dynamic
28+
;
29+
}
30+
extension type Foo(dynamic d) {
31+
abstract extension-type-member representation-field get d() → dynamic;
32+
abstract extension-type-member representation-field get foo() → invalid-type;
33+
method bar = self::Foo|bar;
34+
method tearoff bar = self::Foo|get#bar;
35+
constructor • = self::Foo|constructor#;
36+
constructor tearoff • = self::Foo|constructor#_#new#tearOff;
37+
}
38+
static extension-type-member method Foo|constructor#(dynamic d) → self::Foo% /* erasure=dynamic, declared=! */
39+
;
40+
static extension-type-member method Foo|constructor#_#new#tearOff(dynamic d) → self::Foo% /* erasure=dynamic, declared=! */
41+
return self::Foo|constructor#(d);
42+
static extension-type-member method Foo|bar(lowered final self::Foo% /* erasure=dynamic, declared=! */ #this) → dynamic
43+
;
44+
static extension-type-member method Foo|get#bar(lowered final self::Foo% /* erasure=dynamic, declared=! */ #this) → () → dynamic
45+
return () → dynamic => self::Foo|bar(#this);

0 commit comments

Comments
 (0)