Skip to content

Commit 7449478

Browse files
committed
Account for type param from other item in note_and_explain
Fix rust-lang#89868.
1 parent 3bbc70a commit 7449478

File tree

4 files changed

+175
-43
lines changed

4 files changed

+175
-43
lines changed

compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs

+61-43
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
5454
}
5555
(ty::Param(expected), ty::Param(found)) => {
5656
let generics = tcx.generics_of(body_owner_def_id);
57-
let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
58-
if !sp.contains(e_span) {
59-
diag.span_label(e_span, "expected type parameter");
57+
if let Some(param) = generics.opt_type_param(expected, tcx) {
58+
let e_span = tcx.def_span(param.def_id);
59+
if !sp.contains(e_span) {
60+
diag.span_label(e_span, "expected type parameter");
61+
}
6062
}
61-
let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
62-
if !sp.contains(f_span) {
63-
diag.span_label(f_span, "found type parameter");
63+
if let Some(param) = generics.opt_type_param(found, tcx) {
64+
let f_span = tcx.def_span(param.def_id);
65+
if !sp.contains(f_span) {
66+
diag.span_label(f_span, "found type parameter");
67+
}
6468
}
6569
diag.note(
6670
"a type parameter was expected, but a different one was found; \
@@ -83,23 +87,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
8387
| (ty::Alias(ty::Projection, proj), ty::Param(p))
8488
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
8589
{
86-
let p_def_id = tcx.generics_of(body_owner_def_id).type_param(p, tcx).def_id;
87-
let p_span = tcx.def_span(p_def_id);
88-
let expected = match (values.expected.kind(), values.found.kind()) {
89-
(ty::Param(_), _) => "expected ",
90-
(_, ty::Param(_)) => "found ",
91-
_ => "",
92-
};
93-
if !sp.contains(p_span) {
94-
diag.span_label(p_span, format!("{expected}this type parameter"));
95-
}
96-
let hir = tcx.hir();
90+
let parent = tcx.generics_of(body_owner_def_id)
91+
.opt_type_param(p, tcx)
92+
.and_then(|param| {
93+
let p_def_id = param.def_id;
94+
let p_span = tcx.def_span(p_def_id);
95+
let expected = match (values.expected.kind(), values.found.kind()) {
96+
(ty::Param(_), _) => "expected ",
97+
(_, ty::Param(_)) => "found ",
98+
_ => "",
99+
};
100+
if !sp.contains(p_span) {
101+
diag.span_label(
102+
p_span,
103+
format!("{expected}this type parameter"),
104+
);
105+
}
106+
p_def_id.as_local().and_then(|id| {
107+
let local_id = tcx.hir().local_def_id_to_hir_id(id);
108+
let generics = tcx.hir().find_parent(local_id)?.generics()?;
109+
Some((id, generics))
110+
})
111+
});
97112
let mut note = true;
98-
let parent = p_def_id.as_local().and_then(|id| {
99-
let local_id = hir.local_def_id_to_hir_id(id);
100-
let generics = tcx.hir().find_parent(local_id)?.generics()?;
101-
Some((id, generics))
102-
});
103113
if let Some((local_id, generics)) = parent {
104114
// Synthesize the associated type restriction `Add<Output = Expected>`.
105115
// FIXME: extract this logic for use in other diagnostics.
@@ -172,14 +182,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
172182
(ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
173183
| (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
174184
let generics = tcx.generics_of(body_owner_def_id);
175-
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
176-
let expected = match (values.expected.kind(), values.found.kind()) {
177-
(ty::Param(_), _) => "expected ",
178-
(_, ty::Param(_)) => "found ",
179-
_ => "",
180-
};
181-
if !sp.contains(p_span) {
182-
diag.span_label(p_span, format!("{expected}this type parameter"));
185+
if let Some(param) = generics.opt_type_param(p, tcx) {
186+
let p_span = tcx.def_span(param.def_id);
187+
let expected = match (values.expected.kind(), values.found.kind()) {
188+
(ty::Param(_), _) => "expected ",
189+
(_, ty::Param(_)) => "found ",
190+
_ => "",
191+
};
192+
if !sp.contains(p_span) {
193+
diag.span_label(p_span, format!("{expected}this type parameter"));
194+
}
183195
}
184196
diag.help("type parameters must be constrained to match other types");
185197
if tcx.sess.teach(&diag.get_code().unwrap()) {
@@ -217,9 +229,11 @@ impl<T> Trait<T> for X {
217229
}
218230
(ty::Param(p), ty::Closure(..) | ty::Coroutine(..)) => {
219231
let generics = tcx.generics_of(body_owner_def_id);
220-
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
221-
if !sp.contains(p_span) {
222-
diag.span_label(p_span, "expected this type parameter");
232+
if let Some(param) = generics.opt_type_param(p, tcx) {
233+
let p_span = tcx.def_span(param.def_id);
234+
if !sp.contains(p_span) {
235+
diag.span_label(p_span, "expected this type parameter");
236+
}
223237
}
224238
diag.help(format!(
225239
"every closure has a distinct type and so could not always match the \
@@ -228,14 +242,16 @@ impl<T> Trait<T> for X {
228242
}
229243
(ty::Param(p), _) | (_, ty::Param(p)) => {
230244
let generics = tcx.generics_of(body_owner_def_id);
231-
let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
232-
let expected = match (values.expected.kind(), values.found.kind()) {
233-
(ty::Param(_), _) => "expected ",
234-
(_, ty::Param(_)) => "found ",
235-
_ => "",
236-
};
237-
if !sp.contains(p_span) {
238-
diag.span_label(p_span, format!("{expected}this type parameter"));
245+
if let Some(param) = generics.opt_type_param(p, tcx) {
246+
let p_span = tcx.def_span(param.def_id);
247+
let expected = match (values.expected.kind(), values.found.kind()) {
248+
(ty::Param(_), _) => "expected ",
249+
(_, ty::Param(_)) => "found ",
250+
_ => "",
251+
};
252+
if !sp.contains(p_span) {
253+
diag.span_label(p_span, format!("{expected}this type parameter"));
254+
}
239255
}
240256
}
241257
(ty::Alias(ty::Projection | ty::Inherent, proj_ty), _)
@@ -368,8 +384,10 @@ impl<T> Trait<T> for X {
368384
return false;
369385
};
370386
let generics = tcx.generics_of(body_owner_def_id);
371-
let def_id = generics.type_param(param_ty, tcx).def_id;
372-
let Some(def_id) = def_id.as_local() else {
387+
let Some(param) = generics.opt_type_param(param_ty, tcx) else {
388+
return false;
389+
};
390+
let Some(def_id) = param.def_id.as_local() else {
373391
return false;
374392
};
375393

compiler/rustc_middle/src/ty/generics.rs

+28
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,20 @@ impl<'tcx> Generics {
237237
}
238238
}
239239

240+
/// Returns the `GenericParamDef` with the given index if available.
241+
pub fn opt_param_at(
242+
&'tcx self,
243+
param_index: usize,
244+
tcx: TyCtxt<'tcx>,
245+
) -> Option<&'tcx GenericParamDef> {
246+
if let Some(index) = param_index.checked_sub(self.parent_count) {
247+
self.params.get(index)
248+
} else {
249+
tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
250+
.opt_param_at(param_index, tcx)
251+
}
252+
}
253+
240254
pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] {
241255
if let Some(index) = param_index.checked_sub(self.parent_count) {
242256
&self.params[..index]
@@ -268,6 +282,20 @@ impl<'tcx> Generics {
268282
}
269283
}
270284

285+
/// Returns the `GenericParamDef` associated with this `ParamTy` if it belongs to this
286+
/// `Generics`.
287+
pub fn opt_type_param(
288+
&'tcx self,
289+
param: &ParamTy,
290+
tcx: TyCtxt<'tcx>,
291+
) -> Option<&'tcx GenericParamDef> {
292+
let param = self.opt_param_at(param.index as usize, tcx)?;
293+
match param.kind {
294+
GenericParamDefKind::Type { .. } => Some(param),
295+
_ => None,
296+
}
297+
}
298+
271299
/// Returns the `GenericParamDef` associated with this `ParamConst`.
272300
pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
273301
let param = self.param_at(param.index as usize, tcx);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct A<B>(B);
2+
impl<B>A<B>{fn d(){fn d(){Self(1)}}}
3+
//~^ ERROR the size for values of type `B` cannot be known at compilation time
4+
//~| ERROR the size for values of type `B` cannot be known at compilation time
5+
//~| ERROR mismatched types
6+
//~| ERROR mismatched types
7+
//~| ERROR `main` function not found in crate
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
error[E0601]: `main` function not found in crate `do_not_ice_on_note_and_explain`
2+
--> $DIR/do-not-ice-on-note_and_explain.rs:2:37
3+
|
4+
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
5+
| ^ consider adding a `main` function to `$DIR/do-not-ice-on-note_and_explain.rs`
6+
7+
error[E0277]: the size for values of type `B` cannot be known at compilation time
8+
--> $DIR/do-not-ice-on-note_and_explain.rs:2:32
9+
|
10+
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
11+
| - ---- ^ doesn't have a size known at compile-time
12+
| | |
13+
| | required by a bound introduced by this call
14+
| this type parameter needs to be `Sized`
15+
|
16+
note: required by a bound in `A`
17+
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
18+
|
19+
LL | struct A<B>(B);
20+
| ^ required by this bound in `A`
21+
22+
error[E0308]: mismatched types
23+
--> $DIR/do-not-ice-on-note_and_explain.rs:2:32
24+
|
25+
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
26+
| ---- ^ expected type parameter `B`, found integer
27+
| |
28+
| arguments to this function are incorrect
29+
|
30+
= note: expected type parameter `B`
31+
found type `{integer}`
32+
note: tuple struct defined here
33+
--> $DIR/do-not-ice-on-note_and_explain.rs:1:8
34+
|
35+
LL | struct A<B>(B);
36+
| ^
37+
38+
error[E0308]: mismatched types
39+
--> $DIR/do-not-ice-on-note_and_explain.rs:2:27
40+
|
41+
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
42+
| ^^^^^^^ expected `()`, found `A<B>`
43+
|
44+
= note: expected unit type `()`
45+
found struct `A<B>`
46+
help: consider using a semicolon here
47+
|
48+
LL | impl<B>A<B>{fn d(){fn d(){Self(1);}}}
49+
| +
50+
help: try adding a return type
51+
|
52+
LL | impl<B>A<B>{fn d(){fn d() -> A<B>{Self(1)}}}
53+
| +++++++
54+
55+
error[E0277]: the size for values of type `B` cannot be known at compilation time
56+
--> $DIR/do-not-ice-on-note_and_explain.rs:2:27
57+
|
58+
LL | impl<B>A<B>{fn d(){fn d(){Self(1)}}}
59+
| - ^^^^^^^ doesn't have a size known at compile-time
60+
| |
61+
| this type parameter needs to be `Sized`
62+
|
63+
note: required by a bound in `A`
64+
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
65+
|
66+
LL | struct A<B>(B);
67+
| ^ required by this bound in `A`
68+
help: you could relax the implicit `Sized` bound on `B` if it were used through indirection like `&B` or `Box<B>`
69+
--> $DIR/do-not-ice-on-note_and_explain.rs:1:10
70+
|
71+
LL | struct A<B>(B);
72+
| ^ - ...if indirection were used here: `Box<B>`
73+
| |
74+
| this could be changed to `B: ?Sized`...
75+
76+
error: aborting due to 5 previous errors
77+
78+
Some errors have detailed explanations: E0277, E0308, E0601.
79+
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)