Skip to content

Commit 56227e6

Browse files
author
Lukas Markeffsky
committed
always use shallow tail for metadata projections
1 parent be9ac56 commit 56227e6

File tree

5 files changed

+111
-68
lines changed

5 files changed

+111
-68
lines changed

compiler/rustc_trait_selection/src/traits/project.rs

+74-51
Original file line numberDiff line numberDiff line change
@@ -1075,24 +1075,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
10751075
| ty::Error(_) => false,
10761076
}
10771077
} else if lang_items.pointee_trait() == Some(trait_ref.def_id) {
1078-
let tail = selcx.tcx().struct_tail_with_normalize(
1079-
self_ty,
1080-
|ty| {
1081-
// We throw away any obligations we get from this, since we normalize
1082-
// and confirm these obligations once again during confirmation
1083-
normalize_with_depth(
1084-
selcx,
1085-
obligation.param_env,
1086-
obligation.cause.clone(),
1087-
obligation.recursion_depth + 1,
1088-
ty,
1089-
)
1090-
.value
1091-
},
1092-
|| {},
1093-
);
1094-
1095-
match tail.kind() {
1078+
match self_ty.kind() {
10961079
ty::Bool
10971080
| ty::Char
10981081
| ty::Int(_)
@@ -1113,21 +1096,17 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
11131096
| ty::Never
11141097
// Extern types have unit metadata, according to RFC 2850
11151098
| ty::Foreign(_)
1116-
// If returned by `struct_tail_without_normalization` this is a unit struct
1117-
// without any fields, or not a struct, and therefore is Sized.
1099+
// The metadata of an ADT or tuple is the metadata of its tail,
1100+
// or unit if it has no tail.
11181101
| ty::Adt(..)
1119-
// If returned by `struct_tail_without_normalization` this is the empty tuple.
11201102
| ty::Tuple(..)
1121-
// Integers and floats are always Sized, and so have unit type metadata.
1103+
// Integers and floats are always sized, and so have unit type metadata.
11221104
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..))
1123-
// `{type error}` is sized, so its metadata must be the unit type.
1105+
// The metadata of `{type error}` is `{type error}`.
11241106
| ty::Error(_) => true,
11251107

1126-
// We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata`.
1127-
ty::Param(_) | ty::Alias(..) => self_ty != tail,
1128-
1129-
// FIXME: These should probably project to the tail as well.
1130-
ty::Bound(..) | ty::Placeholder(..) => false,
1108+
// The metadata of these types can only be known from param env candidates.
1109+
ty::Param(_) | ty::Alias(..) | ty::Bound(..) | ty::Placeholder(..) => false,
11311110

11321111
ty::Infer(ty::TyVar(_)) => {
11331112
candidate_set.mark_ambiguous();
@@ -1485,49 +1464,93 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
14851464
let lang_items = tcx.lang_items();
14861465
let item_def_id = obligation.predicate.def_id;
14871466
let trait_def_id = tcx.trait_of_item(item_def_id).unwrap();
1488-
let (term, obligations) = if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
1467+
let mut potentially_unnormalized = false;
1468+
let term = if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
14891469
let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None);
14901470
assert_eq!(discriminant_def_id, item_def_id);
14911471

1492-
(self_ty.discriminant_ty(tcx).into(), Vec::new())
1472+
self_ty.discriminant_ty(tcx).into()
14931473
} else if lang_items.pointee_trait() == Some(trait_def_id) {
14941474
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
14951475
assert_eq!(metadata_def_id, item_def_id);
14961476

1497-
let mut obligations = Vec::new();
1498-
let normalize = |ty| {
1499-
normalize_with_depth_to(
1500-
selcx,
1501-
obligation.param_env,
1502-
obligation.cause.clone(),
1503-
obligation.recursion_depth + 1,
1504-
ty,
1505-
&mut obligations,
1506-
)
1507-
};
1508-
let metadata_ty = self_ty.ptr_metadata_ty_or_tail(tcx, normalize).unwrap_or_else(|tail| {
1509-
if tail == self_ty {
1477+
let metadata_ty = match self_ty.kind() {
1478+
ty::Bool
1479+
| ty::Char
1480+
| ty::Int(..)
1481+
| ty::Uint(..)
1482+
| ty::Float(..)
1483+
| ty::Array(..)
1484+
| ty::RawPtr(..)
1485+
| ty::Ref(..)
1486+
| ty::FnDef(..)
1487+
| ty::FnPtr(..)
1488+
| ty::Closure(..)
1489+
| ty::CoroutineClosure(..)
1490+
| ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
1491+
| ty::Coroutine(..)
1492+
| ty::CoroutineWitness(..)
1493+
| ty::Never
1494+
| ty::Foreign(..)
1495+
| ty::Dynamic(_, _, ty::DynStar) => tcx.types.unit,
1496+
1497+
ty::Error(e) => Ty::new_error(tcx, *e),
1498+
1499+
ty::Str | ty::Slice(_) => tcx.types.usize,
1500+
1501+
ty::Dynamic(_, _, ty::Dyn) => {
1502+
let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
1503+
tcx.type_of(dyn_metadata).instantiate(tcx, &[self_ty.into()])
1504+
}
1505+
1506+
// We know that `self_ty` has the same metadata as its tail. This allows us
1507+
// to prove predicates like `Wrapper<Tail>::Metadata == Tail::Metadata`.
1508+
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
1509+
None => tcx.types.unit,
1510+
Some(tail_def) => {
1511+
let tail_ty = tail_def.ty(tcx, args);
1512+
potentially_unnormalized = true;
1513+
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
1514+
}
1515+
},
1516+
ty::Adt(_, _) => tcx.types.unit,
1517+
1518+
ty::Tuple(elements) => match elements.last() {
1519+
None => tcx.types.unit,
1520+
Some(&tail_ty) => {
1521+
potentially_unnormalized = true;
1522+
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
1523+
}
1524+
},
1525+
1526+
ty::Param(_)
1527+
| ty::Alias(..)
1528+
| ty::Bound(..)
1529+
| ty::Placeholder(..)
1530+
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
15101531
span_bug!(
15111532
obligation.cause.span,
15121533
"`<{self_ty:?} as Pointee>::Metadata` projection candidate assembled, \
15131534
but we cannot project further",
15141535
);
15151536
}
1516-
// We know that `self_ty` has the same metadata as `tail`. This allows us
1517-
// to prove predicates like `Wrapper<Tail>::Metadata == Tail::Metadata`.
1518-
Ty::new_projection(tcx, metadata_def_id, [tail])
1519-
});
1520-
(metadata_ty.into(), obligations)
1537+
};
1538+
1539+
metadata_ty.into()
15211540
} else {
15221541
bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
15231542
};
15241543

