Skip to content

Commit

Permalink
Normalize struct tail properly in borrowck
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Aug 5, 2024
1 parent 26234cb commit 97232bf
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 12 deletions.
47 changes: 47 additions & 0 deletions compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
use rustc_trait_selection::traits::ObligationCause;

Expand Down Expand Up @@ -165,6 +166,52 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
result.unwrap_or(value)
}

#[instrument(skip(self), level = "debug")]
pub(super) fn struct_tail(
&mut self,
ty: Ty<'tcx>,
location: impl NormalizeLocation,
) -> Ty<'tcx> {
let tcx = self.tcx();
if self.infcx.next_trait_solver() {
let body = self.body;
let param_env = self.param_env;
self.fully_perform_op(
location.to_locations(),
ConstraintCategory::Boring,
CustomTypeOp::new(
|ocx| {
let normalize = |ty| {
ocx.structurally_normalize(
&ObligationCause::misc(
location.to_locations().span(body),
body.source.def_id().expect_local(),
),
param_env,
ty,
)
.unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
};

let tail = tcx.struct_tail_with_normalize(
ty,
normalize,
|| {},
);

Ok(normalize(tail))
},
"s",
),
)
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
} else {
let mut normalize = |ty| self.normalize(ty, location);
let tail = tcx.struct_tail_with_normalize(ty, &mut normalize, || {});
normalize(tail)
}
}

#[instrument(skip(self), level = "debug")]
pub(super) fn ascribe_user_type(
&mut self,
Expand Down
13 changes: 2 additions & 11 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2329,17 +2329,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let cast_ty_to = CastTy::from_ty(*ty);
match (cast_ty_from, cast_ty_to) {
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
let mut normalize = |t| self.normalize(t, location);

// N.B. `struct_tail_with_normalize` only "structurally resolves"
// the type. It is not fully normalized, so we have to normalize it
// afterwards.
let src_tail =
tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
let src_tail = normalize(src_tail);
let dst_tail =
tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
let dst_tail = normalize(dst_tail);
let src_tail = self.struct_tail(src.ty, location);
let dst_tail = self.struct_tail(dst.ty, location);

// This checks (lifetime part of) vtable validity for pointer casts,
// which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_typeck/src/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return Ok(Some(PointerKind::Thin));
}

let t = self.try_structurally_resolve_type(span, t);

Ok(match *t.kind() {
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: lifetime may not live long enough
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
|
LL | fn m<'a>() {
| -- lifetime `'a` defined here
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error: lifetime may not live long enough
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
|
LL | fn m<'a>() {
| -- lifetime `'a` defined here
LL | let unsend: *const dyn Cat<'a> = &();
LL | let _send = unsend as *const S<dyn Cat<'static>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
|
= note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
= note: the struct `S<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: aborting due to 1 previous error

3 changes: 3 additions & 0 deletions tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
//@ check-fail
//
// Make sure we can't trick the compiler by using a projection.
Expand Down

0 comments on commit 97232bf

Please sign in to comment.