From ef0ba1d2cead709f11fe7912e0d2bd8c3f5e1b28 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Feb 2022 13:39:07 -0800 Subject: [PATCH] type parameters have unit metadata if they are sized --- compiler/rustc_middle/src/ty/sty.rs | 22 ++++++++------- .../src/traits/project.rs | 27 +++++++++++++++---- src/test/ui/traits/pointee-tail-is-generic.rs | 12 +++++++++ 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/traits/pointee-tail-is-generic.rs diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index a1e906140e0..061520189e9 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2244,12 +2244,13 @@ pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { } } - /// Returns the type of metadata for (potentially fat) pointers to this type. + /// Returns the type of metadata for (potentially fat) pointers to this type, + /// and a boolean signifying if this is conditional on this type being `Sized`. pub fn ptr_metadata_ty( self, tcx: TyCtxt<'tcx>, normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>, - ) -> Ty<'tcx> { + ) -> (Ty<'tcx>, bool) { let tail = tcx.struct_tail_with_normalize(self, normalize); match tail.kind() { // Sized types @@ -2269,28 +2270,31 @@ pub fn ptr_metadata_ty( | ty::Closure(..) | ty::Never | ty::Error(_) + // Extern types have metadata = (). | ty::Foreign(..) // If returned by `struct_tail_without_normalization` this is a unit struct // without any fields, or not a struct, and therefore is Sized. | ty::Adt(..) // If returned by `struct_tail_without_normalization` this is the empty tuple, // a.k.a. unit type, which is Sized - | ty::Tuple(..) => tcx.types.unit, + | ty::Tuple(..) => (tcx.types.unit, false), - ty::Str | ty::Slice(_) => tcx.types.usize, + ty::Str | ty::Slice(_) => (tcx.types.usize, false), ty::Dynamic(..) => { let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap(); - tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]) + (tcx.type_of(dyn_metadata).subst(tcx, &[self.into()]), false) }, - ty::Projection(_) - | ty::Param(_) - | ty::Opaque(..) + // type parameters only have unit metadata if they're sized, so return true + // to make sure we double check this during confirmation + ty::Param(_) | ty::Projection(_) => (tcx.types.unit, true), + + ty::Opaque(..) | ty::Infer(ty::TyVar(_)) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail) + bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", self) } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c32c73c6384..823b03eab95 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1399,6 +1399,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| { + // We throw away any obligations we get from this, since we normalize + // and confirm these obligations once again during confirmation normalize_with_depth( selcx, obligation.param_env, @@ -1415,7 +1417,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Int(_) | ty::Uint(_) | ty::Float(_) - | ty::Foreign(_) | ty::Str | ty::Array(..) | ty::Slice(_) @@ -1428,6 +1429,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Generator(..) | ty::GeneratorWitness(..) | ty::Never + // Extern types have unit metadata, according to RFC 2850 + | ty::Foreign(_) // If returned by `struct_tail_without_normalization` this is a unit struct // without any fields, or not a struct, and therefore is Sized. | ty::Adt(..) @@ -1436,9 +1439,10 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // Integers and floats are always Sized, and so have unit type metadata. | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true, - ty::Projection(..) - | ty::Opaque(..) - | ty::Param(..) + // type parameters and unnormalized projections have pointer metadata if they're still known to be sized + ty::Param(_) | ty::Projection(..) => tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env), + + ty::Opaque(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) @@ -1657,7 +1661,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>( let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); let mut obligations = vec![]; - let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| { + let (metadata_ty, check_is_sized) = self_ty.ptr_metadata_ty(tcx, |ty| { normalize_with_depth_to( selcx, obligation.param_env, @@ -1667,6 +1671,19 @@ fn confirm_pointee_candidate<'cx, 'tcx>( &mut obligations, ) }); + if check_is_sized { + let sized_predicate = ty::Binder::dummy(ty::TraitRef::new( + tcx.require_lang_item(LangItem::Sized, None), + tcx.mk_substs_trait(self_ty, &[]), + )) + .without_const() + .to_predicate(tcx); + obligations.push(Obligation::new( + obligation.cause.clone(), + obligation.param_env, + sized_predicate, + )); + } let substs = tcx.mk_substs([self_ty.into()].iter()); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); diff --git a/src/test/ui/traits/pointee-tail-is-generic.rs b/src/test/ui/traits/pointee-tail-is-generic.rs new file mode 100644 index 00000000000..097881256ba --- /dev/null +++ b/src/test/ui/traits/pointee-tail-is-generic.rs @@ -0,0 +1,12 @@ +// check-pass + +#![feature(ptr_metadata)] + +fn a() { + b::(); + b::>(); +} + +fn b>() {} + +fn main() {}