Skip to content

Commit 774655d

Browse files
authored
Rollup merge of #93977 - compiler-errors:sized-generic-metadata, r=wesleywiser
Type params and assoc types have unit metadata if they are sized Extend the logic in `Pointee` projection to ensure that we can satisfy `<T as Pointee>::Metadata = ()` if `T: Sized`. cc: `@SimonSapin` and #93959
2 parents 0e42393 + 210e829 commit 774655d

File tree

5 files changed

+134
-15
lines changed

5 files changed

+134
-15
lines changed

compiler/rustc_middle/src/ty/sty.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -2252,12 +2252,13 @@ impl<'tcx> Ty<'tcx> {
22522252
}
22532253
}
22542254

2255-
/// Returns the type of metadata for (potentially fat) pointers to this type.
2255+
/// Returns the type of metadata for (potentially fat) pointers to this type,
2256+
/// and a boolean signifying if this is conditional on this type being `Sized`.
22562257
pub fn ptr_metadata_ty(
22572258
self,
22582259
tcx: TyCtxt<'tcx>,
22592260
normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
2260-
) -> Ty<'tcx> {
2261+
) -> (Ty<'tcx>, bool) {
22612262
let tail = tcx.struct_tail_with_normalize(self, normalize);
22622263
match tail.kind() {
22632264
// Sized types
@@ -2277,28 +2278,30 @@ impl<'tcx> Ty<'tcx> {
22772278
| ty::Closure(..)
22782279
| ty::Never
22792280
| ty::Error(_)
2281+
// Extern types have metadata = ().
22802282
| ty::Foreign(..)
22812283
// If returned by `struct_tail_without_normalization` this is a unit struct
22822284
// without any fields, or not a struct, and therefore is Sized.
22832285
| ty::Adt(..)
22842286
// If returned by `struct_tail_without_normalization` this is the empty tuple,
22852287
// a.k.a. unit type, which is Sized
2286-
| ty::Tuple(..) => tcx.types.unit,
2288+
| ty::Tuple(..) => (tcx.types.unit, false),
22872289

2288-
ty::Str | ty::Slice(_) => tcx.types.usize,
2290+
ty::Str | ty::Slice(_) => (tcx.types.usize, false),
22892291
ty::Dynamic(..) => {
22902292
let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
2291-
tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
2293+
(tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]), false)
22922294
},
22932295

2294-
ty::Projection(_)
2295-
| ty::Param(_)
2296-
| ty::Opaque(..)
2297-
| ty::Infer(ty::TyVar(_))
2296+
// type parameters only have unit metadata if they're sized, so return true
2297+
// to make sure we double check this during confirmation
2298+
ty::Param(_) | ty::Projection(_) | ty::Opaque(..) => (tcx.types.unit, true),
2299+
2300+
ty::Infer(ty::TyVar(_))
22982301
| ty::Bound(..)
22992302
| ty::Placeholder(..)
23002303
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
2301-
bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
2304+
bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail)
23022305
}
23032306
}
23042307
}

compiler/rustc_trait_selection/src/traits/project.rs

+30-5
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14691469
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
14701470

14711471
let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
1472+
// We throw away any obligations we get from this, since we normalize
1473+
// and confirm these obligations once again during confirmation
14721474
normalize_with_depth(
14731475
selcx,
14741476
obligation.param_env,
@@ -1485,7 +1487,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14851487
| ty::Int(_)
14861488
| ty::Uint(_)
14871489
| ty::Float(_)
1488-
| ty::Foreign(_)
14891490
| ty::Str
14901491
| ty::Array(..)
14911492
| ty::Slice(_)
@@ -1498,6 +1499,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
14981499
| ty::Generator(..)
14991500
| ty::GeneratorWitness(..)
15001501
| ty::Never
1502+
// Extern types have unit metadata, according to RFC 2850
1503+
| ty::Foreign(_)
15011504
// If returned by `struct_tail_without_normalization` this is a unit struct
15021505
// without any fields, or not a struct, and therefore is Sized.
15031506
| ty::Adt(..)
@@ -1506,9 +1509,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
15061509
// Integers and floats are always Sized, and so have unit type metadata.
15071510
| ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
15081511

1509-
ty::Projection(..)
1512+
// type parameters, opaques, and unnormalized projections have pointer
1513+
// metadata if they're known (e.g. by the param_env) to be sized
1514+
ty::Param(_) | ty::Projection(..) | ty::Opaque(..)
1515+
if tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env) =>
1516+
{
1517+
true
1518+
}
1519+
1520+
// FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
1521+
ty::Param(_)
1522+
| ty::Projection(..)
15101523
| ty::Opaque(..)
1511-
| ty::Param(..)
15121524
| ty::Bound(..)
15131525
| ty::Placeholder(..)
15141526
| ty::Infer(..)
@@ -1517,7 +1529,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
15171529
candidate_set.mark_ambiguous();
15181530
}
15191531
false
1520-
},
1532+
}
15211533
}
15221534
}
15231535
super::ImplSource::Param(..) => {
@@ -1727,7 +1739,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
17271739
let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
17281740

17291741
let mut obligations = vec![];
1730-
let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
1742+
let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| {
17311743
normalize_with_depth_to(
17321744
selcx,
17331745
obligation.param_env,
@@ -1737,6 +1749,19 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
17371749
&mut obligations,
17381750
)
17391751
});
1752+
if check_is_sized {
1753+
let sized_predicate = ty::Binder::dummy(ty::TraitRef::new(
1754+
tcx.require_lang_item(LangItem::Sized, None),
1755+
tcx.mk_substs_trait(self_ty, &[]),
1756+
))
1757+
.without_const()
1758+
.to_predicate(tcx);
1759+
obligations.push(Obligation::new(
1760+
obligation.cause.clone(),
1761+
obligation.param_env,
1762+
sized_predicate,
1763+
));
1764+
}
17401765

