]> git.lizzy.rs Git - rust.git/commitdiff
refactor the handling of builtin candidates
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Sun, 17 Apr 2016 21:04:21 +0000 (00:04 +0300)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Tue, 3 May 2016 15:30:10 +0000 (18:30 +0300)
src/librustc/traits/select.rs
src/librustc/ty/fold.rs
src/librustc/ty/mod.rs
src/librustc/util/ppaux.rs

index 9267ea393ac9f6ab19b790e87d79f652d9a2905b..3a208aba6d83cfc0063f91521aeb53d7a93da1c1 100644 (file)
@@ -187,7 +187,7 @@ pub enum MethodMatchedData {
 /// parameter environment.
 #[derive(PartialEq,Eq,Debug,Clone)]
 enum SelectionCandidate<'tcx> {
-    BuiltinCandidate(ty::BuiltinBound),
+    BuiltinCandidate { has_nested: bool },
     ParamCandidate(ty::PolyTraitRef<'tcx>),
     ImplCandidate(DefId),
     DefaultImplCandidate(DefId),
@@ -240,7 +240,7 @@ enum BuiltinImplConditions<'tcx> {
     None,
     /// There is *no* impl for this, builtin or not. Ignore
     /// all where-clauses.
-    Never(SelectionError<'tcx>),
+    Never,
     /// It is unknown whether there is an impl.
     Ambiguous
 }
@@ -1000,15 +1000,14 @@ fn assemble_candidates<'o>(&mut self,
                 self.assemble_candidates_from_impls(obligation, &mut candidates)?;
 
                 // For other types, we'll use the builtin rules.
-                self.assemble_builtin_bound_candidates(ty::BoundCopy,
-                                                       obligation,
-                                                       &mut candidates)?;
+                let copy_conditions = self.copy_conditions(obligation);
+                self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
             }
-            Some(bound @ ty::BoundSized) => {
+            Some(ty::BoundSized) => {
                 // Sized is never implementable by end-users, it is
                 // always automatically computed.
-                self.assemble_builtin_bound_candidates(bound,
-                                                       obligation,
+                let sized_conditions = self.sized_conditions(obligation);
+                self.assemble_builtin_bound_candidates(sized_conditions,
                                                        &mut candidates)?;
             }
 
@@ -1577,7 +1576,7 @@ fn candidate_should_be_dropped_in_favor_of<'o>(
                 BuiltinObjectCandidate |
                 BuiltinUnsizeCandidate |
                 DefaultImplObjectCandidate(..) |
-                BuiltinCandidate(..) => {
+                BuiltinCandidate { .. } => {
                     // We have a where-clause so don't go around looking
                     // for impls.
                     true
@@ -1618,16 +1617,16 @@ fn candidate_should_be_dropped_in_favor_of<'o>(
     // HACK: if this returns an error, selection exits without considering
     // other impls.
     fn assemble_builtin_bound_candidates<'o>(&mut self,
-                                             bound: ty::BuiltinBound,
-                                             obligation: &TraitObligation<'tcx>,
+                                             conditions: BuiltinImplConditions<'tcx>,
                                              candidates: &mut SelectionCandidateSet<'tcx>)
                                              -> Result<(),SelectionError<'tcx>>
     {
-        match self.builtin_bound(bound, obligation) {
-            BuiltinImplConditions::Where(..) => {
-                debug!("builtin_bound: bound={:?}",
-                       bound);
-                candidates.vec.push(BuiltinCandidate(bound));
+        match conditions {
+            BuiltinImplConditions::Where(nested) => {
+                debug!("builtin_bound: nested={:?}", nested);
+                candidates.vec.push(BuiltinCandidate {
+                    has_nested: nested.skip_binder().len() > 0
+                });
                 Ok(())
             }
             BuiltinImplConditions::None => { Ok(()) }
@@ -1635,193 +1634,106 @@ fn assemble_builtin_bound_candidates<'o>(&mut self,
                 debug!("assemble_builtin_bound_candidates: ambiguous builtin");
                 Ok(candidates.ambiguous = true)
             }
-            BuiltinImplConditions::Never(e) => { Err(e) }
+            BuiltinImplConditions::Never => { Err(Unimplemented) }
         }
     }
 
-    fn builtin_bound(&mut self,
-                     bound: ty::BuiltinBound,
-                     obligation: &TraitObligation<'tcx>)
+    fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
                      -> BuiltinImplConditions<'tcx>
     {
-        // Note: these tests operate on types that may contain bound
-        // regions. To be proper, we ought to skolemize here, but we
-        // forego the skolemization and defer it until the
-        // confirmation step.
+        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
 
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(
+            obligation.predicate.skip_binder().self_ty());
 
-        let always = BuiltinImplConditions::Where(ty::Binder(Vec::new()));
-        let never = BuiltinImplConditions::Never(Unimplemented);
-
-        return match self_ty.sty {
-            ty::TyInfer(ty::IntVar(_)) |
-            ty::TyInfer(ty::FloatVar(_)) |
-            ty::TyUint(_) |
-            ty::TyInt(_) |
-            ty::TyBool |
-            ty::TyFloat(_) |
-            ty::TyFnDef(..) |
-            ty::TyFnPtr(_) |
-            ty::TyChar => {
+        match self_ty.sty {
+            ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
+            ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
+            ty::TyChar | ty::TyBox(_) | ty::TyRef(..) |
+            ty::TyArray(..) | ty::TyTuple(..) | ty::TyClosure(..) |
+            ty::TyError => {
                 // safe for everything
-                always
+                Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyBox(_) => {  // Box<T>
-                match bound {
-                    ty::BoundCopy => never,
-                    ty::BoundSized => always,
+            ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
 
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+                let sized_crit = def.sized_constraint(self.tcx());
+                // (*) binder moved here
+                Where(ty::Binder(match sized_crit.sty {
+                    ty::TyTuple(ref tys) => tys.to_owned().subst(self.tcx(), substs),
+                    ty::TyBool => vec![],
+                    _ => vec![sized_crit.subst(self.tcx(), substs)]
+                }))
             }
 
-            ty::TyRawPtr(..) => {     // *const T, *mut T
-                match bound {
-                    ty::BoundCopy | ty::BoundSized => always,
+            ty::TyProjection(_) | ty::TyParam(_) => None,
+            ty::TyInfer(ty::TyVar(_)) => Ambiguous,
 
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
-            }
-
-            ty::TyTrait(ref data) => {
-                match bound {
-                    ty::BoundSized => never,
-                    ty::BoundCopy => {
-                        // FIXME(#32963): bit-rot fungus infestation
-                        if data.bounds.builtin_bounds.contains(&bound) {
-                            always
-                        } else {
-                            // Recursively check all supertraits to find out if any further
-                            // bounds are required and thus we must fulfill.
-                            let principal =
-                                data.principal_trait_ref_with_self_ty(self.tcx(),
-                                                                      self.tcx().types.err);
-                            let copy_def_id = obligation.predicate.def_id();
-                            for tr in util::supertraits(self.tcx(), principal) {
-                                if tr.def_id() == copy_def_id {
-                                    return always
-                                }
-                            }
-
-                            never
-                        }
-                    }
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+            ty::TyInfer(ty::FreshTy(_))
+            | ty::TyInfer(ty::FreshIntTy(_))
+            | ty::TyInfer(ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}",
+                     self_ty);
             }
+        }
+    }
 
-            ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl }) => {
-                // &mut T or &T
-                match bound {
-                    ty::BoundCopy => {
-                        match mutbl {
-                            // &mut T is affine and hence never `Copy`
-                            hir::MutMutable => never,
-
-                            // &T is always copyable
-                            hir::MutImmutable => always
-                        }
-                    }
-
-                    ty::BoundSized => always,
+    fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
+                     -> BuiltinImplConditions<'tcx>
+    {
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(
+            obligation.predicate.skip_binder().self_ty());
 
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
-            }
+        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
 
-            ty::TyArray(element_ty, _) => {
-                // [T; n]
-                match bound {
-                    ty::BoundCopy => ok_if(vec![element_ty]),
-                    ty::BoundSized => always,
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+        match self_ty.sty {
+            ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
+            ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
+            ty::TyRawPtr(..) | ty::TyError |
+            ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
+                Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyStr | ty::TySlice(_) => {
-                match bound {
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-
-                    ty::BoundCopy | ty::BoundSized => never
-                }
+            ty::TyBox(_) | ty::TyTrait(..) | ty::TyStr | ty::TySlice(..) |
+            ty::TyClosure(..) |
+            ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
+                Never
             }
 
-            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-            ty::TyTuple(ref tys) => ok_if(tys.clone()),
-
-            ty::TyClosure(..) => {
-                match bound {
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-
-                    ty::BoundCopy => never,
-                    ty::BoundSized => always
-                }
+            ty::TyArray(element_ty, _) => {
+                // (*) binder moved here
+                Where(ty::Binder(vec![element_ty]))
             }
 
-            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
-                match bound {
-                    // Fallback to whatever user-defined impls exist in this case.
-                    ty::BoundCopy => BuiltinImplConditions::None,
-
-                    // Sized if all the component types are sized.
-                    ty::BoundSized => {
-                        let sized_crit = def.sized_constraint(self.tcx());
-                        if sized_crit == self.tcx().types.bool {
-                            always
-                        } else {
-                            ok_if(vec![sized_crit.subst(self.tcx(), substs)])
-                        }
-                    }
-
-                    // Shouldn't be coming through here.
-                    ty::BoundSend | ty::BoundSync => bug!(),
-                }
+            ty::TyTuple(ref tys) => {
+                // (*) binder moved here
+                Where(ty::Binder(tys.clone()))
             }
 
-            ty::TyProjection(_) | ty::TyParam(_) => {
-                // Note: A type parameter is only considered to meet a
-                // particular bound if there is a where clause telling
-                // us that it does, and that case is handled by
-                // `assemble_candidates_from_caller_bounds()`.
-                BuiltinImplConditions::None
+            ty::TyStruct(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) => {
+                // Fallback to whatever user-defined impls exist in this case.
+                None
             }
 
             ty::TyInfer(ty::TyVar(_)) => {
                 // Unbound type variable. Might or might not have
                 // applicable impls and so forth, depending on what
                 // those type variables wind up being bound to.
-                debug!("assemble_builtin_bound_candidates: ambiguous builtin");
-                BuiltinImplConditions::Ambiguous
+                Ambiguous
             }
 
-            ty::TyError => always,
-
             ty::TyInfer(ty::FreshTy(_))
             | ty::TyInfer(ty::FreshIntTy(_))
             | ty::TyInfer(ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble builtin bounds of unexpected type: {:?}",
                      self_ty);
             }
-        };
-
-        fn ok_if<'tcx>(v: Vec<Ty<'tcx>>) -> BuiltinImplConditions<'tcx> {
-            BuiltinImplConditions::Where(ty::Binder(v))
         }
     }
 
@@ -1988,9 +1900,9 @@ fn confirm_candidate(&mut self,
                candidate);
 
         match candidate {
-            BuiltinCandidate(builtin_bound) => {
+            BuiltinCandidate { has_nested } => {
                 Ok(VtableBuiltin(
-                    self.confirm_builtin_candidate(obligation, builtin_bound)))
+                    self.confirm_builtin_candidate(obligation, has_nested)))
             }
 
             ParamCandidate(param) => {
@@ -2090,45 +2002,36 @@ fn confirm_param_candidate(&mut self,
 
     fn confirm_builtin_candidate(&mut self,
                                  obligation: &TraitObligation<'tcx>,
-                                 bound: ty::BuiltinBound)
+                                 has_nested: bool)
                                  -> VtableBuiltinData<PredicateObligation<'tcx>>
     {
-        debug!("confirm_builtin_candidate({:?})",
-               obligation);
-
-        match self.builtin_bound(bound, obligation) {
-            BuiltinImplConditions::Where(nested) =>
-                self.vtable_builtin_data(obligation, bound, nested),
-            _ => {
-                span_bug!(
-                    obligation.cause.span,
-                    "confiriming builtin impl for {:?} where none exists",
-                    obligation);
-            }
-        }
-    }
-
-    fn vtable_builtin_data(&mut self,
-                           obligation: &TraitObligation<'tcx>,
-                           bound: ty::BuiltinBound,
-                           nested: ty::Binder<Vec<Ty<'tcx>>>)
-                           -> VtableBuiltinData<PredicateObligation<'tcx>>
-    {
-        debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})",
-               obligation, bound, nested);
+        debug!("confirm_builtin_candidate({:?}, {:?})",
+               obligation, has_nested);
+
+        let obligations = if has_nested {
+            let trait_def = obligation.predicate.def_id();
+            let conditions = match trait_def {
+                _ if Some(trait_def) == self.tcx().lang_items.sized_trait() => {
+                    self.sized_conditions(obligation)
+                }
+                _ if Some(trait_def) == self.tcx().lang_items.copy_trait() => {
+                    self.copy_conditions(obligation)
+                }
+                _ => bug!("unexpected builtin trait {:?}", trait_def)
+            };
+            let nested = match conditions {
+                BuiltinImplConditions::Where(nested) => nested,
+                _ => bug!("obligation {:?} had matched a builtin impl but now doesn't",
+                          obligation)
+            };
 
-        let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) {
-            Ok(def_id) => def_id,
-            Err(_) => {
-                bug!("builtin trait definition not found");
-            }
+            self.collect_predicates_for_types(obligation, trait_def, nested)
+        } else {
+            vec![]
         };
 
-        let obligations = self.collect_predicates_for_types(obligation, trait_def, nested);
-
-        debug!("vtable_builtin_data: obligations={:?}",
+        debug!("confirm_builtin_candidate: obligations={:?}",
                obligations);
-
         VtableBuiltinData { nested: obligations }
     }
 
index 54223e16e17c5e0355605e81d1581bfb888f8002..8fcbc0629523d9efa62a8b63415704d4e2b9a924 100644 (file)
@@ -329,7 +329,6 @@ pub fn replace_late_bound_regions<T,F>(&self,
         where F : FnMut(ty::BoundRegion) -> ty::Region,
               T : TypeFoldable<'tcx>,
     {
-        debug!("replace_late_bound_regions({:?})", value);
         let mut replacer = RegionReplacer::new(self, &mut f);
         let result = value.skip_binder().fold_with(&mut replacer);
         (result, replacer.map)
@@ -444,8 +443,6 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
-                debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})",
-                       r, self.current_depth);
                 let fld_r = &mut self.fld_r;
                 let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
                 if let ty::ReLateBound(debruijn1, br) = region {
index d2b7354abb9b8a5f2e22ce1eacb106a5c8139c67..179c83873762d659081d0bda5406cea0d486f0b6 100644 (file)
@@ -1722,6 +1722,10 @@ pub fn dtor_kind(&self) -> DtorKind {
     /// Returns a simpler type such that `Self: Sized` if and only
     /// if that type is Sized, or `TyErr` if this type is recursive.
     ///
+    /// HACK: instead of returning a list of types, this function can
+    /// return a tuple. In that case, the result is Sized only if
+    /// all elements of the tuple are Sized.
+    ///
     /// This is generally the `struct_tail` if this is a struct, or a
     /// tuple of them if this is an enum.
     ///
@@ -1738,7 +1742,7 @@ pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> {
             None => {
                 let this = tcx.lookup_adt_def_master(self.did);
                 this.calculate_sized_constraint_inner(tcx, &mut Vec::new());
-                self.sized_constraint.unwrap(dep_node)
+                self.sized_constraint(tcx)
             }
             Some(ty) => ty
         }
@@ -1756,6 +1760,10 @@ fn sized_constraint_for_tys<TYS>(
     {
         let tys : Vec<_> = tys.into_iter()
             .map(|ty| self.sized_constraint_for_ty(tcx, stack, ty))
+            .flat_map(|ty| match ty.sty {
+                ty::TyTuple(ref tys) => tys.clone(),
+                _ => vec![ty]
+            })
             .filter(|ty| *ty != tcx.types.bool)
             .collect();
 
@@ -1766,6 +1774,7 @@ fn sized_constraint_for_tys<TYS>(
             _ => tcx.mk_tup(tys)
         }
     }
+
     fn sized_constraint_for_ty(
         &'tcx self,
         tcx: &ty::TyCtxt<'tcx>,
index 9b590ec8aa6d6b86defa79ba0d1195ea82633429..6682a0e2b4f4fa6b813bb278e22dfb4c808a626e 100644 (file)
@@ -493,7 +493,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             BrAnon(n) => write!(f, "BrAnon({:?})", n),
             BrFresh(n) => write!(f, "BrFresh({:?})", n),
             BrNamed(did, name) => {
-                write!(f, "BrNamed({:?}, {:?})", did, name)
+                write!(f, "BrNamed({:?}:{:?}, {:?})", did.krate, did.index, name)
             }
             BrEnv => "BrEnv".fmt(f),
         }