Skip to content

Commit 39d2653

Browse files
chloestefantsovaCommit Queue
authored andcommitted
[cfe] Provide inferred type context to initializing formals
In response to flutter/flutter#160551 Change-Id: I0e4123c76f8d82a6900e12452f0deef2cbb05d36 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/404822 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent d2ce8e7 commit 39d2653

9 files changed

+156
-16
lines changed

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

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,32 @@ class RedirectingFactoryBuilder extends SourceFactoryBuilder {
582582
.createBodyBuilderForOutlineExpression(libraryBuilder,
583583
createBodyBuilderContext(), declarationBuilder.scope, fileUri);
584584
Builder? targetBuilder = redirectionTarget.target;
585+
586+
// Inference of target's formals should happen before building of the
587+
// outline expressions in members and before inferring target's type
588+
// arguments.
589+
//
590+
// (1) The outline expressions, such as formal parameter initializers,
591+
// need properly inferred type contexts. Among other things, it ensures
592+
// that the required coercions, such as int-to-double conversion, are
593+
// run.
594+
//
595+
// (2) Type arguments for the targets of redirecting factories can only
596+
// be inferred if the formal parameters of the targets are inferred too.
597+
// That may not be the case when the target's parameters are initializing
598+
// parameters referring to fields with types that are to be inferred.
599+
if (targetBuilder is SourceFunctionBuilderImpl) {
600+
List<FormalParameterBuilder>? formals = targetBuilder.formals;
601+
if (formals != null) {
602+
for (FormalParameterBuilder formal in formals) {
603+
TypeBuilder formalType = formal.type;
604+
if (formalType is InferableTypeBuilder) {
605+
formalType.inferType(classHierarchy);
606+
}
607+
}
608+
}
609+
}
610+
585611
if (targetBuilder is SourceMemberBuilder) {
586612
// Ensure that target has been built.
587613
targetBuilder.buildOutlineExpressions(
@@ -598,22 +624,6 @@ class RedirectingFactoryBuilder extends SourceFactoryBuilder {
598624
fileOffset, fileUri);
599625
}
600626

601-
// Type arguments for the targets of redirecting factories can only be
602-
// inferred if the formal parameters of the targets are inferred too.
603-
// That may not be the case when the target's parameters are initializing
604-
// parameters referring to fields with types that are to be inferred.
605-
if (targetBuilder is SourceFunctionBuilderImpl) {
606-
List<FormalParameterBuilder>? formals = targetBuilder.formals;
607-
if (formals != null) {
608-
for (FormalParameterBuilder formal in formals) {
609-
TypeBuilder formalType = formal.type;
610-
if (formalType is InferableTypeBuilder) {
611-
formalType.inferType(classHierarchy);
612-
}
613-
}
614-
}
615-
}
616-
617627
typeArguments = inferrer.inferRedirectingFactoryTypeArguments(
618628
helper,
619629
_procedureInternal.function.returnType,

pkg/front_end/test/spell_checking_list_common.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,7 @@ coerced
510510
coerces
511511
coercing
512512
coercion
513+
coercions
513514
coincides
514515
coinductively
515516
collapses
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2025, 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+
void main() {
6+
print(B().foo);
7+
}
8+
9+
abstract class A {
10+
A();
11+
12+
factory A.redir({double foo}) = B;
13+
}
14+
15+
class B<T> extends A {
16+
B({this.foo = 10});
17+
final double foo;
18+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
static factory redir({core::double foo = #C1}) → self::A /* redirection-target: self::B::•<dynamic>*/
10+
return new self::B::•<dynamic>(foo: foo);
11+
}
12+
class B<T extends core::Object? = dynamic> extends self::A {
13+
final field core::double foo;
14+
constructor •({core::double foo = #C1}) → self::B<self::B::T%>
15+
: self::B::foo = foo, super self::A::•()
16+
;
17+
}
18+
static method main() → void {
19+
core::print(new self::B::•<dynamic>().{self::B::foo}{core::double});
20+
}
21+
22+
constants {
23+
#C1 = 10.0
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
static factory redir({core::double foo = #C1}) → self::A /* redirection-target: self::B::•<dynamic>*/
10+
return new self::B::•<dynamic>(foo: foo);
11+
}
12+
class B<T extends core::Object? = dynamic> extends self::A {
13+
final field core::double foo;
14+
constructor •({core::double foo = #C1}) → self::B<self::B::T%>
15+
: self::B::foo = foo, super self::A::•()
16+
;
17+
}
18+
static method main() → void {
19+
core::print(new self::B::•<dynamic>().{self::B::foo}{core::double});
20+
}
21+
22+
constants {
23+
#C1 = 10.0
24+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
constructor •() → self::A
7+
;
8+
static factory redir({core::double foo = null}) → self::A /* redirection-target: self::B::•<dynamic>*/
9+
return new self::B::•<dynamic>(foo: foo);
10+
}
11+
class B<T extends core::Object? = dynamic> extends self::A {
12+
final field core::double foo;
13+
constructor •({core::double foo = 10.0}) → self::B<self::B::T%>
14+
;
15+
}
16+
static method main() → void
17+
;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
library;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
abstract class A extends core::Object {
6+
constructor •() → self::A
7+
: super core::Object::•()
8+
;
9+
static factory redir({core::double foo = #C1}) → self::A /* redirection-target: self::B::•<dynamic>*/
10+
return new self::B::•<dynamic>(foo: foo);
11+
}
12+
class B<T extends core::Object? = dynamic> extends self::A {
13+
final field core::double foo;
14+
constructor •({core::double foo = #C1}) → self::B<self::B::T%>
15+
: self::B::foo = foo, super self::A::•()
16+
;
17+
}
18+
static method main() → void {
19+
core::print(new self::B::•<dynamic>().{self::B::foo}{core::double});
20+
}
21+
22+
constants {
23+
#C1 = 10.0
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
void main() {}
2+
3+
abstract class A {
4+
A();
5+
factory A.redir({double foo}) = B;
6+
}
7+
8+
class B<T> extends A {
9+
B({this.foo = 10});
10+
final double foo;
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
abstract class A {
2+
A();
3+
factory A.redir({double foo}) = B;
4+
}
5+
6+
class B<T> extends A {
7+
B({this.foo = 10});
8+
final double foo;
9+
}
10+
11+
void main() {}

0 commit comments

Comments
 (0)