17411766
let substs = tcx.mk_substs([self_ty.into()].iter());
17421767
let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// edition:2018
2+
3+
#![feature(ptr_metadata)]
4+
#![feature(type_alias_impl_trait)]
5+
6+
type Opaque = impl std::fmt::Debug + ?Sized;
7+
8+
fn opaque() -> &'static Opaque {
9+
&[1] as &[i32]
10+
}
11+
12+
fn a<T: ?Sized>() {
13+
is_thin::<T>();
14+
//~^ ERROR type mismatch resolving `<T as Pointee>::Metadata == ()`
15+
16+
is_thin::<Opaque>();
17+
//~^ ERROR type mismatch resolving `<impl Debug + ?Sized as Pointee>::Metadata == ()`
18+
}
19+
20+
fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
error[E0271]: type mismatch resolving `<T as Pointee>::Metadata == ()`
2+
--> $DIR/pointee-tail-is-generic-errors.rs:13:5
3+
|
4+
LL | is_thin::<T>();
5+
| ^^^^^^^^^^^^ expected `()`, found associated type
6+
|
7+
= note: expected unit type `()`
8+
found associated type `<T as Pointee>::Metadata`
9+
= help: consider constraining the associated type `<T as Pointee>::Metadata` to `()`
10+
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
11+
note: required by a bound in `is_thin`
12+
--> $DIR/pointee-tail-is-generic-errors.rs:20:33
13+
|
14+
LL | fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
15+
| ^^^^^^^^^^^^^ required by this bound in `is_thin`
16+
17+
error[E0271]: type mismatch resolving `<impl Debug + ?Sized as Pointee>::Metadata == ()`
18+
--> $DIR/pointee-tail-is-generic-errors.rs:16:5
19+
|
20+
LL | type Opaque = impl std::fmt::Debug + ?Sized;
21+
| ----------------------------- the found opaque type
22+
...
23+
LL | is_thin::<Opaque>();
24+
| ^^^^^^^^^^^^^^^^^ expected `()`, found associated type
25+
|
26+
= note: expected unit type `()`
27+
found associated type `<impl Debug + ?Sized as Pointee>::Metadata`
28+
note: required by a bound in `is_thin`
29+
--> $DIR/pointee-tail-is-generic-errors.rs:20:33
30+
|
31+
LL | fn is_thin<T: std::ptr::Pointee<Metadata = ()> + ?Sized>() {}
32+
| ^^^^^^^^^^^^^ required by this bound in `is_thin`
33+
help: consider constraining the associated type `<impl Debug + ?Sized as Pointee>::Metadata` to `()`
34+
|
35+
LL | type Opaque = impl std::fmt::Debug<Metadata = ()> + ?Sized;
36+
| +++++++++++++++
37+
38+
error: aborting due to 2 previous errors
39+
40+
For more information about this error, try `rustc --explain E0271`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// check-pass
2+
// edition:2018
3+
4+
#![feature(ptr_metadata)]
5+
#![feature(type_alias_impl_trait)]
6+
7+
type Opaque = impl std::future::Future;
8+
9+
fn opaque() -> Opaque {
10+
async {}
11+
}
12+
13+
fn a<T>() {
14+
// type parameter T is known to be sized
15+
is_thin::<T>();
16+
// tail of ADT (which is a type param) is known to be sized
17+
is_thin::<std::cell::Cell<T>>();
18+
// opaque type is known to be sized
19+
is_thin::<Opaque>();
20+
}
21+
22+
fn a2<T: Iterator>() {
23+
// associated type is known to be sized
24+
is_thin::<T::Item>();
25+
}
26+
27+
fn is_thin<T: std::ptr::Pointee<Metadata = ()>>() {}
28+
29+
fn main() {}

0 commit comments

Comments
 (0)