Skip to content

Commit af1b69d

Browse files
committed
fix: Allow use as self in method call after unbinding
1 parent 0fd6b5a commit af1b69d

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

nova_lint/src/immediately_bind_scoped.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,32 @@ fn is_valid_use_of_unbound_value(cx: &LateContext<'_>, expr: &Expr, hir_id: HirI
161161
return true;
162162
}
163163

164+
// If this is the self value of a method call, it's valid
165+
if path_to_local_id(expr, hir_id) && is_in_self_position(cx, expr) {
166+
return true;
167+
}
168+
169+
false
170+
}
171+
172+
fn is_in_self_position(cx: &LateContext<'_>, expr: &Expr) -> bool {
173+
let mut current_expr = expr;
174+
175+
// Walk up the parent chain to see if we're in a method call
176+
while let Some(parent) = get_parent_expr(cx, current_expr) {
177+
match parent.kind {
178+
// If we find a method call where our expression is in the receiver position
179+
ExprKind::MethodCall(_, receiver, args, _) => {
180+
if receiver.hir_id == current_expr.hir_id {
181+
return true;
182+
}
183+
}
184+
// Continue walking up for other expression types
185+
_ => {}
186+
}
187+
current_expr = parent;
188+
}
189+
164190
false
165191
}
166192

nova_lint/ui/immediately_bind_scoped.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
use nova_vm::{
44
ecmascript::{execution::Agent, types::Value},
55
engine::{
6+
context::{Bindable, GcScope, NoGcScope},
67
Scoped,
7-
context::{Bindable, NoGcScope},
88
},
99
};
1010

@@ -35,6 +35,19 @@ fn test_scoped_get_can_be_immediately_passed_on(
3535
test_consumes_unbound_value(a);
3636
}
3737

38+
fn test_scoped_get_can_be_used_as_self(agent: &Agent, scoped: Scoped<Value>) {
39+
scoped.get(agent).is_undefined();
40+
}
41+
42+
fn test_scoped_get_can_be_used_as_self_immediately_after(
43+
agent: &Agent,
44+
scoped: Scoped<Value>,
45+
gc: NoGcScope,
46+
) {
47+
let a = scoped.get(agent);
48+
a.is_undefined();
49+
}
50+
3851
fn test_consumes_unbound_value(value: Value) {
3952
unimplemented!()
4053
}
@@ -55,6 +68,30 @@ fn test_improbable_but_technically_bad_situation(
5568
let _a = Scoped::new(agent, Value::Undefined, gc).get(agent);
5669
}
5770

71+
// fn take_and_return_value_with_gc<'gc>(
72+
// agent: &mut Agent,
73+
// value: Value,
74+
// mut gc: GcScope<'gc, '_>,
75+
// ) -> Value<'gc> {
76+
// Value::Undefined
77+
// }
78+
79+
// fn test_scoped_used_twice_right_after<'gc>(
80+
// agent: &mut Agent,
81+
// value: Scoped<Value>,
82+
// mut gc: GcScope<'gc, '_>,
83+
// ) {
84+
// let value = value.get(agent);
85+
// let something = if value.is_undefined() {
86+
// true
87+
// } else {
88+
// take_and_return_value_with_gc(agent, value, gc.reborrow())
89+
// .unbind()
90+
// .bind(gc.nogc())
91+
// .is_undefined()
92+
// };
93+
// }
94+
5895
fn main() {
5996
unimplemented!()
6097
}

nova_lint/ui/immediately_bind_scoped.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: the result of `Scoped<Value>::get` should be immediately bound
2-
--> $DIR/immediately_bind_scoped.rs:43:14
2+
--> $DIR/immediately_bind_scoped.rs:56:14
33
|
44
LL | let _a = scoped.get(agent);
55
| ^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | let _a = scoped.get(agent);
88
= note: `#[deny(immediately_bind_scoped)]` on by default
99

1010
error: the result of `Scoped<Value>::get` should be immediately bound
11-
--> $DIR/immediately_bind_scoped.rs:55:14
11+
--> $DIR/immediately_bind_scoped.rs:68:14
1212
|
1313
LL | let _a = Scoped::new(agent, Value::Undefined, gc).get(agent);
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)