Auto merge of #101212 - eholk:dyn-star, r=compiler-errors
Initial implementation of dyn* This PR adds extremely basic and incomplete support for [dyn*](https://smallcultfollowing.com/babysteps//blog/2022/03/29/dyn-can-we-make-dyn-sized/). The goal is to get something in tree behind a flag to make collaboration easier, and also to make sure the implementation so far is not unreasonable. This PR does quite a few things: * Introduce `dyn_star` feature flag * Adds parsing for `dyn* Trait` types * Defines `dyn* Trait` as a sized type * Adds support for explicit casts, like `42usize as dyn* Debug` * Including const evaluation of such casts * Adds codegen for drop glue so things are cleaned up properly when a `dyn* Trait` object goes out of scope * Adds codegen for method calls, at least for methods that take `&self` Quite a bit is still missing, but this gives us a starting point. Note that this is never intended to become stable surface syntax for Rust, but rather `dyn*` is planned to be used as an implementation detail for async functions in dyn traits. Joint work with `@nikomatsakis` and `@compiler-errors.` r? `@bjorn3`
This commit is contained in:
commit
6153d3cbe6
@ -2072,6 +2072,7 @@ impl TyKind {
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum TraitObjectSyntax {
|
||||
Dyn,
|
||||
DynStar,
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -554,6 +554,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)
|
||||
|
@ -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};
|
||||
@ -2013,6 +2014,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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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<dyn Trait>` from a value of type `Foo<T>`, 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;
|
||||
|
@ -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,13 +398,29 @@ 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<T> ( *mut T, Vtable<T: Trait> )
|
||||
// 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)
|
||||
@ -411,6 +428,51 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
fn_abi,
|
||||
)
|
||||
}
|
||||
ty::Dynamic(_, _, ty::DynStar) => {
|
||||
// IN THIS ARM, WE HAVE:
|
||||
// ty = *mut (dyn* Trait)
|
||||
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
|
||||
//
|
||||
// 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),
|
||||
fn_abi,
|
||||
)
|
||||
}
|
||||
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
|
||||
};
|
||||
helper.do_call(
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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)?;
|
||||
|
@ -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(_)
|
||||
|
@ -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(_) => {
|
||||
|
@ -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, _) => {}
|
||||
|
@ -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
|
||||
|
@ -384,6 +384,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.
|
||||
|
@ -544,7 +544,7 @@ pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
|
||||
impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
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);
|
||||
}
|
||||
|
@ -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) =
|
||||
|
@ -1818,6 +1818,7 @@ impl<'tcx> Rvalue<'tcx> {
|
||||
// While the model is undecided, we should be conservative. See
|
||||
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
|
||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
|
||||
Rvalue::Cast(CastKind::DynStar, _, _) => false,
|
||||
|
||||
Rvalue::Use(_)
|
||||
| Rvalue::CopyForDeref(_)
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>,
|
||||
reg: ty::Region<'tcx>,
|
||||
repr: DynKind,
|
||||
) -> Ty<'tcx> {
|
||||
self.mk_ty(Dynamic(obj, reg))
|
||||
self.mk_ty(Dynamic(obj, reg, repr))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -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(_) => {
|
||||
|
@ -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),
|
||||
|
@ -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<DefId>, 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 `<dyn Trait as Trait>::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<usize>| -> 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),
|
||||
}
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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<T>(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<T>(
|
||||
self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -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), ")");
|
||||
}
|
||||
|
@ -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, _))
|
||||
|
@ -1028,9 +1028,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)?),
|
||||
@ -1074,7 +1076,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)
|
||||
}
|
||||
|
@ -692,6 +692,9 @@ impl<'tcx> ExistentialPredicate<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> {
|
||||
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||
/// 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<u32>`, 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]
|
||||
|
@ -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() {
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -651,6 +651,7 @@ symbols! {
|
||||
dropck_parametricity,
|
||||
dylib,
|
||||
dyn_metadata,
|
||||
dyn_star,
|
||||
dyn_trait,
|
||||
e,
|
||||
edition_macro_pats,
|
||||
|
@ -627,10 +627,13 @@ fn encode_ty<'tcx>(
|
||||
}
|
||||
|
||||
// Trait types
|
||||
ty::Dynamic(predicates, region) => {
|
||||
ty::Dynamic(predicates, region, kind) => {
|
||||
// u3dynI<element-type1[..element-typeN]>E, where <element-type> is <predicate>, 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');
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
@ -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))))
|
||||
|
@ -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<dyn Trait>`.
|
||||
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();
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(_)
|
||||
|
@ -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));
|
||||
|
@ -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()))
|
||||
|
@ -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
|
||||
|
@ -326,7 +326,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> 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),
|
||||
}),
|
||||
|
@ -389,7 +389,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -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<T>`, `Rc<T>`, 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<I: Interner> {
|
||||
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<I: Interner>(value: &TyKind<I>) -> usize {
|
||||
Ref(_, _, _) => 11,
|
||||
FnDef(_, _) => 12,
|
||||
FnPtr(_) => 13,
|
||||
Dynamic(_, _) => 14,
|
||||
Dynamic(..) => 14,
|
||||
Closure(_, _) => 15,
|
||||
Generator(_, _, _) => 16,
|
||||
GeneratorWitness(_) => 17,
|
||||
@ -252,7 +280,7 @@ impl<I: Interner> Clone for TyKind<I> {
|
||||
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<I: Interner> PartialEq for TyKind<I> {
|
||||
__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<I: Interner> Ord for TyKind<I> {
|
||||
}
|
||||
}
|
||||
(&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<I: Interner> hash::Hash for TyKind<I> {
|
||||
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<I: Interner> fmt::Debug for TyKind<I> {
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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<T+'a>` is contravariant w/r/t `'a`:
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(current, r, contra);
|
||||
|
@ -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.
|
||||
|
14
src/test/ui/dyn-star/const.rs
Normal file
14
src/test/ui/dyn-star/const.rs
Normal file
@ -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();
|
||||
}
|
23
src/test/ui/dyn-star/drop.rs
Normal file
23
src/test/ui/dyn-star/drop.rs
Normal file
@ -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));
|
||||
}
|
1
src/test/ui/dyn-star/drop.run.stdout
Normal file
1
src/test/ui/dyn-star/drop.run.stdout
Normal file
@ -0,0 +1 @@
|
||||
destructor called
|
13
src/test/ui/dyn-star/error.rs
Normal file
13
src/test/ui/dyn-star/error.rs
Normal file
@ -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() {}
|
9
src/test/ui/dyn-star/error.stderr
Normal file
9
src/test/ui/dyn-star/error.stderr
Normal file
@ -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`.
|
9
src/test/ui/dyn-star/feature-gate-dyn_star.rs
Normal file
9
src/test/ui/dyn-star/feature-gate-dyn_star.rs
Normal file
@ -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() {}
|
12
src/test/ui/dyn-star/feature-gate-dyn_star.stderr
Normal file
12
src/test/ui/dyn-star/feature-gate-dyn_star.stderr
Normal file
@ -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 <https://github.com/rust-lang/rust/issues/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`.
|
13
src/test/ui/dyn-star/make-dyn-star.rs
Normal file
13
src/test/ui/dyn-star/make-dyn-star.rs
Normal file
@ -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);
|
||||
}
|
26
src/test/ui/dyn-star/method.rs
Normal file
26
src/test/ui/dyn-star/method.rs
Normal file
@ -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));
|
||||
}
|
11
src/test/ui/dyn-star/syntax.rs
Normal file
11
src/test/ui/dyn-star/syntax.rs
Normal file
@ -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() {}
|
@ -6,7 +6,7 @@ fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
|
||||
fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
|
||||
|
||||
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ 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 <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
|
||||
|
@ -22,11 +22,11 @@ error: expected parameter name, found `{`
|
||||
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
||||
| ^ 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<str>}) {}
|
||||
| -^ expected one of 9 possible tokens
|
||||
| -^ expected one of 10 possible tokens
|
||||
| |
|
||||
| help: missing `,`
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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(_)
|
||||
|
@ -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<ExprFnSig<'t
|
||||
ty::FnDef(id, subs) => 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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user