Skip to content

Commit

Permalink
Use the error variance for unused generic args
Browse files Browse the repository at this point in the history
  • Loading branch information
oli-obk committed Jun 7, 2024
1 parent 68cc323 commit 026183d
Show file tree
Hide file tree
Showing 17 changed files with 125 additions and 63 deletions.
38 changes: 19 additions & 19 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1802,8 +1802,8 @@ fn receiver_is_implemented<'tcx>(
pub fn check_variances_for_type_defn<'tcx>(
tcx: TyCtxt<'tcx>,
item: LocalDefId,
variances: &[ty::Variance],
) -> Result<(), ErrorGuaranteed> {
variances: &'tcx [ty::Variance],
) -> Result<&'tcx [ty::Variance], ErrorGuaranteed> {
let identity_args = ty::GenericArgs::identity_for_item(tcx, item);

match tcx.def_kind(item) {
Expand All @@ -1819,7 +1819,7 @@ pub fn check_variances_for_type_defn<'tcx>(
);
tcx.type_of(item).skip_binder().error_reported()?;
}
_ => return Ok(()),
_ => return Ok(variances),
}

let ty_predicates = tcx.predicates_of(item);
Expand Down Expand Up @@ -1856,7 +1856,7 @@ pub fn check_variances_for_type_defn<'tcx>(

let ty_generics = tcx.generics_of(item);

let mut res = Ok(());
let mut variances = variances;

for (index, _) in variances.iter().enumerate() {
let parameter = Parameter(index as u32);
Expand All @@ -1868,30 +1868,30 @@ pub fn check_variances_for_type_defn<'tcx>(
let ty_param = &ty_generics.own_params[index];
let hir_param = &hir_generics.params[index];

if ty_param.def_id != hir_param.def_id.into() {
let guar = if ty_param.def_id != hir_param.def_id.into() {
// Valid programs always have lifetimes before types in the generic parameter list.
// ty_generics are normalized to be in this required order, and variances are built
// from ty generics, not from hir generics. but we need hir generics to get
// a span out.
//
// If they aren't in the same order, then the user has written invalid code, and already
// got an error about it (or I'm wrong about this).
tcx.dcx().span_delayed_bug(
hir_param.span,
"hir generics and ty generics in different order",
);
continue;
}

match hir_param.name {
hir::ParamName::Error(guar) => res = Err(guar),
_ => {
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
res = Err(report_bivariance(tcx, hir_param, has_explicit_bounds, item));
tcx.dcx()
.span_delayed_bug(hir_param.span, "hir generics and ty generics in different order")
} else {
match hir_param.name {
hir::ParamName::Error(guar) => guar,
_ => {
let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
report_bivariance(tcx, hir_param, has_explicit_bounds, item)
}
}
}
};
let mut v = variances.to_vec();
v[index] = ty::Variance::Errvariant(guar);
variances = tcx.arena.alloc_slice(&v);
}
res
Ok(variances)
}

fn report_bivariance(
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_hir_analysis/src/variance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
}
};

let _ = crate::check::wfcheck::check_variances_for_type_defn(tcx, item_def_id, variances);
variances
match crate::check::wfcheck::check_variances_for_type_defn(tcx, item_def_id, variances) {
Ok(variances) => variances,
Err(guar) => tcx.arena.alloc_from_iter(variances.iter().map(|_| ty::Errvariant(guar))),
}
}

