diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3f4911c4ecfcf..722d7b71c7ac6 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2072,6 +2072,7 @@ impl TyKind { #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum TraitObjectSyntax { Dyn, + DynStar, None, } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index ca5b7a6415515..8a2b265c400da 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -573,6 +573,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, "the `!` type is experimental"); } + ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::DynStar, ..) => { + gate_feature_post!(&self, dyn_star, ty.span, "dyn* trait objects are unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fc0e95f30c98f..d2a54df10b571 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ - self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, - OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, + self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic, + OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, + UserTypeAnnotationIndex, }; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{Span, DUMMY_SP}; @@ -2009,6 +2010,36 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } + CastKind::DynStar => { + // get the constraints from the target type (`dyn* Clone`) + // + // apply them to prove that the source type `Foo` implements `Clone` etc + let (existential_predicates, region) = match ty.kind() { + Dynamic(predicates, region, ty::DynStar) => (predicates, region), + _ => panic!("Invalid dyn* cast_ty"), + }; + + let self_ty = op.ty(body, tcx); + + self.prove_predicates( + existential_predicates + .iter() + .map(|predicate| predicate.with_self_ty(tcx, self_ty)), + location.to_locations(), + ConstraintCategory::Cast, + ); + + let outlives_predicate = + tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(self_ty, *region), + ))); + self.prove_predicate( + outlives_predicate, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + CastKind::Pointer(PointerCast::MutToConstPointer) => { let ty::RawPtr(ty::TypeAndMut { ty: ty_from, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 2aa11ac2eeaa6..399474d79e3b6 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -701,6 +701,10 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + } Rvalue::Discriminant(place) => { let place = codegen_place(fx, place); let value = place.to_cvalue(fx); diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 2ee98546c992a..cfaadca949107 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -815,7 +815,8 @@ pub(crate) fn assert_assignable<'tcx>( ); // fn(&T) -> for<'l> fn(&'l T) is allowed } - (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { + (&ty::Dynamic(from_traits, _, _from_kind), &ty::Dynamic(to_traits, _, _to_kind)) => { + // FIXME(dyn-star): Do the right thing with DynKinds for (from, to) in from_traits.iter().zip(to_traits) { let from = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index f8e982b775189..cae46ebd2e9a7 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> VirtualIndex { fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<'tcx> { for arg in ty.peel_refs().walk() { if let GenericArgKind::Type(ty) = arg.unpack() { - if let ty::Dynamic(data, _) = ty.kind() { + if let ty::Dynamic(data, _, _) = ty.kind() { return data.principal().expect("expected principal trait object"); } } @@ -86,6 +86,7 @@ fn expect_dyn_trait_in_self<'tcx>(ty: Ty<'tcx>) -> ty::PolyExistentialTraitRef<' /// The `trait_ref` encodes the erased self type. Hence if we are /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T: Trait`. +#[instrument(level = "debug", skip(cx))] pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( cx: &Cx, ty: Ty<'tcx>, @@ -93,8 +94,6 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( ) -> Cx::Value { let tcx = cx.tcx(); - debug!("get_vtable(ty={:?}, trait_ref={:?})", ty, trait_ref); - // Check the cache. if let Some(&val) = cx.vtables().borrow().get(&(ty, trait_ref)) { return val; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3154f12a77964..a6b226ef72096 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -367,6 +367,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.ret(llval); } + #[tracing::instrument(level = "trace", skip(self, helper, bx))] fn codegen_drop_terminator( &mut self, helper: TerminatorCodegenHelper<'tcx>, @@ -397,14 +398,75 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (drop_fn, fn_abi) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? - ty::Dynamic(..) => { + ty::Dynamic(_, _, ty::Dyn) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn Trait) + // which is: exists ( *mut T, Vtable ) + // args[0] args[1] + // + // args = ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // let virtual_drop = Instance { def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), substs: drop_fn.substs, }; + debug!("ty = {:?}", ty); + debug!("drop_fn = {:?}", drop_fn); + debug!("args = {:?}", args); let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); let vtable = args[1]; + // Truncate vtable off of args list + args = &args[..1]; + ( + meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) + .get_fn(&mut bx, vtable, ty, &fn_abi), + fn_abi, + ) + } + ty::Dynamic(_, _, ty::DynStar) => { + // IN THIS ARM, WE HAVE: + // ty = *mut (dyn* Trait) + // which is: *mut exists (T, Vtable) + // + // args = [ * ] + // | + // v + // ( Data, Vtable ) + // | + // v + // /-------\ + // | ... | + // \-------/ + // + // + // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING + // + // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer) + // vtable = (*args[0]).1 // loads the vtable out + // (data, vtable) // an equivalent Rust `*mut dyn Trait` + // + // SO THEN WE CAN USE THE ABOVE CODE. + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), + substs: drop_fn.substs, + }; + debug!("ty = {:?}", ty); + debug!("drop_fn = {:?}", drop_fn); + debug!("args = {:?}", args); + let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); + let data = args[0]; + let data_ty = bx.cx().backend_type(place.layout); + let vtable_ptr = + bx.gep(data_ty, data, &[bx.cx().const_i32(0), bx.cx().const_i32(1)]); + let vtable = bx.load(bx.type_i8p(), vtable_ptr, abi::Align::ONE); + // Truncate vtable off of args list args = &args[..1]; + debug!("args' = {:?}", args); ( meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) .get_fn(&mut bx, vtable, ty, &fn_abi), @@ -845,7 +907,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { llargs.push(data_ptr); continue; } - _ => span_bug!(span, "can't codegen a virtual call on {:?}", op), + Immediate(_) => { + let ty::Ref(_, ty, _) = op.layout.ty.kind() else { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + }; + if !ty.is_dyn_star() { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + } + // FIXME(dyn-star): Make sure this is done on a &dyn* receiver + let place = op.deref(bx.cx()); + let data_ptr = place.project_field(&mut bx, 0); + let meta_ptr = place.project_field(&mut bx, 1); + let meta = bx.load_operand(meta_ptr); + llfn = Some(meth::VirtualIndex::from_index(idx).get_fn( + &mut bx, + meta.immediate(), + op.layout.ty, + &fn_abi, + )); + llargs.push(data_ptr.llval); + continue; + } + _ => { + span_bug!(span, "can't codegen a virtual call on {:#?}", op); + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 574746e340b7b..56852b0fcc821 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -4,6 +4,7 @@ use super::{FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; +use crate::meth::get_vtable; use crate::traits::*; use crate::MemFlags; @@ -271,6 +272,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("unexpected non-pair operand"); } } + mir::CastKind::DynStar => { + let data = match operand.val { + OperandValue::Ref(_, _, _) => todo!(), + OperandValue::Immediate(v) => v, + OperandValue::Pair(_, _) => todo!(), + }; + let trait_ref = + if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() { + data.principal() + } else { + bug!("Only valid to do a DynStar cast into a DynStar type") + }; + let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref); + OperandValue::Pair(data, vtable) + } mir::CastKind::Pointer( PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, ) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 07dbd80e077f9..cbe98548025bc 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -108,6 +108,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), } } + + DynStar => { + if let ty::Dynamic(data, _, ty::DynStar) = cast_ty.kind() { + // Initial cast from sized to dyn trait + let vtable = self.get_vtable_ptr(src.layout.ty, data.principal())?; + let vtable = Scalar::from_maybe_pointer(vtable, self); + let data = self.read_immediate(src)?.to_scalar(); + let _assert_pointer_sized = data.to_pointer(self)?; + let val = Immediate::ScalarPair(data, vtable); + self.write_immediate(val, dest)?; + } else { + bug!() + } + } } Ok(()) } @@ -312,7 +326,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let new_vptr = self.get_vtable_ptr(ty, data_b.principal())?; self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) } - (_, &ty::Dynamic(ref data, _)) => { + (_, &ty::Dynamic(ref data, _, ty::Dyn)) => { // Initial cast from sized to dyn trait let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?; let ptr = self.read_scalar(src)?; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 7dba5059307ea..8637d6a7767e4 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -95,7 +95,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Dynamic(_, _) + | ty::Dynamic(_, _, _) | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs index f9847742f0883..7e4c5fcb031b0 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs @@ -48,7 +48,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::FnPtr(_) | ty::Never | ty::Tuple(_) - | ty::Dynamic(_, _) => self.pretty_print_type(ty), + | ty::Dynamic(_, _, _) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 3fa40dc305952..7e15858c8c188 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -546,6 +546,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // Since no pointer can ever get exposed (rejected above), this is easy to support. } + Rvalue::Cast(CastKind::DynStar, _, _) => { + unimplemented!() + } + Rvalue::Cast(CastKind::Misc, _, _) => {} Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 8576e0f0f7c16..4aa98cb13d82b 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -569,6 +569,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + CastKind::DynStar => { + // FIXME(dyn-star): make sure nothing needs to be done here. + } // Nothing to check here CastKind::PointerFromExposedAddress | CastKind::PointerExposeAddress diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 5377ebde1683f..d5ec5feffa732 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -380,6 +380,8 @@ declare_features! ( (active, doc_cfg_hide, "1.57.0", Some(43781), None), /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), + /// Allows `dyn* Trait` objects. + (incomplete, dyn_star, "CURRENT_RUSTC_VERSION", Some(91611), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index b115ac8b3df95..ae56bea6f862d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -544,7 +544,7 @@ pub struct TraitObjectVisitor(pub FxHashSet); impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { - ty::Dynamic(preds, re) if re.is_static() => { + ty::Dynamic(preds, re, _) if re.is_static() => { if let Some(def_id) = preds.principal_def_id() { self.0.insert(def_id); } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 9a7d722c05a90..3d426ecbfcb05 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -222,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } has_emitted } - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { let mut has_emitted = false; for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index dd768c5358d5a..47e62e82ac4aa 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1834,6 +1834,7 @@ impl<'tcx> Rvalue<'tcx> { // While the model is undecided, we should be conservative. See // Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, + Rvalue::Cast(CastKind::DynStar, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1f7643a76afe5..d2bb897b5b676 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1139,6 +1139,8 @@ pub enum CastKind { /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are /// translated into `&raw mut/const *r`, i.e., they are not actually casts. Pointer(PointerCast), + /// Cast into a dyn* object. + DynStar, /// Remaining unclassified casts. Misc, } diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index c4b743dd46701..981e2d3b6d2d3 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -33,6 +33,8 @@ pub enum CastTy<'tcx> { FnPtr, /// Raw pointers. Ptr(ty::TypeAndMut<'tcx>), + /// Casting into a `dyn*` value. + DynStar, } /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) @@ -50,6 +52,7 @@ pub enum CastKind { ArrayPtrCast, FnPtrPtrCast, FnPtrAddrCast, + DynStarCast, } impl<'tcx> CastTy<'tcx> { @@ -67,6 +70,7 @@ impl<'tcx> CastTy<'tcx> { ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), ty::FnPtr(..) => Some(CastTy::FnPtr), + ty::Dynamic(_, _, ty::DynStar) => Some(CastTy::DynStar), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index afb2d5b2ba5e5..9359703472150 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -63,7 +63,7 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::sty::TyKind::*; -use rustc_type_ir::{InternAs, InternIteratorElement, Interner, TypeFlags}; +use rustc_type_ir::{DynKind, InternAs, InternIteratorElement, Interner, TypeFlags}; use std::any::Any; use std::borrow::Borrow; @@ -2545,8 +2545,9 @@ impl<'tcx> TyCtxt<'tcx> { self, obj: &'tcx List>>, reg: ty::Region<'tcx>, + repr: DynKind, ) -> Ty<'tcx> { - self.mk_ty(Dynamic(obj, reg)) + self.mk_ty(Dynamic(obj, reg, repr)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 648f5f7161fa6..855917fb82869 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -467,7 +467,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } - Dynamic(dty, _) => { + Dynamic(dty, _, _) => { for pred in *dty { match pred.skip_binder() { ExistentialPredicate::Trait(_) | ExistentialPredicate::Projection(_) => { diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index c22c899c5cce1..98b8a7386fe6a 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -171,7 +171,7 @@ impl FlagComputation { self.add_substs(substs); } - &ty::Dynamic(obj, r) => { + &ty::Dynamic(obj, r, _) => { for predicate in obj.iter() { self.bound_computation(predicate, |computation, predicate| match predicate { ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index abb7ddd88b14d..042eeec3f4622 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -625,6 +625,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) } + ty::Dynamic(_, _, ty::DynStar) => { + let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false)); + data.valid_range_mut().start = 0; + let mut vtable = scalar_unit(Pointer); + vtable.valid_range_mut().start = 1; + tcx.intern_layout(self.scalar_pair(data, vtable)) + } + // Arrays and slices. ty::Array(element, mut count) => { if count.has_projections() { @@ -679,7 +687,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Odd unit types. ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, - ty::Dynamic(..) | ty::Foreign(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { let mut unit = self.univariant_uninterned( ty, &[], @@ -2435,7 +2443,9 @@ where | ty::FnDef(..) | ty::GeneratorWitness(..) | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this), + | ty::Dynamic(_, _, ty::Dyn) => { + bug!("TyAndLayout::field({:?}): not applicable", this) + } // Potentially-fat pointers. ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { @@ -2464,7 +2474,7 @@ where match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), - ty::Dynamic(_, _) => { + ty::Dynamic(_, _, ty::Dyn) => { TyMaybeWithLayout::Ty(tcx.mk_imm_ref( tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3), @@ -2533,6 +2543,22 @@ where } } + ty::Dynamic(_, _, ty::DynStar) => { + if i == 0 { + TyMaybeWithLayout::Ty(tcx.types.usize) + } else if i == 1 { + // FIXME(dyn-star) same FIXME as above applies here too + TyMaybeWithLayout::Ty( + tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_array(tcx.types.usize, 3), + ), + ) + } else { + bug!("no field {i} on dyn*") + } + } + ty::Projection(_) | ty::Bound(..) | ty::Placeholder(..) @@ -2728,6 +2754,7 @@ impl<'tcx> ty::Instance<'tcx> { // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any // adjustments `fn_abi_of_instance` might be performing. + #[tracing::instrument(level = "debug", skip(tcx, param_env))] fn fn_sig_for_fn_abi( &self, tcx: TyCtxt<'tcx>, @@ -2874,6 +2901,7 @@ impl<'tcx> ty::Instance<'tcx> { /// with `-Cpanic=abort` will look like they can't unwind when in fact they /// might (from a foreign exception or similar). #[inline] +#[tracing::instrument(level = "debug", skip(tcx))] pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option, abi: SpecAbi) -> bool { if let Some(did) = fn_def_id { // Special attribute for functions which can't unwind. @@ -3090,6 +3118,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// NB: that includes virtual calls, which are represented by "direct calls" /// to an `InstanceDef::Virtual` instance (of `::fn`). #[inline] + #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_of_instance( &self, instance: ty::Instance<'tcx>, @@ -3236,6 +3265,10 @@ pub fn adjust_for_rust_scalar<'tcx>( impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) // arguments of this method, into a separate `struct`. + #[tracing::instrument( + level = "debug", + skip(self, caller_location, fn_def_id, force_thin_self_ptr) + )] fn fn_abi_new_uncached( &self, sig: ty::PolyFnSig<'tcx>, @@ -3245,8 +3278,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) replace this with something typed, like an `enum`. force_thin_self_ptr: bool, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { - debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args); - let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig); let conv = conv_from_spec_abi(self.tcx(), sig.abi); @@ -3289,6 +3320,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); let arg_of = |ty: Ty<'tcx>, arg_idx: Option| -> Result<_, FnAbiError<'tcx>> { + let span = tracing::debug_span!("arg_of"); + let _entered = span.enter(); let is_return = arg_idx.is_none(); let layout = self.layout_of(ty)?; @@ -3345,6 +3378,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { Ok(self.tcx.arena.alloc(fn_abi)) } + #[tracing::instrument(level = "trace", skip(self))] fn fn_abi_adjust_for_abi( &self, fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>, @@ -3419,6 +3453,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } } +#[tracing::instrument(level = "debug", skip(cx))] fn make_thin_self_ptr<'tcx>( cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>), layout: TyAndLayout<'tcx>, @@ -3430,7 +3465,7 @@ fn make_thin_self_ptr<'tcx>( tcx.mk_mut_ptr(layout.ty) } else { match layout.abi { - Abi::ScalarPair(..) => (), + Abi::ScalarPair(..) | Abi::Scalar(..) => (), _ => bug!("receiver type has unsupported layout: {:?}", layout), } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index df72260597f9f..e80cc2ed5fab7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -58,6 +58,7 @@ use std::ops::ControlFlow; use std::{fmt, str}; pub use crate::ty::diagnostics::*; +pub use rustc_type_ir::DynKind::*; pub use rustc_type_ir::InferTy::*; pub use rustc_type_ir::RegionKind::*; pub use rustc_type_ir::TyKind::*; @@ -1113,6 +1114,12 @@ pub trait ToPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } +impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> { + fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { + self + } +} + impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index cac8560ce1c32..9db5a2894843c 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -36,6 +36,7 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_regions(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<'tcx>, @@ -100,6 +101,7 @@ impl<'tcx> TyCtxt<'tcx> { /// N.B., currently, higher-ranked type bounds inhibit /// normalization. Therefore, each time we erase them in /// codegen, we need to normalize the contents. + #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_late_bound_regions( self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e9eecfe78d32c..f7d5d3116afb7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -619,12 +619,16 @@ pub trait PrettyPrinter<'tcx>: ty::Adt(def, substs) => { p!(print_def_path(def.did(), substs)); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, repr) => { let print_r = self.should_print_region(r); if print_r { p!("("); } - p!("dyn ", print(data)); + match repr { + ty::Dyn => p!("dyn "), + ty::DynStar => p!("dyn* "), + } + p!(print(data)); if print_r { p!(" + ", print(r), ")"); } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 81476195d2995..5b3750b8b4da0 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -441,7 +441,9 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(tcx.mk_foreign(a_id)), - (&ty::Dynamic(a_obj, a_region), &ty::Dynamic(b_obj, b_region)) => { + (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| { relation.relate_with_variance( ty::Contravariant, @@ -450,7 +452,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( b_region, ) })?; - Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) + Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr)) } (&ty::Generator(a_id, a_substs, movability), &ty::Generator(b_id, b_substs, _)) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index e6bd2eed565a1..323aa6599b8d5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -1014,9 +1014,11 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> { ty::Array(typ, sz) => ty::Array(typ.try_fold_with(folder)?, sz.try_fold_with(folder)?), ty::Slice(typ) => ty::Slice(typ.try_fold_with(folder)?), ty::Adt(tid, substs) => ty::Adt(tid, substs.try_fold_with(folder)?), - ty::Dynamic(trait_ty, region) => { - ty::Dynamic(trait_ty.try_fold_with(folder)?, region.try_fold_with(folder)?) - } + ty::Dynamic(trait_ty, region, representation) => ty::Dynamic( + trait_ty.try_fold_with(folder)?, + region.try_fold_with(folder)?, + representation, + ), ty::Tuple(ts) => ty::Tuple(ts.try_fold_with(folder)?), ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.try_fold_with(folder)?), ty::FnPtr(f) => ty::FnPtr(f.try_fold_with(folder)?), @@ -1060,7 +1062,7 @@ impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> { } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, substs) => substs.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg) => { + ty::Dynamic(ref trait_ty, ref reg, _) => { trait_ty.visit_with(visitor)?; reg.visit_with(visitor) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 702c2d27187ee..18169045c901c 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -692,6 +692,9 @@ impl<'tcx> ExistentialPredicate<'tcx> { } impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> { + /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), + /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` + /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq`, in our example). pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match self.skip_binder() { @@ -1849,7 +1852,12 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_trait(self) -> bool { - matches!(self.kind(), Dynamic(..)) + matches!(self.kind(), Dynamic(_, _, ty::Dyn)) + } + + #[inline] + pub fn is_dyn_star(self) -> bool { + matches!(self.kind(), Dynamic(_, _, ty::DynStar)) } #[inline] diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 831724bc4b09b..a3e11bbf056b3 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -152,7 +152,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Projection(data) => { stack.extend(data.substs.iter().rev()); } - ty::Dynamic(obj, lt) => { + ty::Dynamic(obj, lt, _) => { stack.push(lt.into()); stack.extend(obj.iter().rev().flat_map(|predicate| { let (substs, opt_ty) = match predicate.skip_binder() { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c1282b8ddaff4..98bdaf0bc62e2 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -216,6 +216,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let from_ty = CastTy::from_ty(ty); let cast_ty = CastTy::from_ty(expr.ty); + debug!("ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}", expr.ty,); let cast_kind = match (from_ty, cast_ty) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { CastKind::PointerExposeAddress @@ -223,6 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => { CastKind::PointerFromExposedAddress } + (_, Some(CastTy::DynStar)) => CastKind::DynStar, (_, _) => CastKind::Misc, }; block.and(Rvalue::Cast(cast_kind, source, expr.ty)) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index be74a9d11e3c5..2a843ab0b8b4b 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -689,7 +689,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::CastKind::Pointer(PointerCast::Unsize), ref operand, target_ty, - ) => { + ) + | mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => { let target_ty = self.monomorphize(target_ty); let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.monomorphize(source_ty); @@ -698,7 +699,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. - if target_ty.is_trait() && !source_ty.is_trait() { + if (target_ty.is_trait() && !source_ty.is_trait()) + || (target_ty.is_dyn_star() && !source_ty.is_dyn_star()) + { create_mono_items_for_vtable_methods( self.tcx, target_ty, @@ -1112,6 +1115,9 @@ fn find_vtable_types_for_unsizing<'tcx>( ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty()) } + // T as dyn* Trait + (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty), + (&ty::Adt(source_adt_def, source_substs), &ty::Adt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 4a2cf74905bf5..b47f0c0978381 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -567,7 +567,8 @@ impl<'a> Parser<'a> { self.check_keyword(kw::Dyn) && (!self.token.uninterpolated_span().rust_2015() || self.look_ahead(1, |t| { - t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t) + (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star)) + && !can_continue_type_after_non_fn_ident(t) })) } @@ -576,10 +577,18 @@ impl<'a> Parser<'a> { /// Note that this does *not* parse bare trait objects. fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { self.bump(); // `dyn` + + // parse dyn* types + let syntax = if self.eat(&TokenKind::BinOp(token::Star)) { + TraitObjectSyntax::DynStar + } else { + TraitObjectSyntax::Dyn + }; + // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds(None)?; *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus); - Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::Dyn)) + Ok(TyKind::TraitObject(bounds, syntax)) } /// Parses a type starting with a path. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 871bc5c1cdb06..aeb535352f656 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -649,6 +649,7 @@ symbols! { dropck_parametricity, dylib, dyn_metadata, + dyn_star, dyn_trait, e, edition_macro_pats, diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index bd8126f617773..aa65a72ab646a 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -627,10 +627,13 @@ fn encode_ty<'tcx>( } // Trait types - ty::Dynamic(predicates, region) => { + ty::Dynamic(predicates, region, kind) => { // u3dynIE, where is , as // vendor extended type. - let mut s = String::from("u3dynI"); + let mut s = String::from(match kind { + ty::Dyn => "u3dynI", + ty::DynStar => "u7dynstarI", + }); s.push_str(&encode_predicates(tcx, predicates, dict, options)); s.push_str(&encode_region(tcx, *region, dict, options)); s.push('E'); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index cfb8d47e54534..79d0ef69ba733 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -479,8 +479,12 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { })?; } - ty::Dynamic(predicates, r) => { - self.push("D"); + ty::Dynamic(predicates, r, kind) => { + self.push(match kind { + ty::Dyn => "D", + // FIXME(dyn-star): need to update v0 mangling docs + ty::DynStar => "D*", + }); self = self.print_dyn_existential(predicates)?; self = r.print(self)?; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 6b03555bc6985..e11a42201443d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -256,7 +256,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } } - if let ty::Dynamic(traits, _) = self_ty.kind() { + if let ty::Dynamic(traits, _, _) = self_ty.kind() { for t in traits.iter() { if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index ecbeb9d79b118..bd73ec4716060 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1067,7 +1067,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, object_ty: Ty<'tcx>, ) { - let ty::Dynamic(predicates, _) = object_ty.kind() else { return; }; + let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); for predicate in predicates.iter() { @@ -1365,7 +1365,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let trait_pred = self.resolve_vars_if_possible(trait_pred); let ty = trait_pred.skip_binder().self_ty(); let is_object_safe = match ty.kind() { - ty::Dynamic(predicates, _) => { + ty::Dynamic(predicates, _, ty::Dyn) => { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates .principal_def_id() @@ -1425,7 +1425,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut spans_and_needs_box = vec![]; match liberated_sig.output().kind() { - ty::Dynamic(predicates, _) => { + ty::Dynamic(predicates, _, _) => { let cause = ObligationCause::misc(ret_ty.span, fn_hir_id); let param_env = ty::ParamEnv::empty(); diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5542f187f93f7..f2779ce2db140 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -600,7 +600,7 @@ fn object_ty_for_trait<'tcx>( let existential_predicates = tcx .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - let object_ty = tcx.mk_dynamic(existential_predicates, lifetime); + let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn); debug!("object_ty_for_trait: object_ty=`{}`", object_ty); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 83bde1c50e23d..a80527f63a004 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -1039,7 +1039,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Ref(_, _, _) | ty::FnDef(_, _) | ty::FnPtr(_) - | ty::Dynamic(_, _) + | ty::Dynamic(_, _, _) | ty::Closure(_, _) | ty::Generator(_, _, _) | ty::GeneratorWitness(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 046a587205b51..43c4ddd3f6faf 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -784,7 +784,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let upcast_trait_ref; match (source.kind(), target.kind()) { // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + (&ty::Dynamic(ref data_a, r_a, repr_a), &ty::Dynamic(ref data_b, r_b, repr_b)) + if repr_a == repr_b => + { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let principal_a = data_a.principal().unwrap(); @@ -810,7 +812,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, repr_b); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -888,7 +890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = vec![]; match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { + (&ty::Dynamic(ref data_a, r_a, ty::Dyn), &ty::Dynamic(ref data_b, r_b, ty::Dyn)) => { // See `assemble_candidates_for_unsizing` for more info. // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. let iter = data_a @@ -907,7 +909,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map(ty::Binder::dummy), ); let existential_predicates = tcx.mk_poly_existential_predicates(iter); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); + let source_trait = tcx.mk_dynamic(existential_predicates, r_b, ty::Dyn); // Require that the traits involved in this upcast are **equal**; // only the **lifetime bound** is changed. @@ -934,7 +936,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r)) => { + (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8b15e10ba9cbf..9efc95b4405ce 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1865,6 +1865,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Array(..) | ty::Closure(..) | ty::Never + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { // safe for everything Where(ty::Binder::dummy(Vec::new())) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9d3a1a4a031ae..f95e217da3073 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -639,7 +639,7 @@ impl<'tcx> WfPredicates<'tcx> { } } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, _) => { // WfObject // // Here, we defer WF checking due to higher-ranked diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index a6a098ce73f8d..45d5ea93d547f 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -326,7 +326,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { )), }) } - ty::Dynamic(predicates, region) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { + // FIXME(dyn-star): handle the dynamic kind (dyn or dyn*) + ty::Dynamic(predicates, region, _kind) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy { bounds: predicates.lower_into(interner), lifetime: region.lower_into(interner), }), diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 9d640672cf92c..9266e4e3f6efb 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -389,7 +389,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { let self_ty = trait_ref.self_ty(); let self_ty_matches = match self_ty.kind() { - ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(), + ty::Dynamic(ref data, re, _) if re.is_static() => data.principal().is_none(), _ => false, }; diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index e164aaed6b4b8..6d54924e515fc 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -18,6 +18,34 @@ use self::TyKind::*; use rustc_data_structures::stable_hasher::HashStable; use rustc_serialize::{Decodable, Decoder, Encodable}; +/// Specifies how a trait object is represented. +#[derive( + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + Encodable, + Decodable, + HashStable_Generic +)] +pub enum DynKind { + /// An unsized `dyn Trait` object + Dyn, + /// A sized `dyn* Trait` object + /// + /// These objects are represented as a `(data, vtable)` pair where `data` is a ptr-sized value + /// (often a pointer to the real object, but not necessarily) and `vtable` is a pointer to + /// the vtable for `dyn* Trait`. The representation is essentially the same as `&dyn Trait` + /// or similar, but the drop function included in the vtable is responsible for freeing the + /// underlying storage if needed. This allows a `dyn*` object to be treated agnostically with + /// respect to whether it points to a `Box`, `Rc`, etc. + DynStar, +} + /// Defines the kinds of types used by the type system. /// /// Types written by the user start out as `hir::TyKind` and get @@ -95,7 +123,7 @@ pub enum TyKind { FnPtr(I::PolyFnSig), /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. - Dynamic(I::ListBinderExistentialPredicate, I::Region), + Dynamic(I::ListBinderExistentialPredicate, I::Region, DynKind), /// The anonymous type of a closure. Used to represent the type of `|a| a`. /// @@ -218,7 +246,7 @@ const fn tykind_discriminant(value: &TyKind) -> usize { Ref(_, _, _) => 11, FnDef(_, _) => 12, FnPtr(_) => 13, - Dynamic(_, _) => 14, + Dynamic(..) => 14, Closure(_, _) => 15, Generator(_, _, _) => 16, GeneratorWitness(_) => 17, @@ -252,7 +280,7 @@ impl Clone for TyKind { Ref(r, t, m) => Ref(r.clone(), t.clone(), m.clone()), FnDef(d, s) => FnDef(d.clone(), s.clone()), FnPtr(s) => FnPtr(s.clone()), - Dynamic(p, r) => Dynamic(p.clone(), r.clone()), + Dynamic(p, r, repr) => Dynamic(p.clone(), r.clone(), repr.clone()), Closure(d, s) => Closure(d.clone(), s.clone()), Generator(d, s, m) => Generator(d.clone(), s.clone(), m.clone()), GeneratorWitness(g) => GeneratorWitness(g.clone()), @@ -297,9 +325,10 @@ impl PartialEq for TyKind { __self_0 == __arg_1_0 && __self_1 == __arg_1_1 } (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => __self_0 == __arg_1_0, - (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => { - __self_0 == __arg_1_0 && __self_1 == __arg_1_1 - } + ( + &Dynamic(ref __self_0, ref __self_1, ref self_repr), + &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), + ) => __self_0 == __arg_1_0 && __self_1 == __arg_1_1 && self_repr == arg_repr, (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { __self_0 == __arg_1_0 && __self_1 == __arg_1_1 } @@ -384,12 +413,16 @@ impl Ord for TyKind { } } (&FnPtr(ref __self_0), &FnPtr(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0), - (&Dynamic(ref __self_0, ref __self_1), &Dynamic(ref __arg_1_0, ref __arg_1_1)) => { - match Ord::cmp(__self_0, __arg_1_0) { - Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), + ( + &Dynamic(ref __self_0, ref __self_1, ref self_repr), + &Dynamic(ref __arg_1_0, ref __arg_1_1, ref arg_repr), + ) => match Ord::cmp(__self_0, __arg_1_0) { + Ordering::Equal => match Ord::cmp(__self_1, __arg_1_1) { + Ordering::Equal => Ord::cmp(self_repr, arg_repr), cmp => cmp, - } - } + }, + cmp => cmp, + }, (&Closure(ref __self_0, ref __self_1), &Closure(ref __arg_1_0, ref __arg_1_1)) => { match Ord::cmp(__self_0, __arg_1_0) { Ordering::Equal => Ord::cmp(__self_1, __arg_1_1), @@ -492,10 +525,11 @@ impl hash::Hash for TyKind { hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state) } - (&Dynamic(ref __self_0, ref __self_1),) => { + (&Dynamic(ref __self_0, ref __self_1, ref repr),) => { hash::Hash::hash(&tykind_discriminant(self), state); hash::Hash::hash(__self_0, state); - hash::Hash::hash(__self_1, state) + hash::Hash::hash(__self_1, state); + hash::Hash::hash(repr, state) } (&Closure(ref __self_0, ref __self_1),) => { hash::Hash::hash(&tykind_discriminant(self), state); @@ -570,7 +604,7 @@ impl fmt::Debug for TyKind { Ref(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Ref", f0, f1, f2), FnDef(f0, f1) => Formatter::debug_tuple_field2_finish(f, "FnDef", f0, f1), FnPtr(f0) => Formatter::debug_tuple_field1_finish(f, "FnPtr", f0), - Dynamic(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Dynamic", f0, f1), + Dynamic(f0, f1, f2) => Formatter::debug_tuple_field3_finish(f, "Dynamic", f0, f1, f2), Closure(f0, f1) => Formatter::debug_tuple_field2_finish(f, "Closure", f0, f1), Generator(f0, f1, f2) => { Formatter::debug_tuple_field3_finish(f, "Generator", f0, f1, f2) @@ -659,9 +693,10 @@ where FnPtr(polyfnsig) => e.emit_enum_variant(disc, |e| { polyfnsig.encode(e); }), - Dynamic(l, r) => e.emit_enum_variant(disc, |e| { + Dynamic(l, r, repr) => e.emit_enum_variant(disc, |e| { l.encode(e); r.encode(e); + repr.encode(e); }), Closure(def_id, substs) => e.emit_enum_variant(disc, |e| { def_id.encode(e); @@ -748,7 +783,7 @@ where 11 => Ref(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 12 => FnDef(Decodable::decode(d), Decodable::decode(d)), 13 => FnPtr(Decodable::decode(d)), - 14 => Dynamic(Decodable::decode(d), Decodable::decode(d)), + 14 => Dynamic(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 15 => Closure(Decodable::decode(d), Decodable::decode(d)), 16 => Generator(Decodable::decode(d), Decodable::decode(d), Decodable::decode(d)), 17 => GeneratorWitness(Decodable::decode(d)), @@ -845,9 +880,10 @@ where FnPtr(polyfnsig) => { polyfnsig.hash_stable(__hcx, __hasher); } - Dynamic(l, r) => { + Dynamic(l, r, repr) => { l.hash_stable(__hcx, __hasher); r.hash_stable(__hcx, __hasher); + repr.hash_stable(__hcx, __hasher); } Closure(def_id, substs) => { def_id.hash_stable(__hcx, __hasher); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index d9789d5aaf031..38128081e8542 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -27,6 +27,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::DynKind; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{ self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable, @@ -1252,6 +1253,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_bounds: &[hir::PolyTraitRef<'_>], lifetime: &hir::Lifetime, borrowed: bool, + representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); @@ -1572,7 +1574,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!("region_bound: {:?}", region_bound); - let ty = tcx.mk_dynamic(existential_predicates, region_bound); + let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation); debug!("trait_object_type: {:?}", ty); ty } @@ -2618,9 +2620,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Some(ast_ty), )) } - hir::TyKind::TraitObject(bounds, ref lifetime, _) => { + hir::TyKind::TraitObject(bounds, ref lifetime, repr) => { self.maybe_lint_bare_trait(ast_ty, in_path); - self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed) + let repr = match repr { + TraitObjectSyntax::Dyn | TraitObjectSyntax::None => ty::Dyn, + TraitObjectSyntax::DynStar => ty::DynStar, + }; + self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr) } hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => { debug!(?maybe_qself, ?path); diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index a3fcda5864b3f..81a979865acc3 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -35,12 +35,13 @@ use crate::type_error_struct; use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; +use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef}; +use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; @@ -52,9 +53,12 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// a function context. #[derive(Debug)] pub struct CastCheck<'tcx> { + /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, + /// The source type for the cast expression expr_ty: Ty<'tcx>, expr_span: Span, + /// The target type. That is, the type we are casting to. cast_ty: Ty<'tcx>, cast_span: Span, span: Span, @@ -101,7 +105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), - ty::Dynamic(ref tty, ..) => Some(PointerKind::VTable(tty.principal_def_id())), + ty::Dynamic(ref tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { None => Some(PointerKind::Thin), Some(f) => { @@ -138,6 +142,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::Generator(..) | ty::Adt(..) | ty::Never + | ty::Dynamic(_, _, ty::DynStar) | ty::Error(_) => { let reported = self .tcx @@ -199,8 +204,76 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +pub enum CastCheckResult<'tcx> { + Ok, + Deferred(CastCheck<'tcx>), + Err(ErrorGuaranteed), +} + +pub fn check_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, + cast_span: Span, + span: Span, +) -> CastCheckResult<'tcx> { + if cast_ty.is_dyn_star() { + check_dyn_star_cast(fcx, expr, expr_ty, cast_ty) + } else { + match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { + Ok(check) => CastCheckResult::Deferred(check), + Err(e) => CastCheckResult::Err(e), + } + } +} + +fn check_dyn_star_cast<'tcx>( + fcx: &FnCtxt<'_, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, + expr_ty: Ty<'tcx>, + cast_ty: Ty<'tcx>, +) -> CastCheckResult<'tcx> { + // Find the bounds in the dyn*. For eaxmple, if we have + // + // let x = 22_usize as dyn* (Clone + Debug + 'static) + // + // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`. + let (existential_predicates, region) = match cast_ty.kind() { + ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region), + _ => panic!("Invalid dyn* cast_ty"), + }; + + let cause = ObligationCause::new( + expr.span, + fcx.body_id, + // FIXME(dyn-star): Use a better obligation cause code + ObligationCauseCode::MiscObligation, + ); + + // For each existential predicate (e.g., `?Self: Clone`) substitute + // the type of the expression (e.g., `usize` in our example above) + // and then require that the resulting predicate (e.g., `usize: Clone`) + // holds (it does). + for existential_predicate in existential_predicates.iter() { + let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty); + fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate)); + } + + // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). + fcx.register_predicate(Obligation::new( + cause, + fcx.param_env, + fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(expr_ty, *region), + ))), + )); + + CastCheckResult::Ok +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, @@ -215,7 +288,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // cases now. We do a more thorough check at the end, once // inference is more completely known. match cast_ty.kind() { - ty::Dynamic(..) | ty::Slice(..) => { + ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => { let reported = check.report_cast_to_unsized_type(fcx); Err(reported) } @@ -854,6 +927,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), + + // FIXME(dyn-star): this needs more conditions... + (_, DynStar) => Ok(CastKind::DynStarCast), + + // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts? + (DynStar, _) => Err(CastError::IllegalCast), } } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 2139200136413..93b00850069c2 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -3,18 +3,15 @@ //! See `mod.rs` for more context on type checking in general. use crate::astconv::AstConv as _; -use crate::check::cast; +use crate::check::cast::{self, CastCheckResult}; use crate::check::coercion::CoerceMany; use crate::check::fatally_break_rust; use crate::check::method::SelfSource; -use crate::check::report_unexpected_variant_res; -use crate::check::BreakableCtxt; -use crate::check::Diverges; -use crate::check::DynamicCoerceMany; use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; -use crate::check::FnCtxt; -use crate::check::Needs; -use crate::check::TupleArgumentsFlag::DontTupleArguments; +use crate::check::{ + report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs, + TupleArgumentsFlag::DontTupleArguments, +}; use crate::errors::{ FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, YieldExprOutsideOfGenerator, @@ -1252,8 +1249,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { - Ok(cast_check) => { + match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) { + CastCheckResult::Ok => t_cast, + CastCheckResult::Deferred(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", t_cast, t_expr, cast_check, @@ -1261,7 +1259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - Err(_) => self.tcx.ty_error(), + CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(), } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 2bfee9a536439..ee0ad7b5d0ab4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }) } - ty::Dynamic(data, _) => { + ty::Dynamic(data, _, ty::Dyn) => { data.iter().find_map(|pred| { if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder() && Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output() diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 7fda6f79f238d..7ab6d9e2bab12 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -527,7 +527,7 @@ fn check_must_not_suspend_ty<'tcx>( } has_emitted } - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { let mut has_emitted = false; for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 8065b848ad6f8..2d459b2cc0e32 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -537,7 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_spans.push((self.tcx.def_span(def.did()), msg)) } // Point at the trait object that couldn't satisfy the bound. - ty::Dynamic(preds, _) => { + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::Trait(tr) => bound_spans diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index 840f0c978484d..eaf0310d57aec 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -257,7 +257,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_invariant_substs(current, substs, variance); } - ty::Dynamic(data, r) => { + ty::Dynamic(data, r, _) => { // The type `Foo` is contravariant w/r/t `'a`: let contra = self.contravariant(variance); self.add_constraints_from_region(current, r, contra); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9f0b7018af5f0..c8875c272bb08 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1600,7 +1600,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty()); Type::Path { path } } - ty::Dynamic(obj, ref reg) => { + ty::Dynamic(obj, ref reg, _) => { // HACK: pick the first `did` as the `did` of the trait object. Someone // might want to implement "native" support for marker-trait-only // trait objects. diff --git a/src/test/ui/dyn-star/const.rs b/src/test/ui/dyn-star/const.rs new file mode 100644 index 0000000000000..e49caf649f892 --- /dev/null +++ b/src/test/ui/dyn-star/const.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(dyn_star)] +#![allow(unused, incomplete_features)] + +use std::fmt::Debug; + +fn make_dyn_star() { + let i = 42usize; + let dyn_i: dyn* Debug = i as dyn* Debug; +} + +fn main() { + make_dyn_star(); +} diff --git a/src/test/ui/dyn-star/drop.rs b/src/test/ui/dyn-star/drop.rs new file mode 100644 index 0000000000000..46b232f3dd399 --- /dev/null +++ b/src/test/ui/dyn-star/drop.rs @@ -0,0 +1,23 @@ +// run-pass +// check-run-results +#![feature(dyn_star)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +#[derive(Debug)] +struct Foo(usize); + +impl Drop for Foo { + fn drop(&mut self) { + println!("destructor called"); + } +} + +fn make_dyn_star(i: Foo) { + let _dyn_i: dyn* Debug = i as dyn* Debug; +} + +fn main() { + make_dyn_star(Foo(42)); +} diff --git a/src/test/ui/dyn-star/drop.run.stdout b/src/test/ui/dyn-star/drop.run.stdout new file mode 100644 index 0000000000000..dadb33ccf3ac3 --- /dev/null +++ b/src/test/ui/dyn-star/drop.run.stdout @@ -0,0 +1 @@ +destructor called diff --git a/src/test/ui/dyn-star/error.rs b/src/test/ui/dyn-star/error.rs new file mode 100644 index 0000000000000..33eff80a5fe70 --- /dev/null +++ b/src/test/ui/dyn-star/error.rs @@ -0,0 +1,13 @@ +#![feature(dyn_star)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +trait Foo {} + +fn make_dyn_star() { + let i = 42; + let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied +} + +fn main() {} diff --git a/src/test/ui/dyn-star/error.stderr b/src/test/ui/dyn-star/error.stderr new file mode 100644 index 0000000000000..d612ccc630ea8 --- /dev/null +++ b/src/test/ui/dyn-star/error.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `{integer}: Foo` is not satisfied + --> $DIR/error.rs:10:27 + | +LL | let dyn_i: dyn* Foo = i as dyn* Foo; + | ^ the trait `Foo` is not implemented for `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/dyn-star/feature-gate-dyn_star.rs b/src/test/ui/dyn-star/feature-gate-dyn_star.rs new file mode 100644 index 0000000000000..4756661cf41b7 --- /dev/null +++ b/src/test/ui/dyn-star/feature-gate-dyn_star.rs @@ -0,0 +1,9 @@ +// Feature gate test for dyn_star + +/// dyn* is not necessarily the final surface syntax (if we have one at all), +/// but for now we will support it to aid in writing tests independently. +pub fn dyn_star_parameter(_: &dyn* Send) { + //~^ dyn* trait objects are unstable +} + +fn main() {} diff --git a/src/test/ui/dyn-star/feature-gate-dyn_star.stderr b/src/test/ui/dyn-star/feature-gate-dyn_star.stderr new file mode 100644 index 0000000000000..2767e9478e2e8 --- /dev/null +++ b/src/test/ui/dyn-star/feature-gate-dyn_star.stderr @@ -0,0 +1,12 @@ +error[E0658]: dyn* trait objects are unstable + --> $DIR/feature-gate-dyn_star.rs:5:31 + | +LL | pub fn dyn_star_parameter(_: &dyn* Send) { + | ^^^^^^^^^ + | + = note: see issue #91611 for more information + = help: add `#![feature(dyn_star)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs new file mode 100644 index 0000000000000..708ffa25d6fee --- /dev/null +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -0,0 +1,13 @@ +// run-pass +#![feature(dyn_star)] +#![allow(incomplete_features)] + +use std::fmt::Debug; + +fn make_dyn_star(i: usize) { + let _dyn_i: dyn* Debug = i as dyn* Debug; +} + +fn main() { + make_dyn_star(42); +} diff --git a/src/test/ui/dyn-star/method.rs b/src/test/ui/dyn-star/method.rs new file mode 100644 index 0000000000000..d04958ca2aac9 --- /dev/null +++ b/src/test/ui/dyn-star/method.rs @@ -0,0 +1,26 @@ +// run-pass +#![feature(dyn_star)] +#![allow(incomplete_features)] + +trait Foo { + fn get(&self) -> usize; +} + +impl Foo for usize { + fn get(&self) -> usize { + *self + } +} + +fn invoke_dyn_star(i: dyn* Foo) -> usize { + i.get() +} + +fn make_and_invoke_dyn_star(i: usize) -> usize { + let dyn_i: dyn* Foo = i as dyn* Foo; + invoke_dyn_star(dyn_i) +} + +fn main() { + println!("{}", make_and_invoke_dyn_star(42)); +} diff --git a/src/test/ui/dyn-star/syntax.rs b/src/test/ui/dyn-star/syntax.rs new file mode 100644 index 0000000000000..618c72562b2a7 --- /dev/null +++ b/src/test/ui/dyn-star/syntax.rs @@ -0,0 +1,11 @@ +// Make sure we can parse the `dyn* Trait` syntax +// +// check-pass + +#![feature(dyn_star)] +#![allow(incomplete_features)] + +pub fn dyn_star_parameter(_: dyn* Send) { +} + +fn main() {} diff --git a/src/test/ui/parser/trait-object-delimiters.rs b/src/test/ui/parser/trait-object-delimiters.rs index b5258eebb90ad..cc04ac052040e 100644 --- a/src/test/ui/parser/trait-object-delimiters.rs +++ b/src/test/ui/parser/trait-object-delimiters.rs @@ -6,7 +6,7 @@ fn foo1(_: &dyn Drop + AsRef) {} //~ ERROR ambiguous `+` in a type fn foo2(_: &dyn (Drop + AsRef)) {} //~ ERROR incorrect braces around trait bounds fn foo3(_: &dyn {Drop + AsRef}) {} //~ ERROR expected parameter name, found `{` -//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` +//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` //~| ERROR at least one trait is required for an object type fn foo4(_: &dyn >) {} //~ ERROR expected identifier, found `<` diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr index 6eb9c7238cb82..99c4515459d2e 100644 --- a/src/test/ui/parser/trait-object-delimiters.stderr +++ b/src/test/ui/parser/trait-object-delimiters.stderr @@ -22,11 +22,11 @@ error: expected parameter name, found `{` LL | fn foo3(_: &dyn {Drop + AsRef}) {} | ^ expected parameter name -error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` +error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{` --> $DIR/trait-object-delimiters.rs:8:17 | LL | fn foo3(_: &dyn {Drop + AsRef}) {} - | -^ expected one of 9 possible tokens + | -^ expected one of 10 possible tokens | | | help: missing `,` diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 74927570b40eb..8bdadf2440231 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -2,7 +2,7 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; -use rustc_typeck::check::{cast::CastCheck, FnCtxt, Inherited}; +use rustc_typeck::check::{cast::{self, CastCheckResult}, FnCtxt, Inherited}; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment @@ -53,7 +53,7 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> "Newly created FnCtxt contained errors" ); - if let Ok(check) = CastCheck::new( + if let CastCheckResult::Deferred(check) = cast::check_cast( &fn_ctxt, e, from_ty, to_ty, // We won't show any error to the user, so we don't care what the span is here. DUMMY_SP, DUMMY_SP, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index d5f64e5118f56..8835b93290958 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -82,7 +82,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult { ty::FnPtr(..) => { return Err((span, "function pointers in const fn are unstable".into())); }, - ty::Dynamic(preds, _) => { + ty::Dynamic(preds, _, _) => { for pred in preds.iter() { match pred.skip_binder() { ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => { @@ -161,6 +161,10 @@ fn check_rvalue<'tcx>( Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, + Rvalue::Cast(CastKind::DynStar, _, _) => { + // FIXME(dyn-star) + unimplemented!() + }, // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => { check_operand(tcx, lhs, span, body)?; @@ -221,7 +225,6 @@ fn check_statement<'tcx>( check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) }, - // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 5a7f9568441c9..a8ad6cf4f6a3c 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -201,7 +201,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { } false }, - ty::Dynamic(binder, _) => { + ty::Dynamic(binder, _, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) { @@ -579,7 +579,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), - ty::Dynamic(bounds, _) => { + ty::Dynamic(bounds, _, _) => { let lang_items = cx.tcx.lang_items(); match bounds.principal() { Some(bound)