Skip to content

Commit da2b3b3

Browse files
committed
fix(analyzer): propagate type narrowing through break statements in loops
1 parent 0c44e86 commit da2b3b3

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

crates/analyzer/src/statement/loop/break.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,21 @@ impl<'ast, 'arena> Analyzable<'ast, 'arena> for Break<'arena> {
8787
let redefined_vars =
8888
block_context.get_redefined_locals(&loop_scope.parent_context_variables, false, &mut removed_var_ids);
8989

90-
for (var_id, parent_type) in &loop_scope.parent_context_variables {
90+
for var_id in loop_scope.parent_context_variables.keys() {
9191
if !redefined_vars.contains_key(var_id) {
92-
loop_scope.possibly_redefined_loop_parent_variables.insert(
93-
*var_id,
94-
Rc::new(add_optional_union_type(
95-
(**parent_type).clone(),
96-
loop_scope
97-
.possibly_redefined_loop_parent_variables
98-
.get(var_id)
99-
.map(std::convert::AsRef::as_ref),
100-
context.codebase,
101-
)),
102-
);
92+
if let Some(current_type) = block_context.locals.get(var_id) {
93+
loop_scope.possibly_redefined_loop_parent_variables.insert(
94+
*var_id,
95+
Rc::new(add_optional_union_type(
96+
(**current_type).clone(),
97+
loop_scope
98+
.possibly_redefined_loop_parent_variables
99+
.get(var_id)
100+
.map(std::convert::AsRef::as_ref),
101+
context.codebase,
102+
)),
103+
);
104+
}
103105
}
104106
}
105107

crates/analyzer/tests/cases/break_narrowing.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ function takeString(string $s): void
55
takeString($s);
66
}
77

8+
function takeInt(int $i): void
9+
{
10+
takeInt($i);
11+
}
12+
813
function testSimpleBreakNarrowing(null|string $value): string
914
{
1015
while (true) {
@@ -19,3 +24,18 @@ function testSimpleBreakNarrowing(null|string $value): string
1924

2025
return $value;
2126
}
27+
28+
function testBreakAfterNullCheck(null|int $value): null|int
29+
{
30+
while (true) {
31+
if ($value !== null) {
32+
break;
33+
}
34+
$value = 0;
35+
break;
36+
}
37+
38+
takeInt($value);
39+
40+
return $value;
41+
}

0 commit comments

Comments
 (0)