Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 5 additions & 16 deletions pyrefly/lib/binding/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3845,21 +3845,22 @@ fn determine_definition_status(
n_values: usize,
n_branches: usize,
n_missing_branches: usize,
n_branches_with_termination_key: usize,
missing_branch_termination_keys: Vec<Idx<Key>>,
) -> DefinitionStatus {
match merge_style {
MergeStyle::LoopDefinitelyRuns if base_has_value => DefinitionStatus::Defined,
MergeStyle::LoopDefinitelyRuns if n_values == n_branches => DefinitionStatus::Defined,
MergeStyle::LoopDefinitelyRuns if n_missing_branches <= n_branches_with_termination_key => {
MergeStyle::LoopDefinitelyRuns
if n_missing_branches <= missing_branch_termination_keys.len() =>
{
if !missing_branch_termination_keys.is_empty() {
DefinitionStatus::DeferredCheck(missing_branch_termination_keys)
} else {
DefinitionStatus::Defined
}
}
_ if n_values == n_branches => DefinitionStatus::Defined,
_ if n_missing_branches <= n_branches_with_termination_key => {
_ if n_missing_branches <= missing_branch_termination_keys.len() => {
if !missing_branch_termination_keys.is_empty() {
DefinitionStatus::DeferredCheck(missing_branch_termination_keys)
} else {
Expand Down Expand Up @@ -3952,7 +3953,6 @@ impl<'a> BindingsBuilder<'a> {
phi_key: PhiKey,
merge_style: MergeStyle,
n_branches: usize,
n_branches_with_termination_key: usize,
) -> FlowInfo {
// Only a promised phi can already appear in a branch's flow.
let phi_idx = phi_key.promised;
Expand Down Expand Up @@ -4080,7 +4080,6 @@ impl<'a> BindingsBuilder<'a> {
n_values,
n_branches,
n_missing_branches,
n_branches_with_termination_key,
missing_branch_termination_keys,
);

Expand Down Expand Up @@ -4213,10 +4212,6 @@ impl<'a> BindingsBuilder<'a> {
0
};

// Count how many branches have a last_stmt_expr (potential type-based termination)
let n_branches_with_termination_key =
flows.iter().filter(|f| f.last_stmt_expr.is_some()).count();

// Collect all termination keys from flows (for building dense MergeItems)
let all_termination_keys: Vec<Option<Idx<Key>>> =
flows.iter().map(|f| f.last_stmt_expr).collect();
Expand Down Expand Up @@ -4263,13 +4258,7 @@ impl<'a> BindingsBuilder<'a> {
promised: self.promised_idx(&key),
key,
};
let flow_info = self.merged_flow_info(
merge_item,
phi_key,
merge_style,
n_branches,
n_branches_with_termination_key,
);
let flow_info = self.merged_flow_info(merge_item, phi_key, merge_style, n_branches);
merged_flow_infos.insert_hashed(name, flow_info);
}

Expand Down
6 changes: 2 additions & 4 deletions pyrefly/lib/test/flow_branching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2283,7 +2283,6 @@ def f() -> int:

// elif condition only executes if the first `if` was False — walrus may not run.
testcase!(
bug = "In order to fix false positives, we handled narrows differently in if/elif and introduced a false negative here",
test_walrus_in_elif,
r#"
def condition() -> bool: ...
Expand All @@ -2292,7 +2291,7 @@ def f() -> bool:
pass
elif (x := condition()):
pass
return x # False negative: x winds up getting applied as if it were in the base flow due to the negative narrow
return x # E: `x` may be uninitialized
"#,
);

Expand Down Expand Up @@ -2380,7 +2379,6 @@ def f() -> None:

// the walrus may not execute, so x should be possibly-uninitialized.
testcase!(
bug = "Should report x as possibly uninitialized since the if branch does not terminate",
test_walrus_in_elif_preceding_if_no_terminate,
r#"
def foo() -> bool:
Expand All @@ -2394,7 +2392,7 @@ def f() -> None:
pass
elif (x := bar()) > 1:
pass
print(x) # should be an error: x may be uninitialized
print(x) # E: `x` may be uninitialized
"#,
);

Expand Down
13 changes: 13 additions & 0 deletions pyrefly/lib/test/flow_looping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
use crate::test::util::TestEnv;
use crate::testcase;

testcase!(
test_for_trailing_expression_does_not_initialize_local,
r#"
import time

def f(xs: list[int]) -> int:
for x in xs:
y = x
time.sleep(1)
return y # E: `y` may be uninitialized
"#,
);

testcase!(
test_loop_with_generic_pin,
r#"
Expand Down
2 changes: 1 addition & 1 deletion pyrefly/lib/test/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ def try_except_twice():
except Exception:
e3 # E: `e3` is uninitialized

e3 # E: `e3` may be uninitialized
e3 # E: `e3` is uninitialized

def try_except_multiple_finally():
try:
Expand Down
Loading