Skip to content

Commit

Permalink
Rollup merge of rust-lang#120972 - lukas-code:autoderef-type-error, r…
Browse files Browse the repository at this point in the history
…=compiler-errors

fix ICE for deref coercions with type errors

Follow-up to rust-lang#120895, where I made types with errors go through the full coercion code, which is necessary if we want to build MIR for bodies with errors (rust-lang#120550).

The code for coercing `&T` to `&U` currently assumes that autoderef for `&T` will succeed for at least two steps (`&T` and `T`):

https://github.com/rust-lang/rust/blob/b17491c8f6d555386104dfd82004c01bfef09c95/compiler/rustc_hir_typeck/src/coercion.rs#L339-L464

But for types with errors, we previously only returned the no-op autoderef step (`&{type error}` -> `&{type error}`) and then stopped early. This PR changes autoderef for types with errors to still go through the built-in derefs (e.g. `&&{type error}` -> `&{type error}` -> `{type error}`) and only stop early when it would have to go looking for `Deref` trait impls.

fixes rust-lang#120945

r? ``@compiler-errors`` or compiler
  • Loading branch information
matthiaskrgr authored Feb 12, 2024
2 parents 323f66a + 95c5b06 commit 8e5f722
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 12 deletions.
8 changes: 4 additions & 4 deletions compiler/rustc_hir_analysis/src/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,6 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
return None;
};

if new_ty.references_error() {
return None;
}

self.state.steps.push((self.state.cur_ty, kind));
debug!(
"autoderef stage #{:?} is {:?} from {:?}",
Expand Down Expand Up @@ -137,6 +133,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
debug!("overloaded_deref_ty({:?})", ty);
let tcx = self.infcx.tcx;

if ty.references_error() {
return None;
}

// <ty as Deref>
let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1635,6 +1635,12 @@ fn check_method_receiver<'tcx>(
let receiver_ty = sig.inputs()[0];
let receiver_ty = wfcx.normalize(span, None, receiver_ty);

// If the receiver already has errors reported, consider it valid to avoid
// unnecessary errors (#58712).
if receiver_ty.references_error() {
return Ok(());
}

if tcx.features().arbitrary_self_types {
if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) {
// Report error; `arbitrary_self_types` was enabled.
Expand Down Expand Up @@ -1749,9 +1755,7 @@ fn receiver_is_valid<'tcx>(
}
} else {
debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
// If the receiver already has errors reported due to it, consider it valid to avoid
// unnecessary errors (#58712).
return receiver_ty.references_error();
return false;
}
}

Expand Down
19 changes: 15 additions & 4 deletions tests/ui/coercion/type-errors.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
// Regression test for an ICE: https://github.com/rust-lang/rust/issues/120884
// Test that we don't ICE for coercions with type errors.
// We still need to properly go through coercions between types with errors instead of
// shortcutting and returning success, because we need the adjustments for building the MIR.

pub fn has_error() -> TypeError {}
//~^ ERROR cannot find type `TypeError` in this scope

// https://github.com/rust-lang/rust/issues/120884
// Casting a function item to a data pointer in valid in HIR, but invalid in MIR.
// We need an adjustment (ReifyFnPointer) to insert a cast from the function item
// to a function pointer as a separate MIR statement.
pub fn cast() -> *const u8 {
// Casting a function item to a data pointer in valid in HIR, but invalid in MIR.
// We need an adjustment (ReifyFnPointer) to insert a cast from the function item
// to a function pointer as a separate MIR statement.
has_error as *const u8
}

// https://github.com/rust-lang/rust/issues/120945
// This one ICEd, because we skipped the builtin deref from `&TypeError` to `TypeError`.
pub fn autoderef_source(e: &TypeError) {
//~^ ERROR cannot find type `TypeError` in this scope
autoderef_target(e)
}

pub fn autoderef_target(_: &TypeError) {}
//~^ ERROR cannot find type `TypeError` in this scope

fn main() {}
14 changes: 13 additions & 1 deletion tests/ui/coercion/type-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ error[E0412]: cannot find type `TypeError` in this scope
LL | pub fn has_error() -> TypeError {}
| ^^^^^^^^^ not found in this scope

error: aborting due to 1 previous error
error[E0412]: cannot find type `TypeError` in this scope
--> $DIR/type-errors.rs:18:29
|
LL | pub fn autoderef_source(e: &TypeError) {
| ^^^^^^^^^ not found in this scope

error[E0412]: cannot find type `TypeError` in this scope
--> $DIR/type-errors.rs:23:29
|
LL | pub fn autoderef_target(_: &TypeError) {}
| ^^^^^^^^^ not found in this scope

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0412`.

0 comments on commit 8e5f722

Please sign in to comment.