diff --git a/src/Cargo.lock b/src/Cargo.lock index c4314b41e3966..2276c18ba1a23 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -536,6 +536,14 @@ name = "either" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ena" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "enum_primitive" version = "0.1.1" @@ -1649,6 +1657,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ + "ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -1679,6 +1688,7 @@ dependencies = [ "rustc_privacy 0.0.0", "rustc_resolve 0.0.0", "rustc_save_analysis 0.0.0", + "rustc_traits 0.0.0", "rustc_trans 0.0.0", "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", @@ -1855,6 +1865,23 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_traits" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "graphviz 0.0.0", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc_const_eval 0.0.0", + "rustc_const_math 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_errors 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + [[package]] name = "rustc_trans" version = "0.0.0" @@ -2633,6 +2660,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e45aa15fe0a8a8f511e6d834626afd55e49b62e5c8802e18328a87e8a8f6065c" "checksum either 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e311a7479512fbdf858fb54d91ec59f3b9f85bc0113659f46bba12b199d273ce" +"checksum ena 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb80e4764284ff0ec7054cb05c557f5ba01ccf65ff0c265e981c0b303d0ffc" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e7627b110fae4..45f98f275c099 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -12,6 +12,7 @@ //! from rustc::ty in no particular order. use ich::{StableHashingContext, NodeIdHashingMode}; +use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use std::hash as std_hash; @@ -75,6 +76,9 @@ for ty::RegionKind { ty::ReFree(ref free_region) => { free_region.hash_stable(hcx, hasher); } + ty::ReCanonical(cvar) => { + cvar.index().hash_stable(hcx, hasher); + } ty::ReLateBound(..) | ty::ReVar(..) | ty::ReSkolemized(..) => { @@ -184,7 +188,6 @@ 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 }); @@ -212,35 +215,49 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::Predicate<'gcx> { hasher: &mut StableHasher<W>) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - ty::Predicate::Trait(ref pred) => { - pred.hash_stable(hcx, hasher); + ty::Predicate::Poly(ref a) => { + a.hash_stable(hcx, hasher); } - ty::Predicate::Equate(ref pred) => { + + ty::Predicate::Atom(ref a) => { + a.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'gcx>> for ty::PredicateAtom<'gcx> { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher<W>) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::PredicateAtom::Trait(ref pred) => { pred.hash_stable(hcx, hasher); } - ty::Predicate::Subtype(ref pred) => { + ty::PredicateAtom::Subtype(ref pred) => { pred.hash_stable(hcx, hasher); } - ty::Predicate::RegionOutlives(ref pred) => { + ty::PredicateAtom::RegionOutlives(ref pred) => { pred.hash_stable(hcx, hasher); } - ty::Predicate::TypeOutlives(ref pred) => { + ty::PredicateAtom::TypeOutlives(ref pred) => { pred.hash_stable(hcx, hasher); } - ty::Predicate::Projection(ref pred) => { + ty::PredicateAtom::Projection(ref pred) => { pred.hash_stable(hcx, hasher); } - ty::Predicate::WellFormed(ty) => { + ty::PredicateAtom::WellFormed(ty) => { ty.hash_stable(hcx, hasher); } - ty::Predicate::ObjectSafe(def_id) => { + ty::PredicateAtom::ObjectSafe(def_id) => { def_id.hash_stable(hcx, hasher); } - ty::Predicate::ClosureKind(def_id, closure_kind) => { + ty::PredicateAtom::ClosureKind(def_id, closure_kind) => { def_id.hash_stable(hcx, hasher); closure_kind.hash_stable(hcx, hasher); } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } @@ -801,6 +818,7 @@ for ty::steal::Steal<T> impl_stable_hash_for!(struct ty::ParamEnv<'tcx> { caller_bounds, + universe, reveal }); @@ -970,3 +988,12 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContex nested.hash_stable(hcx, hasher); } } + +impl<'gcx> HashStable<StableHashingContext<'gcx>> +for ty::UniverseIndex { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher<W>) { + self.depth().hash_stable(hcx, hasher); + } +} diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md index 6c1478531f147..a528b5d08bb9d 100644 --- a/src/librustc/infer/README.md +++ b/src/librustc/infer/README.md @@ -1,239 +1,86 @@ # Type inference engine -This is loosely based on standard HM-type inference, but with an -extension to try and accommodate subtyping. There is nothing -principled about this extension; it's sound---I hope!---but it's a -heuristic, ultimately, and does not guarantee that it finds a valid -typing even if one exists (in fact, there are known scenarios where it -fails, some of which may eventually become problematic). - -## Key idea - -The main change is that each type variable T is associated with a -lower-bound L and an upper-bound U. L and U begin as bottom and top, -respectively, but gradually narrow in response to new constraints -being introduced. When a variable is finally resolved to a concrete -type, it can (theoretically) select any type that is a supertype of L -and a subtype of U. - -There are several critical invariants which we maintain: - -- the upper-bound of a variable only becomes lower and the lower-bound - only becomes higher over time; -- the lower-bound L is always a subtype of the upper bound U; -- the lower-bound L and upper-bound U never refer to other type variables, - but only to types (though those types may contain type variables). - -> An aside: if the terms upper- and lower-bound confuse you, think of -> "supertype" and "subtype". The upper-bound is a "supertype" -> (super=upper in Latin, or something like that anyway) and the lower-bound -> is a "subtype" (sub=lower in Latin). I find it helps to visualize -> a simple class hierarchy, like Java minus interfaces and -> primitive types. The class Object is at the root (top) and other -> types lie in between. The bottom type is then the Null type. -> So the tree looks like: -> -> ```text -> Object -> / \ -> String Other -> \ / -> (null) -> ``` -> -> So the upper bound type is the "supertype" and the lower bound is the -> "subtype" (also, super and sub mean upper and lower in Latin, or something -> like that anyway). - -## Satisfying constraints - -At a primitive level, there is only one form of constraint that the -inference understands: a subtype relation. So the outside world can -say "make type A a subtype of type B". If there are variables -involved, the inferencer will adjust their upper- and lower-bounds as -needed to ensure that this relation is satisfied. (We also allow "make -type A equal to type B", but this is translated into "A <: B" and "B -<: A") - -As stated above, we always maintain the invariant that type bounds -never refer to other variables. This keeps the inference relatively -simple, avoiding the scenario of having a kind of graph where we have -to pump constraints along and reach a fixed point, but it does impose -some heuristics in the case where the user is relating two type -variables A <: B. - -Combining two variables such that variable A will forever be a subtype -of variable B is the trickiest part of the algorithm because there is -often no right choice---that is, the right choice will depend on -future constraints which we do not yet know. The problem comes about -because both A and B have bounds that can be adjusted in the future. -Let's look at some of the cases that can come up. - -Imagine, to start, the best case, where both A and B have an upper and -lower bound (that is, the bounds are not top nor bot respectively). In -that case, if we're lucky, A.ub <: B.lb, and so we know that whatever -A and B should become, they will forever have the desired subtyping -relation. We can just leave things as they are. - -### Option 1: Unify - -However, suppose that A.ub is *not* a subtype of B.lb. In -that case, we must make a decision. One option is to unify A -and B so that they are one variable whose bounds are: - - UB = GLB(A.ub, B.ub) - LB = LUB(A.lb, B.lb) - -(Note that we will have to verify that LB <: UB; if it does not, the -types are not intersecting and there is an error) In that case, A <: B -holds trivially because A==B. However, we have now lost some -flexibility, because perhaps the user intended for A and B to end up -as different types and not the same type. - -Pictorially, what this does is to take two distinct variables with -(hopefully not completely) distinct type ranges and produce one with -the intersection. - -```text - B.ub B.ub - /\ / - A.ub / \ A.ub / - / \ / \ \ / - / X \ UB - / / \ \ / \ - / / / \ / / - \ \ / / \ / - \ X / LB - \ / \ / / \ - \ / \ / / \ - A.lb B.lb A.lb B.lb +The engine is based around an extension of HM-type-inference so that +it supports "multiple universes" (that is, the ability to reason about +variables where different sets of names are in scope per variable). +This is very similar to the "Labeled Unification" procedure described +in the paper, +["A Proof Procedure for the Logic of Hereditary Harrop Formulas"][pplhhhf] +by Gopalan Nadathur, with some extensions to accommodate subtyping. + +[pplhhhf]: https://pdfs.semanticscholar.org/335f/16ac16b3de99679cb7adf435056000ef811b.pdf + +## Universes and skolemization + +Universes and skolemization are two complex sound terms, but the +underlying idea is quite simple. Consider a type like this: + + for<'a> fn(&'a u32) + +Here the `for<'a>` quantifier brings `'a` into scope -- that is, +within the function type, we can refer to `'a`. But outside, we cannot +(in fact, Rust does not allow shadowing in such names, but even if it +did, if we were to use the name `'a`, it would be referring to some +other lifetime, not `'a`). + +To describe this idea, we say that, when we enter the function type, +we enter into a **subuniverse** U1 of the original universe U0. In +this subuniverse U1, we can name all the names from U0, but we can +also use refer to `'a`. In this case, when we refer to `'a`, we are +not referring to any 'real' region, but rather an abstract one -- a +kind of ideal representative, meaning "any region that might later be +used for `'a`". This idea, of an abstract representative, is called a +**skolemized** region (named after [Thoraf Skolem], a philosopher and +mathematician who pioneered the technique). + +[Thoraf Skolem]: https://en.wikipedia.org/wiki/Thoralf_Skolem + +The same ideas (universes and skolemization) apply to types, which +might help make them easier to understand. Consider: + +```rust +fn foo<T: Display>(v: Vec<T>) { ... } ``` +When we type-check the body of `foo`, we are able to refer to `T` as +if it were a real type. But it's not a real type -- it's a *skolemized +type*, representing the abstract idea of "some type T, where the only +thing we know about `T` is that it is `Sized` and it implements +`Display`". -### Option 2: Relate UB/LB - -Another option is to keep A and B as distinct variables but set their -bounds in such a way that, whatever happens, we know that A <: B will hold. -This can be achieved by ensuring that A.ub <: B.lb. In practice there -are two ways to do that, depicted pictorially here: - -```text - Before Option #1 Option #2 - - B.ub B.ub B.ub - /\ / \ / \ - A.ub / \ A.ub /(B')\ A.ub /(B')\ - / \ / \ \ / / \ / / - / X \ __UB____/ UB / - / / \ \ / | | / - / / / \ / | | / - \ \ / / /(A')| | / - \ X / / LB ______LB/ - \ / \ / / / \ / (A')/ \ - \ / \ / \ / \ \ / \ - A.lb B.lb A.lb B.lb A.lb B.lb -``` +Universes form a tree. However, in the compiler, we represent them +using only a single integer (`ty::UniverseIndex`). This suffices +because sibling universes never come into contact with one another -- +so while names from U1 and U0 may "interact" (i.e., appear in the same +constraint etc), if U0 has *another* subuniverse `U1'`, then names +from `U1` and `U1'` will never interact with one another. -In these diagrams, UB and LB are defined as before. As you can see, -the new ranges `A'` and `B'` are quite different from the range that -would be produced by unifying the variables. +## Basic unification -### What we do now +The basic idea of unification is that, when we encounter a type that +we do not know, we instantiate a type variable `?T` (we will use a +leading question mark to refer to inference variables of this kind; +`?'A` will be used for region variables). Later, when we are doing +type-checking etc, we may encounter a constraint that tells us what +`?T` has to be. For example, imagine that `Vec<?T>` is the type of +some variable `x`, and we encounter some code which states that the +type of `x` must be equal to `Vec<i32>`. We could write the constraint +that arises from this as: -Our current technique is to *try* (transactionally) to relate the -existing bounds of A and B, if there are any (i.e., if `UB(A) != top -&& LB(B) != bot`). If that succeeds, we're done. If it fails, then -we merge A and B into same variable. + Vec<?T> = Vec<i32> + +Since we know that `Vec<T>` is only equal to `Vec<U>` if `T=U`, we can +further derive from this constraint that `?T = i32`. This general +process is called **unification**. It's a "tried and true" technique +and there are good descriptions of it in many places; you can read a +Rust-oriented description of it in [this blog post][unification1]. -This is not clearly the correct course. For example, if `UB(A) != -top` but `LB(B) == bot`, we could conceivably set `LB(B)` to `UB(A)` -and leave the variables unmerged. This is sometimes the better -course, it depends on the program. +[unification1]: http://smallcultfollowing.com/babysteps/blog/2017/03/25/unification-in-chalk-part-1/ -The main case which fails today that I would like to support is: +## Extending unification with universes -```rust -fn foo<T>(x: T, y: T) { ... } +To -fn bar() { - let x: @mut int = @mut 3; - let y: @int = @3; - foo(x, y); -} -``` +## Handling subtyping -In principle, the inferencer ought to find that the parameter `T` to -`foo(x, y)` is `@const int`. Today, however, it does not; this is -because the type variable `T` is merged with the type variable for -`X`, and thus inherits its UB/LB of `@mut int`. This leaves no -flexibility for `T` to later adjust to accommodate `@int`. - -Note: `@` and `@mut` are replaced with `Rc<T>` and `Rc<RefCell<T>>` in current Rust. - -### What to do when not all bounds are present - -In the prior discussion we assumed that A.ub was not top and B.lb was -not bot. Unfortunately this is rarely the case. Often type variables -have "lopsided" bounds. For example, if a variable in the program has -been initialized but has not been used, then its corresponding type -variable will have a lower bound but no upper bound. When that -variable is then used, we would like to know its upper bound---but we -don't have one! In this case we'll do different things depending on -how the variable is being used. - -## Transactional support - -Whenever we adjust merge variables or adjust their bounds, we always -keep a record of the old value. This allows the changes to be undone. - -## Regions - -I've only talked about type variables here, but region variables -follow the same principle. They have upper- and lower-bounds. A -region A is a subregion of a region B if A being valid implies that B -is valid. This basically corresponds to the block nesting structure: -the regions for outer block scopes are superregions of those for inner -block scopes. - -## Integral and floating-point type variables - -There is a third variety of type variable that we use only for -inferring the types of unsuffixed integer literals. Integral type -variables differ from general-purpose type variables in that there's -no subtyping relationship among the various integral types, so instead -of associating each variable with an upper and lower bound, we just -use simple unification. Each integer variable is associated with at -most one integer type. Floating point types are handled similarly to -integral types. - -## GLB/LUB - -Computing the greatest-lower-bound and least-upper-bound of two -types/regions is generally straightforward except when type variables -are involved. In that case, we follow a similar "try to use the bounds -when possible but otherwise merge the variables" strategy. In other -words, `GLB(A, B)` where `A` and `B` are variables will often result -in `A` and `B` being merged and the result being `A`. - -## Type coercion - -We have a notion of assignability which differs somewhat from -subtyping; in particular it may cause region borrowing to occur. See -the big comment later in this file on Type Coercion for specifics. - -### In conclusion - -I showed you three ways to relate `A` and `B`. There are also more, -of course, though I'm not sure if there are any more sensible options. -The main point is that there are various options, each of which -produce a distinct range of types for `A` and `B`. Depending on what -the correct values for A and B are, one of these options will be the -right choice: but of course we don't know the right values for A and B -yet, that's what we're trying to find! In our code, we opt to unify -(Option #1). - -# Implementation details - -We make use of a trait-like implementation strategy to consolidate -duplicated code between subtypes, GLB, and LUB computations. See the -section on "Type Combining" in combine.rs for more details. +In truth, outside of trait matching, we rarely encounter *equality* constraints in Rust. diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index 3fd7ee276729f..42c6085e7d7fb 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -62,11 +62,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { - fn to_trace(cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self) - -> TypeTrace<'tcx>; + fn to_trace<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx>; } impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> { @@ -111,6 +112,47 @@ impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> { self.sub_exp(false, actual, expected) } + /// See if we can instantiate `expected` in such a way that + /// `actual` would be an instance of it. Commonly used in trait + /// matching, where you might have a rule like: + /// + /// expected = for<'a> T: Foo<'a> + /// + /// and we want to see if it can full `actual == T: Foo<'static>`. + /// + /// This routine would then instantiate `'a` with a fresh + /// inference variable and equate the result with `actual`. + pub fn instantiable_as<T>(self, + expected: ty::Binder<T>, + actual: T) + -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + debug!("instantiable_as(expected={:?}, actual={:?})", expected, actual); + + let (expected_prime, _) = + self.infcx.replace_late_bound_regions_with_fresh_var( + self.cause.span, + self.param_env.universe, + HigherRankedType, + &expected); + + debug!("instantiable_as: expected_prime={:?}", expected_prime); + + self.eq(expected_prime, actual) + } + + /// Like `instantiable_as`, but just returns true if no immediate + /// error would result. + pub fn can_instantiate_as<T>(self, + expected: ty::Binder<T>, + actual: T) + -> bool + where T: ToTrace<'tcx> + { + self.infcx.probe(|_| self.instantiable_as(expected, actual).is_ok()) + } + /// Make `expected <: actual` pub fn sub<T>(self, expected: T, @@ -191,7 +233,7 @@ impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> { -> Trace<'a, 'gcx, 'tcx> where T: ToTrace<'tcx> { - let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); + let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b); Trace { at: self, trace: trace, a_is_expected } } } @@ -209,8 +251,8 @@ impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> { debug!("sub({:?} <: {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields.sub(a_is_expected) + let mut fields = at.infcx.combine_fields(trace); + fields.sub(at.param_env, a_is_expected) .relate(a, b) .map(move |_| InferOk { value: (), obligations: fields.obligations }) }) @@ -227,8 +269,8 @@ impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> { debug!("eq({:?} == {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields.equate(a_is_expected) + let mut fields = at.infcx.combine_fields(trace); + fields.equate(at.param_env, a_is_expected) .relate(a, b) .map(move |_| InferOk { value: (), obligations: fields.obligations }) }) @@ -243,8 +285,8 @@ impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> { debug!("lub({:?} \\/ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields.lub(a_is_expected) + let mut fields = at.infcx.combine_fields(trace); + fields.lub(at.param_env, a_is_expected) .relate(a, b) .map(move |t| InferOk { value: t, obligations: fields.obligations }) }) @@ -259,8 +301,8 @@ impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> { debug!("glb({:?} /\\ {:?})", a, b); let Trace { at, trace, a_is_expected } = self; at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields.glb(a_is_expected) + let mut fields = at.infcx.combine_fields(trace); + fields.glb(at.param_env, a_is_expected) .relate(a, b) .map(move |t| InferOk { value: t, obligations: fields.obligations }) }) @@ -268,43 +310,61 @@ impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> { } impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { - fn to_trace(cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self) - -> TypeTrace<'tcx> + fn to_trace<'a, 'gcx>(_: TyCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> + { + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Types(ExpectedFound::new(a_is_expected, a, b)) + } + } +} + +impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> { + fn to_trace<'a, 'gcx>(_: TyCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Types(ExpectedFound::new(a_is_expected, a, b)) + values: ValuePairs::ProjectionTypes(ExpectedFound::new(a_is_expected, a, b)) } } } impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { - fn to_trace(cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self) - -> TypeTrace<'tcx> + fn to_trace<'a, 'gcx>(_: TyCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)) + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)) } } } impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { - fn to_trace(cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self) - -> TypeTrace<'tcx> + fn to_trace<'a, 'gcx>(_: TyCtxt<'a, 'gcx, 'tcx>, + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) + values: ValuePairs::PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)) } } } diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs new file mode 100644 index 0000000000000..f23fe008a5b8c --- /dev/null +++ b/src/librustc/infer/canonical.rs @@ -0,0 +1,295 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::InferCtxt; +use hir::def_id::DefId; +use ty::{self, CanonicalVar, Ty, TyCtxt}; +use ty::fold::{TypeFoldable, TypeFolder}; + +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::FxHashMap; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewriten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Canonical<V> { + pub variables: IndexVec<CanonicalVar, CanonicalVarInfo>, + pub value: V, +} + +/// When you canonicalize a value `V`, you get back a `Canonical<V>` +/// formed by replacing unbound inference variables and things with +/// `CanonicalVar`. This struct maps those canonical variables back to +/// the things that were removed; with it, you can reconstruct the +/// original `V`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CanonicalVarValues<'tcx> { + pub var_values: IndexVec<CanonicalVar, CanonicalVarValue<'tcx>>, +} + +/// After you canonicalize, we also return some extra information +/// about closures and generators, for example what `Fn` traits a +/// closure implements (if it has been inferred thus far). This +/// information is needed by the trait checker and becomes part of the +/// query environment. They are effectively "extra facts". +pub struct CanonicalClosureFacts<'tcx> { + pub closure_kinds: FxHashMap<DefId, ty::ClosureKind>, + pub generator_sigs: FxHashMap<DefId, ty::PolyGenSig<'tcx>>, +} + +/// Information about a canonical variable that is included with the +/// canonical value. This is sufficient information for code to create +/// a copy of the canonical value in some other inference context, +/// with fresh inference variables replacing the canonical values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct CanonicalVarInfo { + pub kind: CanonicalVarKind, + pub universe: ty::UniverseIndex, +} + +/// Describes the "kind" of the canonical variable. This is a "kind" +/// in the type-theory sense of the term -- i.e., a "meta" type system +/// that analyzes type-like values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalVarKind { + /// Some kind of type inference variable. + Ty(CanonicalTyVarKind), + + /// Region variable `'?R`. + Region, +} + +/// Rust actually has more than one category of type variables; +/// notably, the type variables we create for literals (e.g., 22 or +/// 22.) can only be instantiated with integral/float types (e.g., +/// usize or f32). In order to faithfully reproduce a type, we need to +/// know what set of types a given type variable can be unified with. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalTyVarKind { + /// General type variable `?T` that can be unified with arbitrary types. + General, + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, +} + +/// The value for a canonical variable. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum CanonicalVarValue<'tcx> { + /// Value from a Type/Int/Float type-variable `?T`. + Ty(Ty<'tcx>), + + /// Region variable `'?R`. + Region(ty::Region<'tcx>), +} + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + pub fn canonicalize<V>(&self, value: &V) -> (Canonical<V>, + CanonicalClosureFacts<'tcx>, + CanonicalVarValues<'tcx>) + where + V: TypeFoldable<'tcx>, + { + let mut canonicalizer = Canonicalizer { + infcx: self, + variables: IndexVec::default(), + indices: FxHashMap::default(), + var_values: IndexVec::default(), + closure_kinds: FxHashMap::default(), + generator_sigs: FxHashMap::default(), + }; + let out_value = value.fold_with(&mut canonicalizer); + let canonical_value = Canonical { + variables: canonicalizer.variables, + value: out_value, + }; + let canonical_closure_facts = CanonicalClosureFacts { + closure_kinds: canonicalizer.closure_kinds, + generator_sigs: canonicalizer.generator_sigs, + }; + let canonical_var_values = CanonicalVarValues { + var_values: canonicalizer.var_values, + }; + (canonical_value, canonical_closure_facts, canonical_var_values) + } +} + +struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + variables: IndexVec<CanonicalVar, CanonicalVarInfo>, + indices: FxHashMap<CanonicalVarValue<'tcx>, CanonicalVar>, + var_values: IndexVec<CanonicalVar, CanonicalVarValue<'tcx>>, + closure_kinds: FxHashMap<DefId, ty::ClosureKind>, + generator_sigs: FxHashMap<DefId, ty::PolyGenSig<'tcx>>, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReStatic | + ty::ReEarlyBound(..) | + ty::ReFree(_) | + ty::ReScope(_) | + ty::ReVar(_) | + ty::ReSkolemized(..) | + ty::ReEmpty | + ty::ReErased => { + // replace all free regions with 'erased + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + universe: ty::UniverseIndex::ROOT, // TODO + }; + let cvar = self.canonical_var(info, CanonicalVarValue::Region(r)); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } + + ty::ReCanonical(_) => { + bug!("canonical region encountered during canonicalization") + } + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if !t.needs_infer() && !t.has_erasable_regions() + && !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) + { + return t; + } + + match t.sty { + ty::TyInfer(ty::TyVar(_)) => { + self.canonicalize_ty_var( + CanonicalTyVarKind::General, + ty::UniverseIndex::ROOT, // TODO + t, + ) + } + + ty::TyInfer(ty::IntVar(_)) => { + self.canonicalize_ty_var( + CanonicalTyVarKind::Int, + ty::UniverseIndex::ROOT, // TODO + t, + ) + } + + ty::TyInfer(ty::FloatVar(_)) => { + self.canonicalize_ty_var( + CanonicalTyVarKind::Float, + ty::UniverseIndex::ROOT, // TODO + t, + ) + } + + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("encountered a fresh type during canonicalization") + } + + ty::TyInfer(ty::CanonicalTy(_)) => { + bug!("encountered a canonical type during canonicalization") + } + + ty::TyClosure(def_id, ..) => { + if let Some(kind) = self.infcx.closure_kind(def_id) { + self.closure_kinds.insert(def_id, kind); + } + t.super_fold_with(self) + } + + ty::TyGenerator(def_id, ..) => { + if let Some(gen_sig) = self.infcx.generator_sig(def_id) { + self.generator_sigs.insert(def_id, gen_sig); + } + t.super_fold_with(self) + } + + ty::TyBool | + ty::TyChar | + ty::TyInt(..) | + ty::TyUint(..) | + ty::TyFloat(..) | + ty::TyAdt(..) | + ty::TyStr | + ty::TyError | + ty::TyArray(..) | + ty::TySlice(..) | + ty::TyRawPtr(..) | + ty::TyRef(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TyDynamic(..) | + ty::TyNever | + ty::TyTuple(..) | + ty::TyProjection(..) | + ty::TyForeign(..) | + ty::TyParam(..) | + ty::TyAnon(..) => t.super_fold_with(self), + } + } +} + +impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { + fn canonical_var( + &mut self, + info: CanonicalVarInfo, + cvv: CanonicalVarValue<'tcx>, + ) -> CanonicalVar { + let Canonicalizer { + indices, + variables, + var_values, + .. + } = self; + + indices + .entry(cvv) + .or_insert_with(|| { + let cvar1 = variables.push(info); + let cvar2 = var_values.push(cvv); + assert_eq!(cvar1, cvar2); + cvar1 + }) + .clone() + } + + fn canonicalize_ty_var( + &mut self, + ty_kind: CanonicalTyVarKind, + universe: ty::UniverseIndex, + ty_var: Ty<'tcx>, + ) -> Ty<'tcx> { + let bound_to = self.infcx.shallow_resolve(ty_var); + if bound_to != ty_var { + self.fold_ty(bound_to) + } else { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Ty(ty_kind), + universe, + }; + let cvar = self.canonical_var(info, CanonicalVarValue::Ty(ty_var)); + self.tcx().mk_infer(ty::InferTy::CanonicalTy(cvar)) + } + } +} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 40e933b26a257..8dec4a2cb7738 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -34,10 +34,10 @@ use super::equate::Equate; use super::glb::Glb; +use super::{InferCtxt, MiscVariable, TypeTrace}; use super::lub::Lub; use super::sub::Sub; -use super::InferCtxt; -use super::{MiscVariable, TypeTrace}; +use super::type_variable::TypeVariableValue; use hir::def_id::DefId; use ty::{IntType, UintType}; @@ -45,7 +45,7 @@ use ty::{self, Ty, TyCtxt}; use ty::error::TypeError; use ty::relate::{self, Relate, RelateResult, TypeRelation}; use ty::subst::Substs; -use traits::{Obligation, PredicateObligations}; +use traits::{PredicateObligation, PredicateObligations}; use syntax::ast; use syntax_pos::Span; @@ -55,7 +55,6 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>, pub trace: TypeTrace<'tcx>, pub cause: Option<ty::relate::Cause>, - pub param_env: ty::ParamEnv<'tcx>, pub obligations: PredicateObligations<'tcx>, } @@ -132,7 +131,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { { self.int_unification_table .borrow_mut() - .unify_var_value(vid, val) + .unify_var_value(vid, Some(val)) .map_err(|e| int_unification_error(vid_is_expected, e))?; match val { IntType(v) => Ok(self.tcx.mk_mach_int(v)), @@ -148,7 +147,7 @@ impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { { self.float_unification_table .borrow_mut() - .unify_var_value(vid, val) + .unify_var_value(vid, Some(ty::FloatVarValue(val))) .map_err(|e| float_unification_error(vid_is_expected, e))?; Ok(self.tcx.mk_mach_float(val)) } @@ -159,20 +158,32 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { self.infcx.tcx } - pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'gcx, 'tcx> { - Equate::new(self, a_is_expected) + pub fn equate<'a>(&'a mut self, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Equate<'a, 'infcx, 'gcx, 'tcx> { + Equate::new(self, param_env, 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) + pub fn sub<'a>(&'a mut self, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Sub<'a, 'infcx, 'gcx, 'tcx> { + Sub::new(self, param_env, a_is_expected) } - pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'gcx, 'tcx> { - Lub::new(self, a_is_expected) + pub fn lub<'a>(&'a mut self, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Lub<'a, 'infcx, 'gcx, 'tcx> { + Lub::new(self, param_env, a_is_expected) } - pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'gcx, 'tcx> { - Glb::new(self, a_is_expected) + pub fn glb<'a>(&'a mut self, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Glb<'a, 'infcx, 'gcx, 'tcx> { + Glb::new(self, param_env, a_is_expected) } /// Here dir is either EqTo, SubtypeOf, or SupertypeOf. The @@ -185,6 +196,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { /// of `a_ty`. Generalization introduces other inference /// variables wherever subtyping could occur. pub fn instantiate(&mut self, + param_env: ty::ParamEnv<'tcx>, a_ty: Ty<'tcx>, dir: RelationDir, b_vid: ty::TyVid, @@ -194,7 +206,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { 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_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_unknown()); debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); @@ -215,9 +227,10 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty); if needs_wf { - self.obligations.push(Obligation::new(self.trace.cause.clone(), - self.param_env, - ty::Predicate::WellFormed(b_ty))); + self.obligations.push( + PredicateObligation::from(self.trace.cause.clone(), + param_env, + ty::PredicateAtom::WellFormed(b_ty))); } // Finally, relate `b_ty` to `a_ty`, as described in previous comment. @@ -227,9 +240,9 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { // 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( + EqTo => self.equate(param_env, a_is_expected).relate(&a_ty, &b_ty), + SubtypeOf => self.sub(param_env, a_is_expected).relate(&a_ty, &b_ty), + SupertypeOf => self.sub(param_env, a_is_expected).relate_with_variance( ty::Contravariant, &a_ty, &b_ty), }?; @@ -264,12 +277,20 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { RelationDir::SupertypeOf => ty::Contravariant, }; + let universe = match self.infcx.type_variables.borrow_mut().probe(for_vid) { + TypeVariableValue::Unknown { universe } => universe, + TypeVariableValue::Known { .. } => { + bug!("generalizing `{:?}` for vid `{:?}` which is bound", ty, for_vid) + } + }; + let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), ambient_variance, needs_wf: false, + universe, }; let ty = generalize.relate(&ty, &ty)?; @@ -284,6 +305,7 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { for_vid_sub_root: ty::TyVid, ambient_variance: ty::Variance, needs_wf: bool, // see the field `needs_wf` in `Generalization` + universe: ty::UniverseIndex, } /// Result from a generalization operation. This includes @@ -388,12 +410,12 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' // `vid` are related via subtyping. return Err(TypeError::CyclicTy); } else { - match variables.probe_root(vid) { - Some(u) => { + match variables.probe(vid) { + TypeVariableValue::Known { value: u } => { drop(variables); self.relate(&u, &u) } - None => { + TypeVariableValue::Unknown { universe } => { match self.ambient_variance { // Invariant: no need to make a fresh type variable. ty::Invariant => return Ok(t), @@ -409,8 +431,8 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' ty::Covariant | ty::Contravariant => (), } - let origin = variables.origin(vid); - let new_var_id = variables.new_var(false, origin, None); + let origin = *variables.var_origin(vid); + let new_var_id = variables.new_var(universe, false, origin); let u = self.tcx().mk_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); @@ -461,11 +483,13 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' ty::Bivariant | ty::Covariant | ty::Contravariant => (), } } + + ty::ReCanonical(..) => bug!("encountered canonical region during inference"), } // FIXME: This is non-ideal because we don't give a // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var(MiscVariable(self.span))) + Ok(self.infcx.next_region_var(self.universe, MiscVariable(self.span))) } } @@ -496,9 +520,9 @@ fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::Int } fn float_unification_error<'tcx>(a_is_expected: bool, - v: (ast::FloatTy, ast::FloatTy)) + v: (ty::FloatVarValue, ty::FloatVarValue)) -> TypeError<'tcx> { - let (a, b) = v; + let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index f9ffaee81f157..86cb68a04c0c9 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -22,13 +22,16 @@ use ty::relate::{self, Relate, RelateResult, TypeRelation}; pub struct Equate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, + param_env: ty::ParamEnv<'tcx>, } impl<'combine, 'infcx, 'gcx, 'tcx> Equate<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) -> Equate<'combine, 'infcx, 'gcx, 'tcx> { - Equate { fields: fields, a_is_expected: a_is_expected } + Equate { fields, a_is_expected, param_env } } } @@ -81,12 +84,20 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(self.param_env, + b, + RelationDir::EqTo, + a_id, + self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(self.param_env, + a, + RelationDir::EqTo, + b_id, + self.a_is_expected)?; Ok(a) } @@ -104,7 +115,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> a, b); let origin = Subtype(self.fields.trace.clone()); - self.fields.infcx.region_vars.make_eqregion(origin, a, b); + self.fields.infcx.region_vars.make_eqregion(origin, self.param_env, a, b); Ok(a) } @@ -112,7 +123,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, ty::Binder<T>> where T: Relate<'tcx> { - self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; - self.fields.higher_ranked_sub(b, a, self.a_is_expected) + self.fields.higher_ranked_sub(self.param_env, a, b, self.a_is_expected)?; + self.fields.higher_ranked_sub(self.param_env, b, a, self.a_is_expected) } } diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index e9916bd77e758..75210abcc0e9a 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -55,8 +55,7 @@ //! ported to this system, and which relies on string concatenation at the //! time of error detection. -use infer; -use super::{InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs}; +use infer::{self, InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs}; use super::region_inference::{RegionResolutionError, ConcreteFailure, SubSupConflict, GenericBoundFailure, GenericKind}; @@ -82,6 +81,7 @@ mod named_anon_conflict; #[macro_use] mod util; mod different_lifetimes; +mod skol_conflict; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, @@ -246,6 +246,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::ReErased => { (format!("lifetime {:?}", region), None) } + + ty::ReCanonical(..) => bug!("encountered canonical region during inference"), }; let message = format!("{}{}{}", prefix, description, suffix); if let Some(span) = span { @@ -293,7 +295,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("report_region_errors: error = {:?}", error); if !self.try_report_named_anon_conflict(&error) && - !self.try_report_anon_anon_conflict(&error) { + !self.try_report_anon_anon_conflict(&error) && + !self.try_report_skol_conflict(&error) { match error.clone() { // These errors could indicate all manner of different @@ -795,9 +798,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { match *values { - infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), - infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), - infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), + ValuePairs::Types(ref exp_found) => { + self.expected_found_str_ty(exp_found) + } + ValuePairs::ProjectionTypes(ref exp_found) => { + self.expected_found_str(exp_found) + } + ValuePairs::TraitRefs(ref exp_found) => { + self.expected_found_str(&exp_found.map(|t| t.print_without_self())) + } + ValuePairs::PolyTraitRefs(ref exp_found) => { + self.expected_found_str(&exp_found.map(|t| t.print_without_self())) + } } } diff --git a/src/librustc/infer/error_reporting/skol_conflict.rs b/src/librustc/infer/error_reporting/skol_conflict.rs new file mode 100644 index 0000000000000..43aad8eddb91e --- /dev/null +++ b/src/librustc/infer/error_reporting/skol_conflict.rs @@ -0,0 +1,54 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error Reporting for Anonymous Region Lifetime Errors +//! where both the regions are anonymous. +use infer::InferCtxt; +use ty; +use ty::error::TypeError; +use infer; +use infer::region_inference::RegionResolutionError::*; +use infer::region_inference::RegionResolutionError; + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + pub fn try_report_skol_conflict(&self, error: &RegionResolutionError<'tcx>) -> bool { + let (origin, sub, sup) = match *error { + ConcreteFailure(ref origin, sub, sup) if sub.is_skolemized() => + (origin, sub, sup), + ConcreteFailure(ref origin, sub, sup) if sup.is_skolemized() => + (origin, sub, sup), + SubSupConflict(_, ref sub_origin, sub, _, sup) if sub.is_skolemized() => + (sub_origin, sub, sup), + SubSupConflict(_, _, sub, ref sup_origin, sup) if sup.is_skolemized() => + (sup_origin, sub, sup), + _ => + return false, // inapplicable + }; + + match *origin { + infer::Subtype(ref trace) => { + // FIXME This is bogus: we can't really tell from this + // information whether it is "overly" polymorphic or what. We + // should change how this error is reported altogether. But it + // will do for now. + let terr = match (sub, sup) { + (&ty::ReSkolemized(_, br_sub), r) => + TypeError::RegionsInsufficientlyPolymorphic(br_sub, r), + (r, &ty::ReSkolemized(_, br_sup)) => + TypeError::RegionsInsufficientlyPolymorphic(br_sup, r), + _ => span_bug!(origin.span(), "at least one side must be skolemized") + }; + self.report_and_explain_type_error(trace.clone(), &terr).emit(); + true + } + _ => false, + } + } +} diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 41e7dffe54dc1..a5b486027c659 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -199,6 +199,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { // replace all free regions with 'erased self.tcx().types.re_erased } + + ty::ReCanonical(..) => { + bug!("encountered canonical region during type-freshening") + } } } @@ -212,7 +216,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { match t.sty { ty::TyInfer(ty::TyVar(v)) => { - let opt_ty = self.infcx.type_variables.borrow_mut().probe(v); + let opt_ty = self.infcx.type_variables.borrow_mut().probe(v).known(); self.freshen( opt_ty, ty::TyVar(v), @@ -222,7 +226,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(v)) => { self.freshen( self.infcx.int_unification_table.borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(tcx)), ty::IntVar(v), ty::FreshIntTy) @@ -231,7 +235,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInfer(ty::FloatVar(v)) => { self.freshen( self.infcx.float_unification_table.borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(tcx)), ty::FloatVar(v), ty::FreshFloatTy) @@ -249,6 +253,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { t } + ty::TyInfer(ty::CanonicalTy(..)) => + bug!("encountered canonical ty during freshening"), + ty::TyClosure(def_id, substs) => { self.freshen_closure_like( def_id, substs, t, diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 9cad6ce6f9fad..f8ed373f72d9c 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -131,7 +131,9 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { // 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()); + debug_assert!(self.infcx.type_variables.borrow_mut() + .probe(vid) + .is_unknown()); ty } @@ -139,7 +141,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { // This variable was created during the // fudging. Recreate it with a fresh variable // here. - self.infcx.next_ty_var(origin) + // + // The ROOT universe is fine because we only + // ever invoke this routine at the + // "item-level" of inference. + self.infcx.next_ty_var(ty::UniverseIndex::ROOT, origin) } } } @@ -150,7 +156,11 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReVar(v) if self.region_vars.contains(&v) => { - self.infcx.next_region_var(self.origin.clone()) + // FIXME -- I am not entirely sure how fudging and + // universes should work, but using root is a + // conservative choice here, and I suspect it doesn't + // much matter. + self.infcx.next_region_var(ty::UniverseIndex::ROOT, self.origin.clone()) } _ => { r diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index d7afeba7dc96b..78240f25e84d6 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -21,13 +21,16 @@ use ty::relate::{Relate, RelateResult, TypeRelation}; pub struct Glb<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, + param_env: ty::ParamEnv<'tcx>, } impl<'combine, 'infcx, 'gcx, 'tcx> Glb<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Glb<'combine, 'infcx, 'gcx, 'tcx> + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Glb<'combine, 'infcx, 'gcx, 'tcx> { - Glb { fields: fields, a_is_expected: a_is_expected } + Glb { fields, a_is_expected, param_env } } } @@ -47,11 +50,11 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), + ty::Invariant => self.fields.equate(self.param_env, self.a_is_expected).relate(a, b), ty::Covariant => self.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), + ty::Contravariant => self.fields.lub(self.param_env, self.a_is_expected).relate(a, b), } } @@ -67,14 +70,14 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> b); let origin = Subtype(self.fields.trace.clone()); - Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b)) + Ok(self.fields.infcx.region_vars.glb_regions(origin, self.param_env, a, b)) } fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> RelateResult<'tcx, ty::Binder<T>> where T: Relate<'tcx> { - self.fields.higher_ranked_glb(a, b, self.a_is_expected) + self.fields.higher_ranked_glb(self.param_env, a, b, self.a_is_expected) } } @@ -90,7 +93,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> } fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(self.a_is_expected); + let mut sub = self.fields.sub(self.param_env, self.a_is_expected); sub.relate(&v, &a)?; sub.relate(&v, &b)?; Ok(()) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 6736751a5a2c2..59b13fb25acce 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -14,23 +14,23 @@ use super::{CombinedSnapshot, InferCtxt, HigherRankedType, - SubregionOrigin, SkolemizationMap}; use super::combine::CombineFields; -use super::region_inference::{TaintDirections}; +use super::region_inference::taint::TaintIterator; +use traits; use ty::{self, TyCtxt, Binder, TypeFoldable}; -use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; +use std::usize; use syntax_pos::Span; use util::nodemap::{FxHashMap, FxHashSet}; -pub struct HrMatchResult<U> { - pub value: U, -} - impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { - pub fn higher_ranked_sub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool) + pub fn higher_ranked_sub<T>(&mut self, + param_env: ty::ParamEnv<'tcx>, + a: &Binder<T>, + b: &Binder<T>, + a_is_expected: bool) -> RelateResult<'tcx, Binder<T>> where T: Relate<'tcx> { @@ -47,35 +47,28 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { + return self.infcx.commit_if_ok(|_snapshot| { let span = self.trace.cause.span; - // First, we instantiate each bound region in the subtype with a fresh - // region variable. + // First, we instantiate each bound region in the supertype with a + // fresh concrete region. + let (b_prime, param_env, _skol_map) = + self.infcx.skolemize_late_bound_regions(param_env, b); + + // Second, we instantiate each bound region in the subtype with a fresh + // region variable. These are declared in the innermost universe. let (a_prime, _) = self.infcx.replace_late_bound_regions_with_fresh_var( span, + param_env.universe, HigherRankedType, a); - // Second, we instantiate each bound region in the supertype with a - // fresh concrete region. - let (b_prime, skol_map) = - self.infcx.skolemize_late_bound_regions(b, snapshot); - debug!("a_prime={:?}", a_prime); debug!("b_prime={:?}", b_prime); // Compare types now that bound regions have been replaced. - let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; - - // Presuming type comparison succeeds, we need to check - // that the skolemized regions do not "leak". - self.infcx.leak_check(!a_is_expected, span, &skol_map, snapshot)?; - - // We are finished with the skolemized regions now so pop - // them off. - self.infcx.pop_skolemized(skol_map, snapshot); + let result = self.sub(param_env, a_is_expected).relate(&a_prime, &b_prime)?; debug!("higher_ranked_sub: OK result={:?}", result); @@ -83,123 +76,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { }); } - /// The value consists of a pair `(t, u)` where `t` is the - /// *matcher* and `u` is a *value*. The idea is to find a - /// substitution `S` such that `S(t) == b`, and then return - /// `S(u)`. In other words, find values for the late-bound regions - /// in `a` that can make `t == b` and then replace the LBR in `u` - /// with those values. - /// - /// This routine is (as of this writing) used in trait matching, - /// particularly projection. - /// - /// NB. It should not happen that there are LBR appearing in `U` - /// that do not appear in `T`. If that happens, those regions are - /// unconstrained, and this routine replaces them with `'static`. - pub fn higher_ranked_match<T, U>(&mut self, - a_pair: &Binder<(T, U)>, - b_match: &T, - a_is_expected: bool) - -> RelateResult<'tcx, HrMatchResult<U>> - where T: Relate<'tcx>, - U: TypeFoldable<'tcx> - { - debug!("higher_ranked_match(a={:?}, b={:?})", - a_pair, b_match); - - // Start a snapshot so we can examine "all bindings that were - // created as part of this type comparison". - return self.infcx.commit_if_ok(|snapshot| { - // First, we instantiate each bound region in the matcher - // with a skolemized region. - let ((a_match, a_value), skol_map) = - self.infcx.skolemize_late_bound_regions(a_pair, snapshot); - - debug!("higher_ranked_match: a_match={:?}", a_match); - debug!("higher_ranked_match: skol_map={:?}", skol_map); - - // Equate types now that bound regions have been replaced. - self.equate(a_is_expected).relate(&a_match, &b_match)?; - - // Map each skolemized region to a vector of other regions that it - // must be equated with. (Note that this vector may include other - // skolemized regions from `skol_map`.) - let skol_resolution_map: FxHashMap<_, _> = - skol_map - .iter() - .map(|(&br, &skol)| { - let tainted_regions = - self.infcx.tainted_regions(snapshot, - skol, - TaintDirections::incoming()); // [1] - - // [1] this routine executes after the skolemized - // regions have been *equated* with something - // else, so examining the incoming edges ought to - // be enough to collect all constraints - - (skol, (br, tainted_regions)) - }) - .collect(); - - // For each skolemized region, pick a representative -- which can - // be any region from the sets above, except for other members of - // `skol_map`. There should always be a representative if things - // are properly well-formed. - let skol_representatives: FxHashMap<_, _> = - skol_resolution_map - .iter() - .map(|(&skol, &(_, ref regions))| { - let representative = - regions.iter() - .filter(|&&r| !skol_resolution_map.contains_key(r)) - .cloned() - .next() - .unwrap_or_else(|| { - bug!("no representative region for `{:?}` in `{:?}`", - skol, regions) - }); - - (skol, representative) - }) - .collect(); - - // Equate all the members of each skolemization set with the - // representative. - for (skol, &(_br, ref regions)) in &skol_resolution_map { - let representative = &skol_representatives[skol]; - debug!("higher_ranked_match: \ - skol={:?} representative={:?} regions={:?}", - skol, representative, regions); - for region in regions.iter() - .filter(|&r| !skol_resolution_map.contains_key(r)) - .filter(|&r| r != representative) - { - let origin = SubregionOrigin::Subtype(self.trace.clone()); - self.infcx.region_vars.make_eqregion(origin, - *representative, - *region); - } - } - - // Replace the skolemized regions appearing in value with - // their representatives - let a_value = - fold_regions_in( - self.tcx(), - &a_value, - |r, _| skol_representatives.get(&r).cloned().unwrap_or(r)); - - debug!("higher_ranked_match: value={:?}", a_value); - - // We are now done with these skolemized variables. - self.infcx.pop_skolemized(skol_map, snapshot); - - Ok(HrMatchResult { value: a_value }) - }); - } - - pub fn higher_ranked_lub<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool) + pub fn higher_ranked_lub<T>(&mut self, + param_env: ty::ParamEnv<'tcx>, + a: &Binder<T>, + b: &Binder<T>, + a_is_expected: bool) -> RelateResult<'tcx, Binder<T>> where T: Relate<'tcx> { @@ -210,14 +91,14 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { let span = self.trace.cause.span; let (a_with_fresh, a_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, a); + span, param_env.universe, HigherRankedType, a); let (b_with_fresh, _) = self.infcx.replace_late_bound_regions_with_fresh_var( - span, HigherRankedType, b); + span, param_env.universe, HigherRankedType, b); // Collect constraints. let result0 = - self.lub(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; + self.lub(param_env, a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; let result0 = self.infcx.resolve_type_vars_if_possible(&result0); debug!("lub result0 = {:?}", result0); @@ -229,7 +110,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fold_regions_in( self.tcx(), &result0, - |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, + |r, debruijn| generalize_region(self.infcx, span, snapshot, param_env, debruijn, &new_vars, &a_map, r)); debug!("lub({:?},{:?}) = {:?}", @@ -242,7 +123,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - snapshot: &CombinedSnapshot, + snapshot: &CombinedSnapshot<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, @@ -255,33 +137,39 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { return r0; } - let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both()); - - // Variables created during LUB computation which are - // *related* to regions that pre-date the LUB computation - // stay as they are. - if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) { - debug!("generalize_region(r0={:?}): \ - non-new-variables found in {:?}", - r0, tainted); - assert!(!r0.is_late_bound()); - return r0; - } + let mut best_index = usize::MAX; - // Otherwise, the variable must be associated with at - // least one of the variables representing bound regions - // in both A and B. Replace the variable with the "first" - // bound region from A that we find it to be associated - // with. - for (a_br, a_r) in a_map { - if tainted.iter().any(|x| x == a_r) { + for r in infcx.tainted_regions(snapshot, param_env, r0) { + // Variables created during LUB computation which are + // *related* to regions that pre-date the LUB computation + // stay as they are. + if !is_var_in_set(new_vars, r) { debug!("generalize_region(r0={:?}): \ - replacing with {:?}, tainted={:?}", - r0, *a_br, tainted); - return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br)); + non-new-variable `{:?}` found in taint regions", + r0, r); + assert!(!r0.is_late_bound()); + return r0; + } + + // Otherwise, the variable must be associated with at + // least one of the variables representing bound regions + // in both A and B. Replace the variable with the "first" + // bound region from A that we find it to be associated + // with. + for (index, (_, &a_r)) in a_map.iter().enumerate() { + if r == a_r && index < best_index { + best_index = index; + } } } + for (a_br, a_r) in a_map.iter().skip(best_index) { + debug!("generalize_region(r0={:?}): \ + replacing with {:?}, tainted={:?}", + r0, *a_br, a_r); + return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br)); + } + span_bug!( span, "region {:?} is not associated with any bound region from A!", @@ -289,7 +177,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } } - pub fn higher_ranked_glb<T>(&mut self, a: &Binder<T>, b: &Binder<T>, a_is_expected: bool) + pub fn higher_ranked_glb<T>(&mut self, + param_env: ty::ParamEnv<'tcx>, + a: &Binder<T>, + b: &Binder<T>, + a_is_expected: bool) -> RelateResult<'tcx, Binder<T>> where T: Relate<'tcx> { @@ -302,16 +194,16 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.cause.span, HigherRankedType, a); + self.trace.cause.span, param_env.universe, HigherRankedType, a); let (b_with_fresh, b_map) = self.infcx.replace_late_bound_regions_with_fresh_var( - self.trace.cause.span, HigherRankedType, b); + self.trace.cause.span, param_env.universe, HigherRankedType, b); let a_vars = var_ids(self, &a_map); let b_vars = var_ids(self, &b_map); // Collect constraints. let result0 = - self.glb(a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; + self.glb(param_env, a_is_expected).relate(&a_with_fresh, &b_with_fresh)?; let result0 = self.infcx.resolve_type_vars_if_possible(&result0); debug!("glb result0 = {:?}", result0); @@ -323,8 +215,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fold_regions_in( self.tcx(), &result0, - |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, - &new_vars, + |r, debruijn| generalize_region(self.infcx, span, snapshot, param_env, + debruijn, &new_vars, &a_map, &a_vars, &b_vars, r)); @@ -338,7 +230,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - snapshot: &CombinedSnapshot, + snapshot: &CombinedSnapshot<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], a_map: &FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, @@ -351,25 +244,24 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { return r0; } - let tainted = infcx.tainted_regions(snapshot, r0, TaintDirections::both()); - let mut a_r = None; let mut b_r = None; let mut only_new_vars = true; - for r in &tainted { - if is_var_in_set(a_vars, *r) { + + for r in infcx.tainted_regions(snapshot, param_env, r0) { + if is_var_in_set(a_vars, r) { if a_r.is_some() { return fresh_bound_variable(infcx, debruijn); } else { - a_r = Some(*r); + a_r = Some(r); } - } else if is_var_in_set(b_vars, *r) { + } else if is_var_in_set(b_vars, r) { if b_r.is_some() { return fresh_bound_variable(infcx, debruijn); } else { - b_r = Some(*r); + b_r = Some(r); } - } else if !is_var_in_set(new_vars, *r) { + } else if !is_var_in_set(new_vars, r) { only_new_vars = false; } } @@ -476,16 +368,16 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn tainted_regions(&self, - snapshot: &CombinedSnapshot, - r: ty::Region<'tcx>, - directions: TaintDirections) - -> FxHashSet<ty::Region<'tcx>> { - self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions) + fn tainted_regions<'this>(&'this self, + snapshot: &CombinedSnapshot<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + r: ty::Region<'tcx>) + -> TaintIterator<'this, 'gcx, 'tcx> { + self.region_vars.tainted(&snapshot.region_vars_snapshot, param_env, r) } fn region_vars_confined_to_snapshot(&self, - snapshot: &CombinedSnapshot) + snapshot: &CombinedSnapshot<'a, 'tcx>) -> Vec<ty::RegionVid> { /*! @@ -566,22 +458,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// skolemized region. This is the first step of checking subtyping /// when higher-ranked things are involved. /// - /// **Important:** you must call this function from within a snapshot. - /// Moreover, before committing the snapshot, you must eventually call - /// either `plug_leaks` or `pop_skolemized` to remove the skolemized - /// regions. If you rollback the snapshot (or are using a probe), then - /// the pop occurs as part of the rollback, so an explicit call is not - /// needed (but is also permitted). - /// /// See `README.md` for more details. pub fn skolemize_late_bound_regions<T>(&self, - binder: &ty::Binder<T>, - snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap<'tcx>) + mut param_env: ty::ParamEnv<'tcx>, + binder: &ty::Binder<T>) + -> (T, ty::ParamEnv<'tcx>, SkolemizationMap<'tcx>) where T : TypeFoldable<'tcx> { let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { - self.region_vars.push_skolemized(br, &snapshot.region_vars_snapshot) + let (p, value) = self.tcx.mk_skolemized_region(param_env, br); + param_env = p; + value }); debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})", @@ -589,187 +476,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result, map); - (result, map) + (result, param_env, map) } - /// Searches the region constraints created since `snapshot` was started - /// and checks to determine whether any of the skolemized regions created - /// in `skol_map` would "escape" -- meaning that they are related to - /// other regions in some way. If so, the higher-ranked subtyping doesn't - /// hold. See `README.md` for more details. - pub fn leak_check(&self, - overly_polymorphic: bool, - _span: Span, - skol_map: &SkolemizationMap<'tcx>, - snapshot: &CombinedSnapshot) - -> RelateResult<'tcx, ()> + /// Given a predicate obligation, which may include binders, + /// convert into the underlying predicate atom obligation, which + /// may be in another universe (if binders were present). + pub fn skolemize_predicate_obligation(&self, obligation: &traits::PredicateObligation<'tcx>) + -> traits::PredicateAtomObligation<'tcx> { - debug!("leak_check: skol_map={:?}", - skol_map); - - let new_vars = self.region_vars_confined_to_snapshot(snapshot); - for (&skol_br, &skol) in skol_map { - // The inputs to a skolemized variable can only - // be itself or other new variables. - let incoming_taints = self.tainted_regions(snapshot, - skol, - TaintDirections::both()); - for &tainted_region in &incoming_taints { - // Each skolemized should only be relatable to itself - // or new variables: - match *tainted_region { - ty::ReVar(vid) => { - if new_vars.contains(&vid) { - continue; - } - } - _ => { - if tainted_region == skol { continue; } - } - }; - - debug!("{:?} (which replaced {:?}) is tainted by {:?}", - skol, - skol_br, - tainted_region); - - return Err(if overly_polymorphic { - debug!("Overly polymorphic!"); - TypeError::RegionsOverlyPolymorphic(skol_br, tainted_region) - } else { - debug!("Not as polymorphic!"); - TypeError::RegionsInsufficientlyPolymorphic(skol_br, tainted_region) - }) + match obligation.predicate { + ty::Predicate::Poly(ref binder) => { + let (atom, param_env, _skol_map) = + self.skolemize_late_bound_regions(obligation.param_env, binder); + obligation.with(atom).with_env(param_env) } - } - - Ok(()) - } - /// This code converts from skolemized regions back to late-bound - /// regions. It works by replacing each region in the taint set of a - /// skolemized region with a bound-region. The bound region will be bound - /// by the outer-most binder in `value`; the caller must ensure that there is - /// such a binder and it is the right place. - /// - /// This routine is only intended to be used when the leak-check has - /// passed; currently, it's used in the trait matching code to create - /// a set of nested obligations frmo an impl that matches against - /// something higher-ranked. More details can be found in - /// `librustc/middle/traits/README.md`. - /// - /// As a brief example, consider the obligation `for<'a> Fn(&'a int) - /// -> &'a int`, and the impl: - /// - /// impl<A,R> Fn<A,R> for SomethingOrOther - /// where A : Clone - /// { ... } - /// - /// Here we will have replaced `'a` with a skolemized region - /// `'0`. This means that our substitution will be `{A=>&'0 - /// int, R=>&'0 int}`. - /// - /// When we apply the substitution to the bounds, we will wind up with - /// `&'0 int : Clone` as a predicate. As a last step, we then go and - /// replace `'0` with a late-bound region `'a`. The depth is matched - /// to the depth of the predicate, in this case 1, so that the final - /// predicate is `for<'a> &'a int : Clone`. - pub fn plug_leaks<T>(&self, - skol_map: SkolemizationMap<'tcx>, - snapshot: &CombinedSnapshot, - value: T) -> T - where T : TypeFoldable<'tcx> - { - debug!("plug_leaks(skol_map={:?}, value={:?})", - skol_map, - value); - - if skol_map.is_empty() { - return value; - } - - // Compute a mapping from the "taint set" of each skolemized - // region back to the `ty::BoundRegion` that it originally - // represented. Because `leak_check` passed, we know that - // these taint sets are mutually disjoint. - let inv_skol_map: FxHashMap<ty::Region<'tcx>, ty::BoundRegion> = - skol_map - .iter() - .flat_map(|(&skol_br, &skol)| { - self.tainted_regions(snapshot, skol, TaintDirections::both()) - .into_iter() - .map(move |tainted_region| (tainted_region, skol_br)) - }) - .collect(); - - debug!("plug_leaks: inv_skol_map={:?}", - inv_skol_map); - - // Remove any instantiated type variables from `value`; those can hide - // references to regions from the `fold_regions` code below. - let value = self.resolve_type_vars_if_possible(&value); - - // Map any skolemization byproducts back to a late-bound - // region. Put that late-bound region at whatever the outermost - // binder is that we encountered in `value`. The caller is - // responsible for ensuring that (a) `value` contains at least one - // binder and (b) that binder is the one we want to use. - let result = self.tcx.fold_regions(&value, &mut false, |r, current_depth| { - match inv_skol_map.get(&r) { - None => r, - Some(br) => { - // It is the responsibility of the caller to ensure - // that each skolemized region appears within a - // binder. In practice, this routine is only used by - // trait checking, and all of the skolemized regions - // appear inside predicates, which always have - // binders, so this assert is satisfied. - assert!(current_depth > 1); - - // since leak-check passed, this skolemized region - // should only have incoming edges from variables - // (which ought not to escape the snapshot, but we - // don't check that) or itself - assert!( - match *r { - ty::ReVar(_) => true, - ty::ReSkolemized(_, ref br1) => br == br1, - _ => false, - }, - "leak-check would have us replace {:?} with {:?}", - r, br); - - self.tcx.mk_region(ty::ReLateBound( - ty::DebruijnIndex::new(current_depth - 1), br.clone())) - } + ty::Predicate::Atom(atom) => { + obligation.with(atom) } - }); - - self.pop_skolemized(skol_map, snapshot); - - debug!("plug_leaks: result={:?}", result); - - result - } - - /// Pops the skolemized regions found in `skol_map` from the region - /// inference context. Whenever you create skolemized regions via - /// `skolemize_late_bound_regions`, they must be popped before you - /// commit the enclosing snapshot (if you do not commit, e.g. within a - /// probe or as a result of an error, then this is not necessary, as - /// popping happens as part of the rollback). - /// - /// Note: popping also occurs implicitly as part of `leak_check`. - pub fn pop_skolemized(&self, - skol_map: SkolemizationMap<'tcx>, - snapshot: &CombinedSnapshot) - { - debug!("pop_skolemized({:?})", skol_map); - let skol_regions: FxHashSet<_> = skol_map.values().cloned().collect(); - self.region_vars.pop_skolemized(&skol_regions, &snapshot.region_vars_snapshot); - if !skol_map.is_empty() { - self.projection_cache.borrow_mut().rollback_skolemized( - &snapshot.projection_cache_snapshot); } } } diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index d5c1163cfc1b1..c4722f9a7f96c 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -70,14 +70,6 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, 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(..)), &ty::TyInfer(TyVar(..))) - if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => { - let v = infcx.next_diverging_ty_var( - TypeVariableOrigin::LatticeVariable(this.cause().span)); - this.relate_bound(v, a, b)?; - Ok(v) - } - // 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 @@ -96,13 +88,17 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, // is (e.g.) `Box<i32>`. 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)); + (&ty::TyInfer(TyVar(a_vid)), _) => { + let universe = infcx.type_variables.borrow_mut().probe(a_vid).universe().unwrap(); + let v = infcx.next_ty_var(universe, + 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)); + (_, &ty::TyInfer(TyVar(b_vid))) => { + let universe = infcx.type_variables.borrow_mut().probe(b_vid).universe().unwrap(); + let v = infcx.next_ty_var(universe, + TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; Ok(v) } diff --git a/src/librustc/infer/lib.rs b/src/librustc/infer/lib.rs new file mode 100644 index 0000000000000..0689e37632d0e --- /dev/null +++ b/src/librustc/infer/lib.rs @@ -0,0 +1,108 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! New recursive solver modeled on Chalk's recursive solver. Most of +//! the guts are broken up into modules; see the comments in those modules. + +#![feature(match_default_bindings)] +#![feature(underscore_lifetimes)] + +#[macro_use] extern crate log; +#[macro_use] extern crate rustc; +extern crate rustc_data_structures; + +use rustc::infer::InferCtxt; +use rustc::ty::{self, CanonicalVar}; +use rustc_data_structures::fx::FxHashMap; +use std::collections::BTreeMap; + +mod canonical; +use self::canonical::{Canonical, CanonicalVarValue}; + +mod fallible; +use self::fallible::Fallible; + +mod search_graph; +use self::search_graph::{DepthFirstNumber, SearchGraph}; + +mod stack; +use self::stack::Stack; + +/// A Solver is the basic context in which you can propose goals for a given +/// program. **All questions posed to the solver are in canonical, closed form, +/// so that each question is answered with effectively a "clean slate"**. This +/// allows for better caching, and simplifies management of the inference +/// context. +pub struct Solver<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + stack: Stack, + search_graph: SearchGraph<'tcx>, + + caching_enabled: bool, + + /// The cache contains **fully solved** goals, whose results are + /// not dependent on the stack in anyway. + cache: FxHashMap<PredicateAtomGoal<'tcx>, Fallible<Solution<'tcx>>>, +} + +/// Internally to the solver, a `Goal` is used to mean something we +/// are trying to prove. It is like an obligation, but stripped of +/// the `cause`. +struct Goal<'tcx, G> { + param_env: ty::ParamEnv<'tcx>, + goal: G, +} + +/// The main top-line goals we try to prove. +type PredicateAtomGoal<'tcx> = Goal<'tcx, ty::PredicateAtom<'tcx>>; + +/// The `minimums` struct is used while solving to track whether we encountered +/// any cycles in the process. +#[derive(Copy, Clone, Debug)] +struct Minimums { + positive: DepthFirstNumber, +} + +impl Minimums { + fn new() -> Self { + Minimums { + positive: DepthFirstNumber::MAX, + } + } + + fn update_from(&mut self, minimums: Minimums) { + self.positive = ::std::cmp::min(self.positive, minimums.positive); + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +enum Solution<'tcx> { + Ambiguous, + Unique(Canonical<ConstrainedCanonicalVarSubstitution<'tcx>>), +} + +/// Combines a `CanonicalVarSubstitution` with region predicates. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +struct ConstrainedCanonicalVarSubstitution<'tcx> { + pub subst: CanonicalVarSubstitution<'tcx>, + // TODO pub constraints: Vec<InEnvironment<Constraint>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +struct CanonicalVarSubstitution<'tcx> { + /// Map free variable with given index to the value with the same + /// index. Naturally, the kind of the variable must agree with + /// the kind of the value. + /// + /// This is a map because the substitution is not necessarily + /// complete. We use a btree map to ensure that the result is in a + /// deterministic order. + pub parameters: BTreeMap<CanonicalVar, CanonicalVarValue<'tcx>>, +} diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 04b470b29fc5e..c017d52a49d35 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -21,13 +21,16 @@ use ty::relate::{Relate, RelateResult, TypeRelation}; pub struct Lub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, + param_env: ty::ParamEnv<'tcx>, } impl<'combine, 'infcx, 'gcx, 'tcx> Lub<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Lub<'combine, 'infcx, 'gcx, 'tcx> + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Lub<'combine, 'infcx, 'gcx, 'tcx> { - Lub { fields: fields, a_is_expected: a_is_expected } + Lub { fields, a_is_expected, param_env } } } @@ -47,11 +50,11 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), + ty::Invariant => self.fields.equate(self.param_env, self.a_is_expected).relate(a, b), ty::Covariant => self.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), + ty::Contravariant => self.fields.glb(self.param_env, self.a_is_expected).relate(a, b), } } @@ -67,14 +70,14 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> b); let origin = Subtype(self.fields.trace.clone()); - Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b)) + Ok(self.fields.infcx.region_vars.lub_regions(origin, self.param_env, a, b)) } fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>) -> RelateResult<'tcx, ty::Binder<T>> where T: Relate<'tcx> { - self.fields.higher_ranked_lub(a, b, self.a_is_expected) + self.fields.higher_ranked_lub(self.param_env, a, b, self.a_is_expected) } } @@ -90,7 +93,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> LatticeDir<'infcx, 'gcx, 'tcx> } fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(self.a_is_expected); + let mut sub = self.fields.sub(self.param_env, self.a_is_expected); sub.relate(&a, &v)?; sub.relate(&b, &v)?; Ok(()) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 79eeebfb25031..1ac53cac54c9a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -13,7 +13,6 @@ pub use self::LateBoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; -pub use self::ValuePairs::*; pub use ty::IntVarValue; pub use self::freshen::TypeFreshener; pub use self::region_inference::{GenericKind, VerifyBound}; @@ -23,14 +22,14 @@ use middle::free_region::{FreeRegionMap, RegionRelations}; use middle::region; use middle::lang_items; use mir::tcx::LvalueTy; -use ty::subst::{Kind, Subst, Substs}; +use ty::subst::{Substs}; use ty::{TyVid, IntVid, FloatVid}; use ty::{self, Ty, TyCtxt}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; -use rustc_data_structures::unify::{self, UnificationTable}; +use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref}; use std::fmt; use syntax::ast; @@ -40,12 +39,12 @@ use util::nodemap::FxHashMap; use arena::DroplessArena; use self::combine::CombineFields; -use self::higher_ranked::HrMatchResult; use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; pub mod at; +pub mod canonical; mod combine; mod equate; pub mod error_reporting; @@ -93,10 +92,10 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub type_variables: RefCell<type_variable::TypeVariableTable<'tcx>>, // Map from integral variable to the kind of integer it represents - int_unification_table: RefCell<UnificationTable<ty::IntVid>>, + int_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::IntVid>>>, // Map from floating variable to the kind of float it represents - float_unification_table: RefCell<UnificationTable<ty::FloatVid>>, + float_unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::FloatVid>>>, // For region variables. region_vars: RegionVarBindings<'a, 'gcx, 'tcx>, @@ -110,7 +109,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // the set of predicates on which errors have been reported, to // avoid reporting the same error twice. - pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>, + pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::PredicateAtom<'tcx>>>>, // When an error occurs, we want to avoid reporting "derived" // errors that are due to this original failure. Normally, we @@ -145,6 +144,7 @@ pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, ty::Region<'tcx>>; #[derive(Clone, Debug)] pub enum ValuePairs<'tcx> { Types(ExpectedFound<Ty<'tcx>>), + ProjectionTypes(ExpectedFound<ty::ProjectionTy<'tcx>>), TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), } @@ -377,8 +377,8 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { in_progress_tables, projection_cache: RefCell::new(traits::ProjectionCache::new()), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - int_unification_table: RefCell::new(UnificationTable::new()), - float_unification_table: RefCell::new(UnificationTable::new()), + int_unification_table: RefCell::new(ut::UnificationTable::new()), + float_unification_table: RefCell::new(ut::UnificationTable::new()), region_vars: RegionVarBindings::new(tcx), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), @@ -398,6 +398,15 @@ impl<T> ExpectedFound<T> { ExpectedFound {expected: b, found: a} } } + + pub fn map<OP, R>(self, mut op: OP) -> ExpectedFound<R> + where OP: FnMut(T) -> R + { + ExpectedFound { + expected: op(self.expected), + found: op(self.found), + } + } } impl<'tcx, T> InferOk<'tcx, T> { @@ -409,9 +418,9 @@ impl<'tcx, T> InferOk<'tcx, T> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx:'a> { projection_cache_snapshot: traits::ProjectionCacheSnapshot, - type_snapshot: type_variable::Snapshot, - int_snapshot: unify::Snapshot<ty::IntVid>, - float_snapshot: unify::Snapshot<ty::FloatVid>, + type_snapshot: type_variable::Snapshot<'tcx>, + int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>, + float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>, region_vars_snapshot: RegionSnapshot, was_in_snapshot: bool, _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>, @@ -611,14 +620,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { use ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; match ty.sty { ty::TyInfer(ty::IntVar(vid)) => { - if self.int_unification_table.borrow_mut().has_value(vid) { + if self.int_unification_table.borrow_mut().probe_value(vid).is_some() { Neither } else { UnconstrainedInt } }, ty::TyInfer(ty::FloatVar(vid)) => { - if self.float_unification_table.borrow_mut().has_value(vid) { + if self.float_unification_table.borrow_mut().probe_value(vid).is_some() { Neither } else { UnconstrainedFloat @@ -628,57 +637,45 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - /// Returns a type variable's default fallback if any exists. A default - /// must be attached to the variable when created, if it is created - /// without a default, this will return None. - /// - /// This code does not apply to integral or floating point variables, - /// only to use declared defaults. - /// - /// See `new_ty_var_with_default` to create a type variable with a default. - /// See `type_variable::Default` for details about what a default entails. - pub fn default(&self, ty: Ty<'tcx>) -> Option<type_variable::Default<'tcx>> { - match ty.sty { - ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().default(vid), - _ => None - } - } - pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> { let mut variables = Vec::new(); - let unbound_ty_vars = self.type_variables - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|t| self.tcx.mk_var(t)); - - let unbound_int_vars = self.int_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_int_var(v)); + { + let mut type_variables = self.type_variables.borrow_mut(); + variables.extend( + type_variables + .unsolved_variables() + .into_iter() + .map(|t| self.tcx.mk_var(t))); + } - let unbound_float_vars = self.float_unification_table - .borrow_mut() - .unsolved_variables() - .into_iter() - .map(|v| self.tcx.mk_float_var(v)); + { + let mut int_unification_table = self.int_unification_table.borrow_mut(); + variables.extend( + (0..int_unification_table.len()) + .map(|i| ty::IntVid { index: i as u32 }) + .filter(|&vid| int_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_int_var(v))); + } - variables.extend(unbound_ty_vars); - variables.extend(unbound_int_vars); - variables.extend(unbound_float_vars); + { + let mut float_unification_table = self.float_unification_table.borrow_mut(); + variables.extend( + (0..float_unification_table.len()) + .map(|i| ty::FloatVid { index: i as u32 }) + .filter(|&vid| float_unification_table.probe_value(vid).is_none()) + .map(|v| self.tcx.mk_float_var(v))); + } return variables; } - fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>) + fn combine_fields(&'a self, trace: TypeTrace<'tcx>) -> CombineFields<'a, 'gcx, 'tcx> { CombineFields { infcx: self, trace, cause: None, - param_env, obligations: PredicateObligations::new(), } } @@ -709,7 +706,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result } - fn start_snapshot<'b>(&'b self) -> CombinedSnapshot<'b, 'tcx> { + fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> { debug!("start_snapshot()"); let in_snapshot = self.in_snapshot.get(); @@ -730,7 +727,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot) { + fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); let CombinedSnapshot { projection_cache_snapshot, type_snapshot, @@ -758,7 +755,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .rollback_to(region_vars_snapshot); } - fn commit_from(&self, snapshot: CombinedSnapshot) { + fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); let CombinedSnapshot { projection_cache_snapshot, type_snapshot, @@ -799,7 +796,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)` pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where - F: FnOnce(&CombinedSnapshot) -> Result<T, E> + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E> { debug!("commit_if_ok()"); let snapshot = self.start_snapshot(); @@ -814,7 +811,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Execute `f` in a snapshot, and commit the bindings it creates pub fn in_snapshot<T, F>(&self, f: F) -> T where - F: FnOnce(&CombinedSnapshot) -> T + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> T { debug!("in_snapshot()"); let snapshot = self.start_snapshot(); @@ -825,7 +822,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Execute `f` then unroll any bindings it creates pub fn probe<R, F>(&self, f: F) -> R where - F: FnOnce(&CombinedSnapshot) -> R, + F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, { debug!("probe()"); let snapshot = self.start_snapshot(); @@ -875,33 +872,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_regions(&self, origin: SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>) { debug!("sub_regions({:?} <: {:?})", a, b); - self.region_vars.make_subregion(origin, a, b); - } - - pub fn equality_predicate(&self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: &ty::PolyEquatePredicate<'tcx>) - -> InferResult<'tcx, ()> - { - self.commit_if_ok(|snapshot| { - let (ty::EquatePredicate(a, b), skol_map) = - self.skolemize_late_bound_regions(predicate, snapshot); - let cause_span = cause.span; - let eqty_ok = self.at(cause, param_env).eq(b, a)?; - self.leak_check(false, cause_span, &skol_map, snapshot)?; - self.pop_skolemized(skol_map, snapshot); - Ok(eqty_ok.unit()) - }) + self.region_vars.make_subregion(origin, param_env, a, b); } pub fn subtype_predicate(&self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - predicate: &ty::PolySubtypePredicate<'tcx>) + predicate: ty::SubtypePredicate<'tcx>) -> Option<InferResult<'tcx, ()>> { // Subtle: it's ok to skip the binder here and resolve because @@ -914,8 +895,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // 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); + let a = self.shallow_resolve(predicate.a); + let b = self.shallow_resolve(predicate.b); a.is_ty_var() && b.is_ty_var() }; @@ -924,47 +905,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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; + Some(self.commit_if_ok(|_snapshot| { + let ty::SubtypePredicate { a_is_expected, a, b} = predicate; let ok = self.at(cause, param_env).sub_exp(a_is_expected, 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>) - -> UnitResult<'tcx> + param_env: ty::ParamEnv<'tcx>, + predicate: ty::RegionOutlivesPredicate<'tcx>) + -> UnitResult<'tcx> { - self.commit_if_ok(|snapshot| { - let (ty::OutlivesPredicate(r_a, r_b), skol_map) = - self.skolemize_late_bound_regions(predicate, snapshot); - let origin = - SubregionOrigin::from_obligation_cause(cause, - || RelateRegionParamBound(cause.span)); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, cause.span, &skol_map, snapshot)?; - Ok(self.pop_skolemized(skol_map, snapshot)) - }) - } - - pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { + let ty::OutlivesPredicate(r_a, r_b) = predicate; + let origin = + SubregionOrigin::from_obligation_cause(cause, + || RelateRegionParamBound(cause.span)); + self.sub_regions(origin, param_env, r_b, r_a); // `b : a` ==> `a <= b` + Ok(()) + } + + pub fn next_ty_var_id(&self, + universe: ty::UniverseIndex, + diverging: bool, + origin: TypeVariableOrigin) + -> TyVid { self.type_variables .borrow_mut() - .new_var(diverging, origin, None) + .new_var(universe, diverging, origin) } - pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(false, origin)) + pub fn next_ty_var(&self, universe: ty::UniverseIndex, origin: TypeVariableOrigin) -> Ty<'tcx> { + self.tcx.mk_var(self.next_ty_var_id(universe, false, origin)) } - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_var(self.next_ty_var_id(true, origin)) + pub fn next_diverging_ty_var(&self, + universe: ty::UniverseIndex, + origin: TypeVariableOrigin) + -> Ty<'tcx> { + self.tcx.mk_var(self.next_ty_var_id(universe, true, origin)) } pub fn next_int_var_id(&self) -> IntVid { @@ -979,18 +959,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .new_key(None) } - pub fn next_region_var(&self, origin: RegionVariableOrigin) + pub fn next_region_var(&self, + universe: ty::UniverseIndex, + origin: RegionVariableOrigin) -> ty::Region<'tcx> { - self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(origin))) + self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(universe, origin))) } /// Create a region inference variable for the given /// region parameter definition. pub fn region_var_for_def(&self, + universe: ty::UniverseIndex, span: Span, def: &ty::RegionParameterDef) -> ty::Region<'tcx> { - self.next_region_var(EarlyBoundRegion(span, def.name)) + self.next_region_var(universe, EarlyBoundRegion(span, def.name)) } /// Create a type inference variable for the given @@ -1002,27 +985,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// use an inference variable for `C` with `[T, U]` /// as the substitutions for the default, `(T, U)`. pub fn type_var_for_def(&self, + universe: ty::UniverseIndex, span: Span, - def: &ty::TypeParameterDef, - substs: &[Kind<'tcx>]) + def: &ty::TypeParameterDef) -> Ty<'tcx> { - let default = if def.has_default { - let default = self.tcx.type_of(def.def_id); - Some(type_variable::Default { - ty: default.subst_spanned(self.tcx, substs, Some(span)), - origin_span: span, - def_id: def.def_id - }) - } else { - None - }; - - let ty_var_id = self.type_variables .borrow_mut() - .new_var(false, - TypeVariableOrigin::TypeParameterDefinition(span, def.name), - default); + .new_var(universe, + false, + TypeVariableOrigin::TypeParameterDefinition(span, def.name)); self.tcx.mk_var(ty_var_id) } @@ -1030,13 +1001,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// Given a set of generics defined on a type or impl, returns a substitution mapping each /// type/region parameter to a fresh inference variable. pub fn fresh_substs_for_item(&self, + universe: ty::UniverseIndex, span: Span, def_id: DefId) -> &'tcx Substs<'tcx> { Substs::for_item(self.tcx, def_id, |def, _| { - self.region_var_for_def(span, def) - }, |def, substs| { - self.type_var_for_def(span, def, substs) + self.region_var_for_def(universe, span, def) + }, |def, _| { + self.type_var_for_def(universe, span, def) }) } @@ -1099,7 +1071,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { - self.resolve_type_vars_if_possible(t).to_string() + self.resolve_type_vars_if_possible(t).print_without_self().to_string() } pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> { @@ -1115,15 +1087,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // so this recursion should always be of very limited // depth. self.type_variables.borrow_mut() - .probe(v) - .map(|t| self.shallow_resolve(t)) - .unwrap_or(typ) + .probe(v) + .known() + .map(|t| self.shallow_resolve(t)) + .unwrap_or(typ) } ty::TyInfer(ty::IntVar(v)) => { self.int_unification_table .borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } @@ -1131,7 +1104,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyInfer(ty::FloatVar(v)) => { self.float_unification_table .borrow_mut() - .probe(v) + .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } @@ -1233,31 +1206,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.report_and_explain_type_error(trace, &err) } - pub fn report_conflicting_default_types(&self, - span: Span, - body_id: ast::NodeId, - expected: type_variable::Default<'tcx>, - actual: type_variable::Default<'tcx>) { - let trace = TypeTrace { - cause: ObligationCause::misc(span, body_id), - values: Types(ExpectedFound { - expected: expected.ty, - found: actual.ty - }) - }; - - self.report_and_explain_type_error( - trace, - &TypeError::TyParamDefaultMismatch(ExpectedFound { - expected, - found: actual - })) - .emit(); - } - pub fn replace_late_bound_regions_with_fresh_var<T>( &self, span: Span, + universe: ty::UniverseIndex, lbrct: LateBoundRegionConversionTime, value: &ty::Binder<T>) -> (T, FxHashMap<ty::BoundRegion, ty::Region<'tcx>>) @@ -1265,40 +1217,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { self.tcx.replace_late_bound_regions( value, - |br| self.next_region_var(LateBoundRegion(span, br, lbrct))) - } - - /// Given a higher-ranked projection predicate like: - /// - /// for<'a> <T as Fn<&'a u32>>::Output = &'a u32 - /// - /// and a target trait-ref like: - /// - /// <T as Fn<&'x u32>> - /// - /// find a substitution `S` for the higher-ranked regions (here, - /// `['a => 'x]`) such that the predicate matches the trait-ref, - /// and then return the value (here, `&'a u32`) but with the - /// substitution applied (hence, `&'x u32`). - /// - /// See `higher_ranked_match` in `higher_ranked/mod.rs` for more - /// details. - pub fn match_poly_projection_predicate(&self, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - match_a: ty::PolyProjectionPredicate<'tcx>, - match_b: ty::TraitRef<'tcx>) - -> InferResult<'tcx, HrMatchResult<Ty<'tcx>>> - { - let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref(self.tcx), p.ty)); - let trace = TypeTrace { - cause, - values: TraitRefs(ExpectedFound::new(true, match_pair.skip_binder().0, match_b)) - }; - - let mut combine = self.combine_fields(trace, param_env); - let result = combine.higher_ranked_match(&match_pair, &match_b, true)?; - Ok(InferOk { value: result, obligations: combine.obligations }) + |br| self.next_region_var(universe, LateBoundRegion(span, br, lbrct))) } /// See `verify_generic_bound` method in `region_inference` @@ -1403,14 +1322,14 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Types(ExpectedFound::new(a_is_expected, a, b)) + values: ValuePairs::Types(ExpectedFound::new(a_is_expected, a, b)) } } pub fn dummy(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeTrace<'tcx> { TypeTrace { cause: ObligationCause::dummy(), - values: Types(ExpectedFound { + values: ValuePairs::Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err, }) @@ -1500,21 +1419,21 @@ impl RegionVariableOrigin { impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - ValuePairs::Types(ref ef) => { - ValuePairs::Types(ef.fold_with(folder)) - } - ValuePairs::TraitRefs(ref ef) => { - ValuePairs::TraitRefs(ef.fold_with(folder)) - } - ValuePairs::PolyTraitRefs(ref ef) => { - ValuePairs::PolyTraitRefs(ef.fold_with(folder)) - } + ValuePairs::Types(ref ef) => + ValuePairs::Types(ef.fold_with(folder)), + ValuePairs::ProjectionTypes(ref ef) => + ValuePairs::ProjectionTypes(ef.fold_with(folder)), + ValuePairs::TraitRefs(ref ef) => + ValuePairs::TraitRefs(ef.fold_with(folder)), + ValuePairs::PolyTraitRefs(ref ef) => + ValuePairs::PolyTraitRefs(ef.fold_with(folder)), } } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { match *self { ValuePairs::Types(ref ef) => ef.visit_with(visitor), + ValuePairs::ProjectionTypes(ref ef) => ef.visit_with(visitor), ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor), ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor), } diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 49f57d9aef50e..3ac9dc1a1ab0b 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -211,13 +211,13 @@ impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { match *c { - Constraint::ConstrainVarSubVar(rv_1, rv_2) => + Constraint::ConstrainVarSubVar(_, rv_1, rv_2) => (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), - Constraint::ConstrainRegSubVar(r_1, rv_2) => + Constraint::ConstrainRegSubVar(_, r_1, rv_2) => (Node::Region(*r_1), Node::RegionVid(rv_2)), - Constraint::ConstrainVarSubReg(rv_1, r_2) => + Constraint::ConstrainVarSubReg(_, rv_1, r_2) => (Node::RegionVid(rv_1), Node::Region(*r_2)), - Constraint::ConstrainRegSubReg(r_1, r_2) => + Constraint::ConstrainRegSubReg(_, r_1, r_2) => (Node::Region(*r_1), Node::Region(*r_2)), } } diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 8351be490767a..a1d7a93aae77c 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -11,8 +11,7 @@ //! See README.md pub use self::Constraint::*; -pub use self::UndoLogEntry::*; -pub use self::CombineMapType::*; +use self::UndoLogEntry::*; pub use self::RegionResolutionError::*; pub use self::VarValue::*; @@ -21,38 +20,39 @@ use super::unify_key; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; -use rustc_data_structures::unify::{self, UnificationTable}; +use rustc_data_structures::unify as ut; use middle::free_region::RegionRelations; use ty::{self, Ty, TyCtxt}; use ty::{Region, RegionVid}; -use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased}; +use ty::{ReCanonical, ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased}; use ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use std::cell::{Cell, RefCell}; +use std::cmp; use std::fmt; -use std::mem; use std::u32; mod graphviz; +pub mod taint; /// A constraint that influences the inference process. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum Constraint<'tcx> { /// One region variable is subregion of another - ConstrainVarSubVar(RegionVid, RegionVid), + ConstrainVarSubVar(ty::ParamEnv<'tcx>, RegionVid, RegionVid), /// Concrete region is subregion of region variable - ConstrainRegSubVar(Region<'tcx>, RegionVid), + ConstrainRegSubVar(ty::ParamEnv<'tcx>, Region<'tcx>, RegionVid), /// Region variable is subregion of concrete region. This does not /// directly affect inference, but instead is checked after /// inference is complete. - ConstrainVarSubReg(RegionVid, Region<'tcx>), + ConstrainVarSubReg(ty::ParamEnv<'tcx>, RegionVid, Region<'tcx>), /// A constraint where neither side is a variable. This does not /// directly affect inference, but instead is checked after /// inference is complete. - ConstrainRegSubReg(Region<'tcx>, Region<'tcx>), + ConstrainRegSubReg(ty::ParamEnv<'tcx>, Region<'tcx>, Region<'tcx>), } /// VerifyGenericBound(T, _, R, RS): The parameter type `T` (or @@ -101,13 +101,13 @@ pub enum VerifyBound<'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct TwoRegions<'tcx> { - a: Region<'tcx>, - b: Region<'tcx>, +struct NormalizedRegions { + a: ty::NormalizedRegion, + b: ty::NormalizedRegion, } #[derive(Copy, Clone, PartialEq)] -pub enum UndoLogEntry<'tcx> { +enum UndoLogEntry<'tcx> { /// Pushed when we start a snapshot. OpenSnapshot, @@ -129,19 +129,11 @@ pub enum UndoLogEntry<'tcx> { AddGiven(Region<'tcx>, ty::RegionVid), /// We added a GLB/LUB "combination variable" - AddCombination(CombineMapType, TwoRegions<'tcx>), - - /// During skolemization, we sometimes purge entries from the undo - /// log in a kind of minisnapshot (unlike other snapshots, this - /// purging actually takes place *on success*). In that case, we - /// replace the corresponding entry with `Noop` so as to avoid the - /// need to do a bunch of swapping. (We can't use `swap_remove` as - /// the order of the vector is important.) - Purged, + AddCombination(CombineMapType, NormalizedRegions), } #[derive(Copy, Clone, PartialEq)] -pub enum CombineMapType { +enum CombineMapType { Lub, Glb, } @@ -177,11 +169,17 @@ pub enum ProcessedErrorOrigin<'tcx> { VariableFailure(RegionVariableOrigin), } -pub type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>; +type CombineMap = FxHashMap<NormalizedRegions, RegionVid>; + +#[derive(Clone, Debug)] +struct RegionVariableInfo { + origin: RegionVariableOrigin, + universe: ty::UniverseIndex, +} pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - var_origins: RefCell<Vec<RegionVariableOrigin>>, + var_infos: RefCell<Vec<RegionVariableInfo>>, /// Constraints of the form `A <= B` introduced by the region /// checker. Here at least one of `A` and `B` must be a region @@ -214,9 +212,8 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// a bit of a hack but seems to work. givens: RefCell<FxHashSet<(Region<'tcx>, ty::RegionVid)>>, - lubs: RefCell<CombineMap<'tcx>>, - glbs: RefCell<CombineMap<'tcx>>, - skolemization_count: Cell<u32>, + lubs: RefCell<CombineMap>, + glbs: RefCell<CombineMap>, bound_count: Cell<u32>, /// The undo log records actions that might later be undone. @@ -230,7 +227,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// back. undo_log: RefCell<Vec<UndoLogEntry<'tcx>>>, - unification_table: RefCell<UnificationTable<ty::RegionVid>>, + unification_table: RefCell<ut::UnificationTable<ut::InPlace<ty::RegionVid>>>, /// This contains the results of inference. It begins as an empty /// option and only acquires a value after inference is complete. @@ -239,133 +236,23 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub struct RegionSnapshot { length: usize, - region_snapshot: unify::Snapshot<ty::RegionVid>, - skolemization_count: u32, -} - -/// When working with skolemized regions, we often wish to find all of -/// the regions that are either reachable from a skolemized region, or -/// which can reach a skolemized region, or both. We call such regions -/// *tained* regions. This struct allows you to decide what set of -/// tainted regions you want. -#[derive(Debug)] -pub struct TaintDirections { - incoming: bool, - outgoing: bool, -} - -impl TaintDirections { - pub fn incoming() -> Self { - TaintDirections { incoming: true, outgoing: false } - } - - pub fn outgoing() -> Self { - TaintDirections { incoming: false, outgoing: true } - } - - pub fn both() -> Self { - TaintDirections { incoming: true, outgoing: true } - } -} - -struct TaintSet<'tcx> { - directions: TaintDirections, - regions: FxHashSet<ty::Region<'tcx>> -} - -impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { - fn new(directions: TaintDirections, - initial_region: ty::Region<'tcx>) - -> Self { - let mut regions = FxHashSet(); - regions.insert(initial_region); - TaintSet { directions: directions, regions: regions } - } - - fn fixed_point(&mut self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - undo_log: &[UndoLogEntry<'tcx>], - verifys: &[Verify<'tcx>]) { - let mut prev_len = 0; - while prev_len < self.len() { - debug!("tainted: prev_len = {:?} new_len = {:?}", - prev_len, self.len()); - - prev_len = self.len(); - - for undo_entry in undo_log { - match undo_entry { - &AddConstraint(ConstrainVarSubVar(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), - tcx.mk_region(ReVar(b))); - } - &AddConstraint(ConstrainRegSubVar(a, b)) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddConstraint(ConstrainVarSubReg(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), b); - } - &AddConstraint(ConstrainRegSubReg(a, b)) => { - self.add_edge(a, b); - } - &AddGiven(a, b) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddVerify(i) => { - verifys[i].bound.for_each_region(&mut |b| { - self.add_edge(verifys[i].region, b); - }); - } - &Purged | - &AddCombination(..) | - &AddVar(..) | - &OpenSnapshot | - &CommitedSnapshot => {} - } - } - } - } - - fn into_set(self) -> FxHashSet<ty::Region<'tcx>> { - self.regions - } - - fn len(&self) -> usize { - self.regions.len() - } - - fn add_edge(&mut self, - source: ty::Region<'tcx>, - target: ty::Region<'tcx>) { - if self.directions.incoming { - if self.regions.contains(&target) { - self.regions.insert(source); - } - } - - if self.directions.outgoing { - if self.regions.contains(&source) { - self.regions.insert(target); - } - } - } + region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>, } impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> RegionVarBindings<'a, 'gcx, 'tcx> { RegionVarBindings { tcx, - var_origins: RefCell::new(Vec::new()), + var_infos: RefCell::new(Vec::new()), values: RefCell::new(None), constraints: RefCell::new(FxHashMap()), verifys: RefCell::new(Vec::new()), givens: RefCell::new(FxHashSet()), lubs: RefCell::new(FxHashMap()), glbs: RefCell::new(FxHashMap()), - skolemization_count: Cell::new(0), bound_count: Cell::new(0), undo_log: RefCell::new(Vec::new()), - unification_table: RefCell::new(UnificationTable::new()), + unification_table: RefCell::new(ut::UnificationTable::new()), } } @@ -380,7 +267,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { RegionSnapshot { length, region_snapshot: self.unification_table.borrow_mut().snapshot(), - skolemization_count: self.skolemization_count.get(), } } @@ -388,10 +274,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { debug!("RegionVarBindings: commit({})", snapshot.length); assert!(self.undo_log.borrow().len() > snapshot.length); assert!((*self.undo_log.borrow())[snapshot.length] == OpenSnapshot); - assert!(self.skolemization_count.get() == snapshot.skolemization_count, - "failed to pop skolemized regions: {} now vs {} at start", - self.skolemization_count.get(), - snapshot.skolemization_count); let mut undo_log = self.undo_log.borrow_mut(); if snapshot.length == 0 { @@ -412,23 +294,22 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } let c = undo_log.pop().unwrap(); assert!(c == OpenSnapshot); - self.skolemization_count.set(snapshot.skolemization_count); self.unification_table.borrow_mut() .rollback_to(snapshot.region_snapshot); } - pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry<'tcx>) { + fn rollback_undo_entry(&self, undo_entry: UndoLogEntry<'tcx>) { match undo_entry { OpenSnapshot => { panic!("Failure to observe stack discipline"); } - Purged | CommitedSnapshot => { + CommitedSnapshot => { // nothing to do here } AddVar(vid) => { - let mut var_origins = self.var_origins.borrow_mut(); - var_origins.pop().unwrap(); - assert_eq!(var_origins.len(), vid.index as usize); + let mut var_infos = self.var_infos.borrow_mut(); + var_infos.pop().unwrap(); + assert_eq!(var_infos.len(), vid.index as usize); } AddConstraint(ref constraint) => { self.constraints.borrow_mut().remove(constraint); @@ -440,25 +321,31 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { AddGiven(sub, sup) => { self.givens.borrow_mut().remove(&(sub, sup)); } - AddCombination(Glb, ref regions) => { + AddCombination(CombineMapType::Glb, ref regions) => { self.glbs.borrow_mut().remove(regions); } - AddCombination(Lub, ref regions) => { + AddCombination(CombineMapType::Lub, ref regions) => { self.lubs.borrow_mut().remove(regions); } } } pub fn num_vars(&self) -> u32 { - let len = self.var_origins.borrow().len(); + let len = self.var_infos.borrow().len(); // enforce no overflow assert!(len as u32 as usize == len); len as u32 } - pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { + pub fn new_region_var(&self, + universe: ty::UniverseIndex, + origin: RegionVariableOrigin) + -> RegionVid { let vid = RegionVid { index: self.num_vars() }; - self.var_origins.borrow_mut().push(origin.clone()); + self.var_infos.borrow_mut().push(RegionVariableInfo { + origin: origin.clone(), + universe, + }); let u_vid = self.unification_table.borrow_mut().new_key( unify_key::RegionVidKey { min_vid: vid } @@ -473,125 +360,12 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { return vid; } - pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { - self.var_origins.borrow()[vid.index as usize].clone() - } - - /// Creates a new skolemized region. Skolemized regions are fresh - /// regions used when performing higher-ranked computations. They - /// must be used in a very particular way and are never supposed - /// to "escape" out into error messages or the code at large. - /// - /// The idea is to always create a snapshot. Skolemized regions - /// can be created in the context of this snapshot, but before the - /// snapshot is committed or rolled back, they must be popped - /// (using `pop_skolemized_regions`), so that their numbers can be - /// recycled. Normally you don't have to think about this: you use - /// the APIs in `higher_ranked/mod.rs`, such as - /// `skolemize_late_bound_regions` and `plug_leaks`, which will - /// guide you on this path (ensure that the `SkolemizationMap` is - /// consumed and you are good). There are also somewhat extensive - /// comments in `higher_ranked/README.md`. - /// - /// The `snapshot` argument to this function is not really used; - /// it's just there to make it explicit which snapshot bounds the - /// skolemized region that results. It should always be the top-most snapshot. - pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) - -> Region<'tcx> { - assert!(self.in_snapshot()); - assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); - - let sc = self.skolemization_count.get(); - self.skolemization_count.set(sc + 1); - self.tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)) + pub fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex { + self.var_infos.borrow()[vid.index as usize].universe } - /// Removes all the edges to/from the skolemized regions that are - /// in `skols`. This is used after a higher-ranked operation - /// completes to remove all trace of the skolemized regions - /// created in that time. - pub fn pop_skolemized(&self, - skols: &FxHashSet<ty::Region<'tcx>>, - snapshot: &RegionSnapshot) { - debug!("pop_skolemized_regions(skols={:?})", skols); - - assert!(self.in_snapshot()); - assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); - assert!(self.skolemization_count.get() as usize >= skols.len(), - "popping more skolemized variables than actually exist, \ - sc now = {}, skols.len = {}", - self.skolemization_count.get(), - skols.len()); - - let last_to_pop = self.skolemization_count.get(); - let first_to_pop = last_to_pop - (skols.len() as u32); - - assert!(first_to_pop >= snapshot.skolemization_count, - "popping more regions than snapshot contains, \ - sc now = {}, sc then = {}, skols.len = {}", - self.skolemization_count.get(), - snapshot.skolemization_count, - skols.len()); - debug_assert! { - skols.iter() - .all(|&k| match *k { - ty::ReSkolemized(index, _) => - index.index >= first_to_pop && - index.index < last_to_pop, - _ => - false - }), - "invalid skolemization keys or keys out of range ({}..{}): {:?}", - snapshot.skolemization_count, - self.skolemization_count.get(), - skols - } - - let mut undo_log = self.undo_log.borrow_mut(); - - let constraints_to_kill: Vec<usize> = - undo_log.iter() - .enumerate() - .rev() - .filter(|&(_, undo_entry)| kill_constraint(skols, undo_entry)) - .map(|(index, _)| index) - .collect(); - - for index in constraints_to_kill { - let undo_entry = mem::replace(&mut undo_log[index], Purged); - self.rollback_undo_entry(undo_entry); - } - - self.skolemization_count.set(snapshot.skolemization_count); - return; - - fn kill_constraint<'tcx>(skols: &FxHashSet<ty::Region<'tcx>>, - undo_entry: &UndoLogEntry<'tcx>) - -> bool { - match undo_entry { - &AddConstraint(ConstrainVarSubVar(..)) => - false, - &AddConstraint(ConstrainRegSubVar(a, _)) => - skols.contains(&a), - &AddConstraint(ConstrainVarSubReg(_, b)) => - skols.contains(&b), - &AddConstraint(ConstrainRegSubReg(a, b)) => - skols.contains(&a) || skols.contains(&b), - &AddGiven(..) => - false, - &AddVerify(_) => - false, - &AddCombination(_, ref two_regions) => - skols.contains(&two_regions.a) || - skols.contains(&two_regions.b), - &AddVar(..) | - &OpenSnapshot | - &Purged | - &CommitedSnapshot => - false, - } - } - + pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { + self.var_infos.borrow()[vid.index as usize].origin.clone() } pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region<'tcx> { @@ -674,13 +448,14 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>) { if sub != sup { // Eventually, it would be nice to add direct support for // equating regions. - self.make_subregion(origin.clone(), sub, sup); - self.make_subregion(origin, sup, sub); + self.make_subregion(origin.clone(), param_env, sub, sup); + self.make_subregion(origin, param_env, sup, sub); if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) { self.unification_table.borrow_mut().union(sub, sup); @@ -690,14 +465,16 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>) { // cannot add constraints once regions are resolved assert!(self.values_are_none()); - debug!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}", + debug!("RegionVarBindings: make_subregion({:?}, {:?}) in {:?} due to {:?}", sub, sup, + param_env, origin); match (sub, sup) { @@ -712,16 +489,16 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // all regions are subregions of static, so we can ignore this } (&ReVar(sub_id), &ReVar(sup_id)) => { - self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin); + self.add_constraint(ConstrainVarSubVar(param_env, sub_id, sup_id), origin); } (_, &ReVar(sup_id)) => { - self.add_constraint(ConstrainRegSubVar(sub, sup_id), origin); + self.add_constraint(ConstrainRegSubVar(param_env, sub, sup_id), origin); } (&ReVar(sub_id), _) => { - self.add_constraint(ConstrainVarSubReg(sub_id, sup), origin); + self.add_constraint(ConstrainVarSubReg(param_env, sub_id, sup), origin); } _ => { - self.add_constraint(ConstrainRegSubReg(sub, sup), origin); + self.add_constraint(ConstrainRegSubReg(param_env, sub, sup), origin); } } } @@ -740,8 +517,11 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { }); } + /// Returns a new region that is the union of `a` and `b`, + /// or at least the closest we can approximate. pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { @@ -759,15 +539,16 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } _ => { - self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| { - this.make_subregion(origin.clone(), old_r, new_r) - }) + self.combine_vars(CombineMapType::Lub, param_env, a, b, origin.clone()) } } } + /// Returns a new region that is the intersection of `a` and `b`, + /// or at least the closest we can approximate. pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { @@ -785,9 +566,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } _ => { - self.combine_vars(Glb, a, b, origin.clone(), |this, old_r, new_r| { - this.make_subregion(origin.clone(), new_r, old_r) - }) + self.combine_vars(CombineMapType::Glb, param_env, a, b, origin.clone()) } } } @@ -795,7 +574,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { match *self.values.borrow() { None => { - span_bug!((*self.var_origins.borrow())[rid.index as usize].span(), + span_bug!((*self.var_infos.borrow())[rid.index as usize].origin.span(), "attempt to resolve region variable before values have \ been computed!") } @@ -808,41 +587,86 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { - let vid = self.unification_table.borrow_mut().find_value(rid).min_vid; + let vid = self.unification_table.borrow_mut().probe_value(rid).min_vid; self.tcx.mk_region(ty::ReVar(vid)) } - fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap<'tcx>> { + fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap> { match t { - Glb => &self.glbs, - Lub => &self.lubs, + CombineMapType::Glb => &self.glbs, + CombineMapType::Lub => &self.lubs, } } - pub fn combine_vars<F>(&self, - t: CombineMapType, - a: Region<'tcx>, - b: Region<'tcx>, - origin: SubregionOrigin<'tcx>, - mut relate: F) - -> Region<'tcx> - where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region<'tcx>, Region<'tcx>) + fn combine_vars(&self, + t: CombineMapType, + param_env: ty::ParamEnv<'tcx>, + a: Region<'tcx>, + b: Region<'tcx>, + origin: SubregionOrigin<'tcx>) + -> Region<'tcx> { - let vars = TwoRegions { a: a, b: b }; + let vars = NormalizedRegions { + a: param_env.normalize_region(a), + b: param_env.normalize_region(b) + }; if let Some(&c) = self.combine_map(t).borrow().get(&vars) { return self.tcx.mk_region(ReVar(c)); } - let c = self.new_region_var(MiscVariable(origin.span())); + let a_universe = self.universe(a); + let b_universe = self.universe(b); + let c_universe = cmp::max(a_universe, b_universe); + let c = self.new_region_var(c_universe, MiscVariable(origin.span())); self.combine_map(t).borrow_mut().insert(vars, c); if self.in_snapshot() { self.undo_log.borrow_mut().push(AddCombination(t, vars)); } - relate(self, a, self.tcx.mk_region(ReVar(c))); - relate(self, b, self.tcx.mk_region(ReVar(c))); + let re_c = self.tcx.mk_region(ReVar(c)); + match t { + CombineMapType::Glb => { + // c is the *intersection* of a and b, and hence + // smaller than both of them, so add constraint that c + // <= a and c <= b. + self.make_subregion(origin.clone(), param_env, re_c, a); + self.make_subregion(origin.clone(), param_env, re_c, b); + } + + CombineMapType::Lub => { + // c is the *union* of a and b, and hence + // larger than both of them, so add constraint that a + // <= c and b <= c. + self.make_subregion(origin.clone(), param_env, a, re_c); + self.make_subregion(origin.clone(), param_env, b, re_c); + } + } debug!("combine_vars() c={:?}", c); self.tcx.mk_region(ReVar(c)) } + fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex { + match *region { + ty::ReScope(..) | + ty::ReStatic | + ty::ReEmpty | + ty::ReErased | + ty::ReFree(..) | + ty::ReEarlyBound(..) => + ty::UniverseIndex::ROOT, + + ty::ReSkolemized(u, _) => + u, + + ty::ReVar(vid) => + self.var_infos.borrow()[vid.index as usize].universe, + + ty::ReLateBound(..) => + bug!("universe(): encountered bound region {:?}", region), + + ty::ReCanonical(..) => + bug!("universe(): encountered canonical region {:?}", region), + } + } + pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVid> { self.undo_log.borrow()[mark.length..] .iter() @@ -855,33 +679,6 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { .collect() } - /// Computes all regions that have been related to `r0` since the - /// mark `mark` was made---`r0` itself will be the first - /// entry. The `directions` parameter controls what kind of - /// relations are considered. For example, one can say that only - /// "incoming" edges to `r0` are desired, in which case one will - /// get the set of regions `{r|r <= r0}`. This is used when - /// checking whether skolemized regions are being improperly - /// related to other regions. - pub fn tainted(&self, - mark: &RegionSnapshot, - r0: Region<'tcx>, - directions: TaintDirections) - -> FxHashSet<ty::Region<'tcx>> { - debug!("tainted(mark={:?}, r0={:?}, directions={:?})", - mark, r0, directions); - - // `result_set` acts as a worklist: we explore all outgoing - // edges and add any new regions we find to result_set. This - // is not a terribly efficient implementation. - let mut taint_set = TaintSet::new(directions, r0); - taint_set.fixed_point(self.tcx, - &self.undo_log.borrow()[mark.length..], - &self.verifys.borrow()); - debug!("tainted: result={:?}", taint_set.regions); - return taint_set.into_set(); - } - /// This function performs the actual region resolution. It must be /// called after all constraints have been added. It performs a /// fixed-point iteration to find region values which satisfy all @@ -903,6 +700,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { b: Region<'tcx>) -> Region<'tcx> { match (a, b) { + (&ReCanonical(..), _) | + (_, &ReCanonical(..)) | (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | @@ -919,7 +718,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } (&ReVar(v_id), _) | (_, &ReVar(v_id)) => { - span_bug!((*self.var_origins.borrow())[v_id.index as usize].span(), + span_bug!((*self.var_infos.borrow())[v_id.index as usize].origin.span(), "lub_concrete_regions invoked with non-concrete \ regions: {:?}, {:?}", a, @@ -1071,11 +870,11 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { debug!("expansion: constraint={:?} origin={:?}", constraint, origin); match *constraint { - ConstrainRegSubVar(a_region, b_vid) => { + ConstrainRegSubVar(_, a_region, b_vid) => { let b_data = &mut var_values[b_vid.index as usize]; self.expand_node(region_rels, a_region, b_vid, b_data) } - ConstrainVarSubVar(a_vid, b_vid) => { + ConstrainVarSubVar(_, a_vid, b_vid) => { match var_values[a_vid.index as usize] { ErrorValue => false, Value(a_region) => { @@ -1117,13 +916,43 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { _ => {} } + let b_universe = self.var_infos.borrow()[b_vid.index as usize].universe; + match *b_data { Value(cur_region) => { - let lub = self.lub_concrete_regions(region_rels, a_region, cur_region); + let mut lub = self.lub_concrete_regions(region_rels, a_region, cur_region); if lub == cur_region { return false; } + // Find the universe of the new value (`lub`) and + // check whether this value is something that we can + // legally name in this variable. If not, promote the + // variable to `'static`, which is surely greater than + // or equal to `lub`. This is obviously a kind of sub-optimal + // choice -- in the future, when we incorporate a knowledge + // of the parameter environment, we might be able to find a + // tighter bound than `'static`. + // + // To make this more concrete, imagine a bound like: + // + // for<'a> '0: 'a + // + // Here we have that `'0` must outlive `'a` -- no + // matter what `'a` is. When solving such a + // constraint, we would initially assign `'0` to be + // `'empty`. We would then compute the LUB of `'empty` + // and `'a` (which is something like `ReSkolemized(1)`), + // resulting in `'a`. + // + // At this point, `lub_universe` would be `1` and + // `b_universe` would be `0`, and hence we would wind + // up promoting `lub` to `'static`. + let lub_universe = self.universe(lub); + if !lub_universe.is_visible_in(b_universe) { + lub = self.tcx.types.re_static; + } + debug!("Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, @@ -1156,7 +985,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // Expansion will ensure that these constraints hold. Ignore. } - ConstrainRegSubReg(sub, sup) => { + ConstrainRegSubReg(_, sub, sup) => { if region_rels.is_subregion_of(sub, sup) { continue; } @@ -1170,7 +999,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { errors.push(ConcreteFailure((*origin).clone(), sub, sup)); } - ConstrainVarSubReg(a_vid, b_region) => { + ConstrainVarSubReg(_, a_vid, b_region) => { let a_data = &mut var_data[a_vid.index as usize]; debug!("contraction: {:?} == {:?}, {:?}", a_vid, @@ -1307,15 +1136,15 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { for (constraint, _) in constraints.iter() { match *constraint { - ConstrainVarSubVar(a_id, b_id) => { + ConstrainVarSubVar(_, a_id, b_id) => { graph.add_edge(NodeIndex(a_id.index as usize), NodeIndex(b_id.index as usize), *constraint); } - ConstrainRegSubVar(_, b_id) => { + ConstrainRegSubVar(_, _, b_id) => { graph.add_edge(dummy_source, NodeIndex(b_id.index as usize), *constraint); } - ConstrainVarSubReg(a_id, _) => { + ConstrainVarSubReg(_, a_id, _) => { graph.add_edge(NodeIndex(a_id.index as usize), dummy_sink, *constraint); } ConstrainRegSubReg(..) => { @@ -1365,14 +1194,14 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { for lower_bound in &lower_bounds { for upper_bound in &upper_bounds { if !region_rels.is_subregion_of(lower_bound.region, upper_bound.region) { - let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); + let info = (*self.var_infos.borrow())[node_idx.index as usize].clone(); debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ sup: {:?}", - origin, + info.origin, node_idx, lower_bound.region, upper_bound.region); - errors.push(SubSupConflict(origin, + errors.push(SubSupConflict(info.origin, lower_bound.origin.clone(), lower_bound.region, upper_bound.origin.clone(), @@ -1382,7 +1211,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - span_bug!((*self.var_origins.borrow())[node_idx.index as usize].span(), + span_bug!((*self.var_infos.borrow())[node_idx.index as usize].origin.span(), "collect_error_for_expanding_node() could not find \ error for var {:?}, lower_bounds={:?}, \ upper_bounds={:?}", @@ -1445,7 +1274,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { let source_node_index = NodeIndex(source_vid.index as usize); for (_, edge) in graph.adjacent_edges(source_node_index, dir) { match edge.data { - ConstrainVarSubVar(from_vid, to_vid) => { + ConstrainVarSubVar(_, from_vid, to_vid) => { let opp_vid = if from_vid == source_vid { to_vid } else { @@ -1456,8 +1285,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - ConstrainRegSubVar(region, _) | - ConstrainVarSubReg(_, region) => { + ConstrainRegSubVar(_, region, _) | + ConstrainVarSubReg(_, _, region) => { state.result.push(RegionAndOrigin { region, origin: this.constraints.borrow().get(&edge.data).unwrap().clone(), @@ -1523,8 +1352,7 @@ impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> { impl fmt::Debug for RegionSnapshot { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionSnapshot(length={},skolemization={})", - self.length, self.skolemization_count) + write!(f, "RegionSnapshot(length={})", self.length) } } @@ -1556,20 +1384,6 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> { } impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> { - fn for_each_region(&self, f: &mut FnMut(ty::Region<'tcx>)) { - match self { - &VerifyBound::AnyRegion(ref rs) | - &VerifyBound::AllRegions(ref rs) => for &r in rs { - f(r); - }, - - &VerifyBound::AnyBound(ref bs) | - &VerifyBound::AllBounds(ref bs) => for b in bs { - b.for_each_region(f); - }, - } - } - pub fn must_hold(&self) -> bool { match self { &VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic), diff --git a/src/librustc/infer/region_inference/taint.rs b/src/librustc/infer/region_inference/taint.rs new file mode 100644 index 0000000000000..43497b01443ae --- /dev/null +++ b/src/librustc/infer/region_inference/taint.rs @@ -0,0 +1,146 @@ +// Copyright 2012-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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The "Tainted" code is used for computing the LUB/GLB for +//! higher-ranked types. See the README for `infer::higher_ranked` for +//! more information. + +use super::{AddCombination, AddConstraint, AddGiven, AddVar, AddVerify, + CommitedSnapshot, + ConstrainVarSubVar, ConstrainVarSubReg, ConstrainRegSubReg, ConstrainRegSubVar, + OpenSnapshot, + RegionSnapshot, RegionVarBindings, + UndoLogEntry}; + +use std::cell::Ref; +use ty::{self, TyCtxt, Region, ReVar}; +use rustc_data_structures::fx::FxHashSet; + +pub(in infer) struct TaintIterator<'a, 'gcx: 'tcx, 'tcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'tcx>, + undo_log: Ref<'a, [UndoLogEntry<'tcx>]>, + regions: FxHashSet<ty::NormalizedRegion>, + queue: Vec<ty::Region<'tcx>>, +} + +impl<'a, 'gcx, 'tcx> TaintIterator<'a, 'gcx, 'tcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, + undo_log: Ref<'a, [UndoLogEntry<'tcx>]>, + param_env: ty::ParamEnv<'tcx>, + initial_region: ty::Region<'tcx>) + -> Self { + let mut regions = FxHashSet(); + let norm_initial_region = param_env.normalize_region(initial_region); + regions.insert(norm_initial_region); + let queue = vec![initial_region]; + TaintIterator { tcx, undo_log, regions, queue } + } + + fn add_edge(regions: &mut FxHashSet<ty::NormalizedRegion>, + queue: &mut Vec<ty::Region<'tcx>>, + param_env: ty::ParamEnv<'tcx>, + source: ty::Region<'tcx>, + target: ty::Region<'tcx>) { + let norm_source = param_env.normalize_region(source); + let norm_target = param_env.normalize_region(target); + + if regions.contains(&norm_target) { + if regions.insert(norm_source) { + queue.push(source); + } + } + + if regions.contains(&norm_source) { + if regions.insert(norm_target) { + queue.push(target); + } + } + } +} + +impl<'a, 'gcx, 'tcx> Iterator for TaintIterator<'a, 'gcx, 'tcx> { + type Item = ty::Region<'tcx>; + + fn next(&mut self) -> Option<ty::Region<'tcx>> { + let region = match self.queue.pop() { + Some(r) => r, + None => return None, + }; + + for undo_entry in &self.undo_log[..] { + match undo_entry { + &AddConstraint(ConstrainVarSubVar(param_env, a, b)) => { + Self::add_edge(&mut self.regions, + &mut self.queue, + param_env, + self.tcx.mk_region(ReVar(a)), + self.tcx.mk_region(ReVar(b))); + } + &AddConstraint(ConstrainRegSubVar(param_env, a, b)) => { + Self::add_edge(&mut self.regions, + &mut self.queue, + param_env, + a, + self.tcx.mk_region(ReVar(b))); + } + &AddConstraint(ConstrainVarSubReg(param_env, a, b)) => { + Self::add_edge(&mut self.regions, + &mut self.queue, + param_env, + self.tcx.mk_region(ReVar(a)), + b); + } + &AddConstraint(ConstrainRegSubReg(param_env, a, b)) => { + Self::add_edge(&mut self.regions, + &mut self.queue, + param_env, + a, + b); + } + &AddGiven(..) => { + bug!("cannot use taint when givens have been added") + } + &AddVerify(..) => { + bug!("cannot use taint when verifys have been added") + } + &AddCombination(..) | + &AddVar(..) | + &OpenSnapshot | + &CommitedSnapshot => {} + } + } + + Some(region) + } +} + +impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { + /// Computes all regions that have been related to `r0` since the + /// mark `mark` was made---`r0` itself will be the first + /// entry. The `directions` parameter controls what kind of + /// relations are considered. For example, one can say that only + /// "incoming" edges to `r0` are desired, in which case one will + /// get the set of regions `{r|r <= r0}`. This is used when + /// checking whether skolemized regions are being improperly + /// related to other regions. + pub(in infer) fn tainted<'this>(&'this self, + mark: &RegionSnapshot, + param_env: ty::ParamEnv<'tcx>, + r0: Region<'tcx>) + -> TaintIterator<'this, 'gcx, 'tcx> { + debug!("tainted(mark={:?}, r0={:?})", mark, r0); + + // `result_set` acts as a worklist: we explore all outgoing + // edges and add any new regions we find to result_set. This + // is not a terribly efficient implementation. + let undo_log = Ref::map(self.undo_log.borrow(), |l| &l[mark.length..]); + TaintIterator::new(self.tcx, undo_log, param_env, r0) + } +} diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 4056999681352..ac192f0ce0f1f 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -11,7 +11,7 @@ use super::SubregionOrigin; use super::combine::{CombineFields, RelationDir}; -use traits::Obligation; +use traits::PredicateObligation; use ty::{self, Ty, TyCtxt}; use ty::TyVar; use ty::fold::TypeFoldable; @@ -22,13 +22,16 @@ use std::mem; pub struct Sub<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool, + param_env: ty::ParamEnv<'tcx>, } impl<'combine, 'infcx, 'gcx, 'tcx> Sub<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(f: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Sub<'combine, 'infcx, 'gcx, 'tcx> + pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + a_is_expected: bool) + -> Sub<'combine, 'infcx, 'gcx, 'tcx> { - Sub { fields: f, a_is_expected: a_is_expected } + Sub { fields, a_is_expected, param_env } } fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R { @@ -64,7 +67,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), + ty::Invariant => self.fields.equate(self.param_env, self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), @@ -94,25 +97,31 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> // is important to the occurs check later on. infcx.type_variables.borrow_mut().sub(a_vid, b_vid); self.fields.obligations.push( - Obligation::new( + PredicateObligation::from( self.fields.trace.cause.clone(), - self.fields.param_env, - ty::Predicate::Subtype( - ty::Binder(ty::SubtypePredicate { - a_is_expected: self.a_is_expected, - a, - b, - })))); + self.param_env, + ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a, + b, + })); Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields - .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; + self.fields.instantiate(self.param_env, + b, + RelationDir::SupertypeOf, + a_id, + !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(self.param_env, + a, + RelationDir::SubtypeOf, + b_id, + self.a_is_expected)?; Ok(a) } @@ -137,7 +146,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> // from the "cause" field, we could perhaps give more tailored // error messages. let origin = SubregionOrigin::Subtype(self.fields.trace.clone()); - self.fields.infcx.region_vars.make_subregion(origin, a, b); + self.fields.infcx.region_vars.make_subregion(origin, self.param_env, a, b); Ok(a) } @@ -146,6 +155,6 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> -> RelateResult<'tcx, ty::Binder<T>> where T: Relate<'tcx> { - self.fields.higher_ranked_sub(a, b, self.a_is_expected) + self.fields.higher_ranked_sub(self.param_env, a, b, self.a_is_expected) } } diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index cc91a637b8931..4ee23d2647fa2 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,26 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::TypeVariableValue::*; -use hir::def_id::{DefId}; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; -use std::cmp::min; +use std::cmp; 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<Delegate<'tcx>>, + /// Extra data for each type variable, such as the origin. This is + /// not stored in the unification table since, when we inquire + /// after the origin of a variable X, we want the origin of **that + /// variable X**, not the origin of some other variable Y with + /// which X has been unified. + var_data: Vec<TypeVariableData>, /// Two variables are unified in `eq_relations` when we have a - /// constraint `?X == ?Y`. - eq_relations: ut::UnificationTable<ty::TyVid>, + /// constraint `?X == ?Y`. This table also stores, for each key, + /// the known value. + eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>, /// Two variables are unified in `eq_relations` when we have a /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second @@ -46,7 +48,7 @@ pub struct TypeVariableTable<'tcx> { /// This is reasonable because, in Rust, subtypes have the same /// "skeleton" and hence there is no possible type such that /// (e.g.) `Box<?3> <: ?3` for any `?3`. - sub_relations: ut::UnificationTable<ty::TyVid>, + sub_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>, } /// Reasons to create a type inference variable @@ -69,73 +71,91 @@ pub enum TypeVariableOrigin { pub type TypeVariableMap = FxHashMap<ty::TyVid, TypeVariableOrigin>; -struct TypeVariableData<'tcx> { - value: TypeVariableValue<'tcx>, +struct TypeVariableData { origin: TypeVariableOrigin, diverging: bool } -enum TypeVariableValue<'tcx> { - Known(Ty<'tcx>), - Bounded { - default: Option<Default<'tcx>> - } +#[derive(Copy, Clone, Debug)] +pub enum TypeVariableValue<'tcx> { + Known { value: Ty<'tcx> }, + Unknown { universe: ty::UniverseIndex }, } -// We will use this to store the required information to recapitulate what happened when -// an error occurs. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Default<'tcx> { - pub ty: Ty<'tcx>, - /// The span where the default was incurred - pub origin_span: Span, - /// The definition that the default originates from - pub def_id: DefId +#[derive(Copy, Clone, Debug)] +pub enum ProbeTyValue<'tcx> { + Ty(Ty<'tcx>), + Vid(ty::TyVid), } -pub struct Snapshot { - snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot<ty::TyVid>, - sub_snapshot: ut::Snapshot<ty::TyVid>, -} +impl<'tcx> TypeVariableValue<'tcx> { + /// If this value is known, returns the type it is known to be. + /// Otherwise, `None`. + pub fn known(&self) -> Option<Ty<'tcx>> { + match *self { + TypeVariableValue::Unknown { .. } => None, + TypeVariableValue::Known { value } => Some(value), + } + } -struct Instantiate<'tcx> { - vid: ty::TyVid, - default: Option<Default<'tcx>>, + /// If this value is unknown, returns the universe, otherwise `None`. + pub fn universe(&self) -> Option<ty::UniverseIndex> { + match *self { + TypeVariableValue::Unknown { universe } => Some(universe), + TypeVariableValue::Known { .. } => None, + } + } + + pub fn is_unknown(&self) -> bool { + match *self { + TypeVariableValue::Unknown { .. } => true, + TypeVariableValue::Known { .. } => false, + } + } } -struct Delegate<'tcx>(PhantomData<&'tcx ()>); +pub struct Snapshot<'tcx> { + /// number of variables at the time of the snapshot + num_vars: usize, + + /// snapshot from the `eq_relations` table + eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>, + + /// snapshot from the `sub_relations` table + sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>, +} impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { TypeVariableTable { - values: sv::SnapshotVec::new(), + var_data: Vec::new(), eq_relations: ut::UnificationTable::new(), sub_relations: ut::UnificationTable::new(), } } - pub fn default(&self, vid: ty::TyVid) -> Option<Default<'tcx>> { - match &self.values.get(vid.index as usize).value { - &Known(_) => None, - &Bounded { ref default, .. } => default.clone() - } - } - + /// Returns the diverges flag given when `vid` was created. + /// + /// Note that this function does not return care whether + /// `vid` has been unified with something else or not. pub fn var_diverges<'a>(&'a self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).diverging + self.var_data[vid.index as usize].diverging } + /// Returns the origin that was given when `vid` was created. + /// + /// Note that this function does not return care whether + /// `vid` has been unified with something else or not. pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.values.get(vid.index as usize).origin + &self.var_data[vid.index as usize].origin } /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. 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()); + debug_assert!(self.probe(a).is_unknown()); + debug_assert!(self.probe(b).is_unknown()); self.eq_relations.union(a, b); self.sub_relations.union(a, b); } @@ -144,8 +164,8 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// 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()); + debug_assert!(self.probe(a).is_unknown()); + debug_assert!(self.probe(b).is_unknown()); self.sub_relations.union(a, b); } @@ -154,43 +174,44 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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 old_value = { - let vid_data = &mut self.values[vid.index as usize]; - mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty)) - }; - - 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) - } - } + debug_assert!(self.probe(vid).is_unknown()); + debug_assert!(self.eq_relations.probe_value(vid).is_unknown(), + "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", + vid, ty, self.eq_relations.probe_value(vid)); + self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty }); } + /// Creates a new type variable. + /// + /// - `diverging`: indicates if this is a "diverging" type + /// variable, e.g. one created as the type of a `return` + /// expression. The code in this module doesn't care if a + /// variable is diverging, but the main Rust type-checker will + /// sometimes "unify" such variables with the `!` or `()` types. + /// - `origin`: indicates *why* the type variable was created. + /// The code in this module doesn't care, but it can be useful + /// for improving error messages. pub fn new_var(&mut self, + universe: ty::UniverseIndex, diverging: bool, - origin: TypeVariableOrigin, - default: Option<Default<'tcx>>,) -> 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 { default: default }, - origin, - diverging, - }); - let v = ty::TyVid { index: index as u32 }; - debug!("new_var: diverging={:?} index={:?}", diverging, v); - v + origin: TypeVariableOrigin) + -> ty::TyVid { + let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe }); + + let sub_key = self.sub_relations.new_key(()); + assert_eq!(eq_key.vid, sub_key); + + assert_eq!(self.var_data.len(), sub_key.index as usize); + self.var_data.push(TypeVariableData { origin, diverging }); + + debug!("new_var(index={:?}, diverging={:?}, origin={:?}", eq_key.vid, diverging, origin); + + eq_key.vid } + /// Returns the number of type variables created thus far. pub fn num_vars(&self) -> usize { - self.values.len() + self.var_data.len() } /// Returns the "root" variable of `vid` in the `eq_relations` @@ -199,7 +220,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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) + self.eq_relations.find(vid).vid } /// Returns the "root" variable of `vid` in the `sub_relations` @@ -219,65 +240,58 @@ impl<'tcx> TypeVariableTable<'tcx> { self.sub_root_var(a) == self.sub_root_var(b) } - pub fn probe(&mut self, vid: ty::TyVid) -> Option<Ty<'tcx>> { - 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<Ty<'tcx>> { - debug_assert!(self.root_var(vid) == vid); - match self.values.get(vid.index as usize).value { - Bounded { .. } => None, - Known(t) => Some(t) - } + /// Retrieves the type to which `vid` has been instantiated, if + /// any. + pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { + self.eq_relations.probe_value(vid) } + /// If `t` is a type-inference variable, and it has been + /// instantiated, then return the with which it was + /// instantiated. Otherwise, returns `t`. pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { ty::TyInfer(ty::TyVar(v)) => { match self.probe(v) { - None => t, - Some(u) => u + TypeVariableValue::Unknown { .. } => t, + TypeVariableValue::Known { value } => value, } } _ => t, } } - pub fn snapshot(&mut self) -> Snapshot { + /// Creates a snapshot of the type variable state. This snapshot + /// must later be committed (`commit()`) or rolled back + /// (`rollback_to()`). Nested snapshots are permitted, but must + /// be processed in a stack-like fashion. + pub fn snapshot(&mut self) -> Snapshot<'tcx> { Snapshot { - snapshot: self.values.start_snapshot(), + num_vars: self.var_data.len(), eq_snapshot: self.eq_relations.snapshot(), sub_snapshot: self.sub_relations.snapshot(), } } - pub fn rollback_to(&mut self, s: Snapshot) { - debug!("rollback_to{:?}", { - for action in self.values.actions_since_snapshot(&s.snapshot) { - match *action { - sv::UndoLog::NewElem(index) => { - debug!("inference variable _#{}t popped", index) - } - _ => { } - } - } - }); - - let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.rollback_to(snapshot); + /// Undoes all changes since the snapshot was created. Any + /// snapshots created since that point must already have been + /// committed or rolled back. + pub fn rollback_to(&mut self, s: Snapshot<'tcx>) { + let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s; + debug!("type_variables::rollback_to(num_vars = {})", num_vars); + assert!(self.var_data.len() >= num_vars); self.eq_relations.rollback_to(eq_snapshot); self.sub_relations.rollback_to(sub_snapshot); + self.var_data.truncate(num_vars); } - pub fn commit(&mut self, s: Snapshot) { - let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.commit(snapshot); + /// Commits all changes since the snapshot was created, making + /// them permanent (unless this snapshot was created within + /// another snapshot). Any snapshots created since that point + /// must already have been committed or rolled back. + pub fn commit(&mut self, s: Snapshot<'tcx>) { + let Snapshot { num_vars, eq_snapshot, sub_snapshot } = s; + debug!("type_variables::commit(num_vars = {})", num_vars); self.eq_relations.commit(eq_snapshot); self.sub_relations.commit(sub_snapshot); } @@ -286,90 +300,125 @@ impl<'tcx> TypeVariableTable<'tcx> { /// 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 + pub fn types_created_since_snapshot(&mut self, snapshot: &Snapshot<'tcx>) -> TypeVariableMap { + self.var_data .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) - }) + .enumerate() + .skip(snapshot.num_vars) // skip those that existed when snapshot was taken + .map(|(index, data)| (ty::TyVid { index: index as u32 }, data.origin)) .collect() } - pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec<Ty<'tcx>> { - /*! - * Find the set of type variables that existed *before* `s` - * but which have only been unified since `s` started, and - * return the types with which they were unified. So if we had - * a type variable `V0`, then we started the snapshot, then we - * created a type variable `V1`, unifed `V0` with `T0`, and - * unified `V1` with `T1`, this function would return `{T0}`. - */ - - let mut new_elem_threshold = u32::MAX; - let mut escaping_types = Vec::new(); - let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); - debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); - for action in actions_since_snapshot { - match *action { - sv::UndoLog::NewElem(index) => { - // if any new variables were created during the - // snapshot, remember the lower index (which will - // always be the first one we see). Note that this - // action must precede those variables being - // specified. - new_elem_threshold = min(new_elem_threshold, index as u32); - debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); - } - - 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. - let escaping_type = match self.values.get(vid.index as usize).value { - Bounded { .. } => bug!(), - Known(ty) => ty, - }; - escaping_types.push(escaping_type); - } - debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); - } - - _ => { } - } - } - + /// Find the set of type variables that existed *before* `s` + /// but which have only been unified since `s` started, and + /// return the types with which they were unified. So if we had + /// a type variable `V0`, then we started the snapshot, then we + /// created a type variable `V1`, unifed `V0` with `T0`, and + /// unified `V1` with `T1`, this function would return `{T0}`. + pub fn types_escaping_snapshot(&mut self, snapshot: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> { + // We want to select only those instantiations that have + // occurred since the snapshot *and* which affect some + // variable that existed prior to the snapshot. This code just + // affects all instantiatons that ever occurred which affect + // variables prior to the snapshot. + // + // It's hard to do better than this, though, without changing + // the unification table to prefer "lower" vids -- the problem + // is that we may have a variable X (from before the snapshot) + // and Y (from after the snapshot) which get unified, with Y + // chosen as the new root. Now we are "instantiating" Y with a + // value, but it escapes into X, but we wouldn't readily see + // that. (In fact, earlier revisions of this code had this + // bug; it was introduced when we added the `eq_relations` + // table, but it's hard to create rust code that triggers it.) + // + // We could tell the table to prefer lower vids, and then we would + // see the case above, but we would get less-well-balanced trees. + // + // Since I hope to kill the leak-check in this branch, and + // that's the code which uses this logic anyway, I'm going to + // use the less efficient algorithm for now. + let mut escaping_types = Vec::with_capacity(snapshot.num_vars); + escaping_types.extend( + (0..snapshot.num_vars) // for all variables that pre-exist the snapshot, collect.. + .map(|i| ty::TyVid { index: i as u32 }) + .filter_map(|vid| self.probe(vid).known())); // ..types they are instantiated with. + debug!("types_escaping_snapshot = {:?}", escaping_types); escaping_types } + /// Returns indices of all variables that are not yet + /// instantiated. pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> { - (0..self.values.len()) + (0..self.var_data.len()) .filter_map(|i| { let vid = ty::TyVid { index: i as u32 }; - if self.probe(vid).is_some() { - None - } else { - Some(vid) + match self.probe(vid) { + TypeVariableValue::Unknown { .. } => Some(vid), + TypeVariableValue::Known { .. } => None, } }) .collect() } } +/////////////////////////////////////////////////////////////////////////// -impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { - type Value = TypeVariableData<'tcx>; - type Undo = Instantiate<'tcx>; +/// These structs (a newtyped TyVid) are used as the unification key +/// for the `eq_relations`; they carry a `TypeVariableValue` along +/// with them. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +struct TyVidEqKey<'tcx> { + vid: ty::TyVid, - fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: Instantiate<'tcx>) { - let Instantiate { vid, default } = action; - values[vid.index as usize].value = Bounded { - default, - }; + // in the table, we map each ty-vid to one of these: + phantom: PhantomData<TypeVariableValue<'tcx>>, +} + +impl<'tcx> From<ty::TyVid> for TyVidEqKey<'tcx> { + fn from(vid: ty::TyVid) -> Self { + TyVidEqKey { vid, phantom: PhantomData } + } +} + +impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { + type Value = TypeVariableValue<'tcx>; + fn index(&self) -> u32 { self.vid.index } + fn from_index(i: u32) -> Self { TyVidEqKey::from(ty::TyVid { index: i }) } + fn tag() -> &'static str { "TyVidEqKey" } +} + +impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { + type Error = ut::NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> { + match (value1, value2) { + // We never equate two type variables, both of which + // have known types. Instead, we recursively equate + // those types. + (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => { + bug!("equating two type variables, both of which have known types") + } + + // If one side is known, prefer that one. + (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1), + (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2), + + // If both sides are unknown, we need to pick the most restrictive universe. + (&TypeVariableValue::Unknown { universe: universe1 }, + &TypeVariableValue::Unknown { universe: universe2 }) => { + let universe = cmp::min(universe1, universe2); + Ok(TypeVariableValue::Unknown { universe }) + } + } } } + +/// Raw `TyVid` are used as the unification key for `sub_relations`; +/// they carry no values. +impl ut::UnifyKey for ty::TyVid { + type Value = (); + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } } + fn tag() -> &'static str { "TyVid" } +} + diff --git a/src/librustc/infer/unify_key.rs b/src/librustc/infer/unify_key.rs index d7e3a53ff25c9..24e3aa51e290a 100644 --- a/src/librustc/infer/unify_key.rs +++ b/src/librustc/infer/unify_key.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::ast; -use ty::{self, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::{Combine, UnifyKey}; +use ty::{self, FloatVarValue, IntVarValue, Ty, TyCtxt}; +use rustc_data_structures::unify::{NoError, EqUnifyValue, UnifyKey, UnifyValue}; pub trait ToType { fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; @@ -20,7 +19,10 @@ impl UnifyKey for ty::IntVid { type Value = Option<IntVarValue>; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } - fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" } + fn tag() -> &'static str { "IntVid" } +} + +impl EqUnifyValue for IntVarValue { } #[derive(PartialEq, Copy, Clone, Debug)] @@ -31,15 +33,17 @@ pub struct RegionVidKey { pub min_vid: ty::RegionVid } -impl Combine for RegionVidKey { - fn combine(&self, other: &RegionVidKey) -> RegionVidKey { - let min_vid = if self.min_vid.index < other.min_vid.index { - self.min_vid +impl UnifyValue for RegionVidKey { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { + let min_vid = if value1.min_vid.index < value2.min_vid.index { + value1.min_vid } else { - other.min_vid + value2.min_vid }; - RegionVidKey { min_vid: min_vid } + Ok(RegionVidKey { min_vid: min_vid }) } } @@ -47,7 +51,7 @@ impl UnifyKey for ty::RegionVid { type Value = RegionVidKey; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::RegionVid { ty::RegionVid { index: i } } - fn tag(_: Option<ty::RegionVid>) -> &'static str { "RegionVid" } + fn tag() -> &'static str { "RegionVid" } } impl ToType for IntVarValue { @@ -62,21 +66,17 @@ impl ToType for IntVarValue { // Floating point type keys impl UnifyKey for ty::FloatVid { - type Value = Option<ast::FloatTy>; + type Value = Option<FloatVarValue>; fn index(&self) -> u32 { self.index } fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } - fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" } + fn tag() -> &'static str { "FloatVid" } } -impl ToType for ast::FloatTy { - fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - tcx.mk_mach_float(*self) - } +impl EqUnifyValue for FloatVarValue { } -impl UnifyKey for ty::TyVid { - type Value = (); - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::TyVid { ty::TyVid { index: i } } - fn tag(_: Option<ty::TyVid>) -> &'static str { "TyVid" } +impl ToType for FloatVarValue { + fn to_type<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { + tcx.mk_mach_float(self.0) + } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 498e1aa3520d5..e160c513bc5dc 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -49,6 +49,7 @@ #![feature(inclusive_range_syntax)] #![cfg_attr(windows, feature(libc))] #![feature(macro_vis_matcher)] +#![feature(match_default_bindings)] #![feature(never_type)] #![feature(nonzero)] #![feature(quote)] @@ -56,6 +57,7 @@ #![feature(slice_patterns)] #![feature(specialization)] #![feature(unboxed_closures)] +#![feature(underscore_lifetimes)] #![feature(trace_macros)] #![feature(test)] #![feature(const_atomic_bool_new)] diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 3bcdc4f7e2c63..492dfecbb5d04 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -139,19 +139,22 @@ impl<'tcx> FreeRegionMap<'tcx> { predicates: &[ty::Predicate<'tcx>]) { debug!("relate_free_regions_from_predicates(predicates={:?})", predicates); for predicate in predicates { - match *predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => { + // Ok to skip binders because we are only looking for free + // regions, which are not late bound. + let predicate_atom = predicate.skip_binders(); + + match predicate_atom { + ty::PredicateAtom::Projection(..) | + ty::PredicateAtom::Trait(..) | + ty::PredicateAtom::Subtype(..) | + ty::PredicateAtom::WellFormed(..) | + ty::PredicateAtom::ObjectSafe(..) | + ty::PredicateAtom::ClosureKind(..) | + ty::PredicateAtom::TypeOutlives(..) | + ty::PredicateAtom::ConstEvaluatable(..) => { // No region bounds here } - ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { + ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { self.relate_regions(r_b, r_a); } } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 10a32c26e741d..bc805e85f7baa 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -50,7 +50,9 @@ fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, ' -> ty::ImplHeader<'tcx> { let tcx = selcx.tcx(); - let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); + let impl_substs = selcx.infcx().fresh_substs_for_item(param_env.universe, + DUMMY_SP, + impl_def_id); let header = ty::ImplHeader { impl_def_id, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index e2b23c12cf1f3..74962d2213976 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -20,7 +20,7 @@ use super::{ OutputTypeParameterMismatch, TraitNotObjectSafe, ConstEvalFailure, - PredicateObligation, + PredicateAtomObligation, Reveal, SelectionContext, SelectionError, @@ -36,7 +36,7 @@ use middle::const_val; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; use syntax::ast; -use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, ToPredicate, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -52,14 +52,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { body_id: Option<hir::BodyId>) { #[derive(Debug)] struct ErrorDescriptor<'tcx> { - predicate: ty::Predicate<'tcx>, + predicate: ty::PredicateAtom<'tcx>, index: Option<usize>, // None if this is an old error } let mut error_map : FxHashMap<_, _> = self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| { - (span, predicates.iter().map(|predicate| ErrorDescriptor { - predicate: predicate.clone(), + (span, predicates.iter().map(|&predicate| ErrorDescriptor { + predicate: predicate, index: None }).collect()) }).collect(); @@ -117,8 +117,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e. that // `error` occurring implies that `cond` occurs. fn error_implies(&self, - cond: &ty::Predicate<'tcx>, - error: &ty::Predicate<'tcx>) + cond: &ty::PredicateAtom<'tcx>, + error: &ty::PredicateAtom<'tcx>) -> bool { if cond == error { @@ -126,7 +126,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) + (&ty::PredicateAtom::Trait(..), &ty::PredicateAtom::Trait(error)) => (cond, error), _ => { // FIXME: make this work in other cases too. @@ -134,16 +134,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } }; - for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) { - if let ty::Predicate::Trait(implication) = implication { - let error = error.to_poly_trait_ref(); - let implication = implication.to_poly_trait_ref(); + for implication in super::elaborate_predicates(self.tcx, vec![cond.to_predicate()]) { + if let Some(implication) = implication.poly_trait(self.tcx) { // FIXME: I'm just not taking associated types at all here. // Eventually I'll need to implement param-env-aware // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. + let cause = ObligationCause::dummy(); let param_env = ty::ParamEnv::empty(Reveal::UserFacing); - if let Ok(_) = self.can_sub(param_env, error, implication) { - debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); + if self.at(&cause, param_env).can_instantiate_as(implication, error) { + debug!("error_implies: {:?} => {:?} => {:?}", cond, implication, error); return true } } @@ -152,7 +151,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { false } - fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>, + fn report_fulfillment_error(&self, + error: &FulfillmentError<'tcx>, body_id: Option<hir::BodyId>) { debug!("report_fulfillment_errors({:?})", error); match error.code { @@ -176,7 +176,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn report_projection_error(&self, - obligation: &PredicateObligation<'tcx>, + obligation: &PredicateAtomObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>) { let predicate = @@ -195,12 +195,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. - if let ty::Predicate::Projection(ref data) = predicate { + if let ty::PredicateAtom::Projection(data) = predicate { let mut selcx = SelectionContext::new(self); - let (data, _) = self.replace_late_bound_regions_with_fresh_var( - obligation.cause.span, - infer::LateBoundRegionConversionTime::HigherRankedType, - data); let normalized = super::normalize_projection_type( &mut selcx, obligation.param_env, @@ -271,13 +267,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn impl_similar_to(&self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>) + trait_ref: ty::TraitRef<'tcx>, + obligation: &PredicateAtomObligation<'tcx>) -> Option<DefId> { let tcx = self.tcx; let param_env = obligation.param_env; - let trait_ref = tcx.erase_late_bound_regions(&trait_ref); let trait_self_ty = trait_ref.self_ty(); let mut self_match_impls = vec![]; @@ -285,7 +280,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.for_each_relevant_impl( trait_ref.def_id, trait_self_ty, |def_id| { - let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); + let impl_substs = self.fresh_substs_for_item(param_env.universe, + obligation.cause.span, + def_id); let impl_trait_ref = tcx .impl_trait_ref(def_id) .unwrap() @@ -322,13 +319,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn on_unimplemented_note( &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>) -> + trait_ref: ty::TraitRef<'tcx>, + obligation: &PredicateAtomObligation<'tcx>) -> OnUnimplementedNote { - let def_id = self.impl_similar_to(trait_ref, obligation) - .unwrap_or(trait_ref.def_id()); - let trait_ref = *trait_ref.skip_binder(); + let def_id = self.impl_similar_to(trait_ref, obligation).unwrap_or(trait_ref.def_id); let desugaring; let method; @@ -373,16 +368,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn find_similar_impl_candidates(&self, - trait_ref: ty::PolyTraitRef<'tcx>) + trait_ref: ty::TraitRef<'tcx>) -> Vec<ty::TraitRef<'tcx>> { let simp = fast_reject::simplify_type(self.tcx, - trait_ref.skip_binder().self_ty(), + trait_ref.self_ty(), true); let mut impl_candidates = Vec::new(); match simp { - Some(simp) => self.tcx.for_each_impl(trait_ref.def_id(), |def_id| { + Some(simp) => self.tcx.for_each_impl(trait_ref.def_id, |def_id| { let imp = self.tcx.impl_trait_ref(def_id).unwrap(); let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), @@ -394,7 +389,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } impl_candidates.push(imp); }), - None => self.tcx.for_each_impl(trait_ref.def_id(), |def_id| { + None => self.tcx.for_each_impl(trait_ref.def_id, |def_id| { impl_candidates.push( self.tcx.impl_trait_ref(def_id).unwrap()); }) @@ -460,7 +455,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// that we can give a more helpful error message (and, in particular, /// we do not suggest increasing the overflow limit, which is not /// going to help). - pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + pub fn report_overflow_error_cycle(&self, cycle: &[PredicateAtomObligation<'tcx>]) -> ! { let cycle = self.resolve_type_vars_if_possible(&cycle.to_owned()); assert!(cycle.len() > 0); @@ -520,7 +515,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), - None => Some(format!("{}", parent_trait_ref.0.self_ty())), + None => Some(format!("{}", parent_trait_ref.self_ty())), } } _ => None, @@ -528,7 +523,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn report_selection_error(&self, - obligation: &PredicateObligation<'tcx>, + obligation: &PredicateAtomObligation<'tcx>, error: &SelectionError<'tcx>) { let span = obligation.cause.span; @@ -549,14 +544,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate) => { - let trait_predicate = - self.resolve_type_vars_if_possible(trait_predicate); + ty::PredicateAtom::Trait(ref trait_ref) => { + let trait_ref = self.resolve_type_vars_if_possible(trait_ref); - if self.tcx.sess.has_errors() && trait_predicate.references_error() { + if self.tcx.sess.has_errors() && trait_ref.references_error() { return; } - let trait_ref = trait_predicate.to_poly_trait_ref(); let (post_message, pre_message) = self.get_parent_trait_ref(&obligation.cause.code) .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t))) @@ -582,13 +575,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_label(span, s.as_str()); err.help(&format!("{}the trait `{}` is not implemented for `{}`", pre_message, - trait_ref, + trait_ref.print_without_self(), trait_ref.self_ty())); } else { err.span_label(span, &*format!("{}the trait `{}` is not implemented for `{}`", pre_message, - trait_ref, + trait_ref.print_without_self(), trait_ref.self_ty())); } @@ -603,7 +596,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // "the type `T` can't be frobnicated" // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", - trait_ref.to_predicate())); + trait_ref.to_predicate())); } else if !have_alt_message { // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_ref); @@ -613,33 +606,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err } - ty::Predicate::Subtype(ref predicate) => { + ty::PredicateAtom::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, - obligation.param_env, - &predicate).err().unwrap(); - struct_span_err!(self.tcx.sess, span, E0278, - "the requirement `{}` is not satisfied (`{}`)", - predicate, err) - } - - ty::Predicate::RegionOutlives(ref predicate) => { + ty::PredicateAtom::RegionOutlives(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.region_outlives_predicate(&obligation.cause, - &predicate).err().unwrap(); + obligation.param_env, + predicate).err().unwrap(); struct_span_err!(self.tcx.sess, span, E0279, "the requirement `{}` is not satisfied (`{}`)", predicate, err) } - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { + ty::PredicateAtom::Projection(..) | ty::PredicateAtom::TypeOutlives(..) => { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); struct_span_err!(self.tcx.sess, span, E0280, @@ -647,14 +631,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate) } - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateAtom::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); self.tcx.report_object_safety_error(span, trait_def_id, violations) } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => { let found_kind = self.closure_kind(closure_def_id).unwrap(); let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap(); let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); @@ -693,7 +677,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return; } - ty::Predicate::WellFormed(ty) => { + ty::PredicateAtom::WellFormed(ty) => { // WF predicates cannot themselves make // errors. They can only block due to // ambiguity; otherwise, they always @@ -702,7 +686,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span_bug!(span, "WF predicate not satisfied for {:?}", ty); } - ty::Predicate::ConstEvaluatable(..) => { + ty::PredicateAtom::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, // not `Unimplemented`. @@ -731,7 +715,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { _ => 1, }; let (expected_tys, expected_ty_count) = - match expected_trait_ref.skip_binder().substs.type_at(1).sty { + match expected_trait_ref.substs.type_at(1).sty { ty::TyTuple(ref tys, _) => (tys.iter().map(|t| &t.sty).collect(), tys.len()), ref sty => (vec![sty], 1), @@ -930,11 +914,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, found_span: Option<Span>, expected_ref: ty::PolyTraitRef<'tcx>, - found: ty::PolyTraitRef<'tcx>) + found: ty::TraitRef<'tcx>) -> DiagnosticBuilder<'tcx> { fn build_fn_sig_string<'a, 'gcx, 'tcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, - trait_ref: &ty::TraitRef<'tcx>) -> String { + trait_ref: ty::TraitRef<'tcx>) -> String { let inputs = trait_ref.substs.type_at(1); let sig = if let ty::TyTuple(inputs, _) = inputs.sty { tcx.mk_fn_sig( @@ -963,14 +947,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let found_str = format!( "expected signature of `{}`", - build_fn_sig_string(self.tcx, found.skip_binder()) + build_fn_sig_string(self.tcx, found) ); err.span_label(span, found_str); let found_span = found_span.unwrap_or(span); let expected_str = format!( "found signature of `{}`", - build_fn_sig_string(self.tcx, expected_ref.skip_binder()) + build_fn_sig_string(self.tcx, *expected_ref.skip_binder()) ); err.span_label(found_span, expected_str); @@ -1022,7 +1006,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>, + fn maybe_report_ambiguity(&self, + obligation: &PredicateAtomObligation<'tcx>, body_id: Option<hir::BodyId>) { // Unable to successfully determine, probably means // insufficient type information, but could mean @@ -1043,8 +1028,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } match predicate { - ty::Predicate::Trait(ref data) => { - let trait_ref = data.to_poly_trait_ref(); + ty::PredicateAtom::Trait(trait_ref) => { let self_ty = trait_ref.self_ty(); if predicate.references_error() { return; @@ -1076,7 +1060,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if !self.tcx.sess.has_errors() { if self.tcx.lang_items().sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) + .map_or(false, |sized_id| sized_id == trait_ref.def_id) { self.need_type_info(body_id, span, self_ty); } else { @@ -1091,7 +1075,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - ty::Predicate::WellFormed(ty) => { + ty::PredicateAtom::WellFormed(ty) => { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { @@ -1099,11 +1083,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - ty::Predicate::Subtype(ref data) => { + ty::PredicateAtom::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(); + let &SubtypePredicate { a_is_expected: _, a, b } = data; // 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(body_id, @@ -1130,10 +1114,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// to the type parameters. fn predicate_can_apply(&self, param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitRef<'tcx>) + pred: ty::TraitRef<'tcx>) -> bool { struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>> } @@ -1143,9 +1128,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::TyParam(ty::ParamTy {name, ..}) = ty.sty { let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| - infcx.next_ty_var( - TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, name))) + let param_env = self.param_env; + self.var_map + .entry(ty) + .or_insert_with(|| { + let origin = TypeVariableOrigin::TypeParameterDefinition(DUMMY_SP, + name); + infcx.next_ty_var(param_env.universe, origin) + }) } else { ty.super_fold_with(self) } @@ -1157,6 +1147,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let cleaned_pred = pred.fold_with(&mut ParamToVarFolder { infcx: self, + param_env, var_map: FxHashMap() }); @@ -1277,7 +1268,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); err.note(&format!("required because it appears within the type `{}`", - parent_trait_ref.0.self_ty())); + parent_trait_ref.self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); self.note_obligation_cause_code(err, &parent_predicate, @@ -1287,8 +1278,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); err.note( &format!("required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref, - parent_trait_ref.0.self_ty())); + parent_trait_ref.print_without_self(), + parent_trait_ref.self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); self.note_obligation_cause_code(err, &parent_predicate, diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index cc2506d1afc50..0f13f8209efe8 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::{InferCtxt, InferOk}; -use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; +use infer::InferCtxt; +use ty::{self, Ty, TypeFoldable, ToPredicate}; use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; @@ -22,13 +22,13 @@ use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; use super::{FulfillmentError, FulfillmentErrorCode}; -use super::{ObligationCause, PredicateObligation, Obligation}; +use super::{ObligationCause, PredicateAtomObligation, PredicateObligation, Obligation}; use super::project; use super::select::SelectionContext; use super::{Unimplemented, ConstEvalFailure}; -impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { - type Predicate = ty::Predicate<'tcx>; +impl<'tcx> ForestObligation for PendingPredicateAtomObligation<'tcx> { + type Predicate = ty::PredicateAtom<'tcx>; fn as_predicate(&self) -> &Self::Predicate { &self.obligation.predicate } } @@ -47,7 +47,43 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { pub struct FulfillmentContext<'tcx> { // A list of all obligations that have been registered with this // fulfillment context. - predicates: ObligationForest<PendingPredicateObligation<'tcx>>, + predicates: ObligationForest<PendingPredicateAtomObligation<'tcx>>, + + // A set of predicates that are useful for inferring closure signatures. + // + // We are looking to help out with a scenario like this: + // + // ``` + // foo(|x| use(*x)) + // + // fn foo<T>(t: T) where T: FnMut(&u32) { .. } + // ``` + // + // In this case, in the expression `foo(|x| use(*x))`, the type + // variable `T` is first instantiated with an inference variable + // `?T` (as part of the subexpression `foo`) and the obligation + // that `?T: FnMut(&u32)` is registered; actually, a few + // obligations get registered, but the most helpful thing is a + // projection predicate `for<'a> <?T as FnMut<(&'a u32,)>>::Output + // = ()`. We then typecheck the arguments. The closure expression + // `|x|` gets that its expected type is `?T`, but that does not + // tell it anything about its expected signature. To solve this, + // it needs to trawl through the list of pending prediates. That's + // where this vector comes in. + // + // This vector stores a copy of predicate that gets registered where the + // following conditions are met: + // + // 0. The predicate is in universe 0. + // 1. The self-type is an uninstantiated type variable. + // 2. It is a projection or trait-ref of a closure trait. + // + // We periodically prune out cases where the self-type got + // instantiated, as they are no longer of potential use. + // + // Closures can read the current state via the + // `pending_closure_predicates()` accessor. + pending_closure_predicates: Vec<ty::Predicate<'tcx>>, // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must @@ -78,14 +114,15 @@ pub struct FulfillmentContext<'tcx> { #[derive(Clone)] pub struct RegionObligation<'tcx> { + pub param_env: ty::ParamEnv<'tcx>, pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, pub cause: ObligationCause<'tcx>, } #[derive(Clone, Debug)] -pub struct PendingPredicateObligation<'tcx> { - pub obligation: PredicateObligation<'tcx>, +pub struct PendingPredicateAtomObligation<'tcx> { + pub obligation: PredicateAtomObligation<'tcx>, pub stalled_on: Vec<Ty<'tcx>>, } @@ -95,6 +132,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), region_obligations: NodeMap(), + pending_closure_predicates: vec![], } } @@ -158,31 +196,82 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } pub fn register_region_obligation(&mut self, + param_env: ty::ParamEnv<'tcx>, t_a: Ty<'tcx>, r_b: ty::Region<'tcx>, cause: ObligationCause<'tcx>) { - register_region_obligation(t_a, r_b, cause, &mut self.region_obligations); + register_region_obligation(param_env, t_a, r_b, cause, &mut self.region_obligations); } pub fn register_predicate_obligation(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>) + { + // Important: record closure predicates *before* we skolemize! + // Otherwise it is too late to recover binding information. + self.record_closure_predicate_if_relevant(infcx, &obligation); + + let atom_obligation = infcx.skolemize_predicate_obligation(&obligation); + self.register_predicate_atom_obligation(infcx, atom_obligation); + } + + fn register_predicate_atom_obligation(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligation: PredicateAtomObligation<'tcx>) { // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. let obligation = infcx.resolve_type_vars_if_possible(&obligation); - debug!("register_predicate_obligation(obligation={:?})", obligation); + debug!("register_predicate_atom_obligation(obligation={:?})", obligation); assert!(!infcx.is_in_snapshot()); - self.predicates.register_obligation(PendingPredicateObligation { + self.predicates.register_obligation(PendingPredicateAtomObligation { obligation, stalled_on: vec![] }); } + fn record_closure_predicate_if_relevant(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligation: &PredicateObligation<'tcx>) { + if obligation.param_env.universe != ty::UniverseIndex::ROOT { + return; + } + + if Self::is_closure_predicate(infcx, &obligation.predicate) { + // Don't let the vector keep growing without bound: clear + // out anything that is no longer relevant. + self.pending_closure_predicates.retain(|p| Self::is_closure_predicate(infcx, p)); + self.pending_closure_predicates.push(obligation.predicate); + } + } + + fn is_closure_predicate(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + predicate: &ty::Predicate<'tcx>) + -> bool + { + // OK to skip binder. We are just looking for a (free) type + // variable. + let self_ty = match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_ref) => trait_ref.self_ty(), + ty::PredicateAtom::Projection(proj) => proj.to_trait_ref(infcx.tcx).self_ty(), + _ => return false, + }; + + // Not a type variable? Then not a closure predicate. + if !self_ty.is_ty_var() { + return false; + } + + // If it is a type variable, check if it has been resolved + // already. If so, no longer of interest. + let self_ty = infcx.shallow_resolve(self_ty); + self_ty.is_ty_var() + } + pub fn register_predicate_obligations(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligations: Vec<PredicateObligation<'tcx>>) @@ -229,8 +318,15 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { self.select(&mut selcx) } - pub fn pending_obligations(&self) -> Vec<PendingPredicateObligation<'tcx>> { - self.predicates.pending_obligations() + /// Returns the list of closure obligations that we have seen + /// which are yet pending (meaning that their self type has not + /// yet been seen to be resolved to a specific closure type, and + /// hence they may still be of use). + /// + /// See the comment on the field `pending_closure_predicates` for + /// more information. + pub fn pending_closure_predicates(&self) -> &[ty::Predicate<'tcx>] { + &self.pending_closure_predicates } /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it @@ -281,25 +377,41 @@ struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { } impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> { - type Obligation = PendingPredicateObligation<'tcx>; + type Obligation = PendingPredicateAtomObligation<'tcx>; type Error = FulfillmentErrorCode<'tcx>; fn process_obligation(&mut self, obligation: &mut Self::Obligation) -> Result<Option<Vec<Self::Obligation>>, Self::Error> { - process_predicate(self.selcx, - obligation, - self.region_obligations) - .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { - obligation: o, - stalled_on: vec![] - }).collect())) + let opt_obligations = process_predicate(self.selcx, obligation, self.region_obligations)?; + + // Return Ok(None) if we failed to make any progress. + let obligations = match opt_obligations { + None => return Ok(None), + Some(vec) => vec, + }; + + // To start, we have to fully skolemize all the + // subobligations, removing any higher-ranked bindings. + let atom_obligations = obligations.iter().map(|obligation| { + self.selcx.infcx().skolemize_predicate_obligation(obligation) + }); + + // Next, convert them into "pending obligations" that are not yet stalled on anything. + let pending_obligations = atom_obligations.map(|atom_obligation| { + PendingPredicateAtomObligation { + obligation: atom_obligation, + stalled_on: vec![], + } + }); + + Ok(Some(pending_obligations.collect())) } fn process_backedge<'c, I>(&mut self, cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>) - where I: Clone + Iterator<Item=&'c PendingPredicateObligation<'tcx>>, + _marker: PhantomData<&'c PendingPredicateAtomObligation<'tcx>>) + where I: Clone + Iterator<Item=&'c PendingPredicateAtomObligation<'tcx>>, { if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { debug!("process_child_obligations: coinductive match"); @@ -312,10 +424,9 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, /// Return the set of type variables contained in a trait ref fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, - t: ty::PolyTraitRef<'tcx>) -> Vec<Ty<'tcx>> + t: ty::TraitRef<'tcx>) -> Vec<Ty<'tcx>> { - t.skip_binder() // ok b/c this check doesn't care about regions - .input_types() + t.input_types() .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) @@ -329,7 +440,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't /// - `Err` if the predicate does not hold fn process_predicate<'a, 'gcx, 'tcx>( selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, - pending_obligation: &mut PendingPredicateObligation<'tcx>, + pending_obligation: &mut PendingPredicateAtomObligation<'tcx>, region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>) -> Result<Option<Vec<PredicateObligation<'tcx>>>, FulfillmentErrorCode<'tcx>> @@ -357,19 +468,20 @@ fn process_predicate<'a, 'gcx, 'tcx>( } match obligation.predicate { - ty::Predicate::Trait(ref data) => { - let trait_obligation = obligation.with(data.clone()); + ty::PredicateAtom::Trait(trait_ref) => { + let trait_obligation = obligation.with(trait_ref); - if data.is_global() { + if trait_ref.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. if // make defaulted unit go through the slow path for better warnings, // please remove this when the warnings are removed. - !trait_obligation.predicate.skip_binder().self_ty().is_defaulted_unit() && - selcx.evaluate_obligation_conservatively(&obligation) { + !trait_obligation.predicate.self_ty().is_defaulted_unit() && + selcx.evaluate_obligation_conservatively(&obligation) + { debug!("selecting trait `{:?}` at depth {} evaluated to holds", - data, obligation.recursion_depth); + trait_ref, obligation.recursion_depth); return Ok(Some(vec![])) } } @@ -377,12 +489,12 @@ fn process_predicate<'a, 'gcx, 'tcx>( match selcx.select(&trait_obligation) { Ok(Some(vtable)) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)", - data, obligation.recursion_depth); - Ok(Some(vtable.nested_obligations())) + trait_ref, obligation.recursion_depth); + Ok(Some(vtable.into_nested_obligations())) } Ok(None) => { debug!("selecting trait `{:?}` at depth {} yielded Ok(None)", - data, obligation.recursion_depth); + trait_ref, obligation.recursion_depth); // This is a bit subtle: for the most part, the // only reason we can fail to make progress on @@ -397,8 +509,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( // the same time. // // FIXME(#32286) logic seems false if no upvars - pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref()); + pending_obligation.stalled_on = trait_ref_type_vars(selcx, trait_ref); debug!("process_predicate: pending obligation {:?} now stalled on {:?}", selcx.infcx().resolve_type_vars_if_possible(obligation), @@ -408,74 +519,38 @@ fn process_predicate<'a, 'gcx, 'tcx>( } Err(selection_err) => { info!("selecting trait `{:?}` at depth {} yielded Err", - data, obligation.recursion_depth); + trait_ref, obligation.recursion_depth); Err(CodeSelectionError(selection_err)) } } } - ty::Predicate::Equate(ref binder) => { - match selcx.infcx().equality_predicate(&obligation.cause, - obligation.param_env, - binder) { - Ok(InferOk { obligations, value: () }) => { - Ok(Some(obligations)) - }, - Err(_) => Err(CodeSelectionError(Unimplemented)), - } - } - - ty::Predicate::RegionOutlives(ref binder) => { - match selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { + ty::PredicateAtom::RegionOutlives(data) => { + match selcx.infcx().region_outlives_predicate(&obligation.cause, + obligation.param_env, + data) { Ok(()) => Ok(Some(Vec::new())), Err(_) => Err(CodeSelectionError(Unimplemented)), } } - ty::Predicate::TypeOutlives(ref binder) => { - // Check if there are higher-ranked regions. - match selcx.tcx().no_late_bound_regions(binder) { - // If there are, inspect the underlying type further. - None => { - // Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`. - let binder = binder.map_bound_ref(|pred| pred.0); - - // Check if the type has any bound regions. - match selcx.tcx().no_late_bound_regions(&binder) { - // If so, this obligation is an error (for now). Eventually we should be - // able to support additional cases here, like `for<'a> &'a str: 'a`. - None => { - Err(CodeSelectionError(Unimplemented)) - } - // Otherwise, we have something of the form - // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. - Some(t_a) => { - let r_static = selcx.tcx().types.re_static; - register_region_obligation(t_a, r_static, - obligation.cause.clone(), - region_obligations); - Ok(Some(vec![])) - } - } - } - // If there aren't, register the obligation. - Some(ty::OutlivesPredicate(t_a, r_b)) => { - register_region_obligation(t_a, r_b, - obligation.cause.clone(), - region_obligations); - Ok(Some(vec![])) - } - } + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => { + register_region_obligation(obligation.param_env, + t_a, + r_b, + obligation.cause.clone(), + region_obligations); + Ok(Some(vec![])) } - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(selcx, &project_obligation) { + ty::PredicateAtom::Projection(data) => { + let project_obligation = obligation.with(data); + match project::project_and_unify_type(selcx, &project_obligation) { Ok(None) => { let tcx = selcx.tcx(); pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref(tcx)); + trait_ref_type_vars(selcx, data.to_trait_ref(tcx)); Ok(None) } Ok(v) => Ok(v), @@ -483,7 +558,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateAtom::ObjectSafe(trait_def_id) => { if !selcx.tcx().is_object_safe(trait_def_id) { Err(CodeSelectionError(Unimplemented)) } else { @@ -491,7 +566,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => { match selcx.infcx().closure_kind(closure_def_id) { Some(closure_kind) => { if closure_kind.extends(kind) { @@ -506,11 +581,12 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } - ty::Predicate::WellFormed(ty) => { + ty::PredicateAtom::WellFormed(ty) => { match ty::wf::obligations(selcx.infcx(), obligation.param_env, obligation.cause.body_id, - ty, obligation.cause.span) { + ty, + obligation.cause.span) { None => { pending_obligation.stalled_on = vec![ty]; Ok(None) @@ -519,29 +595,28 @@ fn process_predicate<'a, 'gcx, 'tcx>( } } - ty::Predicate::Subtype(ref subtype) => { + ty::PredicateAtom::Subtype(subtype) => { match selcx.infcx().subtype_predicate(&obligation.cause, obligation.param_env, subtype) { None => { // none means that both are unresolved - pending_obligation.stalled_on = vec![subtype.skip_binder().a, - subtype.skip_binder().b]; + pending_obligation.stalled_on = vec![subtype.a, subtype.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); + let expected_found = ExpectedFound::new(subtype.a_is_expected, + subtype.a, + subtype.b); Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) } } } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { match selcx.tcx().lift_to_global(&obligation.param_env) { None => { Ok(None) @@ -567,14 +642,16 @@ fn process_predicate<'a, 'gcx, 'tcx>( } -fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, +fn register_region_obligation<'tcx>(param_env: ty::ParamEnv<'tcx>, + t_a: Ty<'tcx>, r_b: ty::Region<'tcx>, cause: ObligationCause<'tcx>, region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>) { - let region_obligation = RegionObligation { sup_type: t_a, - sub_region: r_b, - cause: cause }; + let region_obligation = RegionObligation { param_env, + cause, + sup_type: t_a, + sub_region: r_b }; debug!("register_region_obligation({:?}, cause={:?})", region_obligation, region_obligation.cause); @@ -586,7 +663,7 @@ fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, } fn to_fulfillment_error<'tcx>( - error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>) + error: Error<PendingPredicateAtomObligation<'tcx>, FulfillmentErrorCode<'tcx>>) -> FulfillmentError<'tcx> { let obligation = error.backtrace.into_iter().next().unwrap().obligation; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c08fe187f99bf..eb83816f7524e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -21,7 +21,7 @@ use middle::const_val::ConstEvalErr; use middle::region; use middle::free_region::FreeRegionMap; use ty::subst::Substs; -use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate}; +use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, ToPredicate, ToPredicateAtom}; use ty::error::{ExpectedFound, TypeError}; use infer::{InferCtxt}; @@ -68,14 +68,27 @@ mod util; /// scope. The eventual result is usually a `Selection` (defined below). #[derive(Clone, PartialEq, Eq)] pub struct Obligation<'tcx, T> { + /// Why do we have to prove this thing? pub cause: ObligationCause<'tcx>, + + /// In which environment should we prove this thing? pub param_env: ty::ParamEnv<'tcx>, - pub recursion_depth: usize, + + /// What are we trying to prove? pub predicate: T, + + /// If we started proving this as a result of trying to prove + /// something else, track the total depth to ensure termination. + /// If this goes over a certain threshold, we abort compilation -- + /// in such cases, we can not say whether or not the predicate + /// holds for certain. Stupid halting problem. Such a drag. + pub recursion_depth: usize, } pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; +pub type PredicateAtomObligation<'tcx> = Obligation<'tcx, ty::PredicateAtom<'tcx>>; +pub type PolyTraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitRef<'tcx>>; +pub type TraitObligation<'tcx> = Obligation<'tcx, ty::TraitRef<'tcx>>; /// Why did we incur this obligation? Used for error reporting. #[derive(Clone, Debug, PartialEq, Eq)] @@ -200,7 +213,7 @@ pub struct DerivedObligationCause<'tcx> { /// current obligation. Note that only trait obligations lead to /// derived obligations, so we just store the trait reference here /// directly. - parent_trait_ref: ty::PolyTraitRef<'tcx>, + parent_trait_ref: ty::TraitRef<'tcx>, /// The parent trait had this cause parent_code: Rc<ObligationCauseCode<'tcx>> @@ -208,7 +221,6 @@ pub struct DerivedObligationCause<'tcx> { pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>; pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; -pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>; pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; @@ -216,14 +228,14 @@ pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; pub enum SelectionError<'tcx> { Unimplemented, OutputTypeParameterMismatch(ty::PolyTraitRef<'tcx>, - ty::PolyTraitRef<'tcx>, + ty::TraitRef<'tcx>, ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), ConstEvalFailure(ConstEvalErr<'tcx>), } pub struct FulfillmentError<'tcx> { - pub obligation: PredicateObligation<'tcx>, + pub obligation: PredicateAtomObligation<'tcx>, pub code: FulfillmentErrorCode<'tcx> } @@ -418,11 +430,10 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx param_env, cause: ObligationCause::misc(span, ast::DUMMY_NODE_ID), recursion_depth: 0, - predicate: trait_ref.to_predicate(), + predicate: trait_ref.to_predicate_atom(), }; - let result = SelectionContext::new(infcx) - .evaluate_obligation_conservatively(&obligation); + let result = SelectionContext::new(infcx).evaluate_obligation_conservatively(&obligation); debug!("type_known_to_meet_ty={:?} bound={} => {:?}", ty, infcx.tcx.item_path_str(def_id), result); @@ -509,7 +520,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, predicates); let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), - unnormalized_env.reveal); + unnormalized_env.reveal, + unnormalized_env.universe); tcx.infer_ctxt().enter(|infcx| { let predicates = match fully_normalize( @@ -562,7 +574,9 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: resolved predicates={:?}", predicates); - ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), + unnormalized_env.reveal, + unnormalized_env.universe) }) } @@ -701,6 +715,77 @@ fn vtable_methods<'a, 'tcx>( ) } +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + /// A kind of specialized routine that takes a given trait-ref and + /// tries to "select" a vtable that implements it. Can return in + /// one of three possible states: + /// + /// - Success: returns the vtable that we selected for this + /// trait-ref. This vtable contains pending predicates that were not + /// yet proven to hold. If this operation is not inside of a + /// snapshot, or is inside a snapshot that is committed, those + /// pending predicates should be registered in some enclosing + /// fufillment cx. (If we *are* in a snapshot, and that snapshot + /// is rolled-back, then the predicates can be discarded.) + /// + /// - Ambiguity: if `None` is returned, then the trait-ref could not + /// be selected. Try again some other time. + /// + /// - Error: selecting the trait-ref led to an error. If this + /// operation is inside of a snapshot, and that snapshot is + /// rolled back, then these errors can be discarded. Otherwise, + /// they should be reported to the user. + /// + /// NB. In the success/error case, unless this method is invoked + /// in a snapshot that is rolled back, you *must* process the + /// return value appropriately or it could lead to incorrect + /// compilations or ICEs. In particular, it could mess with the + /// projection cache, which assumes that subobligations will be + /// fully processed and errors will be reported. + pub fn select_trait_ref(&self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + trait_ref: ty::TraitRef<'tcx>) + -> Result<Option<Selection<'tcx>>, Vec<FulfillmentError<'tcx>>> + { + debug!("trait_ref(trait_ref={:?}, param_env={:?})", trait_ref, param_env); + + let obligation = Obligation::new(cause, param_env, trait_ref); + + let mut selcx = SelectionContext::new(self); + selcx.select(&obligation).map_err(|e| { + vec![FulfillmentError { + obligation: obligation.with(trait_ref.to_predicate_atom()), + code: FulfillmentErrorCode::CodeSelectionError(e), + }] + }) + } + + pub fn select_poly_trait_ref(&self, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + poly_trait_ref: ty::PolyTraitRef<'tcx>) + -> Result<Option<Selection<'tcx>>, Vec<FulfillmentError<'tcx>>> + { + let (trait_ref, param_env, _skol_map) = + self.skolemize_late_bound_regions(param_env, &poly_trait_ref); + + self.select_trait_ref(cause, param_env, trait_ref) + } +} + +impl<'tcx> PredicateObligation<'tcx> { + pub fn from<O>(cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + predicate: O) + -> Self + where O: ToPredicate<'tcx> + { + let predicate = predicate.to_predicate(); + Obligation { cause, param_env, recursion_depth: 0, predicate } + } +} + impl<'tcx,O> Obligation<'tcx,O> { pub fn new(cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -733,6 +818,10 @@ impl<'tcx,O> Obligation<'tcx,O> { recursion_depth: self.recursion_depth, predicate: value } } + + pub fn with_env(self, param_env: ty::ParamEnv<'tcx>) -> Obligation<'tcx, O> { + Obligation { param_env, ..self } + } } impl<'tcx> ObligationCause<'tcx> { @@ -753,7 +842,7 @@ impl<'tcx> ObligationCause<'tcx> { } impl<'tcx, N> Vtable<'tcx, N> { - pub fn nested_obligations(self) -> Vec<N> { + pub fn into_nested_obligations(self) -> Vec<N> { match self { VtableImpl(i) => i.nested, VtableParam(n) => n, @@ -766,16 +855,16 @@ impl<'tcx, N> Vtable<'tcx, N> { } } - fn nested_obligations_mut(&mut self) -> &mut Vec<N> { - match self { - &mut VtableImpl(ref mut i) => &mut i.nested, - &mut VtableParam(ref mut n) => n, - &mut VtableBuiltin(ref mut i) => &mut i.nested, - &mut VtableAutoImpl(ref mut d) => &mut d.nested, - &mut VtableGenerator(ref mut c) => &mut c.nested, - &mut VtableClosure(ref mut c) => &mut c.nested, - &mut VtableObject(ref mut d) => &mut d.nested, - &mut VtableFnPointer(ref mut d) => &mut d.nested, + pub fn nested_obligations(&self) -> &[N] { + match *self { + VtableImpl(ref i) => &i.nested, + VtableParam(ref n) => &n, + VtableBuiltin(ref i) => &i.nested, + VtableAutoImpl(ref d) => &d.nested, + VtableClosure(ref c) => &c.nested, + VtableGenerator(ref c) => &c.nested, + VtableObject(ref d) => &d.nested, + VtableFnPointer(ref d) => &d.nested, } } @@ -818,7 +907,7 @@ impl<'tcx, N> Vtable<'tcx, N> { } impl<'tcx> FulfillmentError<'tcx> { - fn new(obligation: PredicateObligation<'tcx>, + fn new(obligation: PredicateAtomObligation<'tcx>, code: FulfillmentErrorCode<'tcx>) -> FulfillmentError<'tcx> { @@ -827,8 +916,12 @@ impl<'tcx> FulfillmentError<'tcx> { } impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> ty::Binder<Ty<'tcx>> { - ty::Binder(self.predicate.skip_binder().self_ty()) + fn def_id(&self) -> DefId { + self.predicate.def_id + } + + fn self_ty(&self) -> Ty<'tcx> { + self.predicate.self_ty() } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1e9816095ea2e..f871892429c96 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -85,6 +85,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn astconv_object_safety_violations(self, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> { + debug!("astconv_object_safety_violations(trait_def_id={:?})", trait_def_id); + let mut violations = vec![]; for def_id in traits::supertrait_def_ids(self, trait_def_id) { @@ -93,7 +95,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", + debug!("astconv_object_safety_violations: trait_def_id={:?} violations={:?}", trait_def_id, violations); @@ -155,22 +157,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { predicates .predicates .into_iter() - .map(|predicate| predicate.subst_supertrait(self, &trait_ref)) + .map(|predicate| predicate.subst_supertrait(self, trait_ref)) .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref data) => { + // We can safely skip binders because `Self` type would not be bound by them. + match predicate.skip_binders() { + ty::PredicateAtom::Trait(ref data) => { // In the case of a trait predicate, we can skip the "self" type. - data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty()) + data.input_types().skip(1).any(|t| t.has_self_ty()) } - ty::Predicate::Projection(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::Equate(..) | - ty::Predicate::ConstEvaluatable(..) => { + ty::PredicateAtom::Projection(..) | + ty::PredicateAtom::WellFormed(..) | + ty::PredicateAtom::ObjectSafe(..) | + ty::PredicateAtom::TypeOutlives(..) | + ty::PredicateAtom::RegionOutlives(..) | + ty::PredicateAtom::ClosureKind(..) | + ty::PredicateAtom::Subtype(..) | + ty::PredicateAtom::ConstEvaluatable(..) => { false } } @@ -184,7 +186,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { fn generics_require_sized_self(self, def_id: DefId) -> bool { let sized_def_id = match self.lang_items().sized_trait() { Some(def_id) => def_id, - None => { return false; /* No Sized trait, can't require it! */ } + None => return false, // No Sized trait, can't require it! }; // Search for a predicate like `Self : Sized` amongst the trait bounds. @@ -192,20 +194,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let predicates = predicates.instantiate_identity(self).predicates; elaborate_predicates(self, predicates) .any(|predicate| { - match predicate { - ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - trait_pred.0.self_ty().is_self() - } - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => { + // We can skip the binder here because our test is not + // related to bound regions. + match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_ref) => + trait_ref.def_id == sized_def_id && trait_ref.self_ty().is_self(), + ty::PredicateAtom::Projection(..) | + ty::PredicateAtom::Subtype(..) | + ty::PredicateAtom::RegionOutlives(..) | + ty::PredicateAtom::WellFormed(..) | + ty::PredicateAtom::ObjectSafe(..) | + ty::PredicateAtom::ClosureKind(..) | + ty::PredicateAtom::TypeOutlives(..) | + ty::PredicateAtom::ConstEvaluatable(..) => { false } } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 9c56df058c3dd..4d9c17feff84f 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -25,14 +25,16 @@ use super::VtableImplData; use super::util; use hir::def_id::DefId; -use infer::{InferCtxt, InferOk}; +use infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime}; use infer::type_variable::TypeVariableOrigin; use middle::const_val::ConstVal; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::symbol::Symbol; -use ty::subst::{Subst, Substs}; -use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; +use ty::subst::Substs; +use ty::{self, ToPredicate, Ty, TyCtxt}; +use ty::error::TypeError; use ty::fold::{TypeFoldable, TypeFolder}; +use ty::subst::Subst; use util::common::FN_OUTPUT_NAME; /// Depending on the stage of compilation, we want projection to be @@ -77,9 +79,6 @@ pub enum Reveal { All, } -pub type PolyProjectionObligation<'tcx> = - Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; - pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; @@ -118,50 +117,12 @@ struct ProjectionTyCandidateSet<'tcx> { ambiguous: bool } -/// Evaluates constraints of the form: -/// -/// for<...> <T as Trait>::U == V -/// -/// If successful, this may result in additional obligations. Also returns -/// the projection cache key used to track these additional obligations. -pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, - obligation: &PolyProjectionObligation<'tcx>) - -> Result<Option<Vec<PredicateObligation<'tcx>>>, - MismatchedProjectionTypes<'tcx>> -{ - debug!("poly_project_and_unify_type(obligation={:?})", - obligation); - - let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { - let (skol_predicate, skol_map) = - infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); - - let skol_obligation = obligation.with(skol_predicate); - let r = match project_and_unify_type(selcx, &skol_obligation) { - Ok(result) => { - let span = obligation.cause.span; - match infcx.leak_check(false, span, &skol_map, snapshot) { - Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, result)), - Err(e) => Err(MismatchedProjectionTypes { err: e }), - } - } - Err(e) => { - Err(e) - } - }; - - r - }) -} - /// Evaluates constraints of the form: /// /// <T as Trait>::U == V /// /// If successful, this may result in additional obligations. -fn project_and_unify_type<'cx, 'gcx, 'tcx>( +pub(in traits) fn project_and_unify_type<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionObligation<'tcx>) -> Result<Option<Vec<PredicateObligation<'tcx>>>, @@ -404,6 +365,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( let tcx = selcx.infcx().tcx; let def_id = projection_ty.item_def_id; let ty_var = selcx.infcx().next_ty_var( + param_env.universe, TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); let projection = ty::Binder(ty::ProjectionPredicate { projection_ty, @@ -627,7 +589,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, let mut obligations: Vec<_> = result.obligations .iter() - .filter(|obligation| match obligation.predicate { + .filter(|obligation| match obligation.predicate.skip_binders() { // We found a `T: Foo<X = U>` predicate, let's check // if `U` references any unresolved type // variables. In principle, we only care if this @@ -637,8 +599,8 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, // indirect obligations (e.g., we project to `?0`, // but we have `T: Foo<X = ?1>` and `?1: Bar<X = // ?0>`). - ty::Predicate::Projection(ref data) => - infcx.any_unresolved_type_vars(&data.ty()), + ty::PredicateAtom::Projection(ref data) => + infcx.any_unresolved_type_vars(&data.ty), // We are only interested in `T: Foo<X = U>` predicates, whre // `U` references one of `unresolved_type_vars`. =) @@ -682,7 +644,7 @@ fn push_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, depth: usize, result: &mut NormalizedTy<'tcx>) { - let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); + let trait_ref = projection_ty.trait_ref(infcx.tcx); let trait_obligation = Obligation { cause, recursion_depth: depth, param_env, @@ -716,7 +678,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc depth: usize) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); + let trait_ref = projection_ty.trait_ref(selcx.tcx()); let trait_obligation = Obligation { cause, recursion_depth: depth, param_env, @@ -724,6 +686,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc let tcx = selcx.infcx().tcx; let def_id = projection_ty.item_def_id; let new_value = selcx.infcx().next_ty_var( + param_env.universe, TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); Normalized { value: new_value, @@ -781,7 +744,7 @@ fn project_type<'cx, 'gcx, 'tcx>( selcx.infcx().report_overflow_error(&obligation, true); } - let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); + let obligation_trait_ref = obligation.predicate.trait_ref(selcx.tcx()); debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); @@ -796,17 +759,16 @@ fn project_type<'cx, 'gcx, 'tcx>( assemble_candidates_from_param_env(selcx, obligation, - &obligation_trait_ref, &mut candidates); assemble_candidates_from_trait_def(selcx, obligation, - &obligation_trait_ref, + obligation_trait_ref, &mut candidates); if let Err(e) = assemble_candidates_from_impls(selcx, obligation, - &obligation_trait_ref, + obligation_trait_ref, &mut candidates) { return Err(ProjectionTyError::TraitSelectionError(e)); } @@ -867,7 +829,7 @@ fn project_type<'cx, 'gcx, 'tcx>( Ok(ProjectedTy::Progress( confirm_candidate(selcx, obligation, - &obligation_trait_ref, + obligation_trait_ref, candidate))) } None => Ok(ProjectedTy::NoProgress( @@ -883,13 +845,11 @@ fn project_type<'cx, 'gcx, 'tcx>( fn assemble_candidates_from_param_env<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) { debug!("assemble_candidates_from_param_env(..)"); assemble_candidates_from_predicates(selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::ParamEnv, obligation.param_env.caller_bounds.iter().cloned()); @@ -908,7 +868,7 @@ fn assemble_candidates_from_param_env<'cx, 'gcx, 'tcx>( fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, + obligation_trait_ref: ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) { debug!("assemble_candidates_from_trait_def(..)"); @@ -935,7 +895,6 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( let bounds = elaborate_predicates(tcx, bounds.predicates); assemble_candidates_from_predicates(selcx, obligation, - obligation_trait_ref, candidate_set, ProjectionTyCandidate::TraitDef, bounds) @@ -944,7 +903,6 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, env_predicates: I) @@ -953,52 +911,90 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); let infcx = selcx.infcx(); - for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", - predicate); - match predicate { - ty::Predicate::Projection(ref data) => { - let same_def_id = - data.0.projection_ty.item_def_id == obligation.predicate.item_def_id; - - let is_match = same_def_id && infcx.probe(|_| { - let data_poly_trait_ref = - data.to_poly_trait_ref(infcx.tcx); - let obligation_poly_trait_ref = - obligation_trait_ref.to_poly_trait_ref(); - infcx.at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() - }); - - debug!("assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id); - - if is_match { - candidate_set.vec.push(ctor(data.clone())); - } + + let env_predicates = env_predicates.into_iter() + .filter_map(|p| filter_env_predicate(infcx, obligation, p)) + .filter(|&p| can_unify_env_predicate(infcx, obligation, p)); + for env_predicate in env_predicates { + infcx.probe(|_| { + if unify_env_predicate(infcx, obligation, env_predicate).is_ok() { + debug!("assemble_candidates_from_predicates: env_predicate={:?} matched", + env_predicate); + candidate_set.vec.push(ctor(env_predicate)); } - _ => { } + }); + } +} + +/// Quickly tests whether a given predicate from the environment MAY +/// satisfy `obligation`. If so, returns `Some(_)` with a +/// poly-projection. +fn filter_env_predicate<'cx, 'gcx, 'tcx>( + infcx: &InferCtxt<'cx, 'gcx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + env_predicate: ty::Predicate<'tcx>) + -> Option<ty::PolyProjectionPredicate<'tcx>> +{ + if let Some(env_projection) = env_predicate.poly_projection(infcx.tcx) { + if obligation.predicate.item_def_id == env_projection.item_def_id() { + return Some(env_projection); } } + None +} + +/// Tests whether we can unify `env_predicate` to satisfy `obligation`. +fn can_unify_env_predicate<'cx, 'gcx, 'tcx>( + infcx: &InferCtxt<'cx, 'gcx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + env_projection: ty::PolyProjectionPredicate<'tcx>) + -> bool +{ + infcx.probe(|_| unify_env_predicate(infcx, obligation, env_projection).is_ok()) +} + +/// Uses `env_predicate` to satisfy `obligation`, if possible. +fn unify_env_predicate<'cx, 'gcx, 'tcx>( + infcx: &InferCtxt<'cx, 'gcx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + env_projection: ty::PolyProjectionPredicate<'tcx>) + -> InferResult<'tcx, Ty<'tcx>> +{ + // Quick sanity check. + if obligation.predicate.item_def_id != env_projection.item_def_id() { + return Err(TypeError::Mismatch); + } + + // The `env_projection` may be wrapped in binders. Instantiate + // those binders with variables and then extract the results. + let (ty::ProjectionPredicate { projection_ty: env_projection_ty, ty: env_ty }, _) = + infcx.replace_late_bound_regions_with_fresh_var( + obligation.cause.span, + obligation.param_env.universe, + LateBoundRegionConversionTime::HigherRankedType, + &env_projection); + + // In the environment we have `<T0 as Foo>::Bar == U`. We are + // normalizing `<T1 as Foo>::Bar`. So unify `<T0 as Foo>::Bar` and + // `<T1 as Foo>::Bar` (really, it's just the input types that + // matter; the trait/associated item have already been checked by + // `fast_reject_env_predicate`). Once that is done, we can return + // `U` as our result. + let InferOk { value: _, obligations } = infcx.at(&obligation.cause, obligation.param_env) + .eq(env_projection_ty, obligation.predicate)?; + Ok(InferOk { value: env_ty, obligations }) } fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, + obligation_trait_ref: ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>) -> Result<(), SelectionError<'tcx>> { // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); + let trait_obligation = obligation.with(obligation_trait_ref); selcx.infcx().probe(|_| { let vtable = match selcx.select(&trait_obligation) { Ok(Some(vtable)) => vtable, @@ -1077,8 +1073,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( let new_candidate = if !is_default { Some(ProjectionTyCandidate::Select) } else if obligation.param_env.reveal == Reveal::All { - assert!(!poly_trait_ref.needs_infer()); - if !poly_trait_ref.needs_subst() { + assert!(!obligation_trait_ref.needs_infer()); + if !obligation_trait_ref.needs_subst() { Some(ProjectionTyCandidate::Select) } else { None @@ -1133,7 +1129,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( fn confirm_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, + obligation_trait_ref: ty::TraitRef<'tcx>, candidate: ProjectionTyCandidate<'tcx>) -> Progress<'tcx> { @@ -1156,11 +1152,10 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>( fn confirm_select_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>) + obligation_trait_ref: ty::TraitRef<'tcx>) -> Progress<'tcx> { - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); + let trait_obligation = obligation.with(obligation_trait_ref); let vtable = match selcx.select(&trait_obligation) { Ok(Some(vtable)) => vtable, _ => { @@ -1196,9 +1191,10 @@ fn confirm_select_candidate<'cx, 'gcx, 'tcx>( fn confirm_object_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>) + obligation_trait_ref: ty::TraitRef<'tcx>) -> Progress<'tcx> { + let infcx = selcx.infcx(); let self_ty = obligation_trait_ref.self_ty(); let object_ty = selcx.infcx().shallow_resolve(self_ty); debug!("confirm_object_candidate(object_ty={:?})", @@ -1212,50 +1208,26 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( object_ty) } }; - let env_predicates = data.projection_bounds().map(|p| { - p.with_self_ty(selcx.tcx(), object_ty).to_predicate() - }).collect(); - let env_predicate = { - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - - // select only those projections that are actually projecting an - // item with the correct name - let env_predicates = env_predicates.filter_map(|p| match p { - ty::Predicate::Projection(data) => - if data.0.projection_ty.item_def_id == obligation.predicate.item_def_id { - Some(data) - } else { - None - }, - _ => None - }); - // select those with a relevant trait-ref - let mut env_predicates = env_predicates.filter(|data| { - let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - selcx.infcx().probe(|_| { - selcx.infcx().at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .is_ok() - }) - }); + let unelaborated_env_predicates: Vec<_> = + data.projection_bounds() + .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate()) + .collect(); - // select the first matching one; there really ought to be one or - // else the object type is not WF, since an object type should - // include all of its projections explicitly - match env_predicates.next() { - Some(env_predicate) => env_predicate, - None => { - debug!("confirm_object_candidate: no env-predicate \ - found in object type `{:?}`; ill-formed", - object_ty); - return Progress::error(selcx.tcx()); - } - } - }; + // select on those predicates that can be unified + let mut env_predicates = + elaborate_predicates(selcx.tcx(), unelaborated_env_predicates) + .filter_map(|p| filter_env_predicate(infcx, obligation, p)) + .filter(|&p| can_unify_env_predicate(infcx, obligation, p)); - confirm_param_env_candidate(selcx, obligation, env_predicate) + // take the first one: + if let Some(env_predicate) = env_predicates.next() { + confirm_param_env_candidate(selcx, obligation, env_predicate) + } else { + debug!("confirm_object_candidate: no env-predicate found in object type `{:?}`; ill-formed", + object_ty); + return Progress::error(selcx.tcx()); + } } fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( @@ -1403,29 +1375,24 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, - poly_projection: ty::PolyProjectionPredicate<'tcx>) + env_projection: ty::PolyProjectionPredicate<'tcx>) -> Progress<'tcx> { - let infcx = selcx.infcx(); - let cause = obligation.cause.clone(); - let param_env = obligation.param_env; - let trait_ref = obligation.predicate.trait_ref(infcx.tcx); - match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) { - Ok(InferOk { value: ty_match, obligations }) => { + match unify_env_predicate(selcx.infcx(), obligation, env_projection) { + Ok(InferOk { value, obligations }) => Progress { - ty: ty_match.value, + ty: value, obligations, - } - } - Err(e) => { + }, + + Err(e) => span_bug!( obligation.cause.span, "Failed to unify obligation `{:?}` \ with poly_projection `{:?}`: {:?}", obligation, - poly_projection, - e); - } + env_projection, + e), } } @@ -1553,21 +1520,24 @@ pub struct ProjectionCacheKey<'tcx> { } impl<'cx, 'gcx, 'tcx> ProjectionCacheKey<'tcx> { - pub fn from_poly_projection_predicate(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, - predicate: &ty::PolyProjectionPredicate<'tcx>) - -> Option<Self> + pub fn from_projection_predicate(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + predicate: &ty::ProjectionPredicate<'tcx>) + -> Option<Self> { let infcx = selcx.infcx(); // We don't do cross-snapshot caching of obligations with escaping regions, // so there's no cache key to use - infcx.tcx.no_late_bound_regions(&predicate) - .map(|predicate| ProjectionCacheKey { + if !predicate.has_escaping_regions() { + Some(ProjectionCacheKey { // We don't attempt to match up with a specific type-variable state // from a specific call to `opt_normalize_projection_type` - if // there's no precise match, the original cache entry is "stranded" // anyway. ty: infcx.resolve_type_vars_if_possible(&predicate.projection_ty) }) + } else { + None + } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 7716770d318ba..fa6dd29404cce 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -17,7 +17,8 @@ use super::coherence; use super::DerivedObligationCause; use super::project; use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey}; -use super::{PredicateObligation, TraitObligation, ObligationCause}; +use super::{PredicateObligation, PredicateAtomObligation}; +use super::{TraitObligation, ObligationCause}; use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; use super::{ObjectCastObligation, Obligation}; @@ -35,34 +36,23 @@ use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener}; use ty::subst::{Kind, Subst, Substs}; -use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::{self, ToPredicate, ToPredicateAtom, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; use ty::relate::TypeRelation; use middle::lang_items; use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec}; +use rustc_data_structures::fx::FxHashSet; use std::iter; use std::cell::RefCell; use std::cmp; use std::fmt; -use std::marker::PhantomData; -use std::mem; use std::rc::Rc; use syntax::abi::Abi; use hir; use lint; use util::nodemap::FxHashMap; -struct InferredObligationsSnapshotVecDelegate<'tcx> { - phantom: PhantomData<&'tcx i32>, -} -impl<'tcx> SnapshotVecDelegate for InferredObligationsSnapshotVecDelegate<'tcx> { - type Value = PredicateObligation<'tcx>; - type Undo = (); - fn reverse(_: &mut Vec<Self::Value>, _: Self::Undo) {} -} - pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, @@ -89,8 +79,6 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { /// would satisfy it. This avoids crippling inference, basically. intercrate: bool, - inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>, - intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, } @@ -137,15 +125,15 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// Trait ref from `obligation` but skolemized with the /// selection-context's freshener. Used to check for recursion. - fresh_trait_ref: ty::PolyTraitRef<'tcx>, + fresh_trait_ref: ty::TraitRef<'tcx>, previous: TraitObligationStackList<'prev, 'tcx>, } #[derive(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell<FxHashMap<ty::TraitRef<'tcx>, - WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>>, + hashmap: RefCell<FxHashMap<CacheKey<'tcx>, + WithDepNode<SelectionResult<'tcx, SelectionCandidate>>>>, } /// The selection process begins by considering all impls, where @@ -220,17 +208,13 @@ pub struct SelectionCache<'tcx> { /// required for associated types to work in default impls, as the bounds /// are visible both as projection bounds and as where-clauses from the /// parameter environment. -#[derive(PartialEq,Eq,Debug,Clone)] -enum SelectionCandidate<'tcx> { +#[derive(PartialEq,Eq,Debug,Copy,Clone)] +enum SelectionCandidate { BuiltinCandidate { has_nested: bool }, - ParamCandidate(ty::PolyTraitRef<'tcx>), + ParamCandidate { bounds_list: BoundsList }, ImplCandidate(DefId), AutoImplCandidate(DefId), - /// This is a trait matching with a projected type as `Self`, and - /// we found an applicable bound in the trait definition. - ProjectionCandidate, - /// Implementation of a `Fn`-family trait by one of the anonymous types /// generated for a `||` expression. ClosureCandidate, @@ -250,36 +234,35 @@ enum SelectionCandidate<'tcx> { BuiltinUnsizeCandidate, } -impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> { - type Lifted = SelectionCandidate<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { - Some(match *self { - BuiltinCandidate { has_nested } => { - BuiltinCandidate { - has_nested, - } - } - ImplCandidate(def_id) => ImplCandidate(def_id), - AutoImplCandidate(def_id) => AutoImplCandidate(def_id), - ProjectionCandidate => ProjectionCandidate, - FnPointerCandidate => FnPointerCandidate, - ObjectCandidate => ObjectCandidate, - BuiltinObjectCandidate => BuiltinObjectCandidate, - BuiltinUnsizeCandidate => BuiltinUnsizeCandidate, - ClosureCandidate => ClosureCandidate, - GeneratorCandidate => GeneratorCandidate, - - ParamCandidate(ref trait_ref) => { - return tcx.lift(trait_ref).map(ParamCandidate); - } - }) +impl<'tcx> ty::Lift<'tcx> for SelectionCandidate { + type Lifted = SelectionCandidate; + fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { + Some(*self) } } -struct SelectionCandidateSet<'tcx> { +/// When we prove an obligation via reference to some in-scope where +/// clause, this enum indicates the source from which we derived that +/// where-clause. +/// +/// Note: the ordering is significant. Things later in the list +/// (somewhat arbitrarily) take precedence over things earlier in the +/// list. +#[derive(PartialEq,Eq,PartialOrd,Ord,Debug,Copy,Clone)] +enum BoundsList { + /// The obligation must have a projection as the self-type -- + /// something like `<T as Foo>::Bar`, in which case the obligation + /// was found in the declaration of the `Foo` trait. + TraitBounds, + + /// Found in the list of where-clauses in the parameter environment. + ParamEnv, +} + +struct SelectionCandidateSet { // a list of candidates that definitely apply to the current // obligation (meaning: types unify). - vec: Vec<SelectionCandidate<'tcx>>, + vec: Vec<SelectionCandidate>, // if this is true, then there were candidates that might or might // not have applied, but we couldn't tell. This occurs when some @@ -289,15 +272,15 @@ struct SelectionCandidateSet<'tcx> { } #[derive(PartialEq,Eq,Debug,Clone)] -struct EvaluatedCandidate<'tcx> { - candidate: SelectionCandidate<'tcx>, +struct EvaluatedCandidate { + candidate: SelectionCandidate, evaluation: EvaluationResult, } /// When does the builtin impl for `T: Trait` apply? enum BuiltinImplConditions<'tcx> { /// The impl is conditional on T1,T2,.. : Trait - Where(ty::Binder<Vec<Ty<'tcx>>>), + Where(Vec<Ty<'tcx>>), /// There is no built-in impl. There may be some other /// candidate (a where-clause or user-defined impl). None, @@ -409,16 +392,17 @@ impl EvaluationResult { #[derive(Clone)] pub struct EvaluationCache<'tcx> { - hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>> + hashmap: RefCell<FxHashMap<CacheKey<'tcx>, WithDepNode<EvaluationResult>>> } +type CacheKey<'tcx> = (ty::TraitRef<'tcx>, ty::ParamEnv<'tcx>); + impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>) -> SelectionContext<'cx, 'gcx, 'tcx> { SelectionContext { infcx, freshener: infcx.freshener(), intercrate: false, - inferred_obligations: SnapshotVec::new(), intercrate_ambiguity_causes: Vec::new(), } } @@ -428,7 +412,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { infcx, freshener: infcx.freshener(), intercrate: true, - inferred_obligations: SnapshotVec::new(), intercrate_ambiguity_causes: Vec::new(), } } @@ -452,22 +435,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection /// context's self. fn in_snapshot<R, F>(&mut self, f: F) -> R - where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R + where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R { - // The irrefutable nature of the operation means we don't need to snapshot the - // inferred_obligations vector. self.infcx.in_snapshot(|snapshot| f(self, snapshot)) } /// Wraps a probe s.t. obligations collected during it are ignored and old obligations are /// retained. fn probe<R, F>(&mut self, f: F) -> R - where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> R + where F: FnOnce(&mut Self, &infer::CombinedSnapshot<'cx, 'tcx>) -> R { - let inferred_obligations_snapshot = self.inferred_obligations.start_snapshot(); - let result = self.infcx.probe(|snapshot| f(self, snapshot)); - self.inferred_obligations.rollback_to(inferred_obligations_snapshot); - result + self.infcx.probe(|snapshot| f(self, snapshot)) } /// Wraps a commit_if_ok s.t. obligations collected during it are not returned in selection if @@ -475,17 +453,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn commit_if_ok<T, E, F>(&mut self, f: F) -> Result<T, E> where F: FnOnce(&mut Self, &infer::CombinedSnapshot) -> Result<T, E> { - let inferred_obligations_snapshot = self.inferred_obligations.start_snapshot(); - match self.infcx.commit_if_ok(|snapshot| f(self, snapshot)) { - Ok(ok) => { - self.inferred_obligations.commit(inferred_obligations_snapshot); - Ok(ok) - }, - Err(err) => { - self.inferred_obligations.rollback_to(inferred_obligations_snapshot); - Err(err) - } - } + self.infcx.commit_if_ok(|snapshot| f(self, snapshot)) } @@ -506,28 +474,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Attempts to satisfy the obligation. If successful, this will affect the surrounding /// type environment by performing unification. - pub fn select(&mut self, obligation: &TraitObligation<'tcx>) - -> SelectionResult<'tcx, Selection<'tcx>> { - debug!("select({:?})", obligation); - assert!(!obligation.predicate.has_escaping_regions()); + pub(in traits) fn select(&mut self, obligation: &TraitObligation<'tcx>) + -> SelectionResult<'tcx, Selection<'tcx>> + { + debug!("select({:?}, param_env={:?})", obligation, obligation.param_env); let tcx = self.tcx(); let stack = self.push_stack(TraitObligationStackList::empty(), obligation); let ret = match self.candidate_from_obligation(&stack)? { None => None, - Some(candidate) => { - let mut candidate = self.confirm_candidate(obligation, candidate)?; - let inferred_obligations = (*self.inferred_obligations).into_iter().cloned(); - candidate.nested_obligations_mut().extend(inferred_obligations); - Some(candidate) - }, + Some(candidate) => Some(self.confirm_candidate(&stack, obligation, candidate)?), }; // Test whether this is a `()` which was produced by defaulting a // diverging type variable with `!` disabled. If so, we may need // to raise a warning. - if obligation.predicate.skip_binder().self_ty().is_defaulted_unit() { + if obligation.self_ty().is_defaulted_unit() { let mut raise_warning = true; // Don't raise a warning if the trait is implemented for ! and only // permits a trivial implementation for !. This stops us warning @@ -535,19 +498,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // a switch can't cause code to stop compiling or execute // differently. let mut never_obligation = obligation.clone(); - let def_id = never_obligation.predicate.skip_binder().trait_ref.def_id; - never_obligation.predicate = never_obligation.predicate.map_bound(|mut trait_pred| { + let def_id = never_obligation.def_id(); + never_obligation.predicate = { + let mut trait_ref = never_obligation.predicate; // Swap out () with ! so we can check if the trait is impld for ! { - let trait_ref = &mut trait_pred.trait_ref; let unit_substs = trait_ref.substs; let mut never_substs = Vec::with_capacity(unit_substs.len()); never_substs.push(From::from(tcx.types.never)); never_substs.extend(&unit_substs[1..]); trait_ref.substs = tcx.intern_substs(&never_substs); } - trait_pred - }); + trait_ref + }; if let Ok(Some(..)) = self.select(&never_obligation) { if !tcx.trait_relevant_for_never(def_id) { // The trait is also implemented for ! and the resulting @@ -595,14 +558,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// and returns `false` if not certain. However, this is not entirely /// accurate if inference variables are involved. pub fn evaluate_obligation_conservatively(&mut self, - obligation: &PredicateObligation<'tcx>) + obligation: &PredicateAtomObligation<'tcx>) -> bool { debug!("evaluate_obligation_conservatively({:?})", obligation); self.probe(|this, _| { - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + this.evaluate_predicate_atom_recursively(TraitObligationStackList::empty(), obligation) == EvaluatedToOk }) } @@ -614,7 +577,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack: TraitObligationStackList<'o, 'tcx>, predicates: I) -> EvaluationResult - where I : Iterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a + where I : IntoIterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a { let mut result = EvaluatedToOk; for obligation in predicates { @@ -635,34 +598,32 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_predicate_recursively<'o>(&mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) - -> EvaluationResult + -> EvaluationResult + { + let obligation = self.infcx().skolemize_predicate_obligation(obligation); + self.evaluate_predicate_atom_recursively(previous_stack, &obligation) + } + + fn evaluate_predicate_atom_recursively<'o>(&mut self, + previous_stack: TraitObligationStackList<'o, 'tcx>, + obligation: &PredicateAtomObligation<'tcx>) + -> EvaluationResult { debug!("evaluate_predicate_recursively({:?})", obligation); match obligation.predicate { - ty::Predicate::Trait(ref t) => { + ty::PredicateAtom::Trait(t) => { assert!(!t.has_escaping_regions()); let obligation = obligation.with(t.clone()); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } - ty::Predicate::Equate(ref p) => { - // does this code ever run? - match self.infcx.equality_predicate(&obligation.cause, obligation.param_env, p) { - Ok(InferOk { obligations, .. }) => { - self.inferred_obligations.extend(obligations); - EvaluatedToOk - }, - Err(_) => EvaluatedToErr - } - } - - ty::Predicate::Subtype(ref p) => { + ty::PredicateAtom::Subtype(p) => { // does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { - self.inferred_obligations.extend(obligations); + self.evaluate_predicates_recursively(previous_stack, &obligations); EvaluatedToOk }, Some(Err(_)) => EvaluatedToErr, @@ -670,25 +631,26 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - ty::Predicate::WellFormed(ty) => { + ty::PredicateAtom::WellFormed(ty) => { match ty::wf::obligations(self.infcx, obligation.param_env, obligation.cause.body_id, - ty, obligation.cause.span) { + ty, + obligation.cause.span) { Some(obligations) => - self.evaluate_predicates_recursively(previous_stack, obligations.iter()), + self.evaluate_predicates_recursively(previous_stack, &obligations), None => EvaluatedToAmbig, } } - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { + ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { // we do not consider region relationships when // evaluating trait matches EvaluatedToOk } - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateAtom::ObjectSafe(trait_def_id) => { if self.tcx().is_object_safe(trait_def_id) { EvaluatedToOk } else { @@ -696,14 +658,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(self, &project_obligation) { + ty::PredicateAtom::Projection(data) => { + let project_obligation = obligation.with(data); + match project::project_and_unify_type(self, &project_obligation) { Ok(Some(subobligations)) => { let result = self.evaluate_predicates_recursively(previous_stack, subobligations.iter()); if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) + ProjectionCacheKey::from_projection_predicate(self, &data) { self.infcx.projection_cache.borrow_mut().complete(key); } @@ -718,7 +680,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => { match self.infcx.closure_kind(closure_def_id) { Some(closure_kind) => { if closure_kind.extends(kind) { @@ -733,7 +695,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { match self.tcx().lift_to_global(&(obligation.param_env, substs)) { Some((param_env, substs)) => { match self.tcx().const_eval(param_env.and((def_id, substs))) { @@ -820,10 +782,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Heuristics: show the diagnostics when there are no candidates in crate. if let Ok(candidate_set) = self.assemble_candidates(stack) { if !candidate_set.ambiguous && candidate_set.vec.is_empty() { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let trait_ref = stack.obligation.predicate; let self_ty = trait_ref.self_ty(); let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.to_string(), + trait_desc: trait_ref.print_without_self().to_string(), self_desc: if self_ty.has_concrete_skeleton() { Some(self_ty.to_string()) } else { @@ -874,7 +836,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref); let cycle = stack.iter().skip(1).take(rec_index+1); - let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate)); + let cycle = cycle.map(|stack| stack.obligation.predicate.to_predicate_atom()); if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); @@ -901,16 +863,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// - all the predicates at positions `X..` between `X` an the top are /// also defaulted traits. pub fn coinductive_match<I>(&mut self, cycle: I) -> bool - where I: Iterator<Item=ty::Predicate<'tcx>> + where I: Iterator<Item=ty::PredicateAtom<'tcx>> { let mut cycle = cycle; cycle.all(|predicate| self.coinductive_predicate(predicate)) } - fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { + fn coinductive_predicate(&self, predicate: ty::PredicateAtom<'tcx>) -> bool { let result = match predicate { - ty::Predicate::Trait(ref data) => { - self.tcx().trait_is_auto(data.def_id()) + ty::PredicateAtom::Trait(ref data) => { + self.tcx().trait_is_auto(data.def_id) } _ => { false @@ -925,18 +887,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// scrutiny. fn evaluate_candidate<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, - candidate: &SelectionCandidate<'tcx>) + candidate: &SelectionCandidate) -> EvaluationResult { debug!("evaluate_candidate: depth={} candidate={:?}", stack.obligation.recursion_depth, candidate); let result = self.probe(|this, _| { let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { + match this.confirm_candidate(stack, stack.obligation, candidate) { Ok(selection) => { this.evaluate_predicates_recursively( stack.list(), - selection.nested_obligations().iter()) + selection.nested_obligations()) } Err(..) => EvaluatedToErr } @@ -948,25 +910,25 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn check_evaluation_cache(&self, param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>) + trait_ref: ty::TraitRef<'tcx>) -> Option<EvaluationResult> { let tcx = self.tcx(); if self.can_use_global_caches(param_env) { let cache = tcx.evaluation_cache.hashmap.borrow(); - if let Some(cached) = cache.get(&trait_ref) { + if let Some(cached) = cache.get(&(trait_ref, param_env)) { return Some(cached.get(tcx)); } } self.infcx.evaluation_cache.hashmap .borrow() - .get(&trait_ref) + .get(&(trait_ref, param_env)) .map(|v| v.get(tcx)) } fn insert_evaluation_cache(&mut self, param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, dep_node: DepNodeIndex, result: EvaluationResult) { @@ -978,15 +940,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if self.can_use_global_caches(param_env) { let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut(); - if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) { - cache.insert(trait_ref, WithDepNode::new(dep_node, result)); + if let Some(key) = self.tcx().lift_to_global(&(trait_ref, param_env)) { + cache.insert(key, WithDepNode::new(dep_node, result)); return; } } self.infcx.evaluation_cache.hashmap .borrow_mut() - .insert(trait_ref, WithDepNode::new(dep_node, result)); + .insert((trait_ref, param_env), + WithDepNode::new(dep_node, result)); } /////////////////////////////////////////////////////////////////////////// @@ -999,13 +962,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn candidate_from_obligation<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> + -> SelectionResult<'tcx, SelectionCandidate> { // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. let recursion_limit = self.infcx.tcx.sess.recursion_limit.get(); if stack.obligation.recursion_depth >= recursion_limit { - self.infcx().report_overflow_error(&stack.obligation, true); + let predicate = stack.obligation.predicate.print_with_colon(); + let obligation = stack.obligation.with(predicate); + self.infcx().report_overflow_error(&obligation, true); } // Check the cache. Note that we skolemize the trait-ref @@ -1020,7 +985,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { assert!(!stack.obligation.predicate.has_escaping_regions()); if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, - &cache_fresh_trait_pred) { + cache_fresh_trait_pred) { debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); @@ -1052,8 +1017,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Treat negative impls as unimplemented - fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + fn filter_negative_impls(&self, candidate: SelectionCandidate) + -> SelectionResult<'tcx, SelectionCandidate> { if let ImplCandidate(def_id) = candidate { if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) @@ -1064,7 +1029,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn candidate_from_obligation_no_cache<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> SelectionResult<'tcx, SelectionCandidate<'tcx>> + -> SelectionResult<'tcx, SelectionCandidate> { if stack.obligation.predicate.references_error() { // If we encounter a `TyError`, we generally prefer the @@ -1082,9 +1047,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Heuristics: show the diagnostics when there are no candidates in crate. let candidate_set = self.assemble_candidates(stack)?; if !candidate_set.ambiguous && candidate_set.vec.is_empty() { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let trait_ref = stack.obligation.predicate; let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.to_string(); + let trait_desc = trait_ref.print_without_self().to_string(); let self_desc = if self_ty.has_concrete_skeleton() { Some(self_ty.to_string()) } else { @@ -1214,13 +1179,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } let obligation = &stack.obligation; - let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); - - // ok to skip binder because of the nature of the - // trait-ref-is-knowable check, which does not care about - // bound regions - let trait_ref = predicate.skip_binder().trait_ref; - + let trait_ref = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); coherence::trait_ref_is_knowable(self.tcx(), trait_ref) } @@ -1256,49 +1215,53 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn check_candidate_cache(&mut self, param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>) - -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> + cache_fresh_trait_pred: ty::TraitRef<'tcx>) + -> Option<SelectionResult<'tcx, SelectionCandidate>> { let tcx = self.tcx(); - let trait_ref = &cache_fresh_trait_pred.0.trait_ref; if self.can_use_global_caches(param_env) { let cache = tcx.selection_cache.hashmap.borrow(); - if let Some(cached) = cache.get(&trait_ref) { + if let Some(cached) = cache.get(&(cache_fresh_trait_pred, param_env)) { return Some(cached.get(tcx)); } } self.infcx.selection_cache.hashmap .borrow() - .get(trait_ref) + .get(&(cache_fresh_trait_pred, param_env)) .map(|v| v.get(tcx)) } fn insert_candidate_cache(&mut self, param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + cache_fresh_trait_pred: ty::TraitRef<'tcx>, dep_node: DepNodeIndex, - candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>) + candidate: SelectionResult<'tcx, SelectionCandidate>) { let tcx = self.tcx(); - let trait_ref = cache_fresh_trait_pred.0.trait_ref; if self.can_use_global_caches(param_env) { let mut cache = tcx.selection_cache.hashmap.borrow_mut(); - if let Some(trait_ref) = tcx.lift_to_global(&trait_ref) { + if let Some(key) = tcx.lift_to_global(&(cache_fresh_trait_pred, param_env)) { if let Some(candidate) = tcx.lift_to_global(&candidate) { - cache.insert(trait_ref, WithDepNode::new(dep_node, candidate)); + debug!("insert_candidate_cache: inserting into global cache {:?} => {:?}", + cache_fresh_trait_pred, candidate); + cache.insert(key, WithDepNode::new(dep_node, candidate)); return; } } } + debug!("insert_candidate_cache: inserting into local cache {:?} => {:?}", + cache_fresh_trait_pred, candidate); + self.infcx.selection_cache.hashmap .borrow_mut() - .insert(trait_ref, WithDepNode::new(dep_node, candidate)); + .insert((cache_fresh_trait_pred, param_env), + WithDepNode::new(dep_node, candidate)); } fn assemble_candidates<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> + -> Result<SelectionCandidateSet, SelectionError<'tcx>> { let TraitObligationStack { obligation, .. } = *stack; let ref obligation = Obligation { @@ -1308,7 +1271,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate) }; - if obligation.predicate.skip_binder().self_ty().is_ty_var() { + if obligation.self_ty().is_ty_var() { // Self is a type variable (e.g. `_: AsRef<str>`). // // This is somewhat problematic, as the current scheme can't really @@ -1329,11 +1292,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Other bounds. Consider both in-scope bounds from fn decl // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); + let def_id = obligation.def_id(); let lang_items = self.tcx().lang_items(); if lang_items.copy_trait() == Some(def_id) { - debug!("obligation self ty is {:?}", - obligation.predicate.0.self_ty()); + debug!("obligation self ty is {:?}", obligation.self_ty()); // User-defined copy impls are permitted, but only for // structs and enums. @@ -1366,8 +1328,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.assemble_candidates_from_object_ty(obligation, &mut candidates); } - self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; + self.assemble_candidates_from_projected_tys(obligation, stack, &mut candidates)?; + self.assemble_candidates_from_caller_bounds(obligation, stack, &mut candidates)?; // Auto implementations have lower priority, so we only // consider triggering a default if there is no other impl that can apply. if candidates.vec.is_empty() { @@ -1377,120 +1339,39 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(candidates) } - fn assemble_candidates_from_projected_tys(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + /// Finds candidates where the thing we are trying to prove looks like + /// + /// <T as Trait>::Foo: Bar + /// + /// by looking in the definition of `Trait` to see if the + /// associated type `Foo` includes a `Bar` bound: + /// + /// trait Trait { + /// type Foo: Bar; + /// } + /// + /// If so, this will be encoded by a predicate on the trait like + /// `<Self as Trait>::Foo: Bar`, so what we do is to find the + /// trait predicates, substitute appropriately, and then check if + /// our obligation goal is found in there. + /// + /// # Parameters + /// + /// - `obligation` -- top of stack, but with type variables resolved + /// - `stack` -- evaluation stack + /// - `candidates` -- list where to push candidates + fn assemble_candidates_from_projected_tys<'o>(&mut self, + obligation: &TraitObligation<'tcx>, + stack: &TraitObligationStack<'o, 'tcx>, + candidates: &mut SelectionCandidateSet) + -> Result<(),SelectionError<'tcx>> { debug!("assemble_candidates_for_projected_tys({:?})", obligation); - // before we go into the whole skolemization thing, just - // quickly check if the self-type is a projection at all. - match obligation.predicate.0.trait_ref.self_ty().sty { - ty::TyProjection(_) | ty::TyAnon(..) => {} - ty::TyInfer(ty::TyVar(_)) => { - span_bug!(obligation.cause.span, - "Self=_ should have been handled by assemble_candidates"); - } - _ => return - } - - let result = self.probe(|this, snapshot| { - this.match_projection_obligation_against_definition_bounds(obligation, - snapshot) - }); - - if result { - candidates.vec.push(ProjectionCandidate); - } - } - - fn match_projection_obligation_against_definition_bounds( - &mut self, - obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> bool - { - let poly_trait_predicate = - self.infcx().resolve_type_vars_if_possible(&obligation.predicate); - let (skol_trait_predicate, skol_map) = - self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot); - debug!("match_projection_obligation_against_definition_bounds: \ - skol_trait_predicate={:?} skol_map={:?}", - skol_trait_predicate, - skol_map); - - let (def_id, substs) = match skol_trait_predicate.trait_ref.self_ty().sty { - ty::TyProjection(ref data) => - (data.trait_ref(self.tcx()).def_id, data.substs), - ty::TyAnon(def_id, substs) => (def_id, substs), - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty not a projection: {:?}", - skol_trait_predicate.trait_ref.self_ty()); - } - }; - debug!("match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs); - - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!("match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds); - - let matching_bound = - util::elaborate_predicates(self.tcx(), bounds.predicates) - .filter_to_traits() - .find( - |bound| self.probe( - |this, _| this.match_projection(obligation, - bound.clone(), - skol_trait_predicate.trait_ref.clone(), - &skol_map, - snapshot))); - - debug!("match_projection_obligation_against_definition_bounds: \ - matching_bound={:?}", - matching_bound); - match matching_bound { - None => false, - Some(bound) => { - // Repeat the successful match, if any, this time outside of a probe. - let result = self.match_projection(obligation, - bound, - skol_trait_predicate.trait_ref.clone(), - &skol_map, - snapshot); - - self.infcx.pop_skolemized(skol_map, snapshot); - - assert!(result); - true - } - } - } - - fn match_projection(&mut self, - obligation: &TraitObligation<'tcx>, - trait_bound: ty::PolyTraitRef<'tcx>, - skol_trait_ref: ty::TraitRef<'tcx>, - skol_map: &infer::SkolemizationMap<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> bool - { - assert!(!skol_trait_ref.has_escaping_regions()); - match self.infcx.at(&obligation.cause, obligation.param_env) - .sup(ty::Binder(skol_trait_ref), trait_bound) { - Ok(InferOk { obligations, .. }) => { - self.inferred_obligations.extend(obligations); - } - Err(_) => { return false; } - } - - self.infcx.leak_check(false, obligation.cause.span, skol_map, snapshot).is_ok() + self.assemble_candidates_from_bounds_list(obligation, + stack, + candidates, + BoundsList::TraitBounds) } /// Given an obligation like `<SomeTrait for T>`, search the obligations that the caller @@ -1498,31 +1379,46 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// /// Never affects inference environment. fn assemble_candidates_from_caller_bounds<'o>(&mut self, + obligation: &TraitObligation<'tcx>, stack: &TraitObligationStack<'o, 'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) -> Result<(),SelectionError<'tcx>> { debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); - let all_bounds = - stack.obligation.param_env.caller_bounds - .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); - - // micro-optimization: filter out predicates relating to different - // traits. - let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); - - let matching_bounds = - matching_bounds.filter( - |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); + self.assemble_candidates_from_bounds_list(obligation, + stack, + candidates, + BoundsList::ParamEnv) + } - let param_candidates = - matching_bounds.map(|bound| ParamCandidate(bound)); + /// Given an obligation `O` like `<SomeTrait for T>`, search the + /// given list of bounds (which must be where-clauses that have + /// been proven elsewhere; e.g., by the caller) to find out + /// whether `O` is listed among them. + /// + /// Never affects inference environment. + fn assemble_candidates_from_bounds_list<'o>(&mut self, + obligation: &TraitObligation<'tcx>, + stack: &TraitObligationStack<'o, 'tcx>, + candidates: &mut SelectionCandidateSet, + bounds_list: BoundsList) + -> Result<(),SelectionError<'tcx>> + { + let mut bounds = self.bounds_list_iterator(stack, obligation, bounds_list); - candidates.vec.extend(param_candidates); + // Final step: If there are any matches, transform into a candidate. + if bounds.next().is_some() { + // at least one match found... + if bounds.next().is_some() { + // ...at least two matches found... + candidates.ambiguous = true; + } else { + // ...exactly one match found. + candidates.vec.push(ParamCandidate { bounds_list }); + } + } Ok(()) } @@ -1544,17 +1440,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn assemble_generator_candidates(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) -> Result<(),SelectionError<'tcx>> { - if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { + if self.tcx().lang_items().gen_trait() != Some(obligation.def_id()) { return Ok(()); } // ok to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty(); match self_ty.sty { ty::TyGenerator(..) => { debug!("assemble_generator_candidates: self_ty={:?} obligation={:?}", @@ -1581,10 +1477,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// unified during the confirmation step. fn assemble_closure_candidates(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) -> Result<(),SelectionError<'tcx>> { - let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.0.def_id()) { + let kind = match self.tcx().lang_items().fn_trait_kind(obligation.def_id()) { Some(k) => k, None => { return Ok(()); } }; @@ -1592,7 +1488,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // ok to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - match obligation.self_ty().skip_binder().sty { + let self_ty = obligation.self_ty(); + match self_ty.sty { ty::TyClosure(closure_def_id, _) => { debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); @@ -1622,16 +1519,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Implement one of the `Fn()` family for a fn pointer. fn assemble_fn_pointer_candidates(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) -> Result<(),SelectionError<'tcx>> { // We provide impl of all fn traits for fn pointers. - if self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()).is_none() { + if self.tcx().lang_items().fn_trait_kind(obligation.def_id()).is_none() { return Ok(()); } // ok to skip binder because what we are inspecting doesn't involve bound regions - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty(); match self_ty.sty { ty::TyInfer(ty::TyVar(_)) => { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); @@ -1659,23 +1556,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Search for impls that might apply to `obligation`. fn assemble_candidates_from_impls(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) -> Result<(), SelectionError<'tcx>> { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); self.tcx().for_each_relevant_impl( - obligation.predicate.def_id(), - obligation.predicate.0.trait_ref.self_ty(), + obligation.def_id(), + obligation.self_ty(), |impl_def_id| { - self.probe(|this, snapshot| { /* [1] */ - match this.match_impl(impl_def_id, obligation, snapshot) { - Ok(skol_map) => { + self.probe(|this, _snapshot| { + match this.match_impl(impl_def_id, obligation) { + Ok(_) => { candidates.vec.push(ImplCandidate(impl_def_id)); - - // NB: we can safely drop the skol map - // since we are in a probe [1] - mem::drop(skol_map); } Err(_) => { } } @@ -1687,15 +1580,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn assemble_candidates_from_auto_impls(&mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) - -> Result<(), SelectionError<'tcx>> + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet) + -> Result<(), SelectionError<'tcx>> { - // OK to skip binder here because the tests we do below do not involve bound regions - let self_ty = *obligation.self_ty().skip_binder(); + let self_ty = obligation.self_ty(); debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); - let def_id = obligation.predicate.def_id(); + let def_id = obligation.def_id(); if self.tcx().trait_is_auto(def_id) { match self_ty.sty { @@ -1743,10 +1635,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Search for impls that might apply to `obligation`. fn assemble_candidates_from_object_ty(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) { debug!("assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder()); + obligation.self_ty()); // Object-safety candidates are only applicable to object-safe // traits. Including this check is useful because it helps @@ -1755,8 +1647,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // self-type from one of the other inputs. Without this check, // these cases wind up being considered ambiguous due to a // (spurious) ambiguity introduced here. - let predicate_trait_ref = obligation.predicate.to_poly_trait_ref(); - if !self.tcx().is_object_safe(predicate_trait_ref.def_id()) { + let predicate_trait_ref = obligation.predicate; + if !self.tcx().is_object_safe(predicate_trait_ref.def_id) { return; } @@ -1764,10 +1656,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // the code below doesn't care about regions, and the // self-ty here doesn't escape this probe, so just erase // any LBR. - let self_ty = this.tcx().erase_late_bound_regions(&obligation.self_ty()); + let self_ty = obligation.self_ty(); let poly_trait_ref = match self_ty.sty { ty::TyDynamic(ref data, ..) => { - if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { + if data.auto_traits().any(|did| did == obligation.def_id()) { debug!("assemble_candidates_from_object_ty: matched builtin bound, \ pushing candidate"); candidates.vec.push(BuiltinObjectCandidate); @@ -1819,29 +1711,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// Search for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing(&mut self, obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) { - // We currently never consider higher-ranked obligations e.g. - // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not - // because they are a priori invalid, and we could potentially add support - // for them later, it's just that there isn't really a strong need for it. - // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>` - // impl, and those are generally applied to concrete types. - // - // That said, one might try to write a fn with a where clause like - // for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>> - // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. - // Still, you'd be more likely to write that where clause as - // T: Trait - // so it seems ok if we (conservatively) fail to accept that `Unsize` - // obligation above. Should be possible to extend this in the future. - let source = match self.tcx().no_late_bound_regions(&obligation.self_ty()) { - Some(t) => t, - None => { - // Don't add any candidates if there are bound regions. - return; - } - }; - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + candidates: &mut SelectionCandidateSet) { + let source = obligation.self_ty(); + let target = obligation.predicate.substs.type_at(1); debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); @@ -1922,8 +1794,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// See the comment for "SelectionCandidate" for more details. fn candidate_should_be_dropped_in_favor_of<'o>( &mut self, - victim: &EvaluatedCandidate<'tcx>, - other: &EvaluatedCandidate<'tcx>) + victim: &EvaluatedCandidate, + other: &EvaluatedCandidate) -> bool { if victim.candidate == other.candidate { @@ -1931,31 +1803,43 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } match other.candidate { - ObjectCandidate | - ParamCandidate(_) | ProjectionCandidate => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates"); - } - ImplCandidate(..) | - ClosureCandidate | - GeneratorCandidate | - FnPointerCandidate | - BuiltinObjectCandidate | - BuiltinUnsizeCandidate | - BuiltinCandidate { .. } => { - // We have a where-clause so don't go around looking - // for impls. - true + ObjectCandidate | ParamCandidate { .. } if other.evaluation == EvaluatedToOk => { + match victim.candidate { + AutoImplCandidate(..) => { + bug!( + "auto implementations shouldn't be recorded \ + when there are other valid candidates"); + } + ImplCandidate(..) | + ClosureCandidate | + GeneratorCandidate | + FnPointerCandidate | + BuiltinObjectCandidate | + BuiltinUnsizeCandidate | + BuiltinCandidate { .. } => { + // We have a where-clause so don't go around looking + // for impls. + true + } + ObjectCandidate => { + // Arbitrarily give param candidates priority + // over object candidates. + true + }, + ParamCandidate { bounds_list: victim_bounds_list, .. } => { + // The "other" must have been either an object + // or a param candidate. If it was an object + // candidate, it does not take precedence, + // since we rank param higher. If it was + // another param candidate, compare the bounds + // list precedence. + match other.candidate { + ObjectCandidate => return false, + ParamCandidate { bounds_list, .. } => bounds_list > victim_bounds_list, + _ => bug!("other not object nor param: {:?}", other.candidate) + } + } } - ObjectCandidate | - ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - true - }, - ParamCandidate(..) => false, }, ImplCandidate(other_def) => { // See if we can toss out `victim` based on specialization. @@ -1988,14 +1872,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // other impls. fn assemble_builtin_bound_candidates<'o>(&mut self, conditions: BuiltinImplConditions<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>) + candidates: &mut SelectionCandidateSet) -> Result<(),SelectionError<'tcx>> { match conditions { BuiltinImplConditions::Where(nested) => { debug!("builtin_bound: nested={:?}", nested); candidates.vec.push(BuiltinCandidate { - has_nested: nested.skip_binder().len() > 0 + has_nested: nested.len() > 0 }); Ok(()) } @@ -2013,9 +1897,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve( - obligation.predicate.skip_binder().self_ty()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); match self_ty.sty { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | @@ -2025,29 +1907,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | ty::TyError => { // safe for everything - Where(ty::Binder(Vec::new())) + Where(Vec::new()) } ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never, ty::TyTuple(tys, _) => { - Where(ty::Binder(tys.last().into_iter().cloned().collect())) + Where(tys.last().into_iter().cloned().collect()) } ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); - // (*) binder moved here - Where(ty::Binder( - sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() - )) + Where(sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()) } ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, ty::TyInfer(ty::TyVar(_)) => Ambiguous, - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { + ty::TyInfer(ty::CanonicalTy(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } @@ -2055,11 +1935,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>) - -> BuiltinImplConditions<'tcx> + -> BuiltinImplConditions<'tcx> { - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve( - obligation.predicate.skip_binder().self_ty()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; @@ -2069,7 +1947,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | ty::TyRawPtr(..) | ty::TyError | ty::TyNever | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { - Where(ty::Binder(Vec::new())) + Where(Vec::new()) } ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | @@ -2080,16 +1958,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyArray(element_ty, _) => { // (*) binder moved here - Where(ty::Binder(vec![element_ty])) + Where(vec![element_ty]) } ty::TyTuple(tys, _) => { // (*) binder moved here - Where(ty::Binder(tys.to_vec())) + Where(tys.to_vec()) } ty::TyClosure(def_id, substs) => { - let trait_id = obligation.predicate.def_id(); + let trait_id = obligation.predicate.def_id; let copy_closures = Some(trait_id) == self.tcx().lang_items().copy_trait() && self.tcx().has_copy_closures(def_id.krate); @@ -2098,7 +1976,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.tcx().has_clone_closures(def_id.krate); if copy_closures || clone_closures { - Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect())) + Where(substs.upvar_tys(def_id, self.tcx()).collect()) } else { Never } @@ -2116,9 +1994,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ambiguous } - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { + ty::TyInfer(ty::CanonicalTy(_)) | + ty::TyInfer(ty::FreshTy(_)) | + ty::TyInfer(ty::FreshIntTy(_)) | + ty::TyInfer(ty::FreshFloatTy(_)) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } @@ -2157,6 +2036,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyParam(..) | ty::TyForeign(..) | ty::TyProjection(..) | + ty::TyInfer(ty::CanonicalTy(_)) | ty::TyInfer(ty::TyVar(_)) | ty::TyInfer(ty::FreshTy(_)) | ty::TyInfer(ty::FreshIntTy(_)) | @@ -2208,50 +2088,38 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + /// Given a list of types `types` that resulted (typically) from + /// an auto trait, create new obligations `T: Foo` for each `T` in + /// `types`. So e.g. if we were check that `(A, B): Send`, this + /// might result in `A: Send` and `B: Send`. fn collect_predicates_for_types(&mut self, param_env: ty::ParamEnv<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, trait_def_id: DefId, - types: ty::Binder<Vec<Ty<'tcx>>>) + types: Vec<Ty<'tcx>>) -> Vec<PredicateObligation<'tcx>> { - // Because the types were potentially derived from - // higher-ranked obligations they may reference late-bound - // regions. For example, `for<'a> Foo<&'a int> : Copy` would - // yield a type like `for<'a> &'a int`. In general, we - // maintain the invariant that we never manipulate bound - // regions, so we have to process these bound regions somehow. - // - // The strategy is to: - // - // 1. Instantiate those regions to skolemized regions (e.g., - // `for<'a> &'a int` becomes `&0 int`. - // 2. Produce something like `&'0 int : Copy` - // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - - types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\ - let ty: ty::Binder<Ty<'tcx>> = ty::Binder(ty); // <----------/ - - self.in_snapshot(|this, snapshot| { - let (skol_ty, skol_map) = - this.infcx().skolemize_late_bound_regions(&ty, snapshot); - let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth(this, - param_env, - cause.clone(), - recursion_depth, - &skol_ty); - let skol_obligation = - this.tcx().predicate_for_trait_def(param_env, - cause.clone(), - trait_def_id, - recursion_depth, - normalized_ty, - &[]); - obligations.push(skol_obligation); - this.infcx().plug_leaks(skol_map, snapshot, obligations) - }) + types.into_iter().flat_map(|ty| { + let Normalized { value: normalized_ty, mut obligations } = + project::normalize_with_depth(self, + param_env, + cause.clone(), + recursion_depth, + &ty); + + // in addition to whatever normalize cooked up, add the + // obligation that `T: Trait` + let addl_obligation = + self.tcx().predicate_for_trait_def(param_env, + cause.clone(), + trait_def_id, + recursion_depth, + normalized_ty, + &[]); + obligations.push(addl_obligation); + + obligations }).collect() } @@ -2262,10 +2130,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // with the values found in the obligation, possibly yielding a // type error. See `README.md` for more details. - fn confirm_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - candidate: SelectionCandidate<'tcx>) - -> Result<Selection<'tcx>,SelectionError<'tcx>> + fn confirm_candidate<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>, + obligation: &TraitObligation<'tcx>, + candidate: SelectionCandidate) + -> Result<Selection<'tcx>,SelectionError<'tcx>> { debug!("confirm_candidate({:?}, {:?})", obligation, @@ -2277,8 +2146,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableBuiltin(data)) } - ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param); + ParamCandidate { bounds_list } => { + let obligations = self.confirm_param_candidate(stack, obligation, bounds_list); Ok(VtableParam(obligations)) } @@ -2321,11 +2190,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableFnPointer(data)) } - ProjectionCandidate => { - self.confirm_projection_candidate(obligation); - Ok(VtableParam(Vec::new())) - } - BuiltinUnsizeCandidate => { let data = self.confirm_builtin_unsize_candidate(obligation)?; Ok(VtableBuiltin(data)) @@ -2333,36 +2197,47 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } - fn confirm_projection_candidate(&mut self, - obligation: &TraitObligation<'tcx>) - { - self.in_snapshot(|this, snapshot| { - let result = - this.match_projection_obligation_against_definition_bounds(obligation, - snapshot); - assert!(result); - }) - } - - fn confirm_param_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - param: ty::PolyTraitRef<'tcx>) - -> Vec<PredicateObligation<'tcx>> + fn confirm_param_candidate<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>, + obligation: &TraitObligation<'tcx>, + bounds_list: BoundsList) + -> Vec<PredicateObligation<'tcx>> { debug!("confirm_param_candidate({:?},{:?})", obligation, - param); + bounds_list); + + // We need a fully resolved predicate for + // `bounds_list_iterator`, and I don't know that `obligation` + // necessarily is. + let obligation = &Obligation { + param_env: obligation.param_env, + cause: obligation.cause.clone(), + recursion_depth: obligation.recursion_depth, + predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate) + }; + + let where_clause_trait_ref = { + let mut bounds = self.bounds_list_iterator(stack, obligation, bounds_list); + bounds.next().unwrap_or_else(|| { + span_bug!(obligation.cause.span, + "bounds list {:?} no longer has any matching entries", + bounds_list); + }) + }; // During evaluation, we already checked that this // where-clause trait-ref could be unified with the obligation // trait-ref. Repeat that unification now without any // transactional boundary; it should not fail. - match self.match_where_clause_trait_ref(obligation, param.clone()) { + match self.match_where_clause_trait_ref(obligation, where_clause_trait_ref) { Ok(obligations) => obligations, Err(()) => { - bug!("Where clause `{:?}` was applicable to `{:?}` but now is not", - param, - obligation); + span_bug!( + obligation.cause.span, + "Where clause `{:?}` was applicable to `{:?}` but now is not", + where_clause_trait_ref, + obligation); } } } @@ -2377,7 +2252,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let lang_items = self.tcx().lang_items(); let obligations = if has_nested { - let trait_def = obligation.predicate.def_id(); + let trait_def = obligation.def_id(); let conditions = match trait_def { _ if Some(trait_def) == lang_items.sized_trait() => { self.sized_conditions(obligation) @@ -2418,26 +2293,25 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. fn confirm_auto_impl_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId) - -> VtableAutoImplData<PredicateObligation<'tcx>> + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId) + -> VtableAutoImplData<PredicateObligation<'tcx>> { debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); - // binder is moved below - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let types = self.constituent_types_for_ty(self_ty); - self.vtable_auto_impl(obligation, trait_def_id, ty::Binder(types)) + self.vtable_auto_impl(obligation, trait_def_id, types) } - /// See `confirm_auto_impl_candidate` + /// See `confirm_default_impl_candidate` fn vtable_auto_impl(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder<Vec<Ty<'tcx>>>) - -> VtableAutoImplData<PredicateObligation<'tcx>> + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId, + nested: Vec<Ty<'tcx>>) + -> VtableAutoImplData<PredicateObligation<'tcx>> { debug!("vtable_auto_impl: nested={:?}", nested); @@ -2449,20 +2323,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_def_id, nested); - let trait_obligations = self.in_snapshot(|this, snapshot| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, skol_map) = - this.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); - let cause = obligation.derived_cause(ImplDerivedObligation); - this.impl_or_trait_obligations(cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - skol_map, - snapshot) - }); - + let trait_ref = obligation.predicate; + let cause = obligation.derived_cause(ImplDerivedObligation); + let trait_obligations = self.impl_or_trait_obligations(cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs); obligations.extend(trait_obligations); debug!("vtable_auto_impl: obligations={:?}", obligations); @@ -2484,19 +2351,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.in_snapshot(|this, snapshot| { - let (substs, skol_map) = - this.rematch_impl(impl_def_id, obligation, - snapshot); + self.in_snapshot(|this, _snapshot| { + let substs = this.rematch_impl(impl_def_id, obligation); debug!("confirm_impl_candidate substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); this.vtable_impl(impl_def_id, substs, cause, obligation.recursion_depth + 1, - obligation.param_env, - skol_map, - snapshot) + obligation.param_env) }) } @@ -2505,25 +2368,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>, cause: ObligationCause<'tcx>, recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - skol_map: infer::SkolemizationMap<'tcx>, - snapshot: &infer::CombinedSnapshot) + param_env: ty::ParamEnv<'tcx>) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})", + debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", impl_def_id, substs, - recursion_depth, - skol_map); + recursion_depth); let mut impl_obligations = self.impl_or_trait_obligations(cause, recursion_depth, param_env, impl_def_id, - &substs.value, - skol_map, - snapshot); + &substs.value); debug!("vtable_impl: impl_def_id={:?} impl_obligations={:?}", impl_def_id, @@ -2552,7 +2410,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // probably flatten the binder from the obligation and the // binder from the object. Have to try to make a broken test // case that results. -nmatsakis - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let poly_trait_ref = match self_ty.sty { ty::TyDynamic(ref data, ..) => { data.principal().unwrap().with_self_ty(self.tcx(), self_ty) @@ -2564,6 +2422,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }; let mut upcast_trait_ref = None; + let mut nested = vec![]; let vtable_base; { @@ -2582,7 +2441,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.commit_if_ok( |this, _| this.match_poly_trait_ref(obligation, t)) { - Ok(_) => { upcast_trait_ref = Some(t); false } + Ok(obligations) => { + upcast_trait_ref = Some(t); + nested.extend(obligations); + false + } Err(_) => { true } } }); @@ -2600,7 +2463,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, - nested: vec![] + nested, } } @@ -2610,27 +2473,28 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("confirm_fn_pointer_candidate({:?})", obligation); - // ok to skip binder; it is reintroduced below - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); let sig = self_ty.fn_sig(self.tcx()); let trait_ref = - self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), + self.tcx().closure_trait_ref_and_return_type(obligation.def_id(), self_ty, sig, util::TupleArgumentsFlag::Yes) .map_bound(|(trait_ref, _)| trait_ref); - let Normalized { value: trait_ref, obligations } = + let Normalized { value: trait_ref, mut obligations } = project::normalize_with_depth(self, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, &trait_ref); - self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref)?; + obligations.extend( + self.confirm_against_poly_trait_ref(obligation.cause.clone(), + obligation.param_env, + obligation.predicate, + trait_ref)?); + Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) } @@ -2639,10 +2503,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // ok to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters - let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(&obligation.self_ty()); let (closure_def_id, substs) = match self_ty.sty { ty::TyGenerator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation) @@ -2657,7 +2518,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.generator_trait_ref_unnormalized(obligation, closure_def_id, substs); let Normalized { value: trait_ref, - obligations + mut obligations } = normalize_with_depth(self, obligation.param_env, obligation.cause.clone(), @@ -2669,10 +2530,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_ref, obligations); - self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref)?; + obligations.extend( + self.confirm_against_poly_trait_ref(obligation.cause.clone(), + obligation.param_env, + obligation.predicate, + trait_ref)?); Ok(VtableGeneratorData { closure_def_id: closure_def_id, @@ -2688,15 +2550,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("confirm_closure_candidate({:?})", obligation); - let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.0.def_id()) { + let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id) { Some(k) => k, None => bug!("closure candidate for non-fn trait {:?}", obligation) }; - // ok to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters - let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let self_ty = self.infcx.shallow_resolve(&obligation.self_ty()); let (closure_def_id, substs) = match self_ty.sty { ty::TyClosure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation) @@ -2718,15 +2577,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_ref, obligations); - self.confirm_poly_trait_refs(obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref)?; + obligations.extend( + self.confirm_against_poly_trait_ref(obligation.cause.clone(), + obligation.param_env, + obligation.predicate, + trait_ref)?); - obligations.push(Obligation::new( + obligations.push(Obligation::with_depth( obligation.cause.clone(), + obligation.recursion_depth, obligation.param_env, - ty::Predicate::ClosureKind(closure_def_id, kind))); + ty::PredicateAtom::ClosureKind(closure_def_id, kind).to_predicate())); Ok(VtableClosureData { closure_def_id, @@ -2760,18 +2621,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// because these output type parameters should not affect the /// selection of the impl. Therefore, if there is a mismatch, we /// report an error to the user. - fn confirm_poly_trait_refs(&mut self, - obligation_cause: ObligationCause<'tcx>, - obligation_param_env: ty::ParamEnv<'tcx>, - obligation_trait_ref: ty::PolyTraitRef<'tcx>, - expected_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result<(), SelectionError<'tcx>> + fn confirm_against_poly_trait_ref(&mut self, + obligation_cause: ObligationCause<'tcx>, + obligation_param_env: ty::ParamEnv<'tcx>, + obligation_trait_ref: ty::TraitRef<'tcx>, + expected_trait_ref: ty::PolyTraitRef<'tcx>) + -> Result<Vec<PredicateObligation<'tcx>>, + SelectionError<'tcx>> { let obligation_trait_ref = obligation_trait_ref.clone(); self.infcx .at(&obligation_cause, obligation_param_env) - .sup(obligation_trait_ref, expected_trait_ref) - .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) + .instantiable_as(expected_trait_ref, obligation_trait_ref) + .map(|InferOk { obligations, value: () }| obligations) .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) } @@ -2781,11 +2643,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { let tcx = self.tcx(); - // assemble_candidates_for_unsizing should ensure there are no late bound - // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve( - tcx.no_late_bound_regions(&obligation.self_ty()).unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); + let source = self.infcx.shallow_resolve(obligation.self_ty()); + let target = obligation.predicate.substs.type_at(1); let target = self.infcx.shallow_resolve(target); debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", @@ -2808,7 +2667,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.at(&obligation.cause, obligation.param_env) .eq(target, new_trait) .map_err(|_| Unimplemented)?; - self.inferred_obligations.extend(obligations); + nested.extend(obligations); // Register one obligation for 'a: 'b. let cause = ObligationCause::new(obligation.cause.span, @@ -2870,7 +2729,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.at(&obligation.cause, obligation.param_env) .eq(b, a) .map_err(|_| Unimplemented)?; - self.inferred_obligations.extend(obligations); + nested.extend(obligations); } // Struct<T> -> Struct<U>. @@ -2934,13 +2793,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.at(&obligation.cause, obligation.param_env) .eq(target, new_struct) .map_err(|_| Unimplemented)?; - self.inferred_obligations.extend(obligations); + nested.extend(obligations); // Construct the nested Field<T>: Unsize<Field<U>> predicate. nested.push(tcx.predicate_for_trait_def( obligation.param_env, obligation.cause.clone(), - obligation.predicate.def_id(), + obligation.def_id(), obligation.recursion_depth + 1, inner_source, &[inner_target])); @@ -2965,13 +2824,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.infcx.at(&obligation.cause, obligation.param_env) .eq(target, new_tuple) .map_err(|_| Unimplemented)?; - self.inferred_obligations.extend(obligations); + nested.extend(obligations); // Construct the nested T: Unsize<U> predicate. nested.push(tcx.predicate_for_trait_def( obligation.param_env, obligation.cause.clone(), - obligation.predicate.def_id(), + obligation.def_id(), obligation.recursion_depth + 1, a_last, &[b_last])); @@ -2995,13 +2854,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn rematch_impl(&mut self, impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> (Normalized<'tcx, &'tcx Substs<'tcx>>, - infer::SkolemizationMap<'tcx>) + obligation: &TraitObligation<'tcx>) + -> Normalized<'tcx, &'tcx Substs<'tcx>> { - match self.match_impl(impl_def_id, obligation, snapshot) { - Ok((substs, skol_map)) => (substs, skol_map), + match self.match_impl(impl_def_id, obligation) { + Ok(tuple) => tuple, Err(()) => { bug!("Impl {:?} was matchable against {:?} but now is not", impl_def_id, @@ -3012,10 +2869,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn match_impl(&mut self, impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &infer::CombinedSnapshot) - -> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>, - infer::SkolemizationMap<'tcx>), ()> + obligation: &TraitObligation<'tcx>) + -> Result<Normalized<'tcx, &'tcx Substs<'tcx>>, ()> { let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); @@ -3026,53 +2881,35 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Err(()); } - let (skol_obligation, skol_map) = self.infcx().skolemize_late_bound_regions( - &obligation.predicate, - snapshot); - let skol_obligation_trait_ref = skol_obligation.trait_ref; - - let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, + let impl_substs = self.infcx.fresh_substs_for_item(obligation.param_env.universe, + obligation.cause.span, impl_def_id); - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), - impl_substs); + let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); - let impl_trait_ref = + let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = project::normalize_with_depth(self, obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, &impl_trait_ref); - debug!("match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", + debug!("match_impl(impl_def_id={:?}, obligation={:?}, impl_trait_ref={:?})", impl_def_id, obligation, - impl_trait_ref, - skol_obligation_trait_ref); + impl_trait_ref); let InferOk { obligations, .. } = self.infcx.at(&obligation.cause, obligation.param_env) - .eq(skol_obligation_trait_ref, impl_trait_ref.value) + .eq(obligation.predicate, impl_trait_ref) .map_err(|e| { debug!("match_impl: failed eq_trait_refs due to `{}`", e); () })?; - self.inferred_obligations.extend(obligations); - - if let Err(e) = self.infcx.leak_check(false, - obligation.cause.span, - &skol_map, - snapshot) { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } + nested_obligations.extend(obligations); debug!("match_impl: success impl_substs={:?}", impl_substs); - Ok((Normalized { - value: impl_substs, - obligations: impl_trait_ref.obligations - }, skol_map)) + Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } fn fast_reject_trait_refs(&mut self, @@ -3084,7 +2921,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // substitution if we find that any of the input types, when // simplified, do not match. - obligation.predicate.skip_binder().input_types() + obligation.predicate.input_types() .zip(impl_trait_ref.input_types()) .any(|(obligation_ty, impl_ty)| { let simplified_obligation_ty = @@ -3108,8 +2945,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { where_clause_trait_ref: ty::PolyTraitRef<'tcx>) -> Result<Vec<PredicateObligation<'tcx>>,()> { - self.match_poly_trait_ref(obligation, where_clause_trait_ref)?; - Ok(Vec::new()) + self.match_poly_trait_ref(obligation, where_clause_trait_ref) } /// Returns `Ok` if `poly_trait_ref` being true implies that the @@ -3117,15 +2953,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn match_poly_trait_ref(&mut self, obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) - -> Result<(),()> + -> Result<Vec<PredicateObligation<'tcx>>,()> { debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", obligation, poly_trait_ref); self.infcx.at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) - .map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations)) + .instantiable_as(poly_trait_ref, obligation.predicate) + .map(|InferOk { obligations, value: () }| obligations) .map_err(|_| ()) } @@ -3133,8 +2969,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Miscellany fn match_fresh_trait_refs(&self, - previous: &ty::PolyTraitRef<'tcx>, - current: &ty::PolyTraitRef<'tcx>) + previous: &ty::TraitRef<'tcx>, + current: &ty::TraitRef<'tcx>) -> bool { let mut matcher = ty::_match::Match::new(self.tcx()); @@ -3146,9 +2982,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_ref = - obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); - + let fresh_trait_ref = obligation.predicate.fold_with(&mut self.freshener); TraitObligationStack { obligation, fresh_trait_ref, @@ -3165,15 +2999,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let closure_type = self.infcx.fn_sig(closure_def_id) .subst(self.tcx(), substs.substs); let ty::Binder((trait_ref, _)) = - self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), - obligation.predicate.0.self_ty(), // (1) + self.tcx().closure_trait_ref_and_return_type(obligation.def_id(), + obligation.self_ty(), closure_type, util::TupleArgumentsFlag::No); - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an unboxed closure type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. ty::Binder(trait_ref) } @@ -3187,14 +3016,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let gen_sig = self.infcx.generator_sig(closure_def_id).unwrap() .subst(self.tcx(), substs.substs); let ty::Binder((trait_ref, ..)) = - self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(), - obligation.predicate.0.self_ty(), // (1) + self.tcx().generator_trait_ref_and_outputs(obligation.def_id(), + obligation.self_ty(), gen_sig); - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an generator type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. ty::Binder(trait_ref) } @@ -3208,9 +3032,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, def_id: DefId, // of impl or trait - substs: &Substs<'tcx>, // for impl or trait - skol_map: infer::SkolemizationMap<'tcx>, - snapshot: &infer::CombinedSnapshot) + substs: &Substs<'tcx>) // for impl or trait -> Vec<PredicateObligation<'tcx>> { debug!("impl_or_trait_obligations(def_id={:?})", def_id); @@ -3232,7 +3054,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // that order. let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); - let predicates = predicates.predicates.iter().flat_map(|predicate| { + predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth, &predicate.subst(tcx, substs)); predicate.obligations.into_iter().chain( @@ -3242,8 +3064,58 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { param_env, predicate: predicate.value })) - }).collect(); - self.infcx().plug_leaks(skol_map, snapshot, predicates) + }).collect() + } + + /// Create the bounds list from the given source for the given obligation. + /// `obligation` is expected to have type variables resolved. + fn bounds_list_iterator<'a>(&'a mut self, + stack: &'a TraitObligationStack<'a, 'tcx>, + obligation: &TraitObligation<'tcx>, + bounds_list: BoundsList) + -> Box<Iterator<Item = ty::PolyTraitRef<'tcx>> + 'a> + where 'cx: 'a { + let bounds: Box<Iterator<Item = ty::Predicate<'tcx>>> = match bounds_list { + BoundsList::ParamEnv => + Box::new(obligation.param_env.caller_bounds.into_iter().cloned()), + + BoundsList::TraitBounds => { + // Identify the trait from which `Self` is a + // projection (if any), along with its substitutions: + let self_ty = obligation.self_ty(); + let (def_id, substs) = match self_ty.sty { + ty::TyProjection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), + ty::TyAnon(def_id, substs) => (def_id, substs), + + // Not a projection? Return empty bounds list. + _ => return Box::new(None.into_iter()), + }; + + debug!("bounds_list_iterator: def_id={:?}, substs={:?}", + def_id, substs); + + let predicates_of = self.tcx().predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx(), substs); + debug!("bounds_list_iterator: bounds={:?}", bounds); + + Box::new(util::elaborate_predicates(self.tcx(), bounds.predicates)) + } + }; + + // Filter down to trait-ref bounds: + let tcx = self.tcx(); + let bounds = bounds.filter_map(move |o| o.poly_trait(tcx)); + + // Micro-optimization: filter out predicates relating to different + // traits. + let bounds = bounds.filter(move |&p| p.def_id() == stack.obligation.def_id()); + + // Remove duplicates. + let mut dedup = FxHashSet(); + let bounds = bounds.filter(move |&p| dedup.insert(p)); + + // Keep only those that may apply + Box::new(bounds.filter(move |&p| self.evaluate_where_clause(stack, p).may_apply())) } } @@ -3270,7 +3142,7 @@ impl<'tcx> TraitObligation<'tcx> { // by using -Z verbose or just a CLI argument. if obligation.recursion_depth >= 0 { let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), + parent_trait_ref: obligation.predicate, parent_code: Rc::new(obligation.cause.code.clone()) }; let derived_code = variant(derived_cause); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index d8d0715ff3957..c2aeb8f6c9031 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -217,7 +217,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_impl: DefId) -> Result<&'tcx Substs<'tcx>, ()> { let selcx = &mut SelectionContext::new(&infcx); - let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); + let target_substs = infcx.fresh_substs_for_item(param_env.universe, DUMMY_SP, target_impl); let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx, param_env, target_impl, @@ -386,14 +386,14 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option<String> { w.push('>'); } - write!(w, " {} for {}", trait_ref, tcx.type_of(impl_def_id)).unwrap(); + write!(w, " {} for {}", trait_ref.print_without_self(), tcx.type_of(impl_def_id)).unwrap(); // The predicates will contain default bounds like `T: Sized`. We need to // remove these bounds, and add `T: ?Sized` to any untouched type parameters. let predicates = tcx.predicates_of(impl_def_id).predicates; let mut pretty_predicates = Vec::with_capacity(predicates.len()); for p in predicates { - if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { + if let Some(poly_trait_ref) = p.poly_trait(tcx) { if Some(poly_trait_ref.def_id()) == sized_trait { types_without_default_bounds.remove(poly_trait_ref.self_ty()); continue; diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index da9dbc0e2c999..84728589a7b52 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> Children { let self_ty = trait_ref.self_ty(); Err(OverlapError { with_impl: possible_sibling, - trait_desc: trait_ref.to_string(), + trait_desc: trait_ref.print_without_self().to_string(), // only report the Self type if it has at least // some outer concrete shell; otherwise, it's // not adding much information. diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 73fdbfe8831e3..aea24f06ac302 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -16,8 +16,10 @@ use dep_graph::{DepKind, DepTrackingMapConfig}; use infer::TransNormalize; use std::marker::PhantomData; +use syntax::ast::DUMMY_NODE_ID; use syntax_pos::DUMMY_SP; -use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable}; +use traits::{ObligationCause, FulfillmentContext, Vtable}; + use ty::{self, Ty, TyCtxt}; use ty::subst::{Subst, Substs}; use ty::fold::{TypeFoldable, TypeFolder}; @@ -42,14 +44,8 @@ pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. ty.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(obligation_cause, - param_env, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { + let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID); + let selection = match infcx.select_poly_trait_ref(cause, param_env, trait_ref) { Ok(Some(selection)) => selection, Ok(None) => { // Ambiguity can happen when monomorphizing during trans diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 42e0834e8e43b..1a16fceca8eb7 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::subst::{Subst, Substs}; -use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; +use ty::{self, ToPredicate, ToPredicateAtom, Ty, TyCtxt}; use ty::outlives::Component; use util::nodemap::FxHashSet; use hir::{self}; @@ -22,39 +22,14 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { match *pred { - ty::Predicate::Trait(ref data) => - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), + ty::Predicate::Poly(ref binder) => + ty::Predicate::Poly(tcx.anonymize_late_bound_regions(binder)), - ty::Predicate::Equate(ref data) => - ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::RegionOutlives(ref data) => - ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::TypeOutlives(ref data) => - ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::Projection(ref data) => - ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data), - - ty::Predicate::ObjectSafe(data) => - ty::Predicate::ObjectSafe(data), - - ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind), - - ty::Predicate::Subtype(ref data) => - ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), - - ty::Predicate::ConstEvaluatable(def_id, substs) => - ty::Predicate::ConstEvaluatable(def_id, substs), + ty::Predicate::Atom(atom) => + ty::Predicate::Atom(atom), } } - struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, set: FxHashSet<ty::Predicate<'tcx>>, @@ -126,120 +101,96 @@ pub fn elaborate_predicates<'cx, 'gcx, 'tcx>( } impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { - pub fn filter_to_traits(self) -> FilterToTraits<Self> { - FilterToTraits::new(self) + pub fn filter_to_traits(self) -> FilterToTraits<'cx, 'gcx, 'tcx> { + FilterToTraits::new(self.visited.tcx, self) } fn push(&mut self, predicate: &ty::Predicate<'tcx>) { let tcx = self.visited.tcx; - match *predicate { - ty::Predicate::Trait(ref data) => { - // Predicates declared on the trait. - let predicates = tcx.super_predicates_of(data.def_id()); - - let mut predicates: Vec<_> = - predicates.predicates - .iter() - .map(|p| p.subst_supertrait(tcx, &data.to_poly_trait_ref())) - .collect(); - - debug!("super_predicates: data={:?} predicates={:?}", - data, predicates); - - // Only keep those bounds that we haven't already - // seen. This is necessary to prevent infinite - // recursion in some cases. One common case is when - // people define `trait Sized: Sized { }` rather than `trait - // Sized { }`. - predicates.retain(|r| self.visited.insert(r)); - - self.stack.extend(predicates); - } - ty::Predicate::WellFormed(..) => { - // Currently, we do not elaborate WF predicates, - // although we easily could. - } - ty::Predicate::ObjectSafe(..) => { - // Currently, we do not elaborate object-safe - // predicates. - } - ty::Predicate::Equate(..) => { - // Currently, we do not "elaborate" predicates like - // `X == Y`, though conceivably we might. For example, - // `&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. - } - ty::Predicate::ClosureKind(..) => { - // Nothing to elaborate when waiting for a closure's kind to be inferred. - } - ty::Predicate::ConstEvaluatable(..) => { - // Currently, we do not elaborate const-evaluatable - // predicates. - } - ty::Predicate::RegionOutlives(..) => { - // Nothing to elaborate from `'a: 'b`. - } - - ty::Predicate::TypeOutlives(ref data) => { - // We know that `T: 'a` for some type `T`. We can - // often elaborate this. For example, if we know that - // `[U]: 'a`, that implies that `U: 'a`. Similarly, if - // we know `&'a U: 'b`, then we know that `'a: 'b` and - // `U: 'b`. - // - // We can basically ignore bound regions here. So for - // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to - // `'a: 'b`. - - // Ignore `for<'a> T: 'a` -- we might in the future - // consider this as evidence that `T: 'static`, but - // I'm a bit wary of such constructions and so for now - // I want to be conservative. --nmatsakis - let ty_max = data.skip_binder().0; - let r_min = data.skip_binder().1; - if r_min.is_late_bound() { - return; - } + // We don't elaborate all kinds of predicates. Also, the + // treatment of binders can be a touch tricky here (in + // particular, we can't just skolemize and recurse). So don't + // do a general match on the kind of predicate, instead try to + // convert to more narrow poly-things. + + // Elaborate `T: Foo` to include where-clauses declared on trait `Foo`. + if let Some(data) = predicate.poly_trait(tcx) { + let predicates = tcx.super_predicates_of(data.def_id()); + + let mut predicates: Vec<_> = + predicates.predicates + .iter() + .map(|p| p.subst_supertrait(tcx, data)) + .collect(); + + debug!("super_predicates: data={:?} predicates={:?}", + data, predicates); + + // Only keep those bounds that we haven't already + // seen. This is necessary to prevent infinite + // recursion in some cases. One common case is when + // people define `trait Sized: Sized { }` rather than `trait + // Sized { }`. + predicates.retain(|r| self.visited.insert(r)); + + self.stack.extend(predicates); + } - let visited = &mut self.visited; - self.stack.extend( - tcx.outlives_components(ty_max) - .into_iter() - .filter_map(|component| match component { - Component::Region(r) => if r.is_late_bound() { - None - } else { - Some(ty::Predicate::RegionOutlives( - ty::Binder(ty::OutlivesPredicate(r, r_min)))) - }, - - Component::Param(p) => { - let ty = tcx.mk_param(p.idx, p.name); - Some(ty::Predicate::TypeOutlives( - ty::Binder(ty::OutlivesPredicate(ty, r_min)))) - }, - - Component::UnresolvedInferenceVariable(_) => { - None - }, - - Component::Projection(_) | - Component::EscapingProjection(_) => { - // We can probably do more here. This - // corresponds to a case like `<T as - // Foo<'a>>::U: 'b`. - None - }, - }) - .filter(|p| visited.insert(p))); + // Elaborate `T: 'a` to include other outlives relationships. + // + // e.g., `&'a i32: 'b` implies that `'a: 'b`. + if let Some(data) = predicate.poly_type_outlives(tcx) { + // We know that `T: 'a` for some type `T`. We can + // often elaborate this. For example, if we know that + // `[U]: 'a`, that implies that `U: 'a`. Similarly, if + // we know `&'a U: 'b`, then we know that `'a: 'b` and + // `U: 'b`. + // + // We can basically ignore bound regions here. So for + // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to + // `'a: 'b`. + + // Ignore `for<'a> T: 'a` -- we might in the future + // consider this as evidence that `T: 'static`, but + // I'm a bit wary of such constructions and so for now + // I want to be conservative. --nmatsakis + let ty_max = data.skip_binder().0; + let r_min = data.skip_binder().1; + if r_min.is_late_bound() { + return; } + + let visited = &mut self.visited; + self.stack.extend( + tcx.outlives_components(ty_max) + .into_iter() + .filter_map(|component| match component { + Component::Region(r) => if r.is_late_bound() { + None + } else { + Some(ty::OutlivesPredicate(r, r_min).to_predicate_atom()) + }, + + Component::Param(p) => { + let ty = tcx.mk_param(p.idx, p.name); + Some(ty::OutlivesPredicate(ty, r_min).to_predicate_atom()) + }, + + Component::UnresolvedInferenceVariable(_) => { + None + }, + + Component::Projection(_) | + Component::EscapingProjection(_) => { + // We can probably do more here. This + // corresponds to a case like `<T as + // Foo<'a>>::U: 'b`. + None + }, + }) + .map(|atom| atom.to_predicate()) + .filter(|p| visited.insert(p))); } } } @@ -265,7 +216,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> { // Supertrait iterator /////////////////////////////////////////////////////////////////////////// -pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<Elaborator<'cx, 'gcx, 'tcx>>; +pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<'cx, 'gcx, 'tcx>; pub fn supertraits<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) @@ -310,12 +261,13 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> { None => { return None; } }; - let predicates = self.tcx.super_predicates_of(def_id); + let tcx = self.tcx; + let predicates = tcx.super_predicates_of(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates .iter() - .filter_map(|p| p.to_opt_poly_trait_ref()) + .filter_map(|p| p.poly_trait(tcx)) .map(|t| t.def_id()) .filter(|&super_def_id| visited.insert(super_def_id))); Some(def_id) @@ -328,29 +280,30 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> { /// A filter around an iterator of predicates that makes it yield up /// just trait references. -pub struct FilterToTraits<I> { - base_iterator: I +pub struct FilterToTraits<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + base_iterator: Elaborator<'cx, 'gcx, 'tcx>, } -impl<I> FilterToTraits<I> { - fn new(base: I) -> FilterToTraits<I> { - FilterToTraits { base_iterator: base } +impl<'cx, 'gcx, 'tcx> FilterToTraits<'cx, 'gcx, 'tcx> { + fn new(tcx: TyCtxt<'cx, 'gcx, 'tcx>, + base_iterator: Elaborator<'cx, 'gcx, 'tcx>) + -> Self { + FilterToTraits { tcx, base_iterator } } } -impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { +impl<'cx, 'gcx, 'tcx> Iterator for FilterToTraits<'cx, 'gcx, 'tcx> { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { loop { match self.base_iterator.next() { - None => { - return None; - } - Some(ty::Predicate::Trait(data)) => { - return Some(data.to_poly_trait_ref()); - } - Some(_) => { + None => return None, + Some(predicate) => { + if let Some(trait_ref) = predicate.poly_trait(self.tcx) { + return Some(trait_ref); + } } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 37c4346a7dc93..b8efca0faf3d4 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1308,6 +1308,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + /// Creates a new skolemized region in the given parameter + /// environment. Returns a new parameter environment and the + /// resulting skolemized region. The new environment has an + /// increased universe index in which the new region is visible. + pub fn mk_skolemized_region(self, + param_env: ty::ParamEnv<'tcx>, + br: ty::BoundRegion) + -> (ty::ParamEnv<'tcx>, ty::Region<'tcx>) { + let universe = param_env.universe.subuniverse(); + let region = self.mk_region(ty::ReSkolemized(universe, br)); + let param_env = ty::ParamEnv { universe, ..param_env }; + (param_env, region) + } + pub fn serialize_query_result_cache<E>(self, encoder: &mut E) -> Result<(), E::Error> diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5cfa72c07126f..4e7e13ed51b57 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -9,9 +9,8 @@ // except according to those terms. use hir::def_id::DefId; -use infer::type_variable; use middle::const_val::ConstVal; -use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt}; +use ty::{self, BoundRegion, Region, Ty, TyCtxt}; use std::fmt; use syntax::abi; @@ -52,7 +51,6 @@ pub enum TypeError<'tcx> { CyclicTy, ProjectionMismatched(ExpectedFound<DefId>), ProjectionBoundsLength(ExpectedFound<usize>), - TyParamDefaultMismatch(ExpectedFound<type_variable::Default<'tcx>>), ExistentialMismatch(ExpectedFound<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>), } @@ -161,11 +159,6 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { values.expected, values.found) }, - TyParamDefaultMismatch(ref values) => { - write!(f, "conflicting type parameter defaults `{}` and `{}`", - values.expected.ty, - values.found.ty) - } ExistentialMismatch(ref values) => { report_maybe_different(f, format!("trait `{}`", values.expected), format!("trait `{}`", values.found)) @@ -222,6 +215,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(), + ty::TyInfer(ty::CanonicalTy(_)) | ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(), ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(), ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(), @@ -257,42 +251,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { "consider boxing your closure and/or using it as a trait object"); } }, - TyParamDefaultMismatch(values) => { - let expected = values.expected; - let found = values.found; - db.span_note(sp, &format!("conflicting type parameter defaults `{}` and `{}`", - expected.ty, - found.ty)); - - match self.hir.span_if_local(expected.def_id) { - Some(span) => { - db.span_note(span, "a default was defined here..."); - } - None => { - let item_def_id = self.parent(expected.def_id).unwrap(); - db.note(&format!("a default is defined on `{}`", - self.item_path_str(item_def_id))); - } - } - - db.span_note( - expected.origin_span, - "...that was applied to an unconstrained type variable here"); - - match self.hir.span_if_local(found.def_id) { - Some(span) => { - db.span_note(span, "a second default was defined here..."); - } - None => { - let item_def_id = self.parent(found.def_id).unwrap(); - db.note(&format!("a second default is defined on `{}`", - self.item_path_str(item_def_id))); - } - } - - db.span_note(found.origin_span, - "...that also applies to the same type variable here"); - } _ => {} } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 149999e0eee0f..84a2af9b4635a 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -519,15 +519,20 @@ pub fn shift_region_ref<'a, 'gcx, 'tcx>( pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, amount: u32, - value: &T) -> T + value: &T) + -> T where T: TypeFoldable<'tcx> { debug!("shift_regions(value={:?}, amount={})", value, amount); - value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - shift_region_ref(tcx, region, amount) - })) + if !value.has_escaping_regions() { + value.clone() + } else { + value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { + shift_region_ref(tcx, region, amount) + })) + } } /// An "escaping region" is a bound region whose binder is not part of `t`. diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 24c19bfc3f3f0..d222e0673e7f7 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -251,7 +251,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // the module more clearly. self.push_item_path(buffer, parent_def_id); if let Some(trait_ref) = impl_trait_ref { - buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty)); + buffer.push(&format!("<impl {} for {}>", trait_ref.print_without_self(), self_ty)); } else { buffer.push(&format!("<impl {}>", self_ty)); } @@ -265,7 +265,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Trait impls. buffer.push(&format!("<{} as {}>", self_ty, - trait_ref)); + trait_ref.print_without_self())); return; } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 26581501234af..24ce8fb299598 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -165,7 +165,7 @@ impl<'a> CacheDecoder<'a> { fn find_filemap_prev_bytepos(&self, prev_bytepos: BytePos) -> Option<(BytePos, StableFilemapId)> { - for (start, id) in self.prev_filemap_starts.range(BytePos(0) ... prev_bytepos).rev() { + for (start, id) in self.prev_filemap_starts.range(BytePos(0) ..= prev_bytepos).rev() { return Some((*start, *id)) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 0deababd21829..7391b510d6542 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -44,7 +44,6 @@ use std::iter::FromIterator; use std::ops::Deref; use std::rc::Rc; use std::slice; -use std::vec::IntoIter; use std::mem; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; @@ -59,16 +58,17 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use hir; -pub use self::sty::{Binder, DebruijnIndex}; +pub use self::sty::{Binder, CanonicalVar, DebruijnIndex}; pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; +pub use self::sty::{TraitRefPrintWithoutSelf, TraitRefPrintWithSelf}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::RegionKind; -pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; +pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid}; pub use self::sty::BoundRegion::*; pub use self::sty::InferTy::*; pub use self::sty::RegionKind::*; @@ -655,12 +655,15 @@ pub struct ClosureUpvar<'tcx> { pub ty: Ty<'tcx>, } -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum IntVarValue { IntType(ast::IntTy), UintType(ast::UintTy), } +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct FloatVarValue(pub ast::FloatTy); + #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef { pub name: Name, @@ -843,39 +846,30 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { } instantiated.predicates.extend(&self.predicates) } - - pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - poly_trait_ref: &ty::PolyTraitRef<'tcx>) - -> InstantiatedPredicates<'tcx> - { - assert_eq!(self.parent, None); - InstantiatedPredicates { - predicates: self.predicates.iter().map(|pred| { - pred.subst_supertrait(tcx, poly_trait_ref) - }).collect() - } - } } #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Predicate<'tcx> { + Poly(Binder<PredicateAtom<'tcx>>), + Atom(PredicateAtom<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum PredicateAtom<'tcx> { /// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` /// would be the type parameters. - Trait(PolyTraitPredicate<'tcx>), - - /// where `T1 == T2`. - Equate(PolyEquatePredicate<'tcx>), + Trait(TraitRef<'tcx>), /// where 'a : 'b - RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), + RegionOutlives(RegionOutlivesPredicate<'tcx>), /// where T : 'a - TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), + TypeOutlives(TypeOutlivesPredicate<'tcx>), /// where <T as TraitRef>::Name == X, approximately. /// See `ProjectionPredicate` struct for details. - Projection(PolyProjectionPredicate<'tcx>), + Projection(ProjectionPredicate<'tcx>), /// no syntax: T WF WellFormed(Ty<'tcx>), @@ -889,20 +883,32 @@ pub enum Predicate<'tcx> { ClosureKind(DefId, ClosureKind), /// `T1 <: T2` - Subtype(PolySubtypePredicate<'tcx>), + Subtype(SubtypePredicate<'tcx>), /// Constant initializer must evaluate successfully. ConstEvaluatable(DefId, &'tcx Substs<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { + /// If there are any binders in this predicate, skip through them + /// and expose the underlying atom. Use with caution, as the depth + /// of late-bound-regions in this atom cannot be interpreted -- + /// you don't know if there was a binder or not! + pub fn skip_binders(self) -> PredicateAtom<'tcx> { + match self { + Predicate::Poly(binder) => *binder.skip_binder(), + Predicate::Atom(atom) => atom, + } + } + /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal /// substitution in terms of what happens with bound regions. See /// lengthy comment below for details. - pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_ref: &ty::PolyTraitRef<'tcx>) + pub fn subst_supertrait(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) -> ty::Predicate<'tcx> { // The interaction between HRTB and supertraits is not entirely @@ -967,54 +973,121 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { let substs = &trait_ref.0.substs; match *self { - Predicate::Trait(ty::Binder(ref data)) => - 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)) => - Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::Projection(ty::Binder(ref data)) => - Predicate::Projection(ty::Binder(data.subst(tcx, substs))), - Predicate::WellFormed(data) => - Predicate::WellFormed(data.subst(tcx, substs)), - Predicate::ObjectSafe(trait_def_id) => - Predicate::ObjectSafe(trait_def_id), - Predicate::ClosureKind(closure_def_id, kind) => - Predicate::ClosureKind(closure_def_id, kind), - Predicate::ConstEvaluatable(def_id, const_substs) => - Predicate::ConstEvaluatable(def_id, const_substs.subst(tcx, substs)), + Predicate::Poly(binder) => + ty::Binder(binder.skip_binder().subst(tcx, substs)).to_predicate(), + + Predicate::Atom(atom) => + ty::Binder(atom.subst(tcx, substs)).to_predicate(), } } -} -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx> -} -pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>; + /// Helper for selecting subsets of predicates. The `op` here is + /// some function that transforms a PredicateAtom into an R, + /// **maintaining the binding level of any late-bound regions**. + fn poly_map<OP, R>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut op: OP) -> Option<Binder<R>> + where OP: FnMut(PredicateAtom<'tcx>) -> Option<R>, + R: TypeFoldable<'tcx>, + { + match self { + Predicate::Poly(binder) => { + match op(*binder.skip_binder()) { // binder moves from here... + Some(v) => { + Some(ty::Binder(v)) // ...to here + } + + None => None, + } + } + Predicate::Atom(atom) => { + let atom = fold::shift_regions(tcx, 1, &atom); // insert a binder here... + match op(atom) { + Some(v) => { + Some(ty::Binder(v)) // ...that we instantiate here + } + + None => None, + } + } + } + } -impl<'tcx> TraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - self.trait_ref.def_id + /// If the underlying atom is a `PredicateAtom::Trait`, returns + /// `Some(trait_ref)`. Else None. + pub fn poly_trait(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> Option<PolyTraitRef<'tcx>> { + self.poly_map(tcx, |atom| atom.trait_()) } - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { - self.trait_ref.input_types() + /// If the underlying atom is a `PredicateAtom::Trait`, returns + /// `Some(trait_ref)`. Else None. + pub fn poly_type_outlives(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> Option<PolyTypeOutlivesPredicate<'tcx>> { + self.poly_map(tcx, |atom| atom.type_outlives()) } - pub fn self_ty(&self) -> Ty<'tcx> { - self.trait_ref.self_ty() + /// If the underlying atom is a `PredicateAtom::Projection`, returns + /// `Some(trait_ref)`. Else None. + pub fn poly_projection(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) + -> Option<PolyProjectionPredicate<'tcx>> { + self.poly_map(tcx, |atom| atom.projection()) + } + + /// Does various short-circuit checks and returns true if `self` + /// and `other` are obviously NOT unifiable. + pub fn fast_reject<O>(&self, other: O) -> bool + where O: ToPredicate<'tcx> + { + let other = other.to_predicate(); + return self.skip_binders().fast_reject(other.skip_binders()); } } -impl<'tcx> PolyTraitPredicate<'tcx> { - pub fn def_id(&self) -> DefId { - // ok to skip binder since trait def-id does not care about regions - self.0.def_id() +impl<'cx, 'gcx, 'tcx> PredicateAtom<'tcx> { + /// Does various short-circuit checks and returns true if `self` + /// and `other` are obviously NOT unifiable. + pub fn fast_reject<O>(self, other: O) -> bool + where O: ToPredicateAtom<'tcx> + { + let other = other.to_predicate_atom(); + return fast_reject_mono(self, other); + + fn fast_reject_mono<'tcx>(a: PredicateAtom<'tcx>, b: PredicateAtom<'tcx>) -> bool { + match (a, b) { + (ty::PredicateAtom::Projection(ref a), ty::PredicateAtom::Projection(ref b)) => + a.projection_ty.item_def_id != b.projection_ty.item_def_id, + (ty::PredicateAtom::Trait(ref a), ty::PredicateAtom::Trait(ref b)) => + a.def_id != b.def_id, + _ => + mem::discriminant(&a) != mem::discriminant(&b), + } + } + } + + /// If this is a `PredicateAtom::Trait`, returns `Some(_)`. Else None. + pub fn trait_(self) -> Option<TraitRef<'tcx>> { + if let PredicateAtom::Trait(t) = self { + Some(t) + } else { + None + } + } + + /// If this is a `PredicateAtom::Projection`, returns `Some(_)`. Else None. + pub fn projection(self) -> Option<ProjectionPredicate<'tcx>> { + if let PredicateAtom::Projection(t) = self { + Some(t) + } else { + None + } + } + + /// If this is a `PredicateAtom::TypeOutlives`, returns `Some(_)`. Else None. + pub fn type_outlives(self) -> Option<TypeOutlivesPredicate<'tcx>> { + if let PredicateAtom::TypeOutlives(t) = self { + Some(t) + } else { + None + } } } @@ -1024,10 +1097,10 @@ pub type PolyEquatePredicate<'tcx> = ty::Binder<EquatePredicate<'tcx>>; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B` -pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>; -pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<ty::Region<'tcx>, - ty::Region<'tcx>>; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; +pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>; +pub type PolyRegionOutlivesPredicate<'tcx> = Binder<RegionOutlivesPredicate<'tcx>>; +pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; +pub type PolyTypeOutlivesPredicate<'tcx> = Binder<OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct SubtypePredicate<'tcx> { @@ -1058,6 +1131,14 @@ pub struct ProjectionPredicate<'tcx> { pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { + /// Returns the def-id of the item being projected by this + /// projection predicate. So if `self` were `<T as Iterator>::Item + /// = U`, then this method would return the def-id for + /// `Iterator::Item`. + pub fn item_def_id(&self) -> DefId { + self.skip_binder().projection_ty.item_def_id + } + pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> { // Note: unlike with TraitRef::to_poly_trait_ref(), // self.0.trait_ref is permitted to have escaping regions. @@ -1072,133 +1153,79 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { } } -pub trait ToPolyTraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; +impl<'tcx> ProjectionPredicate<'tcx> { + /// Given a projection predicate like `<T0 as Trait<T1...Tn>>::Foo + /// = U`, returns the trait ref `T0 as Trait<T1...Tn>` from the + /// projection. + pub fn to_trait_ref(&self, tcx: TyCtxt) -> TraitRef<'tcx> { + self.projection_ty.trait_ref(tcx) + } } -impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - assert!(!self.has_escaping_regions()); - ty::Binder(self.clone()) - } +pub trait ToPredicate<'tcx>: Sized { + fn to_predicate(self) -> Predicate<'tcx>; } -impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - self.map_bound_ref(|trait_pred| trait_pred.trait_ref) +impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> { + fn to_predicate(self) -> Predicate<'tcx> { + self } } -pub trait ToPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx>; +impl<'tcx, T> ToPredicate<'tcx> for T + where T: ToPredicateAtom<'tcx> +{ + fn to_predicate(self) -> Predicate<'tcx> { + Predicate::Atom(self.to_predicate_atom()) + } } -impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - // we're about to add a binder, so let's check that we don't - // accidentally capture anything, or else that might be some - // weird debruijn accounting. - assert!(!self.has_escaping_regions()); - - ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { - trait_ref: self.clone() - })) +impl<'tcx, T> ToPredicate<'tcx> for Binder<T> + where T: ToPredicateAtom<'tcx> +{ + fn to_predicate(self) -> Predicate<'tcx> { + let bound_atom = self.map_bound(|t| t.to_predicate_atom()); + Predicate::Poly(bound_atom) } } -impl<'tcx> ToPredicate<'tcx> for PolyTraitRef<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - ty::Predicate::Trait(self.to_poly_trait_predicate()) - } +pub trait ToPredicateAtom<'tcx>: Sized + TypeFoldable<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx>; } -impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Equate(self.clone()) +impl<'tcx> ToPredicateAtom<'tcx> for PredicateAtom<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx> { + self } } -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::RegionOutlives(self.clone()) +impl<'tcx> ToPredicateAtom<'tcx> for TraitRef<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx> { + PredicateAtom::Trait(self) } } -impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::TypeOutlives(self.clone()) +impl<'tcx> ToPredicateAtom<'tcx> for RegionOutlivesPredicate<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx> { + PredicateAtom::RegionOutlives(self) } } -impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { - fn to_predicate(&self) -> Predicate<'tcx> { - Predicate::Projection(self.clone()) +impl<'tcx> ToPredicateAtom<'tcx> for TypeOutlivesPredicate<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx> { + PredicateAtom::TypeOutlives(self) } } -impl<'tcx> Predicate<'tcx> { - /// Iterates over the types in this predicate. Note that in all - /// cases this is skipping over a binder, so late-bound regions - /// with depth 0 are bound by the predicate. - pub fn walk_tys(&self) -> IntoIter<Ty<'tcx>> { - let vec: Vec<_> = match *self { - ty::Predicate::Trait(ref data) => { - data.skip_binder().input_types().collect() - } - 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] - } - ty::Predicate::RegionOutlives(..) => { - vec![] - } - ty::Predicate::Projection(ref data) => { - data.0.projection_ty.substs.types().chain(Some(data.0.ty)).collect() - } - ty::Predicate::WellFormed(data) => { - vec![data] - } - ty::Predicate::ObjectSafe(_trait_def_id) => { - vec![] - } - ty::Predicate::ClosureKind(_closure_def_id, _kind) => { - vec![] - } - ty::Predicate::ConstEvaluatable(_, substs) => { - substs.types().collect() - } - }; - - // The only reason to collect into a vector here is that I was - // too lazy to make the full (somewhat complicated) iterator - // type that would be needed here. But I wanted this fn to - // return an iterator conceptually, rather than a `Vec`, so as - // to be closer to `Ty::walk`. - vec.into_iter() +impl<'tcx> ToPredicateAtom<'tcx> for ProjectionPredicate<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx> { + PredicateAtom::Projection(self) } +} - pub fn to_opt_poly_trait_ref(&self) -> Option<PolyTraitRef<'tcx>> { - match *self { - Predicate::Trait(ref t) => { - Some(t.to_poly_trait_ref()) - } - Predicate::Projection(..) | - Predicate::Equate(..) | - Predicate::Subtype(..) | - Predicate::RegionOutlives(..) | - Predicate::WellFormed(..) | - Predicate::ObjectSafe(..) | - Predicate::ClosureKind(..) | - Predicate::TypeOutlives(..) | - Predicate::ConstEvaluatable(..) => { - None - } - } +impl<'tcx> ToPredicateAtom<'tcx> for SubtypePredicate<'tcx> { + fn to_predicate_atom(self) -> PredicateAtom<'tcx> { + PredicateAtom::Subtype(self) } } @@ -1236,6 +1263,91 @@ impl<'tcx> InstantiatedPredicates<'tcx> { } } +/// "Universes" are used during type- and trait-checking in the +/// presence of `for<..>` binders to control what sets of names are +/// visible. Universes are arranged into a tree: the root universe +/// contains names that are always visible. But when you enter into +/// some subuniverse, then it may add names that are only visible +/// within that subtree (but it can still name the names of its +/// ancestor universes). +/// +/// To make this more concrete, consider this program: +/// +/// ``` +/// struct Foo { } +/// fn bar<T>(x: T) { +/// let y: for<'a> fn(&'a u8, Foo) = ...; +/// } +/// ``` +/// +/// The struct name `Foo` is in the root universe U0. But the type +/// parameter `T`, introduced on `bar`, is in a subuniverse U1 -- +/// i.e., within `bar`, we can name both `T` and `Foo`, but outside of +/// `bar`, we cannot name `T`. Then, within the type of `y`, the +/// region `'a` is in a subuniverse U2 of U1, because we can name it +/// inside the fn type but not outside. +/// +/// Universes are related to **skolemization** -- which is a way of +/// doing type- and trait-checking around these "forall" binders (also +/// called **universal quantification**). The idea is that when, in +/// the body of `bar`, we refer to `T` as a type, we aren't referring +/// to any type in particular, but rather a kind of "fresh" type that +/// is distinct from all other types we have actually declared. This +/// is called a **skolemized** type, and we use universes to talk +/// about this. In other words, a type name in universe 0 always +/// corresponds to some "ground" type that the user declared, but a +/// type name in a non-zero universe is a skolemized type -- an +/// idealized representative of "types in general" that we use for +/// checking generic functions. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub struct UniverseIndex(u32); + +impl UniverseIndex { + /// The root universe, where things that the user defined are + /// visible. + pub const ROOT: UniverseIndex = UniverseIndex(0); + + /// A "subuniverse" corresponds to being inside a `forall` quantifier. + /// So, for example, suppose we have this type in universe `U`: + /// + /// ``` + /// for<'a> fn(&'a u32) + /// ``` + /// + /// Once we "enter" into this `for<'a>` quantifier, we are in a + /// subuniverse of `U` -- in this new universe, we can name the + /// region `'a`, but that region was not nameable from `U` because + /// it was not in scope there. + pub fn subuniverse(self) -> UniverseIndex { + UniverseIndex(self.0.checked_add(1).unwrap()) + } + + pub fn from(v: u32) -> UniverseIndex { + UniverseIndex(v) + } + + /// Indicates whether a name in this universe is visible in the + /// universe `other`. + pub fn is_visible_in(self, other: UniverseIndex) -> bool { + self <= other + } + + pub fn as_u32(&self) -> u32 { + self.0 + } + + pub fn as_usize(&self) -> usize { + self.0 as usize + } + + /// Gets the "depth" of this universe in the universe tree. This + /// is not really useful except for e.g. the `HashStable` + /// implementation + pub fn depth(&self) -> u32 { + self.0 + } +} + /// When type checking, we use the `ParamEnv` to track /// details about the set of where-clauses that are in scope at this /// particular point. @@ -1250,6 +1362,17 @@ pub struct ParamEnv<'tcx> { /// want `Reveal::All` -- note that this is always paired with an /// empty environment. To get that, use `ParamEnv::reveal()`. pub reveal: traits::Reveal, + + /// What is the innermost universe we have created? Starts out as + /// `UniverseIndex::root()` but grows from there as we enter + /// universal quantifiers. + /// + /// NB: At present, we exclude the universal quantifiers on the + /// item we are type-checking, and just consider those names as + /// part of the root universe. So this would only get incremented + /// when we enter into a higher-ranked (`for<..>`) type or trait + /// bound. + pub universe: UniverseIndex, } impl<'tcx> ParamEnv<'tcx> { @@ -1282,6 +1405,27 @@ impl<'tcx> ParamEnv<'tcx> { } } } + + pub fn normalize_region(self, region: ty::Region<'tcx>) -> NormalizedRegion { + NormalizedRegion { + region: *region + } + } +} + +/// Normally, the meaning of a region is defined *relative* to some +/// environment -- this is particular true with late-bound regions, +/// where region depth requires a parameter environment to +/// interpret. (See late-bound regions for more details.) +/// +/// But there are times when it is convenient to be able to reference +/// a region independently and know what universe it is in. For such +/// cases, the region can be converted to a "normalized region". The +/// primary effect of this is to convert *from* deBruijn indexing in +/// LBR to storing the universe directly. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct NormalizedRegion { + region: RegionKind } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -2565,7 +2709,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // sure that this will succeed without errors anyway. let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), - traits::Reveal::UserFacing); + traits::Reveal::UserFacing, + ty::UniverseIndex::ROOT); let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| { tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 5f1448cd1f18e..a351fbd61ec8c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use infer::type_variable; use middle::const_val::{self, ConstVal, ConstAggregate, ConstEvalErr}; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -100,6 +99,23 @@ impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::TraitRefPrintWithoutSelf<'a> { + type Lifted = ty::TraitRefPrintWithoutSelf<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitRefPrintWithoutSelf { trait_ref }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::TraitRefPrintWithSelf<'a> { + type Lifted = ty::TraitRefPrintWithSelf<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { + tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitRefPrintWithSelf { + trait_ref, + separator: self.separator, + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { type Lifted = ty::ExistentialTraitRef<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { @@ -110,16 +126,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialTraitRef<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> { - type Lifted = ty::TraitPredicate<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) - -> Option<ty::TraitPredicate<'tcx>> { - tcx.lift(&self.trait_ref).map(|trait_ref| ty::TraitPredicate { - trait_ref, - }) - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { type Lifted = ty::EquatePredicate<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) @@ -190,36 +196,45 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { type Lifted = ty::Predicate<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { match *self { - ty::Predicate::Trait(ref binder) => { - tcx.lift(binder).map(ty::Predicate::Trait) - } - ty::Predicate::Equate(ref binder) => { - tcx.lift(binder).map(ty::Predicate::Equate) + ty::Predicate::Poly(ref binder) => + tcx.lift(binder).map(ty::Predicate::Poly), + ty::Predicate::Atom(ref atom) => + tcx.lift(atom).map(ty::Predicate::Atom), + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> { + type Lifted = ty::PredicateAtom<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { + match *self { + ty::PredicateAtom::Trait(ref binder) => { + tcx.lift(binder).map(ty::PredicateAtom::Trait) } - ty::Predicate::Subtype(ref binder) => { - tcx.lift(binder).map(ty::Predicate::Subtype) + ty::PredicateAtom::Subtype(ref binder) => { + tcx.lift(binder).map(ty::PredicateAtom::Subtype) } - ty::Predicate::RegionOutlives(ref binder) => { - tcx.lift(binder).map(ty::Predicate::RegionOutlives) + ty::PredicateAtom::RegionOutlives(ref binder) => { + tcx.lift(binder).map(ty::PredicateAtom::RegionOutlives) } - ty::Predicate::TypeOutlives(ref binder) => { - tcx.lift(binder).map(ty::Predicate::TypeOutlives) + ty::PredicateAtom::TypeOutlives(ref binder) => { + tcx.lift(binder).map(ty::PredicateAtom::TypeOutlives) } - ty::Predicate::Projection(ref binder) => { - tcx.lift(binder).map(ty::Predicate::Projection) + ty::PredicateAtom::Projection(ref binder) => { + tcx.lift(binder).map(ty::PredicateAtom::Projection) } - ty::Predicate::WellFormed(ty) => { - tcx.lift(&ty).map(ty::Predicate::WellFormed) + ty::PredicateAtom::WellFormed(ty) => { + tcx.lift(&ty).map(ty::PredicateAtom::WellFormed) } - ty::Predicate::ClosureKind(closure_def_id, kind) => { - Some(ty::Predicate::ClosureKind(closure_def_id, kind)) + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => { + Some(ty::PredicateAtom::ClosureKind(closure_def_id, kind)) } - ty::Predicate::ObjectSafe(trait_def_id) => { - Some(ty::Predicate::ObjectSafe(trait_def_id)) + ty::PredicateAtom::ObjectSafe(trait_def_id) => { + Some(ty::PredicateAtom::ObjectSafe(trait_def_id)) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { tcx.lift(&substs).map(|substs| { - ty::Predicate::ConstEvaluatable(def_id, substs) + ty::PredicateAtom::ConstEvaluatable(def_id, substs) }) } } @@ -239,6 +254,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { tcx.lift(&self.caller_bounds).map(|caller_bounds| { ty::ParamEnv { reveal: self.reveal, + universe: self.universe, caller_bounds, } }) @@ -381,19 +397,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound<T> { } } -impl<'a, 'tcx> Lift<'tcx> for type_variable::Default<'a> { - type Lifted = type_variable::Default<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.ty).map(|ty| { - type_variable::Default { - ty, - origin_span: self.origin_span, - def_id: self.def_id - } - }) - } -} - impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { type Lifted = ty::error::TypeError<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> { @@ -425,9 +428,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), - TyParamDefaultMismatch(ref x) => { - return tcx.lift(x).map(TyParamDefaultMismatch) - } ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch) }) } @@ -601,12 +601,23 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> { ty::ParamEnv { reveal: self.reveal, caller_bounds: self.caller_bounds.fold_with(folder), + universe: self.universe.fold_with(folder), } } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - let &ty::ParamEnv { reveal: _, ref caller_bounds } = self; - caller_bounds.super_visit_with(visitor) + let &ty::ParamEnv { reveal: _, ref universe, ref caller_bounds } = self; + universe.super_visit_with(visitor) || caller_bounds.super_visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::UniverseIndex { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + *self + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { + false } } @@ -773,6 +784,31 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::TraitRefPrintWithoutSelf<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::TraitRefPrintWithoutSelf { + trait_ref: self.trait_ref.fold_with(folder), + } + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.trait_ref.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::TraitRefPrintWithSelf<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::TraitRefPrintWithSelf { + trait_ref: self.trait_ref.fold_with(folder), + separator: self.separator, + } + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + self.trait_ref.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialTraitRef<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ExistentialTraitRef { @@ -951,41 +987,54 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::Predicate<'tcx>> { impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - ty::Predicate::Trait(ref a) => - 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) => - ty::Predicate::TypeOutlives(binder.fold_with(folder)), - ty::Predicate::Projection(ref binder) => - ty::Predicate::Projection(binder.fold_with(folder)), - ty::Predicate::WellFormed(data) => - ty::Predicate::WellFormed(data.fold_with(folder)), - ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind), - ty::Predicate::ObjectSafe(trait_def_id) => - ty::Predicate::ObjectSafe(trait_def_id), - ty::Predicate::ConstEvaluatable(def_id, substs) => - ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)), + ty::Predicate::Poly(ref a) => ty::Predicate::Poly(a.fold_with(folder)), + ty::Predicate::Atom(ref a) => ty::Predicate::Atom(a.fold_with(folder)), + } + } + + fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { + match *self { + ty::Predicate::Poly(ref a) => a.visit_with(visitor), + ty::Predicate::Atom(ref a) => a.visit_with(visitor), + } + } +} + +impl<'tcx> TypeFoldable<'tcx> for ty::PredicateAtom<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + match *self { + ty::PredicateAtom::Trait(ref a) => + ty::PredicateAtom::Trait(a.fold_with(folder)), + ty::PredicateAtom::Subtype(ref binder) => + ty::PredicateAtom::Subtype(binder.fold_with(folder)), + ty::PredicateAtom::RegionOutlives(ref binder) => + ty::PredicateAtom::RegionOutlives(binder.fold_with(folder)), + ty::PredicateAtom::TypeOutlives(ref binder) => + ty::PredicateAtom::TypeOutlives(binder.fold_with(folder)), + ty::PredicateAtom::Projection(ref binder) => + ty::PredicateAtom::Projection(binder.fold_with(folder)), + ty::PredicateAtom::WellFormed(data) => + ty::PredicateAtom::WellFormed(data.fold_with(folder)), + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => + ty::PredicateAtom::ClosureKind(closure_def_id, kind), + ty::PredicateAtom::ObjectSafe(trait_def_id) => + ty::PredicateAtom::ObjectSafe(trait_def_id), + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => + ty::PredicateAtom::ConstEvaluatable(def_id, substs.fold_with(folder)), } } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { 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), - ty::Predicate::WellFormed(data) => data.visit_with(visitor), - ty::Predicate::ClosureKind(_closure_def_id, _kind) => false, - ty::Predicate::ObjectSafe(_trait_def_id) => false, - ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor), + ty::PredicateAtom::Trait(ref a) => a.visit_with(visitor), + ty::PredicateAtom::Subtype(ref binder) => binder.visit_with(visitor), + ty::PredicateAtom::RegionOutlives(ref binder) => binder.visit_with(visitor), + ty::PredicateAtom::TypeOutlives(ref binder) => binder.visit_with(visitor), + ty::PredicateAtom::Projection(ref binder) => binder.visit_with(visitor), + ty::PredicateAtom::WellFormed(data) => data.visit_with(visitor), + ty::PredicateAtom::ClosureKind(_closure_def_id, _kind) => false, + ty::PredicateAtom::ObjectSafe(_trait_def_id) => false, + ty::PredicateAtom::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor), } } } @@ -1066,18 +1115,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { } } -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 { - trait_ref: self.trait_ref.fold_with(folder) - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.trait_ref.visit_with(visitor) - } -} - impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U> where T : TypeFoldable<'tcx>, U : TypeFoldable<'tcx>, @@ -1119,20 +1156,6 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFoun } } -impl<'tcx> TypeFoldable<'tcx> for type_variable::Default<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - type_variable::Default { - ty: self.ty.fold_with(folder), - origin_span: self.origin_span, - def_id: self.def_id - } - } - - fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.ty.visit_with(visitor) - } -} - impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { self.iter().map(|x| x.fold_with(folder)).collect() @@ -1172,7 +1195,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { ProjectionMismatched(x) => ProjectionMismatched(x), ProjectionBoundsLength(x) => ProjectionBoundsLength(x), Sorts(x) => Sorts(x.fold_with(folder)), - TyParamDefaultMismatch(ref x) => TyParamDefaultMismatch(x.fold_with(folder)), ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)), } } @@ -1191,7 +1213,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> { b.visit_with(visitor) }, Sorts(x) => x.visit_with(visitor), - TyParamDefaultMismatch(ref x) => x.visit_with(visitor), ExistentialMismatch(x) => x.visit_with(visitor), Mismatch | Mutability | diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index d0ac7d0183a58..da85de7561cdd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -14,8 +14,9 @@ use hir::def_id::DefId; use middle::const_val::ConstVal; use middle::region; +use rustc_data_structures::indexed_vec::Idx; use ty::subst::{Substs, Subst}; -use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtDef, TypeFlags, ToPredicate, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; use ty::subst::Kind; @@ -342,18 +343,16 @@ impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { impl<'a, 'gcx, 'tcx> Binder<ExistentialPredicate<'tcx>> { pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { - use ty::ToPredicate; match *self.skip_binder() { - ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(), + ExistentialPredicate::Trait(tr) => + Binder(tr).with_self_ty(tcx, self_ty).to_predicate(), ExistentialPredicate::Projection(p) => - ty::Predicate::Projection(Binder(p.with_self_ty(tcx, self_ty))), - ExistentialPredicate::AutoTrait(did) => { - let trait_ref = Binder(ty::TraitRef { + Binder(p.with_self_ty(tcx, self_ty)).to_predicate(), + ExistentialPredicate::AutoTrait(did) => + Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]), - }); - trait_ref.to_predicate() - } + }).to_predicate(), } } } @@ -427,6 +426,12 @@ impl<'tcx> Binder<&'tcx Slice<ExistentialPredicate<'tcx>>> { /// Note that a `TraitRef` introduces a level of region binding, to /// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a /// U>` or higher-ranked object types. +/// +/// A note on `Display`: there are multiple ways to display a +/// `TraitRef`; the default does not print the self type. Probably the +/// default should be removed, but for now, you can explicitly choose +/// a display style by invoking the methods like +/// `print_with_colon()` and `print_without_self()`. #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitRef<'tcx> { pub def_id: DefId, @@ -449,32 +454,73 @@ impl<'tcx> TraitRef<'tcx> { // associated types. self.substs.types() } + + /// Returns a wrapper that implements `Display` and displays like + /// `P0: Trait<..>`. + pub fn print_with_colon(self) -> TraitRefPrintWithSelf<'tcx> { + TraitRefPrintWithSelf { trait_ref: self, separator: ": " } + } + + /// Returns a wrapper that implements `Display` and displays like + /// `P0: Trait<..>`. + pub fn print_with_as(self) -> TraitRefPrintWithSelf<'tcx> { + TraitRefPrintWithSelf { trait_ref: self, separator: " as " } + } + + /// Returns a wrapper that implements `Display` and displays like + /// `Trait<..>`. + pub fn print_without_self(self) -> TraitRefPrintWithoutSelf<'tcx> { + TraitRefPrintWithoutSelf { trait_ref: self } + } +} + +/// Wrapper around TraitRef used only for its `Display` impl. +/// This version displays like `P0: Trait<P1...Pn>`. +#[derive(Copy, Clone)] +pub struct TraitRefPrintWithSelf<'tcx> { + pub trait_ref: TraitRef<'tcx>, + pub separator: &'static str, +} + +/// Wrapper around TraitRef used only for its `Display` impl. +/// This version displays like `Trait<P1...Pn>`. +#[derive(Copy, Clone)] +pub struct TraitRefPrintWithoutSelf<'tcx> { + pub trait_ref: TraitRef<'tcx> } pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>; impl<'tcx> PolyTraitRef<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { - self.0.self_ty() + // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> + self.skip_binder().self_ty() } pub fn def_id(&self) -> DefId { - self.0.def_id + self.skip_binder().def_id } pub fn substs(&self) -> &'tcx Substs<'tcx> { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.substs + self.skip_binder().substs } pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.input_types() + self.skip_binder().input_types() + } + + pub fn print_with_colon(self) -> Binder<TraitRefPrintWithSelf<'tcx>> { + self.map_bound(|t| t.print_with_colon()) } - pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { - // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) + pub fn print_with_as(self) -> Binder<TraitRefPrintWithSelf<'tcx>> { + self.map_bound(|t| t.print_with_as()) + } + + pub fn print_without_self(self) -> Binder<TraitRefPrintWithoutSelf<'tcx>> { + self.map_bound(|t| t.print_without_self()) } } @@ -521,12 +567,12 @@ pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>; impl<'tcx> PolyExistentialTraitRef<'tcx> { pub fn def_id(&self) -> DefId { - self.0.def_id + self.skip_binder().def_id } pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.input_types() + self.skip_binder().input_types() } } @@ -854,7 +900,7 @@ pub enum RegionKind { /// A skolemized region - basically the higher-ranked version of ReFree. /// Should not exist after typeck. - ReSkolemized(SkolemizedRegionVid, BoundRegion), + ReSkolemized(ty::UniverseIndex, BoundRegion), /// Empty lifetime is for data that is never accessed. /// Bottom in the region lattice. We treat ReEmpty somewhat @@ -867,6 +913,9 @@ pub enum RegionKind { /// Erased region, used by trait selection, in MIR and during trans. ReErased, + + /// Canonicalized region, used only when preparing a trait query. + ReCanonical(CanonicalVar), } impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {} @@ -898,11 +947,6 @@ pub struct RegionVid { pub index: u32, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub struct SkolemizedRegionVid { - pub index: u32, -} - #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum InferTy { TyVar(TyVid), @@ -915,8 +959,13 @@ pub enum InferTy { FreshTy(u32), FreshIntTy(u32), FreshFloatTy(u32), + + /// Canonicalized type variable, used only when preparing a trait query. + CanonicalTy(CanonicalVar), } +newtype_index!(CanonicalVar); + /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { @@ -985,6 +1034,13 @@ impl RegionKind { } } + pub fn is_skolemized(&self) -> bool { + match *self { + ty::ReSkolemized(..) => true, + _ => false, + } + } + pub fn needs_infer(&self) -> bool { match *self { ty::ReVar(..) | ty::ReSkolemized(..) => true, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 39842a543b54b..097956551bb73 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -153,14 +153,15 @@ impl<'tcx> ty::ParamEnv<'tcx> { /// Construct a trait environment suitable for contexts where /// there are no where clauses in scope. pub fn empty(reveal: Reveal) -> Self { - Self::new(ty::Slice::empty(), reveal) + Self::new(ty::Slice::empty(), reveal, ty::UniverseIndex::ROOT) } /// Construct a trait environment with the given set of predicates. pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>, - reveal: Reveal) + reveal: Reveal, + universe: ty::UniverseIndex) -> Self { - ty::ParamEnv { caller_bounds, reveal } + ty::ParamEnv { caller_bounds, reveal, universe } } /// Returns a new parameter environment with the same clauses, but @@ -372,7 +373,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn required_region_bounds(self, erased_self_ty: Ty<'tcx>, predicates: Vec<ty::Predicate<'tcx>>) - -> Vec<ty::Region<'tcx>> { + -> Vec<ty::Region<'tcx>> + { debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", erased_self_ty, predicates); @@ -381,19 +383,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { traits::elaborate_predicates(self, predicates) .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => { + // We ignore late-bound regions below, so we can skip binder: + match predicate.skip_binders() { + ty::PredicateAtom::Projection(..) | + ty::PredicateAtom::Trait(..) | + ty::PredicateAtom::Subtype(..) | + ty::PredicateAtom::WellFormed(..) | + ty::PredicateAtom::ObjectSafe(..) | + ty::PredicateAtom::ClosureKind(..) | + ty::PredicateAtom::ConstEvaluatable(..) | + ty::PredicateAtom::RegionOutlives(..) => { None } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t, r)) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> // erased_self_ty : 'a` (we interpret a @@ -772,6 +774,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) | + ty::ReCanonical(..) | ty::ReSkolemized(..) => { bug!("TypeIdHasher: unexpected region {:?}", r) } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c631e2c4db51b..635b3627efe0e 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -12,7 +12,7 @@ use hir::def_id::DefId; use middle::const_val::{ConstVal, ConstAggregate}; use infer::InferCtxt; use ty::subst::Substs; -use traits; +use traits::{self, PredicateObligation}; use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use std::iter::once; use syntax::ast; @@ -54,7 +54,7 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: ast::NodeId, - trait_ref: &ty::TraitRef<'tcx>, + trait_ref: ty::TraitRef<'tcx>, span: Span) -> Vec<traits::PredicateObligation<'tcx>> { @@ -72,37 +72,30 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, { let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] }; - // (*) ok to skip binders, because wf code is prepared for it - match *predicate { - ty::Predicate::Trait(ref t) => { - wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) + // OK to skip binders, because wf code is prepared for it: + match predicate.skip_binders() { + ty::PredicateAtom::Trait(t) => { + wf.compute_trait_ref(t, Elaborate::None); } - ty::Predicate::Equate(ref t) => { - wf.compute(t.skip_binder().0); - wf.compute(t.skip_binder().1); - } - ty::Predicate::RegionOutlives(..) => { - } - ty::Predicate::TypeOutlives(ref t) => { - wf.compute(t.skip_binder().0); + ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t, _r)) => { + wf.compute(t); } - ty::Predicate::Projection(ref t) => { - let t = t.skip_binder(); // (*) - wf.compute_projection(t.projection_ty); - wf.compute(t.ty); + ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => { + wf.compute_projection(projection_ty); + wf.compute(ty); } - ty::Predicate::WellFormed(t) => { + ty::PredicateAtom::WellFormed(t) => { wf.compute(t); } - ty::Predicate::ObjectSafe(_) => { + ty::PredicateAtom::RegionOutlives(_) | + ty::PredicateAtom::ObjectSafe(_) | + ty::PredicateAtom::ClosureKind(_, _) => { } - ty::Predicate::ClosureKind(..) => { + ty::PredicateAtom::Subtype(ty::SubtypePredicate { a, b, .. }) => { + wf.compute(a); + wf.compute(b); } - ty::Predicate::Subtype(ref data) => { - wf.compute(data.skip_binder().a); // (*) - wf.compute(data.skip_binder().b); // (*) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); @@ -173,7 +166,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// Pushes the obligations required for `trait_ref` to be WF into /// `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { + fn compute_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, elaborate: Elaborate) { let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); let cause = self.cause(traits::MiscObligation); @@ -195,9 +188,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.out.extend( trait_ref.substs.types() .filter(|ty| !ty.has_escaping_regions()) - .map(|ty| traits::Obligation::new(cause.clone(), - param_env, - ty::Predicate::WellFormed(ty)))); + .map(|ty| traits::PredicateObligation::from( + cause.clone(), + param_env, + ty::PredicateAtom::WellFormed(ty)))); } /// Pushes the obligations required for `trait_ref::Item` to be WF @@ -207,12 +201,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // WF and (b) the trait-ref holds. (It may also be // normalizable and be WF that way.) let trait_ref = data.trait_ref(self.infcx.tcx); - self.compute_trait_ref(&trait_ref, Elaborate::None); + self.compute_trait_ref(trait_ref, Elaborate::None); if !data.has_escaping_regions() { - let predicate = trait_ref.to_predicate(); let cause = self.cause(traits::ProjectionWf(data)); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); + self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate())); } } @@ -247,11 +240,11 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); - let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); + let predicate = ty::PredicateAtom::ConstEvaluatable(def_id, substs); let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::new(cause, - self.param_env, - predicate)); + self.out.push(PredicateObligation::from(cause, + self.param_env, + predicate)); } } } @@ -327,12 +320,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { if !r.has_escaping_regions() && !mt.ty.has_escaping_regions() { let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); self.out.push( - traits::Obligation::new( + traits::PredicateObligation::from( cause, param_env, - ty::Predicate::TypeOutlives( - ty::Binder( - ty::OutlivesPredicate(mt.ty, r))))); + ty::OutlivesPredicate(mt.ty, r))); } } @@ -372,10 +363,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let component_traits = data.auto_traits().chain(data.principal().map(|p| p.def_id())); self.out.extend( - component_traits.map(|did| traits::Obligation::new( + component_traits.map(|did| traits::PredicateObligation::from( cause.clone(), param_env, - ty::Predicate::ObjectSafe(did) + ty::PredicateAtom::ObjectSafe(did) )) ); } @@ -402,9 +393,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); self.out.push( // ...not the type we started from, so we made progress. - traits::Obligation::new(cause, - self.param_env, - ty::Predicate::WellFormed(ty))); + traits::PredicateObligation::from( + cause, + self.param_env, + ty::PredicateAtom::WellFormed(ty))); } else { // Yes, resolved, proceed with the // result. Should never return false because diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index acb929981fbf2..6d9e6f90da72e 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -97,6 +97,10 @@ macro_rules! define_print { $vars:tt { debug $dbg:block display $disp:block } ) => { gen_print_impl! { $generic $target, $vars yes $disp yes $dbg } }; + ( $generic:tt $target:ty, + $vars:tt { debug-and-display $dbg:block } ) => { + gen_print_impl! { $generic $target, $vars yes $dbg yes $dbg } + }; ( $generic:tt $target:ty, $vars:tt { debug $dbg:block } ) => { gen_print_impl! { $generic $target, $vars no { @@ -705,6 +709,9 @@ define_print! { ty::ReEarlyBound(ref data) => { write!(f, "{}", data.name) } + ty::ReCanonical(_) => { + write!(f, "'_") + } ty::ReLateBound(_, br) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::ReSkolemized(_, br) => { @@ -761,8 +768,12 @@ define_print! { write!(f, "{:?}", vid) } + ty::ReCanonical(c) => { + write!(f, "'?{}", c.index()) + } + ty::ReSkolemized(id, ref bound_region) => { - write!(f, "ReSkolemized({}, {:?})", id.index, bound_region) + write!(f, "ReSkolemized({:?}, {:?})", id, bound_region) } ty::ReEmpty => write!(f, "ReEmpty"), @@ -861,6 +872,7 @@ define_print! { ty::TyVar(_) => write!(f, "_"), ty::IntVar(_) => write!(f, "{}", "{integer}"), ty::FloatVar(_) => write!(f, "{}", "{float}"), + ty::CanonicalTy(_) => write!(f, "_"), ty::FreshTy(v) => write!(f, "FreshTy({})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v) @@ -871,6 +883,7 @@ define_print! { ty::TyVar(ref v) => write!(f, "{:?}", v), ty::IntVar(ref v) => write!(f, "{:?}", v), ty::FloatVar(ref v) => write!(f, "{:?}", v), + ty::CanonicalTy(v) => write!(f, "?{:?}", v.index()), ty::FreshTy(v) => write!(f, "FreshTy({:?})", v), ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v) @@ -888,6 +901,12 @@ impl fmt::Debug for ty::IntVarValue { } } +impl fmt::Debug for ty::FloatVarValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + // The generic impl doesn't work yet because projections are not // normalized under HRTB. /*impl<T> fmt::Display for ty::Binder<T> @@ -902,10 +921,11 @@ impl fmt::Debug for ty::IntVarValue { define_print_multi! { [ ('tcx) ty::Binder<&'tcx ty::Slice<ty::ExistentialPredicate<'tcx>>>, - ('tcx) ty::Binder<ty::TraitRef<'tcx>>, + // ('tcx) ty::Binder<ty::TraitRef<'tcx>> is intentionally omited + ('tcx) ty::Binder<ty::TraitRefPrintWithSelf<'tcx>>, + ('tcx) ty::Binder<ty::TraitRefPrintWithoutSelf<'tcx>>, + ('tcx) ty::Binder<ty::PredicateAtom<'tcx>>, ('tcx) ty::Binder<ty::FnSig<'tcx>>, - ('tcx) ty::Binder<ty::TraitPredicate<'tcx>>, - ('tcx) ty::Binder<ty::EquatePredicate<'tcx>>, ('tcx) ty::Binder<ty::SubtypePredicate<'tcx>>, ('tcx) ty::Binder<ty::ProjectionPredicate<'tcx>>, ('tcx) ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>, @@ -920,19 +940,35 @@ define_print_multi! { define_print! { ('tcx) ty::TraitRef<'tcx>, (self, f, cx) { - display { - cx.parameterized(f, self.substs, self.def_id, &[]) - } + // NB -- no `display` impl. Instead, use `trait_ref.print_without_self()` + // or `trait_ref.print_with_colon()`. + // + // display { .. } + debug { // when printing out the debug representation, we don't need // to enumerate the `for<...>` etc because the debruijn index // tells you everything you need to know. + print!(f, cx, write("<"), print(self.print_with_colon()), write(">")) + } + } +} + +define_print! { + ('tcx) ty::TraitRefPrintWithoutSelf<'tcx>, (self, f, cx) { + debug-and-display { + cx.parameterized(f, self.trait_ref.substs, self.trait_ref.def_id, &[]) + } + } +} + +define_print! { + ('tcx) ty::TraitRefPrintWithSelf<'tcx>, (self, f, cx) { + debug-and-display { print!(f, cx, - write("<"), - print(self.self_ty()), - write(" as "))?; - cx.parameterized(f, self.substs, self.def_id, &[])?; - write!(f, ">") + print(self.trait_ref.self_ty()), + write("{}", self.separator), + print(self.trait_ref.print_without_self())) } } } @@ -1028,7 +1064,7 @@ define_print! { let mut is_sized = false; write!(f, "impl")?; for predicate in bounds.predicates { - if let Some(trait_ref) = predicate.to_opt_poly_trait_ref() { + if let Some(trait_ref) = predicate.poly_trait(tcx) { // Don't print +Sized, but rather +?Sized if absent. if Some(trait_ref.def_id()) == tcx.lang_items().sized_trait() { is_sized = true; @@ -1037,7 +1073,7 @@ define_print! { print!(f, cx, write("{}", if first { " " } else { "+" }), - print(trait_ref))?; + print(trait_ref.print_without_self()))?; first = false; } } @@ -1172,14 +1208,6 @@ define_print! { } } -define_print! { - ('tcx) ty::EquatePredicate<'tcx>, (self, f, cx) { - display { - print!(f, cx, print(self.0), write(" == "), print(self.1)) - } - } -} - define_print! { ('tcx) ty::SubtypePredicate<'tcx>, (self, f, cx) { display { @@ -1188,18 +1216,6 @@ define_print! { } } -define_print! { - ('tcx) ty::TraitPredicate<'tcx>, (self, f, cx) { - debug { - write!(f, "TraitPredicate({:?})", - self.trait_ref) - } - display { - print!(f, cx, print(self.trait_ref.self_ty()), write(": "), print(self.trait_ref)) - } - } -} - define_print! { ('tcx) ty::ProjectionPredicate<'tcx>, (self, f, cx) { debug { @@ -1225,7 +1241,10 @@ define_print! { let (trait_ref, item_name) = ty::tls::with(|tcx| (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name) ); - print!(f, cx, print_debug(trait_ref), write("::{}", item_name)) + print!(f, cx, + write("<"), + print(trait_ref.print_with_as()), + write(">::{}", item_name)) } } } @@ -1244,25 +1263,37 @@ define_print! { define_print! { ('tcx) ty::Predicate<'tcx>, (self, f, cx) { + debug-and-display { + match *self { + ty::Predicate::Poly(ref data) => data.print(f, cx), + ty::Predicate::Atom(ref data) => data.print(f, cx), + } + } + } +} + +define_print! { + ('tcx) ty::PredicateAtom<'tcx>, (self, f, cx) { display { match *self { - ty::Predicate::Trait(ref data) => data.print(f, cx), - ty::Predicate::Equate(ref predicate) => predicate.print(f, cx), - ty::Predicate::Subtype(ref predicate) => predicate.print(f, cx), - ty::Predicate::RegionOutlives(ref predicate) => predicate.print(f, cx), - ty::Predicate::TypeOutlives(ref predicate) => predicate.print(f, cx), - ty::Predicate::Projection(ref predicate) => predicate.print(f, cx), - ty::Predicate::WellFormed(ty) => print!(f, cx, print(ty), write(" well-formed")), - ty::Predicate::ObjectSafe(trait_def_id) => + ty::PredicateAtom::Trait(ref data) => data.print_with_colon().print(f, cx), + ty::PredicateAtom::Subtype(ref predicate) => predicate.print(f, cx), + ty::PredicateAtom::RegionOutlives(ref predicate) => predicate.print(f, cx), + ty::PredicateAtom::TypeOutlives(ref predicate) => predicate.print(f, cx), + ty::PredicateAtom::Projection(ref predicate) => predicate.print(f, cx), + ty::PredicateAtom::WellFormed(ty) => { + print!(f, cx, print(ty), write(" well-formed")) + } + ty::PredicateAtom::ObjectSafe(trait_def_id) => ty::tls::with(|tcx| { write!(f, "the trait `{}` is object-safe", tcx.item_path_str(trait_def_id)) }), - ty::Predicate::ClosureKind(closure_def_id, kind) => + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => ty::tls::with(|tcx| { write!(f, "the closure `{}` implements the trait `{}`", tcx.item_path_str(closure_def_id), kind) }), - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { write!(f, "the constant `")?; cx.parameterized(f, substs, def_id, &[])?; write!(f, "` can be evaluated") @@ -1271,20 +1302,19 @@ define_print! { } debug { match *self { - ty::Predicate::Trait(ref a) => a.print(f, cx), - ty::Predicate::Equate(ref pair) => pair.print(f, cx), - ty::Predicate::Subtype(ref pair) => pair.print(f, cx), - ty::Predicate::RegionOutlives(ref pair) => pair.print(f, cx), - ty::Predicate::TypeOutlives(ref pair) => pair.print(f, cx), - ty::Predicate::Projection(ref pair) => pair.print(f, cx), - ty::Predicate::WellFormed(ty) => ty.print(f, cx), - ty::Predicate::ObjectSafe(trait_def_id) => { + ty::PredicateAtom::Trait(ref a) => a.print_with_colon().print(f, cx), + ty::PredicateAtom::Subtype(ref pair) => pair.print(f, cx), + ty::PredicateAtom::RegionOutlives(ref pair) => pair.print(f, cx), + ty::PredicateAtom::TypeOutlives(ref pair) => pair.print(f, cx), + ty::PredicateAtom::Projection(ref pair) => pair.print(f, cx), + ty::PredicateAtom::WellFormed(ty) => ty.print(f, cx), + ty::PredicateAtom::ObjectSafe(trait_def_id) => { write!(f, "ObjectSafe({:?})", trait_def_id) } - ty::Predicate::ClosureKind(closure_def_id, kind) => { + ty::PredicateAtom::ClosureKind(closure_def_id, kind) => { write!(f, "ClosureKind({:?}, {:?})", closure_def_id, kind) } - ty::Predicate::ConstEvaluatable(def_id, substs) => { + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 8654f2a50e46b..b0e755aa77855 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -366,6 +366,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { ty::ReStatic => self.item_ub, + ty::ReCanonical(_) | ty::ReEmpty | ty::ReLateBound(..) | ty::ReVar(..) | diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 343b1ed68b804..381b89a238fd6 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,6 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] +ena = "0.8.0" log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index a733e9de5a1ab..473925524b415 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -324,7 +324,7 @@ macro_rules! newtype_index { ); } -#[derive(Clone, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Hash)] pub struct IndexVec<I: Idx, T> { pub raw: Vec<T>, _marker: PhantomData<Fn(&I)> diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 3a20343033c23..e32ab10de4824 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -36,6 +36,7 @@ #![cfg_attr(test, feature(test))] extern crate core; +extern crate ena; #[macro_use] extern crate log; extern crate serialize as rustc_serialize; // used by deriving @@ -57,10 +58,10 @@ pub mod indexed_vec; pub mod obligation_forest; pub mod sip128; pub mod snapshot_map; -pub mod snapshot_vec; +pub use ena::snapshot_vec; pub mod stable_hasher; pub mod transitive_relation; -pub mod unify; +pub use ena::unify; pub mod fx; pub mod tuple_slice; pub mod veccell; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 02cae52166ac3..87e4e8dce4263 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -234,14 +234,11 @@ impl<O: ForestObligation> ObligationForest<O> { } /// Returns the set of obligations that are in a pending state. - pub fn pending_obligations(&self) -> Vec<O> - where O: Clone - { + pub fn pending_obligations<'a>(&'a self) -> impl Iterator<Item = &'a O> + 'a { self.nodes .iter() .filter(|n| n.state.get() == NodeState::Pending) - .map(|n| n.obligation.clone()) - .collect() + .map(|n| &n.obligation) } /// Perform a pass through the obligation list. This must diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index d6155f53485e3..717695b84620a 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -30,6 +30,7 @@ rustc_plugin = { path = "../librustc_plugin" } rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } rustc_save_analysis = { path = "../librustc_save_analysis" } +rustc_traits = { path = "../librustc_traits" } rustc_trans = { path = "../librustc_trans", optional = true } rustc_trans_utils = { path = "../librustc_trans_utils" } rustc_typeck = { path = "../librustc_typeck" } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 5ff75351b635b..201b6e40b0426 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -503,7 +503,8 @@ fn sub_free_bound_false_infer() { //! does NOT hold for any instantiation of `_#1`. test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); + let t_infer1 = env.infcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(DUMMY_SP)); let t_rptr_bound1 = env.t_rptr_late_bound(1); env.check_not_sub(env.t_fn(&[t_infer1], env.tcx().types.isize), env.t_fn(&[t_rptr_bound1], env.tcx().types.isize)); @@ -522,7 +523,8 @@ fn lub_free_bound_infer() { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); - let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); + let t_infer1 = env.infcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(DUMMY_SP)); let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_free1 = env.t_rptr_free(1); env.check_lub(env.t_fn(&[t_infer1], env.tcx().types.isize), @@ -642,7 +644,8 @@ fn glb_bound_free() { fn glb_bound_free_infer() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { let t_rptr_bound1 = env.t_rptr_late_bound(1); - let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); + let t_infer1 = env.infcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(DUMMY_SP)); // compute GLB(fn(_) -> isize, for<'b> fn(&'b isize) -> isize), // which should yield for<'b> fn(&'b isize) -> isize diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 07874a8cc69dd..2f002a23f1d12 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1025,16 +1025,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Attempt to select a concrete impl before checking. ty::TraitContainer(trait_def_id) => { let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); - let trait_ref = ty::Binder(trait_ref); let span = tcx.hir.span(expr_id); - let obligation = - traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), - cx.param_env, - trait_ref.to_poly_trait_predicate()); tcx.infer_ctxt().enter(|infcx| { - let mut selcx = traits::SelectionContext::new(&infcx); - match selcx.select(&obligation) { + let cause = traits::ObligationCause::misc(span, expr_id); + match infcx.select_trait_ref(cause, cx.param_env, trait_ref) { // The method comes from a `T: Trait` bound. // If `T` is `Self`, then this call is inside // a default method definition. diff --git a/src/librustc_mir/transform/nll/renumber.rs b/src/librustc_mir/transform/nll/renumber.rs index a3ff7a041ca07..a77f986187ff7 100644 --- a/src/librustc_mir/transform/nll/renumber.rs +++ b/src/librustc_mir/transform/nll/renumber.rs @@ -30,7 +30,8 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>( // declared on the function signature. let free_region_inference_vars = (0..free_regions.indices.len()) .map(|_| { - infcx.next_region_var(rustc_infer::MiscVariable(DUMMY_SP)) + infcx.next_region_var(ty::UniverseIndex::ROOT, + rustc_infer::MiscVariable(DUMMY_SP)) }) .collect(); @@ -68,7 +69,8 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> { .fold_regions(value, &mut false, |_region, _depth| { self.num_region_variables += 1; self.infcx - .next_region_var(rustc_infer::MiscVariable(DUMMY_SP)) + .next_region_var(ty::UniverseIndex::ROOT, + rustc_infer::MiscVariable(DUMMY_SP)) }) } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 8d6458d793474..4582558239131 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -37,10 +37,10 @@ impl MirPass for SanityCheck { let id = src.item_id(); let def_id = tcx.hir.local_def_id(id); if !tcx.has_attr(def_id, "rustc_mir_borrowck") { - debug!("skipping rustc_peek::SanityCheck on {}", tcx.item_path_str(def_id)); + debug!("skipping rustc_peek::SanityCheck on {:?}", def_id); return; } else { - debug!("running rustc_peek::SanityCheck on {}", tcx.item_path_str(def_id)); + debug!("running rustc_peek::SanityCheck on {:?}", def_id); } let attributes = tcx.get_attrs(def_id); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 630260feed789..9ffc80d8e258c 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -398,15 +398,13 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> { let predicates = self.ev.tcx.predicates_of(self.item_def_id); for predicate in &predicates.predicates { predicate.visit_with(self); - match predicate { - &ty::Predicate::Trait(poly_predicate) => { - self.check_trait_ref(poly_predicate.skip_binder().trait_ref); + match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_ref) => { + self.check_trait_ref(trait_ref); }, - &ty::Predicate::Projection(poly_predicate) => { + ty::PredicateAtom::Projection(proj) => { let tcx = self.ev.tcx; - self.check_trait_ref( - poly_predicate.skip_binder().projection_ty.trait_ref(tcx) - ); + self.check_trait_ref(proj.projection_ty.trait_ref(tcx)); }, _ => (), }; @@ -854,7 +852,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { ty::TyProjection(ref proj) => { let trait_ref = proj.trait_ref(self.tcx); if !self.item_is_accessible(trait_ref.def_id) { - let msg = format!("trait `{}` is private", trait_ref); + let msg = format!("trait `{}` is private", trait_ref.print_without_self()); self.tcx.sess.span_err(self.span, &msg); return true; } @@ -864,23 +862,23 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } ty::TyAnon(def_id, ..) => { for predicate in &self.tcx.predicates_of(def_id).predicates { - let trait_ref = match *predicate { - ty::Predicate::Trait(ref poly_trait_predicate) => { - Some(poly_trait_predicate.skip_binder().trait_ref) + let trait_ref = match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_ref) => { + Some(trait_ref) } - ty::Predicate::Projection(ref poly_projection_predicate) => { - if poly_projection_predicate.skip_binder().ty.visit_with(self) { + ty::PredicateAtom::Projection(projection_predicate) => { + if projection_predicate.ty.visit_with(self) { return true; } - Some(poly_projection_predicate.skip_binder() - .projection_ty.trait_ref(self.tcx)) + Some(projection_predicate.projection_ty.trait_ref(self.tcx)) } - ty::Predicate::TypeOutlives(..) => None, + ty::PredicateAtom::TypeOutlives(..) => None, _ => bug!("unexpected predicate: {:?}", predicate), }; if let Some(trait_ref) = trait_ref { if !self.item_is_accessible(trait_ref.def_id) { - let msg = format!("trait `{}` is private", trait_ref); + let msg = format!("trait `{}` is private", + trait_ref.print_without_self()); self.tcx.sess.span_err(self.span, &msg); return true; } @@ -1277,15 +1275,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { let predicates = self.tcx.predicates_of(self.item_def_id); for predicate in &predicates.predicates { predicate.visit_with(self); - match predicate { - &ty::Predicate::Trait(poly_predicate) => { - self.check_trait_ref(poly_predicate.skip_binder().trait_ref); - }, - &ty::Predicate::Projection(poly_predicate) => { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_ref) => self.check_trait_ref(trait_ref), + ty::PredicateAtom::Projection(predicate) => { let tcx = self.tcx; - self.check_trait_ref( - poly_predicate.skip_binder().projection_ty.trait_ref(tcx) - ); + self.check_trait_ref(predicate.projection_ty.trait_ref(tcx)); }, _ => (), }; @@ -1323,7 +1317,8 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { if !vis.is_at_least(self.required_visibility, self.tcx) { if self.has_pub_restricted || self.has_old_errors { struct_span_err!(self.tcx.sess, self.span, E0445, - "private trait `{}` in public interface", trait_ref) + "private trait `{}` in public interface", + trait_ref.print_without_self()) .span_label(self.span, format!( "private trait can't be public")) .emit(); @@ -1332,7 +1327,8 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { node_id, self.span, &format!("private trait `{}` in public \ - interface (error E0445)", trait_ref)); + interface (error E0445)", + trait_ref.print_without_self())); } } } diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml new file mode 100644 index 0000000000000..fe83344e69952 --- /dev/null +++ b/src/librustc_traits/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_traits" +version = "0.0.0" + +[lib] +name = "rustc_traits" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +bitflags = "1.0" +graphviz = { path = "../libgraphviz" } +log = "0.3" +rustc = { path = "../librustc" } +rustc_const_eval = { path = "../librustc_const_eval" } +rustc_const_math = { path = "../librustc_const_math" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_traits/fallible.rs b/src/librustc_traits/fallible.rs new file mode 100644 index 0000000000000..4842b30e630ba --- /dev/null +++ b/src/librustc_traits/fallible.rs @@ -0,0 +1,19 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct NoSolution; + +pub type Fallible<T> = Result<T, NoSolution>; + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct Overflow; + +pub type CanOverflow<T> = Result<T, Overflow>; diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs new file mode 100644 index 0000000000000..619e43dbc3c9f --- /dev/null +++ b/src/librustc_traits/lib.rs @@ -0,0 +1,107 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! New recursive solver modeled on Chalk's recursive solver. Most of +//! the guts are broken up into modules; see the comments in those modules. + +#![feature(crate_visibility_modifier)] +#![feature(underscore_lifetimes)] + +#[macro_use] extern crate log; +extern crate rustc; +extern crate rustc_data_structures; + +use rustc::infer::InferCtxt; +use rustc::infer::canonical::{Canonical, CanonicalVarValue}; +use rustc::ty::{self, CanonicalVar}; +use rustc_data_structures::fx::FxHashMap; +use std::collections::BTreeMap; + +mod fallible; +use self::fallible::Fallible; + +mod search_graph; +use self::search_graph::{DepthFirstNumber, SearchGraph}; + +mod stack; +use self::stack::Stack; + +/// A Solver is the basic context in which you can propose goals for a given +/// program. **All questions posed to the solver are in canonical, closed form, +/// so that each question is answered with effectively a "clean slate"**. This +/// allows for better caching, and simplifies management of the inference +/// context. +pub struct Solver<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + stack: Stack, + search_graph: SearchGraph<'tcx>, + + caching_enabled: bool, + + /// The cache contains **fully solved** goals, whose results are + /// not dependent on the stack in anyway. + cache: FxHashMap<PredicateAtomGoal<'tcx>, Fallible<Solution<'tcx>>>, +} + +/// Internally to the solver, a `Goal` is used to mean something we +/// are trying to prove. It is like an obligation, but stripped of +/// the `cause`. +struct Goal<'tcx, G> { + param_env: ty::ParamEnv<'tcx>, + goal: G, +} + +/// The main top-line goals we try to prove. +type PredicateAtomGoal<'tcx> = Goal<'tcx, ty::PredicateAtom<'tcx>>; + +/// The `minimums` struct is used while solving to track whether we encountered +/// any cycles in the process. +#[derive(Copy, Clone, Debug)] +struct Minimums { + positive: DepthFirstNumber, +} + +impl Minimums { + fn new() -> Self { + Minimums { + positive: DepthFirstNumber::MAX, + } + } + + fn update_from(&mut self, minimums: Minimums) { + self.positive = ::std::cmp::min(self.positive, minimums.positive); + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +enum Solution<'tcx> { + Ambiguous, + Unique(Canonical<ConstrainedCanonicalVarSubstitution<'tcx>>), +} + +/// Combines a `CanonicalVarSubstitution` with region predicates. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +struct ConstrainedCanonicalVarSubstitution<'tcx> { + pub subst: CanonicalVarSubstitution<'tcx>, + // TODO pub constraints: Vec<InEnvironment<Constraint>>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +struct CanonicalVarSubstitution<'tcx> { + /// Map free variable with given index to the value with the same + /// index. Naturally, the kind of the variable must agree with + /// the kind of the value. + /// + /// This is a map because the substitution is not necessarily + /// complete. We use a btree map to ensure that the result is in a + /// deterministic order. + pub parameters: BTreeMap<CanonicalVar, CanonicalVarValue<'tcx>>, +} + diff --git a/src/librustc_traits/search_graph.rs b/src/librustc_traits/search_graph.rs new file mode 100644 index 0000000000000..ce3aea4b4c232 --- /dev/null +++ b/src/librustc_traits/search_graph.rs @@ -0,0 +1,131 @@ +// 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The search graph encodes the proof search that we are currently +//! doing. When cycles are encountered, it rolls back. + +use ::fallible::*; +use ::stack::StackDepth; +use ::{Minimums, Solution}; + +use rustc::ty; +use rustc_data_structures::fx::FxHashMap; +use std::ops::{Add, Index, IndexMut}; + +pub(super) struct SearchGraph<'tcx> { + indices: FxHashMap<ty::PredicateAtom<'tcx>, DepthFirstNumber>, + nodes: Vec<Node<'tcx>>, +} + +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub(super) struct DepthFirstNumber { + index: usize, +} + +pub(super) struct Node<'tcx> { + pub goal: ty::PredicateAtom<'tcx>, + + pub solution: Fallible<Solution<'tcx>>, + + /// This is `Some(X)` if we are actively exploring this node, or + /// `None` otherwise. + pub stack_depth: Option<StackDepth>, + + /// While this node is on the stack, this field will be set to + /// contain our own depth-first number. Once the node is popped + /// from the stack, it contains the DFN of the minimal ancestor + /// that the table reached (or MAX if no cycle was encountered). + pub links: Minimums, +} + +impl<'tcx> SearchGraph<'tcx> { + pub fn new() -> Self { + SearchGraph { + indices: FxHashMap::default(), + nodes: vec![], + } + } + + pub fn lookup(&self, goal: &ty::PredicateAtom<'tcx>) -> Option<DepthFirstNumber> { + self.indices.get(goal).cloned() + } + + /// Insert a new search node in the tree. The node will be in the initial + /// state for a search node: + /// + /// - stack depth as given + /// - links set to its own DFN + /// - solution is initially `NoSolution` + pub fn insert(&mut self, goal: &ty::PredicateAtom<'tcx>, stack_depth: StackDepth) -> DepthFirstNumber { + let dfn = DepthFirstNumber { + index: self.nodes.len(), + }; + let node = Node { + goal: goal.clone(), + solution: Err(NoSolution), + stack_depth: Some(stack_depth), + links: Minimums { positive: dfn }, + }; + self.nodes.push(node); + let previous_index = self.indices.insert(goal.clone(), dfn); + assert!(previous_index.is_none()); + dfn + } + + /// Clears all nodes with a depth-first number greater than or equal `dfn`. + pub fn rollback_to(&mut self, dfn: DepthFirstNumber) { + debug!("rollback_to(dfn={:?})", dfn); + self.indices.retain(|_key, value| *value < dfn); + self.nodes.truncate(dfn.index); + } + + /// Removes all nodes with a depth-first-number greater than or + /// equal to `dfn`, adding their final solutions into the cache. + pub fn move_to_cache( + &mut self, + dfn: DepthFirstNumber, + cache: &mut FxHashMap<ty::PredicateAtom<'tcx>, Fallible<Solution<'tcx>>>, + ) { + debug!("move_to_cache(dfn={:?})", dfn); + self.indices.retain(|_key, value| *value < dfn); + for node in self.nodes.drain(dfn.index..) { + assert!(node.stack_depth.is_none()); + assert!(node.links.positive >= dfn); + debug!("caching solution {:?} for {:?}", node.solution, node.goal); + cache.insert(node.goal, node.solution); + } + } +} + +impl<'tcx> Index<DepthFirstNumber> for SearchGraph<'tcx> { + type Output = Node<'tcx>; + + fn index(&self, table_index: DepthFirstNumber) -> &Node<'tcx> { + &self.nodes[table_index.index] + } +} + +impl<'tcx> IndexMut<DepthFirstNumber> for SearchGraph<'tcx> { + fn index_mut(&mut self, table_index: DepthFirstNumber) -> &mut Node<'tcx> { + &mut self.nodes[table_index.index] + } +} + +impl DepthFirstNumber { + pub const MAX: DepthFirstNumber = DepthFirstNumber { index: ::std::usize::MAX }; +} + +impl Add<usize> for DepthFirstNumber { + type Output = DepthFirstNumber; + + fn add(self, v: usize) -> DepthFirstNumber { + DepthFirstNumber { index: self.index + v } + } +} diff --git a/src/librustc_traits/stack.rs b/src/librustc_traits/stack.rs new file mode 100644 index 0000000000000..82ff5a3622dcf --- /dev/null +++ b/src/librustc_traits/stack.rs @@ -0,0 +1,116 @@ +use ::fallible::*; +use ::PredicateAtomGoal; + +use rustc::infer::InferCtxt; +use rustc::ty; +use std::mem; +use std::ops::Index; +use std::ops::IndexMut; +use std::usize; + +pub(crate) struct Stack { + entries: Vec<StackEntry>, + overflow_depth: usize, +} + +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct StackDepth { + depth: usize, +} + +/// The data we actively keep for each goal on the stack. +pub struct StackEntry { + /// Was this a coinductive goal? + coinductive_goal: bool, + + /// Initially false, set to true when some subgoal depends on us. + cycle: bool, +} + +impl<'tcx> Stack { + pub(crate) fn new(overflow_depth: usize) -> Self { + Stack { + entries: vec![], + overflow_depth: overflow_depth, + } + } + + pub(crate) fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + pub(crate) fn push(&mut self, + infcx: &InferCtxt<'_, '_, 'tcx>, + goal: &PredicateAtomGoal<'tcx>) + -> CanOverflow<StackDepth> { + let depth = StackDepth { + depth: self.entries.len(), + }; + + if depth.depth >= self.overflow_depth { + // This should perhaps be a result or something, though + // really I'd prefer to move to subgoal abstraction for + // guaranteeing termination. -nmatsakis + return Err(Overflow); + } + + let coinductive_goal = self.coinductive_predicate(infcx, goal.goal); + self.entries.push(StackEntry { coinductive_goal, cycle: false }); + Ok(depth) + } + + fn coinductive_predicate(&self, + infcx: &InferCtxt<'_, '_, 'tcx>, + predicate: ty::PredicateAtom<'tcx>) + -> bool { + let result = match predicate { + ty::PredicateAtom::Trait(ref data) => { + infcx.tcx.trait_is_auto(data.def_id) + } + _ => { + false + } + }; + debug!("coinductive_predicate({:?}) = {:?}", predicate, result); + result + } + + pub(crate) fn pop(&mut self, depth: StackDepth) { + assert_eq!( + depth.depth + 1, + self.entries.len(), + "mismatched stack push/pop" + ); + self.entries.pop(); + } + + /// True if all the goals from the top of the stack down to (and + /// including) the given depth are coinductive. + pub(crate) fn coinductive_cycle_from(&self, depth: StackDepth) -> bool { + self.entries[depth.depth..].iter().all(|entry| entry.coinductive_goal) + } +} + +impl StackEntry { + pub(crate) fn flag_cycle(&mut self) { + self.cycle = true; + } + + pub(crate) fn read_and_reset_cycle_flag(&mut self) -> bool { + mem::replace(&mut self.cycle, false) + } +} + +impl Index<StackDepth> for Stack { + type Output = StackEntry; + + fn index(&self, depth: StackDepth) -> &StackEntry { + &self.entries[depth.depth] + } +} + +impl IndexMut<StackDepth> for Stack { + fn index_mut(&mut self, depth: StackDepth) -> &mut StackEntry { + &mut self.entries[depth.depth] + } +} diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1471e235156eb..40165f4eff37d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -19,7 +19,7 @@ use hir::def::Def; use hir::def_id::DefId; use middle::resolve_lifetime as rl; use namespace::Namespace; -use rustc::ty::subst::{Kind, Subst, Substs}; +use rustc::ty::subst::{Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; @@ -51,7 +51,6 @@ pub trait AstConv<'gcx, 'tcx> { /// Same as ty_infer, but with a known type parameter definition. fn ty_infer_for_def(&self, _def: &ty::TypeParameterDef, - _substs: &[Kind<'tcx>], span: Span) -> Ty<'tcx> { self.ty_infer(span) } @@ -250,7 +249,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } else if infer_types { // No type parameters were provided, we can infer all. let ty_var = if !default_needs_object_self(def) { - self.ty_infer_for_def(def, substs, span) + self.ty_infer_for_def(def, span) } else { self.ty_infer(span) }; @@ -343,7 +342,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_ref = &ast_trait_ref.trait_ref; let trait_def_id = self.trait_def_id(trait_ref); - debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); + debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); self.prohibit_type_params(trait_ref.path.segments.split_last().unwrap().1); @@ -361,8 +360,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { predicate.ok() // ok to ignore Err() because ErrorReported (see above) })); - debug!("ast_path_to_poly_trait_ref({:?}, projections={:?}) -> {:?}", - trait_ref, poly_projections, poly_trait_ref); + debug!("instantiate_poly_trait_ref: trait_ref={:?}", trait_ref); + debug!("instantiate_poly_trait_ref: poly_projections={:?}", poly_projections); + debug!("instantiate_poly_trait_ref: poly_trait_ref={:?}", poly_trait_ref); poly_trait_ref } @@ -502,7 +502,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)); let candidate = self.one_bound_for_assoc_type(candidates, - &trait_ref.to_string(), + &trait_ref.print_without_self().to_string(), binding.item_name, binding.span)?; @@ -547,6 +547,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { { let tcx = self.tcx(); + debug!("conv_object_ty_poly_trait_ref(trait_bounds={:?}, lifetime={:?})", + trait_bounds, lifetime); + if trait_bounds.is_empty() { span_err!(tcx.sess, span, E0224, "at least one non-builtin trait is required for an object type"); @@ -689,7 +692,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let tcx = self.tcx(); let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id) - .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect(); + .predicates.into_iter().filter_map(|p| p.poly_trait(tcx)).collect(); // Check that there is exactly one way to find an associated type with the // correct name. @@ -748,12 +751,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if let Some(span) = bound_span { err.span_label(span, format!("ambiguous `{}` from `{}`", assoc_name, - bound)); + bound.print_without_self())); } else { span_note!(&mut err, span, "associated type `{}` could derive from `{}`", ty_param_name, - bound); + bound.print_without_self()); } } err.emit(); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 272f13b28030e..9f60243f79440 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -232,7 +232,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // ref x | ref const x | ref mut x // then `x` is assigned a value of type `&M T` where M is the mutability // and T is the expected type. - let region_var = self.next_region_var(infer::PatternRegion(pat.span)); + let region_var = self.next_region_var(self.param_env.universe, + infer::PatternRegion(pat.span)); let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl }; let region_ty = tcx.mk_ref(region_var, mt); @@ -285,6 +286,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let element_tys_iter = (0..max_len).map(|_| self.next_ty_var( // FIXME: MiscVariable for now, obtaining the span and name information // from all tuple elements isn't trivial. + ty::UniverseIndex::ROOT, TypeVariableOrigin::TypeInference(pat.span))); let element_tys = tcx.mk_type_list(element_tys_iter); let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false)); @@ -295,7 +297,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pat_ty } PatKind::Box(ref inner) => { - let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span)); + let inner_ty = self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(inner.span)); let uniq_ty = tcx.mk_box(inner_ty); if self.check_dereferencable(pat.span, expected, &inner) { @@ -328,9 +331,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } _ => { let inner_ty = self.next_ty_var( + ty::UniverseIndex::ROOT, TypeVariableOrigin::TypeInference(inner.span)); let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl }; - let region = self.next_region_var(infer::PatternRegion(pat.span)); + let region = self.next_region_var(self.param_env.universe, + infer::PatternRegion(pat.span)); let rptr_ty = tcx.mk_ref(region, mt); debug!("check_pat_walk: demanding {:?} = {:?}", expected, rptr_ty); let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty); @@ -571,7 +576,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // ...but otherwise we want to use any supertype of the // discriminant. This is sort of a workaround, see note (*) in // `check_pat` for some details. - discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); + discrim_ty = self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type_or_error(discrim, discrim_ty); }; @@ -632,7 +638,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // arm for inconsistent arms or to the whole match when a `()` type // is required). Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety, - _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + _ => self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(expr.span)), }; CoerceMany::with_coercion_sites(coerce_first, arms) }; diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 91ce4511a31cb..8330d24ed24d3 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -110,10 +110,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // fnmut vs fnonce. If so, we have to defer further processing. if self.closure_kind(def_id).is_none() { let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs); - let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span, - infer::FnCall, - &closure_ty) - .0; + let fn_sig = self.replace_late_bound_regions_with_fresh_var( + call_expr.span, + self.param_env.universe, + infer::FnCall, + &closure_ty).0; let adjustments = autoderef.adjust_steps(LvaluePreference::NoPreference); self.record_deferred_call_resolution(def_id, DeferredCallResolution { call_expr, @@ -260,7 +261,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // previously appeared within a `Binder<>` and hence would not // have been normalized before. let fn_sig = - self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &fn_sig) + self.replace_late_bound_regions_with_fresh_var(call_expr.span, + self.param_env.universe, + infer::FnCall, + &fn_sig) .0; let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d475fb0cf1a14..bbde15ef5e27d 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -17,7 +17,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::{InferOk, InferResult}; use rustc::infer::LateBoundRegionConversionTime; use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::ty::{self, ToPolyTraitRef, Ty}; +use rustc::ty::{self, Ty}; use rustc::ty::subst::Substs; use rustc::ty::TypeFoldable; use std::cmp; @@ -99,8 +99,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr_def_id, |_, _| span_bug!(expr.span, "closure has region param"), |_, _| { - self.infcx - .next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) + self.infcx.next_ty_var( + ty::UniverseIndex::ROOT, + TypeVariableOrigin::TransformedUpvar(expr.span), + ) }, ); let closure_type = self.tcx.mk_closure(expr_def_id, substs); @@ -164,7 +166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .projection_bounds() .filter_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); - self.deduce_sig_from_projection(&pb) + self.deduce_sig_from_projection(pb) }) .next(); let kind = object_type @@ -186,24 +188,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Here `expected_ty` is known to be a type inference variable. let expected_sig = fulfillment_cx - .pending_obligations() + .pending_closure_predicates() .iter() - .map(|obligation| &obligation.obligation) - .filter_map(|obligation| { + .filter_map(|predicate| { debug!( - "deduce_expectations_from_obligations: obligation.predicate={:?}", - obligation.predicate + "deduce_expectations_from_obligations: predicate={:?}", + predicate ); - match obligation.predicate { + if let Some(poly_proj) = predicate.poly_projection(self.tcx) { // Given a Projection predicate, we can potentially infer // the complete signature. - ty::Predicate::Projection(ref proj_predicate) => { - let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx); - self.self_type_matches_expected_vid(trait_ref, expected_vid) - .and_then(|_| self.deduce_sig_from_projection(proj_predicate)) - } - _ => None, + let poly_trait_ref = poly_proj.to_poly_trait_ref(self.tcx); + self.self_type_matches_expected_vid(poly_trait_ref, expected_vid) + .and_then(|_| self.deduce_sig_from_projection(poly_proj)) + } else { + None } }) .next(); @@ -213,31 +213,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // like `F : Fn<A>`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let expected_kind = fulfillment_cx - .pending_obligations() + .pending_closure_predicates() .iter() - .map(|obligation| &obligation.obligation) - .filter_map(|obligation| { - let opt_trait_ref = match obligation.predicate { - ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), - 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, - ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::ConstEvaluatable(..) => None, - - // NB: This predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `TyClosure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `TyClosure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::Predicate::ClosureKind(..) => None, - }; + .filter_map(|predicate| { + // Look for *either* a projection predicate like `<T + // as Fn<()>>::Output = U` *or* a plain trait + // predicate like `T: Fn<()>` here: + let opt_trait_ref = predicate + .poly_projection(self.tcx) + .map(|proj| proj.to_poly_trait_ref(self.tcx)) + .or_else(|| predicate.poly_trait(self.tcx)); opt_trait_ref .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) .and_then(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id())) @@ -249,11 +234,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (expected_sig, expected_kind) } - /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce - /// everything we need to know about a closure. + /// Given a projection like "<F as Fn(X)>::Result == Y", we can + /// deduce everything we need to know about a closure. fn deduce_sig_from_projection( &self, - projection: &ty::PolyProjectionPredicate<'tcx>, + projection: ty::PolyProjectionPredicate<'tcx>, ) -> Option<ty::FnSig<'tcx>> { let tcx = self.tcx; @@ -303,14 +288,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_ref: ty::PolyTraitRef<'tcx>, expected_vid: ty::TyVid, ) -> Option<ty::PolyTraitRef<'tcx>> { - let self_ty = self.shallow_resolve(trait_ref.self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", - trait_ref, - self_ty - ); + debug!("self_type_matches_expected_vid(trait_ref={:?})", trait_ref); + + // OK to skip binder, we are looking for an unresolved type variable, + // which cannot be bound by this binder (since it is free). + let self_ty = trait_ref.skip_binder().self_ty(); + if !self_ty.is_ty_var() { + return None; + } + + let self_ty = self.shallow_resolve(self_ty); + debug!("self_type_matches_expected_vid: self_ty={:?}", self_ty); match self_ty.sty { - ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), + ty::TyInfer(ty::TyVar(vid)) if vid == expected_vid => Some(trait_ref), _ => None, } } @@ -491,6 +481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Instantiate (this part of..) S to S', i.e., with fresh variables. let (supplied_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var( hir_ty.span, + ty::UniverseIndex::ROOT, LateBoundRegionConversionTime::FnCall, &ty::Binder(supplied_ty), ); // recreated from (*) above @@ -507,6 +498,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (supplied_output_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var( decl.output.span(), + ty::UniverseIndex::ROOT, LateBoundRegionConversionTime::FnCall, &supplied_sig.output(), ); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 94422f93e5922..c0b34155125d1 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -135,6 +135,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> { + debug!("Coerce.unify({:?}, {:?})", a, b); self.commit_if_ok(|_| { if self.use_lub { self.at(&self.cause, self.fcx.param_env) @@ -179,6 +180,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // micro-optimization: no need for this if `b` is // already resolved in some way. let diverging_ty = self.next_diverging_ty_var( + ty::UniverseIndex::ROOT, TypeVariableOrigin::AdjustmentType(self.cause.span)); self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny)) } else { @@ -358,7 +360,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { if r_borrow_var.is_none() { // create var lazilly, at most once let coercion = Coercion(span); - let r = self.next_region_var(coercion); + let r = self.next_region_var(self.param_env.universe, coercion); r_borrow_var = Some(r); // [4] above } r_borrow_var.unwrap() @@ -462,7 +464,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; let coercion = Coercion(self.cause.span); - let r_borrow = self.next_region_var(coercion); + let r_borrow = self.next_region_var(self.param_env.universe, coercion); Some((Adjustment { kind: Adjust::Deref(None), target: mt_a.ty @@ -497,7 +499,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. let origin = TypeVariableOrigin::MiscVariable(self.cause.span); - let coerce_target = self.next_ty_var(origin); + let coerce_target = self.next_ty_var(ty::UniverseIndex::ROOT, origin); let mut coercion = self.unify_and(coerce_target, target, |target| { let unsize = Adjustment { kind: Adjust::Unsize, @@ -511,8 +513,6 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } })?; - let mut selcx = traits::SelectionContext::new(self); - // Use a FIFO queue for this custom fulfillment procedure. let mut queue = VecDeque::new(); @@ -533,39 +533,41 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let traits = [coerce_unsized_did, unsize_did]; while let Some(obligation) = queue.pop_front() { debug!("coerce_unsized resolve step: {:?}", obligation); - let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + + // Continue only for predicates like `T: Unsize` where + // `Unsize` is one of the various unsize traits. Push + // everything else into `coercion.obligations`. + match obligation.predicate.poly_trait(self.tcx) { + Some(tr) if traits.contains(&tr.def_id()) => { if unsize_did == tr.def_id() { if let ty::TyTuple(..) = tr.0.input_types().nth(1).unwrap().sty { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } } - tr.clone() } _ => { coercion.obligations.push(obligation); continue; } - }; - match selcx.select(&obligation.with(trait_ref)) { + } + + // Skolemize away the higher-ranked stuff and run `select`. + // + // (*) We know it's a trait obligation because of the match we just did. + let atom_obligation = self.skolemize_predicate_obligation(&obligation); + let trait_ref = atom_obligation.predicate.trait_().unwrap(); // see (*) above + match self.select_trait_ref(atom_obligation.cause, + atom_obligation.param_env, + trait_ref) { // Uncertain or unimplemented. - Ok(None) | - Err(traits::Unimplemented) => { + Ok(None) | Err(_) => { debug!("coerce_unsized: early return - can't prove obligation"); return Err(TypeError::Mismatch); } - // Object safety violations or miscellaneous. - Err(err) => { - self.report_selection_error(&obligation, &err); - // Treat this like an obligation and follow through - // with the unsizing - the lack of a coercion should - // be silent, as it causes a type mismatch later. - } - Ok(Some(vtable)) => { - for obligation in vtable.nested_obligations() { + for obligation in vtable.into_nested_obligations() { queue.push_back(obligation); } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 554a858bcc173..951bb4c747e16 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -213,7 +213,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id); let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing); + Reveal::UserFacing, + ty::UniverseIndex::ROOT); let param_env = traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, @@ -229,9 +230,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut selcx = traits::SelectionContext::new(&infcx); let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs); - let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, - infer::HigherRankedType, - &ty::Binder(impl_m_own_bounds.predicates)); + let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var( + impl_m_span, + param_env.universe, + infer::HigherRankedType, + &ty::Binder(impl_m_own_bounds.predicates)); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); @@ -257,9 +260,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let tcx = infcx.tcx; let (impl_sig, _) = - infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, - infer::HigherRankedType, - &tcx.fn_sig(impl_m.def_id)); + infcx.replace_late_bound_regions_with_fresh_var( + impl_m_span, + param_env.universe, + infer::HigherRankedType, + &tcx.fn_sig(impl_m.def_id)); let impl_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_node_id, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 610d07efa359d..b9d978b69c789 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -88,7 +88,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( let drop_impl_span = tcx.def_span(drop_impl_did); let fresh_impl_substs = - infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did); + infcx.fresh_substs_for_item(ty::UniverseIndex::ROOT, drop_impl_span, drop_impl_did); let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs); let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id); @@ -307,7 +307,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( // A projection that we couldn't resolve - it // might have a destructor. ty::TyProjection(..) | ty::TyAnon(..) => { - rcx.type_must_outlive(origin(), ty, parent_scope); + rcx.type_must_outlive(origin(), rcx.fcx.param_env, ty, parent_scope); } _ => { @@ -320,9 +320,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( for outlive in outlives { if let Some(r) = outlive.as_region() { - rcx.sub_regions(origin(), parent_scope, r); + rcx.sub_regions(origin(), rcx.fcx.param_env, parent_scope, r); } else if let Some(ty) = outlive.as_type() { - rcx.type_must_outlive(origin(), ty, parent_scope); + rcx.type_must_outlive(origin(), rcx.fcx.param_env, ty, parent_scope); } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index a9830dd5ddece..443d2cdf904a9 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let mut target = autoderef.unambiguous_final_ty(); if let Some(mutbl) = pick.autoref { - let region = self.next_region_var(infer::Autoref(self.span)); + let region = self.next_region_var(self.param_env.universe, infer::Autoref(self.span)); target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target @@ -240,7 +240,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // the process we will unify the transformed-self-type // of the method with the actual type in order to // unify some of these variables. - self.fresh_substs_for_item(self.span, trait_def_id) + self.fresh_substs_for_item(ty::UniverseIndex::ROOT, self.span, trait_def_id) } probe::WhereClausePick(ref poly_trait_ref) => { @@ -303,9 +303,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { = provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) { AstConv::ast_region_to_region(self.fcx, lifetime, Some(def)) } else { - self.region_var_for_def(self.span, def) + self.region_var_for_def(self.param_env.universe, self.span, def) } - }, |def, cur_substs| { + }, |def, _cur_substs| { let i = def.index as usize; if i < parent_substs.len() { parent_substs.type_at(i) @@ -316,7 +316,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { { self.to_ty(ast_ty) } else { - self.type_var_for_def(self.span, def, cur_substs) + self.type_var_for_def(ty::UniverseIndex::ROOT, self.span, def) } }) } @@ -549,15 +549,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { }; traits::elaborate_predicates(self.tcx, predicates.predicates.clone()) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => - Some(trait_pred), - _ => None, - } - }) + .filter_map(|p| p.poly_trait(self.tcx)) + .filter(|p| p.def_id() == sized_def_id) .any(|trait_pred| { - match trait_pred.0.self_ty().sty { + match trait_pred.skip_binder().self_ty().sty { ty::TyDynamic(..) => true, _ => false, } @@ -597,7 +592,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { where T: TypeFoldable<'tcx> { self.fcx - .replace_late_bound_regions_with_fresh_var(self.span, infer::FnCall, value) + .replace_late_bound_regions_with_fresh_var(self.span, + self.param_env.universe, + infer::FnCall, + value) .0 } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 58d72e37d51cf..80e884f47bb5d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -15,8 +15,8 @@ use hir::def::Def; use hir::def_id::DefId; use namespace::Namespace; use rustc::ty::subst::Substs; -use rustc::traits; -use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; +use rustc::traits::{self, PredicateObligation}; +use rustc::ty::{self, Ty, ToPredicate, TraitRef, TypeFoldable}; use rustc::ty::subst::Subst; use rustc::infer::{self, InferOk}; @@ -248,26 +248,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Construct a trait-reference `self_ty : Trait<input_tys>` let substs = Substs::for_item(self.tcx, trait_def_id, - |def, _| self.region_var_for_def(span, def), - |def, substs| { + |def, _| self.region_var_for_def(self.param_env.universe, + span, + def), + |def, _substs| { if def.index == 0 { self_ty } else if let Some(ref input_types) = opt_input_types { input_types[def.index as usize - 1] } else { - self.type_var_for_def(span, def, substs) + self.type_var_for_def(ty::UniverseIndex::ROOT, span, def) } }); let trait_ref = ty::TraitRef::new(trait_def_id, substs); // Construct an obligation - let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = traits::Obligation::misc(span, self.body_id, self.param_env, - poly_trait_ref.to_predicate()); + trait_ref.to_predicate()); // Now we want to know if this can be matched let mut selcx = traits::SelectionContext::new(self); @@ -296,6 +297,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // may reference those regions. let fn_sig = tcx.fn_sig(def_id); let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, + self.param_env.universe, infer::FnCall, &fn_sig).0; let fn_sig = fn_sig.subst(self.tcx, substs); @@ -333,9 +335,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, obligation); - obligations.push(traits::Obligation::new(cause, - self.param_env, - ty::Predicate::WellFormed(method_ty))); + obligations.push( + PredicateObligation::from( + cause, + self.param_env, + ty::PredicateAtom::WellFormed(method_ty))); let callee = MethodCallee { def_id, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 81e5b2fe00a6a..0683389d9a649 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -19,7 +19,7 @@ use hir::def::Def; use namespace::Namespace; use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; -use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable}; +use rustc::ty::{self, Ty, ToPredicate, TraitRef, TypeFoldable}; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::util::nodemap::FxHashSet; use rustc::infer::{self, InferOk}; @@ -588,25 +588,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let bounds: Vec<_> = self.param_env .caller_bounds .iter() - .filter_map(|predicate| { - match *predicate { - ty::Predicate::Trait(ref trait_predicate) => { - match trait_predicate.0.trait_ref.self_ty().sty { - ty::TyParam(ref p) if *p == param_ty => { - Some(trait_predicate.to_poly_trait_ref()) - } - _ => None, - } - } - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::Projection(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => None, + .filter_map(|predicate| predicate.poly_trait(self.tcx)) + .filter(|poly_trait_ref| { + match poly_trait_ref.skip_binder().self_ty().sty { + ty::TyParam(p) => p == param_ty, + _ => false, } }) .collect(); @@ -693,10 +679,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Def::Method(def_id) => { let fty = self.tcx.fn_sig(def_id); self.probe(|_| { - let substs = self.fresh_substs_for_item(self.span, method.def_id); + let substs = self.fresh_substs_for_item(ty::UniverseIndex::ROOT, + self.span, + method.def_id); let fty = fty.subst(self.tcx, substs); let (fty, _) = self.replace_late_bound_regions_with_fresh_var( - self.span, infer::FnCall, &fty); + self.span, self.param_env.universe, infer::FnCall, &fty); if let Some(self_ty) = self_ty { if let Err(_) = self.at(&ObligationCause::dummy(), self.param_env) @@ -952,13 +940,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn select_trait_candidate(&self, trait_ref: ty::TraitRef<'tcx>) - -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> + -> Result<Option<traits::Selection<'tcx>>, + Vec<traits::FulfillmentError<'tcx>>> { let cause = traits::ObligationCause::misc(self.span, self.body_id); - let predicate = - trait_ref.to_poly_trait_ref().to_poly_trait_predicate(); - let obligation = traits::Obligation::new(cause, self.param_env, predicate); - traits::SelectionContext::new(self).select(&obligation) + self.select_trait_ref(cause, self.param_env, trait_ref) } fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) @@ -1071,8 +1057,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let o = self.resolve_type_vars_if_possible(&o); if !selcx.evaluate_obligation(&o) { result = ProbeResult::NoMatch; - if let &ty::Predicate::Trait(ref pred) = &o.predicate { - possibly_unsatisfied_predicates.push(pred.0.trait_ref); + if let ty::PredicateAtom::Trait(pred) = o.predicate.skip_binders() { + possibly_unsatisfied_predicates.push(pred); } } } @@ -1265,12 +1251,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // `impl_self_ty()` for an explanation. self.tcx.types.re_erased } - }, |def, cur_substs| { + }, |def, _cur_substs| { let i = def.index as usize; if i < substs.len() { substs.type_at(i) } else { - self.type_var_for_def(self.span, def, cur_substs) + self.type_var_for_def(ty::UniverseIndex::ROOT, self.span, def) } }); xform_fn_sig.subst(self.tcx, substs) @@ -1287,6 +1273,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { def_id, |_, _| self.tcx.types.re_erased, |_, _| self.next_ty_var( + ty::UniverseIndex::ROOT, TypeVariableOrigin::SubstitutionPlaceholder( self.tcx.def_span(def_id)))) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 8613ec86b4a73..c00962862aeff 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -13,7 +13,7 @@ use check::FnCtxt; use rustc::hir::map as hir_map; -use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; @@ -54,14 +54,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.autoderef(span, ty).any(|(ty, _)| { self.probe(|_| { let fn_once_substs = tcx.mk_substs_trait(ty, - &[self.next_ty_var(TypeVariableOrigin::MiscVariable(span))]); + &[self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(span))]); let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs); - let poly_trait_ref = trait_ref.to_poly_trait_ref(); let obligation = Obligation::misc(span, self.body_id, self.param_env, - poly_trait_ref.to_predicate()); + trait_ref.to_predicate()); SelectionContext::new(self).evaluate_obligation(&obligation) }) }) @@ -271,7 +271,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !unsatisfied_predicates.is_empty() { let bound_list = unsatisfied_predicates.iter() - .map(|p| format!("`{} : {}`", p.self_ty(), p)) + .map(|p| format!("`{} : {}`", p.self_ty(), p.print_without_self())) .collect::<Vec<_>>() .join("\n"); err.note(&format!("the method `{}` exists but the following trait bounds \ diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 82d59ecfc92cf..ef886055e8246 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -92,8 +92,9 @@ use namespace::Namespace; use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; -use rustc::ty::subst::{Kind, Subst, Substs}; -use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode}; +use rustc::ty::subst::{Subst, Substs}; +use rustc::traits::{self, FulfillmentContext, PredicateObligation, + ObligationCause, ObligationCauseCode}; use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue}; use rustc::ty::{self, Ty, TyCtxt, Visibility}; use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; @@ -360,7 +361,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { /// hard constraint exists, creates a fresh type variable. fn coercion_target_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, span: Span) -> Ty<'tcx> { self.only_has_type(fcx) - .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span))) + .unwrap_or_else(|| fcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(span))) } } @@ -945,7 +947,8 @@ impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> { match ty_opt { None => { // infer the variable's type - let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); + let var_ty = self.fcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(span)); self.fcx.locals.borrow_mut().insert(nid, var_ty); var_ty } @@ -1038,7 +1041,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let span = body.value.span; if body.is_generator && can_be_generator { - fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + fcx.yield_ty = Some(fcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(span))); } GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); @@ -1068,7 +1072,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, }; inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, Some(gen_sig)); - let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)); + let witness = fcx.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(span)); fcx.deferred_generator_interiors.borrow_mut().push((body.id(), witness)); let interior = ty::GeneratorInterior::new(witness); @@ -1110,6 +1115,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let mut actual_return_ty = coercion.complete(&fcx); if actual_return_ty.is_never() { actual_return_ty = fcx.next_diverging_ty_var( + ty::UniverseIndex::ROOT, TypeVariableOrigin::DivergingFn(span)); } fcx.demand_suptype(span, ret_ty, actual_return_ty); @@ -1326,7 +1332,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "item `{}` is an associated const, \ which doesn't match its trait `{}`", ty_impl_item.name, - impl_trait_ref); + impl_trait_ref.print_without_self()); err.span_label(impl_item.span, "does not match trait"); // We can only get the spans from local trait definition // Same for E0324 and E0325 @@ -1362,7 +1368,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "item `{}` is an associated method, \ which doesn't match its trait `{}`", ty_impl_item.name, - impl_trait_ref); + impl_trait_ref.print_without_self()); err.span_label(impl_item.span, "does not match trait"); if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, "item in trait"); @@ -1380,7 +1386,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "item `{}` is an associated type, \ which doesn't match its trait `{}`", ty_impl_item.name, - impl_trait_ref); + impl_trait_ref.print_without_self()); err.span_label(impl_item.span, "does not match trait"); if let Some(trait_span) = tcx.hir.span_if_local(ty_trait_item.def_id) { err.span_label(trait_span, "item in trait"); @@ -1627,11 +1633,9 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { ty::GenericPredicates { parent: None, predicates: self.param_env.caller_bounds.iter().filter(|predicate| { - match **predicate { - ty::Predicate::Trait(ref data) => { - data.0.self_ty().is_param(index) - } - _ => false + match predicate.skip_binders() { + ty::PredicateAtom::Trait(ref data) => data.self_ty().is_param(index), + _ => false, } }).cloned().collect() } @@ -1643,18 +1647,18 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { Some(def) => infer::EarlyBoundRegion(span, def.name), None => infer::MiscVariable(span) }; - Some(self.next_region_var(v)) + Some(self.next_region_var(self.param_env.universe, v)) } fn ty_infer(&self, span: Span) -> Ty<'tcx> { - self.next_ty_var(TypeVariableOrigin::TypeInference(span)) + self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(span)) } fn ty_infer_for_def(&self, ty_param_def: &ty::TypeParameterDef, - substs: &[Kind<'tcx>], span: Span) -> Ty<'tcx> { - self.type_var_for_def(span, ty_param_def, substs) + self.type_var_for_def(ty::UniverseIndex::ROOT, span, ty_param_def) } fn projected_ty_from_poly_trait_ref(&self, @@ -1666,6 +1670,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { let (trait_ref, _) = self.replace_late_bound_regions_with_fresh_var( span, + self.param_env.universe, infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), &poly_trait_ref); @@ -1945,7 +1950,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return ty_var; } let span = self.tcx.def_span(def_id); - let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span)); + let ty_var = self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(span)); self.anon_types.borrow_mut().insert(id, ty_var); let predicates_of = self.tcx.predicates_of(def_id); @@ -2046,9 +2052,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { // WF obligations never themselves fail, so no real need to give a detailed cause: let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new(cause, - self.param_env, - ty::Predicate::WellFormed(ty))); + self.register_predicate(PredicateObligation::from(cause, + self.param_env, + ty::PredicateAtom::WellFormed(ty))); } /// Registers obligations that all types appearing in `substs` are well-formed. @@ -2279,7 +2285,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - let input_ty = self.next_ty_var(TypeVariableOrigin::AutoDeref(base_expr.span)); + let input_ty = self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::AutoDeref(base_expr.span)); let method = self.try_overloaded_lvalue_op( expr.span, self_ty, &[input_ty], lvalue_pref, LvalueOp::Index); @@ -2723,6 +2730,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(!self.tables.borrow().adjustments().contains_key(expr.hir_id), "expression with never type wound up being adjusted"); let adj_ty = self.next_diverging_ty_var( + ty::UniverseIndex::ROOT, TypeVariableOrigin::AdjustmentType(expr.span)); self.apply_adjustments(expr, vec![Adjustment { kind: Adjust::NeverToAny, @@ -2801,7 +2809,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let ity = self.tcx.type_of(did); debug!("impl_self_ty: ity={:?}", ity); - let substs = self.fresh_substs_for_item(span, did); + let substs = self.fresh_substs_for_item(ty::UniverseIndex::ROOT, span, did); let substd_ty = self.instantiate_type_scheme(span, &substs, &ity); TypeAndSubsts { substs: substs, ty: substd_ty } @@ -3663,7 +3671,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Finally, borrowck is charged with guaranteeing that the // value whose address was taken can actually be made to live // as long as it needs to live. - let region = self.next_region_var(infer::AddrOfRegion(expr.span)); + let region = self.next_region_var(self.param_env.universe, + infer::AddrOfRegion(expr.span)); tcx.mk_ref(region, tm) } } @@ -3932,7 +3941,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = uty.unwrap_or_else( - || self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span))); + || self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(expr.span))); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); assert_eq!(self.diverges.get(), Diverges::Maybe); for e in args { @@ -3942,7 +3952,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } coerce.complete(self) } else { - self.next_ty_var(TypeVariableOrigin::TypeInference(expr.span)) + self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::TypeInference(expr.span)) }; tcx.mk_array(element_ty, args.len() as u64) } @@ -3972,7 +3983,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (uty, uty) } None => { - let t: Ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span)); + let t: Ty = self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(element.span)); let element_ty = self.check_expr_has_type_or_error(&element, t); (element_ty, t) } @@ -4747,7 +4759,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Handle Self first, so we can adjust the index to match the AST. if has_self && i == 0 { return opt_self_ty.unwrap_or_else(|| { - self.type_var_for_def(span, def, substs) + self.type_var_for_def(ty::UniverseIndex::ROOT, span, def) }); } i -= has_self as usize; @@ -4780,7 +4792,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This can also be reached in some error cases: // We prefer to use inference variables instead of // TyError to let type inference recover somewhat. - self.type_var_for_def(span, def, substs) + self.type_var_for_def(ty::UniverseIndex::ROOT, span, def) } }); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 2d45f797ecb4d..987fead48c474 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -175,8 +175,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // trait matching creating lifetime constraints that are too strict. // E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. - let lhs_ty = self.check_expr_coercable_to_type_with_lvalue_pref(lhs_expr, - self.next_ty_var(TypeVariableOrigin::MiscVariable(lhs_expr.span)), + let lhs_ty = self.check_expr_coercable_to_type_with_lvalue_pref( + lhs_expr, + self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(lhs_expr.span)), lhs_pref); let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty); @@ -186,7 +188,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // using this variable as the expected type, which sometimes lets // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. - let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span)); + let rhs_ty_var = self.next_ty_var(ty::UniverseIndex::ROOT, + TypeVariableOrigin::MiscVariable(rhs_expr.span)); let result = self.lookup_op_method(lhs_ty, &[rhs_ty_var], Op::Binary(op, is_assign)); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index ad7978480a6b1..8cc268a17004f 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { r_o, r_o.cause); let sup_type = self.resolve_type(r_o.sup_type); let origin = self.code_to_origin(&r_o.cause, sup_type); - self.type_must_outlive(origin, sup_type, r_o.sub_region); + self.type_must_outlive(origin, self.fcx.param_env, sup_type, r_o.sub_region); } // Processing the region obligations should not cause the list to grow further: @@ -505,37 +505,37 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { .into_iter() .flat_map(|obligation| { assert!(!obligation.has_escaping_regions()); - match obligation.predicate { - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::Projection(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ConstEvaluatable(..) => + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(..) | + ty::PredicateAtom::Subtype(..) | + ty::PredicateAtom::Projection(..) | + ty::PredicateAtom::ClosureKind(..) | + ty::PredicateAtom::ObjectSafe(..) | + ty::PredicateAtom::ConstEvaluatable(..) => vec![], - ty::Predicate::WellFormed(subty) => { + ty::PredicateAtom::WellFormed(subty) => { + assert!(!subty.has_escaping_regions()); wf_types.push(subty); vec![] } - ty::Predicate::RegionOutlives(ref data) => - match self.tcx.no_late_bound_regions(data) { - None => - vec![], - Some(ty::OutlivesPredicate(r_a, r_b)) => - vec![ImpliedBound::RegionSubRegion(r_b, r_a)], + ty::PredicateAtom::RegionOutlives(data) => + if data.has_escaping_regions() { + vec![] + } else { + let ty::OutlivesPredicate(r_a, r_b) = data; + vec![ImpliedBound::RegionSubRegion(r_b, r_a)] }, - ty::Predicate::TypeOutlives(ref data) => - match self.tcx.no_late_bound_regions(data) { - None => vec![], - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = self.resolve_type_vars_if_possible(&ty_a); - let components = self.tcx.outlives_components(ty_a); - self.implied_bounds_from_components(r_b, components) - } + ty::PredicateAtom::TypeOutlives(data) => + if data.has_escaping_regions() { + vec![] + } else { + let ty::OutlivesPredicate(ty_a, r_b) = data; + let ty_a = self.resolve_type_vars_if_possible(&ty_a); + let components = self.tcx.outlives_components(ty_a); + self.implied_bounds_from_components(r_b, components) }, }})); } @@ -672,7 +672,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { let expr_region = self.tcx.mk_region(ty::ReScope( region::Scope::Node(expr.hir_id.local_id))); self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span), - expr_ty, expr_region); + self.fcx.param_env, + expr_ty, + expr_region); let is_method_call = self.tables.borrow().is_method_call(expr); @@ -763,7 +765,9 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { let rhs_ty = self.resolve_expr_type_adjusted(&rhs); for &ty in &[lhs_ty, rhs_ty] { self.type_must_outlive(infer::Operand(expr.span), - ty, expr_region); + self.fcx.param_env, + ty, + expr_region); } intravisit::walk_expr(self, expr); } @@ -818,7 +822,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { // FIXME(https://github.com/rust-lang/rfcs/issues/811) // nested method calls requires that this rule change let ty0 = self.resolve_node_type(expr.hir_id); - self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region); + self.type_must_outlive(infer::AddrOf(expr.span), + self.fcx.param_env, + ty0, + expr_region); intravisit::walk_expr(self, expr); } @@ -892,7 +899,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /*From:*/ (&ty::TyRef(from_r, ref from_mt), /*To: */ &ty::TyRef(to_r, ref to_mt)) => { // Target cannot outlive source, naturally. - self.sub_regions(infer::Reborrow(cast_expr.span), to_r, from_r); + self.sub_regions(infer::Reborrow(cast_expr.span), self.fcx.param_env, to_r, from_r); self.walk_cast(cast_expr, from_mt.ty, to_mt.ty); } @@ -900,7 +907,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /*To: */ &ty::TyDynamic(.., r)) => { // When T is existentially quantified as a trait // `Foo+'to`, it must outlive the region bound `'to`. - self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), from_ty, r); + self.type_must_outlive(infer::RelateObjectBound(cast_expr.span), + self.fcx.param_env, + from_ty, + r); } /*From:*/ (&ty::TyAdt(from_def, _), @@ -1030,9 +1040,13 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // Specialized version of constrain_call. self.type_must_outlive(infer::CallRcvr(expr.span), - input, expr_region); + self.fcx.param_env, + input, + expr_region); self.type_must_outlive(infer::CallReturn(expr.span), - output, expr_region); + self.fcx.param_env, + output, + expr_region); } if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind { @@ -1063,7 +1077,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { minimum_lifetime: ty::Region<'tcx>, maximum_lifetime: ty::Region<'tcx>) { self.sub_regions(infer::DerefPointer(deref_span), - minimum_lifetime, maximum_lifetime) + self.fcx.param_env, + minimum_lifetime, + maximum_lifetime) } fn check_safety_of_rvalue_destructor_if_necessary(&mut self, @@ -1104,7 +1120,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { match mt.ty.sty { ty::TySlice(_) | ty::TyStr => { self.sub_regions(infer::IndexSlice(index_expr.span), - self.tcx.mk_region(r_index_expr), r_ptr); + self.fcx.param_env, + self.tcx.mk_region(r_index_expr), + r_ptr); } _ => {} } @@ -1134,7 +1152,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { ty={}, ty0={}, id={:?}, minimum_lifetime={:?})", ty, ty0, hir_id, minimum_lifetime); - self.type_must_outlive(origin, ty, minimum_lifetime); + self.type_must_outlive(origin, self.fcx.param_env, ty, minimum_lifetime); } /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the @@ -1273,7 +1291,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let mut borrow_kind = borrow_kind; let origin = infer::DataBorrowed(borrow_cmt.ty, span); - self.type_must_outlive(origin, borrow_cmt.ty, borrow_region); + self.type_must_outlive(origin, self.fcx.param_env, borrow_cmt.ty, borrow_region); loop { debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})", @@ -1402,7 +1420,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("link_reborrowed_region: {:?} <= {:?}", borrow_region, ref_region); - self.sub_regions(cause, borrow_region, ref_region); + self.sub_regions(cause, self.fcx.param_env, borrow_region, ref_region); // If we end up needing to recurse and establish a region link // with `ref_cmt`, calculate what borrow kind we will end up @@ -1484,12 +1502,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); for region in substs.regions() { - self.sub_regions(origin.clone(), expr_region, region); + self.sub_regions(origin.clone(), self.fcx.param_env, expr_region, region); } for ty in substs.types() { let ty = self.resolve_type(ty); - self.type_must_outlive(origin.clone(), ty, expr_region); + self.type_must_outlive(origin.clone(), self.fcx.param_env, ty, expr_region); } } @@ -1498,6 +1516,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// `region`. pub fn type_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, region: ty::Region<'tcx>) { @@ -1511,11 +1530,12 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { assert!(!ty.has_escaping_regions()); let components = self.tcx.outlives_components(ty); - self.components_must_outlive(origin, components, region); + self.components_must_outlive(origin, param_env, components, region); } fn components_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, components: Vec<Component<'tcx>>, region: ty::Region<'tcx>) { @@ -1523,16 +1543,16 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = origin.clone(); match component { Component::Region(region1) => { - self.sub_regions(origin, region, region1); + self.sub_regions(origin, param_env, region, region1); } Component::Param(param_ty) => { - self.param_ty_must_outlive(origin, region, param_ty); + self.param_ty_must_outlive(origin, param_env, region, param_ty); } Component::Projection(projection_ty) => { - self.projection_must_outlive(origin, region, projection_ty); + self.projection_must_outlive(origin, param_env, region, projection_ty); } Component::EscapingProjection(subcomponents) => { - self.components_must_outlive(origin, subcomponents, region); + self.components_must_outlive(origin, param_env, subcomponents, region); } Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error @@ -1548,6 +1568,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn param_ty_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, + _param_env: ty::ParamEnv<'tcx>, region: ty::Region<'tcx>, param_ty: ty::ParamTy) { debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", @@ -1560,6 +1581,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn projection_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, + param_env: ty::ParamEnv<'tcx>, region: ty::Region<'tcx>, projection_ty: ty::ProjectionTy<'tcx>) { @@ -1614,11 +1636,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("projection_must_outlive: no declared bounds"); for component_ty in projection_ty.substs.types() { - self.type_must_outlive(origin.clone(), component_ty, region); + self.type_must_outlive(origin.clone(), param_env, component_ty, region); } for r in projection_ty.substs.regions() { - self.sub_regions(origin.clone(), region, r); + self.sub_regions(origin.clone(), param_env, region, r); } return; @@ -1637,7 +1659,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound); if projection_ty.substs.regions().any(|r| env_bounds.contains(&r)) { debug!("projection_must_outlive: unique declared bound appears in trait ref"); - self.sub_regions(origin.clone(), region, unique_bound); + self.sub_regions(origin.clone(), param_env, region, unique_bound); return; } } @@ -1789,9 +1811,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { traits::elaborate_predicates(self.tcx, predicates) .filter_map(|predicate| { // we're only interesting in `T : 'a` style predicates: - let outlives = match predicate { - ty::Predicate::TypeOutlives(data) => data, - _ => { return None; } + let outlives = match predicate.poly_type_outlives(self.tcx) { + Some(data) => data, + None => return None, }; debug!("projection_bounds: outlives={:?} (1)", @@ -1809,6 +1831,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let (outlives, _) = self.replace_late_bound_regions_with_fresh_var( span, + self.param_env.universe, infer::AssocTypeProjection(projection_ty.item_def_id), &outlives); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index d179b390a2918..4b07219603bf6 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::CaptureByRef => { let origin = UpvarRegion(upvar_id, span); - let freevar_region = self.next_region_var(origin); + let freevar_region = self.next_region_var(self.param_env.universe, origin); let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: freevar_region }; ty::UpvarCapture::ByRef(upvar_borrow) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 483af08cabfce..942c4f117309a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -271,12 +271,11 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // traits. let has_predicates = predicates.predicates.iter().any(|predicate| { - match predicate { - &ty::Predicate::Trait(ref poly_trait_ref) => { - let self_ty = poly_trait_ref.0.self_ty(); - !(self_ty.is_self() && poly_trait_ref.def_id() == trait_def_id) - }, - _ => true, + if let Some(poly_trait_ref) = predicate.poly_trait(self.tcx) { + let self_ty = poly_trait_ref.skip_binder().self_ty(); + !(self_ty.is_self() && poly_trait_ref.def_id() == trait_def_id) + } else { + true } }); @@ -381,7 +380,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { ty::wf::trait_obligations(fcx, fcx.param_env, fcx.body_id, - &trait_ref, + trait_ref, ast_trait_ref.path.span); for obligation in obligations { fcx.register_predicate(obligation); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index ce2ac73a27e0c..3e0c888d34473 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -309,6 +309,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { gcx.types.re_static } + ty::ReCanonical(_) | ty::ReVar(_) | ty::ReErased => { let span = node_id.to_span(&self.fcx.tcx); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index fedfa51d61d11..30a23244cf000 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -224,7 +224,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) { (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => { - infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); + infcx.sub_regions(infer::RelateObjectBound(span), param_env, r_b, r_a); check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty)) } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 5cc6eaa5602fb..196ab5b486c72 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -88,7 +88,7 @@ impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> { E0521, "redundant auto implementations of trait \ `{}`:", - trait_ref); + trait_ref.print_without_self()); err.span_note(self.tcx .span_of_impl(self.tcx.hir.local_def_id(prev_id)) .unwrap(), diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs index 280fb04e04001..71fb2eacd1556 100644 --- a/src/librustc_typeck/coherence/unsafety.rs +++ b/src/librustc_typeck/coherence/unsafety.rs @@ -49,7 +49,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { item.span, E0199, "implementing the trait `{}` is not unsafe", - trait_ref); + trait_ref.print_without_self()); } (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => { @@ -57,7 +57,7 @@ impl<'cx, 'tcx, 'v> UnsafetyChecker<'cx, 'tcx> { item.span, E0200, "the trait `{}` requires an `unsafe impl` declaration", - trait_ref); + trait_ref.print_without_self()); } (Unsafety::Normal, Some(g), Unsafety::Normal, hir::ImplPolarity::Positive) => diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 814470974285f..76d87348bf94c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -33,7 +33,7 @@ use middle::resolve_lifetime as rl; use rustc::traits::Reveal; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; -use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use util::nodemap::FxHashMap; @@ -696,7 +696,7 @@ fn super_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Now require that immediate supertraits are converted, // which will, in turn, reach indirect supertraits. - for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) { + for bound in superbounds.iter().filter_map(|p| p.poly_trait(tcx)) { tcx.at(item.span).super_predicates_of(bound.def_id()); } @@ -1405,7 +1405,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Add in a predicate that `Self:Trait` (where `Trait` is the // current trait). This is needed for builtin bounds. - predicates.push(trait_ref.to_poly_trait_ref().to_predicate()); + predicates.push(trait_ref.to_predicate()); } // Collect the region predicates that were declared inline as @@ -1471,7 +1471,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, lifetime, None); let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); - predicates.push(ty::Predicate::TypeOutlives(pred)) + predicates.push(pred.to_predicate()) } } } @@ -1482,7 +1482,7 @@ fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, for bound in ®ion_pred.bounds { let r2 = AstConv::ast_region_to_region(&icx, bound, None); let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); - predicates.push(ty::Predicate::RegionOutlives(pred)) + predicates.push(pred.to_predicate()); } } @@ -1616,7 +1616,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, hir::RegionTyParamBound(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); - vec![ty::Predicate::TypeOutlives(pred)] + vec![pred.to_predicate()] } hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => { Vec::new() diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 5f55b9b06ef1b..4ed718116fd6a 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -169,11 +169,9 @@ pub fn setup_constraining_predicates<'tcx>(tcx: TyCtxt, changed = false; for j in i..predicates.len() { - if let ty::Predicate::Projection(ref poly_projection) = predicates[j] { - // Note that we can skip binder here because the impl - // trait ref never contains any late-bound regions. - let projection = poly_projection.skip_binder(); - + // Note that we can skip binder here because the impl + // trait ref never contains any late-bound regions. + if let ty::PredicateAtom::Projection(projection) = predicates[j].skip_binders() { // Special case: watch out for some kind of sneaky attempt // to project out an associated type defined by this very // trait. diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index ef6552c8e33f4..9f18a449f7896 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -464,6 +464,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // way early-bound regions do, so we skip them here. } + ty::ReCanonical(_) | ty::ReFree(..) | ty::ReScope(..) | ty::ReVar(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 4b60536e1d176..88f15e401f439 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -965,7 +965,6 @@ impl<'a> Clean<WherePredicate> 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), @@ -978,15 +977,6 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> { } } -impl<'a> Clean<WherePredicate> for ty::TraitPredicate<'a> { - fn clean(&self, cx: &DocContext) -> WherePredicate { - WherePredicate::BoundPredicate { - ty: self.trait_ref.self_ty().clean(cx), - bounds: vec![self.trait_ref.clean(cx)] - } - } -} - impl<'tcx> Clean<WherePredicate> for ty::EquatePredicate<'tcx> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::EquatePredicate(ref lhs, ref rhs) = *self; diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index dd36b28bb39ac..9565d0506df96 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -143,7 +143,8 @@ fn ty_bounds(bounds: Vec<clean::TyParamBound>) -> Vec<clean::TyParamBound> { bounds } -fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, +fn trait_is_same_or_supertrait(cx: &DocContext, + child: DefId, trait_: DefId) -> bool { if child == trait_ { return true diff --git a/src/test/compile-fail/associated-types-eq-hr.rs b/src/test/compile-fail/associated-types-eq-hr.rs index 52a2ca9082d23..f456f185e412f 100644 --- a/src/test/compile-fail/associated-types-eq-hr.rs +++ b/src/test/compile-fail/associated-types-eq-hr.rs @@ -87,23 +87,35 @@ fn tuple_four<T>() // not ok for tuple, two lifetimes, and lifetime matching is invariant } -pub fn main() { +fn a() { foo::<IntStruct>(); foo::<UintStruct>(); //~ ERROR type mismatch +} +fn b() { bar::<IntStruct>(); //~ ERROR type mismatch bar::<UintStruct>(); +} +fn c() { tuple_one::<Tuple>(); - //~^ ERROR E0277 - //~| ERROR type mismatch + //~^ ERROR mismatched types + //~| ERROR mismatched types +} +fn d() { tuple_two::<Tuple>(); - //~^ ERROR E0277 - //~| ERROR type mismatch + //~^ ERROR mismatched types + //~| ERROR mismatched types +} +fn e() { tuple_three::<Tuple>(); +} +fn g() { tuple_four::<Tuple>(); - //~^ ERROR E0277 + //~^ ERROR mismatched types } + +fn main() { } diff --git a/src/test/compile-fail/associated-types/higher-ranked-projection.rs b/src/test/compile-fail/associated-types/higher-ranked-projection.rs index 12341fa8db38f..07266c44644eb 100644 --- a/src/test/compile-fail/associated-types/higher-ranked-projection.rs +++ b/src/test/compile-fail/associated-types/higher-ranked-projection.rs @@ -33,6 +33,5 @@ fn foo<U, T>(_t: T) #[rustc_error] fn main() { //[good]~ ERROR compilation successful foo(()); - //[bad]~^ ERROR type mismatch resolving `for<'a> <&'a _ as Mirror>::Image == _` - //[bad]~| expected bound lifetime parameter 'a, found concrete lifetime + //[bad]~^ ERROR mismatched types } diff --git a/src/test/run-pass/coherence-subtyping.rs b/src/test/compile-fail/coherence-different-binding.rs similarity index 79% rename from src/test/run-pass/coherence-subtyping.rs rename to src/test/compile-fail/coherence-different-binding.rs index eb04514271c75..4ff47be75fd7a 100644 --- a/src/test/run-pass/coherence-subtyping.rs +++ b/src/test/compile-fail/coherence-different-binding.rs @@ -18,7 +18,7 @@ trait Contravariant { impl Contravariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } -impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { +impl Contravariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { //~ ERROR conflicting implementations } /////////////////////////////////////////////////////////////////////////// @@ -30,7 +30,7 @@ trait Covariant { impl Covariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } -impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { +impl Covariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { //~ ERROR conflicting implementations } /////////////////////////////////////////////////////////////////////////// @@ -42,7 +42,7 @@ trait Invariant { impl Invariant for for<'a,'b> fn(&'a u8, &'b u8) -> &'a u8 { } -impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { +impl Invariant for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { //~ ERROR conflicting implementations } fn main() { } diff --git a/src/test/compile-fail/hr-subtype.rs b/src/test/compile-fail/hr-subtype.rs index c88d74d53ce94..e3077eb00406f 100644 --- a/src/test/compile-fail/hr-subtype.rs +++ b/src/test/compile-fail/hr-subtype.rs @@ -52,10 +52,6 @@ macro_rules! check { //[bound_inv_a_b_vs_bound_inv_a]~^^^ ERROR mismatched types //[bound_a_b_ret_a_vs_bound_a_ret_a]~^^^^ ERROR mismatched types //[free_inv_x_vs_free_inv_y]~^^^^^ ERROR mismatched types - //[bound_a_b_vs_bound_a]~^^^^^^ ERROR mismatched types - //[bound_co_a_b_vs_bound_co_a]~^^^^^^^ ERROR mismatched types - //[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR mismatched types - //[bound_co_a_co_b_ret_contra_a]~^^^^^^^^^ ERROR mismatched types } } } @@ -113,4 +109,8 @@ fn main() { //[bound_inv_a_vs_bound_inv_b]~^^^ ERROR compilation successful //[bound_co_a_vs_bound_co_b]~^^^^ ERROR compilation successful //[free_x_vs_free_x]~^^^^^ ERROR compilation successful +//[bound_a_b_vs_bound_a]~^^^^^^ ERROR compilation successful +//[bound_co_a_b_vs_bound_co_a]~^^^^^^^ ERROR compilation successful +//[bound_contra_a_contra_b_ret_co_a]~^^^^^^^^ ERROR compilation successful +//[bound_co_a_co_b_ret_contra_a]~^^^^^^^^^ ERROR compilation successful } diff --git a/src/test/compile-fail/hrtb-conflate-regions.rs b/src/test/compile-fail/hrtb-conflate-regions.rs index 845429d4b0c0b..33e8dd07a81a6 100644 --- a/src/test/compile-fail/hrtb-conflate-regions.rs +++ b/src/test/compile-fail/hrtb-conflate-regions.rs @@ -35,6 +35,6 @@ impl<'a> Foo<(&'a isize, &'a isize)> for SomeStruct } fn a() { want_foo1::<SomeStruct>(); } // OK -- foo wants just one region -fn b() { want_foo2::<SomeStruct>(); } //~ ERROR E0277 +fn b() { want_foo2::<SomeStruct>(); } //~ ERROR mismatched types fn main() { } diff --git a/src/test/compile-fail/hrtb-higher-ranker-supertraits-transitive.rs b/src/test/compile-fail/hrtb-higher-ranker-supertraits-transitive.rs index b55dccec2d56f..c38bc23cb86f6 100644 --- a/src/test/compile-fail/hrtb-higher-ranker-supertraits-transitive.rs +++ b/src/test/compile-fail/hrtb-higher-ranker-supertraits-transitive.rs @@ -54,7 +54,7 @@ fn want_qux<B>(b: &B) where B : Qux { want_foo_for_any_tcx(b); - want_bar_for_any_ccx(b); //~ ERROR E0277 + want_bar_for_any_ccx(b); //~ ERROR mismatched types } fn main() {} diff --git a/src/test/compile-fail/hrtb-higher-ranker-supertraits.rs b/src/test/compile-fail/hrtb-higher-ranker-supertraits.rs index 4c5add4aceaaf..014d6c7729f77 100644 --- a/src/test/compile-fail/hrtb-higher-ranker-supertraits.rs +++ b/src/test/compile-fail/hrtb-higher-ranker-supertraits.rs @@ -25,7 +25,8 @@ fn want_foo_for_some_tcx<'x,F>(f: &'x F) where F : Foo<'x> { want_foo_for_some_tcx(f); - want_foo_for_any_tcx(f); //~ ERROR E0277 + want_foo_for_any_tcx(f); + //~^ ERROR mismatched types } fn want_foo_for_any_tcx<F>(f: &F) @@ -42,7 +43,8 @@ fn want_bar_for_some_ccx<'x,B>(b: &B) want_foo_for_any_tcx(b); want_bar_for_some_ccx(b); - want_bar_for_any_ccx(b); //~ ERROR E0277 + want_bar_for_any_ccx(b); + //~^ ERROR mismatched types } fn want_bar_for_any_ccx<B>(b: &B) diff --git a/src/test/compile-fail/hrtb-just-for-static.rs b/src/test/compile-fail/hrtb-just-for-static.rs index aec950f992cf4..968f8f3c1a6d2 100644 --- a/src/test/compile-fail/hrtb-just-for-static.rs +++ b/src/test/compile-fail/hrtb-just-for-static.rs @@ -31,7 +31,7 @@ fn give_any() { struct StaticInt; impl Foo<&'static isize> for StaticInt { } fn give_static() { - want_hrtb::<StaticInt>() //~ ERROR `for<'a> StaticInt: Foo<&'a isize>` is not satisfied + want_hrtb::<StaticInt>() //~ ERROR mismatched types } fn main() { } diff --git a/src/test/compile-fail/hrtb-perfect-forwarding.rs b/src/test/compile-fail/hrtb-perfect-forwarding.rs index fcfbeefced06b..ef9a5046271ed 100644 --- a/src/test/compile-fail/hrtb-perfect-forwarding.rs +++ b/src/test/compile-fail/hrtb-perfect-forwarding.rs @@ -53,7 +53,7 @@ fn foo_hrtb_bar_not<'b,T>(mut t: T) // be implemented. Thus to satisfy `&mut T : for<'a> Foo<&'a // isize>`, we require `T : for<'a> Bar<&'a isize>`, but the where // clause only specifies `T : Bar<&'b isize>`. - foo_hrtb_bar_not(&mut t); //~ ERROR `for<'a> T: Bar<&'a isize>` is not satisfied + foo_hrtb_bar_not(&mut t); //~ ERROR mismatched types } fn foo_hrtb_bar_hrtb<T>(mut t: T) diff --git a/src/test/compile-fail/issue-19538.rs b/src/test/compile-fail/issue-19538.rs index a619050058262..c9dc96622a74e 100644 --- a/src/test/compile-fail/issue-19538.rs +++ b/src/test/compile-fail/issue-19538.rs @@ -26,5 +26,5 @@ fn main() { let mut thing = Thing; let test: &mut Bar = &mut thing; //~^ ERROR E0038 - //~| ERROR E0038 + //~| ERROR E0308 } diff --git a/src/test/compile-fail/issue-20692.rs b/src/test/compile-fail/issue-20692.rs index 3e44053875552..ef204f61eb247 100644 --- a/src/test/compile-fail/issue-20692.rs +++ b/src/test/compile-fail/issue-20692.rs @@ -12,10 +12,8 @@ trait Array: Sized {} fn f<T: Array>(x: &T) { let _ = x - //~^ ERROR `Array` cannot be made into an object - //~| NOTE the trait cannot require that `Self : Sized` - //~| NOTE requirements on the impl of `std::ops::CoerceUnsized<&Array>` - //~| NOTE the trait `Array` cannot be made into an object + //~^ ERROR non-primitive cast + //~| NOTE an `as` expression can only be used to convert between primitive types. as &Array; //~^ ERROR `Array` cannot be made into an object diff --git a/src/test/compile-fail/issue-27942.rs b/src/test/compile-fail/issue-27942.rs index 0fa4184606e45..42cb42f266953 100644 --- a/src/test/compile-fail/issue-27942.rs +++ b/src/test/compile-fail/issue-27942.rs @@ -17,11 +17,11 @@ pub trait Buffer<'a, R: Resources<'a>> { fn select(&self) -> BufferViewHandle<R>; //~^ ERROR mismatched types //~| lifetime mismatch - //~| NOTE expected type `Resources<'_>` + //~| NOTE expected type `Resources<'a>` //~| NOTE ...does not necessarily outlive the anonymous lifetime #1 defined on the method body //~| ERROR mismatched types //~| lifetime mismatch - //~| NOTE expected type `Resources<'_>` + //~| NOTE expected type `Resources<'a>` //~| NOTE the anonymous lifetime #1 defined on the method body at 17:5... } diff --git a/src/test/compile-fail/issue-38604.rs b/src/test/compile-fail/issue-38604.rs index c1939a7707f39..4994e360f5624 100644 --- a/src/test/compile-fail/issue-38604.rs +++ b/src/test/compile-fail/issue-38604.rs @@ -22,5 +22,5 @@ impl Foo for () { fn main() { let _f: Box<Foo> = //~ ERROR `Foo` cannot be made into an object - Box::new(()); //~ ERROR `Foo` cannot be made into an object + Box::new(()); //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-39970.rs b/src/test/compile-fail/issue-39970.rs index 65ea1baa4a126..37c7a02878761 100644 --- a/src/test/compile-fail/issue-39970.rs +++ b/src/test/compile-fail/issue-39970.rs @@ -27,5 +27,5 @@ impl Visit for () where fn main() { <() as Visit>::visit(); - //~^ ERROR type mismatch resolving `for<'a> <() as Array<'a>>::Element == ()` + //~^ ERROR type mismatch resolving `<() as Array<'a>>::Element == ()` } diff --git a/src/test/compile-fail/issue-40000.rs b/src/test/compile-fail/issue-40000.rs index 7daf4bcbaa44b..be0ccae89aa16 100644 --- a/src/test/compile-fail/issue-40000.rs +++ b/src/test/compile-fail/issue-40000.rs @@ -14,5 +14,4 @@ fn main() { fn foo(x: Box<Fn(&i32)>) {} let bar = Box::new(|x: &i32| {}) as Box<Fn(_)>; foo(bar); //~ ERROR mismatched types - //~| expected concrete lifetime, found bound lifetime parameter } diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 0731fbaf01c43..c04e6d7838fb6 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -33,7 +33,7 @@ fn b() { let y = &x; let z = &x as &Foo; //~^ ERROR E0038 - //~| ERROR E0038 + //~| ERROR E0605 } fn main() { } diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 58794e3b35d53..e8413b6dc61dc 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,4 +23,5 @@ pub fn main() { let arr: &[_] = &[1, 2, 3]; let range = *arr..; //~^ ERROR `[{integer}]: std::marker::Sized` is not satisfied + //~| ERROR the trait bound `[{integer}]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/regions-fn-subtyping-return-static.rs b/src/test/compile-fail/regions-fn-subtyping-return-static.rs index 6be65a5e35905..e63c679daf1e8 100644 --- a/src/test/compile-fail/regions-fn-subtyping-return-static.rs +++ b/src/test/compile-fail/regions-fn-subtyping-return-static.rs @@ -47,8 +47,7 @@ fn baz(x: &S) -> &S { fn supply_F() { want_F(foo); - // FIXME(#33684) -- this should be a subtype, but current alg. rejects it incorrectly - want_F(bar); //~ ERROR E0308 + want_F(bar); want_F(baz); } @@ -58,9 +57,6 @@ fn supply_G() { want_G(bar); want_G(baz); //~^ ERROR mismatched types - //~| expected type `for<'cx> fn(&'cx S) -> &'static S` - //~| found type `for<'r> fn(&'r S) -> &'r S {baz}` - //~| expected concrete lifetime, found bound lifetime parameter 'cx } pub fn main() { diff --git a/src/test/compile-fail/trait-object-safety.rs b/src/test/compile-fail/trait-object-safety.rs index baf239f5956d6..ce5c28aa07cdd 100644 --- a/src/test/compile-fail/trait-object-safety.rs +++ b/src/test/compile-fail/trait-object-safety.rs @@ -23,5 +23,5 @@ impl Tr for St { fn main() { let _: &Tr = &St; //~ ERROR E0038 - //~^ ERROR E0038 + //~^ ERROR E0308 } diff --git a/src/test/compile-fail/trait-test-2.rs b/src/test/compile-fail/trait-test-2.rs index b08aab6da852a..51c7ee792ee15 100644 --- a/src/test/compile-fail/trait-test-2.rs +++ b/src/test/compile-fail/trait-test-2.rs @@ -19,6 +19,6 @@ fn main() { 10.blah::<i32, i32>(); //~ ERROR expected at most 1 type parameter, found 2 type parameters (box 10 as Box<bar>).dup(); //~^ ERROR E0038 - //~| ERROR E0038 + //~| ERROR E0605 //~| ERROR E0277 } diff --git a/src/test/compile-fail/where-for-self-2.rs b/src/test/compile-fail/where-for-self-2.rs index bf8fc29217338..8092ae87cd663 100644 --- a/src/test/compile-fail/where-for-self-2.rs +++ b/src/test/compile-fail/where-for-self-2.rs @@ -29,5 +29,5 @@ fn foo<T>(x: &T) fn main() { foo(&X); - //~^ error: `for<'a> &'a _: Bar` is not satisfied + //~^ ERROR mismatched types } diff --git a/src/test/ui/regions-fn-subtyping-return-static.rs b/src/test/run-pass/regions-fn-subtyping-return-static.rs similarity index 91% rename from src/test/ui/regions-fn-subtyping-return-static.rs rename to src/test/run-pass/regions-fn-subtyping-return-static.rs index 9098511186724..d024b539d85f6 100644 --- a/src/test/ui/regions-fn-subtyping-return-static.rs +++ b/src/test/run-pass/regions-fn-subtyping-return-static.rs @@ -47,8 +47,9 @@ fn baz(x: &S) -> &S { fn supply_F() { want_F(foo); - // FIXME(#33684) -- this should be a subtype, but current alg. rejects it incorrectly - want_F(bar); //~ ERROR E0308 + // Note -- older algorithm rejected this case, but it is a valid + // subtyping. See #33684. + want_F(bar); want_F(baz); } diff --git a/src/test/run-pass/use_inline_dtor.rs b/src/test/run-pass/use_inline_dtor.rs index 0f55a357a00f4..64155249993b0 100644 --- a/src/test/run-pass/use_inline_dtor.rs +++ b/src/test/run-pass/use_inline_dtor.rs @@ -1,3 +1,4 @@ + // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr index ab5b3e1791528..187cf3ced9150 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -5,7 +5,7 @@ error[E0599]: no method named `unwrap` found for type `std::result::Result<(), F | ^^^^^^ | = note: the method `unwrap` exists but the following trait bounds were not satisfied: - `Foo : std::fmt::Debug` + `Foo: std::fmt::Debug` error: aborting due to previous error diff --git a/src/test/ui/regions-fn-subtyping-return-static.stderr b/src/test/ui/regions-fn-subtyping-return-static.stderr deleted file mode 100644 index 4a97537223cf6..0000000000000 --- a/src/test/ui/regions-fn-subtyping-return-static.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/regions-fn-subtyping-return-static.rs:51:12 - | -51 | want_F(bar); //~ ERROR E0308 - | ^^^ expected concrete lifetime, found bound lifetime parameter 'cx - | - = note: expected type `for<'cx> fn(&'cx S) -> &'cx S` - found type `for<'a> fn(&'a S) -> &S {bar::<'_>}` - -error: aborting due to previous error -