Skip to content

Commit c54bacd

Browse files
ecstatic-morsekarroffel
authored andcommitted
Use hygienic identifier to replace self in closure body
1 parent e9637ae commit c54bacd

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

src/implementation/codegen.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ pub(crate) fn generate(
323323
let block = &func.function.block;
324324
quote::quote! { let ret = #block; }
325325
} else {
326-
create_closure_body_and_adjust_signature(&func.function)
326+
create_body_closure(&func.function)
327327
};
328328

329329
//
@@ -389,18 +389,20 @@ fn ty_contains_impl_trait(ty: &syn::Type) -> bool {
389389
vis.seen_impl_trait
390390
}
391391

392-
fn create_closure_body_and_adjust_signature(func: &syn::ItemFn) -> TokenStream {
392+
fn create_body_closure(func: &syn::ItemFn) -> TokenStream {
393393
let is_method = func.sig.receiver().is_some();
394394

395395
// If the function has a receiver (e.g. `self`, `&mut self`, or `self: Box<Self>`) rename it
396-
// to `this__` within the closure
396+
// to `this` within the closure
397397

398398
let mut block = func.block.clone();
399399
let mut closure_args = vec![];
400400
let mut arg_names = vec![];
401401

402402
if is_method {
403-
let this_ident = syn::Ident::new("this__", Span::call_site());
403+
// `mixed_site` makes the identifier hygienic so it won't collide with a local variable
404+
// named `this`.
405+
let this_ident = syn::Ident::new("this", Span::mixed_site());
404406

405407
let mut receiver = func.sig.inputs[0].clone();
406408
match receiver {
@@ -430,7 +432,7 @@ fn create_closure_body_and_adjust_signature(func: &syn::ItemFn) -> TokenStream {
430432
None
431433
};
432434

433-
// this__: [& [mut]] Self
435+
// this: [& [mut]] Self
434436
let new_rcv = syn::PatType {
435437
attrs: rcv.attrs.clone(),
436438
pat: Box::new(syn::Pat::Ident(syn::PatIdent {
@@ -460,7 +462,7 @@ fn create_closure_body_and_adjust_signature(func: &syn::ItemFn) -> TokenStream {
460462
closure_args.push(receiver);
461463
arg_names.push(syn::Ident::new("self", Span::call_site()));
462464

463-
// Replace any references to `self` in the function body with references to `this__`.
465+
// Replace any references to `self` in the function body with references to `this`.
464466
syn::visit_mut::visit_block_mut(
465467
&mut SelfReplacer {
466468
replace_with: &this_ident,
@@ -469,8 +471,9 @@ fn create_closure_body_and_adjust_signature(func: &syn::ItemFn) -> TokenStream {
469471
);
470472
}
471473

472-
// Replace any pattern matching in the function signature with placeholder identifiers.
473-
// Pattern matching gets done in the closure instead.
474+
// Any function arguments of the form `ident: ty` become closure arguments and get passed
475+
// explicitly. More complex ones, e.g. pattern matching like `(a, b): (u32, u32)`, are
476+
// captured instead.
474477
let args = func.sig.inputs.iter().skip(if is_method { 1 } else { 0 });
475478
for arg in args {
476479
match arg {

tests/methods.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ fn methods() {
4141
fn prev_even(&mut self) {
4242
self.count -= 2;
4343
}
44+
45+
#[invariant(is_even(self.count))]
46+
fn this_var_collision(&mut self) -> usize {
47+
#[allow(unused_variables)]
48+
let (this, this__) = (42, 42);
49+
self.count
50+
}
4451
}
4552

4653
let mut adder = EvenAdder { count: 0 };

0 commit comments

Comments
 (0)