Skip to content

Commit 3799af3

Browse files
committed
diagnostics: avoid mismatch between variance index and hir generic
This happens because variances are constructed from ty generics, and ty generics are always constructed with lifetimes first. See compiler/rustc_hir_analysis/src/collect/generics_of.rs:248-269 Fixes #83556
1 parent b3aa8e7 commit 3799af3

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,20 +1755,41 @@ fn check_variances_for_type_defn<'tcx>(
17551755
.collect::<FxHashSet<_>>()
17561756
});
17571757

1758+
let ty_generics = tcx.generics_of(item.owner_id);
1759+
17581760
for (index, _) in variances.iter().enumerate() {
17591761
let parameter = Parameter(index as u32);
17601762

17611763
if constrained_parameters.contains(&parameter) {
17621764
continue;
17631765
}
17641766

1765-
let param = &hir_generics.params[index];
1767+
let ty_param = &ty_generics.params[index];
1768+
let mut hir_param = &hir_generics.params[index];
1769+
1770+
if ty_param.name != hir_param.name.ident().name {
1771+
// valid programs always have lifetimes before types in the generic parameter list
1772+
// ty_generics are normalized to be in this required order, and variances are built
1773+
// from ty generics, not from hir generics. but we need hir generics to get
1774+
// a span out
1775+
//
1776+
// if they aren't in the same order, then the user has written invalid code, and already
1777+
// got an error about it (or I'm wrong about this)
1778+
tcx.sess
1779+
.delay_span_bug(hir_param.span, "hir generics and ty generics in different order");
1780+
for hp in hir_generics.params {
1781+
if hp.name.ident().name == ty_param.name {
1782+
hir_param = hp;
1783+
break;
1784+
}
1785+
}
1786+
}
17661787

1767-
match param.name {
1788+
match hir_param.name {
17681789
hir::ParamName::Error => {}
17691790
_ => {
17701791
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
1771-
report_bivariance(tcx, param, has_explicit_bounds);
1792+
report_bivariance(tcx, hir_param, has_explicit_bounds);
17721793
}
17731794
}
17741795
}

tests/ui/generics/issue-83556.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
struct Foo<T, 'a>(&'a ());
2+
//~^ ERROR lifetime parameters must be declared prior to
3+
//~| ERROR parameter `T` is never used
4+
5+
fn main() {}

tests/ui/generics/issue-83556.stderr

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: lifetime parameters must be declared prior to type and const parameters
2+
--> $DIR/issue-83556.rs:1:15
3+
|
4+
LL | struct Foo<T, 'a>(&'a ());
5+
| ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>`
6+
7+
error[E0392]: parameter `T` is never used
8+
--> $DIR/issue-83556.rs:1:12
9+
|
10+
LL | struct Foo<T, 'a>(&'a ());
11+
| ^ unused parameter
12+
|
13+
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
14+
= help: if you intended `T` to be a const parameter, use `const T: usize` instead
15+
16+
error: aborting due to 2 previous errors
17+
18+
For more information about this error, try `rustc --explain E0392`.

0 commit comments

Comments
 (0)