Skip to content

Commit ddbbda4

Browse files
authored
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 :)
2 parents 9c910ae + ed6315b commit ddbbda4

6 files changed

+199
-62
lines changed

compiler/rustc_middle/src/hir/map/mod.rs

+27-37
Original file line numberDiff line numberDiff line change
@@ -554,53 +554,43 @@ impl<'hir> Map<'hir> {
554554
/// }
555555
/// ```
556556
pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
557-
let mut iter = self.parent_iter(id).peekable();
558-
let mut ignore_tail = false;
559-
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
560-
// When dealing with `return` statements, we don't care about climbing only tail
561-
// expressions.
562-
ignore_tail = true;
563-
}
557+
let enclosing_body_owner = self.tcx.local_def_id_to_hir_id(self.enclosing_body_owner(id));
558+
559+
// Return `None` if the `id` expression is not the returned value of the enclosing body
560+
let mut iter = [id].into_iter().chain(self.parent_id_iter(id)).peekable();
561+
while let Some(cur_id) = iter.next() {
562+
if enclosing_body_owner == cur_id {
563+
break;
564+
}
565+
566+
// A return statement is always the value returned from the enclosing body regardless of
567+
// what the parent expressions are.
568+
if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(cur_id) {
569+
break;
570+
}
564571

565-
let mut prev_hir_id = None;
566-
while let Some((hir_id, node)) = iter.next() {
567-
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
568-
match next_node {
569-
Node::Block(Block { expr: None, .. }) => return None,
570-
// The current node is not the tail expression of its parent.
571-
Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
572+
// If the current expression's value doesnt get used as the parent expressions value then return `None`
573+
if let Some(&parent_id) = iter.peek() {
574+
match self.tcx.hir_node(parent_id) {
575+
// The current node is not the tail expression of the block expression parent expr.
576+
Node::Block(Block { expr: Some(e), .. }) if cur_id != e.hir_id => return None,
572577
Node::Block(Block { expr: Some(e), .. })
573578
if matches!(e.kind, ExprKind::If(_, _, None)) =>
574579
{
575580
return None;
576581
}
582+
583+
// The current expression's value does not pass up through these parent expressions
584+
Node::Block(Block { expr: None, .. })
585+
| Node::Expr(Expr { kind: ExprKind::Loop(..), .. })
586+
| Node::LetStmt(..) => return None,
587+
577588
_ => {}
578589
}
579590
}
580-
match node {
581-
Node::Item(_)
582-
| Node::ForeignItem(_)
583-
| Node::TraitItem(_)
584-
| Node::Expr(Expr { kind: ExprKind::Closure(_), .. })
585-
| Node::ImplItem(_)
586-
// The input node `id` must be enclosed in the method's body as opposed
587-
// to some other place such as its return type (fixes #114918).
588-
// We verify that indirectly by checking that the previous node is the
589-
// current node's body
590-
if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
591-
return Some(hir_id)
592-
}
593-
// Ignore `return`s on the first iteration
594-
Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
595-
| Node::LetStmt(_) => {
596-
return None;
597-
}
598-
_ => {}
599-
}
600-
601-
prev_hir_id = Some(hir_id);
602591
}
603-
None
592+
593+
Some(enclosing_body_owner)
604594
}
605595

606596
/// Retrieves the `OwnerId` for `id`'s parent item, or `id` itself if no

tests/crashes/128810.rs

