[tfa] Fix handling of late local variables with static type Never
Initializers of late local variables are wrapped into closures. The result type of a closure is a static type of the variable. So initializer of a late variable with static type Never have a call to a closure with static result type Never. TFA summary collector handles calls with static result type Never specially, treating all subsequent code as unreachable (by setting control-dependent condition to empty). As a result, all subsequent code after late variable with static type Never (and initializer) is tree-shaken. The fix is to avoid propagating control-dependent condition out of the late variable initializers. TEST=pkg/vm/testcases/transformations/type_flow/transformer/regress_63478.dart Fixes https://github.com/dart-lang/sdk/issues/63478 Change-Id: If41221777c9d249dd21ce5827c586b0f531cbce8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/508363 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
4b0a4e0a75
commit
7ff5e3654d
@@ -2817,6 +2817,7 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr?> {
|
||||
final variable = node.variable;
|
||||
variable.annotations.forEach(_visitAnnotation);
|
||||
final initializer = variable.initializer;
|
||||
final savedCondition = _currentCondition;
|
||||
final TypeExpr initialValue = initializer == null
|
||||
? ((variable.type.nullability == Nullability.nonNullable ||
|
||||
variable.isLate)
|
||||
@@ -2824,6 +2825,11 @@ class SummaryCollector extends RecursiveResultVisitor<TypeExpr?> {
|
||||
: _nullType)
|
||||
: _visit(initializer);
|
||||
_declareVariable(variable, initialValue);
|
||||
if (variable.isLate) {
|
||||
// Restore condition as initializer of a late variable
|
||||
// is not evaluated immediately.
|
||||
_currentCondition = savedCondition;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2026, 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.
|
||||
|
||||
// Regression test for https://github.com/dart-lang/sdk/issues/63478.
|
||||
// Verifies that initializer of a late variable doesn't affect
|
||||
// subsequent statements.
|
||||
|
||||
void test1() {
|
||||
late var x = throw "error";
|
||||
print("reachable");
|
||||
}
|
||||
|
||||
Never sayNever() => throw 'Never';
|
||||
|
||||
void test2() {
|
||||
late Never y = sayNever();
|
||||
print("reachable");
|
||||
}
|
||||
|
||||
void main() {
|
||||
test1();
|
||||
test2();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
library #lib;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
|
||||
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
|
||||
static method test1() → void {
|
||||
function #x#initializer() → Never
|
||||
return throw "error";
|
||||
late Never x = [@vm.inferred-type.metadata=? (receiver not int)] #x#initializer(){() → Never};
|
||||
core::print("reachable");
|
||||
}
|
||||
|
||||
[@vm.inferred-return-type.metadata=!]
|
||||
static method sayNever() → Never
|
||||
return throw "Never";
|
||||
|
||||
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
|
||||
static method test2() → void {
|
||||
function #y#initializer() → Never
|
||||
return self::sayNever();
|
||||
late Never y = [@vm.inferred-type.metadata=? (receiver not int)] #y#initializer(){() → Never};
|
||||
core::print("reachable");
|
||||
}
|
||||
|
||||
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
|
||||
static method main() → void {
|
||||
self::test1();
|
||||
self::test2();
|
||||
}
|
||||
Reference in New Issue
Block a user