From 73f39a026a5a4e7ac37eb4f4840a9cf25ac5d0a5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 14 Apr 2016 15:49:39 +0300 Subject: [PATCH 01/12] Short-cut Sized matching on ADTs Put a constraint type on every ADT def, such that the ADT def is sized iff the constraint type is, and use that in selection. This ignores types that are obviously sized. This improves typeck performance by ~15%. --- src/librustc/dep_graph/dep_node.rs | 2 + src/librustc/traits/select.rs | 155 ++++++++++++++--------------- src/librustc/ty/mod.rs | 151 +++++++++++++++++++++++++++- 3 files changed, 225 insertions(+), 83 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 536c739bf16..85b4b4f59c4 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -88,6 +88,7 @@ pub enum DepNode { ImplOrTraitItems(D), ItemSignature(D), FieldTy(D), + SizedConstraint(D), TraitItemDefIds(D), InherentImpls(D), ImplItems(D), @@ -193,6 +194,7 @@ impl DepNode { ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems), ItemSignature(ref d) => op(d).map(ItemSignature), FieldTy(ref d) => op(d).map(FieldTy), + SizedConstraint(ref d) => op(d).map(SizedConstraint), TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), ImplItems(ref d) => op(d).map(ImplItems), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index d7528fc3130..9267ea393ac 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -13,7 +13,6 @@ pub use self::MethodMatchResult::*; pub use self::MethodMatchedData::*; use self::SelectionCandidate::*; -use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; use super::coherence; @@ -232,10 +231,18 @@ struct EvaluatedCandidate<'tcx> { evaluation: EvaluationResult, } -enum BuiltinBoundConditions<'tcx> { - If(ty::Binder>>), - ParameterBuiltin, - AmbiguousBuiltin +/// When does the builtin impl for `T: Trait` apply? +enum BuiltinImplConditions<'tcx> { + /// The impl is conditional on T1,T2,.. : Trait + Where(ty::Binder>>), + /// There is no built-in impl. There may be some other + /// candidate (a where-clause or user-defined impl). + None, + /// There is *no* impl for this, builtin or not. Ignore + /// all where-clauses. + Never(SelectionError<'tcx>), + /// It is unknown whether there is an impl. + Ambiguous } #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] @@ -1608,6 +1615,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // those will hopefully change to library-defined traits in the // future. + // 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>, @@ -1615,25 +1624,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { -> Result<(),SelectionError<'tcx>> { match self.builtin_bound(bound, obligation) { - Ok(If(..)) => { + BuiltinImplConditions::Where(..) => { debug!("builtin_bound: bound={:?}", bound); candidates.vec.push(BuiltinCandidate(bound)); Ok(()) } - Ok(ParameterBuiltin) => { Ok(()) } - Ok(AmbiguousBuiltin) => { + BuiltinImplConditions::None => { Ok(()) } + BuiltinImplConditions::Ambiguous => { debug!("assemble_builtin_bound_candidates: ambiguous builtin"); Ok(candidates.ambiguous = true) } - Err(e) => { Err(e) } + BuiltinImplConditions::Never(e) => { Err(e) } } } fn builtin_bound(&mut self, bound: ty::BuiltinBound, obligation: &TraitObligation<'tcx>) - -> Result,SelectionError<'tcx>> + -> BuiltinImplConditions<'tcx> { // Note: these tests operate on types that may contain bound // regions. To be proper, we ought to skolemize here, but we @@ -1641,6 +1650,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // confirmation step. let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.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(_)) | @@ -1652,14 +1665,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyFnPtr(_) | ty::TyChar => { // safe for everything - ok_if(Vec::new()) + always } ty::TyBox(_) => { // Box match bound { - ty::BoundCopy => Err(Unimplemented), - - ty::BoundSized => ok_if(Vec::new()), + ty::BoundCopy => never, + ty::BoundSized => always, ty::BoundSync | ty::BoundSend => { bug!("Send/Sync shouldn't occur in builtin_bounds()"); @@ -1669,7 +1681,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyRawPtr(..) => { // *const T, *mut T match bound { - ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()), + ty::BoundCopy | ty::BoundSized => always, ty::BoundSync | ty::BoundSend => { bug!("Send/Sync shouldn't occur in builtin_bounds()"); @@ -1679,10 +1691,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyTrait(ref data) => { match bound { - ty::BoundSized => Err(Unimplemented), + ty::BoundSized => never, ty::BoundCopy => { + // FIXME(#32963): bit-rot fungus infestation if data.bounds.builtin_bounds.contains(&bound) { - ok_if(Vec::new()) + always } else { // Recursively check all supertraits to find out if any further // bounds are required and thus we must fulfill. @@ -1692,11 +1705,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let copy_def_id = obligation.predicate.def_id(); for tr in util::supertraits(self.tcx(), principal) { if tr.def_id() == copy_def_id { - return ok_if(Vec::new()) + return always } } - Err(Unimplemented) + never } } ty::BoundSync | ty::BoundSend => { @@ -1711,14 +1724,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::BoundCopy => { match mutbl { // &mut T is affine and hence never `Copy` - hir::MutMutable => Err(Unimplemented), + hir::MutMutable => never, // &T is always copyable - hir::MutImmutable => ok_if(Vec::new()), + hir::MutImmutable => always } } - ty::BoundSized => ok_if(Vec::new()), + ty::BoundSized => always, ty::BoundSync | ty::BoundSend => { bug!("Send/Sync shouldn't occur in builtin_bounds()"); @@ -1730,7 +1743,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // [T; n] match bound { ty::BoundCopy => ok_if(vec![element_ty]), - ty::BoundSized => ok_if(Vec::new()), + ty::BoundSized => always, ty::BoundSync | ty::BoundSend => { bug!("Send/Sync shouldn't occur in builtin_bounds()"); } @@ -1743,46 +1756,42 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("Send/Sync shouldn't occur in builtin_bounds()"); } - ty::BoundCopy | ty::BoundSized => Err(Unimplemented), + ty::BoundCopy | ty::BoundSized => never } } // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet ty::TyTuple(ref tys) => ok_if(tys.clone()), - ty::TyClosure(_, ref substs) => { - // FIXME -- This case is tricky. In the case of by-ref - // closures particularly, we need the results of - // inference to decide how to reflect the type of each - // upvar (the upvar may have type `T`, but the runtime - // type could be `&mut`, `&`, or just `T`). For now, - // though, we'll do this unsoundly and assume that all - // captures are by value. Really what we ought to do - // is reserve judgement and then intertwine this - // analysis with closure inference. + ty::TyClosure(..) => { + match bound { + ty::BoundSync | ty::BoundSend => { + bug!("Send/Sync shouldn't occur in builtin_bounds()"); + } - // Unboxed closures shouldn't be - // implicitly copyable - if bound == ty::BoundCopy { - return Ok(ParameterBuiltin); + ty::BoundCopy => never, + ty::BoundSized => always } - - // Upvars are always local variables or references to - // local variables, and local variables cannot be - // unsized, so the closure struct as a whole must be - // Sized. - if bound == ty::BoundSized { - return ok_if(Vec::new()); - } - - ok_if(substs.upvar_tys.clone()) } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { - let types: Vec = def.all_fields().map(|f| { - f.ty(self.tcx(), substs) - }).collect(); - nominal(bound, types) + 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::TyProjection(_) | ty::TyParam(_) => { @@ -1790,7 +1799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // particular bound if there is a where clause telling // us that it does, and that case is handled by // `assemble_candidates_from_caller_bounds()`. - Ok(ParameterBuiltin) + BuiltinImplConditions::None } ty::TyInfer(ty::TyVar(_)) => { @@ -1798,10 +1807,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // applicable impls and so forth, depending on what // those type variables wind up being bound to. debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - Ok(AmbiguousBuiltin) + BuiltinImplConditions::Ambiguous } - ty::TyError => ok_if(Vec::new()), + ty::TyError => always, ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) @@ -1811,26 +1820,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; - fn ok_if<'tcx>(v: Vec>) - -> Result, SelectionError<'tcx>> { - Ok(If(ty::Binder(v))) - } - - fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound, - types: Vec>) - -> Result, SelectionError<'tcx>> - { - // First check for markers and other nonsense. - match bound { - // Fallback to whatever user-defined impls exist in this case. - ty::BoundCopy => Ok(ParameterBuiltin), - - // Sized if all the component types are sized. - ty::BoundSized => ok_if(types), - - // Shouldn't be coming through here. - ty::BoundSend | ty::BoundSync => bug!(), - } + fn ok_if<'tcx>(v: Vec>) -> BuiltinImplConditions<'tcx> { + BuiltinImplConditions::Where(ty::Binder(v)) } } @@ -1999,7 +1990,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match candidate { BuiltinCandidate(builtin_bound) => { Ok(VtableBuiltin( - self.confirm_builtin_candidate(obligation, builtin_bound)?)) + self.confirm_builtin_candidate(obligation, builtin_bound))) } ParamCandidate(param) => { @@ -2100,18 +2091,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_builtin_candidate(&mut self, obligation: &TraitObligation<'tcx>, bound: ty::BuiltinBound) - -> Result>, - SelectionError<'tcx>> + -> VtableBuiltinData> { debug!("confirm_builtin_candidate({:?})", obligation); - match self.builtin_bound(bound, obligation)? { - If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)), - AmbiguousBuiltin | ParameterBuiltin => { + match self.builtin_bound(bound, obligation) { + BuiltinImplConditions::Where(nested) => + self.vtable_builtin_data(obligation, bound, nested), + _ => { span_bug!( obligation.cause.span, - "builtin bound for {:?} was ambig", + "confiriming builtin impl for {:?} where none exists", obligation); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index bc342b235dd..b3ca120bd9f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1498,6 +1498,7 @@ pub struct AdtDefData<'tcx, 'container: 'tcx> { pub variants: Vec>, destructor: Cell>, flags: Cell, + sized_constraint: ivar::TyIVar<'tcx, 'container>, } impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> { @@ -1575,7 +1576,8 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { did: did, variants: variants, flags: Cell::new(flags), - destructor: Cell::new(None) + destructor: Cell::new(None), + sized_constraint: ivar::TyIVar::new(), } } @@ -1716,6 +1718,153 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { None => NoDtor, } } + + /// Returns a simpler type such that `Self: Sized` if and only + /// if that type is Sized, or `TyErr` if this type is recursive. + pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> { + let dep_node = DepNode::SizedConstraint(self.did); + match self.sized_constraint.get(dep_node) { + 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) + } + Some(ty) => ty + } + } +} + +impl<'tcx> AdtDefData<'tcx, 'tcx> { + fn sized_constraint_for_tys( + &'tcx self, + tcx: &ty::TyCtxt<'tcx>, + stack: &mut Vec>, + tys: TYS + ) -> Ty<'tcx> + where TYS: IntoIterator> + { + let tys : Vec<_> = tys.into_iter() + .map(|ty| self.sized_constraint_for_ty(tcx, stack, ty)) + .filter(|ty| *ty != tcx.types.bool) + .collect(); + + match tys.len() { + 0 => tcx.types.bool, + 1 => tys[0], + _ => tcx.mk_tup(tys) + } + } + fn sized_constraint_for_ty( + &'tcx self, + tcx: &ty::TyCtxt<'tcx>, + stack: &mut Vec>, + ty: Ty<'tcx> + ) -> Ty<'tcx> { + let result = match ty.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyArray(..) | TyClosure(..) => { + // these are always sized - return a primitive + tcx.types.bool + } + + TyStr | TyTrait(..) | TySlice(_) => { + // these are never sized - return the target type + ty + } + + TyTuple(ref tys) => { + self.sized_constraint_for_tys(tcx, stack, tys.iter().cloned()) + } + + TyEnum(adt, substs) | TyStruct(adt, substs) => { + // recursive case + let adt = tcx.lookup_adt_def_master(adt.did); + adt.calculate_sized_constraint_inner(tcx, stack); + let adt_ty = + adt.sized_constraint + .unwrap(DepNode::SizedConstraint(adt.did)) + .subst(tcx, substs); + debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", + ty, adt_ty); + self.sized_constraint_for_ty(tcx, stack, adt_ty) + } + + TyProjection(..) => { + // must calculate explicitly. + // FIXME: consider special-casing always-Sized projections + ty + } + + TyParam(..) => { + let sized_trait = match tcx.lang_items.sized_trait() { + Some(x) => x, + _ => return ty + }; + let sized_predicate = Binder(TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs(Substs::new_trait( + vec![], vec![], ty + )) + }).to_predicate(); + let predicates = tcx.lookup_predicates(self.did).predicates; + if predicates.into_iter().any(|p| p == sized_predicate) { + tcx.types.bool + } else { + ty + } + } + + TyInfer(..) | TyError => { + bug!("unexpected type `{:?}` in sized_constraint_for_ty", + ty) + } + }; + debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); + result + } + + /// Calculates the Sized-constraint. This replaces all always-Sized + /// types with bool. I could have made the TyIVar an Option, but that + /// would have been so much code. + fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>, + stack: &mut Vec>) + { + + let dep_node = DepNode::SizedConstraint(self.did); + + if self.sized_constraint.get(dep_node).is_some() { + return; + } + + if stack.contains(&self) { + debug!("calculate_sized_constraint: {:?} is recursive", self); + self.sized_constraint.fulfill(dep_node, tcx.types.err); + return; + } + + stack.push(self); + let ty = self.sized_constraint_for_tys( + tcx, stack, + self.variants.iter().flat_map(|v| { + v.fields.last() + }).map(|f| f.unsubst_ty()) + ); + + let self_ = stack.pop().unwrap(); + assert_eq!(self_, self); + + match self.sized_constraint.get(dep_node) { + Some(old_ty) => { + debug!("calculate_sized_constraint: {:?} recurred", self); + assert_eq!(old_ty, tcx.types.err) + } + None => { + debug!("calculate_sized_constraint: {:?} => {:?}", self, ty); + self.sized_constraint.fulfill(dep_node, ty) + } + } + } } impl<'tcx, 'container> VariantDefData<'tcx, 'container> { From 4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 16 Apr 2016 15:16:36 +0300 Subject: [PATCH 02/12] add comments and tests --- src/librustc/ty/mod.rs | 38 ++++++++++++++++++++--- src/test/compile-fail/issue-17431-2.rs | 1 + src/test/compile-fail/issue-26548.rs | 3 +- src/test/compile-fail/range-1.rs | 1 - src/test/compile-fail/sized-cycle-note.rs | 7 +---- src/test/run-pass/issue-31299.rs | 36 +++++++++++++++++++++ 6 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 src/test/run-pass/issue-31299.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b3ca120bd9f..d2b7354abb9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1721,6 +1721,17 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { /// Returns a simpler type such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. + /// + /// This is generally the `struct_tail` if this is a struct, or a + /// tuple of them if this is an enum. + /// + /// Oddly enough, checking that the sized-constraint is Sized is + /// actually more expressive than checking all members: + /// the Sized trait is inductive, so an associated type that references + /// Self would prevent its containing ADT from being Sized. + /// + /// Due to normalization being eager, this applies even if + /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> { let dep_node = DepNode::SizedConstraint(self.did); match self.sized_constraint.get(dep_node) { @@ -1749,6 +1760,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { .collect(); match tys.len() { + _ if tys.references_error() => tcx.types.err, 0 => tcx.types.bool, 1 => tys[0], _ => tcx.mk_tup(tys) @@ -1768,7 +1780,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { tcx.types.bool } - TyStr | TyTrait(..) | TySlice(_) => { + TyStr | TyTrait(..) | TySlice(_) | TyError => { // these are never sized - return the target type ty } @@ -1797,6 +1809,10 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { } TyParam(..) => { + // perf hack: if there is a `T: Sized` bound, then + // we know that `T` is Sized and do not need to check + // it on the impl. + let sized_trait = match tcx.lang_items.sized_trait() { Some(x) => x, _ => return ty @@ -1815,7 +1831,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { } } - TyInfer(..) | TyError => { + TyInfer(..) => { bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) } @@ -1824,9 +1840,21 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { result } - /// Calculates the Sized-constraint. This replaces all always-Sized - /// types with bool. I could have made the TyIVar an Option, but that - /// would have been so much code. + /// Calculates the Sized-constraint. + /// + /// As the Sized-constraint of enums can be a *set* of types, + /// the Sized-constraint may need to be a set also. Because introducing + /// a new type of IVar is currently a complex affair, the Sized-constraint + /// may be a tuple. + /// + /// In fact, there are only a few options for the constraint: + /// - `bool`, if the type is always Sized + /// - an obviously-unsized type + /// - a type parameter or projection whose Sizedness can't be known + /// - a tuple of type parameters or projections, if there are multiple + /// such. + /// - a TyError, if a type contained itself. The representability + /// check should catch this case. fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>, stack: &mut Vec>) { diff --git a/src/test/compile-fail/issue-17431-2.rs b/src/test/compile-fail/issue-17431-2.rs index edbc8c82432..f39fb0e31c6 100644 --- a/src/test/compile-fail/issue-17431-2.rs +++ b/src/test/compile-fail/issue-17431-2.rs @@ -9,6 +9,7 @@ // except according to those terms. struct Baz { q: Option } +//~^ ERROR recursive type `Baz` has infinite size struct Foo { q: Option } //~^ ERROR recursive type `Foo` has infinite size diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index 28080ae09e5..2919b0b3cac 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern: overflow representing the type `S` + trait Mirror { type It: ?Sized; } impl Mirror for T { type It = Self; } struct S(Option<::It>); -//~^ ERROR recursive type `S` has infinite size fn main() { let _s = S(None); diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 895d2450cfe..2a0773af73b 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,5 +23,4 @@ pub fn main() { let arr: &[_] = &[1, 2, 3]; let range = *arr..; //~^ ERROR `[_]: std::marker::Sized` is not satisfied - //~| ERROR `[_]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs index 3d7c4868e96..712b4ac22f0 100644 --- a/src/test/compile-fail/sized-cycle-note.rs +++ b/src/test/compile-fail/sized-cycle-note.rs @@ -17,14 +17,9 @@ // 2. it should elaborate the steps that led to the cycle. struct Baz { q: Option } - +//~^ ERROR recursive type `Baz` has infinite size struct Foo { q: Option } //~^ ERROR recursive type `Foo` has infinite size -//~| NOTE type `Foo` is embedded within `std::option::Option`... -//~| NOTE ...which in turn is embedded within `std::option::Option`... -//~| NOTE ...which in turn is embedded within `Baz`... -//~| NOTE ...which in turn is embedded within `std::option::Option`... -//~| NOTE ...which in turn is embedded within `Foo`, completing the cycle. impl Foo { fn bar(&self) {} } diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs new file mode 100644 index 00000000000..e49e13c458f --- /dev/null +++ b/src/test/run-pass/issue-31299.rs @@ -0,0 +1,36 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #31299. This was generating an overflow error +// because of eager normalization: +// +// proving `M: Sized` requires +// - proving `PtrBack>: Sized` requis +// - normalizing `Vec< as Front>::Back>>: Sized` requires +// - proving `Vec: Front` requires +// - `M: Sized` <-- cycle! +// +// If we skip the normalization step, though, everything goes fine. + +trait Front { + type Back; +} + +impl Front for Vec { + type Back = Vec; +} + +struct PtrBack(Vec); + +struct M(PtrBack>); + +fn main() { + std::mem::size_of::(); +} From babb5df529ceef1cc8c12143d6dd4ab21188cc3e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 18 Apr 2016 00:04:21 +0300 Subject: [PATCH 03/12] refactor the handling of builtin candidates --- src/librustc/traits/select.rs | 333 ++++++++++++---------------------- src/librustc/ty/fold.rs | 3 - src/librustc/ty/mod.rs | 11 +- src/librustc/util/ppaux.rs | 2 +- 4 files changed, 129 insertions(+), 220 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9267ea393ac..3a208aba6d8 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinObjectCandidate | BuiltinUnsizeCandidate | DefaultImplObjectCandidate(..) | - BuiltinCandidate(..) => { + BuiltinCandidate { .. } => { // We have a where-clause so don't go around looking // for impls. true @@ -1618,16 +1617,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 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,182 +1634,44 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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 - match bound { - ty::BoundCopy => never, - ty::BoundSized => always, - - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - ty::TyRawPtr(..) => { // *const T, *mut T - match bound { - ty::BoundCopy | ty::BoundSized => always, - - 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::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, - - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - } - } - - 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()"); - } - } - } - - ty::TyStr | ty::TySlice(_) => { - match bound { - ty::BoundSync | ty::BoundSend => { - bug!("Send/Sync shouldn't occur in builtin_bounds()"); - } - - ty::BoundCopy | ty::BoundSized => 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::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, 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!(), - } + 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::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::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 - } - - ty::TyError => always, + ty::TyProjection(_) | ty::TyParam(_) => None, + ty::TyInfer(ty::TyVar(_)) => Ambiguous, ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) @@ -1818,10 +1679,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } - }; + } + } - fn ok_if<'tcx>(v: Vec>) -> BuiltinImplConditions<'tcx> { - BuiltinImplConditions::Where(ty::Binder(v)) + 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()); + + use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; + + 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::TyBox(_) | ty::TyTrait(..) | ty::TyStr | ty::TySlice(..) | + ty::TyClosure(..) | + ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { + Never + } + + ty::TyArray(element_ty, _) => { + // (*) binder moved here + Where(ty::Binder(vec![element_ty])) + } + + ty::TyTuple(ref tys) => { + // (*) binder moved here + Where(ty::Binder(tys.clone())) + } + + 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. + Ambiguous + } + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("asked to assemble builtin bounds of unexpected type: {:?}", + self_ty); + } } } @@ -1988,9 +1900,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_builtin_candidate(&mut self, obligation: &TraitObligation<'tcx>, - bound: ty::BuiltinBound) + has_nested: bool) -> VtableBuiltinData> { - debug!("confirm_builtin_candidate({:?})", - obligation); + debug!("confirm_builtin_candidate({:?}, {:?})", + obligation, has_nested); - 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); - } - } - } + 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) + }; - fn vtable_builtin_data(&mut self, - obligation: &TraitObligation<'tcx>, - bound: ty::BuiltinBound, - nested: ty::Binder>>) - -> VtableBuiltinData> - { - debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})", - obligation, bound, nested); - - 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 } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 54223e16e17..8fcbc062952 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -329,7 +329,6 @@ impl<'tcx> TyCtxt<'tcx> { 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 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, '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 { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d2b7354abb9..179c8387376 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1722,6 +1722,10 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { /// 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 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { 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 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { { 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 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { _ => tcx.mk_tup(tys) } } + fn sized_constraint_for_ty( &'tcx self, tcx: &ty::TyCtxt<'tcx>, diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9b590ec8aa6..6682a0e2b4f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -493,7 +493,7 @@ impl fmt::Debug for ty::BoundRegion { 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), } From 0a6dfc51777eb388b6e795399bf1d3f8aac57db8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Apr 2016 01:46:23 +0300 Subject: [PATCH 04/12] require the non-last elements of a tuple to be Sized This requirement appears to be missing from RFC1214, but is clearly necessary for translation. The last field of a tuple/enum remains in a state of limbo, compiling but causing an ICE when it is used - we should eventually fix that somehow. this is a [breaking-change] - a soundness fix - and requires a crater run. --- src/libcore/num/bignum.rs | 2 +- src/librustc/traits/error_reporting.rs | 5 ++++ src/librustc/traits/mod.rs | 5 +++- src/librustc/traits/select.rs | 9 ++++++- src/librustc/ty/mod.rs | 4 +-- src/librustc/ty/wf.rs | 35 +++++++++++++++++--------- src/test/compile-fail/unsized3.rs | 1 + src/test/compile-fail/unsized6.rs | 4 +-- 8 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 66c6deb3615..a881b539ced 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -33,7 +33,7 @@ use mem; use intrinsics; /// Arithmetic operations required by bignums. -pub trait FullOps { +pub trait FullOps: Sized { /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`, /// where `W` is the number of bits in `Self`. fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 531a4fbf8be..d02dfcd9ea7 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -764,6 +764,11 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } + ObligationCauseCode::TupleElem => { + err.fileline_note( + cause_span, + "tuple elements must have `Sized` type"); + } ObligationCauseCode::ProjectionWf(data) => { err.note(&format!("required so that the projection `{}` is well-formed", data)); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a160465e2e8..5921cdeab78 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -106,9 +106,12 @@ pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, - /// This is the trait reference from the given projection + /// A slice or array is WF only if `T: Sized` SliceOrArrayElem, + /// A tuple is WF only if its middle elements are Sized + TupleElem, + /// This is the trait reference from the given projection ProjectionWf(ty::ProjectionTy<'tcx>), diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3a208aba6d8..08a996c142d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1652,7 +1652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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::TyArray(..) | ty::TyClosure(..) | ty::TyError => { // safe for everything Where(ty::Binder(Vec::new())) @@ -1660,6 +1660,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, + ty::TyTuple(ref tys) => { + Where(ty::Binder(match tys.last() { + Some(ty) => vec![ty], + _ => vec![] + })) + } + ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 179c8387376..b4156fde6a3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1761,8 +1761,8 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { 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] + ty::TyTuple(ref tys) => tys.last().cloned(), + _ => Some(ty) }) .filter(|ty| *ty != tcx.types.bool) .collect(); diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index f93332e0773..2dda63802e0 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -280,6 +280,22 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { } } + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { + if !subty.has_escaping_regions() { + let cause = self.cause(cause); + match traits::trait_ref_for_builtin_bound(self.infcx.tcx, + ty::BoundSized, + subty) { + Ok(trait_ref) => { + self.out.push( + traits::Obligation::new(cause, + trait_ref.to_predicate())); + } + Err(ErrorReported) => { } + } + } + } + /// Push new obligations into `out`. Returns true if it was able /// to generate all the predicates needed to validate that `ty0` /// is WF. Returns false if `ty0` is an unresolved type variable, @@ -301,23 +317,18 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { ty::TySlice(subty) | ty::TyArray(subty, _) => { - if !subty.has_escaping_regions() { - let cause = self.cause(traits::SliceOrArrayElem); - match traits::trait_ref_for_builtin_bound(self.infcx.tcx, - ty::BoundSized, - subty) { - Ok(trait_ref) => { - self.out.push( - traits::Obligation::new(cause, - trait_ref.to_predicate())); - } - Err(ErrorReported) => { } + self.require_sized(subty, traits::SliceOrArrayElem); + } + + ty::TyTuple(ref tys) => { + if let Some((_last, rest)) = tys.split_last() { + for elem in rest { + self.require_sized(elem, traits::TupleElem); } } } ty::TyBox(_) | - ty::TyTuple(_) | ty::TyRawPtr(_) => { // simple cases that are WF if their type args are WF } diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index f88165c02e9..1d93645fc84 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -60,6 +60,7 @@ fn f8(x1: &S, x2: &S) { fn f9(x1: Box>, x2: Box>) { f5(&(*x1, 34)); //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^^ ERROR `X: std::marker::Sized` is not satisfied } fn f10(x1: Box>, x2: Box>) { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 663cb0a1716..e18ccfee96c 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,9 +14,9 @@ trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); // same + let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied + let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied } fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied From 2f8f256cef42350af2f0376891fd020b6b1c37de Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Apr 2016 02:31:04 +0300 Subject: [PATCH 05/12] require the existential bounds of an object type to be object-safe This is required, as Copy and Sized are object-unsafe. As a soundness fix, this is a [breaking-change] Fixes #32963 --- src/librustc/traits/select.rs | 12 +++++++++--- src/librustc/ty/wf.rs | 19 +++++++++++++++---- src/test/compile-fail/bad-sized.rs | 1 + src/test/compile-fail/issue-32963.rs | 21 +++++++++++++++++++++ src/test/compile-fail/kindck-copy.rs | 8 ++++---- 5 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/issue-32963.rs diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 08a996c142d..738ed85ae6d 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2408,9 +2408,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { - let object_did = data.principal_def_id(); - if !object_safety::is_object_safe(tcx, object_did) { - return Err(TraitNotObjectSafe(object_did)); + let mut object_dids = + data.bounds.builtin_bounds.iter().flat_map(|bound| { + tcx.lang_items.from_builtin_kind(bound).ok() + }) + .chain(Some(data.principal_def_id())); + if let Some(did) = object_dids.find(|did| { + !object_safety::is_object_safe(tcx, *did) + }) { + return Err(TraitNotObjectSafe(did)) } let cause = ObligationCause::new(obligation.cause.span, diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 2dda63802e0..316a81e8f62 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -301,6 +301,7 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. fn compute(&mut self, ty0: Ty<'tcx>) -> bool { + let tcx = self.infcx.tcx; let mut subtys = ty0.walk(); while let Some(ty) = subtys.next() { match ty.sty { @@ -385,10 +386,20 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { // checking those let cause = self.cause(traits::MiscObligation); - self.out.push( - traits::Obligation::new( - cause, - ty::Predicate::ObjectSafe(data.principal_def_id()))); + + let component_traits = + data.bounds.builtin_bounds.iter().flat_map(|bound| { + tcx.lang_items.from_builtin_kind(bound).ok() + }) + .chain(Some(data.principal_def_id())); + self.out.extend( + component_traits.map(|did| { + traits::Obligation::new( + cause.clone(), + ty::Predicate::ObjectSafe(did) + ) + }) + ); } // Inference variables are the complicated case, since we don't diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index f62404e60e6..ba0a6f19f07 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -15,4 +15,5 @@ pub fn main() { //~^ ERROR `Trait + Sized: std::marker::Sized` is not satisfied //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied + //~| ERROR `std::marker::Sized` cannot be made into an object } diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs new file mode 100644 index 00000000000..d0434384cd0 --- /dev/null +++ b/src/test/compile-fail/issue-32963.rs @@ -0,0 +1,21 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +trait Misc {} + +fn size_of_copy() -> usize { mem::size_of::() } + +fn main() { + size_of_copy::(); + //~^ ERROR `std::marker::Copy` cannot be made into an object + //~| ERROR `Misc + Copy: std::marker::Copy` is not satisfied +} diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index 08b4e1a45f3..747fe2d2046 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -45,15 +45,15 @@ fn test<'a,T,U:Copy>(_: &'a isize) { // borrowed object types are generally ok assert_copy::<&'a Dummy>(); - assert_copy::<&'a (Dummy+Copy)>(); - assert_copy::<&'static (Dummy+Copy)>(); + assert_copy::<&'a (Dummy+Send)>(); + assert_copy::<&'static (Dummy+Send)>(); // owned object types are not ok assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied // mutable object types are not ok - assert_copy::<&'a mut (Dummy+Copy)>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'a mut (Dummy+Send)>(); //~ ERROR : std::marker::Copy` is not satisfied // unsafe ptrs are ok assert_copy::<*const isize>(); From 6fc19ada6b2c6373b28e70a1dffda68dba96f9a1 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Apr 2016 13:56:25 +0300 Subject: [PATCH 06/12] fix breaking changes --- src/librustc_back/sha2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs index ba8107e03c9..26f512e0613 100644 --- a/src/librustc_back/sha2.rs +++ b/src/librustc_back/sha2.rs @@ -42,7 +42,7 @@ fn read_u32v_be(dst: &mut[u32], input: &[u8]) { } } -trait ToBits { +trait ToBits: Sized { /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the /// high-order value and the 2nd item is the low order value. fn to_bits(self) -> (Self, Self); From 05f1a057b6e59fd07b4af7a9a2f0101d67faba88 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Apr 2016 16:38:17 +0300 Subject: [PATCH 07/12] address review comments --- src/librustc/ty/mod.rs | 200 +++++++++++++++---------------- src/test/run-pass/issue-31299.rs | 9 +- 2 files changed, 105 insertions(+), 104 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b4156fde6a3..a61e8603dbb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1750,105 +1750,6 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { } impl<'tcx> AdtDefData<'tcx, 'tcx> { - fn sized_constraint_for_tys( - &'tcx self, - tcx: &ty::TyCtxt<'tcx>, - stack: &mut Vec>, - tys: TYS - ) -> Ty<'tcx> - where TYS: IntoIterator> - { - 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.last().cloned(), - _ => Some(ty) - }) - .filter(|ty| *ty != tcx.types.bool) - .collect(); - - match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.mk_tup(tys) - } - } - - fn sized_constraint_for_ty( - &'tcx self, - tcx: &ty::TyCtxt<'tcx>, - stack: &mut Vec>, - ty: Ty<'tcx> - ) -> Ty<'tcx> { - let result = match ty.sty { - TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyArray(..) | TyClosure(..) => { - // these are always sized - return a primitive - tcx.types.bool - } - - TyStr | TyTrait(..) | TySlice(_) | TyError => { - // these are never sized - return the target type - ty - } - - TyTuple(ref tys) => { - self.sized_constraint_for_tys(tcx, stack, tys.iter().cloned()) - } - - TyEnum(adt, substs) | TyStruct(adt, substs) => { - // recursive case - let adt = tcx.lookup_adt_def_master(adt.did); - adt.calculate_sized_constraint_inner(tcx, stack); - let adt_ty = - adt.sized_constraint - .unwrap(DepNode::SizedConstraint(adt.did)) - .subst(tcx, substs); - debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", - ty, adt_ty); - self.sized_constraint_for_ty(tcx, stack, adt_ty) - } - - TyProjection(..) => { - // must calculate explicitly. - // FIXME: consider special-casing always-Sized projections - ty - } - - TyParam(..) => { - // perf hack: if there is a `T: Sized` bound, then - // we know that `T` is Sized and do not need to check - // it on the impl. - - let sized_trait = match tcx.lang_items.sized_trait() { - Some(x) => x, - _ => return ty - }; - let sized_predicate = Binder(TraitRef { - def_id: sized_trait, - substs: tcx.mk_substs(Substs::new_trait( - vec![], vec![], ty - )) - }).to_predicate(); - let predicates = tcx.lookup_predicates(self.did).predicates; - if predicates.into_iter().any(|p| p == sized_predicate) { - tcx.types.bool - } else { - ty - } - } - - TyInfer(..) => { - bug!("unexpected type `{:?}` in sized_constraint_for_ty", - ty) - } - }; - debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); - result - } - /// Calculates the Sized-constraint. /// /// As the Sized-constraint of enums can be a *set* of types, @@ -1876,21 +1777,33 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { if stack.contains(&self) { debug!("calculate_sized_constraint: {:?} is recursive", self); + // This should be reported as an error by `check_representable`. + // + // Consider the type as Sized in the meanwhile to avoid + // further errors. self.sized_constraint.fulfill(dep_node, tcx.types.err); return; } stack.push(self); - let ty = self.sized_constraint_for_tys( - tcx, stack, + + let tys : Vec<_> = self.variants.iter().flat_map(|v| { v.fields.last() - }).map(|f| f.unsubst_ty()) - ); + }).flat_map(|f| { + self.sized_constraint_for_ty(tcx, stack, f.unsubst_ty()) + }).collect(); let self_ = stack.pop().unwrap(); assert_eq!(self_, self); + let ty = match tys.len() { + _ if tys.references_error() => tcx.types.err, + 0 => tcx.types.bool, + 1 => tys[0], + _ => tcx.mk_tup(tys) + }; + match self.sized_constraint.get(dep_node) { Some(old_ty) => { debug!("calculate_sized_constraint: {:?} recurred", self); @@ -1902,6 +1815,87 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { } } } + + fn sized_constraint_for_ty( + &'tcx self, + tcx: &ty::TyCtxt<'tcx>, + stack: &mut Vec>, + ty: Ty<'tcx> + ) -> Vec> { + let result = match ty.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyArray(..) | TyClosure(..) => { + vec![] + } + + TyStr | TyTrait(..) | TySlice(_) | TyError => { + // these are never sized - return the target type + vec![ty] + } + + TyTuple(ref tys) => { + tys.last().into_iter().flat_map(|ty| { + self.sized_constraint_for_ty(tcx, stack, ty) + }).collect() + } + + TyEnum(adt, substs) | TyStruct(adt, substs) => { + // recursive case + let adt = tcx.lookup_adt_def_master(adt.did); + adt.calculate_sized_constraint_inner(tcx, stack); + let adt_ty = + adt.sized_constraint + .unwrap(DepNode::SizedConstraint(adt.did)) + .subst(tcx, substs); + debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", + ty, adt_ty); + if let ty::TyTuple(ref tys) = adt_ty.sty { + tys.iter().flat_map(|ty| { + self.sized_constraint_for_ty(tcx, stack, ty) + }).collect() + } else { + self.sized_constraint_for_ty(tcx, stack, adt_ty) + } + } + + TyProjection(..) => { + // must calculate explicitly. + // FIXME: consider special-casing always-Sized projections + vec![ty] + } + + TyParam(..) => { + // perf hack: if there is a `T: Sized` bound, then + // we know that `T` is Sized and do not need to check + // it on the impl. + + let sized_trait = match tcx.lang_items.sized_trait() { + Some(x) => x, + _ => return vec![ty] + }; + let sized_predicate = Binder(TraitRef { + def_id: sized_trait, + substs: tcx.mk_substs(Substs::new_trait( + vec![], vec![], ty + )) + }).to_predicate(); + let predicates = tcx.lookup_predicates(self.did).predicates; + if predicates.into_iter().any(|p| p == sized_predicate) { + vec![] + } else { + vec![ty] + } + } + + TyInfer(..) => { + bug!("unexpected type `{:?}` in sized_constraint_for_ty", + ty) + } + }; + debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result); + result + } } impl<'tcx, 'container> VariantDefData<'tcx, 'container> { diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs index e49e13c458f..6c04e66068e 100644 --- a/src/test/run-pass/issue-31299.rs +++ b/src/test/run-pass/issue-31299.rs @@ -12,12 +12,19 @@ // because of eager normalization: // // proving `M: Sized` requires -// - proving `PtrBack>: Sized` requis +// - proving `PtrBack>: Sized` requires // - normalizing `Vec< as Front>::Back>>: Sized` requires // - proving `Vec: Front` requires // - `M: Sized` <-- cycle! // // If we skip the normalization step, though, everything goes fine. +// +// This could be fixed by implementing lazy normalization everywhere. +// +// However, we want this to work before then. For that, when checking +// whether a type is Sized we only check that the tails are Sized. As +// PtrBack does not have a tail, we don't need to normalize anything +// and this compiles trait Front { type Back; From 5876b4b12aca5c614cf83218a1ca1fe10dde5422 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Apr 2016 17:26:31 +0300 Subject: [PATCH 08/12] improve error message for WF Tuples --- src/librustc/traits/error_reporting.rs | 4 ++++ src/test/compile-fail/unsized3.rs | 4 +++- src/test/compile-fail/unsized6.rs | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d02dfcd9ea7..98812f4e00f 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -768,6 +768,10 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, err.fileline_note( cause_span, "tuple elements must have `Sized` type"); + + err.fileline_warn( + cause_span, + "this is a new restriction added in rustc 1.10"); } ObligationCauseCode::ProjectionWf(data) => { err.note(&format!("required so that the projection `{}` is well-formed", diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index 1d93645fc84..d5f2cf65a69 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -60,7 +60,9 @@ fn f8(x1: &S, x2: &S) { fn f9(x1: Box>, x2: Box>) { f5(&(*x1, 34)); //~^ ERROR `X: std::marker::Sized` is not satisfied - //~^^ ERROR `X: std::marker::Sized` is not satisfied + //~| WARNING this is a new restriction added in rustc 1.10 + //~^^^ ERROR `X: std::marker::Sized` is not satisfied + //~| WARNING this is a new restriction added in rustc 1.10 } fn f10(x1: Box>, x2: Box>) { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index e18ccfee96c..ba9a8a4f294 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -15,12 +15,15 @@ trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied + //~| WARNING this is a new restriction added in rustc 1.10 let y: X; //~ERROR `X: std::marker::Sized` is not satisfied let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied + //~| WARNING this is a new restriction added in rustc 1.10 } fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied + //~| WARNING this is a new restriction added in rustc 1.10 } fn f3(x1: Box, x2: Box, x3: Box) { From 6057a7f18827f065668fcf22cfc0242de8f694b9 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 1 May 2016 09:59:28 +0300 Subject: [PATCH 09/12] change the newly-added errors to warnings this commit should be reverted after a release cycle --- src/librustc/lint/builtin.rs | 16 +- src/librustc/middle/free_region.rs | 1 + src/librustc/traits/error_reporting.rs | 161 ++++++++++++++------ src/librustc/traits/fulfill.rs | 54 ++++++- src/librustc/traits/mod.rs | 1 + src/librustc/traits/object_safety.rs | 2 + src/librustc/traits/select.rs | 19 +-- src/librustc/traits/util.rs | 63 ++++---- src/librustc/ty/mod.rs | 12 +- src/librustc/ty/structural_impls.rs | 3 + src/librustc/ty/util.rs | 1 + src/librustc/ty/wf.rs | 38 +++-- src/librustc/util/ppaux.rs | 4 + src/librustc_lint/lib.rs | 4 + src/librustc_metadata/tyencode.rs | 3 + src/librustc_passes/consts.rs | 3 + src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/closure.rs | 1 + src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/dropck.rs | 5 + src/librustc_typeck/check/method/probe.rs | 1 + src/librustc_typeck/check/mod.rs | 9 +- src/librustc_typeck/collect.rs | 1 + src/test/compile-fail/bad-sized.rs | 1 - src/test/compile-fail/issue-32963.rs | 3 +- src/test/compile-fail/rfc1592-deprecated.rs | 31 ++++ src/test/compile-fail/unsized3.rs | 3 - src/test/compile-fail/unsized6.rs | 5 +- src/test/run-pass/rfc1592-deprecated.rs | 29 ++++ 29 files changed, 363 insertions(+), 117 deletions(-) create mode 100644 src/test/compile-fail/rfc1592-deprecated.rs create mode 100644 src/test/run-pass/rfc1592-deprecated.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2564838c67d..6dd98425df3 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -185,6 +185,18 @@ declare_lint! { "detects super or self keywords at the beginning of global path" } +declare_lint! { + pub UNSIZED_IN_TUPLE, + Warn, + "unsized types in the interior of a tuple were erroneously allowed" +} + +declare_lint! { + pub OBJECT_UNSAFE_FRAGMENT, + Warn, + "object-unsafe non-principal fragments in object types were erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -220,7 +232,9 @@ impl LintPass for HardwiredLints { TRANSMUTE_FROM_FN_ITEM_TYPES, OVERLAPPING_INHERENT_IMPLS, RENAMED_AND_REMOVED_LINTS, - SUPER_OR_SELF_IN_GLOBAL_PATH + SUPER_OR_SELF_IN_GLOBAL_PATH, + UNSIZED_IN_TUPLE, + OBJECT_UNSAFE_FRAGMENT ) } } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 51eebd43731..758fb7a81fd 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -56,6 +56,7 @@ impl FreeRegionMap { match *predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 98812f4e00f..b89ce2ce3b2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,23 +36,27 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; use syntax::attr::{AttributeMethods, AttrMetaMethods}; +use syntax::ast; use syntax::codemap::Span; use syntax::errors::DiagnosticBuilder; #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { span: Span, + warning_node_id: Option, predicate: ty::Predicate<'tcx> } impl<'tcx> TraitErrorKey<'tcx> { fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>, - e: &FulfillmentError<'tcx>) -> Self { + e: &FulfillmentError<'tcx>, + warning_node_id: Option) -> Self { let predicate = infcx.resolve_type_vars_if_possible(&e.obligation.predicate); TraitErrorKey { span: e.obligation.cause.span, - predicate: infcx.tcx.erase_regions(&predicate) + predicate: infcx.tcx.erase_regions(&predicate), + warning_node_id: warning_node_id } } } @@ -60,13 +64,23 @@ impl<'tcx> TraitErrorKey<'tcx> { pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, errors: &Vec>) { for error in errors { - report_fulfillment_error(infcx, error); + report_fulfillment_error(infcx, error, None); + } +} + +pub fn report_fulfillment_errors_as_warnings<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + errors: &Vec>, + node_id: ast::NodeId) +{ + for error in errors { + report_fulfillment_error(infcx, error, Some(node_id)); } } fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - error: &FulfillmentError<'tcx>) { - let error_key = TraitErrorKey::from_error(infcx, error); + error: &FulfillmentError<'tcx>, + warning_node_id: Option) { + let error_key = TraitErrorKey::from_error(infcx, error, warning_node_id); debug!("report_fulfillment_errors({:?}) - key={:?}", error, error_key); if !infcx.reported_trait_errors.borrow_mut().insert(error_key) { @@ -75,10 +89,10 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } match error.code { FulfillmentErrorCode::CodeSelectionError(ref e) => { - report_selection_error(infcx, &error.obligation, e); + report_selection_error(infcx, &error.obligation, e, warning_node_id); } FulfillmentErrorCode::CodeProjectionError(ref e) => { - report_projection_error(infcx, &error.obligation, e); + report_projection_error(infcx, &error.obligation, e, warning_node_id); } FulfillmentErrorCode::CodeAmbiguity => { maybe_report_ambiguity(infcx, &error.obligation); @@ -88,18 +102,29 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>) + error: &MismatchedProjectionTypes<'tcx>, + warning_node_id: Option) { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); if !predicate.references_error() { - let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); + if let Some(warning_node_id) = warning_node_id { + infcx.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("type mismatch resolving `{}`: {}", + predicate, + error.err)); + } else { + let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271, + "type mismatch resolving `{}`: {}", + predicate, + error.err); + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } } } @@ -383,7 +408,8 @@ pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>, pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>) + error: &SelectionError<'tcx>, + warning_node_id: Option) { match *error { SelectionError::Unimplemented => { @@ -401,6 +427,17 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() { let trait_ref = trait_predicate.to_poly_trait_ref(); + + if let Some(warning_node_id) = warning_node_id { + infcx.tcx.sess.add_lint( + ::lint::builtin::UNSIZED_IN_TUPLE, + warning_node_id, + obligation.cause.span, + format!("the trait bound `{}` is not satisfied", + trait_ref.to_predicate())); + return; + } + let mut err = struct_span_err!( infcx.tcx.sess, obligation.cause.span, E0277, "the trait bound `{}` is not satisfied", @@ -480,12 +517,15 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, ty::Predicate::ObjectSafe(trait_def_id) => { let violations = object_safety_violations( infcx.tcx, trait_def_id); - let mut err = report_object_safety_error(infcx.tcx, - obligation.cause.span, - trait_def_id, - violations); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); + let err = report_object_safety_error(infcx.tcx, + obligation.cause.span, + trait_def_id, + warning_node_id, + violations); + if let Some(mut err) = err { + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } } ty::Predicate::ClosureKind(closure_def_id, kind) => { @@ -514,6 +554,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, "WF predicate not satisfied for {:?}", ty); } + + ty::Predicate::Rfc1592(ref data) => { + span_bug!( + obligation.cause.span, + "RFC1592 predicate not satisfied for {:?}", + data); + } } } } @@ -537,10 +584,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, TraitNotObjectSafe(did) => { let violations = object_safety_violations(infcx.tcx, did); - let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did, - violations); - note_obligation_cause(infcx, &mut err, obligation); - err.emit(); + let err = report_object_safety_error(infcx.tcx, obligation.cause.span, did, + warning_node_id, + violations); + if let Some(mut err) = err { + note_obligation_cause(infcx, &mut err, obligation); + err.emit(); + } } } } @@ -548,47 +598,70 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>, span: Span, trait_def_id: DefId, + warning_node_id: Option, violations: Vec) - -> DiagnosticBuilder<'tcx> + -> Option> { - let mut err = struct_span_err!( - tcx.sess, span, E0038, - "the trait `{}` cannot be made into an object", - tcx.item_path_str(trait_def_id)); + let mut err = match warning_node_id { + Some(_) => None, + None => { + Some(struct_span_err!( + tcx.sess, span, E0038, + "the trait `{}` cannot be made into an object", + tcx.item_path_str(trait_def_id))) + } + }; let mut reported_violations = FnvHashSet(); for violation in violations { if !reported_violations.insert(violation.clone()) { continue; } - match violation { + let buf; + let note = match violation { ObjectSafetyViolation::SizedSelf => { - err.note("the trait cannot require that `Self : Sized`"); + "the trait cannot require that `Self : Sized`" } ObjectSafetyViolation::SupertraitSelf => { - err.note("the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing" } ObjectSafetyViolation::Method(method, MethodViolationCode::StaticMethod) => { - err.note(&format!("method `{}` has no receiver", - method.name)); + buf = format!("method `{}` has no receiver", + method.name); + &buf } ObjectSafetyViolation::Method(method, MethodViolationCode::ReferencesSelf) => { - err.note(&format!("method `{}` references the `Self` type \ + buf = format!("method `{}` references the `Self` type \ in its arguments or return type", - method.name)); + method.name); + &buf } ObjectSafetyViolation::Method(method, MethodViolationCode::Generic) => { - err.note(&format!("method `{}` has generic type parameters", - method.name)); + buf = format!("method `{}` has generic type parameters", + method.name); + &buf } + }; + match (warning_node_id, &mut err) { + (Some(node_id), &mut None) => { + tcx.sess.add_lint( + ::lint::builtin::OBJECT_UNSAFE_FRAGMENT, + node_id, + span, + note.to_string()); + } + (None, &mut Some(ref mut err)) => { + err.note(note); + } + _ => unreachable!() } } err @@ -765,13 +838,7 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, err.note("slice and array elements must have `Sized` type"); } ObligationCauseCode::TupleElem => { - err.fileline_note( - cause_span, - "tuple elements must have `Sized` type"); - - err.fileline_warn( - cause_span, - "this is a new restriction added in rustc 1.10"); + err.note("tuple elements must have `Sized` type"); } ObligationCauseCode::ProjectionWf(data) => { err.note(&format!("required so that the projection `{}` is well-formed", diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 8946ec2153b..a184e951b83 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -13,6 +13,7 @@ use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef}; use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error}; use std::iter; +use std::mem; use syntax::ast; use util::common::ErrorReported; use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap}; @@ -70,6 +71,9 @@ pub struct FulfillmentContext<'tcx> { predicates: ObligationForest, LocalFulfilledPredicates<'tcx>>, + // A list of new obligations due to RFC1592. + rfc1592_obligations: Vec>, + // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must // outlive the lifetime 'a". These constraints derive from @@ -116,6 +120,7 @@ impl<'tcx> FulfillmentContext<'tcx> { FulfillmentContext { duplicate_set: LocalFulfilledPredicates::new(), predicates: ObligationForest::new(), + rfc1592_obligations: Vec::new(), region_obligations: NodeMap(), } } @@ -197,6 +202,13 @@ impl<'tcx> FulfillmentContext<'tcx> { self.predicates.push_tree(obligation, LocalFulfilledPredicates::new()); } + pub fn register_rfc1592_obligation<'a>(&mut self, + _infcx: &InferCtxt<'a,'tcx>, + obligation: PredicateObligation<'tcx>) + { + self.rfc1592_obligations.push(obligation); + } + pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] @@ -207,11 +219,26 @@ impl<'tcx> FulfillmentContext<'tcx> { } } + pub fn select_rfc1592_obligations<'a>(&mut self, + infcx: &InferCtxt<'a,'tcx>) + -> Result<(),Vec>> + { + while !self.rfc1592_obligations.is_empty() { + for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) { + self.register_predicate_obligation(infcx, obligation); + } + + self.select_all_or_error(infcx)?; + } + + Ok(()) + } pub fn select_all_or_error<'a>(&mut self, infcx: &InferCtxt<'a,'tcx>) -> Result<(),Vec>> { self.select_where_possible(infcx)?; + let errors: Vec<_> = self.predicates.to_errors(CodeAmbiguity) .into_iter() @@ -279,12 +306,14 @@ impl<'tcx> FulfillmentContext<'tcx> { // Process pending obligations. let outcome = { let region_obligations = &mut self.region_obligations; + let rfc1592_obligations = &mut self.rfc1592_obligations; self.predicates.process_obligations( |obligation, tree, backtrace| process_predicate(selcx, - tree, - obligation, - backtrace, - region_obligations)) + tree, + obligation, + backtrace, + region_obligations, + rfc1592_obligations)) }; debug!("select: outcome={:?}", outcome); @@ -321,11 +350,13 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, tree_cache: &mut LocalFulfilledPredicates<'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, backtrace: Backtrace>, - region_obligations: &mut NodeMap>>) + region_obligations: &mut NodeMap>>, + rfc1592_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> { - match process_predicate1(selcx, pending_obligation, region_obligations) { + match process_predicate1(selcx, pending_obligation, region_obligations, + rfc1592_obligations) { Ok(Some(v)) => process_child_obligations(selcx, tree_cache, &pending_obligation.obligation, @@ -507,7 +538,8 @@ fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>, /// - `Err` if the predicate does not hold fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, - region_obligations: &mut NodeMap>>) + region_obligations: &mut NodeMap>>, + rfc1592_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> { @@ -677,6 +709,14 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, s => Ok(s) } } + + ty::Predicate::Rfc1592(ref inner) => { + rfc1592_obligations.push(PredicateObligation { + predicate: ty::Predicate::clone(inner), + ..obligation.clone() + }); + Ok(Some(vec![])) + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 5921cdeab78..7da95b6646a 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -28,6 +28,7 @@ use syntax::codemap::{Span, DUMMY_SP}; pub use self::error_reporting::TraitErrorKey; pub use self::error_reporting::recursive_type_with_infinite_size_error; pub use self::error_reporting::report_fulfillment_errors; +pub use self::error_reporting::report_fulfillment_errors_as_warnings; pub use self::error_reporting::report_overflow_error; pub use self::error_reporting::report_overflow_error_cycle; pub use self::error_reporting::report_selection_error; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c870d609814..59db68b1c3c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -166,6 +166,7 @@ pub fn supertraits_reference_self<'tcx>(tcx: &TyCtxt<'tcx>, ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) => { false } @@ -204,6 +205,7 @@ fn generics_require_sized_self<'tcx>(tcx: &TyCtxt<'tcx>, } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 738ed85ae6d..2338eff3ec3 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -419,6 +419,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } match obligation.predicate { + ty::Predicate::Rfc1592(..) => EvaluatedToOk, + ty::Predicate::Trait(ref t) => { assert!(!t.has_escaping_regions()); let obligation = obligation.with(t.clone()); @@ -1661,10 +1663,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, ty::TyTuple(ref tys) => { - Where(ty::Binder(match tys.last() { - Some(ty) => vec![ty], - _ => vec![] - })) + // FIXME(#33242) we only need to constrain the last field + Where(ty::Binder(tys.clone())) } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2408,11 +2408,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { - let mut object_dids = - data.bounds.builtin_bounds.iter().flat_map(|bound| { - tcx.lang_items.from_builtin_kind(bound).ok() - }) - .chain(Some(data.principal_def_id())); + let mut object_dids = Some(data.principal_def_id()).into_iter(); + // FIXME(#33243) +// data.bounds.builtin_bounds.iter().flat_map(|bound| { +// tcx.lang_items.from_builtin_kind(bound).ok() +// }) +// .chain(Some(data.principal_def_id())); if let Some(did) = object_dids.find(|did| { !object_safety::is_object_safe(tcx, *did) }) { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 90def00be07..d82f9d7549d 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -18,6 +18,39 @@ use util::nodemap::FnvHashSet; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; +fn anonymize_predicate<'tcx>(tcx: &TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) + -> ty::Predicate<'tcx> { + match *pred { + ty::Predicate::Trait(ref data) => + ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::Rfc1592(ref data) => + ty::Predicate::Rfc1592(Box::new(anonymize_predicate(tcx, data))), + + ty::Predicate::Equate(ref data) => + ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::RegionOutlives(ref data) => + ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::TypeOutlives(ref data) => + ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::Projection(ref data) => + ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)), + + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data), + + ty::Predicate::ObjectSafe(data) => + ty::Predicate::ObjectSafe(data), + + ty::Predicate::ClosureKind(closure_def_id, kind) => + ty::Predicate::ClosureKind(closure_def_id, kind) + } +} + + struct PredicateSet<'a,'tcx:'a> { tcx: &'a TyCtxt<'tcx>, set: FnvHashSet>, @@ -39,32 +72,7 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> { // // to be considered equivalent. So normalize all late-bound // regions before we throw things into the underlying set. - let normalized_pred = match *pred { - ty::Predicate::Trait(ref data) => - ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Equate(ref data) => - ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::RegionOutlives(ref data) => - ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::TypeOutlives(ref data) => - ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Projection(ref data) => - ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data), - - ty::Predicate::ObjectSafe(data) => - ty::Predicate::ObjectSafe(data), - - ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind) - }; - self.set.insert(normalized_pred) + self.set.insert(anonymize_predicate(self.tcx, pred)) } } @@ -143,6 +151,9 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { self.stack.extend(predicates); } + ty::Predicate::Rfc1592(..) => { + // Nothing to elaborate. + } ty::Predicate::WellFormed(..) => { // Currently, we do not elaborate WF predicates, // although we easily could. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a61e8603dbb..3e3dae3b3e9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -804,6 +804,9 @@ pub enum Predicate<'tcx> { /// would be the parameters in the `TypeSpace`. Trait(PolyTraitPredicate<'tcx>), + /// A predicate created by RFC1592 + Rfc1592(Box>), + /// where `T1 == T2`. Equate(PolyEquatePredicate<'tcx>), @@ -904,6 +907,8 @@ impl<'tcx> Predicate<'tcx> { match *self { Predicate::Trait(ty::Binder(ref data)) => Predicate::Trait(ty::Binder(data.subst(tcx, substs))), + Predicate::Rfc1592(ref pi) => + Predicate::Rfc1592(Box::new(pi.subst_supertrait(tcx, trait_ref))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => @@ -1083,6 +1088,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Trait(ref data) => { data.0.trait_ref.substs.types.as_slice().to_vec() } + ty::Predicate::Rfc1592(ref data) => { + return data.walk_tys() + } ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } @@ -1123,6 +1131,7 @@ impl<'tcx> Predicate<'tcx> { Predicate::Trait(ref t) => { Some(t.to_poly_trait_ref()) } + Predicate::Rfc1592(..) | Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | @@ -1835,7 +1844,8 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { } TyTuple(ref tys) => { - tys.last().into_iter().flat_map(|ty| { + // FIXME(#33242) we only need to constrain the last field + tys.iter().flat_map(|ty| { self.sized_constraint_for_ty(tcx, stack, ty) }).collect() } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4d64dd83071..ac3dfa82bd6 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -634,6 +634,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), + ty::Predicate::Rfc1592(ref a) => + ty::Predicate::Rfc1592(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => @@ -654,6 +656,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), + ty::Predicate::Rfc1592(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2e4f37f1cc1..b6bd8f5f55f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -299,6 +299,7 @@ impl<'tcx> TyCtxt<'tcx> { match predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 316a81e8f62..609252f948a 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,9 @@ pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Rfc1592(ref data) => { + bug!("RFC1592 predicate `{:?}` in predicate_obligations", data); + } } wf.normalize() @@ -155,6 +158,7 @@ pub fn implied_bounds<'a,'tcx>( assert!(!obligation.has_escaping_regions()); match obligation.predicate { ty::Predicate::Trait(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | @@ -280,16 +284,23 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { } } - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>, + rfc1592: bool) { if !subty.has_escaping_regions() { let cause = self.cause(cause); match traits::trait_ref_for_builtin_bound(self.infcx.tcx, ty::BoundSized, subty) { Ok(trait_ref) => { + let predicate = trait_ref.to_predicate(); + let predicate = if rfc1592 { + ty::Predicate::Rfc1592(box predicate) + } else { + predicate + }; self.out.push( traits::Obligation::new(cause, - trait_ref.to_predicate())); + predicate)); } Err(ErrorReported) => { } } @@ -318,13 +329,13 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { ty::TySlice(subty) | ty::TyArray(subty, _) => { - self.require_sized(subty, traits::SliceOrArrayElem); + self.require_sized(subty, traits::SliceOrArrayElem, false); } ty::TyTuple(ref tys) => { if let Some((_last, rest)) = tys.split_last() { for elem in rest { - self.require_sized(elem, traits::TupleElem); + self.require_sized(elem, traits::TupleElem, true); } } } @@ -387,18 +398,23 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { let cause = self.cause(traits::MiscObligation); + // FIXME(#33243): remove RFC1592 + self.out.push(traits::Obligation::new( + cause.clone(), + ty::Predicate::ObjectSafe(data.principal_def_id()) + )); let component_traits = data.bounds.builtin_bounds.iter().flat_map(|bound| { tcx.lang_items.from_builtin_kind(bound).ok() - }) - .chain(Some(data.principal_def_id())); + }); +// .chain(Some(data.principal_def_id())); self.out.extend( - component_traits.map(|did| { - traits::Obligation::new( - cause.clone(), - ty::Predicate::ObjectSafe(did) + component_traits.map(|did| { traits::Obligation::new( + cause.clone(), + ty::Predicate::Rfc1592( + box ty::Predicate::ObjectSafe(did) ) - }) + )}) ); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6682a0e2b4f..728306b25dd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -459,6 +459,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), + ty::Predicate::Rfc1592(ref a) => { + write!(f, "RFC1592({:?})", a) + } ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), @@ -1056,6 +1059,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), + ty::Predicate::Rfc1592(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index e7c9097a56a..4832f18f213 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -190,6 +190,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN), reference: "RFC 1445 ", }, + FutureIncompatibleInfo { + id: LintId::of(UNSIZED_IN_TUPLE), + reference: "RFC PR 1592 ", + } ]); // We have one lint pass defined specially diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 61d055d4d51..57aa347847e 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -449,6 +449,9 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, p: &ty::Predicate<'tcx>) { match *p { + ty::Predicate::Rfc1592(..) => { + bug!("RFC1592 predicate in metadata `{:?}`", p); + } ty::Predicate::Trait(ref trait_ref) => { write!(w, "t"); enc_trait_ref(w, cx, trait_ref.0.trait_ref); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index dede4d2a42a..6fb9739fca4 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -277,6 +277,9 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { traits::report_fulfillment_errors(&infcx, errors); } } + if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { + traits::report_fulfillment_errors_as_warnings(&infcx, errors, e.id); + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ac7745985e6..5e07011d5ba 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1143,8 +1143,8 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>, traits::astconv_object_safety_violations(tcx, principal.def_id()); if !object_safety_violations.is_empty() { traits::report_object_safety_error( - tcx, span, principal.def_id(), object_safety_violations) - .emit(); + tcx, span, principal.def_id(), None, object_safety_violations) + .unwrap().emit(); return tcx.types.err; } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 4ac7e3323ef..b84ded1ea7a 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -179,6 +179,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::Rfc1592(..) => None, // NB: This predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f1c6868efd2..6c8d437f429 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -477,7 +477,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - report_selection_error(self.fcx.infcx(), &obligation, &err); + report_selection_error(self.fcx.infcx(), &obligation, &err, None); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 368b826b1bb..b9fda210454 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -114,6 +114,11 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( return Err(()); } + if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { + traits::report_fulfillment_errors_as_warnings(&infcx, errors, + drop_impl_node_id); + } + let free_regions = FreeRegionMap::new(); infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); Ok(()) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2defbf0d33e..8a71debdf20 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -492,6 +492,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Rfc1592(..) | ty::Predicate::TypeOutlives(..) => { None } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 385f04b8564..6599199c239 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1989,13 +1989,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // upvar inference should have ensured that all deferred call // resolutions are handled by now. assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); + let infcx = self.infcx(); self.select_all_obligations_and_apply_defaults(); let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); - match fulfillment_cx.select_all_or_error(self.infcx()) { + match fulfillment_cx.select_all_or_error(infcx) { Ok(()) => { } - Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } + Err(errors) => { report_fulfillment_errors(infcx, &errors); } + } + + if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(infcx) { + traits::report_fulfillment_errors_as_warnings(infcx, errors, self.body_id); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index c10488a03ef..4dd093e2e4b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -450,6 +450,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { ty::Predicate::TypeOutlives(ref data) => { data.skip_binder().0.is_param(def.space, def.index) } + ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index ba0a6f19f07..f62404e60e6 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -15,5 +15,4 @@ pub fn main() { //~^ ERROR `Trait + Sized: std::marker::Sized` is not satisfied //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied - //~| ERROR `std::marker::Sized` cannot be made into an object } diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs index d0434384cd0..c4e8f766117 100644 --- a/src/test/compile-fail/issue-32963.rs +++ b/src/test/compile-fail/issue-32963.rs @@ -16,6 +16,5 @@ fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); - //~^ ERROR `std::marker::Copy` cannot be made into an object - //~| ERROR `Misc + Copy: std::marker::Copy` is not satisfied + //~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied } diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs new file mode 100644 index 00000000000..0c12c1c4444 --- /dev/null +++ b/src/test/compile-fail/rfc1592-deprecated.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +trait Foo { + fn foo(&self) -> (Self, Self); + //~^ WARNING hard error +} + +impl Foo for T { + fn foo(&self) -> (Self, Self) { + (*self, *self) + } +} + +fn main() { + assert_eq!((11).foo(), (11, 11)); + + let junk: Box = Box::new(42); + //~^ WARNING hard error + let f = format!("{:?}", junk); + assert_eq!(f, "42"); +} diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs index d5f2cf65a69..f88165c02e9 100644 --- a/src/test/compile-fail/unsized3.rs +++ b/src/test/compile-fail/unsized3.rs @@ -60,9 +60,6 @@ fn f8(x1: &S, x2: &S) { fn f9(x1: Box>, x2: Box>) { f5(&(*x1, 34)); //~^ ERROR `X: std::marker::Sized` is not satisfied - //~| WARNING this is a new restriction added in rustc 1.10 - //~^^^ ERROR `X: std::marker::Sized` is not satisfied - //~| WARNING this is a new restriction added in rustc 1.10 } fn f10(x1: Box>, x2: Box>) { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index ba9a8a4f294..d40c12f67a0 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,16 +14,13 @@ trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied - //~| WARNING this is a new restriction added in rustc 1.10 + let _: (isize, (X, isize)); let y: X; //~ERROR `X: std::marker::Sized` is not satisfied let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied - //~| WARNING this is a new restriction added in rustc 1.10 } fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied - //~| WARNING this is a new restriction added in rustc 1.10 } fn f3(x1: Box, x2: Box, x3: Box) { diff --git a/src/test/run-pass/rfc1592-deprecated.rs b/src/test/run-pass/rfc1592-deprecated.rs new file mode 100644 index 00000000000..81bf0258789 --- /dev/null +++ b/src/test/run-pass/rfc1592-deprecated.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +trait Foo { + fn foo(&self) -> (Self, Self); +} + +impl Foo for T { + fn foo(&self) -> (Self, Self) { + (*self, *self) + } +} + +fn main() { + assert_eq!((11).foo(), (11, 11)); + + let junk: Box = Box::new(42); + let f = format!("{:?}", junk); + assert_eq!(f, "42"); +} From 62db786fc82cff397bbb031cfb03fab34b5043a5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 1 May 2016 17:19:11 +0300 Subject: [PATCH 10/12] stop using commit_if_ok where no errors can happen --- src/librustc/infer/mod.rs | 11 +++++ src/librustc/traits/select.rs | 83 +++++++++++++---------------------- 2 files changed, 42 insertions(+), 52 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 312a446d440..6da4c44fe9a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -814,6 +814,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } + // Execute `f` in a snapshot, and commit the bindings it creates + pub fn in_snapshot(&self, f: F) -> T where + F: FnOnce(&CombinedSnapshot) -> T + { + debug!("in_snapshot()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + self.commit_from(snapshot); + r + } + /// Execute `f` and commit only the region bindings if successful. /// The function f must be very careful not to leak any non-region /// variables that get created. diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 2338eff3ec3..8a6582e8420 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -49,7 +49,6 @@ use std::fmt; use std::rc::Rc; use syntax::abi::Abi; use hir; -use util::common::ErrorReported; use util::nodemap::FnvHashMap; pub struct SelectionContext<'cx, 'tcx:'cx> { @@ -1402,7 +1401,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - self.infcx.commit_if_ok(|snapshot| { + self.infcx.in_snapshot(|snapshot| { let (self_ty, _) = self.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot); let poly_trait_ref = match self_ty.sty { @@ -1413,7 +1412,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_from_object_ty: matched builtin bound, \ pushing candidate"); candidates.vec.push(BuiltinObjectCandidate); - return Ok(()); + return; } } _ => {} @@ -1424,10 +1423,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_candidates_from_object_ty: ambiguous"); candidates.ambiguous = true; // could wind up being an object type - return Ok(()); + return; } _ => { - return Ok(()); + return; } }; @@ -1455,9 +1454,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else if upcast_trait_refs == 1 { candidates.vec.push(ObjectCandidate); } - - Ok::<(),()>(()) - }).unwrap(); + }) } /// Search for unsizing that might apply to `obligation`. @@ -1854,21 +1851,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 2. Produce something like `&'0 int : Copy` // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - // Move the binder into the individual types - let bound_types: Vec>> = - types.skip_binder() - .iter() - .map(|&nested_ty| ty::Binder(nested_ty)) - .collect(); + types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\ + let ty: ty::Binder> = ty::Binder(ty); // <----------/ - // For each type, produce a vector of resulting obligations - let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { - self.infcx.commit_if_ok(|snapshot| { + self.infcx.in_snapshot(|snapshot| { let (skol_ty, skol_map) = - self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); + self.infcx().skolemize_late_bound_regions(&ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = project::normalize_with_depth(self, - obligation.cause.clone(), + derived_cause.clone(), obligation.recursion_depth + 1, &skol_ty); let skol_obligation = @@ -1879,15 +1870,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { normalized_ty, vec![]); obligations.push(skol_obligation); - Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations)) + self.infcx().plug_leaks(skol_map, snapshot, &obligations) }) - }).collect(); - - // Flatten those vectors (couldn't do it above due `collect`) - match obligations { - Ok(obligations) => obligations.into_iter().flat_map(|o| o).collect(), - Err(ErrorReported) => Vec::new(), - } + }).collect() } /////////////////////////////////////////////////////////////////////////// @@ -1928,9 +1913,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ImplCandidate(impl_def_id) => { - let vtable_impl = - self.confirm_impl_candidate(obligation, impl_def_id)?; - Ok(VtableImpl(vtable_impl)) + Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) } ClosureCandidate(closure_def_id, substs, kind) => { @@ -1974,14 +1957,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - let _: Result<(),()> = - self.infcx.commit_if_ok(|snapshot| { - let result = - self.match_projection_obligation_against_bounds_from_trait(obligation, - snapshot); - assert!(result); - Ok(()) - }); + self.infcx.in_snapshot(|snapshot| { + let result = + self.match_projection_obligation_against_bounds_from_trait(obligation, + snapshot); + assert!(result); + }) } fn confirm_param_candidate(&mut self, @@ -2112,20 +2093,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id, nested); - let trait_obligations: Result,()> = self.infcx.commit_if_ok(|snapshot| { + let trait_obligations = self.infcx.in_snapshot(|snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); - Ok(self.impl_or_trait_obligations(obligation.cause.clone(), - obligation.recursion_depth + 1, - trait_def_id, - &trait_ref.substs, - skol_map, - snapshot)) + self.impl_or_trait_obligations(obligation.cause.clone(), + obligation.recursion_depth + 1, + trait_def_id, + &trait_ref.substs, + skol_map, + snapshot) }); - // no Errors in that code above - obligations.append(&mut trait_obligations.unwrap()); + obligations.extend(trait_obligations); debug!("vtable_default_impl_data: obligations={:?}", obligations); @@ -2138,8 +2118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_impl_candidate(&mut self, obligation: &TraitObligation<'tcx>, impl_def_id: DefId) - -> Result>, - SelectionError<'tcx>> + -> VtableImplData<'tcx, PredicateObligation<'tcx>> { debug!("confirm_impl_candidate({:?},{:?})", obligation, @@ -2147,13 +2126,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.commit_if_ok(|snapshot| { + self.infcx.in_snapshot(|snapshot| { let (substs, skol_map) = self.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate substs={:?}", substs); - Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), - obligation.recursion_depth + 1, skol_map, snapshot)) + self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), + obligation.recursion_depth + 1, skol_map, snapshot) }) } From 6c883840e68860b834fecfa6df337241af3c2a67 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 1 May 2016 17:46:56 +0300 Subject: [PATCH 11/12] stop dropping impls from cause backtraces --- src/librustc/traits/select.rs | 48 ++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8a6582e8420..138ca7a0f35 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1823,20 +1823,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn collect_predicates_for_types(&mut self, - obligation: &TraitObligation<'tcx>, + cause: ObligationCause<'tcx>, + recursion_depth: usize, trait_def_id: DefId, types: ty::Binder>>) -> Vec> { - let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) { - Some(_) => { - self.derived_cause(obligation, BuiltinDerivedObligation) - }, - None => { - self.derived_cause(obligation, ImplDerivedObligation) - } - }; - // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound // regions. For example, `for<'a> Foo<&'a int> : Copy` would @@ -1859,14 +1851,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx().skolemize_late_bound_regions(&ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = project::normalize_with_depth(self, - derived_cause.clone(), - obligation.recursion_depth + 1, + cause.clone(), + recursion_depth, &skol_ty); let skol_obligation = util::predicate_for_trait_def(self.tcx(), - derived_cause.clone(), + cause.clone(), trait_def_id, - obligation.recursion_depth + 1, + recursion_depth, normalized_ty, vec![]); obligations.push(skol_obligation); @@ -2013,7 +2005,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation) }; - self.collect_predicates_for_types(obligation, trait_def, nested) + let cause = self.derived_cause(obligation, BuiltinDerivedObligation); + self.collect_predicates_for_types(cause, + obligation.recursion_depth+1, + trait_def, + nested) } else { vec![] }; @@ -2087,17 +2083,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: ty::Binder>>) -> VtableDefaultImplData> { - debug!("vtable_default_impl_data: nested={:?}", nested); + debug!("vtable_default_impl: nested={:?}", nested); - let mut obligations = self.collect_predicates_for_types(obligation, - trait_def_id, - nested); + let cause = self.derived_cause(obligation, BuiltinDerivedObligation); + let mut obligations = self.collect_predicates_for_types( + cause, + obligation.recursion_depth+1, + trait_def_id, + nested); let trait_obligations = self.infcx.in_snapshot(|snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); - self.impl_or_trait_obligations(obligation.cause.clone(), + let cause = self.derived_cause(obligation, ImplDerivedObligation); + self.impl_or_trait_obligations(cause, obligation.recursion_depth + 1, trait_def_id, &trait_ref.substs, @@ -2107,7 +2107,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligations.extend(trait_obligations); - debug!("vtable_default_impl_data: obligations={:?}", obligations); + debug!("vtable_default_impl: obligations={:?}", obligations); VtableDefaultImplData { trait_def_id: trait_def_id, @@ -2131,8 +2131,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate substs={:?}", substs); - self.vtable_impl(impl_def_id, substs, obligation.cause.clone(), - obligation.recursion_depth + 1, skol_map, snapshot) + let cause = self.derived_cause(obligation, ImplDerivedObligation); + self.vtable_impl(impl_def_id, substs, cause, + obligation.recursion_depth + 1, + skol_map, snapshot) }) } From 238e4ee104179c5a6beb5bb25ffe28a3fd77bff5 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 2 May 2016 17:18:05 +0300 Subject: [PATCH 12/12] fixes --- src/librustc_lint/lib.rs | 6 +++++- src/librustdoc/clean/mod.rs | 1 + src/test/compile-fail/issue-20692.rs | 1 + src/test/compile-fail/rfc1592-deprecated.rs | 11 ++++++----- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4832f18f213..e0abe1aebd2 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -192,7 +192,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { }, FutureIncompatibleInfo { id: LintId::of(UNSIZED_IN_TUPLE), - reference: "RFC PR 1592 ", + reference: "issue #33242 ", + }, + FutureIncompatibleInfo { + id: LintId::of(OBJECT_UNSAFE_FRAGMENT), + reference: "issue #33243 ", } ]); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 35922c477cc..6895bceeb00 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -865,6 +865,7 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::WellFormed(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"), + Predicate::Rfc1592(..) => panic!("not user writable"), } } } diff --git a/src/test/compile-fail/issue-20692.rs b/src/test/compile-fail/issue-20692.rs index 62d775adac3..1c9e588cb2c 100644 --- a/src/test/compile-fail/issue-20692.rs +++ b/src/test/compile-fail/issue-20692.rs @@ -14,6 +14,7 @@ fn f(x: &T) { let _ = x //~^ ERROR `Array` cannot be made into an object //~| NOTE the trait cannot require that `Self : Sized` + //~| NOTE requirements on the impl of `std::ops::CoerceUnsized<&Array>` as &Array; //~^ ERROR `Array` cannot be made into an object diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs index 0c12c1c4444..e766f977200 100644 --- a/src/test/compile-fail/rfc1592-deprecated.rs +++ b/src/test/compile-fail/rfc1592-deprecated.rs @@ -10,10 +10,9 @@ use std::fmt; -trait Foo { - fn foo(&self) -> (Self, Self); - //~^ WARNING hard error -} +#[deny(warnings)] trait Foo { fn foo(&self) -> (Self, Self); } +//~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied +//~| WARNING hard error impl Foo for T { fn foo(&self) -> (Self, Self) { @@ -21,11 +20,13 @@ impl Foo for T { } } +#[deny(warnings)] fn main() { assert_eq!((11).foo(), (11, 11)); let junk: Box = Box::new(42); - //~^ WARNING hard error + //~^ ERROR the trait cannot require that `Self : Sized` + //~| WARNING hard error let f = format!("{:?}", junk); assert_eq!(f, "42"); }