Skip to content

Commit e18539c

Browse files
Haofeiclaude
andcommitted
review #2: traverse assignment-target reads uniformly in semantic passes
Controlled-assignment targets evaluate subexpressions (a field base, an index expression) that are genuine reads of bindings. Several use/ident/effect/capture passes only visited the assigned value, silently dropping those target reads. Route them all through crate::hir::assign_target_reads / its AST analogue: local.rs: collect_hir_stmt_idents, collect_hir_stmt_effect_events, collect_hir_stmt_inline_capture_uses, collect_closure_local_moved_uses_from_stmt, collect_retained_closure_captures_from_stmt body.rs: collect_stmt_uses, collect_spawn_capture_idents_from_stmt, check_explicit_closure_captures_stmt analyzer: check_match_exhaustiveness, check_unknown_bindings This makes use-after-move, unknown-binding, capture, and effect analysis see reads like obj/idx in 'obj.field[idx] = value' that were previously invisible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 89674fa commit e18539c

3 files changed

Lines changed: 68 additions & 20 deletions

File tree

crates/rsscript/src/analyzer.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,8 +1996,12 @@ impl Analyzer<'_> {
19961996
self.check_match_exhaustiveness_block(&arm.body);
19971997
}
19981998
}
1999-
HirStmt::Expr(expr) | HirStmt::Assign { value: expr, .. } => {
2000-
self.check_match_exhaustiveness_expr(expr)
1999+
HirStmt::Expr(expr) => self.check_match_exhaustiveness_expr(expr),
2000+
HirStmt::Assign { target, value, .. } => {
2001+
for read in crate::hir::assign_target_reads(target) {
2002+
self.check_match_exhaustiveness_expr(read);
2003+
}
2004+
self.check_match_exhaustiveness_expr(value);
20012005
}
20022006
HirStmt::Break(_) | HirStmt::Continue(_) | HirStmt::Unknown(_) => {}
20032007
}
@@ -3299,8 +3303,12 @@ impl Analyzer<'_> {
32993303
self.check_unknown_bindings_in_block(&arm.body, &mut arm_visible);
33003304
}
33013305
}
3302-
HirStmt::Expr(value) | HirStmt::Assign { value, .. } => {
3303-
self.check_unknown_bindings_in_expr(value, visible)
3306+
HirStmt::Expr(value) => self.check_unknown_bindings_in_expr(value, visible),
3307+
HirStmt::Assign { target, value, .. } => {
3308+
for read in crate::hir::assign_target_reads(target) {
3309+
self.check_unknown_bindings_in_expr(read, visible);
3310+
}
3311+
self.check_unknown_bindings_in_expr(value, visible);
33043312
}
33053313
HirStmt::Break(_) | HirStmt::Continue(_) | HirStmt::Unknown(_) => {}
33063314
}

