Skip to content

Commit 6822837

Browse files
johnniwintherwhesse
authored andcommitted
[cp][cfe] Use effective target in redirecting factory tear off lowering
The tear-off lowering for a redirecting factory called the immediate target (even when this was also a redirecting factory) instead of the effective target. This caused problem in backends that don't support redirecting factories directly. Closes #47916 Change-Id: I708c59dae9d210e0eb6dab4d01c6a044f6b2fd00
1 parent 0180af2 commit 6822837

File tree

56 files changed

+1955
-7
lines changed

Some content is hidden

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

56 files changed

+1955
-7
lines changed

pkg/front_end/lib/src/fasta/builder/factory_builder.dart

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,14 @@ class RedirectingFactoryBuilder extends SourceFactoryBuilder {
396396
inferrer.helper = library.loader.createBodyBuilderForOutlineExpression(
397397
library, classBuilder, this, classBuilder!.scope, fileUri);
398398
Builder? targetBuilder = redirectionTarget.target;
399+
if (targetBuilder is MemberBuilder) {
400+
// Ensure that target has been built.
401+
targetBuilder.buildOutlineExpressions(
402+
targetBuilder.library as SourceLibraryBuilder,
403+
coreTypes,
404+
delayedActionPerformers,
405+
synthesizedFunctionNodes);
406+
}
399407
if (targetBuilder is FunctionBuilder) {
400408
target = targetBuilder.member;
401409
} else if (targetBuilder is DillMemberBuilder) {
@@ -446,13 +454,33 @@ class RedirectingFactoryBuilder extends SourceFactoryBuilder {
446454
new RedirectingFactoryBody(target, typeArguments, function);
447455
function.body!.parent = function;
448456
}
449-
if (_factoryTearOff != null &&
450-
(target is Constructor || target is Procedure && target.isFactory)) {
451-
synthesizedFunctionNodes.add(buildRedirectingFactoryTearOffBody(
452-
_factoryTearOff!,
453-
target!,
454-
typeArguments ?? [],
455-
_tearOffTypeParameters!));
457+
if (_factoryTearOff != null) {
458+
Set<Procedure> seenTargets = {};
459+
while (target is Procedure && target.isRedirectingFactory) {
460+
if (!seenTargets.add(target)) {
461+
// Cyclic dependency.
462+
target = null;
463+
break;
464+
}
465+
RedirectingFactoryBody body =
466+
target.function.body as RedirectingFactoryBody;
467+
if (typeArguments != null) {
468+
Substitution substitution = Substitution.fromPairs(
469+
target.function.typeParameters, typeArguments);
470+
typeArguments =
471+
body.typeArguments?.map(substitution.substituteType).toList();
472+
} else {
473+
typeArguments = body.typeArguments;
474+
}
475+
target = body.target;
476+
}
477+
if (target is Constructor || target is Procedure && target.isFactory) {
478+
synthesizedFunctionNodes.add(buildRedirectingFactoryTearOffBody(
479+
_factoryTearOff!,
480+
target!,
481+
typeArguments ?? [],
482+
_tearOffTypeParameters!));
483+
}
456484
}
457485
if (isConst && isPatch) {
458486
_finishPatch();
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) 2022, 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+
abstract class A {
6+
const factory A() = B;
7+
}
8+
9+
abstract class B implements A {
10+
const factory B() = C;
11+
}
12+
13+
class C implements B {
14+
const C();
15+
}
16+
17+
main() {
18+
A.new;
19+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
7+
static factory •() → self::A
8+
return self::B::•();
9+
static method _#new#tearOff() → self::A
10+
return new self::C::•();
11+
}
12+
abstract class B extends core::Object implements self::A {
13+
static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
14+
static factory •() → self::B
15+
return new self::C::•();
16+
static method _#new#tearOff() → self::B
17+
return new self::C::•();
18+
}
19+
class C extends core::Object implements self::B /*hasConstConstructor*/ {
20+
const constructor •() → self::C
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff() → self::C
24+
return new self::C::•();
25+
}
26+
static method main() → dynamic {
27+
#C3;
28+
}
29+
30+
constants {
31+
#C1 = constructor-tearoff self::A::•
32+
#C2 = constructor-tearoff self::B::•
33+
#C3 = static-tearoff self::A::_#new#tearOff
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
7+
static factory •() → self::A
8+
return self::B::•();
9+
static method _#new#tearOff() → self::A
10+
return new self::C::•();
11+
}
12+
abstract class B extends core::Object implements self::A {
13+
static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
14+
static factory •() → self::B
15+
return new self::C::•();
16+
static method _#new#tearOff() → self::B
17+
return new self::C::•();
18+
}
19+
class C extends core::Object implements self::B /*hasConstConstructor*/ {
20+
const constructor •() → self::C
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff() → self::C
24+
return new self::C::•();
25+
}
26+
static method main() → dynamic {
27+
#C3;
28+
}
29+
30+
constants {
31+
#C1 = constructor-tearoff self::A::•
32+
#C2 = constructor-tearoff self::B::•
33+
#C3 = static-tearoff self::A::_#new#tearOff
34+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
abstract class A {
2+
const factory A() = B;
3+
}
4+
5+
abstract class B implements A {
6+
const factory B() = C;
7+
}
8+
9+
class C implements B {
10+
const C();
11+
}
12+
13+
main() {}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
abstract class A {
2+
const factory A() = B;
3+
}
4+
5+
abstract class B implements A {
6+
const factory B() = C;
7+
}
8+
9+
class C implements B {
10+
const C();
11+
}
12+
13+
main() {}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
7+
static factory •() → self::A
8+
return self::B::•();
9+
static method _#new#tearOff() → self::A
10+
return new self::C::•();
11+
}
12+
abstract class B extends core::Object implements self::A {
13+
static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
14+
static factory •() → self::B
15+
return new self::C::•();
16+
static method _#new#tearOff() → self::B
17+
return new self::C::•();
18+
}
19+
class C extends core::Object implements self::B /*hasConstConstructor*/ {
20+
const constructor •() → self::C
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff() → self::C
24+
return new self::C::•();
25+
}
26+
static method main() → dynamic {
27+
#C3;
28+
}
29+
30+
constants {
31+
#C1 = constructor-tearoff self::A::•
32+
#C2 = constructor-tearoff self::B::•
33+
#C3 = static-tearoff self::A::_#new#tearOff
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
7+
static factory •() → self::A
8+
return self::B::•();
9+
static method _#new#tearOff() → self::A
10+
return new self::C::•();
11+
}
12+
abstract class B extends core::Object implements self::A {
13+
static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
14+
static factory •() → self::B
15+
return new self::C::•();
16+
static method _#new#tearOff() → self::B
17+
return new self::C::•();
18+
}
19+
class C extends core::Object implements self::B /*hasConstConstructor*/ {
20+
const constructor •() → self::C
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff() → self::C
24+
return new self::C::•();
25+
}
26+
static method main() → dynamic {
27+
#C3;
28+
}
29+
30+
constants {
31+
#C1 = constructor-tearoff self::A::•
32+
#C2 = constructor-tearoff self::B::•
33+
#C3 = static-tearoff self::A::_#new#tearOff
34+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[self::A::•]/*isLegacy*/;
7+
static factory •() → self::A
8+
return self::B::•();
9+
static method _#new#tearOff() → self::A
10+
return new self::C::•();
11+
}
12+
abstract class B extends core::Object implements self::A {
13+
static final field dynamic _redirecting# = <dynamic>[self::B::•]/*isLegacy*/;
14+
static factory •() → self::B
15+
return new self::C::•();
16+
static method _#new#tearOff() → self::B
17+
return new self::C::•();
18+
}
19+
class C extends core::Object implements self::B /*hasConstConstructor*/ {
20+
const constructor •() → self::C
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff() → self::C
24+
return new self::C::•();
25+
}
26+
static method main() → dynamic
27+
;
28+
29+
30+
Extra constant evaluation status:
31+
Evaluated: ConstructorTearOff @ org-dartlang-testcase:///issue47916.dart:5:16 -> ConstructorTearOffConstant(A.)
32+
Evaluated: ConstructorTearOff @ org-dartlang-testcase:///issue47916.dart:9:16 -> ConstructorTearOffConstant(B.)
33+
Extra constant evaluation: evaluated: 9, effectively constant: 2
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
7+
static factory •() → self::A
8+
return self::B::•();
9+
static method _#new#tearOff() → self::A
10+
return new self::C::•();
11+
}
12+
abstract class B extends core::Object implements self::A {
13+
static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
14+
static factory •() → self::B
15+
return new self::C::•();
16+
static method _#new#tearOff() → self::B
17+
return new self::C::•();
18+
}
19+
class C extends core::Object implements self::B /*hasConstConstructor*/ {
20+
const constructor •() → self::C
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff() → self::C
24+
return new self::C::•();
25+
}
26+
static method main() → dynamic {
27+
#C3;
28+
}
29+
30+
constants {
31+
#C1 = constructor-tearoff self::A::•
32+
#C2 = constructor-tearoff self::B::•
33+
#C3 = static-tearoff self::A::_#new#tearOff
34+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) 2022, 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+
abstract class A<T> {
6+
const factory A() = B;
7+
}
8+
9+
abstract class B<S, T> implements A<T> {
10+
const factory B() = C;
11+
}
12+
13+
class C<T, S, U> implements B<S, T> {
14+
const C();
15+
}
16+
17+
main() {
18+
A<int>.new;
19+
B<String, double>.new;
20+
C<bool, num, void>.new;
21+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A<T extends core::Object? = dynamic> extends core::Object {
6+
static final field dynamic _redirecting# = <dynamic>[#C1]/*isLegacy*/;
7+
static factory •<T extends core::Object? = dynamic>() → self::A<self::A::•::T%>
8+
return self::B::•<dynamic, self::A::•::T%>();
9+
static method _#new#tearOff<T extends core::Object? = dynamic>() → self::A<self::A::_#new#tearOff::T%>
10+
return new self::C::•<self::A::_#new#tearOff::T%, dynamic, dynamic>();
11+
}
12+
abstract class B<S extends core::Object? = dynamic, T extends core::Object? = dynamic> extends core::Object implements self::A<self::B::T%> {
13+
static final field dynamic _redirecting# = <dynamic>[#C2]/*isLegacy*/;
14+
static factory •<S extends core::Object? = dynamic, T extends core::Object? = dynamic>() → self::B<self::B::•::S%, self::B::•::T%>
15+
return new self::C::•<self::B::•::T%, self::B::•::S%, dynamic>();
16+
static method _#new#tearOff<S extends core::Object? = dynamic, T extends core::Object? = dynamic>() → self::B<self::B::_#new#tearOff::S%, self::B::_#new#tearOff::T%>
17+
return new self::C::•<self::B::_#new#tearOff::T%, self::B::_#new#tearOff::S%, dynamic>();
18+
}
19+
class C<T extends core::Object? = dynamic, S extends core::Object? = dynamic, U extends core::Object? = dynamic> extends core::Object implements self::B<self::C::S%, self::C::T%> /*hasConstConstructor*/ {
20+
const constructor •() → self::C<self::C::T%, self::C::S%, self::C::U%>
21+
: super core::Object::•()
22+
;
23+
static method _#new#tearOff<T extends core::Object? = dynamic, S extends core::Object? = dynamic, U extends core::Object? = dynamic>() → self::C<self::C::_#new#tearOff::T%, self::C::_#new#tearOff::S%, self::C::_#new#tearOff::U%>
24+
return new self::C::•<self::C::_#new#tearOff::T%, self::C::_#new#tearOff::S%, self::C::_#new#tearOff::U%>();
25+
}
26+
static method main() → dynamic {
27+
#C4;
28+
#C6;
29+
#C8;
30+
}
31+
32+
constants {
33+
#C1 = constructor-tearoff self::A::•
34+
#C2 = constructor-tearoff self::B::•
35+
#C3 = static-tearoff self::A::_#new#tearOff
36+
#C4 = instantiation #C3 <core::int>
37+
#C5 = static-tearoff self::B::_#new#tearOff
38+
#C6 = instantiation #C5 <core::String, core::double>
39+
#C7 = static-tearoff self::C::_#new#tearOff
40+
#C8 = instantiation #C7 <core::bool, core::num, void>
41+
}

0 commit comments

Comments
 (0)