]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc/traits/project.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc / traits / project.rs
index 30faf1a5f8b91b75fc13bf0ea69aaaec3f7acef3..aed4f4393241191d1f2d655f2ba594a709d67b10 100644 (file)
@@ -38,7 +38,7 @@ use std::rc::Rc;
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ProjectionMode {
+pub enum Reveal {
     /// FIXME (#32205)
     /// At coherence-checking time, we're still constructing the
     /// specialization graph, and thus we only project
@@ -67,7 +67,7 @@ pub enum ProjectionMode {
     ///
     /// The projection would succeed if `Output` had been defined
     /// directly in the impl for `u8`.
-    Topmost,
+    ExactMatch,
 
     /// At type-checking time, we refuse to project any associated
     /// type that is marked `default`. Non-`default` ("final") types
@@ -91,36 +91,22 @@ pub enum ProjectionMode {
     /// fn main() {
     ///     let <() as Assoc>::Output = true;
     /// }
-    AnyFinal,
+    NotSpecializable,
 
-    /// At trans time, all projections will succeed.
-    Any,
-}
-
-impl ProjectionMode {
-    pub fn is_topmost(&self) -> bool {
-        match *self {
-            ProjectionMode::Topmost => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_any_final(&self) -> bool {
-        match *self {
-            ProjectionMode::AnyFinal => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_any(&self) -> bool {
-        match *self {
-            ProjectionMode::Any => true,
-            _ => false,
-        }
-    }
+    /// At trans time, all monomorphic projections will succeed.
+    /// Also, `impl Trait` is normalized to the concrete type,
+    /// which has to be already collected by type-checking.
+    ///
+    /// NOTE: As `impl Trait`'s concrete type should *never*
+    /// be observable directly by the user, `Reveal::All`
+    /// should not be used by checks which may expose
+    /// type equality or type contents to the user.
+    /// There are some exceptions, e.g. around OIBITS and
+    /// transmute-checking, which expose some details, but
+    /// not the whole concrete type of the `impl Trait`.
+    All,
 }
 
-
 pub type PolyProjectionObligation<'tcx> =
     Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
 
@@ -322,6 +308,17 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
 
         let ty = ty.super_fold_with(self);
         match ty.sty {
+            ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*)
+                // Only normalize `impl Trait` after type-checking, usually in trans.
+                if self.selcx.projection_mode() == Reveal::All {
+                    let generic_ty = self.tcx().lookup_item_type(def_id).ty;
+                    let concrete_ty = generic_ty.subst(self.tcx(), substs);
+                    self.fold_ty(concrete_ty)
+                } else {
+                    ty
+                }
+            }
+
             ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*)
 
                 // (*) This is kind of hacky -- we need to be able to
@@ -797,8 +794,11 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
     debug!("assemble_candidates_from_trait_def(..)");
 
     // Check whether the self-type is itself a projection.
-    let trait_ref = match obligation_trait_ref.self_ty().sty {
-        ty::TyProjection(ref data) => data.trait_ref.clone(),
+    let (def_id, substs) = match obligation_trait_ref.self_ty().sty {
+        ty::TyProjection(ref data) => {
+            (data.trait_ref.def_id, data.trait_ref.substs)
+        }
+        ty::TyAnon(def_id, substs) => (def_id, substs),
         ty::TyInfer(ty::TyVar(_)) => {
             // If the self-type is an inference variable, then it MAY wind up
             // being a projected type, so induce an ambiguity.
@@ -809,8 +809,8 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>(
     };
 
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let trait_predicates = selcx.tcx().lookup_predicates(trait_ref.def_id);
-    let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
+    let trait_predicates = selcx.tcx().lookup_predicates(def_id);
+    let bounds = trait_predicates.instantiate(selcx.tcx(), substs);
     let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec());
     assemble_candidates_from_predicates(selcx,
                                         obligation,
@@ -902,7 +902,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
 
                 candidate_set.vec.push(ProjectionTyCandidate::Select);
             }
-            super::VtableImpl(ref impl_data) if !selcx.projection_mode().is_any() => {
+            super::VtableImpl(ref impl_data) => {
                 // We have to be careful when projecting out of an
                 // impl because of specialization. If we are not in
                 // trans (i.e., projection mode is not "any"), and the
@@ -926,37 +926,43 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                                                  impl_data.impl_def_id,
                                                  obligation.predicate.item_name);
                 let new_candidate = if let Some(node_item) = opt_node_item {
-                    if node_item.node.is_from_trait() {
-                        if node_item.item.ty.is_some() {
-                            // The impl inherited a `type Foo =
-                            // Bar` given in the trait, which is
-                            // implicitly default. No candidate.
-                            None
-                        } else {
-                            // The impl did not specify `type` and neither
-                            // did the trait:
-                            //
-                            // ```rust
-                            // trait Foo { type T; }
-                            // impl Foo for Bar { }
-                            // ```
-                            //
-                            // This is an error, but it will be
-                            // reported in `check_impl_items_against_trait`.
-                            // We accept it here but will flag it as
-                            // an error when we confirm the candidate
-                            // (which will ultimately lead to `normalize_to_error`
-                            // being invoked).
+                    let is_default = if node_item.node.is_from_trait() {
+                        // If true, the impl inherited a `type Foo = Bar`
+                        // given in the trait, which is implicitly default.
+                        // Otherwise, the impl did not specify `type` and
+                        // neither did the trait:
+                        //
+                        // ```rust
+                        // trait Foo { type T; }
+                        // impl Foo for Bar { }
+                        // ```
+                        //
+                        // This is an error, but it will be
+                        // reported in `check_impl_items_against_trait`.
+                        // We accept it here but will flag it as
+                        // an error when we confirm the candidate
+                        // (which will ultimately lead to `normalize_to_error`
+                        // being invoked).
+                        node_item.item.ty.is_some()
+                    } else {
+                        node_item.item.defaultness.is_default()
+                    };
+
+                    // Only reveal a specializable default if we're past type-checking
+                    // and the obligations is monomorphic, otherwise passes such as
+                    // transmute checking and polymorphic MIR optimizations could
+                    // get a result which isn't correct for all monomorphizations.
+                    if !is_default {
+                        Some(ProjectionTyCandidate::Select)
+                    } else if selcx.projection_mode() == Reveal::All {
+                        assert!(!poly_trait_ref.needs_infer());
+                        if !poly_trait_ref.needs_subst() {
                             Some(ProjectionTyCandidate::Select)
+                        } else {
+                            None
                         }
-                    } else if node_item.item.defaultness.is_default() {
-                        // The impl specified `default type Foo =
-                        // Bar`. No candidate.
-                        None
                     } else {
-                        // The impl specified `type Foo = Bar`
-                        // with no default. Add a candidate.
-                        Some(ProjectionTyCandidate::Select)
+                        None
                     }
                 } else {
                     // This is saying that neither the trait nor
@@ -1006,11 +1012,6 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
                 };
                 candidate_set.vec.extend(new_candidate);
             }
-            super::VtableImpl(_) => {
-                // In trans mode, we can just project out of impls, no prob.
-                assert!(selcx.projection_mode().is_any());
-                candidate_set.vec.push(ProjectionTyCandidate::Select);
-            }
             super::VtableParam(..) => {
                 // This case tell us nothing about the value of an
                 // associated type. Consider:
@@ -1332,7 +1333,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
 /// starting from the given impl.
 ///
 /// Based on the "projection mode", this lookup may in fact only examine the
-/// topmost impl. See the comments for `ProjectionMode` for more details.
+/// topmost impl. See the comments for `Reveal` for more details.
 fn assoc_ty_def<'cx, 'gcx, 'tcx>(
     selcx: &SelectionContext<'cx, 'gcx, 'tcx>,
     impl_def_id: DefId,
@@ -1341,7 +1342,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>(
 {
     let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
 
-    if selcx.projection_mode().is_topmost() {
+    if selcx.projection_mode() == Reveal::ExactMatch {
         let impl_node = specialization_graph::Node::Impl(impl_def_id);
         for item in impl_node.items(selcx.tcx()) {
             if let ty::TypeTraitItem(assoc_ty) = item {