From ef0ba1d2cead709f11fe7912e0d2bd8c3f5e1b28 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Feb 2022 13:39:07 -0800 Subject: [PATCH 1/3] 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() {} From 1d834cb657d4911535a01af38e974d11d081e9f4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Feb 2022 19:57:23 -0800 Subject: [PATCH 2/3] opaque types may also be sized --- compiler/rustc_middle/src/ty/sty.rs | 9 +++---- .../src/traits/project.rs | 16 +++++++++--- src/test/ui/traits/pointee-tail-is-generic.rs | 25 ++++++++++++++++--- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 061520189e9..f64d1e06f6c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2282,19 +2282,18 @@ pub fn ptr_metadata_ty( 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, &[self.into()]), false) + (tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()]), false) }, // 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::Param(_) | ty::Projection(_) | ty::Opaque(..) => (tcx.types.unit, true), - ty::Opaque(..) - | ty::Infer(ty::TyVar(_)) + ty::Infer(ty::TyVar(_)) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", self) + bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail) } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 823b03eab95..26f7d0782c2 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1439,10 +1439,18 @@ 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, - // 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), + // type parameters, opaques, and unnormalized projections have pointer + // metadata if they're known (e.g. by the param_env) to be sized + ty::Param(_) | ty::Projection(..) | ty::Opaque(..) + if tail.is_sized(selcx.tcx().at(obligation.cause.span), obligation.param_env) => + { + true + } - ty::Opaque(..) + // FIXME(compiler-errors): are Bound and Placeholder types ever known sized? + ty::Param(_) + | ty::Projection(..) + | ty::Opaque(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) @@ -1451,7 +1459,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( candidate_set.mark_ambiguous(); } false - }, + } } } super::ImplSource::Param(..) => { diff --git a/src/test/ui/traits/pointee-tail-is-generic.rs b/src/test/ui/traits/pointee-tail-is-generic.rs index 097881256ba..e0da0fc3861 100644 --- a/src/test/ui/traits/pointee-tail-is-generic.rs +++ b/src/test/ui/traits/pointee-tail-is-generic.rs @@ -1,12 +1,29 @@ // check-pass +// edition:2018 #![feature(ptr_metadata)] +#![feature(type_alias_impl_trait)] -fn a() { - b::(); - b::>(); +type Opaque = impl std::future::Future; + +fn opaque() -> Opaque { + async {} } -fn b>() {} +fn a() { + // type parameter T is known to be sized + is_thin::(); + // tail of ADT (which is a type param) is known to be sized + is_thin::>(); + // opaque type is known to be sized + is_thin::(); +} + +fn a2() { + // associated type is known to be sized + is_thin::(); +} + +fn is_thin>() {} fn main() {} From 210e829010022d2a8e49a2519aec8ac6bee20ed1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 3 Mar 2022 22:04:23 -0800 Subject: [PATCH 3/3] add tests for metadata for unsized generics and opaques --- .../traits/pointee-tail-is-generic-errors.rs | 22 ++++++++++ .../pointee-tail-is-generic-errors.stderr | 40 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/test/ui/traits/pointee-tail-is-generic-errors.rs create mode 100644 src/test/ui/traits/pointee-tail-is-generic-errors.stderr diff --git a/src/test/ui/traits/pointee-tail-is-generic-errors.rs b/src/test/ui/traits/pointee-tail-is-generic-errors.rs new file mode 100644 index 00000000000..d081721aca2 --- /dev/null +++ b/src/test/ui/traits/pointee-tail-is-generic-errors.rs @@ -0,0 +1,22 @@ +// edition:2018 + +#![feature(ptr_metadata)] +#![feature(type_alias_impl_trait)] + +type Opaque = impl std::fmt::Debug + ?Sized; + +fn opaque() -> &'static Opaque { + &[1] as &[i32] +} + +fn a() { + is_thin::(); + //~^ ERROR type mismatch resolving `::Metadata == ()` + + is_thin::(); + //~^ ERROR type mismatch resolving `::Metadata == ()` +} + +fn is_thin + ?Sized>() {} + +fn main() {} diff --git a/src/test/ui/traits/pointee-tail-is-generic-errors.stderr b/src/test/ui/traits/pointee-tail-is-generic-errors.stderr new file mode 100644 index 00000000000..fa5fe67e53c --- /dev/null +++ b/src/test/ui/traits/pointee-tail-is-generic-errors.stderr @@ -0,0 +1,40 @@ +error[E0271]: type mismatch resolving `::Metadata == ()` + --> $DIR/pointee-tail-is-generic-errors.rs:13:5 + | +LL | is_thin::(); + | ^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Metadata` + = help: consider constraining the associated type `::Metadata` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: required by a bound in `is_thin` + --> $DIR/pointee-tail-is-generic-errors.rs:20:33 + | +LL | fn is_thin + ?Sized>() {} + | ^^^^^^^^^^^^^ required by this bound in `is_thin` + +error[E0271]: type mismatch resolving `::Metadata == ()` + --> $DIR/pointee-tail-is-generic-errors.rs:16:5 + | +LL | type Opaque = impl std::fmt::Debug + ?Sized; + | ----------------------------- the found opaque type +... +LL | is_thin::(); + | ^^^^^^^^^^^^^^^^^ expected `()`, found associated type + | + = note: expected unit type `()` + found associated type `::Metadata` +note: required by a bound in `is_thin` + --> $DIR/pointee-tail-is-generic-errors.rs:20:33 + | +LL | fn is_thin + ?Sized>() {} + | ^^^^^^^^^^^^^ required by this bound in `is_thin` +help: consider constraining the associated type `::Metadata` to `()` + | +LL | type Opaque = impl std::fmt::Debug + ?Sized; + | +++++++++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`.