15251544
let predicate =
15261545
ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term };
15271546

1528-
confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
1529-
.with_addl_obligations(obligations)
1530-
.with_addl_obligations(data)
1547+
confirm_param_env_candidate(
1548+
selcx,
1549+
obligation,
1550+
ty::Binder::dummy(predicate),
1551+
potentially_unnormalized,
1552+
)
1553+
.with_addl_obligations(data)
15311554
}
15321555

15331556
fn confirm_fn_pointer_candidate<'cx, 'tcx>(

tests/ui/layout/layout-cycle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::mem;
88

99
pub struct S<T: Tr> {
1010
pub f: <T as Tr>::I,
11-
_tail: (), // without this, we get "reached the recursion limit finding the struct tail" instead
11+
_tail: (), // without this, we get an overflow error instead
1212
}
1313

1414
pub trait Tr {

tests/ui/sized/recursive-type-tail.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//@ check-fail
2-
//@ error-pattern: reached the recursion limit finding the struct tail
32

43
trait A { type Assoc; }
54

65
impl A for () {
76
type Assoc = Foo<()>;
7+
//~^ ERROR overflow evaluating the requirement `<Foo<()> as Pointee>::Metadata == ()`
88
}
99
struct Foo<T: A>(T::Assoc);
1010

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
error: reached the recursion limit finding the struct tail for `<() as A>::Assoc`
1+
error[E0275]: overflow evaluating the requirement `<Foo<()> as Pointee>::Metadata == ()`
2+
--> $DIR/recursive-type-tail.rs:6:18
23
|
3-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
4-
5-
error: reached the recursion limit finding the struct tail for `<() as A>::Assoc`
4+
LL | type Assoc = Foo<()>;
5+
| ^^^^^^^
66
|
7-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
8-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
9-
10-
error: reached the recursion limit finding the struct tail for `<() as A>::Assoc`
7+
= note: required for `<() as A>::Assoc` to implement `Thin`
8+
= note: required for `<() as A>::Assoc` to implement `Sized`
9+
note: required by a bound in `A::Assoc`
10+
--> $DIR/recursive-type-tail.rs:3:11
1111
|
12-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
13-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
14-
15-
error: reached the recursion limit finding the struct tail for `<() as A>::Assoc`
12+
LL | trait A { type Assoc; }
13+
| ^^^^^^^^^^^ required by this bound in `A::Assoc`
14+
help: consider relaxing the implicit `Sized` restriction
1615
|
17-
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
18-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
16+
LL | trait A { type Assoc: ?Sized; }
17+
| ++++++++
1918

20-
error: aborting due to 4 previous errors
19+
error: aborting due to 1 previous error
2120

21+
For more information about this error, try `rustc --explain E0275`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ check-pass
2+
3+
#![feature(ptr_metadata)]
4+
5+
use std::ptr::Thin;
6+
7+
struct Wrapper<T: ?Sized>(T);
8+
9+
fn check_thin<T: ?Sized + Thin>() {}
10+
11+
// Test that normalization of `<Wrapper<[T]> as Pointee>::Metadata` respects the
12+
// `<[T] as Pointee>::Metadata == ()` bound from the param env.
13+
fn foo<T>()
14+
where
15+
[T]: Thin,
16+
{
17+
check_thin::<Wrapper<[T]>>();
18+
}
19+
20+
fn main() {}

0 commit comments

Comments
 (0)