Skip to content

Commit 97232bf

Browse files
Normalize struct tail properly in borrowck
1 parent 26234cb commit 97232bf

File tree

6 files changed

+70
-12
lines changed

6 files changed

+70
-12
lines changed

compiler/rustc_borrowck/src/type_check/canonical.rs

+47
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_middle::mir::ConstraintCategory;
77
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
88
use rustc_span::def_id::DefId;
99
use rustc_span::Span;
10+
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
1011
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
1112
use rustc_trait_selection::traits::ObligationCause;
1213

@@ -165,6 +166,52 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
165166
result.unwrap_or(value)
166167
}
167168

169+
#[instrument(skip(self), level = "debug")]
170+
pub(super) fn struct_tail(
171+
&mut self,
172+
ty: Ty<'tcx>,
173+
location: impl NormalizeLocation,
174+
) -> Ty<'tcx> {
175+
let tcx = self.tcx();
176+
if self.infcx.next_trait_solver() {
177+
let body = self.body;
178+
let param_env = self.param_env;
179+
self.fully_perform_op(
180+
location.to_locations(),
181+
ConstraintCategory::Boring,
182+
CustomTypeOp::new(
183+
|ocx| {
184+
let normalize = |ty| {
185+
ocx.structurally_normalize(
186+
&ObligationCause::misc(
187+
location.to_locations().span(body),
188+
body.source.def_id().expect_local(),
189+
),
190+
param_env,
191+
ty,
192+
)
193+
.unwrap_or_else(|_| bug!("struct tail should have been computable, since we computed it in HIR"))
194+
};
195+
196+
let tail = tcx.struct_tail_with_normalize(
197+
ty,
198+
normalize,
199+
|| {},
200+
);
201+
202+
Ok(normalize(tail))
203+
},
204+
"s",
205+
),
206+
)
207+
.unwrap_or_else(|guar| Ty::new_error(tcx, guar))
208+
} else {
209+
let mut normalize = |ty| self.normalize(ty, location);
210+
let tail = tcx.struct_tail_with_normalize(ty, &mut normalize, || {});
211+
normalize(tail)
212+
}
213+
}
214+
168215
#[instrument(skip(self), level = "debug")]
169216
pub(super) fn ascribe_user_type(
170217
&mut self,

compiler/rustc_borrowck/src/type_check/mod.rs

+2-11
Original file line numberDiff line numberDiff line change
@@ -2329,17 +2329,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23292329
let cast_ty_to = CastTy::from_ty(*ty);
23302330
match (cast_ty_from, cast_ty_to) {
23312331
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
2332-
let mut normalize = |t| self.normalize(t, location);
2333-
2334-
// N.B. `struct_tail_with_normalize` only "structurally resolves"
2335-
// the type. It is not fully normalized, so we have to normalize it
2336-
// afterwards.
2337-
let src_tail =
2338-
tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
2339-
let src_tail = normalize(src_tail);
2340-
let dst_tail =
2341-
tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
2342-
let dst_tail = normalize(dst_tail);
2332+
let src_tail = self.struct_tail(src.ty, location);
2333+
let dst_tail = self.struct_tail(dst.ty, location);
23432334

23442335
// This checks (lifetime part of) vtable validity for pointer casts,
23452336
// which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).

compiler/rustc_hir_typeck/src/cast.rs

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9797
return Ok(Some(PointerKind::Thin));
9898
}
9999

100+
let t = self.try_structurally_resolve_type(span, t);
101+
100102
Ok(match *t.kind() {
101103
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
102104
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),

tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.stderr renamed to tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.current.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: lifetime may not live long enough
2-
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:21:17
2+
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
33
|
44
LL | fn m<'a>() {
55
| -- lifetime `'a` defined here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/ptr-to-trait-obj-different-regions-id-trait.rs:24:17
3+
|
4+
LL | fn m<'a>() {
5+
| -- lifetime `'a` defined here
6+
LL | let unsend: *const dyn Cat<'a> = &();
7+
LL | let _send = unsend as *const S<dyn Cat<'static>>;
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
9+
|
10+
= note: requirement occurs because of the type `S<dyn Cat<'_>>`, which makes the generic argument `dyn Cat<'_>` invariant
11+
= note: the struct `S<T>` is invariant over the parameter `T`
12+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
13+
14+
error: aborting due to 1 previous error
15+

tests/ui/cast/ptr-to-trait-obj-different-regions-id-trait.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//@ revisions: current next
2+
//@ ignore-compare-mode-next-solver (explicit revisions)
3+
//@[next] compile-flags: -Znext-solver
14
//@ check-fail
25
//
36
// Make sure we can't trick the compiler by using a projection.

0 commit comments

Comments
 (0)