about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2020-06-28 20:34:56 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2020-10-06 11:19:30 +0100
commit2bdf723da7c465e052a1b1fc448c0014c46b9e51 (patch)
tree7a8bec8c03d6787d713f912f59e9e7db9da699af /compiler/rustc_trait_selection/src
parent0a76584dcc6dd6ae8f32f905dde379a99da7e516 (diff)
downloadrust-2bdf723da7c465e052a1b1fc448c0014c46b9e51.tar.gz
rust-2bdf723da7c465e052a1b1fc448c0014c46b9e51.zip
Ensure that associated types for trait objects satisfy their bounds
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs64
1 files changed, 51 insertions, 13 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 76be4a80452..1ed4cca107e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -9,7 +9,7 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::GrowableBitSet;
-use rustc_infer::infer::InferOk;
+use rustc_infer::infer::{self, InferOk};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
 use rustc_middle::ty::{self, Ty};
 use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
@@ -342,21 +342,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
         debug!("confirm_object_candidate({:?})", obligation);
 
-        // FIXME(nmatsakis) skipping binder here seems wrong -- we should
-        // probably flatten the binder from the obligation and the binder
-        // from the object. Have to try to make a broken test case that
-        // results.
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        let poly_trait_ref = match self_ty.kind() {
-            ty::Dynamic(data, ..) => data
-                .principal()
-                .unwrap_or_else(|| {
-                    span_bug!(obligation.cause.span, "object candidate with no principal")
-                })
-                .with_self_ty(self.tcx(), self_ty),
+        let self_ty = self.infcx.replace_bound_vars_with_placeholders(&obligation.self_ty());
+        let data = match self_ty.kind() {
+            ty::Dynamic(data, ..) => data,
             _ => span_bug!(obligation.cause.span, "object candidate with non-object"),
         };
 
+        let poly_trait_ref = data
+            .principal()
+            .unwrap_or_else(|| {
+                span_bug!(obligation.cause.span, "object candidate with no principal")
+            })
+            .with_self_ty(self.tcx(), self_ty);
+
         let mut upcast_trait_ref = None;
         let mut nested = vec![];
         let vtable_base;
@@ -388,6 +386,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
         }
 
+        for bound in data.skip_binder() {
+            match bound {
+                ty::ExistentialPredicate::Projection(projection) => {
+                    // This maybe belongs in wf, but that can't (doesn't) handle
+                    // higher-ranked things.
+                    // Prevent, e.g., `dyn Iterator<Item = str>`.
+                    // FIXME(generic_associated_types): We need some way to
+                    // ensure that for `dyn for<'a> X<Item<'a> = &'a ()>` the
+                    // bound holds for all `'a`.
+                    let (infer_projection, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+                        obligation.cause.span,
+                        infer::HigherRankedType,
+                        &ty::Binder::bind(projection),
+                    );
+                    let substs: Vec<_> =
+                        iter::once(self_ty.into()).chain(infer_projection.substs).collect();
+                    let bounds =
+                        self.tcx().item_bounds(projection.item_def_id).iter().map(|bound| {
+                            // In the example above, `bound` is `<Self as Iterator>::Item: Sized`
+                            // `subst_bound` is `str: Sized`.
+                            let subst_bound = util::subst_assoc_item_bound(
+                                self.tcx(),
+                                bound,
+                                infer_projection.ty,
+                                &substs,
+                            );
+                            Obligation::new(
+                                obligation.cause.clone(),
+                                obligation.param_env.clone(),
+                                subst_bound,
+                            )
+                        });
+                    debug!("confirm_object_candidate: adding bounds: {:?}", bounds);
+                    nested.extend(bounds);
+                }
+                ty::ExistentialPredicate::Trait(_) | ty::ExistentialPredicate::AutoTrait(_) => {}
+            }
+        }
+
+        debug!("confirm_object_candidate: nested: {:?}", nested);
         ImplSourceObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested }
     }