diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7b6f3af2a11ec..b8888eee9c6ef 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -170,6 +170,7 @@ impl_stable_hash_for!(enum ty::Visibility { impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); +impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate where A: HashStable>, @@ -200,6 +201,9 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx ty::Predicate::Equate(ref pred) => { pred.hash_stable(hcx, hasher); } + ty::Predicate::Subtype(ref pred) => { + pred.hash_stable(hcx, hasher); + } ty::Predicate::RegionOutlives(ref pred) => { pred.hash_stable(hcx, hasher); } diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs deleted file mode 100644 index 4acb8b807d594..0000000000000 --- a/src/librustc/infer/bivariate.rs +++ /dev/null @@ -1,123 +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. - -//! Applies the "bivariance relationship" to two types and/or regions. -//! If (A,B) are bivariant then either A <: B or B <: A. It occurs -//! when type/lifetime parameters are unconstrained. Usually this is -//! an error, but we permit it in the specific case where a type -//! parameter is constrained in a where-clause via an associated type. -//! -//! There are several ways one could implement bivariance. You could -//! just do nothing at all, for example, or you could fully verify -//! that one of the two subtyping relationships hold. We choose to -//! thread a middle line: we relate types up to regions, but ignore -//! all region relationships. -//! -//! At one point, handling bivariance in this fashion was necessary -//! for inference, but I'm actually not sure if that is true anymore. -//! In particular, it might be enough to say (A,B) are bivariant for -//! all (A,B). - -use super::combine::CombineFields; -use super::type_variable::{BiTo}; - -use ty::{self, Ty, TyCtxt}; -use ty::TyVar; -use ty::relate::{Relate, RelateResult, TypeRelation}; - -pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Bivariate<'combine, 'infcx, 'gcx, 'tcx> - { - Bivariate { fields: fields, a_is_expected: a_is_expected } - } -} - -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> - for Bivariate<'combine, 'infcx, 'gcx, 'tcx> -{ - fn tag(&self) -> &'static str { "Bivariate" } - - fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - // If we have Foo and Foo is invariant w/r/t A, - // and we want to assert that - // - // Foo <: Foo || - // Foo <: Foo - // - // then still A must equal B. - ty::Invariant => self.relate(a, b), - - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.relate(a, b), - ty::Contravariant => self.relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); - Ok(a) - } - - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?; - Ok(a) - } - - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?; - Ok(a) - } - - _ => { - self.fields.infcx.super_combine_tys(self, a, b) - } - } - } - - fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'tcx> - { - let a1 = self.tcx().erase_late_bound_regions(a); - let b1 = self.tcx().erase_late_bound_regions(b); - let c = self.relate(&a1, &b1)?; - Ok(ty::Binder(c)) - } -} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 5d33d6e6d2e71..b73079b02bdd9 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -32,14 +32,12 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. -use super::bivariate::Bivariate; use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; use super::InferCtxt; use super::{MiscVariable, TypeTrace}; -use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use ty::{IntType, UintType}; use ty::{self, Ty, TyCtxt}; @@ -49,7 +47,6 @@ use ty::relate::{RelateResult, TypeRelation}; use traits::PredicateObligations; use syntax::ast; -use syntax::util::small_vector::SmallVector; use syntax_pos::Span; #[derive(Clone)] @@ -60,6 +57,11 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub obligations: PredicateObligations<'tcx>, } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum RelationDir { + SubtypeOf, SupertypeOf, EqTo +} + impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_tys(&self, relation: &mut R, @@ -159,10 +161,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Equate::new(self, a_is_expected) } - pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> { - Bivariate::new(self, a_is_expected) - } - pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> { Sub::new(self, a_is_expected) } @@ -175,6 +173,15 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Glb::new(self, a_is_expected) } + /// Here dir is either EqTo, SubtypeOf, or SupertypeOf. The + /// idea is that we should ensure that the type `a_ty` is equal + /// to, a subtype of, or a supertype of (respectively) the type + /// to which `b_vid` is bound. + /// + /// Since `b_vid` has not yet been instantiated with a type, we + /// will first instantiate `b_vid` with a *generalized* version + /// of `a_ty`. Generalization introduces other inference + /// variables wherever subtyping could occur. pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, @@ -182,101 +189,66 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { a_is_expected: bool) -> RelateResult<'tcx, ()> { - // We use SmallVector here instead of Vec because this code is hot and - // it's rare that the stack length exceeds 1. - let mut stack = SmallVector::new(); - stack.push((a_ty, dir, b_vid)); - loop { - // For each turn of the loop, we extract a tuple - // - // (a_ty, dir, b_vid) - // - // to relate. Here dir is either SubtypeOf or - // SupertypeOf. The idea is that we should ensure that - // the type `a_ty` is a subtype or supertype (respectively) of the - // type to which `b_vid` is bound. - // - // If `b_vid` has not yet been instantiated with a type - // (which is always true on the first iteration, but not - // necessarily true on later iterations), we will first - // instantiate `b_vid` with a *generalized* version of - // `a_ty`. Generalization introduces other inference - // variables wherever subtyping could occur (at time of - // this writing, this means replacing free regions with - // region variables). - let (a_ty, dir, b_vid) = match stack.pop() { - None => break, - Some(e) => e, - }; - // Get the actual variable that b_vid has been inferred to - let (b_vid, b_ty) = { - let mut variables = self.infcx.type_variables.borrow_mut(); - let b_vid = variables.root_var(b_vid); - (b_vid, variables.probe_root(b_vid)) - }; - - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", - a_ty, - dir, - b_vid); - - // Check whether `vid` has been instantiated yet. If not, - // make a generalized form of `ty` and instantiate with - // that. - let b_ty = match b_ty { - Some(t) => t, // ...already instantiated. - None => { // ...not yet instantiated: - // Generalize type if necessary. - let generalized_ty = match dir { - EqTo => self.generalize(a_ty, b_vid, false), - BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), - }?; - debug!("instantiate(a_ty={:?}, dir={:?}, \ - b_vid={:?}, generalized_ty={:?})", - a_ty, dir, b_vid, - generalized_ty); - self.infcx.type_variables - .borrow_mut() - .instantiate_and_push( - b_vid, generalized_ty, &mut stack); - generalized_ty - } - }; - - // The original triple was `(a_ty, dir, b_vid)` -- now we have - // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`: - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - match dir { - BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty), - EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), - SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( - ty::Contravariant, &a_ty, &b_ty), - }?; - } + use self::RelationDir::*; + + // Get the actual variable that b_vid has been inferred to + debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_none()); + + debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); + + // Generalize type of `a_ty` appropriately depending on the + // direction. As an example, assume: + // + // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an + // inference variable, + // - and `dir` == `SubtypeOf`. + // + // Then the generalized form `b_ty` would be `&'?2 ?3`, where + // `'?2` and `?3` are fresh region/type inference + // variables. (Down below, we will relate `a_ty <: b_ty`, + // adding constraints like `'x: '?2` and `?1 <: ?3`.) + let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?; + debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", + a_ty, dir, b_vid, b_ty); + self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty); + + // Finally, relate `b_ty` to `a_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + match dir { + EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), + SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, &a_ty, &b_ty), + }?; Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that - /// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also - /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok` + /// Attempts to generalize `ty` for the type variable `for_vid`. + /// This checks for cycle -- that is, whether the type `ty` + /// references `for_vid`. If `is_eq_relation` is false, it will + /// also replace all regions/unbound-type-variables with fresh + /// variables. Returns `TyError` in the case of a cycle, `Ok` /// otherwise. + /// + /// Preconditions: + /// + /// - `for_vid` is a "root vid" fn generalize(&self, ty: Ty<'tcx>, for_vid: ty::TyVid, - make_region_vars: bool) + is_eq_relation: bool) -> RelateResult<'tcx, Ty<'tcx>> { let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, - for_vid: for_vid, - make_region_vars: make_region_vars, + for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), + is_eq_relation: is_eq_relation, cycle_detected: false }; let u = ty.fold_with(&mut generalize); @@ -291,8 +263,8 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, span: Span, - for_vid: ty::TyVid, - make_region_vars: bool, + for_vid_sub_root: ty::TyVid, + is_eq_relation: bool, cycle_detected: bool, } @@ -303,17 +275,17 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { // Check to see whether the type we are genealizing references - // `vid`. At the same time, also update any type variables to - // the values that they are bound to. This is needed to truly - // check for cycles, but also just makes things readable. - // - // (In particular, you could have something like `$0 = Box<$1>` - // where `$1` has already been instantiated with `Box<$0>`) + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. match t.sty { ty::TyInfer(ty::TyVar(vid)) => { let mut variables = self.infcx.type_variables.borrow_mut(); let vid = variables.root_var(vid); - if vid == self.for_vid { + let sub_vid = variables.sub_root_var(vid); + if sub_vid == self.for_vid_sub_root { + // If sub-roots are equal, then `for_vid` and + // `vid` are related via subtyping. self.cycle_detected = true; self.tcx().types.err } else { @@ -322,7 +294,18 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx drop(variables); self.fold_ty(u) } - None => t, + None => { + if !self.is_eq_relation { + let origin = variables.origin(vid); + let new_var_id = variables.new_var(false, origin, None); + let u = self.tcx().mk_var(new_var_id); + debug!("generalize: replacing original vid={:?} with new={:?}", + vid, u); + u + } else { + t + } + } } } } @@ -359,7 +342,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx ty::ReScope(..) | ty::ReVar(..) | ty::ReFree(..) => { - if !self.make_region_vars { + if self.is_eq_relation { return r; } } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index bf247acec5a2d..f620965ced845 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::CombineFields; +use super::combine::{CombineFields, RelationDir}; use super::{Subtype}; -use super::type_variable::{EqTo}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; @@ -58,17 +57,17 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id); + infcx.type_variables.borrow_mut().equate(a_id, b_id); Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 806b94486615f..72b23a3bc181c 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::{self, TyCtxt}; +use infer::type_variable::TypeVariableMap; +use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use super::InferCtxt; @@ -54,57 +55,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// the actual types (`?T`, `Option(&self, origin: &RegionVariableOrigin, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - let (region_vars, value) = self.probe(|snapshot| { - let vars_at_start = self.type_variables.borrow().num_vars(); + debug!("fudge_regions_if_ok(origin={:?})", origin); + let (type_variables, region_vars, value) = self.probe(|snapshot| { match f() { Ok(value) => { let value = self.resolve_type_vars_if_possible(&value); // At this point, `value` could in principle refer - // to regions that have been created during the - // snapshot (we assert below that `f()` does not - // create any new type variables, so there - // shouldn't be any of those). Once we exit - // `probe()`, those are going to be popped, so we - // will have to eliminate any references to them. - - assert_eq!(self.type_variables.borrow().num_vars(), vars_at_start, - "type variables were created during fudge_regions_if_ok"); + // to types/regions that have been created during + // the snapshot. Once we exit `probe()`, those are + // going to be popped, so we will have to + // eliminate any references to them. + + let type_variables = + self.type_variables.borrow_mut().types_created_since_snapshot( + &snapshot.type_snapshot); let region_vars = self.region_vars.vars_created_since_snapshot( &snapshot.region_vars_snapshot); - Ok((region_vars, value)) + Ok((type_variables, region_vars, value)) } Err(e) => Err(e), } })?; // At this point, we need to replace any of the now-popped - // region variables that appear in `value` with a fresh region - // variable. We can't do this during the probe because they - // would just get popped then too. =) + // type/region variables that appear in `value` with a fresh + // variable of the appropriate kind. We can't do this during + // the probe because they would just get popped then too. =) // Micro-optimization: if no variables have been created, then // `value` can't refer to any of them. =) So we can just return it. - if region_vars.is_empty() { + if type_variables.is_empty() && region_vars.is_empty() { return Ok(value); } let mut fudger = RegionFudger { infcx: self, + type_variables: &type_variables, region_vars: ®ion_vars, origin: origin }; @@ -115,6 +111,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + type_variables: &'a TypeVariableMap, region_vars: &'a Vec, origin: &'a RegionVariableOrigin, } @@ -124,6 +121,32 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { self.infcx.tcx } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::TyInfer(ty::InferTy::TyVar(vid)) => { + match self.type_variables.get(&vid) { + None => { + // This variable was created before the + // "fudging". Since we refresh all type + // variables to their binding anyhow, we know + // that it is unbound, so we can just return + // it. + debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_none()); + ty + } + + Some(&origin) => { + // This variable was created during the + // fudging. Recreate it with a fresh variable + // here. + self.infcx.next_ty_var(origin) + } + } + } + _ => ty.super_fold_with(self), + } + } + fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { match *r { ty::ReVar(v) if self.region_vars.contains(&v) => { diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8ccadc6b2af04..a6dd18c113f1a 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -49,7 +49,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + // FIXME(#41044) -- not correct, need test + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index f7b26a918b3a2..d4d090f0153d0 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -44,6 +44,10 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. + // + // Subtle hack: ordering *may* be significant here. This method + // relates `v` to `a` first, which may help us to avoid unecessary + // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } @@ -74,7 +78,29 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, Ok(v) } - (&ty::TyInfer(TyVar(..)), _) | + // If one side is known to be a variable and one is not, + // create a variable (`v`) to represent the LUB. Make sure to + // relate `v` to the non-type-variable first (by passing it + // first to `relate_bound`). Otherwise, we would produce a + // subtype obligation that must then be processed. + // + // Example: if the LHS is a type variable, and RHS is + // `Box`, then we current compare `v` to the RHS first, + // which will instantiate `v` with `Box`. Then when `v` + // is compared to the LHS, we instantiate LHS with `Box`. + // But if we did in reverse order, we would create a `v <: + // LHS` (or vice versa) constraint and then instantiate + // `v`. This would require further processing to achieve same + // end-result; in partiular, this screws up some of the logic + // in coercion, which expects LUB to figure out that the LHS + // is (e.g.) `Box`. A more obvious solution might be to + // iterate on the subtype obligations that are returned, but I + // think this suffices. -nmatsakis + (&ty::TyInfer(TyVar(..)), _) => { + let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); + this.relate_bound(v, b, a)?; + Ok(v) + } (_, &ty::TyInfer(TyVar(..))) => { let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 89571dea10c34..d7e5c92b6e17b 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -49,7 +49,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + // FIXME(#41044) -- not correct, need test + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b07ef4dfd448e..e98792b120de2 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -48,7 +48,6 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; -mod bivariate; mod combine; mod equate; pub mod error_reporting; @@ -552,7 +551,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { } impl ExpectedFound { - fn new(a_is_expected: bool, a: T, b: T) -> Self { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { if a_is_expected { ExpectedFound {expected: a, found: b} } else { @@ -1037,9 +1036,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. }) }) } @@ -1130,6 +1129,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } + pub fn subtype_predicate(&self, + cause: &ObligationCause<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>) + -> Option> + { + // Subtle: it's ok to skip the binder here and resolve because + // `shallow_resolve` just ignores anything that is not a type + // variable, and because type variable's can't (at present, at + // least) capture any of the things bound by this binder. + // + // Really, there is no *particular* reason to do this + // `shallow_resolve` here except as a + // micro-optimization. Naturally I could not + // resist. -nmatsakis + let two_unbound_type_vars = { + let a = self.shallow_resolve(predicate.skip_binder().a); + let b = self.shallow_resolve(predicate.skip_binder().b); + a.is_ty_var() && b.is_ty_var() + }; + + if two_unbound_type_vars { + // Two unbound type variables? Can't make progress. + return None; + } + + Some(self.commit_if_ok(|snapshot| { + let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + + let cause_span = cause.span; + let ok = self.sub_types(a_is_expected, cause, a, b)?; + self.leak_check(false, cause_span, &skol_map, snapshot)?; + self.pop_skolemized(skol_map, snapshot); + Ok(ok.unit()) + })) + } + pub fn region_outlives_predicate(&self, cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index dae30ea97c80d..2a7dbbc026bc0 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -9,11 +9,12 @@ // except according to those terms. use super::SubregionOrigin; -use super::combine::CombineFields; -use super::type_variable::{SubtypeOf, SupertypeOf}; +use super::combine::{CombineFields, RelationDir}; +use traits::Obligation; use ty::{self, Ty, TyCtxt}; use ty::TyVar; +use ty::fold::TypeFoldable; use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; @@ -65,7 +66,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), } } @@ -79,19 +80,38 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables - .borrow_mut() - .relate_vars(a_id, SubtypeOf, b_id); + (&ty::TyInfer(TyVar(a_vid)), &ty::TyInfer(TyVar(b_vid))) => { + // Shouldn't have any LBR here, so we can safely put + // this under a binder below without fear of accidental + // capture. + assert!(!a.has_escaping_regions()); + assert!(!b.has_escaping_regions()); + + // can't make progress on `A <: B` if both A and B are + // type variables, so record an obligation. We also + // have to record in the `type_variables` tracker that + // the two variables are equal modulo subtyping, which + // is important to the occurs check later on. + infcx.type_variables.borrow_mut().sub(a_vid, b_vid); + self.fields.obligations.push( + Obligation::new( + self.fields.trace.cause.clone(), + ty::Predicate::Subtype( + ty::Binder(ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a, + b, + })))); + Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { self.fields - .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; + .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; Ok(a) } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 67f37e5f9272e..4ae2a8026409d 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::RelationDir::*; use self::TypeVariableValue::*; -use self::UndoEntry::*; use hir::def_id::{DefId}; -use syntax::util::small_vector::SmallVector; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; @@ -21,16 +18,39 @@ use std::cmp::min; use std::marker::PhantomData; use std::mem; use std::u32; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; pub struct TypeVariableTable<'tcx> { values: sv::SnapshotVec>, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X == ?Y`. eq_relations: ut::UnificationTable, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second + /// table exists only to help with the occurs check. In particular, + /// we want to report constraints like these as an occurs check + /// violation: + /// + /// ?1 <: ?3 + /// Box <: ?1 + /// + /// This works because `?1` and `?3` are unified in the + /// `sub_relations` relation (not in `eq_relations`). Then when we + /// process the `Box <: ?1` constraint, we do an occurs check + /// on `Box` and find a potential cycle. + /// + /// This is reasonable because, in Rust, subtypes have the same + /// "skeleton" and hence there is no possible type such that + /// (e.g.) `Box <: ?3` for any `?3`. + sub_relations: ut::UnificationTable, } /// Reasons to create a type inference variable -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), @@ -44,8 +64,11 @@ pub enum TypeVariableOrigin { DivergingBlockExpr(Span), DivergingFn(Span), LatticeVariable(Span), + Generalized(ty::TyVid), } +pub type TypeVariableMap = FxHashMap; + struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, origin: TypeVariableOrigin, @@ -55,7 +78,6 @@ struct TypeVariableData<'tcx> { enum TypeVariableValue<'tcx> { Known(Ty<'tcx>), Bounded { - relations: Vec, default: Option> } } @@ -74,47 +96,25 @@ pub struct Default<'tcx> { pub struct Snapshot { snapshot: sv::Snapshot, eq_snapshot: ut::Snapshot, + sub_snapshot: ut::Snapshot, } -enum UndoEntry<'tcx> { - // The type of the var was specified. - SpecifyVar(ty::TyVid, Vec, Option>), - Relate(ty::TyVid, ty::TyVid), - RelateRange(ty::TyVid, usize), +struct Instantiate<'tcx> { + vid: ty::TyVid, + default: Option>, } struct Delegate<'tcx>(PhantomData<&'tcx ()>); -type Relation = (RelationDir, ty::TyVid); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum RelationDir { - SubtypeOf, SupertypeOf, EqTo, BiTo -} - -impl RelationDir { - fn opposite(self) -> RelationDir { - match self { - SubtypeOf => SupertypeOf, - SupertypeOf => SubtypeOf, - EqTo => EqTo, - BiTo => BiTo, - } - } -} - impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { TypeVariableTable { values: sv::SnapshotVec::new(), eq_relations: ut::UnificationTable::new(), + sub_relations: ut::UnificationTable::new(), } } - fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { - relations(self.values.get_mut(a.index as usize)) - } - pub fn default(&self, vid: ty::TyVid) -> Option> { match &self.values.get(vid.index as usize).value { &Known(_) => None, @@ -130,68 +130,46 @@ impl<'tcx> TypeVariableTable<'tcx> { &self.values.get(vid.index as usize).origin } - /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. + /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. - pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - let a = self.root_var(a); - let b = self.root_var(b); - if a != b { - if dir == EqTo { - // a and b must be equal which we mark in the unification table - let root = self.eq_relations.union(a, b); - // In addition to being equal, all relations from the variable which is no longer - // the root must be added to the root so they are not forgotten as the other - // variable should no longer be referenced (other than to get the root) - let other = if a == root { b } else { a }; - let count = { - let (relations, root_relations) = if other.index < root.index { - let (pre, post) = self.values.split_at_mut(root.index as usize); - (relations(&mut pre[other.index as usize]), relations(&mut post[0])) - } else { - let (pre, post) = self.values.split_at_mut(other.index as usize); - (relations(&mut post[0]), relations(&mut pre[root.index as usize])) - }; - root_relations.extend_from_slice(relations); - relations.len() - }; - self.values.record(RelateRange(root, count)); - } else { - self.relations(a).push((dir, b)); - self.relations(b).push((dir.opposite(), a)); - self.values.record(Relate(a, b)); - } - } + pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.eq_relations.union(a, b); + self.sub_relations.union(a, b); } - /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the - /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)` - /// where `vid1` is some other variable id. + /// Records that `a <: b`, depending on `dir`. /// - /// Precondition: `vid` must be a root in the unification table - pub fn instantiate_and_push( - &mut self, - vid: ty::TyVid, - ty: Ty<'tcx>, - stack: &mut SmallVector<(Ty<'tcx>, RelationDir, ty::TyVid)>) - { - debug_assert!(self.root_var(vid) == vid); - let old_value = { - let value_ptr = &mut self.values.get_mut(vid.index as usize).value; - mem::replace(value_ptr, Known(ty)) - }; + /// Precondition: neither `a` nor `b` are known. + pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.sub_relations.union(a, b); + } + + /// Instantiates `vid` with the type `ty`. + /// + /// Precondition: `vid` must not have been previously instantiated. + pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { + let vid = self.root_var(vid); + debug_assert!(self.probe_root(vid).is_none()); - let (relations, default) = match old_value { - Bounded { relations, default } => (relations, default), - Known(_) => bug!("Asked to instantiate variable that is \ - already instantiated") + let old_value = { + let vid_data = &mut self.values[vid.index as usize]; + mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty)) }; - for &(dir, vid) in &relations { - stack.push((ty, dir, vid)); + match old_value { + TypeVariableValue::Bounded { default } => { + self.values.record(Instantiate { vid: vid, default: default }); + } + TypeVariableValue::Known(old_ty) => { + bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", + vid, ty, old_ty) + } } - - self.values.record(SpecifyVar(vid, relations, default)); } pub fn new_var(&mut self, @@ -200,8 +178,9 @@ impl<'tcx> TypeVariableTable<'tcx> { default: Option>,) -> ty::TyVid { debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); + self.sub_relations.new_key(()); let index = self.values.push(TypeVariableData { - value: Bounded { relations: vec![], default: default }, + value: Bounded { default: default }, origin: origin, diverging: diverging }); @@ -214,15 +193,41 @@ impl<'tcx> TypeVariableTable<'tcx> { self.values.len() } + /// Returns the "root" variable of `vid` in the `eq_relations` + /// equivalence table. All type variables that have been equated + /// will yield the same root variable (per the union-find + /// algorithm), so `root_var(a) == root_var(b)` implies that `a == + /// b` (transitively). pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations.find(vid) } + /// Returns the "root" variable of `vid` in the `sub_relations` + /// equivalence table. All type variables that have been are + /// related via equality or subtyping will yield the same root + /// variable (per the union-find algorithm), so `sub_root_var(a) + /// == sub_root_var(b)` implies that: + /// + /// exists X. (a <: X || X <: a) && (b <: X || X <: b) + pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + self.sub_relations.find(vid) + } + + /// True if `a` and `b` have same "sub-root" (i.e., exists some + /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. + pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { + self.sub_root_var(a) == self.sub_root_var(b) + } + pub fn probe(&mut self, vid: ty::TyVid) -> Option> { let vid = self.root_var(vid); self.probe_root(vid) } + pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + self.values.get(vid.index as usize).origin.clone() + } + /// Retrieves the type of `vid` given that it is currently a root in the unification table pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { debug_assert!(self.root_var(vid) == vid); @@ -248,6 +253,7 @@ impl<'tcx> TypeVariableTable<'tcx> { Snapshot { snapshot: self.values.start_snapshot(), eq_snapshot: self.eq_relations.snapshot(), + sub_snapshot: self.sub_relations.snapshot(), } } @@ -263,13 +269,37 @@ impl<'tcx> TypeVariableTable<'tcx> { } }); - self.values.rollback_to(s.snapshot); - self.eq_relations.rollback_to(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.rollback_to(snapshot); + self.eq_relations.rollback_to(eq_snapshot); + self.sub_relations.rollback_to(sub_snapshot); } pub fn commit(&mut self, s: Snapshot) { - self.values.commit(s.snapshot); - self.eq_relations.commit(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.commit(snapshot); + self.eq_relations.commit(eq_snapshot); + self.sub_relations.commit(sub_snapshot); + } + + /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are + /// ty-variables created during the snapshot, and the values + /// `{V2}` are the root variables that they were unified with, + /// along with their origin. + pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + + actions_since_snapshot + .iter() + .filter_map(|action| match action { + &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }), + _ => None, + }) + .map(|vid| { + let origin = self.values.get(vid.index as usize).origin.clone(); + (vid, origin) + }) + .collect() } pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec> { @@ -298,7 +328,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(SpecifyVar(vid, ..)) => { + sv::UndoLog::Other(Instantiate { vid, .. }) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. @@ -334,35 +364,12 @@ impl<'tcx> TypeVariableTable<'tcx> { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = UndoEntry<'tcx>; - - fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { - match action { - SpecifyVar(vid, relations, default) => { - values[vid.index as usize].value = Bounded { - relations: relations, - default: default - }; - } + type Undo = Instantiate<'tcx>; - Relate(a, b) => { - relations(&mut (*values)[a.index as usize]).pop(); - relations(&mut (*values)[b.index as usize]).pop(); - } - - RelateRange(i, n) => { - let relations = relations(&mut (*values)[i.index as usize]); - for _ in 0..n { - relations.pop(); - } - } - } - } -} - -fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { - match v.value { - Known(_) => bug!("var_sub_var: variable is known"), - Bounded { ref mut relations, .. } => relations + fn reverse(values: &mut Vec>, action: Instantiate<'tcx>) { + let Instantiate { vid, default } = action; + values[vid.index as usize].value = Bounded { + default: default + }; } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 3b002fd4dfc1a..9176a4c01575f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -32,6 +32,7 @@ #![feature(i128_type)] #![feature(libc)] #![feature(loop_break_value)] +#![feature(never_type)] #![feature(nonzero)] #![cfg_attr(stage0, feature(pub_restricted))] #![feature(quote)] diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab40098..963cc4314eda5 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -60,6 +60,7 @@ impl FreeRegionMap { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 931c77badad22..f7a7d0e2071f2 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -39,6 +39,7 @@ use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; +use ty::SubtypePredicate; use util::nodemap::{FxHashMap, FxHashSet}; use syntax_pos::{DUMMY_SP, Span}; @@ -68,6 +69,19 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { found_pattern: Option<&'a Pat>, } +impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn is_match(&self, ty: Ty<'tcx>) -> bool { + ty == *self.target_ty || match (&ty.sty, &self.target_ty.sty) { + (&ty::TyInfer(ty::TyVar(a_vid)), &ty::TyInfer(ty::TyVar(b_vid))) => + self.infcx.type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid), + + _ => false, + } + } +} + impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { NestedVisitorMap::None @@ -76,7 +90,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { fn visit_local(&mut self, local: &'a Local) { if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) { let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let is_match = ty.walk().any(|t| t == *self.target_ty); + let is_match = ty.walk().any(|t| self.is_match(t)); if is_match && self.found_pattern.is_none() { self.found_pattern = Some(&*local.pat); @@ -112,6 +126,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { FulfillmentErrorCode::CodeAmbiguity => { self.maybe_report_ambiguity(&error.obligation); } + FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { + self.report_mismatched_types(&error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone()) + .emit(); + } } } @@ -555,6 +576,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } + ty::Predicate::Subtype(ref predicate) => { + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) + } + ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.equality_predicate(&obligation.cause, @@ -761,6 +789,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref data) => { + if data.references_error() || self.tcx.sess.has_errors() { + // no need to overload user in such cases + } else { + let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); + // both must be type variables, or the other would've been instantiated + assert!(a.is_ty_var() && b.is_ty_var()); + self.need_type_info(obligation, a); + } + } + _ => { if !self.tcx.sess.has_errors() { let mut err = struct_span_err!(self.tcx.sess, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b87d18464377f..64453f2983b92 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,6 +11,7 @@ use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate}; +use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; @@ -496,6 +497,26 @@ fn process_predicate<'a, 'gcx, 'tcx>( s => Ok(s) } } + + ty::Predicate::Subtype(ref subtype) => { + match selcx.infcx().subtype_predicate(&obligation.cause, subtype) { + None => { + // none means that both are unresolved + pending_obligation.stalled_on = vec![subtype.skip_binder().a, + subtype.skip_binder().b]; + Ok(None) + } + Some(Ok(ok)) => { + Ok(Some(ok.obligations)) + } + Some(Err(err)) => { + let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, + subtype.skip_binder().a, + subtype.skip_binder().b); + Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + } + } + } } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 47cbccdd2ab10..ea243d65881ea 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -20,7 +20,8 @@ use hir::def_id::DefId; use middle::free_region::FreeRegionMap; use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate}; -use infer::InferCtxt; +use ty::error::{ExpectedFound, TypeError}; +use infer::{InferCtxt}; use std::rc::Rc; use syntax::ast; @@ -214,6 +215,8 @@ pub struct FulfillmentError<'tcx> { pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound>, + TypeError<'tcx>), // always comes from a SubtypePredicate CodeAmbiguity, } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7cd0b26940d91..d190635bec306 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -178,6 +178,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Equate(..) => { false } @@ -209,6 +210,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 38ea1e4a19b91..67d50210ba39a 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -568,6 +568,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref p) => { + // does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, p) { + Some(Ok(InferOk { obligations, .. })) => { + self.inferred_obligations.extend(obligations); + EvaluatedToOk + }, + Some(Err(_)) => EvaluatedToErr, + None => EvaluatedToAmbig, + } + } + ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.infcx, obligation.cause.body_id, ty, obligation.cause.span) { diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 44ef461327ddb..9d0b1035ade49 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,6 +130,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeSubtypeError(ref a, ref b) => + write!(f, "CodeSubtypeError({:?}, {:?})", a, b), super::CodeAmbiguity => write!(f, "Ambiguity") } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 602f27a64d4d8..d4245ec9b2475 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -42,7 +42,10 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::ObjectSafe(data), ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind) + ty::Predicate::ClosureKind(closure_def_id, kind), + + ty::Predicate::Subtype(ref data) => + ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), } } @@ -160,6 +163,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { // `X == Y`, though conceivably we might. For example, // `&X == &Y` implies that `X == Y`. } + ty::Predicate::Subtype(..) => { + // Currently, we do not "elaborate" predicates like `X + // <: Y`, though conceivably we might. + } ty::Predicate::Projection(..) => { // Nothing to elaborate in a projection predicate. } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 292e30e3d41f1..d720911db39fb 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -755,6 +755,9 @@ pub enum Predicate<'tcx> { /// for some substitutions `...` and T being a closure type. /// Satisfied (or refuted) once we know the closure's kind. ClosureKind(DefId, ClosureKind), + + /// `T1 <: T2` + Subtype(PolySubtypePredicate<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { @@ -833,6 +836,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::Trait(ty::Binder(data.subst(tcx, substs))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::Subtype(ty::Binder(ref data)) => + Predicate::Subtype(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), Predicate::TypeOutlives(ty::Binder(ref data)) => @@ -912,6 +917,14 @@ pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Reg &'tcx ty::Region>; pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx ty::Region>; +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct SubtypePredicate<'tcx> { + pub a_is_expected: bool, + pub a: Ty<'tcx>, + pub b: Ty<'tcx> +} +pub type PolySubtypePredicate<'tcx> = ty::Binder>; + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1025,6 +1038,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } + ty::Predicate::Subtype(ty::Binder(SubtypePredicate { a, b, a_is_expected: _ })) => { + vec![a, b] + } ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { vec![data.0] } @@ -1061,6 +1077,7 @@ impl<'tcx> Predicate<'tcx> { } Predicate::Projection(..) | Predicate::Equate(..) | + Predicate::Subtype(..) | Predicate::RegionOutlives(..) | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 9126600e3f653..a4466d7d84011 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -111,6 +111,18 @@ impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { + type Lifted = ty::SubtypePredicate<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option> { + tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: a, + b: b, + }) + } +} + impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -167,6 +179,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::Equate(ref binder) => { tcx.lift(binder).map(ty::Predicate::Equate) } + ty::Predicate::Subtype(ref binder) => { + tcx.lift(binder).map(ty::Predicate::Subtype) + } ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) } @@ -693,6 +708,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::Trait(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::Subtype(ref binder) => + ty::Predicate::Subtype(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => ty::Predicate::RegionOutlives(binder.fold_with(folder)), ty::Predicate::TypeOutlives(ref binder) => @@ -712,6 +729,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), + ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), @@ -776,8 +794,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::EquatePredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) + ty::EquatePredicate(self.0.fold_with(folder), self.1.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -785,6 +802,20 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: self.a.fold_with(folder), + b: self.b.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.a.visit_with(visitor) || self.b.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitPredicate { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index fd8191303a9a6..2efefd750ae8a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -312,6 +312,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 8a5bd6862cf45..0b0e8a180cc36 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,10 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Subtype(ref data) => { + wf.compute(data.skip_binder().a); // (*) + wf.compute(data.skip_binder().b); // (*) + } } wf.normalize() @@ -156,6 +160,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match obligation.predicate { ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) => diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6323f1dc0d4c4..2daf71d95addf 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -416,6 +416,7 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), + ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair), @@ -676,6 +677,12 @@ impl<'tcx> fmt::Display for ty::Binder> { } } +impl<'tcx> fmt::Display for ty::Binder> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) + } +} + impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) @@ -897,6 +904,12 @@ impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> { } } +impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} <: {}", self.a, self.b) + } +} + impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TraitPredicate({:?})", @@ -949,6 +962,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), + ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index a46238309bb46..3515e5c5ede35 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -43,7 +43,16 @@ pub trait ObligationProcessor { obligation: &mut Self::Obligation) -> Result>, Self::Error>; - fn process_backedge<'c, I>(&mut self, cycle: I, + /// As we do the cycle check, we invoke this callback when we + /// encounter an actual cycle. `cycle` is an iterator that starts + /// at the start of the cycle in the stack and walks **toward the + /// top**. + /// + /// In other words, if we had O1 which required O2 which required + /// O3 which required O1, we would give an iterator yielding O1, + /// O2, O3 (O1 is not yielded twice). + fn process_backedge<'c, I>(&mut self, + cycle: I, _marker: PhantomData<&'c Self::Obligation>) where I: Clone + Iterator; } @@ -239,8 +248,8 @@ impl ObligationForest { } } Entry::Vacant(v) => { - debug!("register_obligation_at({:?}, {:?}) - ok", - obligation, parent); + debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}", + obligation, parent, self.nodes.len()); v.insert(NodeIndex::new(self.nodes.len())); self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); @@ -376,6 +385,9 @@ impl ObligationForest { where P: ObligationProcessor { let mut stack = self.scratch.take().unwrap(); + debug_assert!(stack.is_empty()); + + debug!("process_cycles()"); for index in 0..self.nodes.len() { // For rustc-benchmarks/inflate-0.1.0 this state test is extremely @@ -389,6 +401,9 @@ impl ObligationForest { } } + debug!("process_cycles: complete"); + + debug_assert!(stack.is_empty()); self.scratch = Some(stack); } @@ -402,21 +417,6 @@ impl ObligationForest { NodeState::OnDfsStack => { let index = stack.iter().rposition(|n| *n == index).unwrap(); - // I need a Clone closure - #[derive(Clone)] - struct GetObligation<'a, O: 'a>(&'a [Node]); - impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { - type Output = &'a O; - extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { - extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)), PhantomData); } @@ -645,3 +645,20 @@ impl Node { } } } + +// I need a Clone closure +#[derive(Clone)] +struct GetObligation<'a, O: 'a>(&'a [Node]); + +impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { + type Output = &'a O; + extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} + +impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { + extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 51fbc5aab6cd1..78176b155691c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -169,6 +169,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), ty::Predicate::Equate(..) => None, + ty::Predicate::Subtype(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a5acd0c7e5300..2033eaf886166 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -195,8 +195,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Consider coercing the subtype to a DST let unsize = self.coerce_unsized(a, b); if unsize.is_ok() { + debug!("coerce: unsize successful"); return unsize; } + debug!("coerce: unsize failed"); // Examine the supertype and consider auto-borrowing. // @@ -745,7 +747,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { let prev_ty = self.resolve_type_vars_with_obligations(prev_ty); let new_ty = self.resolve_type_vars_with_obligations(new_ty); - debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty); // Special-ish case: we can coerce any type `T` into the `!` // type, but only if the source expression diverges. diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 5b0418921563a..59dbbfe49f0a9 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -576,6 +576,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } } ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | @@ -1148,19 +1149,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.probe(|_| { // First check that the self type can be related. - match self.sub_types(false, - &ObligationCause::dummy(), - self_ty, - probe.xform_self_ty) { - Ok(InferOk { obligations, value: () }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) - } + let sub_obligations = match self.sub_types(false, + &ObligationCause::dummy(), + self_ty, + probe.xform_self_ty) { + Ok(InferOk { obligations, value: () }) => obligations, Err(_) => { debug!("--> cannot relate self-types"); return false; } - } + }; // If so, impls may carry other conditions (e.g., where // clauses) that must be considered. Make sure that those @@ -1199,6 +1197,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Evaluate those obligations to see if they might possibly hold. let mut all_true = true; for o in obligations.iter() + .chain(sub_obligations.iter()) .chain(norm_obligations.iter()) .chain(ref_obligations.iter()) { if !selcx.evaluate_obligation(o) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c995b7e92843d..77213b5a7436f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,9 +88,9 @@ use hir::def::{Def, CtorKind}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_back::slice::ref_slice; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; -use rustc::infer::type_variable::{self, TypeVariableOrigin}; +use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; +use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal}; use rustc::ty::{ParamTy, ParameterEnvironment}; use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; @@ -105,7 +105,7 @@ use session::{Session, CompileResult}; use TypeAndSubsts; use lint; use util::common::{ErrorReported, indenter}; -use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; +use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; use std::cell::{Cell, RefCell}; use std::cmp; @@ -1978,218 +1978,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + // Implements type inference fallback algorithm fn select_all_obligations_and_apply_defaults(&self) { - if self.tcx.sess.features.borrow().default_type_parameter_fallback { - self.new_select_all_obligations_and_apply_defaults(); - } else { - self.old_select_all_obligations_and_apply_defaults(); - } - } - - // Implements old type inference fallback algorithm - fn old_select_all_obligations_and_apply_defaults(&self) { self.select_obligations_where_possible(); self.default_type_parameters(); self.select_obligations_where_possible(); } - fn new_select_all_obligations_and_apply_defaults(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - // For the time being this errs on the side of being memory wasteful but provides better - // error reporting. - // let type_variables = self.type_variables.clone(); - - // There is a possibility that this algorithm will have to run an arbitrary number of times - // to terminate so we bound it by the compiler's recursion limit. - for _ in 0..self.tcx.sess.recursion_limit.get() { - // First we try to solve all obligations, it is possible that the last iteration - // has made it possible to make more progress. - self.select_obligations_where_possible(); - - let mut conflicts = Vec::new(); - - // Collect all unsolved type, integral and floating point variables. - let unsolved_variables = self.unsolved_variables(); - - // We must collect the defaults *before* we do any unification. Because we have - // directly attached defaults to the type variables any unification that occurs - // will erase defaults causing conflicting defaults to be completely ignored. - let default_map: FxHashMap, _> = - unsolved_variables - .iter() - .filter_map(|t| self.default(t).map(|d| (*t, d))) - .collect(); - - let mut unbound_tyvars = FxHashSet(); - - debug!("select_all_obligations_and_apply_defaults: defaults={:?}", default_map); - - // We loop over the unsolved variables, resolving them and if they are - // and unconstrainted numeric type we add them to the set of unbound - // variables. We do this so we only apply literal fallback to type - // variables without defaults. - for ty in &unsolved_variables { - let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt | UnconstrainedFloat => { - unbound_tyvars.insert(resolved); - }, - Neither => {} - } - } - } - - // We now remove any numeric types that also have defaults, and instead insert - // the type variable with a defined fallback. - for ty in &unsolved_variables { - if let Some(_default) = default_map.get(ty) { - let resolved = self.resolve_type_vars_if_possible(ty); - - debug!("select_all_obligations_and_apply_defaults: \ - ty: {:?} with default: {:?}", - ty, _default); - - match resolved.sty { - ty::TyInfer(ty::TyVar(_)) => { - unbound_tyvars.insert(ty); - } - - ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) => { - unbound_tyvars.insert(ty); - if unbound_tyvars.contains(resolved) { - unbound_tyvars.remove(resolved); - } - } - - _ => {} - } - } - } - - // If there are no more fallbacks to apply at this point we have applied all possible - // defaults and type inference will proceed as normal. - if unbound_tyvars.is_empty() { - break; - } - - // Finally we go through each of the unbound type variables and unify them with - // the proper fallback, reporting a conflicting default error if any of the - // unifications fail. We know it must be a conflicting default because the - // variable would only be in `unbound_tyvars` and have a concrete value if - // it had been solved by previously applying a default. - - // We wrap this in a transaction for error reporting, if we detect a conflict - // we will rollback the inference context to its prior state so we can probe - // for conflicts and correctly report them. - - let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| { - conflicts.extend( - self.apply_defaults_and_return_conflicts(&unbound_tyvars, &default_map, None) - ); - - // If there are conflicts we rollback, otherwise commit - if conflicts.len() > 0 { - Err(()) - } else { - Ok(()) - } - }); - - // Loop through each conflicting default, figuring out the default that caused - // a unification failure and then report an error for each. - for (conflict, default) in conflicts { - let conflicting_default = - self.apply_defaults_and_return_conflicts( - &unbound_tyvars, - &default_map, - Some(conflict) - ) - .last() - .map(|(_, tv)| tv) - .unwrap_or(type_variable::Default { - ty: self.next_ty_var( - TypeVariableOrigin::MiscVariable(syntax_pos::DUMMY_SP)), - origin_span: syntax_pos::DUMMY_SP, - // what do I put here? - def_id: self.tcx.hir.local_def_id(ast::CRATE_NODE_ID) - }); - - // This is to ensure that we elimnate any non-determinism from the error - // reporting by fixing an order, it doesn't matter what order we choose - // just that it is consistent. - let (first_default, second_default) = - if default.def_id < conflicting_default.def_id { - (default, conflicting_default) - } else { - (conflicting_default, default) - }; - - - self.report_conflicting_default_types( - first_default.origin_span, - self.body_id, - first_default, - second_default) - } - } - - self.select_obligations_where_possible(); - } - - // For use in error handling related to default type parameter fallback. We explicitly - // apply the default that caused conflict first to a local version of the type variable - // table then apply defaults until we find a conflict. That default must be the one - // that caused conflict earlier. - fn apply_defaults_and_return_conflicts<'b>( - &'b self, - unbound_vars: &'b FxHashSet>, - default_map: &'b FxHashMap, type_variable::Default<'tcx>>, - conflict: Option>, - ) -> impl Iterator, type_variable::Default<'tcx>)> + 'b { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - - conflict.into_iter().chain(unbound_vars.iter().cloned()).flat_map(move |ty| { - if self.type_var_diverges(ty) { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(ty) { - UnconstrainedInt => { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.types.f64) - }, - Neither => { - if let Some(default) = default_map.get(ty) { - let default = default.clone(); - let default_ty = self.normalize_associated_types_in( - default.origin_span, &default.ty); - match self.eq_types(false, - &self.misc(default.origin_span), - ty, - default_ty) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - return Some((ty, default)); - } - } - } - } - } - } - - None - }) - } - fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); @@ -2757,11 +2552,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // No argument expectations are produced if unification fails. let origin = self.misc(call_span); let ures = self.sub_types(false, &origin, formal_ret, ret_ty); + // FIXME(#15760) can't use try! here, FromError doesn't default // to identity so the resulting type is not constrained. match ures { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(e) => return Err(e), + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + let result = self.save_and_restore_obligations_in_snapshot_flag(|_| { + let mut fulfill = FulfillmentContext::new(); + let ok = ok; // FIXME(#30046) + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }); + + match result { + Ok(()) => { } + Err(_) => return Err(()), + } + } + Err(_) => return Err(()), } // Record all the argument types, with the substitutions diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index fb951fd20e564..2d72052f1e5ad 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1378,7 +1378,7 @@ E0102: r##" You hit this error because the compiler lacks the information to determine the type of this variable. Erroneous code example: -```compile_fail,E0102 +```compile_fail,E0282 // could be an array of anything let x = []; // error: cannot determine a type for this local variable ``` diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a24c..fb8ba51853fe8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -838,7 +838,7 @@ impl Clean> for ty::Region { pub enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec }, RegionPredicate { lifetime: Lifetime, bounds: Vec}, - EqPredicate { lhs: Type, rhs: Type } + EqPredicate { lhs: Type, rhs: Type }, } impl Clean for hir::WherePredicate { @@ -875,6 +875,7 @@ impl<'a> Clean for ty::Predicate<'a> { match *self { Predicate::Trait(ref pred) => pred.clean(cx), Predicate::Equate(ref pred) => pred.clean(cx), + Predicate::Subtype(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), @@ -904,6 +905,13 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } } +impl<'tcx> Clean for ty::SubtypePredicate<'tcx> { + fn clean(&self, _cx: &DocContext) -> WherePredicate { + panic!("subtype predicates are an internal rustc artifact \ + and should not be seen by rustdoc") + } +} + impl<'tcx> Clean for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref a, ref b) = *self; diff --git a/src/test/compile-fail/E0102.rs b/src/test/compile-fail/E0102.rs index 1d64798bb8382..6a17ddebd1dc1 100644 --- a/src/test/compile-fail/E0102.rs +++ b/src/test/compile-fail/E0102.rs @@ -10,6 +10,7 @@ fn main() { let x = []; - //~^ ERROR E0102 - //~| NOTE cannot resolve type of variable + //~^ ERROR type annotations needed + //~| NOTE consider giving `x` a type + //~| NOTE cannot infer type for `_` } diff --git a/src/test/compile-fail/binop-move-semantics.rs b/src/test/compile-fail/binop-move-semantics.rs index 0cc6ea3e984d9..cff0064497aff 100644 --- a/src/test/compile-fail/binop-move-semantics.rs +++ b/src/test/compile-fail/binop-move-semantics.rs @@ -62,7 +62,6 @@ fn mut_plus_immut() { &mut f + &f; //~ ERROR: cannot borrow `f` as immutable because it is also borrowed as mutable - //~^ cannot borrow `f` as immutable because it is also borrowed as mutable } fn immut_plus_mut() { @@ -71,7 +70,6 @@ fn immut_plus_mut() { &f + &mut f; //~ ERROR: cannot borrow `f` as mutable because it is also borrowed as immutable - //~^ cannot borrow `f` as mutable because it is also borrowed as immutable } fn main() {} diff --git a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs index 56cbe0b187867..f09e7ffd7e4b7 100644 --- a/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs +++ b/src/test/compile-fail/borrowck/borrowck-lend-flow-loop.rs @@ -109,7 +109,6 @@ fn while_aliased_mut_cond(cond: bool, cond2: bool) { borrow(&*v); //~ ERROR cannot borrow if cond2 { x = &mut v; //~ ERROR cannot borrow - //~^ ERROR cannot borrow } } } diff --git a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs index f789d44016eb1..38e0e27a7b98e 100644 --- a/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs +++ b/src/test/compile-fail/borrowck/borrowck-mut-borrow-linear-errors.rs @@ -19,7 +19,6 @@ fn main() { match 1 { 1 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time - //~| ERROR cannot borrow `x` as mutable more than once at a time 2 => { addr = &mut x; } //~^ ERROR cannot borrow `x` as mutable more than once at a time _ => { addr = &mut x; } diff --git a/src/test/compile-fail/default_ty_param_conflict.rs b/src/test/compile-fail/default_ty_param_conflict.rs deleted file mode 100644 index 8cde239ca6edf..0000000000000 --- a/src/test/compile-fail/default_ty_param_conflict.rs +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -#![feature(default_type_parameter_fallback)] - -use std::fmt::Debug; - -// Example from the RFC -fn foo() -> F { F::default() } -//~^ NOTE: a default was defined here... - -fn bar(b: B) { println!("{:?}", b); } -//~^ NOTE: a second default was defined here... - -fn main() { - // Here, F is instantiated with $0=uint - let x = foo(); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: conflicting type parameter defaults `usize` and `isize` - //~| NOTE: ...that was applied to an unconstrained type variable here - - // Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added. - bar(x); - //~^ NOTE: ...that also applies to the same type variable here -} diff --git a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs b/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs deleted file mode 100644 index e5b035e50aa93..0000000000000 --- a/src/test/compile-fail/default_ty_param_conflict_cross_crate.rs +++ /dev/null @@ -1,32 +0,0 @@ -// 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. -// -//aux-build:default_ty_param_cross_crate_crate.rs - -#![feature(default_type_parameter_fallback)] - -extern crate default_param_test; - -use default_param_test::{Foo, bleh}; - -fn meh(x: Foo) {} -//~^ NOTE: a default was defined here... - -fn main() { - let foo = bleh(); - //~^ NOTE: ...that also applies to the same type variable here - - meh(foo); - //~^ ERROR: mismatched types - //~| NOTE: conflicting type parameter defaults `bool` and `char` - //~| NOTE: conflicting type parameter defaults `bool` and `char` - //~| a second default is defined on `default_param_test::bleh` - //~| NOTE: ...that was applied to an unconstrained type variable here -} diff --git a/src/test/compile-fail/destructure-trait-ref.rs b/src/test/compile-fail/destructure-trait-ref.rs index 835ec8e4a5e7e..09bd3a2fc57d9 100644 --- a/src/test/compile-fail/destructure-trait-ref.rs +++ b/src/test/compile-fail/destructure-trait-ref.rs @@ -35,7 +35,7 @@ fn main() { // n == m let &x = &1isize as &T; //~ ERROR type `&T` cannot be dereferenced let &&x = &(&1isize as &T); //~ ERROR type `&T` cannot be dereferenced - let box x = box 1isize as Box; //~ ERROR `T: std::marker::Sized` is not satisfied + let box x = box 1isize as Box; //~ ERROR type `std::boxed::Box` cannot be dereferenced // n > m let &&x = &1isize as &T; diff --git a/src/test/compile-fail/issue-12187-1.rs b/src/test/compile-fail/issue-12187-1.rs index 346fae11070e1..6aeb9442c40ed 100644 --- a/src/test/compile-fail/issue-12187-1.rs +++ b/src/test/compile-fail/issue-12187-1.rs @@ -16,4 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` + //~| NOTE consider giving a type to pattern } diff --git a/src/test/compile-fail/issue-12187-2.rs b/src/test/compile-fail/issue-12187-2.rs index 848174d6fe1e0..d52ed06c4085d 100644 --- a/src/test/compile-fail/issue-12187-2.rs +++ b/src/test/compile-fail/issue-12187-2.rs @@ -16,4 +16,5 @@ fn main() { let &v = new(); //~^ ERROR type annotations needed [E0282] //~| NOTE cannot infer type for `_` + //~| NOTE consider giving a type to pattern } diff --git a/src/test/compile-fail/issue-25579.rs b/src/test/compile-fail/issue-25579.rs index 849c9aa18c905..323ce3b0adf33 100644 --- a/src/test/compile-fail/issue-25579.rs +++ b/src/test/compile-fail/issue-25579.rs @@ -17,7 +17,6 @@ fn causes_ice(mut l: &mut Sexpression) { loop { match l { &mut Sexpression::Num(ref mut n) => {}, &mut Sexpression::Cons(ref mut expr) => { //~ ERROR cannot borrow `l.0` - //~| ERROR cannot borrow `l.0` l = &mut **expr; //~ ERROR cannot assign to `l` } }} diff --git a/src/test/compile-fail/issue-30225.rs b/src/test/compile-fail/issue-30225.rs new file mode 100644 index 0000000000000..7acbbfb8826df --- /dev/null +++ b/src/test/compile-fail/issue-30225.rs @@ -0,0 +1,48 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #30225, which was an ICE that would trigger as +// a result of a poor interaction between trait result caching and +// type inference. Specifically, at that time, unification could cause +// unrelated type variables to become instantiated, if subtyping +// relationships existed. These relationships are now propagated +// through obligations and hence everything works out fine. + +trait Foo : Sized { + fn foo(self, u: Option, v: Option) {} +} + +struct A; +struct B; + +impl Foo for () {} // impl A +impl Foo for u32 {} // impl B, creating ambiguity + +fn toxic() { + // cache the resolution <() as Foo<$0,$1>> = impl A + let u = None; + let v = None; + Foo::foo((), u, v); +} + +fn bomb() { + let mut u = None; // type is Option<$0> + let mut v = None; // type is Option<$1> + let mut x = None; // type is Option<$2> + + Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>> + u = v; // mark $0 and $1 in a subtype relationship + //~^ ERROR mismatched types + x = Some(()); // set $2 = (), allowing impl selection + // to proceed for <() as Foo<$0, $1>> = impl A. + // kaboom, this *used* to trigge an ICE +} + +fn main() {} diff --git a/src/test/compile-fail/issue-38412.rs b/src/test/compile-fail/issue-38412.rs index 3b62aaf2ab8e9..b4feadbacf740 100644 --- a/src/test/compile-fail/issue-38412.rs +++ b/src/test/compile-fail/issue-38412.rs @@ -11,7 +11,6 @@ fn main() { let Box(a) = loop { }; //~^ ERROR expected tuple struct/variant, found struct `Box` - //~| ERROR expected tuple struct/variant, found struct `Box` // (The below is a trick to allow compiler to infer a type for // variable `a` without attempting to ascribe a type to the diff --git a/src/test/compile-fail/issue-7813.rs b/src/test/compile-fail/issue-7813.rs index fdd89058fd397..a5f001b785cc9 100644 --- a/src/test/compile-fail/issue-7813.rs +++ b/src/test/compile-fail/issue-7813.rs @@ -9,8 +9,8 @@ // except according to those terms. fn main() { - let v = &[]; - let it = v.iter(); //~ ERROR type annotations needed [E0282] - //~| NOTE cannot infer type for `T` - //~| NOTE consider giving `it` a type + let v = &[]; //~ ERROR type annotations needed + //~| NOTE consider giving `v` a type + //~| NOTE cannot infer type for `_` + let it = v.iter(); } diff --git a/src/test/compile-fail/lint-unused-imports.rs b/src/test/compile-fail/lint-unused-imports.rs index f6f7c210f466a..5bb2ab75c53fd 100644 --- a/src/test/compile-fail/lint-unused-imports.rs +++ b/src/test/compile-fail/lint-unused-imports.rs @@ -21,7 +21,6 @@ use std::fmt::{}; // Should get errors for both 'Some' and 'None' use std::option::Option::{Some, None}; //~^ ERROR unused imports: `None`, `Some` -//~| ERROR unused imports: `None`, `Some` use test::A; //~ ERROR unused import: `test::A` // Be sure that if we just bring some methods into scope that they're also diff --git a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs b/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs deleted file mode 100644 index 8fc2c2e6bce70..0000000000000 --- a/src/test/run-pass/default_ty_param_default_dependent_associated_type.rs +++ /dev/null @@ -1,36 +0,0 @@ -// 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. -// - -#![feature(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -trait Id { - type This; -} - -impl Id for A { - type This = A; -} - -struct Foo::This> { - data: PhantomData<(X, Y)> -} - -impl Foo { - fn new() -> Foo { - Foo { data: PhantomData } - } -} - -fn main() { - let foo = Foo::new(); -} diff --git a/src/test/run-pass/default_ty_param_dependent_defaults.rs b/src/test/run-pass/default_ty_param_dependent_defaults.rs deleted file mode 100644 index ac833d0f54744..0000000000000 --- a/src/test/run-pass/default_ty_param_dependent_defaults.rs +++ /dev/null @@ -1,19 +0,0 @@ -// 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. -// - -#![feature(default_type_parameter_fallback)] -use std::marker::PhantomData; - -struct Foo { t: T, data: PhantomData } - -fn main() { - let foo = Foo { t: 'a', data: PhantomData }; -} diff --git a/src/test/run-pass/default_ty_param_method_call_test.rs b/src/test/run-pass/default_ty_param_method_call_test.rs deleted file mode 100644 index e8d93092ec53d..0000000000000 --- a/src/test/run-pass/default_ty_param_method_call_test.rs +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -#![feature(default_type_parameter_fallback)] - -struct Foo; - -impl Foo { - fn method(&self) -> A { - A::default() - } -} - -fn main() { - let f = Foo.method(); - println!("{}", f); -} diff --git a/src/test/run-pass/default_ty_param_struct.rs b/src/test/run-pass/default_ty_param_struct.rs deleted file mode 100644 index d9ac51fc23b02..0000000000000 --- a/src/test/run-pass/default_ty_param_struct.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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. - -#![feature(default_type_parameter_fallback)] - -struct Foo(A); - -impl Foo { - fn new() -> Foo { - Foo(A::default()) - } -} - -fn main() { - let foo = Foo::new(); -} diff --git a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs b/src/test/run-pass/default_ty_param_struct_and_type_alias.rs deleted file mode 100644 index d3bdab9082e32..0000000000000 --- a/src/test/run-pass/default_ty_param_struct_and_type_alias.rs +++ /dev/null @@ -1,40 +0,0 @@ -// 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. -// - -#![feature(default_type_parameter_fallback)] - -use std::marker::PhantomData; - -pub struct DeterministicHasher; -pub struct RandomHasher; - - -pub struct MyHashMap { - data: PhantomData<(K, V, H)> -} - -impl MyHashMap { - fn new() -> MyHashMap { - MyHashMap { data: PhantomData } - } -} - -mod mystd { - use super::{MyHashMap, RandomHasher}; - pub type HashMap = MyHashMap; -} - -fn try_me(hash_map: mystd::HashMap) {} - -fn main() { - let hash_map = mystd::HashMap::new(); - try_me(hash_map); -} diff --git a/src/test/run-pass/default_ty_param_trait_impl.rs b/src/test/run-pass/default_ty_param_trait_impl.rs deleted file mode 100644 index c67d3a49aff3d..0000000000000 --- a/src/test/run-pass/default_ty_param_trait_impl.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -#![feature(default_type_parameter_fallback)] - -// Another example from the RFC -trait Foo { } -trait Bar { } - -impl Foo for Vec {} -impl Bar for usize {} - -fn takes_foo(f: F) {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - takes_foo(x); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default_ty_param_trait_impl_simple.rs b/src/test/run-pass/default_ty_param_trait_impl_simple.rs deleted file mode 100644 index 067ad524922c0..0000000000000 --- a/src/test/run-pass/default_ty_param_trait_impl_simple.rs +++ /dev/null @@ -1,26 +0,0 @@ -// 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. - -#![feature(default_type_parameter_fallback)] - -// An example from the RFC -trait Foo { fn takes_foo(&self); } -trait Bar { } - -impl Foo for Vec { - fn takes_foo(&self) {} -} - -impl Bar for usize {} - -fn main() { - let x = Vec::new(); // x: Vec<$0> - x.takes_foo(); // adds oblig Vec<$0> : Foo -} diff --git a/src/test/run-pass/default_ty_param_type_alias.rs b/src/test/run-pass/issue-40951.rs similarity index 64% rename from src/test/run-pass/default_ty_param_type_alias.rs rename to src/test/run-pass/issue-40951.rs index 1b4747406d0c6..adc7101b16aa1 100644 --- a/src/test/run-pass/default_ty_param_type_alias.rs +++ b/src/test/run-pass/issue-40951.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(default_type_parameter_fallback)] +// Regression test for #40951. -use std::collections::HashMap; +const FOO: [&'static str; 1] = ["foo"]; -type IntMap = HashMap; +fn find(t: &[T], element: &T) { } fn main() { - let x = IntMap::new(); + let x = format!("hi"); + find(&FOO, &&*x); } diff --git a/src/test/run-pass/type-infer-generalize-ty-var.rs b/src/test/run-pass/type-infer-generalize-ty-var.rs new file mode 100644 index 0000000000000..d7fb85ca4842e --- /dev/null +++ b/src/test/run-pass/type-infer-generalize-ty-var.rs @@ -0,0 +1,60 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test a scenario where we generate a constraint like `?1 <: &?2`. +// In such a case, it is important that we instantiate `?1` with `&?3` +// where `?3 <: ?2`, and not with `&?2`. This is a regression test for +// #18653. The important thing is that we build. + +use std::cell::RefCell; + +enum Wrap { + WrapSome(A), + WrapNone +} + +use Wrap::*; + +struct T; +struct U; + +trait Get { + fn get(&self) -> &T; +} + +impl Get for Wrap { + fn get(&self) -> &(MyShow + 'static) { + static x: usize = 42; + &x + } +} + +impl Get for Wrap { + fn get(&self) -> &usize { + static x: usize = 55; + &x + } +} + +trait MyShow { fn dummy(&self) { } } +impl<'a> MyShow for &'a (MyShow + 'a) { } +impl MyShow for usize { } +fn constrain<'a>(rc: RefCell<&'a (MyShow + 'a)>) { } + +fn main() { + let mut collection: Wrap<_> = WrapNone; + + { + let __arg0 = Get::get(&collection); + let __args_cell = RefCell::new(__arg0); + constrain(__args_cell); + } + collection = WrapSome(T); +} diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index d9da1bdc34858..06cbd9a3df416 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -97,6 +97,7 @@ fn push_expected_errors(expected_errors: &mut Vec, let primary_spans: Vec<_> = spans_in_this_file.iter() .cloned() .filter(|span| span.is_primary) + .take(1) // sometimes we have more than one showing up in the json; pick first .collect(); let primary_spans = if primary_spans.is_empty() { // subdiagnostics often don't have a span of their own;