#[instrument(level = "trace", skip(tcx), ret)]
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_infer/src/infer/relate/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> {
match variance {
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
ty::Covariant => self.relate(a, b),
// TODO: report a new error kind
ty::Errvariant(_) => Ok(a),
ty::Errvariant(guar) => {
self.fields.infcx.set_tainted_by_errors(guar);
Ok(a)
}
// FIXME(#41044) -- not correct, need test
ty::Bivariant => Ok(a),
ty::Contravariant => self.fields.lub().relate(a, b),
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_infer/src/infer/relate/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
match variance {
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
ty::Covariant => self.relate(a, b),
// TODO: report a new kind of type error that preserves the `ErrorGuaranteed`?
ty::Errvariant(_) => Ok(a),
ty::Errvariant(guar) => {
self.fields.infcx.set_tainted_by_errors(guar);
Ok(a)
}
// FIXME(#41044) -- not correct, need test
ty::Bivariant => Ok(a),
ty::Contravariant => self.fields.glb().relate(a, b),
Expand Down
12 changes: 10 additions & 2 deletions compiler/rustc_infer/src/infer/relate/type_relating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,11 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
ty::Invariant => {
infcx.inner.borrow_mut().type_variables().equate(a_id, b_id);
}
ty::Errvariant(_) | ty::Bivariant => {
ty::Errvariant(guar) => {
infcx.set_tainted_by_errors(guar);
return Ok(Ty::new_error(self.tcx(), guar));
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
}
Expand Down Expand Up @@ -204,7 +208,11 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> {
.unwrap_region_constraints()
.make_eqregion(origin, a, b);
}
ty::Errvariant(_) | ty::Bivariant => {
ty::Errvariant(guar) => {
self.fields.infcx.set_tainted_by_errors(guar);
return Ok(ty::Region::new_error(self.tcx(), guar));
}
ty::Bivariant => {
unreachable!("Expected bivariance to be handled in relate_with_variance")
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
struct Fail<T>;
//~^ ERROR: type parameter `T` is never used

impl Fail<i32> {
const C: () = ();
}

fn main() {
Fail::<()>::C
//~^ ERROR: no associated item named `C` found for struct `Fail<()>`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0392]: type parameter `T` is never used
--> $DIR/wrong-projection-self-ty-on-invalid-type.rs:1:13
|
LL | struct Fail<T>;
| ^ unused type parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead

error[E0599]: no associated item named `C` found for struct `Fail<()>` in the current scope
--> $DIR/wrong-projection-self-ty-on-invalid-type.rs:9:17
|
LL | struct Fail<T>;
| -------------- associated item `C` not found for this struct
...
LL | Fail::<()>::C
| ^ associated item not found in `Fail<()>`
|
= note: the associated item was found for
- `Fail<i32>`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0392, E0599.
For more information about an error, try `rustc --explain E0392`.
1 change: 0 additions & 1 deletion tests/ui/inference/dont-collect-stmts-from-parent-body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ fn main() {
impl<T> Type<T> {
fn new() -> Type<T> {
Type
//~^ ERROR type annotations needed
}
}
};
Expand Down
16 changes: 2 additions & 14 deletions tests/ui/inference/dont-collect-stmts-from-parent-body.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,6 @@ LL | struct Type<T>;
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
= help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead

error[E0282]: type annotations needed
--> $DIR/dont-collect-stmts-from-parent-body.rs:10:17
|
LL | Type
| ^^^^ cannot infer type of the type parameter `T` declared on the struct `Type`
|
help: consider specifying the generic argument
|
LL | Type::<T>
| +++++

error: aborting due to 2 previous errors
error: aborting due to 1 previous error

Some errors have detailed explanations: E0282, E0392.
For more information about an error, try `rustc --explain E0282`.
For more information about this error, try `rustc --explain E0392`.
1 change: 1 addition & 0 deletions tests/ui/traits/trait-selection-ice-84727.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ where
{
fn over(self) -> Cell<NewFg> {
//~^ ERROR mismatched types
//~| ERROR `over` has an incompatible type for trait
self.over();
}
}
Expand Down
34 changes: 29 additions & 5 deletions tests/ui/traits/trait-selection-ice-84727.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ LL | Self: Over<Color<BottomBg>, Cell<NewFg>>,
| ^^^^^ not found in this scope

error[E0412]: cannot find type `NewBg` in this scope
--> $DIR/trait-selection-ice-84727.rs:32:27
--> $DIR/trait-selection-ice-84727.rs:33:27
|
LL | fn over(self) -> Cell<NewBg> {
| ^^^^^ not found in this scope
Expand All @@ -27,21 +27,45 @@ help: you might be missing a type parameter
LL | impl<'b, TopFg, TopBg, BottomFg, BottomBg, NewBg> Over<&Cell<BottomFg, BottomBg>, ()>
| +++++++

error[E0053]: method `over` has an incompatible type for trait
--> $DIR/trait-selection-ice-84727.rs:21:22
|
LL | impl<TopFg, TopBg, BottomFg, BottomBg, NewFg, NewBg>
| ----- ----- expected type parameter
| |
| found type parameter
...
LL | fn over(self) -> Cell<NewFg> {
| ^^^^^^^^^^^
| |
| expected type parameter `NewBg`, found type parameter `NewFg`
| help: change the output type to match the trait: `Cell<NewFg, NewBg>`
|
note: type in trait
--> $DIR/trait-selection-ice-84727.rs:12:22
|
LL | fn over(self) -> Output;
| ^^^^^^
= note: expected signature `fn(Cell<_, _>) -> Cell<_, NewBg>`
found signature `fn(Cell<_, _>) -> Cell<_, NewFg>`
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

error[E0308]: mismatched types
--> $DIR/trait-selection-ice-84727.rs:21:22
|
LL | fn over(self) -> Cell<NewFg> {
| ---- ^^^^^^^^^^^ expected `Cell<NewFg>`, found `()`
| |
| implicitly returns `()` as its body has no tail or `return` expression
LL |
...
LL | self.over();
| - help: remove this semicolon to return this value
|
= note: expected struct `Cell<NewFg>`
found unit type `()`

error: aborting due to 5 previous errors
error: aborting due to 6 previous errors

Some errors have detailed explanations: E0308, E0412.
For more information about an error, try `rustc --explain E0308`.
Some errors have detailed explanations: E0053, E0308, E0412.
For more information about an error, try `rustc --explain E0053`.
2 changes: 1 addition & 1 deletion tests/ui/variance/variance-regions-direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
// No uses at all is bivariant:

#[rustc_variance]
struct Test7<'a> { //~ ERROR [*]
struct Test7<'a> { //~ ERROR [💥]
//~^ ERROR: `'a` is never used
x: isize
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/variance/variance-regions-direct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ error: [+, o]
LL | struct Test6<'a, 'b:'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^

error: [*]
error: [💥]
--> $DIR/variance-regions-direct.rs:52:1
|
LL | struct Test7<'a> {
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/variance/variance-regions-indirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@
#![feature(rustc_attrs)]

#[rustc_variance]
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, 💥]
//~^ ERROR: `'d` is never used
Test8A(extern "Rust" fn(&'a isize)),
Test8B(&'b [isize]),
Test8C(&'b mut &'c str),
}

#[rustc_variance]
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -]
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [💥, o, +, -]
//~^ ERROR: `'w` is never used
f: Base<'z, 'y, 'x, 'w>
}

#[rustc_variance] // Combine - and + to yield o
struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, 💥]
//~^ ERROR: `'c` is never used
f: Base<'a, 'a, 'b, 'c>
}

#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *]
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, 💥]
//~^ ERROR: `'c` is never used
f: Base<'a, 'b, 'a, 'c>
}
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/variance/variance-regions-indirect.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@ LL | struct Derived3<'a:'b, 'b, 'c> {
|
= help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData`

error: [-, +, o, *]
error: [-, +, o, 💥]
--> $DIR/variance-regions-indirect.rs:8:1
|
LL | enum Base<'a, 'b, 'c:'b, 'd> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: [*, o, +, -]
error: [💥, o, +, -]
--> $DIR/variance-regions-indirect.rs:16:1
|
LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: [o, o, *]
error: [o, o, 💥]
--> $DIR/variance-regions-indirect.rs:22:1
|
LL | struct Derived2<'a, 'b:'a, 'c> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: [o, +, *]
error: [o, +, 💥]
--> $DIR/variance-regions-indirect.rs:28:1
|
LL | struct Derived3<'a:'b, 'b, 'c> {
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/variance/variance-trait-bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +]
}

#[rustc_variance]
enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +]
enum TestEnum<U,T:Setter<U>> { //~ ERROR [💥, +]
//~^ ERROR: `U` is never used
Foo(T)
}

#[rustc_variance]
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [💥, +]
//~^ ERROR: `U` is never used
t: T
}

#[rustc_variance]
struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [💥, +]
//~^ ERROR: `U` is never used
t: T
}
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/variance/variance-trait-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ error: [+, +]
LL | struct TestStruct<U,T:Setter<U>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: [*, +]
error: [💥, +]
--> $DIR/variance-trait-bounds.rs:21:1
|
LL | enum TestEnum<U,T:Setter<U>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: [*, +]
error: [💥, +]
--> $DIR/variance-trait-bounds.rs:27:1
|
LL | struct TestContraStruct<U,T:Setter<U>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: [*, +]
error: [💥, +]
--> $DIR/variance-trait-bounds.rs:33:1
|
LL | struct TestBox<U,T:Getter<U>+Setter<U>> {
Expand Down

0 comments on commit 026183d

Please sign in to comment.