mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Rollup merge of #129168 - BoxyUwU:mismatched_ty_correct_id, r=compiler-errors
Return correct HirId when finding body owner in diagnostics Fixes #129145 Fixes #128810 r? ```@compiler-errors``` ```rust 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 } } ``` When type checking the `{ true }` anon const we would error with a type mismatch. This then results in diagnostics code attempting to check whether its due to a type mismatch with the return type. That logic was implemented by walking up the hir until we reached the body owner, except instead of using the `enclosing_body_owner` function it special cased various hir nodes incorrectly resulting in us walking out of the anon const and stopping at `fn collate` instead. This then resulted in diagnostics logic inside of the anon consts `ParamEnv` attempting to do trait solving involving the `<i32 as Collate<B>>::Pass` type which ICEs because it is in the wrong environment. I have rewritten this function to just walk up until it hits the `enclosing_body_owner` and made some other changes since I found this pretty hard to read/understand. Hopefully it's easier to understand now, it also makes it more obvious that this is not implemented in a very principled way and is definitely missing cases :)
This commit is contained in:
commit
ddbbda47eb
@ -554,53 +554,43 @@ impl<'hir> Map<'hir> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
|
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
|
||||||
let mut iter = self.parent_iter(id).peekable();
|
let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
|
||||||
let mut ignore_tail = false;
|
|
||||||
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
|
// Return `None` if the `id` expression is not the returned value of the enclosing body
|
||||||
// When dealing with `return` statements, we don't care about climbing only tail
|
let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
|
||||||
// expressions.
|
while let Some(cur_id) = iter.next() {
|
||||||
ignore_tail = true;
|
if enclosing_body_owner == cur_id {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut prev_hir_id = None;
|
// A return statement is always the value returned from the enclosing body regardless of
|
||||||
while let Some((hir_id, node)) = iter.next() {
|
// what the parent expressions are.
|
||||||
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
|
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
|
||||||
match next_node {
|
break;
|
||||||
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), .. })
|
Node::Block(Block { expr: Some(e), .. })
|
||||||
if matches!(e.kind, ExprKind::If(_, _, None)) =>
|
if matches!(e.kind, ExprKind::If(_, _, None)) =>
|
||||||
{
|
{
|
||||||
return 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);
|
Some(enclosing_body_owner)
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
|
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
//@ known-bug: rust-lang/rust#128810
|
|
||||||
|
|
||||||
#![feature(fn_delegation)]
|
|
||||||
|
|
||||||
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(&());
|
|
||||||
}
|
|
||||||
|
|
||||||
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 } }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() { }
|
|
@ -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() { }
|
@ -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
tests/ui/typeck/const-in-fn-call-generics.rs
Normal file
16
tests/ui/typeck/const-in-fn-call-generics.rs
Normal file
@ -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
tests/ui/typeck/const-in-fn-call-generics.stderr
Normal file
9
tests/ui/typeck/const-in-fn-call-generics.stderr
Normal file
@ -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…
Reference in New Issue
Block a user