diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 3382095b4560f..d19f3b6d27a75 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2623,7 +2623,7 @@ impl Iterator for Unfold where F: FnMut(&mut St) -> Option { /// two `Step` objects. #[unstable(feature = "step_trait", reason = "likely to be replaced by finer-grained traits")] -pub trait Step: PartialOrd { +pub trait Step: PartialOrd+Sized { /// Steps `self` if possible. fn step(&self, by: &Self) -> Option; diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c0956753c988c..32f367e12f034 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -56,7 +56,7 @@ pub trait Sized { /// Types that can be "unsized" to a dynamically sized type. #[unstable(feature = "unsize")] #[lang="unsize"] -pub trait Unsize { +pub trait Unsize { // Empty. } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index ad891bf8fa623..7507e5782d6a2 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -19,7 +19,7 @@ use char::CharExt; use cmp::{Eq, PartialOrd}; use fmt; use intrinsics; -use marker::Copy; +use marker::{Copy, Sized}; use mem::size_of; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; @@ -1264,7 +1264,7 @@ pub enum FpCategory { #[doc(hidden)] #[unstable(feature = "core_float", reason = "stable interface is via `impl f{32,64}` in later crates")] -pub trait Float { +pub trait Float: Sized { /// Returns the NaN value. fn nan() -> Self; /// Returns the infinite value. diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 3c9338c2cd29c..d5bceb3ba623c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -25,6 +25,7 @@ use default::Default; use fmt; use iter::ExactSizeIterator; use iter::{Map, Iterator, DoubleEndedIterator}; +use marker::Sized; use mem; use ops::{Fn, FnMut, FnOnce}; use option::Option::{self, None, Some}; @@ -37,7 +38,7 @@ pub mod pattern; /// A trait to abstract the idea of creating a new instance of a type from a /// string. #[stable(feature = "rust1", since = "1.0.0")] -pub trait FromStr { +pub trait FromStr: Sized { /// The associated error which can be returned from parsing. #[stable(feature = "rust1", since = "1.0.0")] type Err; diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index f6f3438f46720..a0b571b65ab5c 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -561,7 +561,7 @@ pub type Edges<'a,E> = Cow<'a,[E]>; /// `Cow<[T]>` to leave implementers the freedom to create /// entirely new vectors or to pass back slices into internally owned /// vectors. -pub trait GraphWalk<'a, N, E> { +pub trait GraphWalk<'a, N: Clone, E: Clone> { /// Returns all the nodes in this graph. fn nodes(&'a self) -> Nodes<'a, N>; /// Returns all of the edges in this graph. diff --git a/src/librand/distributions/range.rs b/src/librand/distributions/range.rs index e196708368ad3..26f92ee3b1cf0 100644 --- a/src/librand/distributions/range.rs +++ b/src/librand/distributions/range.rs @@ -12,6 +12,7 @@ // this is surprisingly complicated to be both generic & correct +use core::marker::Sized; use Rng; use distributions::{Sample, IndependentSample}; @@ -57,7 +58,7 @@ impl IndependentSample for Range { /// uniformly between two values. This should not be used directly, /// and is only to facilitate `Range`. #[doc(hidden)] -pub trait SampleRange { +pub trait SampleRange: Sized { /// Construct the `Range` object that `sample_range` /// requires. This should not ever be called directly, only via /// `Range::new`, which will check that `low < high`, so this diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 6b53f835be592..f48a28965c685 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -130,6 +130,7 @@ pub mod middle { pub mod lang_items; pub mod liveness; pub mod mem_categorization; + pub mod outlives; pub mod pat_util; pub mod privacy; pub mod reachable; @@ -144,6 +145,7 @@ pub mod middle { pub mod ty_match; pub mod ty_relate; pub mod ty_walk; + pub mod wf; pub mod weak_lang_items; } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 679213874f964..a8b22846b786d 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -790,6 +790,12 @@ fn parse_predicate_<'a,'tcx, F>(st: &mut PState<'a, 'tcx>, 'o' => ty::Binder(ty::OutlivesPredicate(parse_ty_(st, conv), parse_region_(st, conv))).to_predicate(), 'p' => ty::Binder(parse_projection_predicate_(st, conv)).to_predicate(), + 'w' => ty::Predicate::WellFormed(parse_ty_(st, conv)), + 'O' => { + let def_id = parse_def_(st, NominalType, conv); + assert_eq!(next(st), '|'); + ty::Predicate::ObjectSafe(def_id) + } c => panic!("Encountered invalid character in metadata: {}", c) } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 88666be6c2cc2..7170a3681713a 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -457,6 +457,13 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Encoder, mywrite!(w, "p"); enc_projection_predicate(w, cx, data) } + ty::Predicate::WellFormed(data) => { + mywrite!(w, "w"); + enc_ty(w, cx, data); + } + ty::Predicate::ObjectSafe(trait_def_id) => { + mywrite!(w, "O{}|", (cx.ds)(trait_def_id)); + } } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 5c3b0a1c2d246..c064b31173f98 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1061,7 +1061,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } -trait doc_decoder_helpers { +trait doc_decoder_helpers: Sized { fn as_int(&self) -> isize; fn opt_child(&self, tag: c::astencode_tag) -> Option; } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 3755b4c57c3ec..e5ee2ca0d4022 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -239,7 +239,7 @@ impl OverloadedCallType { // supplies types from the tree. After type checking is complete, you // can just use the tcx as the typer. -pub struct ExprUseVisitor<'d,'t,'a: 't, 'tcx:'a> { +pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> { typer: &'t infer::InferCtxt<'a, 'tcx>, mc: mc::MemCategorizationContext<'t, 'a, 'tcx>, delegate: &'d mut (Delegate<'tcx>+'d), @@ -273,7 +273,8 @@ enum PassArgs { impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { pub fn new(delegate: &'d mut Delegate<'tcx>, typer: &'t infer::InferCtxt<'a, 'tcx>) - -> ExprUseVisitor<'d,'t,'a, 'tcx> { + -> ExprUseVisitor<'d,'t,'a,'tcx> + { ExprUseVisitor { typer: typer, mc: mc::MemCategorizationContext::new(typer), diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 102cd001a296a..5af37e9530cce 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -10,7 +10,7 @@ //! This file defines -use middle::implicator::Implication; +use middle::wf::ImpliedBound; use middle::ty::{self, FreeRegion}; use util::common::can_reach; use util::nodemap::{FnvHashMap, FnvHashSet}; @@ -30,18 +30,19 @@ impl FreeRegionMap { FreeRegionMap { map: FnvHashMap(), statics: FnvHashSet() } } - pub fn relate_free_regions_from_implications<'tcx>(&mut self, - implications: &[Implication<'tcx>]) + pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self, + implied_bounds: &[ImpliedBound<'tcx>]) { - for implication in implications { - debug!("implication: {:?}", implication); - match *implication { - Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => { + debug!("relate_free_regions_from_implied_bounds()"); + for implied_bound in implied_bounds { + debug!("implied bound: {:?}", implied_bound); + match *implied_bound { + ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => { self.relate_free_regions(free_a, free_b); } - Implication::RegionSubRegion(..) | - Implication::RegionSubGeneric(..) | - Implication::Predicate(..) => { + ImpliedBound::RegionSubRegion(..) | + ImpliedBound::RegionSubParam(..) | + ImpliedBound::RegionSubProjection(..) => { } } } @@ -56,6 +57,8 @@ impl FreeRegionMap { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) => { // No region bounds here } diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs index 84fc2f7b2e540..1961c15d6e607 100644 --- a/src/librustc/middle/implicator.rs +++ b/src/librustc/middle/implicator.rs @@ -13,7 +13,7 @@ use middle::infer::{InferCtxt, GenericKind}; use middle::subst::Substs; use middle::traits; -use middle::ty::{self, RegionEscape, ToPolyTraitRef, ToPredicate, Ty}; +use middle::ty::{self, RegionEscape, ToPredicate, Ty}; use middle::ty_fold::{TypeFoldable, TypeFolder}; use syntax::ast; @@ -278,9 +278,7 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { for predicate in predicates.predicates.as_slice() { match *predicate { - ty::Predicate::Trait(ref data) => { - self.accumulate_from_assoc_types_transitive(data); - } + ty::Predicate::Trait(..) => { } ty::Predicate::Equate(..) => { } ty::Predicate::Projection(..) => { } ty::Predicate::RegionOutlives(ref data) => { @@ -301,6 +299,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { } } } + ty::Predicate::ObjectSafe(_) | + ty::Predicate::WellFormed(_) => { + } } } @@ -349,53 +350,6 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> { } } - /// Given that there is a requirement that `Foo : 'a`, where - /// `Foo` is declared like `struct Foo where T : SomeTrait`, - /// this code finds all the associated types defined in - /// `SomeTrait` (and supertraits) and adds a requirement that `::N : 'a` (where `N` is some associated type - /// defined in `SomeTrait`). This rule only applies to - /// trait-bounds that are not higher-ranked, because we cannot - /// project out of a HRTB. This rule helps code using associated - /// types to compile, see Issue #22246 for an example. - fn accumulate_from_assoc_types_transitive(&mut self, - data: &ty::PolyTraitPredicate<'tcx>) - { - debug!("accumulate_from_assoc_types_transitive({:?})", - data); - - for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) { - match self.tcx().no_late_bound_regions(&poly_trait_ref) { - Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); } - None => { } - } - } - } - - fn accumulate_from_assoc_types(&mut self, - trait_ref: ty::TraitRef<'tcx>) - { - debug!("accumulate_from_assoc_types({:?})", - trait_ref); - - let trait_def_id = trait_ref.def_id; - let trait_def = self.tcx().lookup_trait_def(trait_def_id); - let assoc_type_projections: Vec<_> = - trait_def.associated_type_names - .iter() - .map(|&name| self.tcx().mk_projection(trait_ref.clone(), name)) - .collect(); - debug!("accumulate_from_assoc_types: assoc_type_projections={:?}", - assoc_type_projections); - let tys = match self.fully_normalize(&assoc_type_projections) { - Ok(tys) => { tys } - Err(ErrorReported) => { return; } - }; - for ty in tys { - self.accumulate_from_ty(ty); - } - } - fn accumulate_from_object_ty(&mut self, ty: Ty<'tcx>, region_bound: ty::Region, diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 663746ac2dd3c..44eceb1f213af 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -239,8 +239,7 @@ pub trait ErrorReporting<'tcx> { fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, - sub: Region, - sups: Vec); + sub: Region); fn report_sub_sup_conflict(&self, var_origin: RegionVariableOrigin, @@ -292,8 +291,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { self.report_concrete_failure(origin, sub, sup); } - GenericBoundFailure(kind, param_ty, sub, sups) => { - self.report_generic_bound_failure(kind, param_ty, sub, sups); + GenericBoundFailure(kind, param_ty, sub) => { + self.report_generic_bound_failure(kind, param_ty, sub); } SubSupConflict(var_origin, @@ -527,14 +526,18 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, bound_kind: GenericKind<'tcx>, - sub: Region, - _sups: Vec) + sub: Region) { // FIXME: it would be better to report the first error message // with the span of the parameter itself, rather than the span // where the error was detected. But that span is not readily // accessible. + let is_warning = match origin { + infer::RFC1214Subregion(_) => true, + _ => false, + }; + let labeled_user_string = match bound_kind { GenericKind::Param(ref p) => format!("the parameter type `{}`", p), @@ -545,7 +548,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { match sub { ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => { // Does the required lifetime have a nice name we can print? - span_err!(self.tcx.sess, origin.span(), E0309, + span_err_or_warn!( + is_warning, self.tcx.sess, origin.span(), E0309, "{} may not live long enough", labeled_user_string); self.tcx.sess.fileline_help( origin.span(), @@ -557,7 +561,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { ty::ReStatic => { // Does the required lifetime have a nice name we can print? - span_err!(self.tcx.sess, origin.span(), E0310, + span_err_or_warn!( + is_warning, self.tcx.sess, origin.span(), E0310, "{} may not live long enough", labeled_user_string); self.tcx.sess.fileline_help( origin.span(), @@ -568,9 +573,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { _ => { // If not, be less specific. - span_err!(self.tcx.sess, origin.span(), E0311, - "{} may not live long enough", - labeled_user_string); + span_err_or_warn!( + is_warning, self.tcx.sess, origin.span(), E0311, + "{} may not live long enough", + labeled_user_string); self.tcx.sess.fileline_help( origin.span(), &format!( @@ -583,6 +589,10 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { } } + if is_warning { + self.tcx.sess.note_rfc_1214(origin.span()); + } + self.note_region_origin(&origin); } @@ -591,6 +601,13 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sub: Region, sup: Region) { match origin { + infer::RFC1214Subregion(ref suborigin) => { + // Ideally, this would be a warning, but it doesn't + // seem to come up in practice, since the changes from + // RFC1214 mostly trigger errors in type definitions + // that don't wind up coming down this path. + self.report_concrete_failure((**suborigin).clone(), sub, sup); + } infer::Subtype(trace) => { let terr = TypeError::RegionsDoesNotOutlive(sup, sub); self.report_and_explain_type_error(trace, &terr); @@ -819,6 +836,23 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup, ""); } + infer::ParameterInScope(_, span) => { + self.tcx.sess.span_err( + span, + &format!("type/lifetime parameter not in scope here")); + self.tcx.note_and_explain_region( + "the parameter is only valid for ", + sub, + ""); + } + infer::DataBorrowed(ty, span) => { + self.tcx.sess.span_err( + span, + &format!("a value of type `{}` is borrowed for too long", + self.ty_to_string(ty))); + self.tcx.note_and_explain_region("the type is valid for ", sub, ""); + self.tcx.note_and_explain_region("but the borrow lasts for ", sup, ""); + } infer::ReferenceOutlivesReferent(ty, span) => { self.tcx.sess.span_err( span, @@ -1567,6 +1601,9 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) { match *origin { + infer::RFC1214Subregion(ref suborigin) => { + self.note_region_origin(suborigin); + } infer::Subtype(ref trace) => { let desc = match trace.origin { infer::Misc(_) => { @@ -1714,6 +1751,17 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { span, "...so that variable is valid at time of its declaration"); } + infer::ParameterInScope(_, span) => { + self.tcx.sess.span_note( + span, + &format!("...so that a type/lifetime parameter is in scope here")); + } + infer::DataBorrowed(ty, span) => { + self.tcx.sess.span_note( + span, + &format!("...so that the type `{}` is not borrowed for too long", + self.ty_to_string(ty))); + } infer::ReferenceOutlivesReferent(ty, span) => { self.tcx.sess.span_note( span, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index f63154af72426..578b39af88cb4 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -17,7 +17,7 @@ pub use self::TypeOrigin::*; pub use self::ValuePairs::*; pub use middle::ty::IntVarValue; pub use self::freshen::TypeFreshener; -pub use self::region_inference::GenericKind; +pub use self::region_inference::{GenericKind, VerifyBound}; use middle::free_region::FreeRegionMap; use middle::mem_categorization as mc; @@ -35,6 +35,7 @@ use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell, Ref}; use std::fmt; +use std::rc::Rc; use syntax::ast; use syntax::codemap; use syntax::codemap::{Span, DUMMY_SP}; @@ -188,6 +189,11 @@ pub struct TypeTrace<'tcx> { /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] pub enum SubregionOrigin<'tcx> { + // Marker to indicate a constraint that only arises due to new + // provisions from RFC 1214. This will result in a warning, not an + // error. + RFC1214Subregion(Rc>), + // Arose from a subtyping relation Subtype(TypeTrace<'tcx>), @@ -229,9 +235,15 @@ pub enum SubregionOrigin<'tcx> { // Creating a pointer `b` to contents of an upvar ReborrowUpvar(Span, ty::UpvarId), + // Data with type `Ty<'tcx>` was borrowed + DataBorrowed(Ty<'tcx>, Span), + // (&'a &'b T) where a >= b ReferenceOutlivesReferent(Ty<'tcx>, Span), + // Type or region parameters must be in scope. + ParameterInScope(ParameterOrigin, Span), + // The type T of an expression E must outlive the lifetime for E. ExprTypeIsNotInScope(Ty<'tcx>, Span), @@ -260,6 +272,15 @@ pub enum SubregionOrigin<'tcx> { SafeDestructor(Span), } +/// Places that type/region parameters can appear. +#[derive(Clone, Copy, Debug)] +pub enum ParameterOrigin { + Path, // foo::bar + MethodCall, // foo.bar() <-- parameters on impl providing bar() + OverloadedOperator, // a + b when overloaded + OverloadedDeref, // *a when overloaded +} + /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -1398,13 +1419,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, a: ty::Region, - bs: Vec) { + bound: VerifyBound) { debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, - bs); + bound); - self.region_vars.verify_generic_bound(origin, kind, a, bs); + self.region_vars.verify_generic_bound(origin, kind, a, bound); } pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx> @@ -1565,6 +1586,7 @@ impl TypeOrigin { impl<'tcx> SubregionOrigin<'tcx> { pub fn span(&self) -> Span { match *self { + RFC1214Subregion(ref a) => a.span(), Subtype(ref a) => a.span(), InfStackClosure(a) => a, InvokeClosure(a) => a, @@ -1577,7 +1599,9 @@ impl<'tcx> SubregionOrigin<'tcx> { RelateDefaultParamBound(a, _) => a, Reborrow(a) => a, ReborrowUpvar(a, _) => a, + DataBorrowed(_, a) => a, ReferenceOutlivesReferent(_, a) => a, + ParameterInScope(_, a) => a, ExprTypeIsNotInScope(_, a) => a, BindingTypeIsNotValidAtDecl(a) => a, CallRcvr(a) => a, diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index 4b62c7beab002..e8f8dbfbb0e63 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -64,15 +64,41 @@ pub enum Verify<'tcx> { // outlive `RS`. Therefore verify that `R <= RS[i]` for some // `i`. Inference variables may be involved (but this verification // step doesn't influence inference). - VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec), + VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, VerifyBound), } -#[derive(Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] pub enum GenericKind<'tcx> { Param(ty::ParamTy), Projection(ty::ProjectionTy<'tcx>), } +// When we introduce a verification step, we wish to test that a +// particular region (let's call it `'min`) meets some bound. +// The bound is described the by the following grammar: +#[derive(Debug)] +pub enum VerifyBound { + // B = exists {R} --> some 'r in {R} must outlive 'min + // + // Put another way, the subject value is known to outlive all + // regions in {R}, so if any of those outlives 'min, then the + // bound is met. + AnyRegion(Vec), + + // B = forall {R} --> all 'r in {R} must outlive 'min + // + // Put another way, the subject value is known to outlive some + // region in {R}, so if all of those outlives 'min, then the bound + // is met. + AllRegions(Vec), + + // B = exists {B} --> 'min must meet some bound b in {B} + AnyBound(Vec), + + // B = forall {B} --> 'min must meet all bounds b in {B} + AllBounds(Vec), +} + #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct TwoRegions { a: Region, @@ -102,12 +128,11 @@ pub enum RegionResolutionError<'tcx> { /// `o` requires that `a <= b`, but this does not hold ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), - /// `GenericBoundFailure(p, s, a, bs) + /// `GenericBoundFailure(p, s, a) /// /// The parameter/associated-type `p` must be known to outlive the lifetime - /// `a`, but it is only known to outlive `bs` (and none of the - /// regions in `bs` outlive `a`). - GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region, Vec), + /// `a` (but none of the known bounds are sufficient). + GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region), /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: /// @@ -408,6 +433,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { debug!("RegionVarBindings: add_verify({:?})", verify); + // skip no-op cases known to be satisfied + match verify { + VerifyGenericBound(_, _, _, VerifyBound::AllBounds(ref bs)) if bs.len() == 0 => { + return; + } + _ => { } + } + let mut verifys = self.verifys.borrow_mut(); let index = verifys.len(); verifys.push(verify); @@ -497,8 +530,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, sub: Region, - sups: Vec) { - self.add_verify(VerifyGenericBound(kind, origin, sub, sups)); + bound: VerifyBound) { + self.add_verify(VerifyGenericBound(kind, origin, sub, bound)); } pub fn lub_regions(&self, @@ -663,12 +696,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { &mut result_set, r, a, b); } - VerifyGenericBound(_, _, a, ref bs) => { - for &b in bs { - consider_adding_bidirectional_edges( - &mut result_set, r, - a, b); - } + VerifyGenericBound(_, _, a, ref bound) => { + bound.for_each_region(&mut |b| { + consider_adding_bidirectional_edges(&mut result_set, r, + a, b) + }); } } } @@ -1258,26 +1290,22 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { continue; } - debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}", - sub, - sup); + debug!("region inference error at {:?}: {:?} <= {:?} is not true", + origin, sub, sup); + errors.push(ConcreteFailure((*origin).clone(), sub, sup)); } - VerifyGenericBound(ref kind, ref origin, sub, ref sups) => { + VerifyGenericBound(ref kind, ref origin, sub, ref bound) => { let sub = normalize(values, sub); - if sups.iter() - .map(|&sup| normalize(values, sup)) - .any(|sup| free_regions.is_subregion_of(self.tcx, sub, sup)) - { + if bound.is_met(self.tcx, free_regions, values, sub) { continue; } - let sups = sups.iter().map(|&sup| normalize(values, sup)) - .collect(); - errors.push( - GenericBoundFailure( - (*origin).clone(), kind.clone(), sub, sups)); + debug!("region inference error at {:?}: verifying {:?} <= {:?}", + origin, sub, bound); + + errors.push(GenericBoundFailure((*origin).clone(), kind.clone(), sub)); } } } @@ -1438,10 +1466,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) { - debug!("pushing SubSupConflict sub: {:?} sup: {:?}", - lower_bound.region, upper_bound.region); + let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); + debug!("region inference error at {:?} for {:?}: \ + SubSupConflict sub: {:?} sup: {:?}", + origin, node_idx, lower_bound.region, upper_bound.region); errors.push(SubSupConflict( - (*self.var_origins.borrow())[node_idx.index as usize].clone(), + origin, lower_bound.origin.clone(), lower_bound.region, upper_bound.origin.clone(), @@ -1484,16 +1514,20 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { match self.glb_concrete_regions(free_regions, upper_bound_1.region, upper_bound_2.region) { - Ok(_) => {} - Err(_) => { - errors.push(SupSupConflict( - (*self.var_origins.borrow())[node_idx.index as usize].clone(), - upper_bound_1.origin.clone(), - upper_bound_1.region, - upper_bound_2.origin.clone(), - upper_bound_2.region)); - return; - } + Ok(_) => {} + Err(_) => { + let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); + debug!("region inference error at {:?} for {:?}: \ + SupSupConflict sub: {:?} sup: {:?}", + origin, node_idx, upper_bound_1.region, upper_bound_2.region); + errors.push(SupSupConflict( + origin, + upper_bound_1.origin.clone(), + upper_bound_1.region, + upper_bound_2.origin.clone(), + upper_bound_2.region)); + return; + } } } } @@ -1676,3 +1710,82 @@ impl<'tcx> GenericKind<'tcx> { } } } + +impl VerifyBound { + fn for_each_region(&self, f: &mut FnMut(ty::Region)) { + match self { + &VerifyBound::AnyRegion(ref rs) | + &VerifyBound::AllRegions(ref rs) => + for &r in rs { f(r); }, + + &VerifyBound::AnyBound(ref bs) | + &VerifyBound::AllBounds(ref bs) => + for b in bs { b.for_each_region(f); }, + } + } + + pub fn must_hold(&self) -> bool { + match self { + &VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic), + &VerifyBound::AllRegions(ref bs) => bs.is_empty(), + &VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()), + &VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()), + } + } + + pub fn cannot_hold(&self) -> bool { + match self { + &VerifyBound::AnyRegion(ref bs) => bs.is_empty(), + &VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty), + &VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()), + &VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()), + } + } + + pub fn or(self, vb: VerifyBound) -> VerifyBound { + if self.must_hold() || vb.cannot_hold() { + self + } else if self.cannot_hold() || vb.must_hold() { + vb + } else { + VerifyBound::AnyBound(vec![self, vb]) + } + } + + pub fn and(self, vb: VerifyBound) -> VerifyBound { + if self.must_hold() && vb.must_hold() { + self + } else if self.cannot_hold() && vb.cannot_hold() { + self + } else { + VerifyBound::AllBounds(vec![self, vb]) + } + } + + fn is_met<'tcx>(&self, + tcx: &ty::ctxt<'tcx>, + free_regions: &FreeRegionMap, + var_values: &Vec, + min: ty::Region) + -> bool { + match self { + &VerifyBound::AnyRegion(ref rs) => + rs.iter() + .map(|&r| normalize(var_values, r)) + .any(|r| free_regions.is_subregion_of(tcx, min, r)), + + &VerifyBound::AllRegions(ref rs) => + rs.iter() + .map(|&r| normalize(var_values, r)) + .all(|r| free_regions.is_subregion_of(tcx, min, r)), + + &VerifyBound::AnyBound(ref bs) => + bs.iter() + .any(|b| b.is_met(tcx, free_regions, var_values, min)), + + &VerifyBound::AllBounds(ref bs) => + bs.iter() + .all(|b| b.is_met(tcx, free_regions, var_values, min)), + } + } +} diff --git a/src/librustc/middle/outlives.rs b/src/librustc/middle/outlives.rs new file mode 100644 index 0000000000000..9a2570d710d38 --- /dev/null +++ b/src/librustc/middle/outlives.rs @@ -0,0 +1,231 @@ +// 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. + +// The outlines relation `T: 'a` or `'a: 'b`. This code frequently +// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that +// RFC for reference. + +use middle::infer::InferCtxt; +use middle::ty::{self, RegionEscape, Ty}; + +#[derive(Debug)] +pub enum Component<'tcx> { + Region(ty::Region), + Param(ty::ParamTy), + UnresolvedInferenceVariable(ty::InferTy), + + // Projections like `T::Foo` are tricky because a constraint like + // `T::Foo: 'a` can be satisfied in so many ways. There may be a + // where-clause that says `T::Foo: 'a`, or the defining trait may + // include a bound like `type Foo: 'static`, or -- in the most + // conservative way -- we can prove that `T: 'a` (more generally, + // that all components in the projection outlive `'a`). This code + // is not in a position to judge which is the best technique, so + // we just product the projection as a component and leave it to + // the consumer to decide (but see `EscapingProjection` below). + Projection(ty::ProjectionTy<'tcx>), + + // In the case where a projection has escaping regions -- meaning + // regions bound within the type itself -- we always use + // the most conservative rule, which requires that all components + // outlive the bound. So for example if we had a type like this: + // + // for<'a> Trait1< >::Foo > + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // + // then the inner projection (underlined) has an escaping region + // `'a`. We consider that outer trait `'c` to meet a bound if `'b` + // outlives `'b: 'c`, and we don't consider whether the trait + // declares that `Foo: 'static` etc. Therefore, we just return the + // free components of such a projection (in this case, `'b`). + // + // However, in the future, we may want to get smarter, and + // actually return a "higher-ranked projection" here. Therefore, + // we mark that these components are part of an escaping + // projection, so that implied bounds code can avoid relying on + // them. This gives us room to improve the regionck reasoning in + // the future without breaking backwards compat. + EscapingProjection(Vec>), + + // This is a temporary marker indicating "outlives components" + // that are due to the new rules introduced by RFC 1214. For the + // time being, violations of these requirements generally induce + // warnings, not errors. + RFC1214(Vec>), +} + +/// Returns all the things that must outlive `'a` for the condition +/// `ty0: 'a` to hold. +pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty0: Ty<'tcx>) + -> Vec> { + let mut components = vec![]; + compute_components(infcx, ty0, &mut components); + debug!("components({:?}) = {:?}", ty0, components); + components +} + +fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>, + out: &mut Vec>) { + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match ty.sty { + ty::TyClosure(_, ref substs) => { + // FIXME(#27086). We do not accumulate from substs, since they + // don't represent reachable data. This means that, in + // practice, some of the lifetime parameters might not + // be in scope when the body runs, so long as there is + // no reachable data with that lifetime. For better or + // worse, this is consistent with fn types, however, + // which can also encapsulate data in this fashion + // (though it's somewhat harder, and typically + // requires virtual dispatch). + // + // Note that changing this (in a naive way, at least) + // causes regressions for what appears to be perfectly + // reasonable code like this: + // + // ``` + // fn foo<'a>(p: &Data<'a>) { + // bar(|q: &mut Parser| q.read_addr()) + // } + // fn bar(p: Box) { + // } + // ``` + // + // Note that `p` (and `'a`) are not used in the + // closure at all, but to meet the requirement that + // the closure type `C: 'static` (so it can be coerced + // to the object type), we get the requirement that + // `'a: 'static` since `'a` appears in the closure + // type `C`. + // + // A smarter fix might "prune" unused `func_substs` -- + // this would avoid breaking simple examples like + // this, but would still break others (which might + // indeed be invalid, depending on your POV). Pruning + // would be a subtle process, since we have to see + // what func/type parameters are used and unused, + // taking into consideration UFCS and so forth. + + for &upvar_ty in &substs.upvar_tys { + compute_components(infcx, upvar_ty, out); + } + } + + // Bare functions and traits are both binders. In the RFC, + // this means we would add the bound regions to the "bound + // regions list". In our representation, no such list is + // maintained explicitly, because bound regions themselves can + // be readily identified. However, because the outlives + // relation did not used to be applied to fn/trait-object + // arguments, we wrap the resulting components in an RFC1214 + // wrapper so we can issue warnings. + ty::TyBareFn(..) | ty::TyTrait(..) => { + // OutlivesFunction, OutlivesObject, OutlivesFragment + let subcomponents = capture_components(infcx, ty); + out.push(Component::RFC1214(subcomponents)); + } + + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::TyParam(p) => { + out.push(Component::Param(p)); + } + + // For projections, we prefer to generate an obligation like + // `>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranke regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::TyProjection(ref data) => { + if !data.has_escaping_regions() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Projection(*data)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let subcomponents = capture_components(infcx, ty); + out.push(Component::EscapingProjection(subcomponents)); + } + } + + // If we encounter an inference variable, try to resolve it + // and proceed with resolved version. If we cannot resolve it, + // then record the unresolved variable as a component. + ty::TyInfer(_) => { + let ty = infcx.resolve_type_vars_if_possible(&ty); + if let ty::TyInfer(infer_ty) = ty.sty { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } else { + compute_components(infcx, ty, out); + } + } + + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + ty::TyBool(..) | // OutlivesScalar + ty::TyChar(..) | // OutlivesScalar + ty::TyInt(..) | // OutlivesScalar + ty::TyUint(..) | // OutlivesScalar + ty::TyFloat(..) | // OutlivesScalar + ty::TyEnum(..) | // OutlivesNominalType + ty::TyStruct(..) | // OutlivesNominalType + ty::TyBox(..) | // OutlivesNominalType (ish) + ty::TyStr(..) | // OutlivesScalar (ish) + ty::TyArray(..) | // ... + ty::TySlice(..) | // ... + ty::TyRawPtr(..) | // ... + ty::TyRef(..) | // OutlivesReference + ty::TyTuple(..) | // ... + ty::TyError(..) => { + push_region_constraints(out, ty.regions()); + for subty in ty.walk_shallow() { + compute_components(infcx, subty, out); + } + } + } +} + +fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + ty: Ty<'tcx>) + -> Vec> { + let mut temp = vec![]; + push_region_constraints(&mut temp, ty.regions()); + for subty in ty.walk_shallow() { + compute_components(infcx, subty, &mut temp); + } + temp +} + +fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec) { + for r in regions { + if !r.is_bound() { + out.push(Component::Region(r)); + } + } +} diff --git a/src/librustc/middle/traits/error_reporting.rs b/src/librustc/middle/traits/error_reporting.rs index 1f79db9e5232b..467c752499b36 100644 --- a/src/librustc/middle/traits/error_reporting.rs +++ b/src/librustc/middle/traits/error_reporting.rs @@ -25,11 +25,12 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use middle::infer::InferCtxt; -use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef}; +use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty}; use middle::ty_fold::TypeFoldable; use std::collections::HashMap; use std::fmt; use syntax::codemap::Span; +use syntax::ast; use syntax::attr::{AttributeMethods, AttrMetaMethods}; pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, @@ -54,22 +55,28 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } +fn is_warning(obligation: &Obligation) -> bool { + obligation.cause.code.is_rfc1214() +} + pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>) { let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate); + // The TyError created by normalize_to_error can end up being unified // into all obligations: for example, if our obligation is something // like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>, // then $X will be unified with TyError, but the error still needs to be // reported. if !infcx.tcx.sess.has_errors() || !predicate.references_error() { - span_err!(infcx.tcx.sess, obligation.cause.span, E0271, - "type mismatch resolving `{}`: {}", - predicate, - error.err); + span_err_or_warn!( + is_warning(obligation), infcx.tcx.sess, obligation.cause.span, E0271, + "type mismatch resolving `{}`: {}", + predicate, + error.err); note_obligation_cause(infcx, obligation); } } @@ -173,66 +180,90 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, obligation: &PredicateObligation<'tcx>, error: &SelectionError<'tcx>) { + let is_warning = is_warning(obligation); match *error { SelectionError::Unimplemented => { - match &obligation.cause.code { - &ObligationCauseCode::CompareImplMethodObligation => { - span_err!(infcx.tcx.sess, obligation.cause.span, E0276, - "the requirement `{}` appears on the impl \ - method but not on the corresponding trait method", - obligation.predicate);; - } - _ => { - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { - let trait_predicate = - infcx.resolve_type_vars_if_possible(trait_predicate); - - if !infcx.tcx.sess.has_errors() || - !trait_predicate.references_error() { - let trait_ref = trait_predicate.to_poly_trait_ref(); - span_err!(infcx.tcx.sess, obligation.cause.span, E0277, - "the trait `{}` is not implemented for the type `{}`", - trait_ref, - trait_ref.self_ty()); - // Check if it has a custom "#[rustc_on_unimplemented]" - // error message, report with that message if it does - let custom_note = report_on_unimplemented(infcx, &trait_ref.0, - obligation.cause.span); - if let Some(s) = custom_note { - infcx.tcx.sess.span_note(obligation.cause.span, - &s); - } + if let ObligationCauseCode::CompareImplMethodObligation = obligation.cause.code { + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0276, + "the requirement `{}` appears on the impl \ + method but not on the corresponding trait method", + obligation.predicate);; + } else { + match obligation.predicate { + ty::Predicate::Trait(ref trait_predicate) => { + let trait_predicate = + infcx.resolve_type_vars_if_possible(trait_predicate); + + if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() { + let trait_ref = trait_predicate.to_poly_trait_ref(); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0277, + "the trait `{}` is not implemented for the type `{}`", + trait_ref, trait_ref.self_ty()); + + // Check if it has a custom "#[rustc_on_unimplemented]" + // error message, report with that message if it does + let custom_note = report_on_unimplemented(infcx, &trait_ref.0, + obligation.cause.span); + if let Some(s) = custom_note { + infcx.tcx.sess.span_note(obligation.cause.span, &s); } + note_obligation_cause(infcx, obligation); } + } - ty::Predicate::Equate(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.equality_predicate(obligation.cause.span, - &predicate).err().unwrap(); - span_err!(infcx.tcx.sess, obligation.cause.span, E0278, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err); - } + ty::Predicate::Equate(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.equality_predicate(obligation.cause.span, + &predicate).err().unwrap(); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0278, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err); + note_obligation_cause(infcx, obligation); + } - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = infcx.resolve_type_vars_if_possible(predicate); - let err = infcx.region_outlives_predicate(obligation.cause.span, - &predicate).err().unwrap(); - span_err!(infcx.tcx.sess, obligation.cause.span, E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err); - } + ty::Predicate::RegionOutlives(ref predicate) => { + let predicate = infcx.resolve_type_vars_if_possible(predicate); + let err = infcx.region_outlives_predicate(obligation.cause.span, + &predicate).err().unwrap(); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0279, + "the requirement `{}` is not satisfied (`{}`)", + predicate, + err); + note_obligation_cause(infcx, obligation); + } - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = - infcx.resolve_type_vars_if_possible(&obligation.predicate); - span_err!(infcx.tcx.sess, obligation.cause.span, E0280, - "the requirement `{}` is not satisfied", - predicate); - } + ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + let predicate = + infcx.resolve_type_vars_if_possible(&obligation.predicate); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0280, + "the requirement `{}` is not satisfied", + predicate); + note_obligation_cause(infcx, obligation); + } + + ty::Predicate::ObjectSafe(trait_def_id) => { + report_object_safety_error(infcx.tcx, + obligation.cause.span, + trait_def_id, + is_warning); + note_obligation_cause(infcx, obligation); + } + + ty::Predicate::WellFormed(ty) => { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + infcx.tcx.sess.span_bug( + obligation.cause.span, + &format!("WF predicate not satisfied for {:?}", ty)); } } } @@ -242,62 +273,73 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, let expected_trait_ref = infcx.resolve_type_vars_if_possible(&*expected_trait_ref); let actual_trait_ref = infcx.resolve_type_vars_if_possible(&*actual_trait_ref); if !actual_trait_ref.self_ty().references_error() { - span_err!(infcx.tcx.sess, obligation.cause.span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty(), - expected_trait_ref, - actual_trait_ref, - e); - note_obligation_cause(infcx, obligation); + span_err_or_warn!( + is_warning, infcx.tcx.sess, obligation.cause.span, E0281, + "type mismatch: the type `{}` implements the trait `{}`, \ + but the trait `{}` is required ({})", + expected_trait_ref.self_ty(), + expected_trait_ref, + actual_trait_ref, + e); + note_obligation_cause(infcx, obligation); } } TraitNotObjectSafe(did) => { - span_err!(infcx.tcx.sess, obligation.cause.span, E0038, - "cannot convert to a trait object because trait `{}` is not object-safe", - infcx.tcx.item_path_str(did)); - - for violation in object_safety_violations(infcx.tcx, did) { - match violation { - ObjectSafetyViolation::SizedSelf => { - infcx.tcx.sess.span_note( - obligation.cause.span, - "the trait cannot require that `Self : Sized`"); - } + report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning); + note_obligation_cause(infcx, obligation); + } + } +} - ObjectSafetyViolation::SupertraitSelf => { - infcx.tcx.sess.span_note( - obligation.cause.span, - "the trait cannot use `Self` as a type parameter \ - in the supertrait listing"); - } +pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>, + span: Span, + trait_def_id: ast::DefId, + is_warning: bool) +{ + span_err_or_warn!( + is_warning, tcx.sess, span, E0038, + "the trait `{}` cannot be made into an object", + tcx.item_path_str(trait_def_id)); - ObjectSafetyViolation::Method(method, - MethodViolationCode::StaticMethod) => { - infcx.tcx.sess.span_note( - obligation.cause.span, - &format!("method `{}` has no receiver", - method.name)); - } + for violation in object_safety_violations(tcx, trait_def_id) { + match violation { + ObjectSafetyViolation::SizedSelf => { + tcx.sess.span_note( + span, + "the trait cannot require that `Self : Sized`"); + } - ObjectSafetyViolation::Method(method, - MethodViolationCode::ReferencesSelf) => { - infcx.tcx.sess.span_note( - obligation.cause.span, - &format!("method `{}` references the `Self` type \ - in its arguments or return type", - method.name)); - } + ObjectSafetyViolation::SupertraitSelf => { + tcx.sess.span_note( + span, + "the trait cannot use `Self` as a type parameter \ + in the supertrait listing"); + } - ObjectSafetyViolation::Method(method, - MethodViolationCode::Generic) => { - infcx.tcx.sess.span_note( - obligation.cause.span, - &format!("method `{}` has generic type parameters", - method.name)); - } - } + ObjectSafetyViolation::Method(method, + MethodViolationCode::StaticMethod) => { + tcx.sess.span_note( + span, + &format!("method `{}` has no receiver", + method.name)); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::ReferencesSelf) => { + tcx.sess.span_note( + span, + &format!("method `{}` references the `Self` type \ + in its arguments or return type", + method.name)); + } + + ObjectSafetyViolation::Method(method, + MethodViolationCode::Generic) => { + tcx.sess.span_note( + span, + &format!("method `{}` has generic type parameters", + method.name)); } } } @@ -342,14 +384,11 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, infcx.tcx.lang_items.sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - span_err!(infcx.tcx.sess, obligation.cause.span, E0282, - "unable to infer enough type information about `{}`; \ - type annotations or generic parameter binding required", - self_ty); + need_type_info(infcx, obligation.cause.span, self_ty); } else { span_err!(infcx.tcx.sess, obligation.cause.span, E0283, "type annotations required: cannot resolve `{}`", - predicate);; + predicate); note_obligation_cause(infcx, obligation); } } @@ -366,6 +405,14 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } + ty::Predicate::WellFormed(ty) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if !ty.references_error() && !infcx.tcx.sess.has_errors() { + need_type_info(infcx, obligation.cause.span, ty); + } + } + _ => { if !infcx.tcx.sess.has_errors() { span_err!(infcx.tcx.sess, obligation.cause.span, E0284, @@ -377,6 +424,16 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, } } +fn need_type_info<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) +{ + span_err!(infcx.tcx.sess, span, E0282, + "unable to infer enough type information about `{}`; \ + type annotations or generic parameter binding required", + ty); +} + fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, obligation: &Obligation<'tcx, T>) where T: fmt::Display @@ -396,6 +453,27 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, let tcx = infcx.tcx; match *cause_code { ObligationCauseCode::MiscObligation => { } + ObligationCauseCode::RFC1214(ref subcode) => { + tcx.sess.note_rfc_1214(cause_span); + note_obligation_cause_code(infcx, predicate, cause_span, subcode); + } + ObligationCauseCode::SliceOrArrayElem => { + tcx.sess.span_note( + cause_span, + &format!("slice and array elements must have `Sized` type")); + } + ObligationCauseCode::ProjectionWf(data) => { + tcx.sess.span_note( + cause_span, + &format!("required so that the projection `{}` is well-formed", + data)); + } + ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { + tcx.sess.span_note( + cause_span, + &format!("required so that reference `{}` does not outlive its referent", + ref_ty)); + } ObligationCauseCode::ItemObligation(item_def_id) => { let item_name = tcx.item_path_str(item_def_id); tcx.sess.span_note( diff --git a/src/librustc/middle/traits/fulfill.rs b/src/librustc/middle/traits/fulfill.rs index 44fc6b6b8abdc..1fca66f137918 100644 --- a/src/librustc/middle/traits/fulfill.rs +++ b/src/librustc/middle/traits/fulfill.rs @@ -10,6 +10,7 @@ use middle::infer::InferCtxt; use middle::ty::{self, RegionEscape, Ty, HasTypeFlags}; +use middle::wf; use std::collections::HashSet; use std::fmt; @@ -20,16 +21,19 @@ use util::nodemap::NodeMap; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; +use super::is_object_safe; use super::FulfillmentError; use super::ObligationCause; +use super::ObligationCauseCode; use super::PredicateObligation; use super::project; +use super::RFC1214Warning; use super::select::SelectionContext; use super::Unimplemented; use super::util::predicate_for_builtin_bound; pub struct FulfilledPredicates<'tcx> { - set: HashSet> + set: HashSet<(RFC1214Warning, ty::Predicate<'tcx>)> } /// The fulfillment context is used to drive trait resolution. It @@ -187,7 +191,9 @@ impl<'tcx> FulfillmentContext<'tcx> { assert!(!obligation.has_escaping_regions()); - if self.is_duplicate_or_add(infcx.tcx, &obligation.predicate) { + let w = RFC1214Warning(obligation.cause.code.is_rfc1214()); + + if self.is_duplicate_or_add(infcx.tcx, w, &obligation.predicate) { debug!("register_predicate({:?}) -- already seen, skip", obligation); return; } @@ -250,7 +256,9 @@ impl<'tcx> FulfillmentContext<'tcx> { &self.predicates } - fn is_duplicate_or_add(&mut self, tcx: &ty::ctxt<'tcx>, + fn is_duplicate_or_add(&mut self, + tcx: &ty::ctxt<'tcx>, + w: RFC1214Warning, predicate: &ty::Predicate<'tcx>) -> bool { // This is a kind of dirty hack to allow us to avoid "rederiving" @@ -265,10 +273,12 @@ impl<'tcx> FulfillmentContext<'tcx> { // evaluating the 'nested obligations'. This cache lets us // skip those. - if self.errors_will_be_reported && predicate.is_global() { - tcx.fulfilled_predicates.borrow_mut().is_duplicate_or_add(predicate) + let will_warn_due_to_rfc1214 = w.0; + let errors_will_be_reported = self.errors_will_be_reported && !will_warn_due_to_rfc1214; + if errors_will_be_reported && predicate.is_global() { + tcx.fulfilled_predicates.borrow_mut().is_duplicate_or_add(w, predicate) } else { - self.duplicate_set.is_duplicate_or_add(predicate) + self.duplicate_set.is_duplicate_or_add(w, predicate) } } @@ -472,6 +482,32 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, } } } + + ty::Predicate::ObjectSafe(trait_def_id) => { + if !is_object_safe(selcx.tcx(), trait_def_id) { + errors.push(FulfillmentError::new( + obligation.clone(), + CodeSelectionError(Unimplemented))); + } + true + } + + ty::Predicate::WellFormed(ty) => { + let rfc1214 = match obligation.cause.code { + ObligationCauseCode::RFC1214(_) => true, + _ => false, + }; + match wf::obligations(selcx.infcx(), obligation.cause.body_id, + ty, obligation.cause.span, rfc1214) { + Some(obligations) => { + new_obligations.extend(obligations); + true + } + None => { + false + } + } + } } } @@ -492,11 +528,12 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, sub_region: r_b, cause: cause }; - debug!("register_region_obligation({:?})", - region_obligation); + debug!("register_region_obligation({:?}, cause={:?})", + region_obligation, region_obligation.cause); - region_obligations.entry(region_obligation.cause.body_id).or_insert(vec![]) - .push(region_obligation); + region_obligations.entry(region_obligation.cause.body_id) + .or_insert(vec![]) + .push(region_obligation); } @@ -507,11 +544,13 @@ impl<'tcx> FulfilledPredicates<'tcx> { } } - pub fn is_duplicate(&self, p: &ty::Predicate<'tcx>) -> bool { - self.set.contains(p) + pub fn is_duplicate(&self, w: RFC1214Warning, p: &ty::Predicate<'tcx>) -> bool { + let key = (w, p.clone()); + self.set.contains(&key) } - fn is_duplicate_or_add(&mut self, p: &ty::Predicate<'tcx>) -> bool { - !self.set.insert(p.clone()) + fn is_duplicate_or_add(&mut self, w: RFC1214Warning, p: &ty::Predicate<'tcx>) -> bool { + let key = (w, p.clone()); + !self.set.insert(key) } } diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 376430e87c6f0..6c501b1a609c4 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -27,6 +27,7 @@ use syntax::codemap::{Span, DUMMY_SP}; pub use self::error_reporting::report_fulfillment_errors; pub use self::error_reporting::report_overflow_error; pub use self::error_reporting::report_selection_error; +pub use self::error_reporting::report_object_safety_error; pub use self::error_reporting::suggest_new_overflow_limit; pub use self::coherence::orphan_check; pub use self::coherence::overlapping_impls; @@ -80,7 +81,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; /// Why did we incur this obligation? Used for error reporting. -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct ObligationCause<'tcx> { pub span: Span, @@ -95,15 +96,27 @@ pub struct ObligationCause<'tcx> { pub code: ObligationCauseCode<'tcx> } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from span. MiscObligation, + /// Obligation that triggers warning until RFC 1214 is fully in place. + RFC1214(Rc>), + + /// This is the trait reference from the given projection + SliceOrArrayElem, + + /// This is the trait reference from the given projection + ProjectionWf(ty::ProjectionTy<'tcx>), + /// In an impl of trait X for type Y, type Y must /// also implement all supertraits of X. ItemObligation(ast::DefId), + /// A type like `&'a T` is WF only if `T: 'a`. + ReferenceOutlivesReferent(Ty<'tcx>), + /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), @@ -124,7 +137,6 @@ pub enum ObligationCauseCode<'tcx> { // static items must have `Sync` type SharedStatic, - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), ImplDerivedObligation(DerivedObligationCause<'tcx>), @@ -132,7 +144,7 @@ pub enum ObligationCauseCode<'tcx> { CompareImplMethodObligation, } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct DerivedObligationCause<'tcx> { /// The trait reference of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to @@ -516,6 +528,24 @@ impl<'tcx> ObligationCause<'tcx> { } } +/// This marker is used in some caches to record whether the +/// predicate, if it is found to be false, will yield a warning (due +/// to RFC1214) or an error. We separate these two cases in the cache +/// so that if we see the same predicate twice, first resulting in a +/// warning, and next resulting in an error, we still report the +/// error, rather than considering it a duplicate. +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +pub struct RFC1214Warning(bool); + +impl<'tcx> ObligationCauseCode<'tcx> { + pub fn is_rfc1214(&self) -> bool { + match *self { + ObligationCauseCode::RFC1214(..) => true, + _ => false, + } + } +} + impl<'tcx, N> Vtable<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index e7f11b06bd132..9d300c0973167 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -40,7 +40,7 @@ pub enum ObjectSafetyViolation<'tcx> { } /// Reasons a method might not be object-safe. -#[derive(Copy,Clone,Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum MethodViolationCode { /// e.g., `fn foo()` StaticMethod, @@ -140,6 +140,8 @@ fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>, .any(is_self) } ty::Predicate::Projection(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::Equate(..) => { @@ -181,6 +183,8 @@ fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>, ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) => { false } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 0c9cf1a68b732..f63523b77d60f 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -27,6 +27,7 @@ use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; use super::{ObjectCastObligation, Obligation}; use super::TraitNotObjectSafe; +use super::RFC1214Warning; use super::Selection; use super::SelectionResult; use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, @@ -44,6 +45,7 @@ use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; use middle::ty_match; use middle::ty_relate::TypeRelation; +use middle::wf; use std::cell::RefCell; use std::fmt; @@ -444,7 +446,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // have been proven elsewhere. This cache only contains // predicates that are global in scope and hence unaffected by // the current environment. - if self.tcx().fulfilled_predicates.borrow().is_duplicate(&obligation.predicate) { + let w = RFC1214Warning(false); + if self.tcx().fulfilled_predicates.borrow().is_duplicate(w, &obligation.predicate) { return EvaluatedToOk; } @@ -465,12 +468,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::Predicate::WellFormed(ty) => { + match wf::obligations(self.infcx, obligation.cause.body_id, + ty, obligation.cause.span, + obligation.cause.code.is_rfc1214()) { + Some(obligations) => + self.evaluate_predicates_recursively(previous_stack, obligations.iter()), + None => + EvaluatedToAmbig, + } + } + ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { // we do not consider region relationships when // evaluating trait matches EvaluatedToOk } + ty::Predicate::ObjectSafe(trait_def_id) => { + if object_safety::is_object_safe(self.tcx(), trait_def_id) { + EvaluatedToOk + } else { + EvaluatedToErr(Unimplemented) + } + } + ty::Predicate::Projection(ref data) => { self.infcx.probe(|_| { let project_obligation = obligation.with(data.clone()); @@ -2900,13 +2922,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // chain. Ideally, we should have a way to configure this either // by using -Z verbose or just a CLI argument. if obligation.recursion_depth >= 0 { - let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()), + let derived_code = match obligation.cause.code { + ObligationCauseCode::RFC1214(ref base_code) => { + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: base_code.clone(), + }; + ObligationCauseCode::RFC1214(Rc::new(variant(derived_cause))) + } + _ => { + let derived_cause = DerivedObligationCause { + parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_code: Rc::new(obligation.cause.code.clone()) + }; + variant(derived_cause) + } }; - ObligationCause::new(obligation.cause.span, - obligation.cause.body_id, - variant(derived_cause)) + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) } else { obligation.cause.clone() } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index af9d5e5157d28..6df13a3bdaf55 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -10,7 +10,7 @@ use middle::subst::Substs; use middle::infer::InferCtxt; -use middle::ty::{self, Ty, ToPredicate, ToPolyTraitRef}; +use middle::ty::{self, HasTypeFlags, Ty, ToPredicate, ToPolyTraitRef}; use std::fmt; use syntax::ast; use syntax::codemap::Span; @@ -56,6 +56,12 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> { 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), }; self.set.insert(normalized_pred) } @@ -136,6 +142,14 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> { self.stack.extend(predicates); } + ty::Predicate::WellFormed(..) => { + // Currently, we do not elaborate WF predicates, + // although we easily could. + } + ty::Predicate::ObjectSafe(..) => { + // Currently, we do not elaborate object-safe + // predicates. + } ty::Predicate::Equate(..) => { // Currently, we do not "elaborate" predicates like // `X == Y`, though conceivably we might. For example, @@ -562,3 +576,9 @@ impl<'tcx> fmt::Debug for super::MismatchedProjectionTypes<'tcx> { write!(f, "MismatchedProjectionTypes({:?})", self.err) } } + +impl<'tcx, T: HasTypeFlags> HasTypeFlags for Obligation<'tcx, T> { + fn has_type_flags(&self, flags: ty::TypeFlags) -> bool { + self.predicate.has_type_flags(flags) + } +} diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2fe1f14d521ba..49bf0e580b9e0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1670,6 +1670,13 @@ impl Region { } } + pub fn needs_infer(&self) -> bool { + match *self { + ty::ReInfer(..) => true, + _ => false + } + } + pub fn escapes_depth(&self, depth: u32) -> bool { match *self { ty::ReLateBound(debruijn, _) => debruijn.depth > depth, @@ -2410,6 +2417,12 @@ pub enum Predicate<'tcx> { /// where ::Name == X, approximately. /// See `ProjectionPredicate` struct for details. Projection(PolyProjectionPredicate<'tcx>), + + /// no syntax: T WF + WellFormed(Ty<'tcx>), + + /// trait must be object-safe + ObjectSafe(ast::DefId), } impl<'tcx> Predicate<'tcx> { @@ -2495,6 +2508,10 @@ impl<'tcx> Predicate<'tcx> { Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), Predicate::Projection(ty::Binder(ref data)) => Predicate::Projection(ty::Binder(data.subst(tcx, substs))), + Predicate::WellFormed(data) => + Predicate::WellFormed(data.subst(tcx, substs)), + Predicate::ObjectSafe(trait_def_id) => + Predicate::ObjectSafe(trait_def_id), } } } @@ -2567,7 +2584,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::N`. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct ProjectionTy<'tcx> { /// The trait reference `T as Trait<..>`. pub trait_ref: ty::TraitRef<'tcx>, @@ -2682,6 +2699,12 @@ impl<'tcx> Predicate<'tcx> { .chain(Some(data.0.ty)) .collect() } + ty::Predicate::WellFormed(data) => { + vec![data] + } + ty::Predicate::ObjectSafe(_trait_def_id) => { + vec![] + } }; // The only reason to collect into a vector here is that I was @@ -2699,6 +2722,8 @@ impl<'tcx> Predicate<'tcx> { Predicate::RegionOutlives(ref p) => p.has_escaping_regions(), Predicate::TypeOutlives(ref p) => p.has_escaping_regions(), Predicate::Projection(ref p) => p.has_escaping_regions(), + Predicate::WellFormed(p) => p.has_escaping_regions(), + Predicate::ObjectSafe(_trait_def_id) => false, } } @@ -2710,6 +2735,8 @@ impl<'tcx> Predicate<'tcx> { Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | + Predicate::WellFormed(..) | + Predicate::ObjectSafe(..) | Predicate::TypeOutlives(..) => { None } @@ -2806,6 +2833,15 @@ pub struct ParameterEnvironment<'a, 'tcx:'a> { /// Caches the results of trait selection. This cache is used /// for things that have to do with the parameters in scope. pub selection_cache: traits::SelectionCache<'tcx>, + + /// Scope that is attached to free regions for this scope. This + /// is usually the id of the fn body, but for more abstract scopes + /// like structs we often use the node-id of the struct. + /// + /// FIXME(#3696). It would be nice to refactor so that free + /// regions don't have this implicit scope and instead introduce + /// relationships in the environment. + pub free_id: ast::NodeId, } impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { @@ -2819,6 +2855,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { implicit_region_bound: self.implicit_region_bound, caller_bounds: caller_bounds, selection_cache: traits::SelectionCache::new(), + free_id: self.free_id, } } @@ -2826,6 +2863,18 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match cx.map.find(id) { Some(ast_map::NodeImplItem(ref impl_item)) => { match impl_item.node { + ast::TypeImplItem(_) => { + // associated types don't have their own entry (for some reason), + // so for now just grab environment for the impl + let impl_id = cx.map.get_parent(id); + let impl_def_id = ast_util::local_def(impl_id); + let scheme = cx.lookup_item_type(impl_def_id); + let predicates = cx.lookup_predicates(impl_def_id); + cx.construct_parameter_environment(impl_item.span, + &scheme.generics, + &predicates, + id) + } ast::ConstImplItem(_, _) => { let def_id = ast_util::local_def(id); let scheme = cx.lookup_item_type(def_id); @@ -2854,42 +2903,37 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } } - ast::TypeImplItem(_) => { - cx.sess.bug("ParameterEnvironment::for_item(): \ - can't create a parameter environment \ - for type impl items") - } ast::MacImplItem(_) => cx.sess.bug("unexpanded macro") } } Some(ast_map::NodeTraitItem(trait_item)) => { match trait_item.node { - ast::ConstTraitItem(_, ref default) => { - match *default { - Some(_) => { - let def_id = ast_util::local_def(id); - let scheme = cx.lookup_item_type(def_id); - let predicates = cx.lookup_predicates(def_id); - cx.construct_parameter_environment(trait_item.span, - &scheme.generics, - &predicates, - id) - } - None => { - cx.sess.bug("ParameterEnvironment::from_item(): \ - can't create a parameter environment \ - for const trait items without defaults") - } - } + ast::TypeTraitItem(..) => { + // associated types don't have their own entry (for some reason), + // so for now just grab environment for the trait + let trait_id = cx.map.get_parent(id); + let trait_def_id = ast_util::local_def(trait_id); + let trait_def = cx.lookup_trait_def(trait_def_id); + let predicates = cx.lookup_predicates(trait_def_id); + cx.construct_parameter_environment(trait_item.span, + &trait_def.generics, + &predicates, + id) } - ast::MethodTraitItem(_, None) => { - cx.sess.span_bug(trait_item.span, - "ParameterEnvironment::for_item(): - can't create a parameter \ - environment for required trait \ - methods") + ast::ConstTraitItem(..) => { + let def_id = ast_util::local_def(id); + let scheme = cx.lookup_item_type(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(trait_item.span, + &scheme.generics, + &predicates, + id) } - ast::MethodTraitItem(_, Some(ref body)) => { + ast::MethodTraitItem(_, ref body) => { + // for the body-id, use the id of the body + // block, unless this is a trait method with + // no default, then fallback to the method id. + let body_id = body.as_ref().map(|b| b.id).unwrap_or(id); let method_def_id = ast_util::local_def(id); match cx.impl_or_trait_item(method_def_id) { MethodTraitItem(ref method_ty) => { @@ -2899,7 +2943,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { trait_item.span, method_generics, method_bounds, - body.id) + body_id) } _ => { cx.sess @@ -2909,11 +2953,6 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } } } - ast::TypeTraitItem(..) => { - cx.sess.bug("ParameterEnvironment::from_item(): \ - can't create a parameter environment \ - for type trait items") - } } } Some(ast_map::NodeItem(item)) => { @@ -2942,6 +2981,15 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { &predicates, id) } + ast::ItemTrait(..) => { + let def_id = ast_util::local_def(id); + let trait_def = cx.lookup_trait_def(def_id); + let predicates = cx.lookup_predicates(def_id); + cx.construct_parameter_environment(item.span, + &trait_def.generics, + &predicates, + id) + } _ => { cx.sess.span_bug(item.span, "ParameterEnvironment::from_item(): @@ -4144,6 +4192,49 @@ impl<'tcx> TyS<'tcx> { } } + /// Returns the regions directly referenced from this type (but + /// not types reachable from this type via `walk_tys`). This + /// ignores late-bound regions binders. + pub fn regions(&self) -> Vec { + match self.sty { + TyRef(region, _) => { + vec![*region] + } + TyTrait(ref obj) => { + let mut v = vec![obj.bounds.region_bound]; + v.push_all(obj.principal.skip_binder().substs.regions().as_slice()); + v + } + TyEnum(_, substs) | + TyStruct(_, substs) => { + substs.regions().as_slice().to_vec() + } + TyClosure(_, ref substs) => { + substs.func_substs.regions().as_slice().to_vec() + } + TyProjection(ref data) => { + data.trait_ref.substs.regions().as_slice().to_vec() + } + TyBareFn(..) | + TyBool | + TyChar | + TyInt(_) | + TyUint(_) | + TyFloat(_) | + TyBox(_) | + TyStr | + TyArray(_, _) | + TySlice(_) | + TyRawPtr(_) | + TyTuple(_) | + TyParam(_) | + TyInfer(_) | + TyError => { + vec![] + } + } + } + /// Walks `ty` and any types appearing within `ty`, invoking the /// callback `f` on each type. If the callback returns false, then the /// children of the current type are ignored. @@ -6142,13 +6233,18 @@ impl<'tcx> ctxt<'tcx> { /// themselves. This should really be a unique type; `FreshTy(0)` is a /// popular choice. /// + /// NB: in some cases, particularly around higher-ranked bounds, + /// this function returns a kind of conservative approximation. + /// That is, all regions returned by this function are definitely + /// required, but there may be other region bounds that are not + /// returned, as well as requirements like `for<'a> T: 'a`. + /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. pub fn required_region_bounds(&self, erased_self_ty: Ty<'tcx>, predicates: Vec>) - -> Vec - { + -> Vec { debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", erased_self_ty, predicates); @@ -6161,6 +6257,8 @@ impl<'tcx> ctxt<'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::RegionOutlives(..) => { None } @@ -6175,11 +6273,7 @@ impl<'tcx> ctxt<'tcx> { // construct such an object, but this seems // correct even if that code changes). if t == erased_self_ty && !r.has_escaping_regions() { - if r.has_escaping_regions() { - Some(ty::ReStatic) - } else { - Some(r) - } + Some(r) } else { None } @@ -6515,12 +6609,19 @@ impl<'tcx> ctxt<'tcx> { /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. - pub fn empty_parameter_environment<'a>(&'a self) -> ParameterEnvironment<'a,'tcx> { + pub fn empty_parameter_environment<'a>(&'a self) + -> ParameterEnvironment<'a,'tcx> { ty::ParameterEnvironment { tcx: self, free_substs: Substs::empty(), caller_bounds: Vec::new(), implicit_region_bound: ty::ReEmpty, - selection_cache: traits::SelectionCache::new(), } + selection_cache: traits::SelectionCache::new(), + + // for an empty parameter + // environment, there ARE no free + // regions, so it shouldn't matter + // what we use for the free id + free_id: ast::DUMMY_NODE_ID } } /// Constructs and returns a substitution that can be applied to move from @@ -6604,6 +6705,7 @@ impl<'tcx> ctxt<'tcx> { implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()), caller_bounds: predicates, selection_cache: traits::SelectionCache::new(), + free_id: free_id, }; let cause = traits::ObligationCause::misc(span, free_id); @@ -6662,6 +6764,8 @@ impl<'tcx> ctxt<'tcx> { ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::Projection(..) => { // For now, assume all these where-clauses // may give drop implementation capabilty @@ -6906,6 +7010,8 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), Predicate::Projection(ref pair) => write!(f, "{:?}", pair), + Predicate::WellFormed(ty) => write!(f, "WF({:?})", ty), + Predicate::ObjectSafe(trait_def_id) => write!(f, "ObjectSafe({:?})", trait_def_id), } } } @@ -6951,6 +7057,20 @@ impl<'tcx> RegionEscape for Ty<'tcx> { } } +impl<'tcx> RegionEscape for TraitTy<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.principal.has_regions_escaping_depth(depth) || + self.bounds.has_regions_escaping_depth(depth) + } +} + +impl<'tcx> RegionEscape for ExistentialBounds<'tcx> { + fn has_regions_escaping_depth(&self, depth: u32) -> bool { + self.region_bound.has_regions_escaping_depth(depth) || + self.projection_bounds.has_regions_escaping_depth(depth) + } +} + impl<'tcx> RegionEscape for Substs<'tcx> { fn has_regions_escaping_depth(&self, depth: u32) -> bool { self.types.has_regions_escaping_depth(depth) || @@ -7016,6 +7136,8 @@ impl<'tcx> RegionEscape for Predicate<'tcx> { Predicate::RegionOutlives(ref data) => data.has_regions_escaping_depth(depth), Predicate::TypeOutlives(ref data) => data.has_regions_escaping_depth(depth), Predicate::Projection(ref data) => data.has_regions_escaping_depth(depth), + Predicate::WellFormed(ty) => ty.has_regions_escaping_depth(depth), + Predicate::ObjectSafe(_trait_def_id) => false, } } } @@ -7174,6 +7296,8 @@ impl<'tcx> HasTypeFlags for Predicate<'tcx> { Predicate::RegionOutlives(ref data) => data.has_type_flags(flags), Predicate::TypeOutlives(ref data) => data.has_type_flags(flags), Predicate::Projection(ref data) => data.has_type_flags(flags), + Predicate::WellFormed(data) => data.has_type_flags(flags), + Predicate::ObjectSafe(_trait_def_id) => false, } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index cc1efeaea080f..09c50804e836b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -394,6 +394,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::TypeOutlives(binder.fold_with(folder)), ty::Predicate::Projection(ref binder) => ty::Predicate::Projection(binder.fold_with(folder)), + ty::Predicate::WellFormed(data) => + ty::Predicate::WellFormed(data.fold_with(folder)), + ty::Predicate::ObjectSafe(trait_def_id) => + ty::Predicate::ObjectSafe(trait_def_id), } } } @@ -543,6 +547,7 @@ impl<'a, 'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'a, 'tcx> where ' implicit_region_bound: self.implicit_region_bound.fold_with(folder), caller_bounds: self.caller_bounds.fold_with(folder), selection_cache: traits::SelectionCache::new(), + free_id: self.free_id, } } } diff --git a/src/librustc/middle/wf.rs b/src/librustc/middle/wf.rs new file mode 100644 index 0000000000000..670b9d72d868b --- /dev/null +++ b/src/librustc/middle/wf.rs @@ -0,0 +1,546 @@ +// Copyright 2012-2013 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 middle::infer::InferCtxt; +use middle::outlives::{self, Component}; +use middle::subst::Substs; +use middle::traits; +use middle::ty::{self, RegionEscape, ToPredicate, Ty}; +use std::iter::once; +use std::mem; +use std::rc::Rc; +use syntax::ast; +use syntax::codemap::Span; +use util::common::ErrorReported; + +/// Returns the set of obligations needed to make `ty` well-formed. +/// If `ty` contains unresolved inference variables, this may include +/// further WF obligations. However, if `ty` IS an unresolved +/// inference variable, returns `None`, because we are not able to +/// make any progress at all. This is to prevent "livelock" where we +/// say "$0 is WF if $0 is WF". +pub fn obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + ty: Ty<'tcx>, + span: Span, + rfc1214: bool) + -> Option>> +{ + let mut wf = WfPredicates { infcx: infcx, + body_id: body_id, + span: span, + out: vec![], + rfc1214: rfc1214 }; + if wf.compute(ty) { + debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); + let result = wf.normalize(); + debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); + Some(result) + } else { + None // no progress made, return None + } +} + +/// Returns the obligations that make this trait reference +/// well-formed. For example, if there is a trait `Set` defined like +/// `trait Set`, then the trait reference `Foo: Set` is WF +/// if `Bar: Eq`. +pub fn trait_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + trait_ref: &ty::TraitRef<'tcx>, + span: Span, + rfc1214: bool) + -> Vec> +{ + let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, + out: vec![], rfc1214: rfc1214 }; + wf.compute_trait_ref(trait_ref); + wf.normalize() +} + +pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + predicate: &ty::Predicate<'tcx>, + span: Span, + rfc1214: bool) + -> Vec> +{ + let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, + out: vec![], rfc1214: rfc1214 }; + + // (*) ok to skip binders, because wf code is prepared for it + match *predicate { + ty::Predicate::Trait(ref t) => { + wf.compute_trait_ref(&t.skip_binder().trait_ref); // (*) + } + ty::Predicate::Equate(ref t) => { + wf.compute(t.skip_binder().0); + wf.compute(t.skip_binder().1); + } + ty::Predicate::RegionOutlives(..) => { + } + ty::Predicate::TypeOutlives(ref t) => { + wf.compute(t.skip_binder().0); + } + ty::Predicate::Projection(ref t) => { + let t = t.skip_binder(); // (*) + wf.compute_projection(t.projection_ty); + wf.compute(t.ty); + } + ty::Predicate::WellFormed(t) => { + wf.compute(t); + } + ty::Predicate::ObjectSafe(_) => { + } + } + + wf.normalize() +} + +/// Implied bounds are region relationships that we deduce +/// automatically. The idea is that (e.g.) a caller must check that a +/// function's argument types are well-formed immediately before +/// calling that fn, and hence the *callee* can assume that its +/// argument types are well-formed. This may imply certain relationships +/// between generic parameters. For example: +/// +/// fn foo<'a,T>(x: &'a T) +/// +/// can only be called with a `'a` and `T` such that `&'a T` is WF. +/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. +#[derive(Debug)] +pub enum ImpliedBound<'tcx> { + RegionSubRegion(ty::Region, ty::Region), + RegionSubParam(ty::Region, ty::ParamTy), + RegionSubProjection(ty::Region, ty::ProjectionTy<'tcx>), +} + +/// Compute the implied bounds that a callee/impl can assume based on +/// the fact that caller/projector has ensured that `ty` is WF. See +/// the `ImpliedBound` type for more details. +pub fn implied_bounds<'a,'tcx>( + infcx: &'a InferCtxt<'a,'tcx>, + body_id: ast::NodeId, + ty: Ty<'tcx>, + span: Span) + -> Vec> +{ + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Currently (at least) these resulting + // predicates are always guaranteed to be a subset of the original + // type, so we need not fear non-termination. + let mut wf_types = vec![ty]; + + let mut implied_bounds = vec![]; + + while let Some(ty) = wf_types.pop() { + // Compute the obligations for `ty` to be well-formed. If `ty` is + // an unresolved inference variable, just substituted an empty set + // -- because the return type here is going to be things we *add* + // to the environment, it's always ok for this set to be smaller + // than the ultimate set. (Note: normally there won't be + // unresolved inference variables here anyway, but there might be + // during typeck under some circumstances.) + let obligations = obligations(infcx, body_id, ty, span, false).unwrap_or(vec![]); + + // From the full set of obligations, just filter down to the + // region relationships. + implied_bounds.extend( + obligations + .into_iter() + .flat_map(|obligation| { + assert!(!obligation.has_escaping_regions()); + match obligation.predicate { + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::Projection(..) | + ty::Predicate::ObjectSafe(..) => + vec![], + + ty::Predicate::WellFormed(subty) => { + wf_types.push(subty); + vec![] + } + + ty::Predicate::RegionOutlives(ref data) => + match infcx.tcx.no_late_bound_regions(data) { + None => + vec![], + Some(ty::OutlivesPredicate(r_a, r_b)) => + vec![ImpliedBound::RegionSubRegion(r_b, r_a)], + }, + + ty::Predicate::TypeOutlives(ref data) => + match infcx.tcx.no_late_bound_regions(data) { + None => vec![], + Some(ty::OutlivesPredicate(ty_a, r_b)) => { + let components = outlives::components(infcx, ty_a); + implied_bounds_from_components(r_b, components) + } + }, + }})); + } + + implied_bounds +} + +/// When we have an implied bound that `T: 'a`, we can further break +/// this down to determine what relationships would have to hold for +/// `T: 'a` to hold. We get to assume that the caller has validated +/// those relationships. +fn implied_bounds_from_components<'tcx>(sub_region: ty::Region, + sup_components: Vec>) + -> Vec> +{ + sup_components + .into_iter() + .flat_map(|component| { + match component { + Component::Region(r) => + vec!(ImpliedBound::RegionSubRegion(sub_region, r)), + Component::Param(p) => + vec!(ImpliedBound::RegionSubParam(sub_region, p)), + Component::Projection(p) => + vec!(ImpliedBound::RegionSubProjection(sub_region, p)), + Component::EscapingProjection(_) => + // If the projection has escaping regions, don't + // try to infer any implied bounds even for its + // free components. This is conservative, because + // the caller will still have to prove that those + // free components outlive `sub_region`. But the + // idea is that the WAY that the caller proves + // that may change in the future and we want to + // give ourselves room to get smarter here. + vec!(), + Component::UnresolvedInferenceVariable(..) => + vec!(), + Component::RFC1214(components) => + implied_bounds_from_components(sub_region, components), + } + }) + .collect() +} + +struct WfPredicates<'a,'tcx:'a> { + infcx: &'a InferCtxt<'a, 'tcx>, + body_id: ast::NodeId, + span: Span, + out: Vec>, + rfc1214: bool +} + +impl<'a,'tcx> WfPredicates<'a,'tcx> { + fn rfc1214) -> R>(&mut self, f: F) -> R { + let b = mem::replace(&mut self.rfc1214, true); + let r = f(self); + self.rfc1214 = b; + r + } + + fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + if !self.rfc1214 { + traits::ObligationCause::new(self.span, self.body_id, code) + } else { + let code = traits::ObligationCauseCode::RFC1214(Rc::new(code)); + traits::ObligationCause::new(self.span, self.body_id, code) + } + } + + fn normalize(&mut self) -> Vec> { + let cause = self.cause(traits::MiscObligation); + let infcx = &mut self.infcx; + self.out.iter() + .inspect(|pred| assert!(!pred.has_escaping_regions())) + .flat_map(|pred| { + let mut selcx = traits::SelectionContext::new(infcx); + let pred = traits::normalize(&mut selcx, cause.clone(), pred); + once(pred.value).chain(pred.obligations) + }) + .collect() + } + + fn compute_rfc1214(&mut self, ty: Ty<'tcx>) { + let b = mem::replace(&mut self.rfc1214, true); + for subty in ty.walk().skip(1) { + self.compute(subty); + } + self.rfc1214 = b; + } + + /// Pushes the obligations required for `trait_ref` to be WF into + /// `self.out`. + fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { + let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); + self.out.extend(obligations); + + let cause = self.cause(traits::MiscObligation); + self.out.extend( + trait_ref.substs.types + .as_slice() + .iter() + .filter(|ty| !ty.has_escaping_regions()) + .map(|ty| traits::Obligation::new(cause.clone(), + ty::Predicate::WellFormed(ty)))); + } + + /// Pushes the obligations required for `trait_ref::Item` to be WF + /// into `self.out`. + fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { + // A projection is well-formed if (a) the trait ref itself is + // WF WF and (b) the trait-ref holds. (It may also be + // normalizable and be WF that way.) + + self.compute_trait_ref(&data.trait_ref); + + if !data.has_escaping_regions() { + let predicate = data.trait_ref.to_predicate(); + let cause = self.cause(traits::ProjectionWf(data)); + self.out.push(traits::Obligation::new(cause, predicate)); + } + } + + /// 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, + /// in which case we are not able to simplify at all. + fn compute(&mut self, ty0: Ty<'tcx>) -> bool { + let mut subtys = ty0.walk(); + while let Some(ty) = subtys.next() { + match ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(..) | + ty::TyUint(..) | + ty::TyFloat(..) | + ty::TyError | + ty::TyStr | + ty::TyParam(_) => { + // WfScalar, WfParameter, etc + } + + ty::TySlice(subty) | + ty::TyArray(subty, _) => { + self.rfc1214(|this| { + if !subty.has_escaping_regions() { + let cause = this.cause(traits::SliceOrArrayElem); + match traits::trait_ref_for_builtin_bound(this.infcx.tcx, + ty::BoundSized, + subty) { + Ok(trait_ref) => { + this.out.push( + traits::Obligation::new(cause, + trait_ref.to_predicate())); + } + Err(ErrorReported) => { } + } + } + }) + } + + ty::TyBox(_) | + ty::TyTuple(_) | + ty::TyRawPtr(_) => { + // simple cases that are WF if their type args are WF + } + + ty::TyProjection(data) => { + subtys.skip_current_subtree(); // subtree handled by compute_projection + self.compute_projection(data); + } + + ty::TyEnum(def, substs) | + ty::TyStruct(def, substs) => { + // WfNominalType + let obligations = self.nominal_obligations(def.did, substs); + self.out.extend(obligations); + } + + ty::TyRef(r, mt) => { + // WfReference + if !r.has_escaping_regions() && !mt.ty.has_escaping_regions() { + let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + self.out.push( + traits::Obligation::new( + cause, + ty::Predicate::TypeOutlives( + ty::Binder( + ty::OutlivesPredicate(mt.ty, *r))))); + } + } + + ty::TyClosure(..) => { + // the types in a closure are always the types of + // local variables (or possibly references to local + // variables), which are separately checked w/r/t + // WFedness. + } + + ty::TyBareFn(..) => { + // process the bound types; because the old implicator + // did not do this, go into RFC1214 mode. + subtys.skip_current_subtree(); + self.compute_rfc1214(ty); + } + + ty::TyTrait(ref data) => { + // WfObject + // + // Here, we defer WF checking due to higher-ranked + // regions. This is perhaps not ideal. + self.from_object_ty(ty, data); + + // FIXME(#27579) RFC also considers adding trait + // obligations that don't refer to Self and + // checking those + + let cause = self.cause(traits::MiscObligation); + self.out.push( + traits::Obligation::new( + cause, + ty::Predicate::ObjectSafe(data.principal_def_id()))); + + // process the bound types; because the old implicator + // did not do this, go into RFC1214 mode. + subtys.skip_current_subtree(); + self.compute_rfc1214(ty); + } + + // Inference variables are the complicated case, since we don't + // know what type they are. We do two things: + // + // 1. Check if they have been resolved, and if so proceed with + // THAT type. + // 2. If not, check whether this is the type that we + // started with (ty0). In that case, we've made no + // progress at all, so return false. Otherwise, + // we've at least simplified things (i.e., we went + // from `Vec<$0>: WF` to `$0: WF`, so we can + // register a pending obligation and keep + // moving. (Goal is that an "inductive hypothesis" + // is satisfied to ensure termination.) + ty::TyInfer(_) => { + let ty = self.infcx.shallow_resolve(ty); + if let ty::TyInfer(_) = ty.sty { // not yet resolved... + if ty == ty0 { // ...this is the type we started from! no progress. + return false; + } + + let cause = self.cause(traits::MiscObligation); + self.out.push( // ...not the type we started from, so we made progress. + traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); + } else { + // Yes, resolved, proceed with the + // result. Should never return false because + // `ty` is not a TyInfer. + assert!(self.compute(ty)); + } + } + } + } + + // if we made it through that loop above, we made progress! + return true; + } + + fn nominal_obligations(&mut self, + def_id: ast::DefId, + substs: &Substs<'tcx>) + -> Vec> + { + let predicates = + self.infcx.tcx.lookup_predicates(def_id) + .instantiate(self.infcx.tcx, substs); + let cause = self.cause(traits::ItemObligation(def_id)); + predicates.predicates + .into_iter() + .map(|pred| traits::Obligation::new(cause.clone(), pred)) + .filter(|pred| !pred.has_escaping_regions()) + .collect() + } + + fn from_object_ty(&mut self, ty: Ty<'tcx>, data: &ty::TraitTy<'tcx>) { + // Imagine a type like this: + // + // trait Foo { } + // trait Bar<'c> : 'c { } + // + // &'b (Foo+'c+Bar<'d>) + // ^ + // + // In this case, the following relationships must hold: + // + // 'b <= 'c + // 'd <= 'c + // + // The first conditions is due to the normal region pointer + // rules, which say that a reference cannot outlive its + // referent. + // + // The final condition may be a bit surprising. In particular, + // you may expect that it would have been `'c <= 'd`, since + // usually lifetimes of outer things are conservative + // approximations for inner things. However, it works somewhat + // differently with trait objects: here the idea is that if the + // user specifies a region bound (`'c`, in this case) it is the + // "master bound" that *implies* that bounds from other traits are + // all met. (Remember that *all bounds* in a type like + // `Foo+Bar+Zed` must be met, not just one, hence if we write + // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and + // 'y.) + // + // Note: in fact we only permit builtin traits, not `Bar<'d>`, I + // am looking forward to the future here. + + if !data.has_escaping_regions() { + let implicit_bounds = + object_region_bounds(self.infcx.tcx, + &data.principal, + data.bounds.builtin_bounds); + + let explicit_bound = data.bounds.region_bound; + + for implicit_bound in implicit_bounds { + let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); + let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); + self.out.push(traits::Obligation::new(cause, outlives.to_predicate())); + } + } + } +} + +/// Given an object type like `SomeTrait+Send`, computes the lifetime +/// bounds that must hold on the elided self type. These are derived +/// from the declarations of `SomeTrait`, `Send`, and friends -- if +/// they declare `trait SomeTrait : 'static`, for example, then +/// `'static` would appear in the list. The hard work is done by +/// `ty::required_region_bounds`, see that for more information. +pub fn object_region_bounds<'tcx>( + tcx: &ty::ctxt<'tcx>, + principal: &ty::PolyTraitRef<'tcx>, + others: ty::BuiltinBounds) + -> Vec +{ + // Since we don't actually *know* the self type for an object, + // this "open(err)" serves as a kind of dummy standin -- basically + // a skolemized type. + let open_ty = tcx.mk_infer(ty::FreshTy(0)); + + // Note that we preserve the overall binding levels here. + assert!(!open_ty.has_escaping_regions()); + let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty)); + let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs))); + + let mut predicates = others.to_predicates(tcx, open_ty); + predicates.extend(trait_refs.iter().map(|t| t.to_predicate())); + + tcx.required_region_bounds(open_ty, predicates) +} + diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 99a58f07ae62b..ffb3a8ccb36ba 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -90,6 +90,13 @@ impl Session { } self.diagnostic().handler().fatal(msg) } + pub fn span_err_or_warn(&self, is_warning: bool, sp: Span, msg: &str) { + if is_warning { + self.span_warn(sp, msg); + } else { + self.span_err(sp, msg); + } + } pub fn span_err(&self, sp: Span, msg: &str) { if self.opts.treat_err_as_bug { self.span_bug(sp, msg); @@ -99,6 +106,13 @@ impl Session { None => self.diagnostic().span_err(sp, msg) } } + pub fn note_rfc_1214(&self, span: Span) { + self.span_note( + span, + &format!("this warning results from recent bug fixes and clarifications; \ + it will become a HARD ERROR in the next release. \ + See RFC 1214 for details.")); + } pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { if self.opts.treat_err_as_bug { self.span_bug(sp, msg); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index da20f730babab..3e9a64a8eb61e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -831,6 +831,11 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate), + ty::Predicate::WellFormed(ty) => write!(f, "{} well-formed", ty), + ty::Predicate::ObjectSafe(trait_def_id) => + ty::tls::with(|tcx| { + write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) + }), } } } diff --git a/src/librustc_data_structures/unify/mod.rs b/src/librustc_data_structures/unify/mod.rs index 7582b7ff61d88..4d79b1a64c191 100644 --- a/src/librustc_data_structures/unify/mod.rs +++ b/src/librustc_data_structures/unify/mod.rs @@ -272,7 +272,7 @@ impl<'tcx,K> UnificationTable impl<'tcx,K,V> UnificationTable where K: UnifyKey>, - V: Clone+PartialEq, + V: Clone+PartialEq+Debug, { pub fn unify_var_var(&mut self, a_id: K, diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 99f375c32868e..345026bdae673 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -52,7 +52,7 @@ use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS}; use middle::const_eval::{self, ConstVal}; use middle::const_eval::EvalHint::UncheckedExprHint; use middle::def; -use middle::implicator::object_region_bounds; +use middle::wf::object_region_bounds; use middle::resolve_lifetime as rl; use middle::privacy::{AllPublic, LastMod}; use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace}; @@ -1523,12 +1523,13 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, ast_ty: &ast::Ty) -> Ty<'tcx> { - debug!("ast_ty_to_ty(ast_ty={:?})", - ast_ty); + debug!("ast_ty_to_ty(id={:?}, ast_ty={:?})", + ast_ty.id, ast_ty); let tcx = this.tcx(); if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&ast_ty.id) { + debug!("ast_ty_to_ty: id={:?} ty={:?} (cached)", ast_ty.id, ty); return ty; } @@ -1667,6 +1668,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } }; + debug!("ast_ty_to_ty: id={:?} ty={:?}", ast_ty.id, typ); tcx.ast_ty_to_ty_cache.borrow_mut().insert(ast_ty.id, typ); return typ; } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index cb5875ec8bcea..9098b241e5b1d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -177,6 +177,8 @@ fn deduce_expectations_from_obligations<'a,'tcx>( ty::Predicate::Equate(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::WellFormed(..) => None, + ty::Predicate::ObjectSafe(..) => None, }; opt_trait_ref .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid)) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 39e67beab583d..30a9d65661a36 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -254,9 +254,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( /// This function is meant to by applied to the type for every /// expression in the program. pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, - typ: ty::Ty<'tcx>, - span: Span, - scope: region::CodeExtent) { + typ: ty::Ty<'tcx>, + span: Span, + scope: region::CodeExtent) { debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", typ, scope); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e9869e2a00e5d..d84cbe1f879e6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -432,7 +432,9 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { traits::ObligationCause::misc(self.span, self.fcx.body_id), method_predicates); - self.fcx.add_default_region_param_bounds( + // this is a projection from a trait reference, so we have to + // make sure that the trait reference inputs are well-formed. + self.fcx.add_wf_bounds( all_substs, self.call_expr); } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2ff40b3590d29..f8235ace3dd6a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -480,6 +480,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { ty::Predicate::Equate(..) | ty::Predicate::Projection(..) | ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::TypeOutlives(..) => { None } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6221134afd38a..bf5d1373d0bf5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -90,7 +90,7 @@ use middle::infer; use middle::infer::type_variable; use middle::pat_util::{self, pat_id_map}; use middle::privacy::{AllPublic, LastMod}; -use middle::region::{self, CodeExtent}; +use middle::region::{self}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace}; use middle::traits::{self, report_fulfillment_errors}; use middle::ty::{FnSig, GenericPredicates, TypeScheme}; @@ -133,7 +133,8 @@ pub mod coercion; pub mod demand; pub mod method; mod upvar; -pub mod wf; +mod wf; +mod wfcheck; mod cast; mod closure; mod callee; @@ -382,7 +383,12 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> { } } -pub fn check_item_types(ccx: &CrateCtxt) { +pub fn check_wf_old(ccx: &CrateCtxt) { + // FIXME(#25759). The new code below is much more reliable but (for now) + // only generates warnings. So as to ensure that we continue + // getting errors where we used to get errors, we run the old wf + // code first and abort if it encounters any errors. If no abort + // comes, we run the new code and issue warnings. let krate = ccx.tcx.map.krate(); let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx); visit::walk_crate(&mut visit, krate); @@ -390,17 +396,34 @@ pub fn check_item_types(ccx: &CrateCtxt) { // If types are not well-formed, it leads to all manner of errors // downstream, so stop reporting errors at this point. ccx.tcx.sess.abort_if_errors(); +} - let mut visit = CheckItemTypesVisitor { ccx: ccx }; +pub fn check_wf_new(ccx: &CrateCtxt) { + let krate = ccx.tcx.map.krate(); + let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx); visit::walk_crate(&mut visit, krate); + // If types are not well-formed, it leads to all manner of errors + // downstream, so stop reporting errors at this point. + ccx.tcx.sess.abort_if_errors(); +} + +pub fn check_item_types(ccx: &CrateCtxt) { + let krate = ccx.tcx.map.krate(); + let mut visit = CheckItemTypesVisitor { ccx: ccx }; + visit::walk_crate(&mut visit, krate); ccx.tcx.sess.abort_if_errors(); +} +pub fn check_item_bodies(ccx: &CrateCtxt) { + let krate = ccx.tcx.map.krate(); let mut visit = CheckItemBodiesVisitor { ccx: ccx }; visit::walk_crate(&mut visit, krate); ccx.tcx.sess.abort_if_errors(); +} +pub fn check_drop_impls(ccx: &CrateCtxt) { for drop_method_did in ccx.tcx.destructors.borrow().iter() { if drop_method_did.krate == ast::LOCAL_CRATE { let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node); @@ -445,9 +468,8 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, fcx.select_all_obligations_and_apply_defaults(); upvar::closure_analyze_fn(&fcx, fn_id, decl, body); - fcx.select_all_obligations_or_error(); + fcx.select_obligations_where_possible(); fcx.check_casts(); - fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body); @@ -587,7 +609,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, if let ty::FnConverging(ret_ty) = ret_ty { fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fn_sig_tys.push(ret_ty); + fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments } debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}", @@ -601,6 +623,14 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, // Add formal parameters. for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) { + // The type of the argument must be well-formed. + // + // NB -- this is now checked in wfcheck, but that + // currently only results in warnings, so we issue an + // old-style WF obligation here so that we still get the + // errors that we used to get. + fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation); + // Create type variables for each argument. pat_util::pat_bindings( &tcx.def_map, @@ -1508,10 +1538,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_ty(&self, ast_t: &ast::Ty) -> Ty<'tcx> { let t = ast_ty_to_ty(self, self, ast_t); - let mut bounds_checker = wf::BoundsChecker::new(self, - self.body_id, - None); - bounds_checker.check_ty(t, ast_t.span); + // Generally speaking, we must check that types entered by the + // user are well-formed. This is not true for `_`, since those + // types are generated by inference. Now, you might think that + // we could as well generate a WF obligation -- but + // unfortunately that breaks code like `foo as *const _`, + // because those type variables wind up being unconstrained + // until very late. Nasty. Probably it'd be best to refactor + // that code path, but that's tricky because of + // defaults. Argh! + match ast_t.node { + ast::TyInfer => { } + _ => { self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); } + } t } @@ -1630,15 +1669,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fulfillment_cx.register_region_obligation(ty, region, cause); } - pub fn add_default_region_param_bounds(&self, - substs: &Substs<'tcx>, - expr: &ast::Expr) + /// Registers an obligation for checking later, during regionck, that the type `ty` must + /// outlive the region `r`. + pub fn register_wf_obligation(&self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>) + { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new(cause, ty::Predicate::WellFormed(ty))); + } + + pub fn register_old_wf_obligation(&self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>) + { + // Registers an "old-style" WF obligation that uses the + // implicator code. This is basically a buggy version of + // `register_wf_obligation` that is being kept around + // temporarily just to help with phasing in the newer rules. + // + // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_region_obligation(ty, ty::ReEmpty, cause); + } + + /// Registers obligations that all types appearing in `substs` are well-formed. + pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &ast::Expr) { for &ty in &substs.types { - let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id)); - let cause = traits::ObligationCause::new(expr.span, self.body_id, - traits::MiscObligation); - self.register_region_obligation(ty, default_bound, cause); + self.register_wf_obligation(ty, expr.span, traits::MiscObligation); } } @@ -2370,6 +2432,12 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, 1 }; + // All the input types from the fn signature must outlive the call + // so as to validate implied bounds. + for &fn_input_ty in fn_inputs { + fcx.register_wf_obligation(fn_input_ty, sp, traits::MiscObligation); + } + let mut expected_arg_tys = expected_arg_tys; let expected_arg_count = fn_inputs.len(); let formal_tys = if tuple_arguments == TupleArguments { @@ -2478,7 +2546,8 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Expectation::rvalue_hint(fcx.tcx(), ty) }); - check_expr_with_unifier(fcx, &**arg, + check_expr_with_unifier(fcx, + &**arg, expected.unwrap_or(ExpectHasType(formal_ty)), NoPreference, || { // 2. Coerce to the most detailed type that could be coerced @@ -3363,7 +3432,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // We always require that the type provided as the value for // a type parameter outlives the moment of instantiation. - constrain_path_type_parameters(fcx, expr); + fcx.opt_node_ty_substs(expr.id, |item_substs| { + fcx.add_wf_bounds(&item_substs.substs, expr); + }); } ast::ExprInlineAsm(ref ia) => { for &(_, ref input) in &ia.inputs { @@ -3476,16 +3547,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } ast::ExprCall(ref callee, ref args) => { callee::check_call(fcx, expr, &**callee, &args[..], expected); + + // we must check that return type of called functions is WF: + let ret_ty = fcx.expr_ty(expr); + fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation); } ast::ExprMethodCall(ident, ref tps, ref args) => { - check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref); - let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a)); - let args_err = arg_tys.fold(false, - |rest_err, a| { - rest_err || a.references_error()}); - if args_err { - fcx.write_error(id); - } + check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref); + let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a)); + let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error()); + if args_err { + fcx.write_error(id); + } } ast::ExprCast(ref e, ref t) => { if let ast::TyFixedLengthVec(_, ref count_expr) = t.node { @@ -3904,14 +3977,6 @@ pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, } } -fn constrain_path_type_parameters(fcx: &FnCtxt, - expr: &ast::Expr) -{ - fcx.opt_node_ty_substs(expr.id, |item_substs| { - fcx.add_default_region_param_bounds(&item_substs.substs, expr); - }); -} - impl<'tcx> Expectation<'tcx> { /// Provide an expectation for an rvalue expression given an *optional* /// hint, which is not required for type safety (the resulting type might diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index aeac38dab9047..ced3ee82de2bd 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -86,15 +86,19 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; use middle::free_region::FreeRegionMap; -use middle::implicator; +use middle::implicator::{self, Implication}; use middle::mem_categorization as mc; +use middle::outlives; use middle::region::CodeExtent; +use middle::subst::Substs; use middle::traits; -use middle::ty::{self, ReScope, Ty, MethodCall, HasTypeFlags}; -use middle::infer::{self, GenericKind}; +use middle::ty::{self, RegionEscape, ReScope, Ty, MethodCall, HasTypeFlags}; +use middle::infer::{self, GenericKind, InferCtxt, SubregionOrigin, VerifyBound}; use middle::pat_util; +use middle::wf::{self, ImpliedBound}; use std::mem; +use std::rc::Rc; use syntax::{ast, ast_util}; use syntax::codemap::Span; use syntax::visit; @@ -120,12 +124,19 @@ pub fn regionck_expr(fcx: &FnCtxt, e: &ast::Expr) { rcx.resolve_regions_and_report_errors(); } -pub fn regionck_item(fcx: &FnCtxt, item: &ast::Item) { - let mut rcx = Rcx::new(fcx, RepeatingScope(item.id), item.id, Subject(item.id)); +/// Region checking during the WF phase for items. `wf_tys` are the +/// types from which we should derive implied bounds, if any. +pub fn regionck_item<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, + item_id: ast::NodeId, + span: Span, + wf_tys: &[Ty<'tcx>]) { + debug!("regionck_item(item.id={:?}, wf_tys={:?}", item_id, wf_tys); + let mut rcx = Rcx::new(fcx, RepeatingScope(item_id), item_id, Subject(item_id)); let tcx = fcx.tcx(); rcx.free_region_map .relate_free_regions_from_predicates(tcx, &fcx.infcx().parameter_environment.caller_bounds); - rcx.visit_region_obligations(item.id); + rcx.relate_free_regions(wf_tys, item_id, span); + rcx.visit_region_obligations(item_id); rcx.resolve_regions_and_report_errors(); } @@ -154,22 +165,6 @@ pub fn regionck_fn(fcx: &FnCtxt, fcx.tcx().store_free_region_map(fn_id, rcx.free_region_map); } -/// Checks that the types in `component_tys` are well-formed. This will add constraints into the -/// region graph. Does *not* run `resolve_regions_and_report_errors` and so forth. -pub fn regionck_ensure_component_tys_wf<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - component_tys: &[Ty<'tcx>]) { - let mut rcx = Rcx::new(fcx, RepeatingScope(0), 0, SubjectNode::None); - for &component_ty in component_tys { - // Check that each type outlives the empty region. Since the - // empty region is a subregion of all others, this can't fail - // unless the type does not meet the well-formedness - // requirements. - type_must_outlive(&mut rcx, infer::RelateParamBound(span, component_ty), - component_ty, ty::ReEmpty); - } -} - /////////////////////////////////////////////////////////////////////////// // INTERNALS @@ -213,6 +208,10 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { self.fcx.ccx.tcx } + pub fn infcx(&self) -> &InferCtxt<'a,'tcx> { + self.fcx.infcx() + } + fn set_body_id(&mut self, body_id: ast::NodeId) -> ast::NodeId { mem::replace(&mut self.body_id, body_id) } @@ -325,11 +324,16 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { .to_vec(); for r_o in ®ion_obligations { - debug!("visit_region_obligations: r_o={:?}", - r_o); + debug!("visit_region_obligations: r_o={:?} cause={:?}", + r_o, r_o.cause); let sup_type = self.resolve_type(r_o.sup_type); - let origin = infer::RelateParamBound(r_o.cause.span, sup_type); - type_must_outlive(self, origin, sup_type, r_o.sub_region); + let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code); + + if r_o.sub_region != ty::ReEmpty { + type_must_outlive(self, origin, sup_type, r_o.sub_region); + } else { + self.visit_old_school_wf(node_id, sup_type, origin); + } } // Processing the region obligations should not cause the list to grow further: @@ -337,6 +341,62 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len()); } + fn visit_old_school_wf(&mut self, + body_id: ast::NodeId, + ty: Ty<'tcx>, + origin: infer::SubregionOrigin<'tcx>) { + // As a weird kind of hack, we use a region of empty as a signal + // to mean "old-school WF rules". The only reason the old-school + // WF rules are not encoded using WF is that this leads to errors, + // and we want to phase those in gradually. + + // FIXME(#27579) remove this weird special case once we phase in new WF rules completely + let implications = implicator::implications(self.infcx(), + body_id, + ty, + ty::ReEmpty, + origin.span()); + let origin_for_ty = |ty: Option>| match ty { + None => origin.clone(), + Some(ty) => infer::ReferenceOutlivesReferent(ty, origin.span()), + }; + for implication in implications { + match implication { + Implication::RegionSubRegion(ty, r1, r2) => { + self.fcx.mk_subr(origin_for_ty(ty), r1, r2); + } + Implication::RegionSubGeneric(ty, r1, GenericKind::Param(param_ty)) => { + param_ty_must_outlive(self, origin_for_ty(ty), r1, param_ty); + } + Implication::RegionSubGeneric(ty, r1, GenericKind::Projection(proj_ty)) => { + projection_must_outlive(self, origin_for_ty(ty), r1, proj_ty); + } + Implication::Predicate(def_id, predicate) => { + let cause = traits::ObligationCause::new(origin.span(), + body_id, + traits::ItemObligation(def_id)); + let obligation = traits::Obligation::new(cause, predicate); + self.fcx.register_predicate(obligation); + } + } + } + } + + fn code_to_origin(&self, + span: Span, + sup_type: Ty<'tcx>, + code: &traits::ObligationCauseCode<'tcx>) + -> SubregionOrigin<'tcx> { + match *code { + traits::ObligationCauseCode::RFC1214(ref code) => + infer::RFC1214Subregion(Rc::new(self.code_to_origin(span, sup_type, code))), + traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => + infer::ReferenceOutlivesReferent(ref_type, span), + _ => + infer::RelateParamBound(span, sup_type), + } + } + /// This method populates the region map's `free_region_map`. It walks over the transformed /// argument and return types for each function just before we check the body of that function, /// looking for types where you have a borrowed pointer to other borrowed data (e.g., `&'a &'b @@ -356,33 +416,28 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { for &ty in fn_sig_tys { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={:?})", ty); - let body_scope = CodeExtent::from_node_id(body_id); - let body_scope = ty::ReScope(body_scope); - let implications = implicator::implications(self.fcx.infcx(), body_id, - ty, body_scope, span); + let implied_bounds = wf::implied_bounds(self.fcx.infcx(), body_id, ty, span); // Record any relations between free regions that we observe into the free-region-map. - self.free_region_map.relate_free_regions_from_implications(&implications); + self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds); // But also record other relationships, such as `T:'x`, // that don't go into the free-region-map but which we use // here. - for implication in implications { + for implication in implied_bounds { debug!("implication: {:?}", implication); match implication { - implicator::Implication::RegionSubRegion(_, - ty::ReFree(free_a), - ty::ReInfer(ty::ReVar(vid_b))) => { + ImpliedBound::RegionSubRegion(ty::ReFree(free_a), + ty::ReInfer(ty::ReVar(vid_b))) => { self.fcx.inh.infcx.add_given(free_a, vid_b); } - implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => { - debug!("RegionSubGeneric: {:?} <= {:?}", - r_a, generic_b); - - self.region_bound_pairs.push((r_a, generic_b.clone())); + ImpliedBound::RegionSubParam(r_a, param_b) => { + self.region_bound_pairs.push((r_a, GenericKind::Param(param_b))); } - implicator::Implication::RegionSubRegion(..) | - implicator::Implication::Predicate(..) => { + ImpliedBound::RegionSubProjection(r_a, projection_b) => { + self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); + } + ImpliedBound::RegionSubRegion(..) => { // In principle, we could record (and take // advantage of) every relationship here, but // we are also free not to -- it simply means @@ -492,12 +547,11 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { // that the lifetime of any regions that appear in a // variable's type enclose at least the variable's scope. - let var_region = tcx.region_maps.var_region(id); - type_of_node_must_outlive( - rcx, infer::BindingTypeIsNotValidAtDecl(span), - id, var_region); - let var_scope = tcx.region_maps.var_scope(id); + + let origin = infer::BindingTypeIsNotValidAtDecl(span); + type_of_node_must_outlive(rcx, origin, id, ty::ReScope(var_scope)); + let typ = rcx.resolve_node_type(id); dropck::check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope); }) @@ -514,7 +568,29 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { type_must_outlive(rcx, infer::ExprTypeIsNotInScope(expr_ty, expr.span), expr_ty, ty::ReScope(CodeExtent::from_node_id(expr.id))); - let has_method_map = rcx.fcx.infcx().is_method_call(expr.id); + let method_call = MethodCall::expr(expr.id); + let opt_method_callee = rcx.fcx.inh.tables.borrow().method_map.get(&method_call).cloned(); + let has_method_map = opt_method_callee.is_some(); + + // the region corresponding to this expression + let expr_region = ty::ReScope(CodeExtent::from_node_id(expr.id)); + + // If we are calling a method (either explicitly or via an + // overloaded operator), check that all of the types provided as + // arguments for its type parameters are well-formed, and all the regions + // provided as arguments outlive the call. + if let Some(callee) = opt_method_callee { + let origin = match expr.node { + ast::ExprMethodCall(..) => + infer::ParameterOrigin::MethodCall, + ast::ExprUnary(op, _) if op == ast::UnDeref => + infer::ParameterOrigin::OverloadedDeref, + _ => + infer::ParameterOrigin::OverloadedOperator + }; + + substs_wf_in_scope(rcx, origin, &callee.substs, expr.span, expr_region); + } // Check any autoderefs or autorefs that appear. let adjustment = rcx.fcx.inh.tables.borrow().adjustments.get(&expr.id).map(|a| a.clone()); @@ -585,6 +661,13 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { } match expr.node { + ast::ExprPath(..) => { + rcx.fcx.opt_node_ty_substs(expr.id, |item_substs| { + let origin = infer::ParameterOrigin::Path; + substs_wf_in_scope(rcx, origin, &item_substs.substs, expr.span, expr_region); + }); + } + ast::ExprCall(ref callee, ref args) => { if has_method_map { constrain_call(rcx, expr, Some(&**callee), @@ -895,6 +978,9 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, debug!("constrain_autoderefs: #{} is overloaded, method={:?}", i, method); + let origin = infer::ParameterOrigin::OverloadedDeref; + substs_wf_in_scope(rcx, origin, method.substs, deref_expr.span, r_deref_expr); + // Treat overloaded autoderefs as if an AutoRef adjustment // was applied on the base type, as that is always the case. let fn_sig = method.ty.fn_sig(); @@ -1196,6 +1282,9 @@ fn link_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, let mut borrow_cmt = borrow_cmt; let mut borrow_kind = borrow_kind; + let origin = infer::DataBorrowed(borrow_cmt.ty, span); + type_must_outlive(rcx, origin, borrow_cmt.ty, *borrow_region); + loop { debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", borrow_region, @@ -1395,74 +1484,295 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, } } -/// Ensures that all borrowed data reachable via `ty` outlives `region`. -pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, - origin: infer::SubregionOrigin<'tcx>, - ty: Ty<'tcx>, - region: ty::Region) +/// Checks that the values provided for type/region arguments in a given +/// expression are well-formed and in-scope. +pub fn substs_wf_in_scope<'a,'tcx>(rcx: &mut Rcx<'a,'tcx>, + origin: infer::ParameterOrigin, + substs: &Substs<'tcx>, + expr_span: Span, + expr_region: ty::Region) { + debug!("substs_wf_in_scope(substs={:?}, \ + expr_region={:?}, \ + origin={:?}, \ + expr_span={:?})", + substs, expr_region, origin, expr_span); + + let origin = infer::ParameterInScope(origin, expr_span); + + for ®ion in substs.regions() { + rcx.fcx.mk_subr(origin.clone(), expr_region, region); + } + + for &ty in &substs.types { + let ty = rcx.resolve_type(ty); + type_must_outlive(rcx, origin.clone(), ty, expr_region); + } +} + +/// Ensures that type is well-formed in `region`, which implies (among +/// other things) that all borrowed data reachable via `ty` outlives +/// `region`. +pub fn type_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + origin: infer::SubregionOrigin<'tcx>, + ty: Ty<'tcx>, + region: ty::Region) { + let ty = rcx.resolve_type(ty); + debug!("type_must_outlive(ty={:?}, region={:?})", ty, region); - let implications = implicator::implications(rcx.fcx.infcx(), rcx.body_id, - ty, region, origin.span()); - for implication in implications { - debug!("implication: {:?}", implication); - match implication { - implicator::Implication::RegionSubRegion(None, r_a, r_b) => { - rcx.fcx.mk_subr(origin.clone(), r_a, r_b); + assert!(!ty.has_escaping_regions()); + + let components = outlives::components(rcx.infcx(), ty); + components_must_outlive(rcx, origin, components, region); +} + +fn components_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + origin: infer::SubregionOrigin<'tcx>, + components: Vec>, + region: ty::Region) +{ + for component in components { + let origin = origin.clone(); + match component { + outlives::Component::Region(region1) => { + rcx.fcx.mk_subr(origin, region, region1); + } + outlives::Component::Param(param_ty) => { + param_ty_must_outlive(rcx, origin, region, param_ty); } - implicator::Implication::RegionSubRegion(Some(ty), r_a, r_b) => { - let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); - rcx.fcx.mk_subr(o1, r_a, r_b); + outlives::Component::Projection(projection_ty) => { + projection_must_outlive(rcx, origin, region, projection_ty); } - implicator::Implication::RegionSubGeneric(None, r_a, ref generic_b) => { - generic_must_outlive(rcx, origin.clone(), r_a, generic_b); + outlives::Component::EscapingProjection(subcomponents) => { + components_must_outlive(rcx, origin, subcomponents, region); } - implicator::Implication::RegionSubGeneric(Some(ty), r_a, ref generic_b) => { - let o1 = infer::ReferenceOutlivesReferent(ty, origin.span()); - generic_must_outlive(rcx, o1, r_a, generic_b); + outlives::Component::UnresolvedInferenceVariable(v) => { + // ignore this, we presume it will yield an error + // later, since if a type variable is not resolved by + // this point it never will be + rcx.tcx().sess.delay_span_bug( + origin.span(), + &format!("unresolved inference variable in outlives: {:?}", v)); } - implicator::Implication::Predicate(def_id, predicate) => { - let cause = traits::ObligationCause::new(origin.span(), - rcx.body_id, - traits::ItemObligation(def_id)); - let obligation = traits::Obligation::new(cause, predicate); - rcx.fcx.register_predicate(obligation); + outlives::Component::RFC1214(subcomponents) => { + let suborigin = infer::RFC1214Subregion(Rc::new(origin)); + components_must_outlive(rcx, suborigin, subcomponents, region); } } } } -fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region, - generic: &GenericKind<'tcx>) { - let param_env = &rcx.fcx.inh.infcx.parameter_environment; +fn param_ty_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region, + param_ty: ty::ParamTy) { + debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", + region, param_ty, origin); - debug!("param_must_outlive(region={:?}, generic={:?})", - region, - generic); + let verify_bound = param_bound(rcx, param_ty); + let generic = GenericKind::Param(param_ty); + rcx.fcx.infcx().verify_generic_bound(origin, generic, region, verify_bound); +} - // To start, collect bounds from user: - let mut param_bounds = rcx.tcx().required_region_bounds(generic.to_ty(rcx.tcx()), - param_env.caller_bounds.clone()); +fn projection_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + origin: infer::SubregionOrigin<'tcx>, + region: ty::Region, + projection_ty: ty::ProjectionTy<'tcx>) +{ + debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", + region, projection_ty, origin); + + // This case is thorny for inference. The fundamental problem is + // that there are many cases where we have choice, and inference + // doesn't like choice (the current region inference in + // particular). :) First off, we have to choose between using the + // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and + // OutlivesProjectionComponent rules, any one of which is + // sufficient. If there are no inference variables involved, it's + // not hard to pick the right rule, but if there are, we're in a + // bit of a catch 22: if we picked which rule we were going to + // use, we could add constraints to the region inference graph + // that make it apply, but if we don't add those constraints, the + // rule might not apply (but another rule might). For now, we err + // on the side of adding too few edges into the graph. + + // Compute the bounds we can derive from the environment or trait + // definition. We know that the projection outlives all the + // regions in this list. + let env_bounds = projection_declared_bounds(rcx, origin.span(), projection_ty); + + debug!("projection_must_outlive: env_bounds={:?}", + env_bounds); + + // If we know that the projection outlives 'static, then we're + // done here. + if env_bounds.contains(&ty::ReStatic) { + debug!("projection_must_outlive: 'static as declared bound"); + return; + } - // In the case of a projection T::Foo, we may be able to extract bounds from the trait def: - match *generic { - GenericKind::Param(..) => { } - GenericKind::Projection(ref projection_ty) => { - param_bounds.push_all( - &projection_bounds(rcx, origin.span(), projection_ty)); + // If declared bounds list is empty, the only applicable rule is + // OutlivesProjectionComponent. If there are inference variables, + // then, we can break down the outlives into more primitive + // components without adding unnecessary edges. + // + // If there are *no* inference variables, however, we COULD do + // this, but we choose not to, because the error messages are less + // good. For example, a requirement like `T::Item: 'r` would be + // translated to a requirement that `T: 'r`; when this is reported + // to the user, it will thus say "T: 'r must hold so that T::Item: + // 'r holds". But that makes it sound like the only way to fix + // the problem is to add `T: 'r`, which isn't true. So, if there are no + // inference variables, we use a verify constraint instead of adding + // edges, which winds up enforcing the same condition. + let needs_infer = { + projection_ty.trait_ref.substs.types.iter().any(|t| t.needs_infer()) || + projection_ty.trait_ref.substs.regions().iter().any(|r| r.needs_infer()) + }; + if env_bounds.is_empty() && needs_infer { + debug!("projection_must_outlive: no declared bounds"); + + for &component_ty in &projection_ty.trait_ref.substs.types { + type_must_outlive(rcx, origin.clone(), component_ty, region); + } + + for &r in projection_ty.trait_ref.substs.regions() { + rcx.fcx.mk_subr(origin.clone(), region, r); + } + + return; + } + + // If we find that there is a unique declared bound `'b`, and this bound + // appears in the trait reference, then the best action is to require that `'b:'r`, + // so do that. This is best no matter what rule we use: + // + // - OutlivesProjectionEnv or OutlivesProjectionTraitDef: these would translate to + // the requirement that `'b:'r` + // - OutlivesProjectionComponent: this would require `'b:'r` in addition to other conditions + if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) { + let unique_bound = env_bounds[0]; + debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); + if projection_ty.trait_ref.substs.regions() + .iter() + .any(|r| env_bounds.contains(r)) + { + debug!("projection_must_outlive: unique declared bound appears in trait ref"); + rcx.fcx.mk_subr(origin.clone(), region, unique_bound); + return; } } + // Fallback to verifying after the fact that there exists a + // declared bound, or that all the components appearing in the + // projection outlive; in some cases, this may add insufficient + // edges into the inference graph, leading to inference failures + // even though a satisfactory solution exists. + let verify_bound = projection_bound(rcx, origin.span(), env_bounds, projection_ty); + let generic = GenericKind::Projection(projection_ty); + rcx.fcx.infcx().verify_generic_bound(origin, generic.clone(), region, verify_bound); +} + +fn type_bound<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, span: Span, ty: Ty<'tcx>) -> VerifyBound { + match ty.sty { + ty::TyParam(p) => { + param_bound(rcx, p) + } + ty::TyProjection(data) => { + let declared_bounds = projection_declared_bounds(rcx, span, data); + projection_bound(rcx, span, declared_bounds, data) + } + _ => { + recursive_type_bound(rcx, span, ty) + } + } +} + +fn param_bound<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, param_ty: ty::ParamTy) -> VerifyBound { + let param_env = &rcx.infcx().parameter_environment; + + debug!("param_bound(param_ty={:?})", + param_ty); + + let mut param_bounds = declared_generic_bounds_from_env(rcx, GenericKind::Param(param_ty)); + // Add in the default bound of fn body that applies to all in // scope type parameters: param_bounds.push(param_env.implicit_region_bound); - // Finally, collect regions we scraped from the well-formedness + VerifyBound::AnyRegion(param_bounds) +} + +fn projection_declared_bounds<'a, 'tcx>(rcx: &Rcx<'a,'tcx>, + span: Span, + projection_ty: ty::ProjectionTy<'tcx>) + -> Vec +{ + // First assemble bounds from where clauses and traits. + + let mut declared_bounds = + declared_generic_bounds_from_env(rcx, GenericKind::Projection(projection_ty)); + + declared_bounds.push_all( + &declared_projection_bounds_from_trait(rcx, span, projection_ty)); + + declared_bounds +} + +fn projection_bound<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + span: Span, + declared_bounds: Vec, + projection_ty: ty::ProjectionTy<'tcx>) + -> VerifyBound { + debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})", + declared_bounds, projection_ty); + + // see the extensive comment in projection_must_outlive + + let ty = rcx.tcx().mk_projection(projection_ty.trait_ref, projection_ty.item_name); + let recursive_bound = recursive_type_bound(rcx, span, ty); + + VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) +} + +fn recursive_type_bound<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>) + -> VerifyBound { + let mut bounds = vec![]; + + for subty in ty.walk_shallow() { + bounds.push(type_bound(rcx, span, subty)); + } + + let mut regions = ty.regions(); + regions.retain(|r| !r.is_bound()); // ignore late-bound regions + bounds.push(VerifyBound::AllRegions(regions)); + + // remove bounds that must hold, since they are not interesting + bounds.retain(|b| !b.must_hold()); + + if bounds.len() == 1 { + bounds.pop().unwrap() + } else { + VerifyBound::AllBounds(bounds) + } +} + +fn declared_generic_bounds_from_env<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, + generic: GenericKind<'tcx>) + -> Vec +{ + let param_env = &rcx.infcx().parameter_environment; + + // To start, collect bounds from user: + let mut param_bounds = rcx.tcx().required_region_bounds(generic.to_ty(rcx.tcx()), + param_env.caller_bounds.clone()); + + // Next, collect regions we scraped from the well-formedness // constraints in the fn signature. To do that, we walk the list // of known relations from the fn ctxt. // @@ -1473,27 +1783,22 @@ fn generic_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, // The problem is that the type of `x` is `&'a A`. To be // well-formed, then, A must be lower-generic by `'a`, but we // don't know that this holds from first principles. - for &(ref r, ref p) in &rcx.region_bound_pairs { + for &(r, p) in &rcx.region_bound_pairs { debug!("generic={:?} p={:?}", generic, p); if generic == p { - param_bounds.push(*r); + param_bounds.push(r); } } - // Inform region inference that this generic must be properly - // bounded. - rcx.fcx.infcx().verify_generic_bound(origin, - generic.clone(), - region, - param_bounds); + param_bounds } -fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, - span: Span, - projection_ty: &ty::ProjectionTy<'tcx>) - -> Vec +fn declared_projection_bounds_from_trait<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, + span: Span, + projection_ty: ty::ProjectionTy<'tcx>) + -> Vec { let fcx = rcx.fcx; let tcx = fcx.tcx(); diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 7790a29db12f7..47eb1f472c31d 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -9,7 +9,7 @@ // except according to those terms. use astconv::AstConv; -use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; +use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck, wfcheck}; use constrained_type_params::{identify_constrained_type_params, Parameter}; use CrateCtxt; use middle::region; @@ -23,7 +23,7 @@ use std::collections::HashSet; use syntax::ast; use syntax::ast_util::local_def; use syntax::codemap::{DUMMY_SP, Span}; -use syntax::parse::token::special_idents; +use syntax::parse::token::{special_idents}; use syntax::visit; use syntax::visit::Visitor; @@ -86,9 +86,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { Some(ty::BoundSend) | Some(ty::BoundSync) => {} Some(_) | None => { if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) { - span_err!(ccx.tcx.sess, item.span, E0192, - "negative impls are only allowed for traits with \ - default impls (e.g., `Send` and `Sync`)") + wfcheck::error_192(ccx, item.span); } } } @@ -122,9 +120,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates); if ccx.tcx.trait_has_default_impl(local_def(item.id)) { if !items.is_empty() { - span_err!(ccx.tcx.sess, item.span, E0380, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) must have no methods or associated items") + wfcheck::error_380(ccx, item.span); } } } @@ -149,7 +145,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); f(self, &fcx); fcx.select_all_obligations_or_error(); - regionck::regionck_item(&fcx, item); + regionck::regionck_item(&fcx, item.id, item.span, &[]); } /// In a type definition, we check that to ensure that the types of the fields are well-formed. @@ -182,11 +178,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } } - let field_tys: Vec = - variants.iter().flat_map(|v| v.fields.iter().map(|f| f.ty)).collect(); - - regionck::regionck_ensure_component_tys_wf( - fcx, item.span, &field_tys); + for field in variants.iter().flat_map(|v| v.fields.iter()) { + fcx.register_old_wf_obligation(field.ty, field.span, traits::MiscObligation); + } }); } @@ -355,8 +349,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { span: Span, param_name: ast::Name) { - span_err!(self.tcx().sess, span, E0392, - "parameter `{}` is never used", param_name); + wfcheck::error_392(self.tcx(), span, param_name); let suggested_marker_id = self.tcx().lang_items.phantom_data(); match suggested_marker_id { @@ -420,9 +413,7 @@ fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, for method_param in generics.types.get_slice(subst::FnSpace) { if impl_params.contains(&method_param.name) { - span_err!(tcx.sess, span, E0194, - "type parameter `{}` shadows another type parameter of the same name", - method_param.name); + wfcheck::error_194(tcx, span, method_param.name); } } } @@ -521,11 +512,6 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { } } - pub fn check_ty(&mut self, ty: Ty<'tcx>, span: Span) { - self.span = span; - ty.fold_with(self); - } - fn check_traits_in_ty(&mut self, ty: Ty<'tcx>, span: Span) { self.span = span; // When checking types outside of a type def'n, we ignore @@ -709,6 +695,8 @@ fn filter_to_trait_obligations<'tcx>(bounds: ty::InstantiatedPredicates<'tcx>) ty::Predicate::Projection(..) => { result.predicates.push(space, predicate.clone()) } + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::Equate(..) | ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs new file mode 100644 index 0000000000000..03e6ae2dd1545 --- /dev/null +++ b/src/librustc_typeck/check/wfcheck.rs @@ -0,0 +1,630 @@ +// Copyright 2014 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 astconv::AstConv; +use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck}; +use constrained_type_params::{identify_constrained_type_params, Parameter}; +use CrateCtxt; +use middle::region::DestructionScopeData; +use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace}; +use middle::traits; +use middle::ty::{self, Ty}; +use middle::ty_fold::{TypeFolder}; +use middle::wf; + +use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; +use syntax::ast; +use syntax::ast_util::local_def; +use syntax::codemap::{Span}; +use syntax::parse::token::{special_idents}; +use syntax::ptr::P; +use syntax::visit; +use syntax::visit::Visitor; + +pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> { + ccx: &'ccx CrateCtxt<'ccx, 'tcx>, + code: traits::ObligationCauseCode<'tcx>, +} + +impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { + pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'tcx>) + -> CheckTypeWellFormedVisitor<'ccx, 'tcx> { + CheckTypeWellFormedVisitor { + ccx: ccx, + code: traits::ObligationCauseCode::RFC1214( + Rc::new(traits::ObligationCauseCode::MiscObligation)) + } + } + + fn tcx(&self) -> &ty::ctxt<'tcx> { + self.ccx.tcx + } + + /// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are + /// well-formed, meaning that they do not require any constraints not declared in the struct + /// definition itself. For example, this definition would be illegal: + /// + /// struct Ref<'a, T> { x: &'a T } + /// + /// because the type did not declare that `T:'a`. + /// + /// We do this check as a pre-pass before checking fn bodies because if these constraints are + /// not included it frequently leads to confusing errors in fn bodies. So it's better to check + /// the types first. + fn check_item_well_formed(&mut self, item: &ast::Item) { + let ccx = self.ccx; + debug!("check_item_well_formed(it.id={}, it.ident={})", + item.id, + ccx.tcx.item_path_str(local_def(item.id))); + + match item.node { + /// Right now we check that every default trait implementation + /// has an implementation of itself. Basically, a case like: + /// + /// `impl Trait for T {}` + /// + /// has a requirement of `T: Trait` which was required for default + /// method implementations. Although this could be improved now that + /// there's a better infrastructure in place for this, it's being left + /// for a follow-up work. + /// + /// Since there's such a requirement, we need to check *just* positive + /// implementations, otherwise things like: + /// + /// impl !Send for T {} + /// + /// won't be allowed unless there's an *explicit* implementation of `Send` + /// for `T` + ast::ItemImpl(_, ast::ImplPolarity::Positive, _, + ref trait_ref, ref self_ty, _) => { + self.check_impl(item, self_ty, trait_ref); + } + ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => { + // FIXME(#27579) what amount of WF checking do we need for neg impls? + + let trait_ref = ccx.tcx.impl_trait_ref(local_def(item.id)).unwrap(); + ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id); + match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) { + Some(ty::BoundSend) | Some(ty::BoundSync) => {} + Some(_) | None => { + if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) { + error_192(ccx, item.span); + } + } + } + } + ast::ItemFn(_, _, _, _, _, ref body) => { + self.check_item_fn(item, body); + } + ast::ItemStatic(..) => { + self.check_item_type(item); + } + ast::ItemConst(..) => { + self.check_item_type(item); + } + ast::ItemStruct(ref struct_def, ref ast_generics) => { + self.check_type_defn(item, |fcx| { + vec![struct_variant(fcx, &**struct_def)] + }); + + self.check_variances_for_type_defn(item, ast_generics); + } + ast::ItemEnum(ref enum_def, ref ast_generics) => { + self.check_type_defn(item, |fcx| { + enum_variants(fcx, enum_def) + }); + + self.check_variances_for_type_defn(item, ast_generics); + } + ast::ItemTrait(_, _, _, ref items) => { + self.check_trait(item, items); + } + _ => {} + } + } + + fn check_trait_or_impl_item(&mut self, item_id: ast::NodeId, span: Span) { + let code = self.code.clone(); + self.with_fcx(item_id, span, |fcx, this| { + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + let free_id = fcx.inh.infcx.parameter_environment.free_id; + + let item = fcx.tcx().impl_or_trait_item(local_def(item_id)); + + let mut implied_bounds = match item.container() { + ty::TraitContainer(_) => vec![], + ty::ImplContainer(def_id) => impl_implied_bounds(fcx, def_id, span) + }; + + match item { + ty::ConstTraitItem(assoc_const) => { + let ty = fcx.instantiate_type_scheme(span, free_substs, &assoc_const.ty); + fcx.register_wf_obligation(ty, span, code.clone()); + } + ty::MethodTraitItem(method) => { + reject_shadowing_type_parameters(fcx.tcx(), span, &method.generics); + let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method.fty); + let predicates = fcx.instantiate_bounds(span, free_substs, &method.predicates); + this.check_fn_or_method(fcx, span, &method_ty, &predicates, + free_id, &mut implied_bounds); + } + ty::TypeTraitItem(assoc_type) => { + if let Some(ref ty) = assoc_type.ty { + let ty = fcx.instantiate_type_scheme(span, free_substs, ty); + fcx.register_wf_obligation(ty, span, code.clone()); + } + } + } + + implied_bounds + }) + } + + fn with_item_fcx(&mut self, item: &ast::Item, f: F) where + F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>, + &mut CheckTypeWellFormedVisitor<'ccx,'tcx>) -> Vec>, + { + self.with_fcx(item.id, item.span, f) + } + + fn with_fcx(&mut self, id: ast::NodeId, span: Span, mut f: F) where + F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>, + &mut CheckTypeWellFormedVisitor<'ccx,'tcx>) -> Vec>, + { + let ccx = self.ccx; + let param_env = ty::ParameterEnvironment::for_item(ccx.tcx, id); + let tables = RefCell::new(ty::Tables::empty()); + let inh = Inherited::new(ccx.tcx, &tables, param_env); + let fcx = blank_fn_ctxt(ccx, &inh, ty::FnDiverging, id); + let wf_tys = f(&fcx, self); + fcx.select_all_obligations_or_error(); + regionck::regionck_item(&fcx, id, span, &wf_tys); + } + + /// In a type definition, we check that to ensure that the types of the fields are well-formed. + fn check_type_defn(&mut self, item: &ast::Item, mut lookup_fields: F) where + F: for<'fcx> FnMut(&FnCtxt<'fcx, 'tcx>) -> Vec>, + { + self.with_item_fcx(item, |fcx, this| { + let variants = lookup_fields(fcx); + + for variant in &variants { + // For DST, all intermediate types must be sized. + if let Some((_, fields)) = variant.fields.split_last() { + for field in fields { + fcx.register_builtin_bound( + field.ty, + ty::BoundSized, + traits::ObligationCause::new(field.span, + fcx.body_id, + traits::FieldSized)); + } + } + + // All field types must be well-formed. + for field in &variant.fields { + fcx.register_wf_obligation(field.ty, field.span, this.code.clone()) + } + } + + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + let predicates = fcx.tcx().lookup_predicates(local_def(item.id)); + let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + this.check_where_clauses(fcx, item.span, &predicates); + + vec![] // no implied bounds in a struct def'n + }); + } + + fn check_trait(&mut self, + item: &ast::Item, + items: &[P]) + { + let trait_def_id = local_def(item.id); + + if self.ccx.tcx.trait_has_default_impl(trait_def_id) { + if !items.is_empty() { + error_380(self.ccx, item.span); + } + } + + self.with_item_fcx(item, |fcx, this| { + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + let predicates = fcx.tcx().lookup_predicates(trait_def_id); + let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + this.check_where_clauses(fcx, item.span, &predicates); + vec![] + }); + } + + fn check_item_fn(&mut self, + item: &ast::Item, + body: &ast::Block) + { + self.with_item_fcx(item, |fcx, this| { + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + let type_scheme = fcx.tcx().lookup_item_type(local_def(item.id)); + let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); + let bare_fn_ty = match item_ty.sty { + ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty, + _ => { + this.tcx().sess.span_bug(item.span, "Fn item without bare fn type"); + } + }; + + let predicates = fcx.tcx().lookup_predicates(local_def(item.id)); + let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + + let mut implied_bounds = vec![]; + this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates, + body.id, &mut implied_bounds); + implied_bounds + }) + } + + fn check_item_type(&mut self, + item: &ast::Item) + { + debug!("check_item_type: {:?}", item); + + self.with_item_fcx(item, |fcx, this| { + let type_scheme = fcx.tcx().lookup_item_type(local_def(item.id)); + let item_ty = fcx.instantiate_type_scheme(item.span, + &fcx.inh + .infcx + .parameter_environment + .free_substs, + &type_scheme.ty); + + fcx.register_wf_obligation(item_ty, item.span, this.code.clone()); + + vec![] // no implied bounds in a const etc + }); + } + + fn check_impl(&mut self, + item: &ast::Item, + ast_self_ty: &ast::Ty, + ast_trait_ref: &Option) + { + debug!("check_impl: {:?}", item); + + self.with_item_fcx(item, |fcx, this| { + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + let item_def_id = local_def(item.id); + + match *ast_trait_ref { + Some(ref ast_trait_ref) => { + let trait_ref = fcx.tcx().impl_trait_ref(item_def_id).unwrap(); + let trait_ref = + fcx.instantiate_type_scheme( + ast_trait_ref.path.span, free_substs, &trait_ref); + let obligations = + wf::trait_obligations(fcx.infcx(), + fcx.body_id, + &trait_ref, + ast_trait_ref.path.span, + true); + for obligation in obligations { + fcx.register_predicate(obligation); + } + } + None => { + let self_ty = fcx.tcx().node_id_to_type(item.id); + let self_ty = fcx.instantiate_type_scheme(item.span, free_substs, &self_ty); + fcx.register_wf_obligation(self_ty, ast_self_ty.span, this.code.clone()); + } + } + + let predicates = fcx.tcx().lookup_predicates(item_def_id); + let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates); + this.check_where_clauses(fcx, item.span, &predicates); + + impl_implied_bounds(fcx, local_def(item.id), item.span) + }); + } + + fn check_where_clauses<'fcx>(&mut self, + fcx: &FnCtxt<'fcx,'tcx>, + span: Span, + predicates: &ty::InstantiatedPredicates<'tcx>) + { + let obligations = + predicates.predicates + .iter() + .flat_map(|p| wf::predicate_obligations(fcx.infcx(), + fcx.body_id, + p, + span, + true)); + + for obligation in obligations { + fcx.register_predicate(obligation); + } + } + + fn check_fn_or_method<'fcx>(&mut self, + fcx: &FnCtxt<'fcx,'tcx>, + span: Span, + fty: &ty::BareFnTy<'tcx>, + predicates: &ty::InstantiatedPredicates<'tcx>, + free_id: ast::NodeId, + implied_bounds: &mut Vec>) + { + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + let fty = fcx.instantiate_type_scheme(span, free_substs, fty); + let free_id_outlive = DestructionScopeData::new(free_id); + let sig = fcx.tcx().liberate_late_bound_regions(free_id_outlive, &fty.sig); + + for &input_ty in &sig.inputs { + fcx.register_wf_obligation(input_ty, span, self.code.clone()); + } + implied_bounds.extend(sig.inputs); + + match sig.output { + ty::FnConverging(output) => { + fcx.register_wf_obligation(output, span, self.code.clone()); + + // FIXME(#25759) return types should not be implied bounds + implied_bounds.push(output); + } + ty::FnDiverging => { } + } + + self.check_where_clauses(fcx, span, predicates); + } + + fn check_variances_for_type_defn(&self, + item: &ast::Item, + ast_generics: &ast::Generics) + { + let item_def_id = local_def(item.id); + let ty_predicates = self.tcx().lookup_predicates(item_def_id); + let variances = self.tcx().item_variances(item_def_id); + + let mut constrained_parameters: HashSet<_> = + variances.types + .iter_enumerated() + .filter(|&(_, _, &variance)| variance != ty::Bivariant) + .map(|(space, index, _)| self.param_ty(ast_generics, space, index)) + .map(|p| Parameter::Type(p)) + .collect(); + + identify_constrained_type_params(self.tcx(), + ty_predicates.predicates.as_slice(), + None, + &mut constrained_parameters); + + for (space, index, _) in variances.types.iter_enumerated() { + let param_ty = self.param_ty(ast_generics, space, index); + if constrained_parameters.contains(&Parameter::Type(param_ty)) { + continue; + } + let span = self.ty_param_span(ast_generics, item, space, index); + self.report_bivariance(span, param_ty.name); + } + + for (space, index, &variance) in variances.regions.iter_enumerated() { + if variance != ty::Bivariant { + continue; + } + + assert_eq!(space, TypeSpace); + let span = ast_generics.lifetimes[index].lifetime.span; + let name = ast_generics.lifetimes[index].lifetime.name; + self.report_bivariance(span, name); + } + } + + fn param_ty(&self, + ast_generics: &ast::Generics, + space: ParamSpace, + index: usize) + -> ty::ParamTy + { + let name = match space { + TypeSpace => ast_generics.ty_params[index].ident.name, + SelfSpace => special_idents::type_self.name, + FnSpace => self.tcx().sess.bug("Fn space occupied?"), + }; + + ty::ParamTy { space: space, idx: index as u32, name: name } + } + + fn ty_param_span(&self, + ast_generics: &ast::Generics, + item: &ast::Item, + space: ParamSpace, + index: usize) + -> Span + { + match space { + TypeSpace => ast_generics.ty_params[index].span, + SelfSpace => item.span, + FnSpace => self.tcx().sess.span_bug(item.span, "Fn space occupied?"), + } + } + + fn report_bivariance(&self, + span: Span, + param_name: ast::Name) + { + error_392(self.tcx(), span, param_name); + + let suggested_marker_id = self.tcx().lang_items.phantom_data(); + match suggested_marker_id { + Some(def_id) => { + self.tcx().sess.fileline_help( + span, + &format!("consider removing `{}` or using a marker such as `{}`", + param_name, + self.tcx().item_path_str(def_id))); + } + None => { + // no lang items, no help! + } + } + } +} + +fn reject_shadowing_type_parameters<'tcx>(tcx: &ty::ctxt<'tcx>, + span: Span, + generics: &ty::Generics<'tcx>) { + let impl_params = generics.types.get_slice(subst::TypeSpace).iter() + .map(|tp| tp.name).collect::>(); + + for method_param in generics.types.get_slice(subst::FnSpace) { + if impl_params.contains(&method_param.name) { + error_194(tcx, span, method_param.name); + } + } +} + +impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { + fn visit_item(&mut self, i: &ast::Item) { + debug!("visit_item: {:?}", i); + self.check_item_well_formed(i); + visit::walk_item(self, i); + } + + fn visit_trait_item(&mut self, trait_item: &'v ast::TraitItem) { + debug!("visit_trait_item: {:?}", trait_item); + self.check_trait_or_impl_item(trait_item.id, trait_item.span); + visit::walk_trait_item(self, trait_item) + } + + fn visit_impl_item(&mut self, impl_item: &'v ast::ImplItem) { + debug!("visit_impl_item: {:?}", impl_item); + self.check_trait_or_impl_item(impl_item.id, impl_item.span); + visit::walk_impl_item(self, impl_item) + } +} + +/////////////////////////////////////////////////////////////////////////// +// ADT + +struct AdtVariant<'tcx> { + fields: Vec>, +} + +struct AdtField<'tcx> { + ty: Ty<'tcx>, + span: Span, +} + +fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + struct_def: &ast::StructDef) + -> AdtVariant<'tcx> { + let fields = + struct_def.fields + .iter() + .map(|field| { + let field_ty = fcx.tcx().node_id_to_type(field.node.id); + let field_ty = fcx.instantiate_type_scheme(field.span, + &fcx.inh + .infcx + .parameter_environment + .free_substs, + &field_ty); + AdtField { ty: field_ty, span: field.span } + }) + .collect(); + AdtVariant { fields: fields } +} + +fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + enum_def: &ast::EnumDef) + -> Vec> { + enum_def.variants.iter() + .map(|variant| { + match variant.node.kind { + ast::TupleVariantKind(ref args) if !args.is_empty() => { + let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id); + + // the regions in the argument types come from the + // enum def'n, and hence will all be early bound + let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap(); + AdtVariant { + fields: args.iter().enumerate().map(|(index, arg)| { + let arg_ty = arg_tys[index]; + let arg_ty = + fcx.instantiate_type_scheme(variant.span, + &fcx.inh + .infcx + .parameter_environment + .free_substs, + &arg_ty); + AdtField { + ty: arg_ty, + span: arg.ty.span + } + }).collect() + } + } + ast::TupleVariantKind(_) => { + AdtVariant { + fields: Vec::new() + } + } + ast::StructVariantKind(ref struct_def) => { + struct_variant(fcx, &**struct_def) + } + } + }) + .collect() +} + +fn impl_implied_bounds<'fcx,'tcx>(fcx: &FnCtxt<'fcx, 'tcx>, + impl_def_id: ast::DefId, + span: Span) + -> Vec> +{ + let free_substs = &fcx.inh.infcx.parameter_environment.free_substs; + match fcx.tcx().impl_trait_ref(impl_def_id) { + Some(ref trait_ref) => { + // Trait impl: take implied bounds from all types that + // appear in the trait reference. + let trait_ref = fcx.instantiate_type_scheme(span, free_substs, trait_ref); + trait_ref.substs.types.as_slice().to_vec() + } + + None => { + // Inherent impl: take implied bounds from the self type. + let self_ty = fcx.tcx().lookup_item_type(impl_def_id).ty; + let self_ty = fcx.instantiate_type_scheme(span, free_substs, &self_ty); + vec![self_ty] + } + } +} + +pub fn error_192<'ccx,'tcx>(ccx: &'ccx CrateCtxt<'ccx, 'tcx>, span: Span) { + span_err!(ccx.tcx.sess, span, E0192, + "negative impls are only allowed for traits with \ + default impls (e.g., `Send` and `Sync`)") +} + +pub fn error_380<'ccx,'tcx>(ccx: &'ccx CrateCtxt<'ccx, 'tcx>, span: Span) { + span_err!(ccx.tcx.sess, span, E0380, + "traits with default impls (`e.g. unsafe impl \ + Trait for ..`) must have no methods or associated items") +} + +pub fn error_392<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, param_name: ast::Name) { + span_err!(tcx.sess, span, E0392, + "parameter `{}` is never used", param_name); +} + +pub fn error_194<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, name: ast::Name) { + span_err!(tcx.sess, span, E0194, + "type parameter `{}` shadows another type parameter of the same name", + name); +} diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 42c6bcbfbb999..1652c67c531d3 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -200,10 +200,13 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. if !traits::is_object_safe(self.tcx, data.principal_def_id()) { - // this just means the self-ty is illegal, - // and probably this error should have - // been reported elsewhere, but I'm trying to avoid - // giving a misleading message below. + // FIXME(#27579). This just means the + // self-ty is illegal; WF will report this + // error. But it will do so as a warning + // for a release or two. For backwards + // compat reasons, then, we continue to + // report it here so that things which + // were errors remain errors. span_err!(self.tcx.sess, self_ty.span, E0372, "the trait `{}` cannot be made into an object", self.tcx.item_path_str(data.principal_def_id())); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index dabc09db68d8e..3c315e335c637 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -490,6 +490,8 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { } ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | ty::Predicate::Projection(..) => { false } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5d7822a71bb5d..e6824c811c58e 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -345,9 +345,23 @@ pub fn check_crate(tcx: &ty::ctxt, trait_map: ty::TraitMap) { time(time_passes, "coherence checking", (), |_| coherence::check_coherence(&ccx)); - time(time_passes, "type checking", (), |_| + time(time_passes, "wf checking (old)", (), |_| + check::check_wf_old(&ccx)); + + time(time_passes, "item-types checking", (), |_| check::check_item_types(&ccx)); + time(time_passes, "item-bodies checking", (), |_| + check::check_item_bodies(&ccx)); + + time(time_passes, "drop-impl checking", (), |_| + check::check_drop_impls(&ccx)); + + // Do this last so that if there are errors in the old code, they + // get reported, and we don't get extra warnings. + time(time_passes, "wf checking (new)", (), |_| + check::check_wf_new(&ccx)); + check_for_entry_fn(&ccx); tcx.sess.abort_if_errors(); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 52f69784b5cc7..04b1f8ee1b1d3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -818,7 +818,9 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::Equate(ref pred) => pred.clean(cx), Predicate::RegionOutlives(ref pred) => pred.clean(cx), Predicate::TypeOutlives(ref pred) => pred.clean(cx), - Predicate::Projection(ref pred) => pred.clean(cx) + Predicate::Projection(ref pred) => pred.clean(cx), + Predicate::WellFormed(_) => panic!("not user writable"), + Predicate::ObjectSafe(_) => panic!("not user writable"), } } } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index af1387346106a..5e96ec6ab0df3 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -194,7 +194,7 @@ pub trait Encodable { fn encode(&self, s: &mut S) -> Result<(), S::Error>; } -pub trait Decodable { +pub trait Decodable: Sized { fn decode(d: &mut D) -> Result; } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 4b62434d06894..773bd7f560694 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -369,7 +369,7 @@ mod tests { use sync::{Arc, Mutex, StaticMutex, Condvar}; use thread; - struct Packet(Arc<(Mutex, Condvar)>); + struct Packet(Arc<(Mutex, Condvar)>); unsafe impl Send for Packet {} unsafe impl Sync for Packet {} diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 3bf170b5fe218..a228cbfd85ba3 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -60,7 +60,7 @@ pub use self::imp::Key as __KeyInner; /// }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct LocalKey { +pub struct LocalKey { // The key itself may be tagged with #[thread_local], and this `Key` is // stored as a `static`, and it's not valid for a static to reference the // address of another thread_local static. For this reason we kinda wonkily diff --git a/src/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index 303ab0f9f0134..810e3bb62f705 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -55,7 +55,7 @@ pub use self::imp::KeyInner as __KeyInner; #[unstable(feature = "scoped_tls", reason = "scoped TLS has yet to have wide enough use to fully consider \ stabilizing its interface")] -pub struct ScopedKey { inner: fn() -> &'static imp::KeyInner } +pub struct ScopedKey { inner: fn() -> &'static imp::KeyInner } /// Declare a new scoped thread local storage key. /// diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bcc90dc47d9df..08c6dcc7f872a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -475,7 +475,7 @@ pub enum WherePredicate { /// A lifetime predicate, e.g. `'a: 'b+'c` RegionPredicate(WhereRegionPredicate), /// An equality predicate (unsupported) - EqPredicate(WhereEqPredicate) + EqPredicate(WhereEqPredicate), } /// A type bound, eg `for<'c> Foo: Send+Clone+'c` diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 669b930ecc92e..3c8347f8a8e0e 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -30,6 +30,18 @@ macro_rules! span_err { }) } +#[macro_export] +macro_rules! span_err_or_warn { + ($is_warning:expr, $session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ + __diagnostic_used!($code); + if $is_warning { + $session.span_warn_with_code($span, &format!($($message)*), stringify!($code)) + } else { + $session.span_err_with_code($span, &format!($($message)*), stringify!($code)) + } + }) +} + #[macro_export] macro_rules! span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ diff --git a/src/test/auxiliary/issue13507.rs b/src/test/auxiliary/issue13507.rs index 7d82e79f94911..78d0394a6e5ad 100644 --- a/src/test/auxiliary/issue13507.rs +++ b/src/test/auxiliary/issue13507.rs @@ -72,7 +72,6 @@ pub mod testtypes { // Tests TyTrait pub trait FooTrait { fn foo_method(&self) -> usize; - fn foo_static_method() -> usize; } // Tests TyStruct diff --git a/src/test/compile-fail/associated-types-outlives.rs b/src/test/compile-fail/associated-types-outlives.rs new file mode 100644 index 0000000000000..f070ab6799c08 --- /dev/null +++ b/src/test/compile-fail/associated-types-outlives.rs @@ -0,0 +1,38 @@ +// Copyright 2015 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 issue #24622. The older associated types code +// was erroneously assuming that all projections outlived the current +// fn body, causing this (invalid) code to be accepted. + +pub trait Foo<'a> { + type Bar; +} + +impl<'a, T:'a> Foo<'a> for T { + type Bar = &'a T; +} + +fn denormalise<'a, T>(t: &'a T) -> >::Bar { + t +} + +pub fn free_and_use Foo<'a>, + F: for<'a> FnOnce(>::Bar)>(x: T, f: F) { + let y; + 'body: loop { // lifetime annotations added for clarity + 's: loop { y = denormalise(&x); break } + drop(x); //~ ERROR cannot move out of `x` because it is borrowed + return f(y); + } +} + +pub fn main() { +} diff --git a/src/test/compile-fail/associated-types-projection-to-unrelated-trait-in-method-without-default.rs b/src/test/compile-fail/associated-types-projection-to-unrelated-trait-in-method-without-default.rs new file mode 100644 index 0000000000000..3f72391ff90c7 --- /dev/null +++ b/src/test/compile-fail/associated-types-projection-to-unrelated-trait-in-method-without-default.rs @@ -0,0 +1,39 @@ +// Copyright 2015 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. + +// Check that we get an error when you use `::Value` in +// the trait definition even if there is no default method. + +trait Get { + type Value; +} + +trait Other { + fn okay(&self, foo: U, bar: ::Value); + //~^ ERROR E0277 +} + +impl Get for () { + type Value = f32; +} + +impl Get for f64 { + type Value = u32; +} + +impl Other for () { + fn okay(&self, _foo: U, _bar: ::Value) { } +} + +impl Other for f64 { + fn okay(&self, _foo: U, _bar: ::Value) { } +} + +fn main() { } diff --git a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs b/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs index 4e6ae96e3fc75..d18746cdf0ba5 100644 --- a/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs +++ b/src/test/compile-fail/cast-to-unsized-trait-object-suggestion.rs @@ -9,12 +9,12 @@ // except according to those terms. fn main() { - &1 as Copy; + &1 as Send; //~^ ERROR cast to unsized type //~| HELP try casting to a reference instead: - //~| SUGGESTION &1 as &Copy; - Box::new(1) as Copy; + //~| SUGGESTION &1 as &Send; + Box::new(1) as Send; //~^ ERROR cast to unsized type //~| HELP try casting to a `Box` instead: - //~| SUGGESTION Box::new(1) as Box; + //~| SUGGESTION Box::new(1) as Box; } diff --git a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs index d27529bad4305..16ed73e9095e4 100644 --- a/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs +++ b/src/test/compile-fail/closure-bounds-static-cant-capture-borrowed.rs @@ -12,7 +12,9 @@ fn bar(blk: F) where F: FnOnce() + 'static { } fn foo(x: &()) { - bar(|| { //~ ERROR cannot infer an appropriate lifetime + bar(|| { + //~^ ERROR cannot infer + //~| ERROR does not fulfill let _ = x; }) } diff --git a/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs b/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs new file mode 100644 index 0000000000000..ce6baeb204c93 --- /dev/null +++ b/src/test/compile-fail/coherence-impl-trait-for-trait-object-safe.rs @@ -0,0 +1,19 @@ +// Copyright 2015 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. + +// Test that we give suitable error messages when the user attempts to +// impl a trait `Trait` for its own object type. + +// If the trait is not object-safe, we give a more tailored message +// because we're such schnuckels: +trait NotObjectSafe { fn eq(&self, other: Self); } +impl NotObjectSafe for NotObjectSafe { } //~ ERROR E0372 + +fn main() { } diff --git a/src/test/compile-fail/coherence-impl-trait-for-trait.rs b/src/test/compile-fail/coherence-impl-trait-for-trait.rs index 332965cc94014..cd75b0e34f24b 100644 --- a/src/test/compile-fail/coherence-impl-trait-for-trait.rs +++ b/src/test/compile-fail/coherence-impl-trait-for-trait.rs @@ -24,9 +24,4 @@ impl Baz for Baz { } //~ ERROR E0371 trait Other { } impl Other for Baz { } // OK, Other not a supertrait of Baz -// If the trait is not object-safe, we give a more tailored message -// because we're such schnuckels: -trait NotObjectSafe { fn eq(&self, other: Self); } -impl NotObjectSafe for NotObjectSafe { } //~ ERROR E0372 - fn main() { } diff --git a/src/test/compile-fail/dropck-object-cycle.rs b/src/test/compile-fail/dropck-object-cycle.rs new file mode 100644 index 0000000000000..5432cbf402a0c --- /dev/null +++ b/src/test/compile-fail/dropck-object-cycle.rs @@ -0,0 +1,57 @@ +// Copyright 2014 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. + +// This test used to be part of a run-pass test, but revised outlives +// rule means that it no longer compiles. + +#![allow(unused_variables)] + +trait Trait<'a> { + fn long(&'a self) -> isize; + fn short<'b>(&'b self) -> isize; +} + +fn object_invoke1<'d>(x: &'d Trait<'d>) -> (isize, isize) { loop { } } + +trait MakerTrait { + fn mk() -> Self; +} + +fn make_val() -> T { + MakerTrait::mk() +} + +impl<'t> MakerTrait for Box+'static> { + fn mk() -> Box+'static> { loop { } } +} + +pub fn main() { + let m : Box = make_val(); + assert_eq!(object_invoke1(&*m), (4,5)); + //~^ ERROR `*m` does not live long enough + + // the problem here is that the full type of `m` is + // + // Box+'static> + // + // Here `'m` must be exactly the lifetime of the variable `m`. + // This is because of two requirements: + // 1. First, the basic type rules require that the + // type of `m`'s value outlives the lifetime of `m`. This puts a lower + // bound `'m`. + // + // 2. Meanwhile, the signature of `object_invoke1` requires that + // we create a reference of type `&'d Trait<'d>` for some `'d`. + // `'d` cannot outlive `'m`, so that forces the lifetime to be `'m`. + // + // This then conflicts with the dropck rules, which require that + // the type of `m` *strictly outlives* `'m`. Hence we get an + // error. +} diff --git a/src/test/compile-fail/infinite-instantiation.rs b/src/test/compile-fail/infinite-instantiation.rs index 559e0e9a292a6..9b02bf4cb85a8 100644 --- a/src/test/compile-fail/infinite-instantiation.rs +++ b/src/test/compile-fail/infinite-instantiation.rs @@ -15,7 +15,7 @@ // so for now just live with it. // This test case was originally for issue #2258. -trait ToOpt { +trait ToOpt: Sized { fn to_option(&self) -> Option; } diff --git a/src/test/compile-fail/issue-16747.rs b/src/test/compile-fail/issue-16747.rs index a3529c9ea90b6..dd7e8a869eca9 100644 --- a/src/test/compile-fail/issue-16747.rs +++ b/src/test/compile-fail/issue-16747.rs @@ -15,10 +15,10 @@ trait ListItem<'a> { trait Collection { fn len(&self) -> usize; } struct List<'a, T: ListItem<'a>> { + slice: &'a [T] //~^ ERROR the parameter type `T` may not live long enough //~| HELP consider adding an explicit lifetime bound //~| NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at - slice: &'a [T] } impl<'a, T: ListItem<'a>> Collection for List<'a, T> { fn len(&self) -> usize { diff --git a/src/test/compile-fail/issue-18389.rs b/src/test/compile-fail/issue-18389.rs index 41be78dd7b96e..7d95082079f9f 100644 --- a/src/test/compile-fail/issue-18389.rs +++ b/src/test/compile-fail/issue-18389.rs @@ -11,10 +11,7 @@ use std::any::Any; use std::any::TypeId; -pub trait Pt {} -pub trait Rt {} - -trait Private { +trait Private { fn call(&self, p: P, r: R); } pub trait Public: Private< //~ ERROR private trait in exported type parameter bound diff --git a/src/test/compile-fail/issue-18959.rs b/src/test/compile-fail/issue-18959.rs index ebda2481803a7..95176da9020d5 100644 --- a/src/test/compile-fail/issue-18959.rs +++ b/src/test/compile-fail/issue-18959.rs @@ -21,10 +21,11 @@ impl Foo for Thing { fn foo(b: &Bar) { b.foo(&0) //~^ ERROR the trait `Foo` is not implemented for the type `Bar` + //~| ERROR E0038 } fn main() { let mut thing = Thing; - let test: &Bar = &mut thing; //~ ERROR cannot convert to a trait object + let test: &Bar = &mut thing; //~ ERROR E0038 foo(test); } diff --git a/src/test/compile-fail/issue-19380.rs b/src/test/compile-fail/issue-19380.rs index dbc0e410cf95c..aae77c90b6bf2 100644 --- a/src/test/compile-fail/issue-19380.rs +++ b/src/test/compile-fail/issue-19380.rs @@ -23,6 +23,6 @@ struct Bar { const FOO : Foo = Foo; const BAR : Bar = Bar { foos: &[&FOO]}; -//~^ ERROR: cannot convert to a trait object because trait `Qiz` is not object-safe [E0038] +//~^ ERROR E0038 fn main() { } diff --git a/src/test/compile-fail/issue-19538.rs b/src/test/compile-fail/issue-19538.rs index b9c90755b2c73..a619050058262 100644 --- a/src/test/compile-fail/issue-19538.rs +++ b/src/test/compile-fail/issue-19538.rs @@ -25,5 +25,6 @@ impl Bar for Thing { } fn main() { let mut thing = Thing; let test: &mut Bar = &mut thing; - //~^ ERROR cannot convert to a trait object because trait `Bar` is not object-safe + //~^ ERROR E0038 + //~| ERROR E0038 } diff --git a/src/test/compile-fail/issue-20005.rs b/src/test/compile-fail/issue-20005.rs index d91479a2e4e89..041289c2ccdbd 100644 --- a/src/test/compile-fail/issue-20005.rs +++ b/src/test/compile-fail/issue-20005.rs @@ -19,6 +19,7 @@ trait To { self //~ error: the trait `core::marker::Sized` is not implemented ) -> >::Result where Dst: From { From::from( //~ error: the trait `core::marker::Sized` is not implemented + //~^ ERROR E0277 self ) } diff --git a/src/test/compile-fail/issue-23041.rs b/src/test/compile-fail/issue-23041.rs index 68895759c5c2a..c08cdd72b3825 100644 --- a/src/test/compile-fail/issue-23041.rs +++ b/src/test/compile-fail/issue-23041.rs @@ -13,6 +13,5 @@ fn main() { fn bar(x:i32) ->i32 { 3*x }; let b:Box = Box::new(bar as fn(_)->_); - b.downcast_ref::_>(); - //~^ ERROR cannot determine a type for this expression: unconstrained type + b.downcast_ref::_>(); //~ ERROR E0101 } diff --git a/src/test/compile-fail/issue-24013.rs b/src/test/compile-fail/issue-24013.rs index 0adad8a88cbc9..df857a2e6eb1f 100644 --- a/src/test/compile-fail/issue-24013.rs +++ b/src/test/compile-fail/issue-24013.rs @@ -13,5 +13,5 @@ fn main() { let a = 1; let b = 2; unsafe {swap::<&mut _>(transmute(&a), transmute(&b))}; - //~^ ERROR cannot determine a type for this expression: unconstrained type + //~^ ERROR unable to infer enough type information about `_` } diff --git a/src/test/compile-fail/issue-27592.rs b/src/test/compile-fail/issue-27592.rs new file mode 100644 index 0000000000000..ccf5eabc1110d --- /dev/null +++ b/src/test/compile-fail/issue-27592.rs @@ -0,0 +1,29 @@ +// Copyright 2015 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 issue #27591. + +fn write<'a, F: ::std::ops::FnOnce()->::std::fmt::Arguments<'a> + 'a>(fcn: F) { + use std::fmt::Write; + let _ = match fcn() { a => write!(&mut Stream, "{}", a), }; +} + +struct Stream; +impl ::std::fmt::Write for Stream { + fn write_str(&mut self, _s: &str) -> ::std::fmt::Result { + Ok( () ) + } +} + +fn main() { + write(|| format_args!("{}", "Hello world")); + //~^ ERROR borrowed value does not live long enough + //~| ERROR borrowed value does not live long enough +} diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs index 9a166a6752b7e..ee8bc7d6e2901 100644 --- a/src/test/compile-fail/issue-3907-2.rs +++ b/src/test/compile-fail/issue-3907-2.rs @@ -17,6 +17,7 @@ struct S { name: isize } -fn bar(_x: Foo) {} //~ ERROR the trait `core::marker::Sized` is not implemented +fn bar(_x: Foo) {} +//~^ ERROR E0277 fn main() {} diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 066590252a54a..0731fbaf01c43 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -31,7 +31,9 @@ fn a() { fn b() { let x: Box<_> = box 3; let y = &x; - let z = &x as &Foo; //~ ERROR E0038 + let z = &x as &Foo; + //~^ ERROR E0038 + //~| ERROR E0038 } fn main() { } diff --git a/src/test/compile-fail/object-safety-generics.rs b/src/test/compile-fail/object-safety-generics.rs index fd20accfa1e6b..63e5718537cf9 100644 --- a/src/test/compile-fail/object-safety-generics.rs +++ b/src/test/compile-fail/object-safety-generics.rs @@ -23,14 +23,15 @@ trait Quux { fn make_bar(t: &T) -> &Bar { t - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE method `bar` has generic type parameters } fn make_bar_explicit(t: &T) -> &Bar { t as &Bar - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE method `bar` has generic type parameters + //~| ERROR E0038 } fn make_quux(t: &T) -> &Quux { diff --git a/src/test/compile-fail/object-safety-issue-22040.rs b/src/test/compile-fail/object-safety-issue-22040.rs index edf32131b6875..de419a259a24c 100644 --- a/src/test/compile-fail/object-safety-issue-22040.rs +++ b/src/test/compile-fail/object-safety-issue-22040.rs @@ -25,6 +25,7 @@ struct SExpr<'x> { impl<'x> PartialEq for SExpr<'x> { fn eq(&self, other:&SExpr<'x>) -> bool { println!("L1: {} L2: {}", self.elements.len(), other.elements.len()); + //~^ ERROR E0038 let result = self.elements.len() == other.elements.len(); println!("Got compare {}", result); @@ -43,8 +44,8 @@ impl <'x> Expr for SExpr<'x> { } fn main() { - let a: Box = Box::new(SExpr::new()); //~ ERROR trait `Expr` is not object-safe - let b: Box = Box::new(SExpr::new()); //~ ERROR trait `Expr` is not object-safe + let a: Box = Box::new(SExpr::new()); //~ ERROR E0038 + let b: Box = Box::new(SExpr::new()); //~ ERROR E0038 - assert_eq!(a , b); + // assert_eq!(a , b); } diff --git a/src/test/compile-fail/object-safety-mentions-Self.rs b/src/test/compile-fail/object-safety-mentions-Self.rs index b546774ccbd8c..55b780906355a 100644 --- a/src/test/compile-fail/object-safety-mentions-Self.rs +++ b/src/test/compile-fail/object-safety-mentions-Self.rs @@ -26,26 +26,28 @@ trait Quux { fn make_bar(t: &T) -> &Bar { t - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE method `bar` references the `Self` type in its arguments or return type } fn make_bar_explicit(t: &T) -> &Bar { t as &Bar - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE method `bar` references the `Self` type in its arguments or return type + //~| ERROR E0038 } fn make_baz(t: &T) -> &Baz { t - //~^ ERROR `Baz` is not object-safe + //~^ ERROR E0038 //~| NOTE method `bar` references the `Self` type in its arguments or return type } fn make_baz_explicit(t: &T) -> &Baz { t as &Baz - //~^ ERROR `Baz` is not object-safe + //~^ ERROR E0038 //~| NOTE method `bar` references the `Self` type in its arguments or return type + //~| ERROR E0038 } fn make_quux(t: &T) -> &Quux { diff --git a/src/test/compile-fail/object-safety-no-static.rs b/src/test/compile-fail/object-safety-no-static.rs index 6a010d49692d2..2dc7983d1b561 100644 --- a/src/test/compile-fail/object-safety-no-static.rs +++ b/src/test/compile-fail/object-safety-no-static.rs @@ -17,14 +17,15 @@ trait Foo { fn foo_implicit(b: Box) -> Box { b - //~^ ERROR cannot convert to a trait object + //~^ ERROR E0038 //~| NOTE method `foo` has no receiver } fn foo_explicit(b: Box) -> Box { b as Box - //~^ ERROR cannot convert to a trait object + //~^ ERROR E0038 //~| NOTE method `foo` has no receiver + //~| ERROR E0038 } fn main() { diff --git a/src/test/compile-fail/object-safety-sized-2.rs b/src/test/compile-fail/object-safety-sized-2.rs index 3a02461bbb223..401602bd681a3 100644 --- a/src/test/compile-fail/object-safety-sized-2.rs +++ b/src/test/compile-fail/object-safety-sized-2.rs @@ -19,14 +19,15 @@ trait Bar fn make_bar(t: &T) -> &Bar { t - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE the trait cannot require that `Self : Sized` } fn make_bar_explicit(t: &T) -> &Bar { t as &Bar - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE the trait cannot require that `Self : Sized` + //~| ERROR E0038 } fn main() { diff --git a/src/test/compile-fail/object-safety-sized.rs b/src/test/compile-fail/object-safety-sized.rs index bc214f6f3d962..29b4e4db65c36 100644 --- a/src/test/compile-fail/object-safety-sized.rs +++ b/src/test/compile-fail/object-safety-sized.rs @@ -17,14 +17,15 @@ trait Bar : Sized { fn make_bar(t: &T) -> &Bar { t - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE the trait cannot require that `Self : Sized` } fn make_bar_explicit(t: &T) -> &Bar { t as &Bar - //~^ ERROR `Bar` is not object-safe + //~^ ERROR E0038 //~| NOTE the trait cannot require that `Self : Sized` + //~| ERROR E0038 } fn main() { diff --git a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs index d3f9dc73020fb..ba82635a4016e 100644 --- a/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs +++ b/src/test/compile-fail/object-safety-supertrait-mentions-Self.rs @@ -24,7 +24,7 @@ fn make_bar>(t: &T) -> &Bar { fn make_baz(t: &T) -> &Baz { t - //~^ ERROR `Baz` is not object-safe + //~^ ERROR E0038 //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing } diff --git a/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs b/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs index 9a13541bd0b17..f2ff877cd8236 100644 --- a/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs +++ b/src/test/compile-fail/regions-assoc-type-in-supertrait-outlives-container.rs @@ -47,7 +47,7 @@ fn with_assoc<'a,'b>() { // outlive 'a. In this case, that means TheType<'b>::TheAssocType, // which is &'b (), must outlive 'a. - let _: &'a WithAssoc> = loop { }; //~ ERROR cannot infer + let _: &'a WithAssoc> = loop { }; //~ ERROR reference has a longer lifetime } fn main() { diff --git a/src/test/compile-fail/regions-close-associated-type-into-object.rs b/src/test/compile-fail/regions-close-associated-type-into-object.rs index fdc97ecaf21e2..61897aac18769 100644 --- a/src/test/compile-fail/regions-close-associated-type-into-object.rs +++ b/src/test/compile-fail/regions-close-associated-type-into-object.rs @@ -72,13 +72,12 @@ fn meh1<'a, T: Iter>(v: &'a T) -> Box where T::Item : Clone { // This case is kind of interesting. It's the same as `ok3` but - // without the explicit declaration. In principle, it seems like - // we ought to be able to infer that `T::Item : 'a` because we - // invoked `v.as_self()` which yielded a value of type `&'a - // T::Item`. But we're not that smart at present. + // without the explicit declaration. This is valid because `T: 'a + // => T::Item: 'a`, and the former we can deduce from our argument + // of type `&'a T`. let item = Clone::clone(v.as_item()); - Box::new(item) //~ ERROR associated type `::Item` may not live + Box::new(item) } fn main() {} diff --git a/src/test/compile-fail/regions-close-object-into-object-1.rs b/src/test/compile-fail/regions-close-object-into-object-1.rs index 5472e09ba4be4..5d9818d624b7e 100644 --- a/src/test/compile-fail/regions-close-object-into-object-1.rs +++ b/src/test/compile-fail/regions-close-object-into-object-1.rs @@ -12,7 +12,7 @@ #![allow(warnings)] trait A { } -struct B<'a, T>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (A+'a)); trait X { } diff --git a/src/test/compile-fail/regions-close-object-into-object-2.rs b/src/test/compile-fail/regions-close-object-into-object-2.rs index 1ef000852d561..6cef995665517 100644 --- a/src/test/compile-fail/regions-close-object-into-object-2.rs +++ b/src/test/compile-fail/regions-close-object-into-object-2.rs @@ -11,7 +11,7 @@ #![feature(box_syntax)] trait A { } -struct B<'a, T>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (A+'a)); trait X { } impl<'a, T> X for B<'a, T> {} diff --git a/src/test/compile-fail/regions-close-object-into-object-3.rs b/src/test/compile-fail/regions-close-object-into-object-3.rs index b7dc759b2717f..3004245b15a24 100644 --- a/src/test/compile-fail/regions-close-object-into-object-3.rs +++ b/src/test/compile-fail/regions-close-object-into-object-3.rs @@ -12,7 +12,7 @@ #![allow(warnings)] trait A { } -struct B<'a, T>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (A+'a)); trait X { } impl<'a, T> X for B<'a, T> {} diff --git a/src/test/compile-fail/regions-close-object-into-object-4.rs b/src/test/compile-fail/regions-close-object-into-object-4.rs index 247578d253ea0..bc5b7b7cf7874 100644 --- a/src/test/compile-fail/regions-close-object-into-object-4.rs +++ b/src/test/compile-fail/regions-close-object-into-object-4.rs @@ -11,7 +11,7 @@ #![feature(box_syntax)] trait A { } -struct B<'a, T>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (A+'a)); trait X { } impl<'a, T> X for B<'a, T> {} diff --git a/src/test/compile-fail/regions-close-object-into-object-5.rs b/src/test/compile-fail/regions-close-object-into-object-5.rs index 253132e5f07d0..ac269a4d896f2 100644 --- a/src/test/compile-fail/regions-close-object-into-object-5.rs +++ b/src/test/compile-fail/regions-close-object-into-object-5.rs @@ -16,15 +16,22 @@ trait A fn get(&self) -> T { panic!() } } -struct B<'a, T>(&'a (A+'a)); +struct B<'a, T:'a>(&'a (A+'a)); trait X { fn foo(&self) {} } impl<'a, T> X for B<'a, T> {} fn f<'a, T, U>(v: Box+'static>) -> Box { - box B(&*v) as Box //~ ERROR the parameter type `T` may not live long enough + // oh dear! + box B(&*v) as Box //~^ ERROR the parameter type `T` may not live long enough + //~| WARNING the parameter type `T` may not live long enough + //~| WARNING the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| WARNING the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough } fn main() {} diff --git a/src/test/compile-fail/regions-enum-not-wf.rs b/src/test/compile-fail/regions-enum-not-wf.rs index 0165dbdabf3c2..e21f92bc9b885 100644 --- a/src/test/compile-fail/regions-enum-not-wf.rs +++ b/src/test/compile-fail/regions-enum-not-wf.rs @@ -12,25 +12,27 @@ #![allow(dead_code)] -enum Ref1<'a, T> { //~ ERROR the parameter type `T` may not live long enough - Ref1Variant1(&'a T) +enum Ref1<'a, T> { + Ref1Variant1(&'a T) //~ ERROR the parameter type `T` may not live long enough } -enum Ref2<'a, T> { //~ ERROR the parameter type `T` may not live long enough +enum Ref2<'a, T> { Ref2Variant1, - Ref2Variant2(isize, &'a T), + Ref2Variant2(isize, &'a T), //~ ERROR the parameter type `T` may not live long enough } enum RefOk<'a, T:'a> { RefOkVariant1(&'a T) } -enum RefIndirect<'a, T> { //~ ERROR the parameter type `T` may not live long enough +enum RefIndirect<'a, T> { RefIndirectVariant1(isize, RefOk<'a,T>) + //~^ ERROR the parameter type `T` may not live long enough } -enum RefDouble<'a, 'b, T> { //~ ERROR reference has a longer lifetime than the data +enum RefDouble<'a, 'b, T> { RefDoubleVariant1(&'a &'b T) + //~^ ERROR reference has a longer lifetime than the data } fn main() { } diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-1.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-1.rs new file mode 100644 index 0000000000000..65594ab8f2e29 --- /dev/null +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-1.rs @@ -0,0 +1,40 @@ +// 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. + +// Illustrates the "projection gap": in this test, even though we know +// that `T::Foo: 'x`, that does not tell us that `T: 'x`, because +// there might be other ways for the caller of `func` to show that +// `T::Foo: 'x` holds (e.g., where-clause). + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) +{ + wf::<&'x T>(); + //~^ ERROR the parameter type `T` may not live long enough +} + +fn caller2<'x, T:Trait1<'x>>(t: &'x T) +{ + wf::<&'x T::Foo>(); // OK +} + +fn caller3<'x, T:Trait1<'x>>(t: &'x T::Foo) +{ + wf::<&'x T::Foo>(); // OK +} + +fn main() { } diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs new file mode 100644 index 0000000000000..b3037a1e187f4 --- /dev/null +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-2.rs @@ -0,0 +1,33 @@ +// 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. + +// Along with the other tests in this series, illustrates the +// "projection gap": in this test, we know that `T: 'x`, and that is +// enough to conclude that `T::Foo: 'x`. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T) +{ + wf::<&'x T::Foo>(); +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs new file mode 100644 index 0000000000000..a2e6de2137696 --- /dev/null +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-3.rs @@ -0,0 +1,33 @@ +// 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. + +// Along with the other tests in this series, illustrates the +// "projection gap": in this test, we know that `T::Foo: 'x`, and that +// is (naturally) enough to conclude that `T::Foo: 'x`. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) +{ + wf::<&'x T::Foo>(); +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs new file mode 100644 index 0000000000000..b8582f8c26b31 --- /dev/null +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-4.rs @@ -0,0 +1,33 @@ +// 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. + +// Along with the other tests in this series, illustrates the +// "projection gap": in this test, we know that `T: 'x`, and that +// is (naturally) enough to conclude that `T: 'x`. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Trait1<'x> { + type Foo; +} + +// calling this fn should trigger a check that the type argument +// supplied is well-formed. +fn wf() { } + +fn func<'x, T:Trait1<'x>>(t: &'x T) +{ + wf::<&'x T>(); +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/regions-implied-bounds-projection-gap-hr-1.rs b/src/test/compile-fail/regions-implied-bounds-projection-gap-hr-1.rs new file mode 100644 index 0000000000000..47985f931dd34 --- /dev/null +++ b/src/test/compile-fail/regions-implied-bounds-projection-gap-hr-1.rs @@ -0,0 +1,39 @@ +// 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. + +// The "projection gap" is particularly "fun" around higher-ranked +// projections. This is because the current code is hard-coded to say +// that a projection that contains escaping regions, like `>::Foo` where `'z` is bound, can only be found to +// outlive a region if all components that appear free (`'y`, where) +// outlive that region. However, we DON'T add those components to the +// implied bounds set, but rather we treat projections with escaping +// regions as opaque entities, just like projections without escaping +// regions. + +trait Trait1 { } + +trait Trait2<'a, 'b> { + type Foo; +} + +fn wf() { } + +// As a side-effect of the conservative process above, this argument +// is not automatically considered well-formed, since for it to be WF, +// we would need to know that `'y: 'x`, but we do not infer that. +fn callee<'x, 'y, T>( + t: &'x for<'z> Trait1< >::Foo >) +{ + wf::<&'x &'y i32>(); + //~^ ERROR reference has a longer lifetime than the data it references +} + +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-enum-region-rev.rs b/src/test/compile-fail/regions-outlives-nominal-type-enum-region-rev.rs new file mode 100644 index 0000000000000..db25a0698fed4 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-enum-region-rev.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + enum Bar<'a,'b> { + V(&'a Foo<'b>) //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-enum-region.rs b/src/test/compile-fail/regions-outlives-nominal-type-enum-region.rs new file mode 100644 index 0000000000000..403757042d2f3 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-enum-region.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + enum Bar<'a,'b> { + V(&'a Foo<'b>) //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-enum-type-rev.rs b/src/test/compile-fail/regions-outlives-nominal-type-enum-type-rev.rs new file mode 100644 index 0000000000000..cc294651db773 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-enum-type-rev.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_type { + struct Foo { + x: fn(T) + } + enum Bar<'a,'b> { + V(&'a Foo<&'b i32>) //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-enum-type.rs b/src/test/compile-fail/regions-outlives-nominal-type-enum-type.rs new file mode 100644 index 0000000000000..e269767cc1683 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-enum-type.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo { + x: T + } + enum Bar<'a,'b> { + F(&'a Foo<&'b i32>) //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-struct-region-rev.rs b/src/test/compile-fail/regions-outlives-nominal-type-struct-region-rev.rs new file mode 100644 index 0000000000000..c7e6ace8b9224 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-struct-region-rev.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_region { + struct Foo<'a> { + x: fn(&'a i32), + } + struct Bar<'a,'b> { + f: &'a Foo<'b> //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-struct-region.rs b/src/test/compile-fail/regions-outlives-nominal-type-struct-region.rs new file mode 100644 index 0000000000000..2fe6444c33aec --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-struct-region.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_region { + struct Foo<'a> { + x: &'a i32, + } + struct Bar<'a,'b> { + f: &'a Foo<'b> //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-struct-type-rev.rs b/src/test/compile-fail/regions-outlives-nominal-type-struct-type-rev.rs new file mode 100644 index 0000000000000..c4b631bce9874 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-struct-type-rev.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod rev_variant_struct_type { + struct Foo { + x: fn(T) + } + struct Bar<'a,'b> { + f: &'a Foo<&'b i32> //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-outlives-nominal-type-struct-type.rs b/src/test/compile-fail/regions-outlives-nominal-type-struct-type.rs new file mode 100644 index 0000000000000..1c9489444a6a3 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-nominal-type-struct-type.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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. + +// Test that a nominal type (like `Foo<'a>`) outlives `'b` if its +// arguments (like `'a`) outlive `'b`. +// +// Rule OutlivesNominalType from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +mod variant_struct_type { + struct Foo { + x: T + } + struct Bar<'a,'b> { + f: &'a Foo<&'b i32> //~ ERROR reference has a longer lifetime + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs b/src/test/compile-fail/regions-outlives-projection-container-hrtb.rs similarity index 82% rename from src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs rename to src/test/compile-fail/regions-outlives-projection-container-hrtb.rs index 0d3d2e296bec6..b8c4a7f8a8c05 100644 --- a/src/test/compile-fail/regions-assoc-type-outlives-container-hrtb.rs +++ b/src/test/compile-fail/regions-outlives-projection-container-hrtb.rs @@ -37,10 +37,10 @@ pub struct WithHrAssoc } fn with_assoc<'a,'b>() { - // We get no error here because the where clause has a higher-ranked assoc type, - // which could not be projected from. + // We get an error because beacuse 'b:'a does not hold: let _: &'a WithHrAssoc> = loop { }; + //~^ ERROR reference has a longer lifetime } /////////////////////////////////////////////////////////////////////////// @@ -57,12 +57,13 @@ pub struct WithHrAssocSub } fn with_assoc_sub<'a,'b>() { - // Same here, because although the where clause is not HR, it - // extends a trait in a HR way. + // The error here is just because `'b:'a` must hold for the type + // below to be well-formed, it is not related to the HR relation. let _: &'a WithHrAssocSub> = loop { }; + //~^ ERROR reference has a longer lifetime } #[rustc_error] -fn main() { //~ ERROR compilation successful +fn main() { } diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs b/src/test/compile-fail/regions-outlives-projection-container-wc.rs similarity index 93% rename from src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs rename to src/test/compile-fail/regions-outlives-projection-container-wc.rs index 2ceaea98d2797..71606ba812fac 100644 --- a/src/test/compile-fail/regions-assoc-type-outlives-container-wc.rs +++ b/src/test/compile-fail/regions-outlives-projection-container-wc.rs @@ -41,7 +41,8 @@ fn with_assoc<'a,'b>() { // outlive 'a. In this case, that means TheType<'b>::TheAssocType, // which is &'b (), must outlive 'a. - let _: &'a WithAssoc> = loop { }; //~ ERROR cannot infer + let _: &'a WithAssoc> = loop { }; + //~^ ERROR reference has a longer lifetime } fn main() { diff --git a/src/test/compile-fail/regions-assoc-type-outlives-container.rs b/src/test/compile-fail/regions-outlives-projection-container.rs similarity index 82% rename from src/test/compile-fail/regions-assoc-type-outlives-container.rs rename to src/test/compile-fail/regions-outlives-projection-container.rs index e3e57ff17115c..957e56fe5109f 100644 --- a/src/test/compile-fail/regions-assoc-type-outlives-container.rs +++ b/src/test/compile-fail/regions-outlives-projection-container.rs @@ -45,7 +45,7 @@ fn with_assoc<'a,'b>() { // outlive 'a. In this case, that means TheType<'b>::TheAssocType, // which is &'b (), must outlive 'a. - let _: &'a WithAssoc> = loop { }; //~ ERROR cannot infer + let _: &'a WithAssoc> = loop { }; //~ ERROR reference has a longer lifetime } fn with_assoc1<'a,'b>() where 'b : 'a { @@ -59,11 +59,10 @@ fn with_assoc1<'a,'b>() where 'b : 'a { } fn without_assoc<'a,'b>() { - // Here there are no associated types and the `'b` appearing in - // `TheType<'b>` is purely covariant, so there is no requirement - // that `'b:'a` holds. + // Here there are no associated types but there is a requirement + // that `'b:'a` holds because the `'b` appears in `TheType<'b>`. - let _: &'a WithoutAssoc> = loop { }; + let _: &'a WithoutAssoc> = loop { }; //~ ERROR reference has a longer lifetime } fn call_with_assoc<'a,'b>() { @@ -72,13 +71,13 @@ fn call_with_assoc<'a,'b>() { // no data. call::<&'a WithAssoc>>(); - //~^ ERROR cannot infer + //~^ ERROR reference has a longer lifetime } fn call_without_assoc<'a,'b>() { // As `without_assoc`, but in a distinct scenario. - call::<&'a WithoutAssoc>>(); + call::<&'a WithoutAssoc>>(); //~ ERROR reference has a longer lifetime } fn call() { } diff --git a/src/test/compile-fail/regions-outlives-projection-hrtype.rs b/src/test/compile-fail/regions-outlives-projection-hrtype.rs new file mode 100644 index 0000000000000..2d271b7be73e0 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-projection-hrtype.rs @@ -0,0 +1,36 @@ +// Copyright 2015 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. + +// Test for the outlives relation when applied to a projection on a +// type with bound regions. In this case, we are checking that +// ` fn(&'r T) as TheTrait>::TheType: 'a` If we're not +// careful, we could wind up with a constraint that `'r:'a`, but since +// `'r` is bound, that leads to badness. This test checks that +// everything works. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait TheTrait { + type TheType; +} + +fn wf() { } + +type FnType = for<'r> fn(&'r T); + +fn foo<'a,'b,T>() + where FnType: TheTrait +{ + wf::< as TheTrait>::TheType >(); +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/regions-outlives-projection-trait-def.rs b/src/test/compile-fail/regions-outlives-projection-trait-def.rs new file mode 100644 index 0000000000000..04682a7729735 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-projection-trait-def.rs @@ -0,0 +1,31 @@ +// Copyright 2014 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. + +// Test that `>::Type: 'b`, where `trait Foo<'a> { Type: +// 'a; }`, does not require that `F: 'b`. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait SomeTrait<'a> { + type Type: 'a; +} + +impl<'a: 'c, 'c, T> SomeTrait<'a> for &'c T where T: SomeTrait<'a> { + type Type = >::Type; + // ~~~~~~~~~~~~~~~~~~~~~~~~~~ + // | + // Note that this type must outlive 'a, due to the trait + // definition. If we fall back to OutlivesProjectionComponents + // here, then we would require that `T:'a`, which is too strong. +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/regions-outlives-scalar.rs b/src/test/compile-fail/regions-outlives-scalar.rs new file mode 100644 index 0000000000000..94f7a350cf787 --- /dev/null +++ b/src/test/compile-fail/regions-outlives-scalar.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +// Test that scalar values outlive all regions. +// Rule OutlivesScalar from RFC 1214. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct Foo<'a> { + x: &'a i32, + y: &'static i32 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/regions-struct-not-wf.rs b/src/test/compile-fail/regions-struct-not-wf.rs index c22812c3d86dc..a7f1828970324 100644 --- a/src/test/compile-fail/regions-struct-not-wf.rs +++ b/src/test/compile-fail/regions-struct-not-wf.rs @@ -12,20 +12,23 @@ #![allow(dead_code)] -struct Ref<'a, T> { //~ ERROR the parameter type `T` may not live long enough +struct Ref<'a, T> { field: &'a T + //~^ ERROR the parameter type `T` may not live long enough } struct RefOk<'a, T:'a> { field: &'a T } -struct RefIndirect<'a, T> { //~ ERROR the parameter type `T` may not live long enough +struct RefIndirect<'a, T> { field: RefOk<'a, T> + //~^ ERROR the parameter type `T` may not live long enough } -struct DoubleRef<'a, 'b, T> { //~ ERROR reference has a longer lifetime than the data it references +struct DoubleRef<'a, 'b, T> { field: &'a &'b T + //~^ ERROR reference has a longer lifetime than the data it references } fn main() { } diff --git a/src/test/compile-fail/regions-wf-trait-object.rs b/src/test/compile-fail/regions-wf-trait-object.rs new file mode 100644 index 0000000000000..e1f1fdaeb341d --- /dev/null +++ b/src/test/compile-fail/regions-wf-trait-object.rs @@ -0,0 +1,21 @@ +// Copyright 2014 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.t + +// Check that the explicit lifetime bound (`'b`, in this example) must +// outlive all the superbound from the trait (`'a`, in this example). + +trait TheTrait<'t>: 't { } + +struct Foo<'a,'b> { + x: Box+'b> + //~^ ERROR reference has a longer lifetime +} + +fn main() { } diff --git a/src/test/compile-fail/rfc1214-warn-and-error.rs b/src/test/compile-fail/rfc1214-warn-and-error.rs new file mode 100644 index 0000000000000..50fd3fc961c1d --- /dev/null +++ b/src/test/compile-fail/rfc1214-warn-and-error.rs @@ -0,0 +1,37 @@ +// Copyright 2015 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. + +// Test that an RFC1214 warning from an earlier function (`foo`) does +// not suppress an error for the same problem (`WantEq`, +// `NotEq: !Eq`) in a later function (`bar)`. Earlier versions of the +// warning mechanism had an issue due to caching. + +#![allow(dead_code)] +#![allow(unused_variables)] + +struct WantEq { t: T } + +struct NotEq; + +trait Trait { } + +fn foo() { + let x: Box>> = loop { }; + //~^ WARN E0277 +} + +fn bar() { + wf::>(); + //~^ ERROR E0277 +} + +fn wf() { } + +fn main() { } diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-in-fns.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-in-fns.rs new file mode 100644 index 0000000000000..dbfda61f5525a --- /dev/null +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-in-fns.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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. + +trait Trait {} + +struct Foo { + x: T, +} + +enum Bar { + ABar(isize), + BBar(T), + CBar(usize), +} + +fn explode(x: Foo) {} +//~^ ERROR not implemented + +fn kaboom(y: Bar) {} +//~^ ERROR not implemented + +fn main() { +} diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums-in-impls.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums-in-impls.rs new file mode 100644 index 0000000000000..c647dd38ee38a --- /dev/null +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums-in-impls.rs @@ -0,0 +1,35 @@ +// Copyright 2014 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. + +trait Trait {} + +struct Foo { + x: T, +} + +enum Bar { + ABar(isize), + BBar(T), + CBar(usize), +} + +trait PolyTrait +{ + fn whatever(&self, t: T) {} +} + +struct Struct; + +impl PolyTrait> for Struct { +//~^ ERROR not implemented +} + +fn main() { +} diff --git a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs index 988961e7fa14a..e1b005b0c8533 100644 --- a/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs +++ b/src/test/compile-fail/trait-bounds-on-structs-and-enums.rs @@ -20,12 +20,6 @@ enum Bar { CBar(usize), } -fn explode(x: Foo) {} -//~^ ERROR not implemented - -fn kaboom(y: Bar) {} -//~^ ERROR not implemented - impl Foo { //~^ ERROR the trait `Trait` is not implemented fn uhoh() {} @@ -55,16 +49,5 @@ enum Enum { DictionaryLike { field: Bar }, //~ ERROR not implemented } -trait PolyTrait -{ - fn whatever(&self, t: T) {} -} - -struct Struct; - -impl PolyTrait> for Struct { -//~^ ERROR not implemented -} - fn main() { } diff --git a/src/test/compile-fail/trait-object-safety.rs b/src/test/compile-fail/trait-object-safety.rs index d45d13556e121..baf239f5956d6 100644 --- a/src/test/compile-fail/trait-object-safety.rs +++ b/src/test/compile-fail/trait-object-safety.rs @@ -22,5 +22,6 @@ impl Tr for St { } fn main() { - let _: &Tr = &St; //~ ERROR cannot convert to a trait object because trait `Tr` is not + let _: &Tr = &St; //~ ERROR E0038 + //~^ ERROR E0038 } diff --git a/src/test/compile-fail/trait-test-2.rs b/src/test/compile-fail/trait-test-2.rs index b09b10ffa0aad..b11cbde292969 100644 --- a/src/test/compile-fail/trait-test-2.rs +++ b/src/test/compile-fail/trait-test-2.rs @@ -17,6 +17,8 @@ impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { 10.dup::(); //~ ERROR does not take type parameters 10.blah::(); //~ ERROR incorrect number of type parameters - (box 10 as Box).dup(); //~ ERROR cannot convert to a trait object - //~^ ERROR the trait `bar` is not implemented for the type `bar` + (box 10 as Box).dup(); + //~^ ERROR E0038 + //~| ERROR E0038 + //~| ERROR E0277 } diff --git a/src/test/compile-fail/traits-issue-23003-overflow.rs b/src/test/compile-fail/traits-issue-23003-overflow.rs index ea41775f310d3..80d2884ee60aa 100644 --- a/src/test/compile-fail/traits-issue-23003-overflow.rs +++ b/src/test/compile-fail/traits-issue-23003-overflow.rs @@ -9,10 +9,11 @@ // except according to those terms. // A variant of traits-issue-23003 in which an infinite series of -// types are required. This currently creates an overflow. This test -// is included to ensure that some controlled failure, at least, -// results -- but it might be that we should adjust the rules somewhat -// to make this legal. -nmatsakis +// types are required. This test now just compiles fine, since the +// relevant rules that triggered the overflow were removed. + +#![feature(rustc_attrs)] +#![allow(dead_code)] use std::marker::PhantomData; @@ -32,7 +33,7 @@ impl Async for Complete { type Cancel = Receipt>>; } -fn foo(r: Receipt>) { } -//~^ ERROR overflow +fn foo(_: Receipt>) { } -fn main() { } +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/traits-negative-impls.rs b/src/test/compile-fail/traits-negative-impls.rs index 8dc977a8e490b..c37f45dcf50bb 100644 --- a/src/test/compile-fail/traits-negative-impls.rs +++ b/src/test/compile-fail/traits-negative-impls.rs @@ -32,12 +32,23 @@ fn dummy() { Outer(TestType); //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType` + //~| ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType` +} + +fn dummy1b() { + struct TestType; + impl !Send for TestType {} is_send(TestType); - //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType` + //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy1b::TestType` +} + +fn dummy1c() { + struct TestType; + impl !Send for TestType {} is_send((8, TestType)); - //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType` + //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy1c::TestType` } fn dummy2() { diff --git a/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs b/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs index 8cc531625d179..09687724656fa 100644 --- a/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs +++ b/src/test/compile-fail/type-parameter-defaults-referencing-Self-ppaux.rs @@ -22,5 +22,6 @@ impl MyAdd for i32 { fn main() { let x: i32 = 5; let y = x as MyAdd; - //~^ ERROR as `MyAdd` + //~^ ERROR E0038 + //~| ERROR cast to unsized type: `i32` as `MyAdd` } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index da4d6c75227fc..319b81bde36ed 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]] +struct Test5<'a, 'b:'a> { //~ ERROR regions=[[+, o];[];[]] x: extern "Rust" fn(&'a mut &'b isize), } @@ -52,7 +52,7 @@ struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[]] +struct Test6<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] x: &'a mut extern "Rust" fn(&'b isize), } diff --git a/src/test/compile-fail/wf-array-elem-sized.rs b/src/test/compile-fail/wf-array-elem-sized.rs new file mode 100644 index 0000000000000..c8b7f35b3aa58 --- /dev/null +++ b/src/test/compile-fail/wf-array-elem-sized.rs @@ -0,0 +1,21 @@ +// Copyright 2015 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. + +// Check that array elemen types must be Sized. Issue #25692. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct Foo { + foo: [[u8]], //~ WARN E0277 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-const-type.rs b/src/test/compile-fail/wf-const-type.rs new file mode 100644 index 0000000000000..c3015afd8dd0d --- /dev/null +++ b/src/test/compile-fail/wf-const-type.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// Test that we check the types of constants are well-formed. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct IsCopy { t: T } +struct NotCopy; + +const FOO: IsCopy> = IsCopy { t: None }; +//~^ ERROR E0277 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/wf-enum-bound.rs b/src/test/compile-fail/wf-enum-bound.rs new file mode 100644 index 0000000000000..1d271d1530a75 --- /dev/null +++ b/src/test/compile-fail/wf-enum-bound.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Test that we check enum bounds for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +enum SomeEnum //~ WARN E0277 + where T: ExtraCopy +{ + SomeVariant(T,U) +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-enum-fields-struct-variant.rs b/src/test/compile-fail/wf-enum-fields-struct-variant.rs new file mode 100644 index 0000000000000..5eb53e7edde6b --- /dev/null +++ b/src/test/compile-fail/wf-enum-fields-struct-variant.rs @@ -0,0 +1,28 @@ +// Copyright 2014 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. + +// Test that we check struct fields for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct IsCopy { + value: T +} + +enum AnotherEnum { + AnotherVariant { + f: IsCopy //~ ERROR E0277 + } +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/wf-enum-fields.rs b/src/test/compile-fail/wf-enum-fields.rs new file mode 100644 index 0000000000000..76ad40f845768 --- /dev/null +++ b/src/test/compile-fail/wf-enum-fields.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Test that we check struct fields for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct IsCopy { + value: T +} + +enum SomeEnum { + SomeVariant(IsCopy) //~ ERROR E0277 +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/wf-fn-where-clause.rs b/src/test/compile-fail/wf-fn-where-clause.rs new file mode 100644 index 0000000000000..769894613c764 --- /dev/null +++ b/src/test/compile-fail/wf-fn-where-clause.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// Test that we check where-clauses on fn items. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +fn foo() where T: ExtraCopy //~ WARN E0277 +{ +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-impl-associated-type-region.rs b/src/test/compile-fail/wf-impl-associated-type-region.rs new file mode 100644 index 0000000000000..2d7727fff3503 --- /dev/null +++ b/src/test/compile-fail/wf-impl-associated-type-region.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// Check that we require that associated types in an impl are well-formed. + +#![feature(rustc_attrs)] + +pub trait Foo<'a> { + type Bar; +} + +impl<'a, T> Foo<'a> for T { + type Bar = &'a T; //~ WARN E0309 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation diff --git a/src/test/compile-fail/wf-impl-associated-type-trait.rs b/src/test/compile-fail/wf-impl-associated-type-trait.rs new file mode 100644 index 0000000000000..8a612c321570d --- /dev/null +++ b/src/test/compile-fail/wf-impl-associated-type-trait.rs @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +// Check that we require that associated types in an impl are well-formed. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +pub trait MyHash { } + +pub struct MySet { + data: Vec +} + +pub trait Foo { + type Bar; +} + +impl Foo for T { + type Bar = MySet; + //~^ WARN the trait `MyHash` is not implemented for the type `T` +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful + diff --git a/src/test/compile-fail/wf-in-fn-arg.rs b/src/test/compile-fail/wf-in-fn-arg.rs new file mode 100644 index 0000000000000..e302cac0006b1 --- /dev/null +++ b/src/test/compile-fail/wf-in-fn-arg.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for argument types in fn items. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct MustBeCopy { + t: T +} + +fn bar(_: &MustBeCopy) //~ ERROR E0277 +{ +} + +fn main() { } diff --git a/src/test/compile-fail/wf-in-fn-ret.rs b/src/test/compile-fail/wf-in-fn-ret.rs new file mode 100644 index 0000000000000..719bc9282ad7d --- /dev/null +++ b/src/test/compile-fail/wf-in-fn-ret.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for return types in fn items. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct MustBeCopy { + t: T +} + +fn bar() -> MustBeCopy //~ ERROR E0277 +{ +} + +fn main() { } diff --git a/src/test/compile-fail/wf-in-fn-type-arg.rs b/src/test/compile-fail/wf-in-fn-type-arg.rs new file mode 100644 index 0000000000000..08ee0e954ac2d --- /dev/null +++ b/src/test/compile-fail/wf-in-fn-type-arg.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for types in fns. + +struct MustBeCopy { + t: T +} + +struct Bar { + // needs T: Copy + x: fn(MustBeCopy) //~ ERROR E0277 +} + +fn main() { } diff --git a/src/test/compile-fail/wf-in-fn-type-ret.rs b/src/test/compile-fail/wf-in-fn-type-ret.rs new file mode 100644 index 0000000000000..6942f78606060 --- /dev/null +++ b/src/test/compile-fail/wf-in-fn-type-ret.rs @@ -0,0 +1,22 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for types in fns. + +struct MustBeCopy { + t: T +} + +struct Foo { + // needs T: 'static + x: fn() -> MustBeCopy //~ ERROR E0277 +} + +fn main() { } diff --git a/src/test/compile-fail/wf-in-fn-type-static.rs b/src/test/compile-fail/wf-in-fn-type-static.rs new file mode 100644 index 0000000000000..593c9435f6c75 --- /dev/null +++ b/src/test/compile-fail/wf-in-fn-type-static.rs @@ -0,0 +1,32 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions related to regions also for +// types in fns. + +#![allow(dead_code)] +#![feature(rustc_attrs)] + +struct MustBeCopy { + t: T +} + +struct Foo { + // needs T: 'static + x: fn() -> &'static T //~ WARN E0310 +} + +struct Bar { + // needs T: Copy + x: fn(&'static T) //~ WARN E0310 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-in-fn-where-clause.rs b/src/test/compile-fail/wf-in-fn-where-clause.rs new file mode 100644 index 0000000000000..fc3d234aac252 --- /dev/null +++ b/src/test/compile-fail/wf-in-fn-where-clause.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for where clauses in fn items. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait MustBeCopy { +} + +fn bar() //~ WARN E0277 + where T: MustBeCopy +{ +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-in-obj-type-static.rs b/src/test/compile-fail/wf-in-obj-type-static.rs new file mode 100644 index 0000000000000..c697dfd50ad47 --- /dev/null +++ b/src/test/compile-fail/wf-in-obj-type-static.rs @@ -0,0 +1,28 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for types in fns. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait Object { } + +struct MustBeCopy { + t: T +} + +struct Foo { + // needs T: 'static + x: Object<&'static T> //~ WARN E0310 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-in-obj-type-trait.rs b/src/test/compile-fail/wf-in-obj-type-trait.rs new file mode 100644 index 0000000000000..add48219c1d7e --- /dev/null +++ b/src/test/compile-fail/wf-in-obj-type-trait.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +// Check that we enforce WF conditions also for types in fns. + +trait Object { } + +struct MustBeCopy { + t: T +} + +struct Bar { + // needs T: Copy + x: Object> //~ ERROR E0277 +} + +fn main() { } diff --git a/src/test/compile-fail/wf-inherent-impl-method-where-clause.rs b/src/test/compile-fail/wf-inherent-impl-method-where-clause.rs new file mode 100644 index 0000000000000..44671be835533 --- /dev/null +++ b/src/test/compile-fail/wf-inherent-impl-method-where-clause.rs @@ -0,0 +1,27 @@ +// Copyright 2014 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. + +// Test that we check where-clauses on inherent impl methods. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +struct Foo(T,U); + +impl Foo { + fn foo(self) where T: ExtraCopy //~ WARN E0277 + {} +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-inherent-impl-where-clause.rs b/src/test/compile-fail/wf-inherent-impl-where-clause.rs new file mode 100644 index 0000000000000..a0f588c1961d1 --- /dev/null +++ b/src/test/compile-fail/wf-inherent-impl-where-clause.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Test that we check where-clauses on inherent impls. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +struct Foo(T,U); + +impl Foo where T: ExtraCopy //~ WARN E0277 +{ +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-object-safe.rs b/src/test/compile-fail/wf-object-safe.rs new file mode 100644 index 0000000000000..92c0a8c5be8af --- /dev/null +++ b/src/test/compile-fail/wf-object-safe.rs @@ -0,0 +1,20 @@ +// Copyright 2015 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. + +// Check that object-safe traits are not WF when used as object types. +// Issue #21953. + +trait A { + fn foo(&self, _x: &Self); +} + +fn main() { + let _x: &A; //~ ERROR E0038 +} diff --git a/src/test/compile-fail/wf-outlives-ty-in-fn-or-trait.rs b/src/test/compile-fail/wf-outlives-ty-in-fn-or-trait.rs new file mode 100644 index 0000000000000..dc0cbeff153a9 --- /dev/null +++ b/src/test/compile-fail/wf-outlives-ty-in-fn-or-trait.rs @@ -0,0 +1,32 @@ +// Copyright 2014 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. + +// Test that an appearance of `T` in fn args or in a trait object must +// still meet the outlives bounds. Since this is a new requirement, +// this is currently only a warning, not a hard error. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait Trait { } + +struct Foo<'a,T> { + f: &'a fn(T), + //~^ WARN E0309 +} + +struct Bar<'a,T> { + f: &'a Trait, + //~^ WARN E0309 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful + diff --git a/src/test/compile-fail/wf-static-type.rs b/src/test/compile-fail/wf-static-type.rs new file mode 100644 index 0000000000000..ba02c5dca3e6d --- /dev/null +++ b/src/test/compile-fail/wf-static-type.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// Test that we check the types of statics are well-formed. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct IsCopy { t: T } +struct NotCopy; + +static FOO: IsCopy> = IsCopy { t: None }; +//~^ ERROR E0277 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/wf-struct-bound.rs b/src/test/compile-fail/wf-struct-bound.rs new file mode 100644 index 0000000000000..43378061e40c0 --- /dev/null +++ b/src/test/compile-fail/wf-struct-bound.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Test that we check struct bounds for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +struct SomeStruct //~ WARN E0277 + where T: ExtraCopy +{ + data: (T,U) +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-struct-field.rs b/src/test/compile-fail/wf-struct-field.rs new file mode 100644 index 0000000000000..8a631a6c335a0 --- /dev/null +++ b/src/test/compile-fail/wf-struct-field.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Test that we check struct fields for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct IsCopy { + value: T +} + +struct SomeStruct { + data: IsCopy //~ ERROR E0277 +} + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/wf-trait-associated-type-bound.rs b/src/test/compile-fail/wf-trait-associated-type-bound.rs new file mode 100644 index 0000000000000..63a532138e3bd --- /dev/null +++ b/src/test/compile-fail/wf-trait-associated-type-bound.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// Test that we check associated type bounds for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +trait SomeTrait { //~ WARN E0277 + type Type1: ExtraCopy; +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-associated-type-region.rs b/src/test/compile-fail/wf-trait-associated-type-region.rs new file mode 100644 index 0000000000000..b3aa4e19c9656 --- /dev/null +++ b/src/test/compile-fail/wf-trait-associated-type-region.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// Test that we check associated type default values for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait SomeTrait<'a> { + type Type1; + type Type2 = &'a Self::Type1; + //~^ WARN E0309 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-associated-type-trait.rs b/src/test/compile-fail/wf-trait-associated-type-trait.rs new file mode 100644 index 0000000000000..8c491e04c981d --- /dev/null +++ b/src/test/compile-fail/wf-trait-associated-type-trait.rs @@ -0,0 +1,26 @@ +// Copyright 2014 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. + +// Test that we check associated type default values for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +struct IsCopy { x: T } + +trait SomeTrait { + type Type1; + type Type2 = IsCopy; + //~^ WARN E0277 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-bound.rs b/src/test/compile-fail/wf-trait-bound.rs new file mode 100644 index 0000000000000..147b3ce236d42 --- /dev/null +++ b/src/test/compile-fail/wf-trait-bound.rs @@ -0,0 +1,25 @@ +// Copyright 2014 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. + +// Test that we check supertrait bounds for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +trait SomeTrait //~ WARN E0277 + where T: ExtraCopy +{ +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-default-fn-arg.rs b/src/test/compile-fail/wf-trait-default-fn-arg.rs new file mode 100644 index 0000000000000..57c6c1979f87e --- /dev/null +++ b/src/test/compile-fail/wf-trait-default-fn-arg.rs @@ -0,0 +1,29 @@ +// Copyright 2015 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. + +// Check that we test WF conditions for fn arguments. Because the +// current code is so goofy, this is only a warning for now. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Bar { value: Box } + +trait Foo { + fn bar(&self, x: &Bar) { + //~^ WARN E0277 + // + // Here, Eq ought to be implemented. + } +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-default-fn-ret.rs b/src/test/compile-fail/wf-trait-default-fn-ret.rs new file mode 100644 index 0000000000000..939876403e54d --- /dev/null +++ b/src/test/compile-fail/wf-trait-default-fn-ret.rs @@ -0,0 +1,30 @@ +// Copyright 2015 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. + +// Check that we test WF conditions for fn arguments. Because the +// current code is so goofy, this is only a warning for now. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Bar { value: Box } + +trait Foo { + fn bar(&self) -> Bar { + //~^ WARN E0277 + // + // Here, Eq ought to be implemented. + loop { } + } +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-default-fn-where-clause.rs b/src/test/compile-fail/wf-trait-default-fn-where-clause.rs new file mode 100644 index 0000000000000..b1c0d71fc5b3b --- /dev/null +++ b/src/test/compile-fail/wf-trait-default-fn-where-clause.rs @@ -0,0 +1,29 @@ +// Copyright 2015 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. + +// Check that we test WF conditions for fn arguments. Because the +// current code is so goofy, this is only a warning for now. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +trait Bar { } + +trait Foo { + fn bar(&self) where A: Bar { + //~^ WARN E0277 + // + // Here, Eq ought to be implemented. + } +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-fn-arg.rs b/src/test/compile-fail/wf-trait-fn-arg.rs new file mode 100644 index 0000000000000..ff263c85eb371 --- /dev/null +++ b/src/test/compile-fail/wf-trait-fn-arg.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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. + +// Check that we test WF conditions for fn arguments in a trait definition. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Bar { value: Box } + +trait Foo { + fn bar(&self, x: &Bar); + //~^ WARN E0277 + // + // Here, Eq ought to be implemented. +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-fn-ret.rs b/src/test/compile-fail/wf-trait-fn-ret.rs new file mode 100644 index 0000000000000..5c8f3030c2c21 --- /dev/null +++ b/src/test/compile-fail/wf-trait-fn-ret.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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. + +// Check that we test WF conditions for fn return types in a trait definition. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Bar { value: Box } + +trait Foo { + fn bar(&self) -> &Bar; + //~^ WARN E0277 + // + // Here, Eq ought to be implemented. +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-fn-where-clause.rs b/src/test/compile-fail/wf-trait-fn-where-clause.rs new file mode 100644 index 0000000000000..51b5475e51fba --- /dev/null +++ b/src/test/compile-fail/wf-trait-fn-where-clause.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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. + +// Check that we test WF conditions for fn where clauses in a trait definition. + +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(unused_variables)] + +struct Bar { value: Box } + +trait Foo { + fn bar(&self) where Bar: Copy; + //~^ WARN E0277 + // + // Here, Eq ought to be implemented. +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/wf-trait-superbound.rs b/src/test/compile-fail/wf-trait-superbound.rs new file mode 100644 index 0000000000000..58ee766dad112 --- /dev/null +++ b/src/test/compile-fail/wf-trait-superbound.rs @@ -0,0 +1,23 @@ +// Copyright 2014 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. + +// Test that we check supertrait bounds for WFedness. + +#![feature(associated_type_defaults)] +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait ExtraCopy { } + +trait SomeTrait: ExtraCopy { //~ WARN E0277 +} + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/where-clauses-not-parameter.rs b/src/test/compile-fail/where-clauses-not-parameter.rs deleted file mode 100644 index 7968cc37090ac..0000000000000 --- a/src/test/compile-fail/where-clauses-not-parameter.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2014 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. - -fn equal(_: &T, _: &T) -> bool where isize : Eq { - true //~^ ERROR cannot bound type `isize`, where clause bounds may only be attached -} - -// This should be fine involves a type parameter. -fn test() -> bool where Option : Eq {} - -// This should be rejected as well. -fn test2() -> bool where Option : Eq {} -//~^ ERROR cannot bound type `core::option::Option`, where clause bounds may - -#[derive(PartialEq)] -//~^ ERROR cannot bound type `isize`, where clause bounds -enum Foo where isize : Eq { MkFoo(T) } -//~^ ERROR cannot bound type `isize`, where clause bounds - -fn test3() -> bool where Option> : Eq {} - -fn test4() -> bool where Option> : Eq {} -//~^ ERROR cannot bound type `core::option::Option>`, where clause bounds - -trait Baz where isize : Eq { - //~^ ERROR cannot bound type `isize`, where clause bounds may only - fn baz(&self, t: T) where String : Eq; //~ ERROR cannot bound type `collections::string::String` - //~^ ERROR cannot bound type `isize`, where clause -} - -impl Baz for isize where isize : Eq { - //~^ ERROR cannot bound type `isize`, where clause bounds - fn baz() where String : Eq {} -} - -fn main() { - equal(&0, &0); -} diff --git a/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs b/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs index 6070cff9a2952..8059db5204ee6 100644 --- a/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs +++ b/src/test/run-pass/associated-types-projection-to-unrelated-trait.rs @@ -21,7 +21,8 @@ trait Get { } trait Other { - fn okay(&self, foo: U, bar: ::Value); + fn okay(&self, foo: U, bar: ::Value) + where Self: Get; } impl Get for () { diff --git a/src/test/run-pass/issue-14254.rs b/src/test/run-pass/issue-14254.rs index ed96eee6ddffb..9049ae0548fa9 100644 --- a/src/test/run-pass/issue-14254.rs +++ b/src/test/run-pass/issue-14254.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -trait Foo { +trait Foo: Sized { fn bar(&self); fn baz(&self) { } fn bah(_: Option) { } diff --git a/src/test/run-pass/issue-21058.rs b/src/test/run-pass/issue-21058.rs index 5fe3434e499e1..0ca936878148b 100644 --- a/src/test/run-pass/issue-21058.rs +++ b/src/test/run-pass/issue-21058.rs @@ -21,10 +21,10 @@ fn main() { // str std::intrinsics::type_name::(), // Trait - std::intrinsics::type_name::(), + std::intrinsics::type_name::(), // Newtype std::intrinsics::type_name::(), // DST std::intrinsics::type_name::() - )}, ("[u8]", "str", "core::marker::Copy + 'static", "NT", "DST")); + )}, ("[u8]", "str", "core::marker::Send + 'static", "NT", "DST")); } diff --git a/src/test/run-pass/issue-5708.rs b/src/test/run-pass/issue-5708.rs index dfb560db10067..6ab3395109915 100644 --- a/src/test/run-pass/issue-5708.rs +++ b/src/test/run-pass/issue-5708.rs @@ -52,7 +52,7 @@ pub trait MyTrait { fn dummy(&self, t: T) -> T { panic!() } } -pub struct MyContainer<'a, T> { +pub struct MyContainer<'a, T:'a> { foos: Vec<&'a (MyTrait+'a)> , } diff --git a/src/test/run-pass/project-defer-unification.rs b/src/test/run-pass/project-defer-unification.rs new file mode 100644 index 0000000000000..9a6ea2272fea7 --- /dev/null +++ b/src/test/run-pass/project-defer-unification.rs @@ -0,0 +1,105 @@ +// Copyright 2015 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. + +// A regression test extracted from image-0.3.11. The point of +// failure was in `index_colors` below. + +use std::ops::{Deref, DerefMut}; + +#[derive(Copy, Clone)] +pub struct Luma { pub data: [T; 1] } + +impl Pixel for Luma { + type Subpixel = T; +} + +pub struct ImageBuffer { + pixels: P, + c: Container, +} + +pub trait GenericImage: Sized { + type Pixel: Pixel; +} + +pub trait Pixel: Copy + Clone { + type Subpixel: Primitive; +} + +pub trait Primitive: Copy + PartialOrd + Clone { +} + +impl GenericImage for ImageBuffer +where P: Pixel + 'static, + Container: Deref + DerefMut, + P::Subpixel: 'static { + + type Pixel = P; +} + +impl Primitive for u8 { } + +impl ImageBuffer +where P: Pixel + 'static, + P::Subpixel: 'static, + Container: Deref +{ + pub fn pixels<'a>(&'a self) -> Pixels<'a, Self> { + loop { } + } + + pub fn pixels_mut(&mut self) -> PixelsMut

{ + loop { } + } +} + +pub struct Pixels<'a, I: 'a> { + image: &'a I, + x: u32, + y: u32, + width: u32, + height: u32 +} + +impl<'a, I: GenericImage> Iterator for Pixels<'a, I> { + type Item = (u32, u32, I::Pixel); + + fn next(&mut self) -> Option<(u32, u32, I::Pixel)> { + loop { } + } +} + +pub struct PixelsMut<'a, P: Pixel + 'a> where P::Subpixel: 'a { + chunks: &'a mut P::Subpixel +} + +impl<'a, P: Pixel + 'a> Iterator for PixelsMut<'a, P> where P::Subpixel: 'a { + type Item = &'a mut P; + + fn next(&mut self) -> Option<&'a mut P> { + loop { } + } +} + +pub fn index_colors(image: &ImageBuffer>) + -> ImageBuffer, Vec> +where Pix: Pixel + 'static, +{ + let mut indices: ImageBuffer<_,Vec<_>> = loop { }; + for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) { + // failured occurred here ^^ because we were requiring that we + // could project Pixel or Subpixel from `T_indices` (type of + // `indices`), but the type is insufficiently constrained + // until we reach the return below. + } + indices +} + +fn main() { } diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 33889b27a872b..72a214f4c9ad0 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -42,7 +42,7 @@ fn field_invoke1<'f, 'g>(x: &'g Struct1<'f>) -> (isize,isize) { (l,s) } -struct Struct2<'h, 'i> { +struct Struct2<'h, 'i:'h> { f: &'h (Trait<'i>+'h) } @@ -126,7 +126,10 @@ pub fn main() { assert_eq!(field_invoke2(&s2), 3); let m : Box = make_val(); - assert_eq!(object_invoke1(&*m), (4,5)); + // assert_eq!(object_invoke1(&*m), (4,5)); + // ~~~~~~~~~~~~~~~~~~~ + // this call yields a compilation error; see compile-fail/dropck-object-cycle.rs + // for details. assert_eq!(object_invoke2(&*m), 5); // The RefMakerTrait above is pretty strange (i.e. it is strange