-25
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#![feature(fn_delegation)]
2+
#![allow(incomplete_features)]
3+
4+
use std::marker::PhantomData;
5+
6+
pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
7+
8+
impl<'a> InvariantRef<'a, ()> {
9+
pub const NEW: Self = InvariantRef::new(&());
10+
//~^ ERROR: no function or associated item named `new` found
11+
}
12+
13+
trait Trait {
14+
fn foo(&self) -> u8 { 0 }
15+
fn bar(&self) -> u8 { 1 }
16+
fn meh(&self) -> u8 { 2 }
17+
}
18+
19+
struct Z(u8);
20+
21+
impl Trait for Z {
22+
reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
23+
//~^ ERROR: use of undeclared lifetime name `'a`
24+
//~| ERROR: use of undeclared lifetime name `'a`
25+
//~| ERROR: use of undeclared lifetime name `'a`
26+
//~| ERROR: the trait bound `u8: Trait` is not satisfied
27+
//~| ERROR: the trait bound `u8: Trait` is not satisfied
28+
//~| ERROR: the trait bound `u8: Trait` is not satisfied
29+
//~| ERROR: mismatched types
30+
//~| ERROR: mismatched types
31+
//~| ERROR: mismatched types
32+
}
33+
34+
fn main() { }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
error[E0261]: use of undeclared lifetime name `'a`
2+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
3+
|
4+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
5+
| ^^ undeclared lifetime
6+
|
7+
help: consider introducing lifetime `'a` here
8+
|
9+
LL | reuse <u8 as Trait>::{foo'a, , bar, meh} { &const { InvariantRef::<'a>::NEW } }
10+
| +++
11+
help: consider introducing lifetime `'a` here
12+
|
13+
LL | impl<'a> Trait for Z {
14+
| ++++
15+
16+
error[E0261]: use of undeclared lifetime name `'a`
17+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
18+
|
19+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
20+
| ^^ undeclared lifetime
21+
|
22+
help: consider introducing lifetime `'a` here
23+
|
24+
LL | reuse <u8 as Trait>::{foo, bar'a, , meh} { &const { InvariantRef::<'a>::NEW } }
25+
| +++
26+
help: consider introducing lifetime `'a` here
27+
|
28+
LL | impl<'a> Trait for Z {
29+
| ++++
30+
31+
error[E0261]: use of undeclared lifetime name `'a`
32+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:68
33+
|
34+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
35+
| ^^ undeclared lifetime
36+
|
37+
help: consider introducing lifetime `'a` here
38+
|
39+
LL | reuse <u8 as Trait>::{foo, bar, meh'a, } { &const { InvariantRef::<'a>::NEW } }
40+
| +++
41+
help: consider introducing lifetime `'a` here
42+
|
43+
LL | impl<'a> Trait for Z {
44+
| ++++
45+
46+
error[E0599]: no function or associated item named `new` found for struct `InvariantRef` in the current scope
47+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:9:41
48+
|
49+
LL | pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
50+
| -------------------------------------- function or associated item `new` not found for this struct
51+
...
52+
LL | pub const NEW: Self = InvariantRef::new(&());
53+
| ^^^ function or associated item not found in `InvariantRef<'_, _>`
54+
55+
error[E0308]: mismatched types
56+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
57+
|
58+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
59+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
60+
|
61+
= note: expected type `u8`
62+
found struct `InvariantRef<'_, ()>`
63+
64+
error[E0277]: the trait bound `u8: Trait` is not satisfied
65+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
66+
|
67+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
68+
| ^^ the trait `Trait` is not implemented for `u8`
69+
|
70+
= help: the trait `Trait` is implemented for `Z`
71+
72+
error[E0308]: mismatched types
73+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
74+
|
75+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
76+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
77+
|
78+
= note: expected type `u8`
79+
found struct `InvariantRef<'_, ()>`
80+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
81+
82+
error[E0277]: the trait bound `u8: Trait` is not satisfied
83+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
84+
|
85+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
86+
| ^^ the trait `Trait` is not implemented for `u8`
87+
|
88+
= help: the trait `Trait` is implemented for `Z`
89+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
90+
91+
error[E0308]: mismatched types
92+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:53
93+
|
94+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
95+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `u8`, found `InvariantRef<'_, ()>`
96+
|
97+
= note: expected type `u8`
98+
found struct `InvariantRef<'_, ()>`
99+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
100+
101+
error[E0277]: the trait bound `u8: Trait` is not satisfied
102+
--> $DIR/correct_body_owner_parent_found_in_diagnostics.rs:22:12
103+
|
104+
LL | reuse <u8 as Trait>::{foo, bar, meh} { &const { InvariantRef::<'a>::NEW } }
105+
| ^^ the trait `Trait` is not implemented for `u8`
106+
|
107+
= help: the trait `Trait` is implemented for `Z`
108+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
109+
110+
error: aborting due to 10 previous errors
111+
112+
Some errors have detailed explanations: E0261, E0277, E0308, E0599.
113+
For more information about an error, try `rustc --explain E0261`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fn generic<const N: u32>() {}
2+
3+
trait Collate<const A: u32> {
4+
type Pass;
5+
fn collate(self) -> Self::Pass;
6+
}
7+
8+
impl<const B: u32> Collate<B> for i32 {
9+
type Pass = ();
10+
fn collate(self) -> Self::Pass {
11+
generic::<{ true }>()
12+
//~^ ERROR: mismatched types
13+
}
14+
}
15+
16+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/const-in-fn-call-generics.rs:11:21
3+
|
4+
LL | generic::<{ true }>()
5+
| ^^^^ expected `u32`, found `bool`
6+
7+
error: aborting due to 1 previous error
8+
9+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)