Skip to content

Commit

Permalink
[stable][cfe] Add ExtensionTypeRepresentationFieldInitializer.replace…
Browse files Browse the repository at this point in the history
…Child

The added method is required for the resolution of redirection targets
to work: it replaces the immediate target invocation node with the
final target invocation node.

Closes #55135

Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/357161
Cherry-pick-request: #55194
Change-Id: I96643c5af0ca91209cd936aee78f13c416679275
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357600
Commit-Queue: Chloe Stefantsova <[email protected]>
Reviewed-by: Johnni Winther <[email protected]>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Mar 19, 2024
1 parent 99b7157 commit 6afc2d7
Show file tree
Hide file tree
Showing 20 changed files with 636 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ This is a patch release that:
incremental compiler whenever it restored a typedef from dill such that the
typedef contained a generic function type on its right-hand side (issue
[#55158][]).
- Fixes an issue in the CFE that prevented redirecting factories from being
resolved in initializers of extension types (issue [#55194][]).

[#55158]: https://github.com/dart-lang/sdk/issues/55158
[#55194]: https://github.com/dart-lang/sdk/issues/55194

## 3.3.1 - 2024-03-06

Expand Down
10 changes: 5 additions & 5 deletions pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,6 @@ abstract class InternalExpression extends AuxiliaryExpression {

/// Common base class for internal initializers.
abstract class InternalInitializer extends AuxiliaryInitializer {
@override
void replaceChild(TreeNode child, TreeNode replacement) {
// Do nothing. The node should not be part of the resulting AST, anyway.
}

@override
void visitChildren(Visitor<dynamic> v) =>
unsupported("${runtimeType}.visitChildren", -1, null);
Expand Down Expand Up @@ -3452,6 +3447,11 @@ class ExtensionTypeRepresentationFieldInitializer extends InternalInitializer {
value.parent = this;
}

@override
void transformChildren(Transformer v) {
value = v.transform(value)..parent = this;
}

/// [Procedure] that represents the representation field.
Procedure get field => fieldReference.asProcedure;

Expand Down
26 changes: 26 additions & 0 deletions pkg/front_end/testcases/dart2js/issue55135.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

class B implements A {
final int x = 1;
}
abstract class A {
int get x;
factory A() = B;
}

extension type C._(A point) implements A {
C() : point = A(); // << initializer is redirecting factory
}

void main() {
expectEquals(A().x, 1);
expectEquals(C().x, 1);
}

expectEquals(x, y) {
if (x != y) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
47 changes: 47 additions & 0 deletions pkg/front_end/testcases/dart2js/issue55135.dart.strong.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library;
import self as self;
import "dart:core" as core;

class B extends core::Object implements self::A {
final field core::int x = 1;
synthetic constructor •() → self::B
: super core::Object::•()
;
static method _#new#tearOff() → self::B
return new self::B::•();
}
abstract class A extends core::Object {
abstract get x() → core::int;
static factory •() → self::A /* redirection-target: self::B::• */
return new self::B::•();
static method _#new#tearOff() → self::A
return new self::B::•();
}
extension type C(self::A point) implements self::A {
abstract extension-type-member representation-field get point() → self::A;
constructor _ = self::C|constructor#_;
constructor tearoff _ = self::C|constructor#_#_#tearOff;
constructor • = self::C|constructor#;
constructor tearoff • = self::C|constructor#_#new#tearOff;
}
static extension-type-member method C|constructor#_(self::A point) → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* = self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* = self::A */
return self::C|constructor#();
static method main() → void {
self::expectEquals(new self::B::•().{self::A::x}{core::int}, 1);
self::expectEquals(self::C|constructor#().{self::A::x}{core::int}, 1);
}
static method expectEquals(dynamic x, dynamic y) → dynamic {
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library;
import self as self;
import "dart:core" as core;

class B extends core::Object implements self::A {
final field core::int x = 1;
synthetic constructor •() → self::B
: super core::Object::•()
;
static method _#new#tearOff() → self::B
return new self::B::•();
}
abstract class A extends core::Object {
abstract get x() → core::int;
static factory •() → self::A /* redirection-target: self::B::• */
return new self::B::•();
static method _#new#tearOff() → self::A
return new self::B::•();
}
extension type C(self::A point) implements self::A {
abstract extension-type-member representation-field get point() → self::A;
constructor _ = self::C|constructor#_;
constructor tearoff _ = self::C|constructor#_#_#tearOff;
constructor • = self::C|constructor#;
constructor tearoff • = self::C|constructor#_#new#tearOff;
}
static extension-type-member method C|constructor#_(self::A point) → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* = self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* = self::A */
return self::C|constructor#();
static method main() → void {
self::expectEquals(new self::B::•().{self::A::x}{core::int}, 1);
self::expectEquals(self::C|constructor#().{self::A::x}{core::int}, 1);
}
static method expectEquals(dynamic x, dynamic y) → dynamic {
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class B implements A {
final int x = 1;
}

abstract class A {
int get x;
factory A() = B;
}

extension type C._(A point) implements A {
C() : point = A();
}
void main() {}
expectEquals(x, y) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
abstract class A {
factory A() = B;
int get x;
}

class B implements A {
final int x = 1;
}

expectEquals(x, y) {}
extension type C._(A point) implements A {
C() : point = A();
}
void main() {}
47 changes: 47 additions & 0 deletions pkg/front_end/testcases/dart2js/issue55135.dart.weak.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library;
import self as self;
import "dart:core" as core;

class B extends core::Object implements self::A {
final field core::int x = 1;
synthetic constructor •() → self::B
: super core::Object::•()
;
static method _#new#tearOff() → self::B
return new self::B::•();
}
abstract class A extends core::Object {
abstract get x() → core::int;
static factory •() → self::A /* redirection-target: self::B::• */
return new self::B::•();
static method _#new#tearOff() → self::A
return new self::B::•();
}
extension type C(self::A point) implements self::A {
abstract extension-type-member representation-field get point() → self::A;
constructor _ = self::C|constructor#_;
constructor tearoff _ = self::C|constructor#_#_#tearOff;
constructor • = self::C|constructor#;
constructor tearoff • = self::C|constructor#_#new#tearOff;
}
static extension-type-member method C|constructor#_(self::A point) → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* = self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* = self::A */
return self::C|constructor#();
static method main() → void {
self::expectEquals(new self::B::•().{self::A::x}{core::int}, 1);
self::expectEquals(self::C|constructor#().{self::A::x}{core::int}, 1);
}
static method expectEquals(dynamic x, dynamic y) → dynamic {
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library;
import self as self;
import "dart:core" as core;

class B extends core::Object implements self::A {
final field core::int x = 1;
synthetic constructor •() → self::B
: super core::Object::•()
;
static method _#new#tearOff() → self::B
return new self::B::•();
}
abstract class A extends core::Object {
abstract get x() → core::int;
static factory •() → self::A /* redirection-target: self::B::• */
return new self::B::•();
static method _#new#tearOff() → self::A
return new self::B::•();
}
extension type C(self::A point) implements self::A {
abstract extension-type-member representation-field get point() → self::A;
constructor _ = self::C|constructor#_;
constructor tearoff _ = self::C|constructor#_#_#tearOff;
constructor • = self::C|constructor#;
constructor tearoff • = self::C|constructor#_#new#tearOff;
}
static extension-type-member method C|constructor#_(self::A point) → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* = self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* = self::A */
return self::C|constructor#();
static method main() → void {
self::expectEquals(new self::B::•().{self::A::x}{core::int}, 1);
self::expectEquals(self::C|constructor#().{self::A::x}{core::int}, 1);
}
static method expectEquals(dynamic x, dynamic y) → dynamic {
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
library;
import self as self;
import "dart:core" as core;

class B extends core::Object implements self::A {
final field core::int x;
synthetic constructor •() → self::B
;
static method _#new#tearOff() → self::B
return new self::B::•();
}
abstract class A extends core::Object {
abstract get x() → core::int;
static factory •() → self::A /* redirection-target: self::B::• */
return new self::B::•();
static method _#new#tearOff() → self::A
return new self::B::•();
}
extension type C(self::A point) implements self::A {
abstract extension-type-member representation-field get point() → self::A;
constructor _ = self::C|constructor#_;
constructor tearoff _ = self::C|constructor#_#_#tearOff;
constructor • = self::C|constructor#;
constructor tearoff • = self::C|constructor#_#new#tearOff;
}
static extension-type-member method C|constructor#_(self::A point) → self::C /* = self::A */
;
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* = self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* = self::A */
;
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* = self::A */
return self::C|constructor#();
static method main() → void
;
static method expectEquals(dynamic x, dynamic y) → dynamic
;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
library;
import self as self;
import "dart:core" as core;

class B extends core::Object implements self::A {
final field core::int x = 1;
synthetic constructor •() → self::B
: super core::Object::•()
;
static method _#new#tearOff() → self::B
return new self::B::•();
}
abstract class A extends core::Object {
abstract get x() → core::int;
static factory •() → self::A /* redirection-target: self::B::• */
return new self::B::•();
static method _#new#tearOff() → self::A
return new self::B::•();
}
extension type C(self::A point) implements self::A {
abstract extension-type-member representation-field get point() → self::A;
constructor _ = self::C|constructor#_;
constructor tearoff _ = self::C|constructor#_#_#tearOff;
constructor • = self::C|constructor#;
constructor tearoff • = self::C|constructor#_#new#tearOff;
}
static extension-type-member method C|constructor#_(self::A point) → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* = self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* = self::A */ {
lowered final self::C /* = self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* = self::A */
return self::C|constructor#();
static method main() → void {
self::expectEquals(new self::B::•().{self::A::x}{core::int}, 1);
self::expectEquals(self::C|constructor#().{self::A::x}{core::int}, 1);
}
static method expectEquals(dynamic x, dynamic y) → dynamic {
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
26 changes: 26 additions & 0 deletions pkg/front_end/testcases/extension_types/issue55135.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

class B implements A {
final int x = 1;
}
abstract class A {
int get x;
factory A() = B;
}

extension type C._(A point) implements A {
C() : point = A(); // << initializer is redirecting factory
}

void main() {
expectEquals(A().x, 1);
expectEquals(C().x, 1);
}

expectEquals(x, y) {
if (x != y) {
throw "Expected equal values, got '${x}' and '${y}'.";
}
}
Loading

0 comments on commit 6afc2d7

Please sign in to comment.