Skip to content

Commit

Permalink
[cfe] Add ExtensionTypeRepresentationFieldInitializer.replaceChild
Browse files Browse the repository at this point in the history
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

Change-Id: I421f182192aae17f4bd3dcfe6d8216befde0e93e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/357161
Reviewed-by: Johnni Winther <[email protected]>
Commit-Queue: Chloe Stefantsova <[email protected]>
  • Loading branch information
chloestefantsova authored and Commit Queue committed Mar 13, 2024
1 parent c506bb8 commit ef6d68c
Show file tree
Hide file tree
Showing 19 changed files with 641 additions and 5 deletions.
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 @@ -350,11 +350,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 @@ -3374,6 +3369,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 /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* erasure=self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* erasure=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 /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* erasure=self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* erasure=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,16 @@
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,16 @@
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 /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* erasure=self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* erasure=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 /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* erasure=self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* erasure=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 /* erasure=self::A */
;
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* erasure=self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* erasure=self::A */
;
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* erasure=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 /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = point;
return #this;
}
static extension-type-member method C|constructor#_#_#tearOff(self::A point) → self::C /* erasure=self::A */
return self::C|constructor#_(point);
static extension-type-member method C|constructor#() → self::C /* erasure=self::A */ {
lowered final self::C /* erasure=self::A */ #this = new self::B::•();
return #this;
}
static extension-type-member method C|constructor#_#new#tearOff() → self::C /* erasure=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 ef6d68c

Please sign in to comment.