Skip to content

Commit

Permalink
Rewrite get_fn_id_for_return_block
Browse files Browse the repository at this point in the history
  • Loading branch information
BoxyUwU committed Aug 16, 2024
1 parent 27b93da commit ed6315b
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 62 deletions.
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`.

0 comments on commit ed6315b

Please sign in to comment.