crates/rsscript/src/checks/body.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,12 @@ fn check_explicit_closure_captures_stmt(
150150
check_explicit_closure_captures_block(analyzer, &arm.body, binding_names);
151151
}
152152
}
153-
HirStmt::Expr(expr) | HirStmt::Assign { value: expr, .. } => {
154-
check_explicit_closure_captures_expr(analyzer, expr, binding_names)
153+
HirStmt::Expr(expr) => check_explicit_closure_captures_expr(analyzer, expr, binding_names),
154+
HirStmt::Assign { target, value, .. } => {
155+
for read in crate::hir::assign_target_reads(target) {
156+
check_explicit_closure_captures_expr(analyzer, read, binding_names);
157+
}
158+
check_explicit_closure_captures_expr(analyzer, value, binding_names);
155159
}
156160
HirStmt::Break(_) | HirStmt::Continue(_) | HirStmt::Unknown(_) => {}
157161
}
@@ -1068,7 +1072,13 @@ fn collect_stmt_uses(statement: &HirStmt, uses: &mut HashSet<String>) {
10681072
collect_block_uses(&arm.body, uses);
10691073
}
10701074
}
1071-
HirStmt::Expr(expr) | HirStmt::Assign { value: expr, .. } => collect_expr_uses(expr, uses),
1075+
HirStmt::Expr(expr) => collect_expr_uses(expr, uses),
1076+
HirStmt::Assign { target, value, .. } => {
1077+
for read in crate::hir::assign_target_reads(target) {
1078+
collect_expr_uses(read, uses);
1079+
}
1080+
collect_expr_uses(value, uses);
1081+
}
10721082
HirStmt::Break(_) | HirStmt::Continue(_) | HirStmt::Unknown(_) => {}
10731083
}
10741084
}
@@ -3645,8 +3655,13 @@ fn collect_spawn_capture_idents_from_stmt(statement: &HirStmt, captures: &mut Ve
36453655
| HirStmt::Return {
36463656
value: Some(value), ..
36473657
}
3648-
| HirStmt::Expr(value)
3649-
| HirStmt::Assign { value, .. } => collect_spawn_capture_idents(value, captures),
3658+
| HirStmt::Expr(value) => collect_spawn_capture_idents(value, captures),
3659+
HirStmt::Assign { target, value, .. } => {
3660+
for read in crate::hir::assign_target_reads(target) {
3661+
collect_spawn_capture_idents(read, captures);
3662+
}
3663+
collect_spawn_capture_idents(value, captures);
3664+
}
36503665
HirStmt::With { resource, body, .. } => {
36513666
collect_spawn_capture_idents(resource, captures);
36523667
for statement in &body.statements {

crates/rsscript/src/checks/local.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,9 +1041,12 @@ fn collect_closure_local_moved_uses_from_stmt(statement: &HirStmt, moved_uses: &
10411041
| HirStmt::Return {
10421042
value: Some(value), ..
10431043
}
1044-
| HirStmt::Expr(value)
1045-
| HirStmt::Assign { value, .. } => {
1046-
collect_closure_local_moved_uses_from_expr(value, moved_uses)
1044+
| HirStmt::Expr(value) => collect_closure_local_moved_uses_from_expr(value, moved_uses),
1045+
HirStmt::Assign { target, value, .. } => {
1046+
for read in crate::hir::assign_target_reads(target) {
1047+
collect_closure_local_moved_uses_from_expr(read, moved_uses);
1048+
}
1049+
collect_closure_local_moved_uses_from_expr(value, moved_uses);
10471050
}
10481051
HirStmt::With { resource, body, .. } => {
10491052
collect_closure_local_moved_uses_from_expr(resource, moved_uses);
@@ -1200,12 +1203,19 @@ fn collect_retained_closure_captures_from_stmt(
12001203
| HirStmt::Return {
12011204
value: Some(value), ..
12021205
}
1203-
| HirStmt::Expr(value)
1204-
| HirStmt::Assign { value, .. } => {
1206+
| HirStmt::Expr(value) => {
12051207
if let Some(state) = entry_state {
12061208
collect_retained_closure_captures_from_expr(value, state, captures);
12071209
}
12081210
}
1211+
HirStmt::Assign { target, value, .. } => {
1212+
if let Some(state) = entry_state {
1213+
for read in crate::hir::assign_target_reads(target) {
1214+
collect_retained_closure_captures_from_expr(read, state, captures);
1215+
}
1216+
collect_retained_closure_captures_from_expr(value, state, captures);
1217+
}
1218+
}
12091219
HirStmt::With { resource, body, .. } => {
12101220
if let Some(state) = entry_state {
12111221
collect_retained_closure_captures_from_expr(resource, state, captures);
@@ -2050,8 +2060,13 @@ fn collect_hir_stmt_idents(statement: &HirStmt, uses: &mut Vec<(String, Span)>)
20502060
| HirStmt::Return {
20512061
value: Some(value), ..
20522062
}
2053-
| HirStmt::Expr(value)
2054-
| HirStmt::Assign { value, .. } => collect_hir_expr_idents(value, uses),
2063+
| HirStmt::Expr(value) => collect_hir_expr_idents(value, uses),
2064+
HirStmt::Assign { target, value, .. } => {
2065+
for read in crate::hir::assign_target_reads(target) {
2066+
collect_hir_expr_idents(read, uses);
2067+
}
2068+
collect_hir_expr_idents(value, uses);
2069+
}
20552070
HirStmt::With { resource, .. } => collect_hir_expr_idents(resource, uses),
20562071
HirStmt::If { condition, .. } => collect_hir_expr_idents(condition, uses),
20572072
HirStmt::Loop {
@@ -2084,8 +2099,13 @@ fn collect_hir_stmt_effect_events(statement: &HirStmt, events: &mut Vec<HirEffec
20842099
| HirStmt::Return {
20852100
value: Some(value), ..
20862101
}
2087-
| HirStmt::Expr(value)
2088-
| HirStmt::Assign { value, .. } => collect_hir_expr_effect_events(value, events),
2102+
| HirStmt::Expr(value) => collect_hir_expr_effect_events(value, events),
2103+
HirStmt::Assign { target, value, .. } => {
2104+
for read in crate::hir::assign_target_reads(target) {
2105+
collect_hir_expr_effect_events(read, events);
2106+
}
2107+
collect_hir_expr_effect_events(value, events);
2108+
}
20892109
HirStmt::With { resource, .. } => collect_hir_expr_effect_events(resource, events),
20902110
HirStmt::If { condition, .. } => collect_hir_expr_effect_events(condition, events),
20912111
HirStmt::Loop {
@@ -2310,8 +2330,13 @@ fn collect_hir_stmt_inline_capture_uses(statement: &HirStmt, uses: &mut Vec<(Str
23102330
| HirStmt::Return {
23112331
value: Some(value), ..
23122332
}
2313-
| HirStmt::Expr(value)
2314-
| HirStmt::Assign { value, .. } => collect_hir_expr_inline_capture_uses(value, uses),
2333+
| HirStmt::Expr(value) => collect_hir_expr_inline_capture_uses(value, uses),
2334+
HirStmt::Assign { target, value, .. } => {
2335+
for read in crate::hir::assign_target_reads(target) {
2336+
collect_hir_expr_inline_capture_uses(read, uses);
2337+
}
2338+
collect_hir_expr_inline_capture_uses(value, uses);
2339+
}
23152340
HirStmt::With { resource, .. } => collect_hir_expr_inline_capture_uses(resource, uses),
23162341
HirStmt::If { condition, .. } => collect_hir_expr_inline_capture_uses(condition, uses),
23172342
HirStmt::Loop {

0 commit comments

Comments
 (0)