diff options
| author | Alexander Regueiro <alexreg@me.com> | 2018-11-01 19:43:38 +0000 |
|---|---|---|
| committer | Alexander Regueiro <alexreg@me.com> | 2018-11-07 21:56:06 +0000 |
| commit | d08a42bf2c2115fc1869b3a72ee40fa4dd445795 (patch) | |
| tree | ea3b31be61940c2a7275da8f57952472803cf572 /src | |
| parent | 25a42b2ceb46887e9941cec667eac99844dd7ad0 (diff) | |
| download | rust-d08a42bf2c2115fc1869b3a72ee40fa4dd445795.tar.gz rust-d08a42bf2c2115fc1869b3a72ee40fa4dd445795.zip | |
Look at projections from supertraits when constructing trait objects.
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc/hir/mod.rs | 6 | ||||
| -rw-r--r-- | src/librustc/traits/util.rs | 2 | ||||
| -rw-r--r-- | src/librustc/ty/mod.rs | 47 | ||||
| -rw-r--r-- | src/librustc_typeck/astconv.rs | 85 | ||||
| -rw-r--r-- | src/librustc_typeck/check/wfcheck.rs | 6 |
5 files changed, 77 insertions, 69 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index a2095ff40c0..f57e3ff913b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -506,9 +506,9 @@ pub enum TraitBoundModifier { } /// The AST represents all type param bounds as types. -/// typeck::collect::compute_bounds matches these against -/// the "special" built-in traits (see middle::lang_items) and -/// detects Copy, Send and Sync. +/// `typeck::collect::compute_bounds` matches these against +/// the "special" built-in traits (see `middle::lang_items`) and +/// detects `Copy`, `Send` and `Sync`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum GenericBound { Trait(PolyTraitRef, TraitBoundModifier), diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 74f8d67ce04..24097fcca70 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -333,7 +333,7 @@ impl<I> FilterToTraits<I> { } } -impl<'tcx,I:Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { +impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c7c197d11c0..c18c55bcb5d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -294,7 +294,7 @@ impl Visibility { } } - /// Returns true if an item with this visibility is accessible from the given block. + /// Returns `true` if an item with this visibility is accessible from the given block. pub fn is_accessible_from<T: DefIdTree>(self, module: DefId, tree: T) -> bool { let restriction = match self { // Public items are visible everywhere. @@ -309,7 +309,7 @@ impl Visibility { tree.is_descendant_of(module, restriction) } - /// Returns true if this visibility is at least as accessible as the given visibility + /// Returns `true` if this visibility is at least as accessible as the given visibility pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool { let vis_restriction = match vis { Visibility::Public => return self == Visibility::Public, @@ -320,7 +320,7 @@ impl Visibility { self.is_accessible_from(vis_restriction, tree) } - // Returns true if this item is visible anywhere in the local crate. + // Returns `true` if this item is visible anywhere in the local crate. pub fn is_visible_locally(self) -> bool { match self { Visibility::Public => true, @@ -451,7 +451,7 @@ bitflags! { // FIXME: Rename this to the actual property since it's used for generators too const HAS_TY_CLOSURE = 1 << 9; - // true if there are "names" of types and regions and so forth + // `true` if there are "names" of types and regions and so forth // that are local to a particular fn const HAS_FREE_LOCAL_NAMES = 1 << 10; @@ -953,7 +953,7 @@ impl<'a, 'gcx, 'tcx> Generics { _ => bug!("expected lifetime parameter, but found another generic parameter") } } else { - tcx.generics_of(self.parent.expect("parent_count>0 but no parent?")) + tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) .region_param(param, tcx) } } @@ -970,7 +970,7 @@ impl<'a, 'gcx, 'tcx> Generics { _ => bug!("expected type parameter, but found another generic parameter") } } else { - tcx.generics_of(self.parent.expect("parent_count>0 but no parent?")) + tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) .type_param(param, tcx) } } @@ -993,6 +993,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { self.instantiate_into(tcx, &mut instantiated, substs); instantiated } + pub fn instantiate_own(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { InstantiatedPredicates { @@ -1256,14 +1257,14 @@ pub struct ProjectionPredicate<'tcx> { pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { - /// Returns the def-id of the associated item being projected. + /// Returns the `DefId` of the associated item being projected. pub fn item_def_id(&self) -> DefId { self.skip_binder().projection_ty.item_def_id } pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'_, '_, '_>) -> PolyTraitRef<'tcx> { - // Note: unlike with TraitRef::to_poly_trait_ref(), - // self.0.trait_ref is permitted to have escaping regions. + // Note: unlike with `TraitRef::to_poly_trait_ref()`, + // `self.0.trait_ref` is permitted to have escaping regions. // This is because here `self` has a `Binder` and so does our // return value, so we are preserving the number of binding // levels. @@ -1274,12 +1275,12 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { self.map_bound(|predicate| predicate.ty) } - /// The DefId of the TraitItem for the associated type. + /// The `DefId` of the `TraitItem` for the associated type. /// - /// Note that this is not the DefId of the TraitRef containing this - /// associated type, which is in tcx.associated_item(projection_def_id()).container. + /// Note that this is not the `DefId` of the `TraitRef` containing this + /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. pub fn projection_def_id(&self) -> DefId { - // ok to skip binder since trait def-id does not care about regions + // okay to skip binder since trait def-id does not care about regions self.skip_binder().projection_ty.item_def_id } } @@ -1515,14 +1516,14 @@ impl UniverseIndex { UniverseIndex::from_u32(self.private.checked_add(1).unwrap()) } - /// True if `self` can name a name from `other` -- in other words, + /// `true` if `self` can name a name from `other` -- in other words, /// if the set of names in `self` is a superset of those in /// `other` (`self >= other`). pub fn can_name(self, other: UniverseIndex) -> bool { self.private >= other.private } - /// True if `self` cannot name some names from `other` -- in other + /// `true` if `self` cannot name some names from `other` -- in other /// words, if the set of names in `self` is a strict subset of /// those in `other` (`self < other`). pub fn cannot_name(self, other: UniverseIndex) -> bool { @@ -1574,7 +1575,7 @@ impl<'tcx> ParamEnv<'tcx> { /// are revealed. This is suitable for monomorphized, post-typeck /// environments like codegen or doing optimizations. /// - /// NB. If you want to have predicates in scope, use `ParamEnv::new`, + /// N.B. If you want to have predicates in scope, use `ParamEnv::new`, /// or invoke `param_env.with_reveal_all()`. pub fn reveal_all() -> Self { Self::new(List::empty(), Reveal::All) @@ -1979,14 +1980,14 @@ impl ReprOptions { self.int.unwrap_or(attr::SignedInt(ast::IntTy::Isize)) } - /// Returns true if this `#[repr()]` should inhabit "smart enum + /// Returns `true` if this `#[repr()]` should inhabit "smart enum /// layout" optimizations, such as representing `Foo<&T>` as a /// single pointer. pub fn inhibit_enum_layout_opt(&self) -> bool { self.c() || self.int.is_some() } - /// Returns true if this `#[repr()]` should inhibit struct field reordering + /// Returns `true` if this `#[repr()]` should inhibit struct field reordering /// optimizations, such as with repr(C) or repr(packed(1)). pub fn inhibit_struct_field_reordering_opt(&self) -> bool { !(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1) @@ -2089,7 +2090,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.intersects(AdtFlags::IS_FUNDAMENTAL) } - /// Returns true if this is PhantomData<T>. + /// Returns `true` if this is PhantomData<T>. #[inline] pub fn is_phantom_data(&self) -> bool { self.flags.intersects(AdtFlags::IS_PHANTOM_DATA) @@ -2105,7 +2106,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.intersects(AdtFlags::IS_RC) } - /// Returns true if this is Box<T>. + /// Returns `true` if this is Box<T>. #[inline] pub fn is_box(&self) -> bool { self.flags.intersects(AdtFlags::IS_BOX) @@ -2422,7 +2423,7 @@ impl<'a, 'tcx> ClosureKind { } } - /// True if this a type that impls this closure kind + /// Returns `true` if this a type that impls this closure kind /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { match (self, other) { @@ -2678,7 +2679,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { as Box<dyn Iterator<Item = AssociatedItem> + 'a> } - /// Returns true if the impls are the same polarity and the trait either + /// Returns `true` if the impls are the same polarity and the trait either /// has no items or is annotated #[marker] and prevents item overrides. pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { if self.features().overlapping_marker_traits { @@ -2802,7 +2803,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { attr::contains_name(&self.get_attrs(did), attr) } - /// Returns true if this is an `auto trait`. + /// Returns `true` if this is an `auto trait`. pub fn trait_is_auto(self, trait_def_id: DefId) -> bool { self.trait_def(trait_def_id).has_auto_impl } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 18f8473b5b5..daf04aa0db2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -451,7 +451,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } // We manually build up the substitution, rather than using convenience - // methods in subst.rs so that we can iterate over the arguments and + // methods in `subst.rs` so that we can iterate over the arguments and // parameters in lock-step linearly, rather than trying to match each pair. let mut substs: SmallVec<[Kind<'tcx>; 8]> = SmallVec::with_capacity(count); @@ -469,7 +469,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } } - // (Unless it's been handled in `parent_substs`) `Self` is handled first. + // `Self` is handled first, unless it's been handled in `parent_substs`. if has_self { if let Some(¶m) = params.peek() { if param.index == 0 { @@ -698,7 +698,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { trait_ref.path.segments.last().unwrap()) } - /// Get the DefId of the given trait ref. It _must_ actually be a trait. + /// Get the `DefId` of the given trait ref. It _must_ actually be a trait. fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId { let path = &trait_ref.path; match path.def { @@ -711,7 +711,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } } - /// The given `trait_ref` must actually be trait. + /// The given trait ref must actually be a trait. pub(super) fn instantiate_poly_trait_ref_inner(&self, trait_ref: &hir::TraitRef, self_ty: Ty<'tcx>, @@ -738,7 +738,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let predicate: Result<_, ErrorReported> = self.ast_type_binding_to_poly_projection_predicate( trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings); - // ok to ignore Err because ErrorReported (see above) + // okay to ignore Err because of ErrorReported (see above) Some((predicate.ok()?, binding.span)) })); @@ -947,14 +947,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { ) } - /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - /// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`). - fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>) - -> ty::ExistentialTraitRef<'tcx> { - assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF); - ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) - } - fn conv_object_ty_poly_trait_ref(&self, span: Span, trait_bounds: &[hir::PolyTraitRef], @@ -969,7 +961,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { return tcx.types.err; } - let mut projection_bounds = vec![]; + let mut projection_bounds = Vec::new(); let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); let principal = self.instantiate_poly_trait_ref(&trait_bounds[0], dummy_self, @@ -994,23 +986,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { .emit(); } - // Erase the dummy_self (TRAIT_OBJECT_DUMMY_SELF) used above. - let existential_principal = principal.map_bound(|trait_ref| { - self.trait_ref_to_existential(trait_ref) - }); - let existential_projections = projection_bounds.iter().map(|(bound, _)| { - bound.map_bound(|b| { - let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx)); - ty::ExistentialProjection { - ty: b.ty, - item_def_id: b.projection_ty.item_def_id, - substs: trait_ref.substs, - } - }) - }); - // Check that there are no gross object safety violations; - // most importantly, that the supertraits don't contain Self, + // most importantly, that the supertraits don't contain `Self`, // to avoid ICEs. let object_safety_violations = tcx.global_tcx().astconv_object_safety_violations(principal.def_id()); @@ -1021,13 +998,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { return tcx.types.err; } - // Use a BTreeSet to keep output in a more consistent order. + // Use a `BTreeSet` to keep output in a more consistent order. let mut associated_types = BTreeSet::default(); for tr in traits::supertraits(tcx, principal) { associated_types.extend(tcx.associated_items(tr.def_id()) .filter(|item| item.kind == ty::AssociatedKind::Type) .map(|item| item.def_id)); + + projection_bounds.extend(tcx.predicates_of(tr.def_id()) + .predicates.into_iter() + .filter_map(|(pred, span)| { + if let ty::Predicate::Projection(proj) = pred { + Some((proj, span)) + } else { + None + } + })); } for (projection_bound, _) in &projection_bounds { @@ -1046,11 +1033,28 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { .emit(); } + // Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above. + let existential_principal = principal.map_bound(|trait_ref| { + assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF); + ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) + }); + let existential_projections = projection_bounds.iter().map(|(bound, _)| { + bound.map_bound(|b| { + let trait_ref = ty::ExistentialTraitRef::erase_self_ty(self.tcx(), + b.projection_ty.trait_ref(tcx)); + ty::ExistentialProjection { + ty: b.ty, + item_def_id: b.projection_ty.item_def_id, + substs: trait_ref.substs, + } + }) + }); + // Dedup auto traits so that `dyn Trait + Send + Send` is the same as `dyn Trait + Send`. auto_traits.sort(); auto_traits.dedup(); - // skip_binder is okay, because the predicates are re-bound. + // Calling `skip_binder` is okay, because the predicates are re-bound. let mut v = iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())) .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait)) @@ -1128,7 +1132,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { span) } - // Checks that bounds contains exactly one element and reports appropriate // errors otherwise. fn one_bound_for_assoc_type<I>(&self, @@ -1186,11 +1189,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { } // Create a type from a path to an associated type. - // For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C - // and item_segment is the path segment for D. We return a type and a def for + // For a path `A::B::C::D`, `ty` and `ty_path_def` are the type and def for `A::B::C` + // and item_segment is the path segment for `D`. We return a type and a def for // the whole path. - // Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type - // parameter or Self. + // Will fail except for `T::A` and `Self::A`; i.e., if `ty`/`ty_path_def` are not a type + // parameter or `Self`. pub fn associated_path_def_to_ty(&self, ref_id: ast::NodeId, span: Span, @@ -1210,7 +1213,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { // item is declared. let bound = match (&ty.sty, ty_path_def) { (_, Def::SelfTy(Some(_), Some(impl_def_id))) => { - // `Self` in an impl of a trait - we have a concrete self type and a + // `Self` in an impl of a trait - we have a concrete `self` type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { Some(trait_ref) => trait_ref, @@ -1361,7 +1364,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let span = path.span; match path.def { Def::Existential(did) => { - // check for desugared impl trait + // Check for desugared impl trait. assert!(ty::is_impl_trait_defn(tcx, did).is_none()); let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1); @@ -1398,7 +1401,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { tcx.mk_ty_param(index, tcx.hir.name(node_id).as_interned_str()) } Def::SelfTy(_, Some(def_id)) => { - // Self in impl (we know the concrete type). + // `Self` in impl (we know the concrete type) assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); @@ -1406,7 +1409,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { tcx.at(span).type_of(def_id) } Def::SelfTy(Some(_), None) => { - // Self in trait. + // `Self` in trait assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); tcx.mk_self_type() diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 266b9e3c0ab..53f53657863 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -186,6 +186,8 @@ fn check_associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId, span: Span, sig_if_method: Option<&hir::MethodSig>) { + debug!("check_associated_item: {:?}", item_id); + let code = ObligationCauseCode::MiscObligation; for_id(tcx, item_id, span).with_fcx(|fcx, tcx| { let item = fcx.tcx.associated_item(fcx.tcx.hir.local_def_id(item_id)); @@ -311,6 +313,8 @@ fn check_type_defn<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { + debug!("check_trait: {:?}", item.id); + let trait_def_id = tcx.hir.local_def_id(item.id); let trait_def = tcx.trait_def(trait_def_id); @@ -1012,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } None => { - // Inherent impl: take implied bounds from the self type. + // Inherent impl: take implied bounds from the `self` type. let self_ty = self.tcx.type_of(impl_def_id); let self_ty = self.normalize_associated_types_in(span, &self_ty); vec![self_ty] |
