Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return correct HirId when finding body owner in diagnostics #129168

Merged
merged 1 commit into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 27 additions & 37 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,53 +554,43 @@ impl<'hir> Map<'hir> {
/// }
/// ```
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
let mut iter = self.parent_iter(id).peekable();
let mut ignore_tail = false;
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
// When dealing with `return` statements, we don't care about climbing only tail
// expressions.
ignore_tail = true;
}
let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));

// Return `None` if the `id` expression is not the returned value of the enclosing body
let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
while let Some(cur_id) = iter.next() {
if enclosing_body_owner == cur_id {
break;
}

// A return statement is always the value returned from the enclosing body regardless of
// what the parent expressions are.
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
break;
}

let mut prev_hir_id = None;
while let Some((hir_id, node)) = iter.next() {
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
match next_node {
Node::Block(Block { expr: None, .. }) => return None,
// The current node is not the tail expression of its parent.
Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
// If the current expression's value doesnt get used as the parent expressions value then return `None`
if let Some(&parent_id) = iter.peek() {
match self.tcx.hir_node(parent_id) {
// The current node is not the tail expression of the block expression parent expr.
Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None,
Node::Block(Block { expr: Some(e), .. })
if matches!(e.kind, ExprKind::If(_, _, None)) =>
{
return None;
}

// The current expression's value does not pass up through these parent expressions
Node::Block(Block { expr: None, .. })
| Node::Expr(Expr { kind: ExprKind::Loop(..), .. })
| Node::LetStmt(..) => return None,

_ => {}
}
}
match node {
Node::Item(_)
| Node::ForeignItem(_)
| Node::TraitItem(_)
| Node::Expr(Expr { kind: ExprKind::Closure(_), .. })
| Node::ImplItem(_)
// The input node `id` must be enclosed in the method's body as opposed
// to some other place such as its return type (fixes #114918).
// We verify that indirectly by checking that the previous node is the
// current node's body
if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
return Some(hir_id)
}
// Ignore `return`s on the first iteration
Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
| Node::LetStmt(_) => {
return None;
}
_ => {}
}

prev_hir_id = Some(hir_id);
}
None

Some(enclosing_body_owner)
}

/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
Expand Down
25 changes: 0 additions & 25 deletions tests/crashes/128810.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![feature(fn_delegation)]
#![allow(incomplete_features)]

use std::marker::PhantomData;

pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);

impl<'a> InvariantRef<'a, ()> {
pub const NEW: Self = InvariantRef::new(&());
//~^ ERROR: no function or associated item named `new` found
}

trait Trait {
fn foo(&self) -> u8 { 0 }
fn bar(&self) -> u8 { 1 }
fn meh(&self) -> u8 { 2 }
}

struct Z(u8);

impl Trait for Z {
reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
//~^ ERROR: use of undeclared lifetime name `'a`
//~| ERROR: use of undeclared lifetime name `'a`
//~| ERROR: use of undeclared lifetime name `'a`
//~| ERROR: the trait bound `u8: Trait` is not satisfied
//~| ERROR: the trait bound `u8: Trait` is not satisfied
//~| ERROR: the trait bound `u8: Trait` is not satisfied
//~| ERROR: mismatched types
//~| ERROR: mismatched types
//~| ERROR: mismatched types
}

fn main() { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
LL | reuse <u8 as Trait>::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } }
| +++
help: consider introducing lifetime `'a` here
|
LL | impl<'a> Trait for Z {
| ++++

error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
LL | reuse <u8 as Trait>::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } }
| +++
help: consider introducing lifetime `'a` here
|
LL | impl<'a> Trait for Z {
| ++++

error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^ undeclared lifetime
|
help: consider introducing lifetime `'a` here
|
LL | reuse <u8 as Trait>::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } }
| +++
help: consider introducing lifetime `'a` here
|
LL | impl<'a> Trait for Z {
| ++++

error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
|
LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
| -------------------------------------- function or associated item `new` not found for this struct
...
LL | pub const NEW: Self = InvariantRef::new(&());
| ^^^ function or associated item not found in `InvariantRef<'_, _>`

error[E0308]: mismatched types
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
|
= note: expected type `u8`
found struct `InvariantRef<'_, ()>`

error[E0277]: the trait bound `u8: Trait` is not satisfied
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^ the trait `Trait` is not implemented for `u8`
|
= help: the trait `Trait` is implemented for `Z`

error[E0308]: mismatched types
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
|
= note: expected type `u8`
found struct `InvariantRef<'_, ()>`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0277]: the trait bound `u8: Trait` is not satisfied
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^ the trait `Trait` is not implemented for `u8`
|
= help: the trait `Trait` is implemented for `Z`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0308]: mismatched types
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
|
= note: expected type `u8`
found struct `InvariantRef<'_, ()>`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0277]: the trait bound `u8: Trait` is not satisfied
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
|
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
| ^^ the trait `Trait` is not implemented for `u8`
|
= help: the trait `Trait` is implemented for `Z`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error: aborting due to 10 previous errors

Some errors have detailed explanations: E0261, E0277, E0308, E0599.
For more information about an error, try `rustc --explain E0261`.
16 changes: 16 additions & 0 deletions tests/ui/typeck/const-in-fn-call-generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
fn generic<const N: u32>() {}

trait Collate<const A: u32> {
type Pass;
fn collate(self) -> Self::Pass;
}

impl<const B: u32> Collate<B> for i32 {
type Pass = ();
fn collate(self) -> Self::Pass {
generic::<{ true }>()
//~^ ERROR: mismatched types
}
}

fn main() {}
9 changes: 9 additions & 0 deletions tests/ui/typeck/const-in-fn-call-generics.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
error[E0308]: mismatched types
--> $DIR/const-in-fn-call-generics.rs:11:21
|
LL | generic::<{ true }>()
| ^^^^ expected `u32`, found `bool`

error: aborting due to 1 previous error

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