Skip to content

Commit

Permalink
delegation: Fix hygiene for self
Browse files Browse the repository at this point in the history
And fix diagnostics for `self` from a macro.
  • Loading branch information
petrochenkov committed Jun 14, 2024
1 parent f8e5660 commit cbc3bdb
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 22 deletions.
24 changes: 13 additions & 11 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3281,17 +3281,19 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
self.visit_path(&delegation.path, delegation.id);
if let Some(body) = &delegation.body {
// `PatBoundCtx` is not necessary in this context
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];

let span = delegation.path.segments.last().unwrap().ident.span;
self.fresh_binding(
Ident::new(kw::SelfLower, span),
delegation.id,
PatternSource::FnParam,
&mut bindings,
);
self.visit_block(body);
self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| {
// `PatBoundCtx` is not necessary in this context
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];

let span = delegation.path.segments.last().unwrap().ident.span;
this.fresh_binding(
Ident::new(kw::SelfLower, span),
delegation.id,
PatternSource::FnParam,
&mut bindings,
);
this.visit_block(body);
});
}
}

Expand Down
24 changes: 15 additions & 9 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,12 +1021,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
},
);
let is_assoc_fn = self.self_type_is_available();
let self_from_macro = "a `self` parameter, but a macro invocation can only \
access identifiers it receives from parameters";
if let Some((fn_kind, span)) = &self.diag_metadata.current_function {
// The current function has a `self` parameter, but we were unable to resolve
// a reference to `self`. This can only happen if the `self` identifier we
// are resolving came from a different hygiene context.
if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
err.span_label(*span, format!("this function has {self_from_macro}"));
} else {
let doesnt = if is_assoc_fn {
let (span, sugg) = fn_kind
Expand Down Expand Up @@ -1068,14 +1070,18 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
}
} else if let Some(item_kind) = self.diag_metadata.current_item {
err.span_label(
item_kind.ident.span,
format!(
"`self` not allowed in {} {}",
item_kind.kind.article(),
item_kind.kind.descr()
),
);
if matches!(item_kind.kind, ItemKind::Delegation(..)) {
err.span_label(item_kind.span, format!("delegation supports {self_from_macro}"));
} else {
err.span_label(
item_kind.ident.span,
format!(
"`self` not allowed in {} {}",
item_kind.kind.article(),
item_kind.kind.descr()
),
);
}
}
true
}
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/delegation/macro-inside-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ struct S(u8);

// Macro expansion works inside delegation items.
macro_rules! u8 { () => { u8 } }
macro_rules! self_0 { () => { &self.0 } }
macro_rules! self_0 { ($self:ident) => { &$self.0 } }
impl Trait for S {
reuse <u8!() as Trait>::{foo, bar} { self_0!() }
reuse <u8!() as Trait>::{foo, bar} { self_0!(self) }
}

fn main() {
Expand Down
20 changes: 20 additions & 0 deletions tests/ui/delegation/self-hygiene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]

macro_rules! emit_self { () => { self } }
//~^ ERROR expected value, found module `self`
//~| ERROR expected value, found module `self`

struct S;
impl S {
fn method(self) {
emit_self!();
}
}

fn foo(arg: u8) {}
reuse foo as bar {
emit_self!()
}

fn main() {}
31 changes: 31 additions & 0 deletions tests/ui/delegation/self-hygiene.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
error[E0424]: expected value, found module `self`
--> $DIR/self-hygiene.rs:4:34
|
LL | macro_rules! emit_self { () => { self } }
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
...
LL | / fn method(self) {
LL | | emit_self!();
| | ------------ in this macro invocation
LL | | }
| |_____- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
|
= note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0424]: expected value, found module `self`
--> $DIR/self-hygiene.rs:4:34
|
LL | macro_rules! emit_self { () => { self } }
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
...
LL | / reuse foo as bar {
LL | | emit_self!()
| | ------------ in this macro invocation
LL | | }
| |_- delegation supports a `self` parameter, but a macro invocation can only access identifiers it receives from parameters
|
= note: this error originates in the macro `emit_self` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0424`.

0 comments on commit cbc3bdb

Please sign in to comment.