Auto merge of #55093 - nikomatsakis:nll-issue-54574-multisegment-path, r=pnkfelix

nll type annotations in multisegment path

This turned out to be sort of tricky. The problem is that if you have a path like

```
<Foo<&'static u32>>::bar
```

and it comes from an impl like `impl<T> Foo<T>` then the self-type the user gave doesn't *directly* map to the substitutions that the impl wants. To handle this, then, we have to preserve not just the "user-given substs" we used to do, but also a "user-given self-ty", which we have to apply later. This PR makes those changes.

It also removes the code from NLL relate-ops that handled canonical variables and moves to use normal inference variables instead. This simplifies a few things and gives us a bit more flexibility (for example, I predict we are going to have to start normalizing at some point, and it would be easy now).

r? @matthewjasper -- you were just touching this code, do you feel comfortable reviewing this?

Fixes #54574
This commit is contained in:
bors 2018-10-16 23:27:43 +00:00
commit 01ca85becd
31 changed files with 1256 additions and 844 deletions

View File

@ -587,3 +587,24 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::ClosureOutlivesSubj
}
impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted });
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::UserTypeAnnotation<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
mir::UserTypeAnnotation::Ty(ref ty) => {
ty.hash_stable(hcx, hasher);
}
mir::UserTypeAnnotation::FnDef(ref def_id, ref substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
}
}
}
}

View File

@ -1417,3 +1417,8 @@ impl_stable_hash_for!(enum traits::QuantifierKind {
Universal,
Existential
});
impl_stable_hash_for!(struct ty::subst::UserSubsts<'tcx> { substs, user_self_ty });
impl_stable_hash_for!(struct ty::subst::UserSelfTy<'tcx> { impl_def_id, self_ty });

View File

@ -241,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
/// canonicalized) then represents the values that you computed
/// for each of the canonical inputs to your query.
pub(in infer) fn instantiate_canonical_with_fresh_inference_vars<T>(
pub fn instantiate_canonical_with_fresh_inference_vars<T>(
&self,
span: Span,
canonical: &Canonical<'tcx, T>,
@ -249,9 +249,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
where
T: TypeFoldable<'tcx>,
{
assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created");
assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created");
let canonical_inference_vars =
self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
let result = canonical.substitute(self.tcx, &canonical_inference_vars);

View File

@ -62,6 +62,7 @@ mod higher_ranked;
pub mod lattice;
mod lexical_region_resolve;
mod lub;
pub mod nll_relate;
pub mod opaque_types;
pub mod outlives;
pub mod region_constraints;

View File

@ -0,0 +1,736 @@
// Copyright 2017 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.
//! This code is kind of an alternate way of doing subtyping,
//! supertyping, and type equating, distinct from the `combine.rs`
//! code but very similar in its effect and design. Eventually the two
//! ought to be merged. This code is intended for use in NLL.
//!
//! Here are the key differences:
//!
//! - This code generally assumes that there are no unbound type
//! inferences variables, because at NLL
//! time types are fully inferred up-to regions.
//! - Actually, to support user-given type annotations like
//! `Vec<_>`, we do have some measure of support for type
//! inference variables, but we impose some simplifying
//! assumptions on them that would not be suitable for the infer
//! code more generally. This could be fixed.
//! - This code uses "universes" to handle higher-ranked regions and
//! not the leak-check. This is "more correct" than what rustc does
//! and we are generally migrating in this direction, but NLL had to
//! get there first.
use crate::infer::InferCtxt;
use crate::ty::fold::{TypeFoldable, TypeVisitor};
use crate::ty::relate::{self, Relate, RelateResult, TypeRelation};
use crate::ty::subst::Kind;
use crate::ty::{self, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
pub struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
where
D: TypeRelatingDelegate<'tcx>,
{
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
/// Callback to use when we deduce an outlives relationship
delegate: D,
/// How are we relating `a` and `b`?
///
/// - covariant means `a <: b`
/// - contravariant means `b <: a`
/// - invariant means `a == b
/// - bivariant means that it doesn't matter
ambient_variance: ty::Variance,
/// When we pass through a set of binders (e.g., when looking into
/// a `fn` type), we push a new bound region scope onto here. This
/// will contain the instantiated region for each region in those
/// binders. When we then encounter a `ReLateBound(d, br)`, we can
/// use the debruijn index `d` to find the right scope, and then
/// bound region name `br` to find the specific instantiation from
/// within that scope. See `replace_bound_region`.
///
/// This field stores the instantiations for late-bound regions in
/// the `a` type.
a_scopes: Vec<BoundRegionScope<'tcx>>,
/// Same as `a_scopes`, but for the `b` type.
b_scopes: Vec<BoundRegionScope<'tcx>>,
}
pub trait TypeRelatingDelegate<'tcx> {
/// Push a constraint `sup: sub` -- this constraint must be
/// satisfied for the two types to be related. `sub` and `sup` may
/// be regions from the type or new variables created through the
/// delegate.
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
/// Creates a new universe index. Used when instantiating placeholders.
fn create_next_universe(&mut self) -> ty::UniverseIndex;
/// Creates a new region variable representing a higher-ranked
/// region that is instantiated existentially. This creates an
/// inference variable, typically.
///
/// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
/// we will invoke this method to instantiate `'a` with an
/// inference variable (though `'b` would be instantiated first,
/// as a placeholder).
fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
/// Creates a new region variable representing a
/// higher-ranked region that is instantiated universally.
/// This creates a new region placeholder, typically.
///
/// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
/// we will invoke this method to instantiate `'b` with a
/// placeholder region.
fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
/// Creates a new existential region in the given universe. This
/// is used when handling subtyping and type variables -- if we
/// have that `?X <: Foo<'a>`, for example, we would instantiate
/// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
/// existential variable created by this function. We would then
/// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
/// relation stating that `'?0: 'a`).
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
}
#[derive(Clone, Debug)]
struct ScopesAndKind<'tcx> {
scopes: Vec<BoundRegionScope<'tcx>>,
kind: Kind<'tcx>,
}
#[derive(Clone, Debug, Default)]
struct BoundRegionScope<'tcx> {
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
}
#[derive(Copy, Clone)]
struct UniversallyQuantified(bool);
impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
pub fn new(
infcx: &'me InferCtxt<'me, 'gcx, 'tcx>,
delegate: D,
ambient_variance: ty::Variance,
) -> Self {
Self {
infcx,
delegate,
ambient_variance,
a_scopes: vec![],
b_scopes: vec![],
}
}
fn ambient_covariance(&self) -> bool {
match self.ambient_variance {
ty::Variance::Covariant | ty::Variance::Invariant => true,
ty::Variance::Contravariant | ty::Variance::Bivariant => false,
}
}
fn ambient_contravariance(&self) -> bool {
match self.ambient_variance {
ty::Variance::Contravariant | ty::Variance::Invariant => true,
ty::Variance::Covariant | ty::Variance::Bivariant => false,
}
}
fn create_scope(
&mut self,
value: &ty::Binder<impl TypeFoldable<'tcx>>,
universally_quantified: UniversallyQuantified,
) -> BoundRegionScope<'tcx> {
let mut scope = BoundRegionScope::default();
// Create a callback that creates (via the delegate) either an
// existential or placeholder region as needed.
let mut next_region = {
let delegate = &mut self.delegate;
let mut lazy_universe = None;
move |br: ty::BoundRegion| {
if universally_quantified.0 {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
let universe = lazy_universe.unwrap_or_else(|| {
let universe = delegate.create_next_universe();
lazy_universe = Some(universe);
universe
});
let placeholder = ty::Placeholder { universe, name: br };
delegate.next_placeholder_region(placeholder)
} else {
delegate.next_existential_region_var()
}
}
};
value.skip_binder().visit_with(&mut ScopeInstantiator {
next_region: &mut next_region,
target_index: ty::INNERMOST,
bound_region_scope: &mut scope,
});
scope
}
/// When we encounter binders during the type traversal, we record
/// the value to substitute for each of the things contained in
/// that binder. (This will be either a universal placeholder or
/// an existential inference variable.) Given the debruijn index
/// `debruijn` (and name `br`) of some binder we have now
/// encountered, this routine finds the value that we instantiated
/// the region with; to do so, it indexes backwards into the list
/// of ambient scopes `scopes`.
fn lookup_bound_region(
debruijn: ty::DebruijnIndex,
br: &ty::BoundRegion,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
// The debruijn index is a "reverse index" into the
// scopes listing. So when we have INNERMOST (0), we
// want the *last* scope pushed, and so forth.
let debruijn_index = debruijn.index() - first_free_index.index();
let scope = &scopes[scopes.len() - debruijn_index - 1];
// Find this bound region in that scope to map to a
// particular region.
scope.map[br]
}
/// If `r` is a bound region, find the scope in which it is bound
/// (from `scopes`) and return the value that we instantiated it
/// with. Otherwise just return `r`.
fn replace_bound_region(
&self,
r: ty::Region<'tcx>,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
if let ty::ReLateBound(debruijn, br) = r {
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
} else {
r
}
}
/// Push a new outlives requirement into our output set of
/// constraints.
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
debug!("push_outlives({:?}: {:?})", sup, sub);
self.delegate.push_outlives(sup, sub);
}
/// When we encounter a canonical variable `var` in the output,
/// equate it with `kind`. If the variable has been previously
/// equated, then equate it again.
fn relate_var(&mut self, var_ty: Ty<'tcx>, value_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty);
let generalized_ty = self.generalize_value(value_ty);
self.infcx
.force_instantiate_unchecked(var_ty, generalized_ty);
// The generalized values we extract from `canonical_var_values` have
// been fully instantiated and hence the set of scopes we have
// doesn't matter -- just to be sure, put an empty vector
// in there.
let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
// Relate the generalized kind to the original one.
let result = self.relate(&generalized_ty, &value_ty);
// Restore the old scopes now.
self.a_scopes = old_a_scopes;
debug!("equate_var: complete, result = {:?}", result);
result
}
fn generalize_value<T: Relate<'tcx>>(&mut self, value: T) -> T {
TypeGeneralizer {
tcx: self.infcx.tcx,
delegate: &mut self.delegate,
first_free_index: ty::INNERMOST,
ambient_variance: self.ambient_variance,
// These always correspond to an `_` or `'_` written by
// user, and those are always in the root universe.
universe: ty::UniverseIndex::ROOT,
}.relate(&value, &value)
.unwrap()
}
}
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
self.infcx.tcx
}
fn tag(&self) -> &'static str {
"nll::subtype"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
a: &T,
b: &T,
) -> RelateResult<'tcx, T> {
debug!(
"relate_with_variance(variance={:?}, a={:?}, b={:?})",
variance, a, b
);
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
debug!(
"relate_with_variance: ambient_variance = {:?}",
self.ambient_variance
);
let r = self.relate(a, b)?;
self.ambient_variance = old_ambient_variance;
debug!("relate_with_variance: r={:?}", r);
Ok(r)
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
let a = self.infcx.shallow_resolve(a);
match a.sty {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
self.relate_var(a.into(), b.into())
}
_ => {
debug!(
"tys(a={:?}, b={:?}, variance={:?})",
a, b, self.ambient_variance
);
relate::super_relate_tys(self, a, b)
}
}
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!(
"regions(a={:?}, b={:?}, variance={:?})",
a, b, self.ambient_variance
);
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
debug!("regions: v_a = {:?}", v_a);
debug!("regions: v_b = {:?}", v_b);
if self.ambient_covariance() {
// Covariance: a <= b. Hence, `b: a`.
self.push_outlives(v_b, v_a);
}
if self.ambient_contravariance() {
// Contravariant: b <= a. Hence, `a: b`.
self.push_outlives(v_a, v_b);
}
Ok(a)
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
b: &ty::Binder<T>,
) -> RelateResult<'tcx, ty::Binder<T>>
where
T: Relate<'tcx>,
{
// We want that
//
// ```
// for<'a> fn(&'a u32) -> &'a u32 <:
// fn(&'b u32) -> &'b u32
// ```
//
// but not
//
// ```
// fn(&'a u32) -> &'a u32 <:
// for<'b> fn(&'b u32) -> &'b u32
// ```
//
// We therefore proceed as follows:
//
// - Instantiate binders on `b` universally, yielding a universe U1.
// - Instantiate binders on `a` existentially in U1.
debug!(
"binders({:?}: {:?}, ambient_variance={:?})",
a, b, self.ambient_variance
);
if self.ambient_covariance() {
// Covariance, so we want `for<..> A <: for<..> B` --
// therefore we compare any instantiation of A (i.e., A
// instantiated with existentials) against every
// instantiation of B (i.e., B instantiated with
// universals).
let b_scope = self.create_scope(b, UniversallyQuantified(true));
let a_scope = self.create_scope(a, UniversallyQuantified(false));
debug!("binders: a_scope = {:?} (existential)", a_scope);
debug!("binders: b_scope = {:?} (universal)", b_scope);
self.b_scopes.push(b_scope);
self.a_scopes.push(a_scope);
// Reset the ambient variance to covariant. This is needed
// to correctly handle cases like
//
// for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
//
// Somewhat surprisingly, these two types are actually
// **equal**, even though the one on the right looks more
// polymorphic. The reason is due to subtyping. To see it,
// consider that each function can call the other:
//
// - The left function can call the right with `'b` and
// `'c` both equal to `'a`
//
// - The right function can call the left with `'a` set to
// `{P}`, where P is the point in the CFG where the call
// itself occurs. Note that `'b` and `'c` must both
// include P. At the point, the call works because of
// subtyping (i.e., `&'b u32 <: &{P} u32`).
let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
self.relate(a.skip_binder(), b.skip_binder())?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
if self.ambient_contravariance() {
// Contravariance, so we want `for<..> A :> for<..> B`
// -- therefore we compare every instantiation of A (i.e.,
// A instantiated with universals) against any
// instantiation of B (i.e., B instantiated with
// existentials). Opposite of above.
let a_scope = self.create_scope(a, UniversallyQuantified(true));
let b_scope = self.create_scope(b, UniversallyQuantified(false));
debug!("binders: a_scope = {:?} (universal)", a_scope);
debug!("binders: b_scope = {:?} (existential)", b_scope);
self.a_scopes.push(a_scope);
self.b_scopes.push(b_scope);
// Reset ambient variance to contravariance. See the
// covariant case above for an explanation.
let variance =
::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
self.relate(a.skip_binder(), b.skip_binder())?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
Ok(a.clone())
}
}
/// When we encounter a binder like `for<..> fn(..)`, we actually have
/// to walk the `fn` value to find all the values bound by the `for`
/// (these are not explicitly present in the ty representation right
/// now). This visitor handles that: it descends the type, tracking
/// binder depth, and finds late-bound regions targeting the
/// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`.
struct ScopeInstantiator<'me, 'tcx: 'me> {
next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
// The debruijn index of the scope we are instantiating.
target_index: ty::DebruijnIndex,
bound_region_scope: &'me mut BoundRegionScope<'tcx>,
}
impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
self.target_index.shift_in(1);
t.super_visit_with(self);
self.target_index.shift_out(1);
false
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
let ScopeInstantiator {
bound_region_scope,
next_region,
..
} = self;
match r {
ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
bound_region_scope
.map
.entry(*br)
.or_insert_with(|| next_region(*br));
}
_ => {}
}
false
}
}
/// The "type generalize" is used when handling inference variables.
///
/// The basic strategy for handling a constraint like `?A <: B` is to
/// apply a "generalization strategy" to the type `B` -- this replaces
/// all the lifetimes in the type `B` with fresh inference
/// variables. (You can read more about the strategy in this [blog
/// post].)
///
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
/// establishes `'0: 'x` as a constraint.
///
/// As a side-effect of this generalization procedure, we also replace
/// all the bound regions that we have traversed with concrete values,
/// so that the resulting generalized type is independent from the
/// scopes.
///
/// [blog post]: https://is.gd/0hKvIr
struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
where
D: TypeRelatingDelegate<'tcx> + 'me,
{
tcx: TyCtxt<'me, 'gcx, 'tcx>,
delegate: &'me mut D,
/// After we generalize this type, we are going to relative it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
first_free_index: ty::DebruijnIndex,
universe: ty::UniverseIndex,
}
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
self.tcx
}
fn tag(&self) -> &'static str {
"nll::generalizer"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
a: &T,
b: &T,
) -> RelateResult<'tcx, T> {
debug!(
"TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
variance, a, b
);
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
debug!(
"TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
self.ambient_variance
);
let r = self.relate(a, b)?;
self.ambient_variance = old_ambient_variance;
debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
Ok(r)
}
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("TypeGeneralizer::tys(a={:?})", a,);
match a.sty {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
bug!(
"unexpected inference variable encountered in NLL generalization: {:?}",
a
);
}
_ => relate::super_relate_tys(self, a, a),
}
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
_: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("TypeGeneralizer::regions(a={:?})", a,);
if let ty::ReLateBound(debruijn, _) = a {
if *debruijn < self.first_free_index {
return Ok(a);
}
}
// For now, we just always create a fresh region variable to
// replace all the regions in the source type. In the main
// type checker, we special case the case where the ambient
// variance is `Invariant` and try to avoid creating a fresh
// region variable, but since this comes up so much less in
// NLL (only when users use `_` etc) it is much less
// important.
//
// As an aside, since these new variables are created in
// `self.universe` universe, this also serves to enforce the
// universe scoping rules.
//
// FIXME(#54105) -- if the ambient variance is bivariant,
// though, we may however need to check well-formedness or
// risk a problem like #41677 again.
let replacement_region_vid = self.delegate.generalize_existential(self.universe);
Ok(replacement_region_vid)
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
_: &ty::Binder<T>,
) -> RelateResult<'tcx, ty::Binder<T>>
where
T: Relate<'tcx>,
{
debug!("TypeGeneralizer::binders(a={:?})", a,);
self.first_free_index.shift_in(1);
let result = self.relate(a.skip_binder(), a.skip_binder())?;
self.first_free_index.shift_out(1);
Ok(ty::Binder::bind(result))
}
}
impl InferCtxt<'_, '_, 'tcx> {
/// A hacky sort of method used by the NLL type-relating code:
///
/// - `var` must be some unbound type variable.
/// - `value` must be a suitable type to use as its value.
///
/// `var` will then be equated with `value`. Note that this
/// sidesteps a number of important checks, such as the "occurs
/// check" that prevents cyclic types, so it is important not to
/// use this method during regular type-check.
fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) {
match (&var.sty, &value.sty) {
(&ty::Infer(ty::TyVar(vid)), _) => {
let mut type_variables = self.type_variables.borrow_mut();
// In NLL, we don't have type inference variables
// floating around, so we can do this rather imprecise
// variant of the occurs-check.
assert!(!value.has_infer_types());
type_variables.instantiate(vid, value);
}
(&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => {
let mut int_unification_table = self.int_unification_table.borrow_mut();
int_unification_table
.unify_var_value(vid, Some(ty::IntVarValue::IntType(value)))
.unwrap_or_else(|_| {
bug!("failed to unify int var `{:?}` with `{:?}`", vid, value);
});
}
(&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => {
let mut int_unification_table = self.int_unification_table.borrow_mut();
int_unification_table
.unify_var_value(vid, Some(ty::IntVarValue::UintType(value)))
.unwrap_or_else(|_| {
bug!("failed to unify int var `{:?}` with `{:?}`", vid, value);
});
}
(&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => {
let mut float_unification_table = self.float_unification_table.borrow_mut();
float_unification_table
.unify_var_value(vid, Some(ty::FloatVarValue(value)))
.unwrap_or_else(|_| {
bug!("failed to unify float var `{:?}` with `{:?}`", vid, value)
});
}
_ => {
bug!(
"force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}",
var,
value,
);
}
}
}
}

View File

@ -37,7 +37,7 @@ use syntax::ast::{self, Name};
use syntax::symbol::InternedString;
use syntax_pos::{Span, DUMMY_SP};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::subst::{Subst, Substs};
use ty::subst::{CanonicalUserSubsts, Subst, Substs};
use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt};
use util::ppaux;
@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> {
/// e.g. via `let x: T`, then we carry that type here. The MIR
/// borrow checker needs this information since it can affect
/// region inference.
pub user_ty: Option<(CanonicalTy<'tcx>, Span)>,
pub user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
/// Name of the local, used in debuginfo and pretty-printing.
///
@ -1737,7 +1737,7 @@ pub enum StatementKind<'tcx> {
/// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect
AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
AscribeUserType(Place<'tcx>, ty::Variance, UserTypeAnnotation<'tcx>),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
@ -2188,7 +2188,7 @@ pub enum AggregateKind<'tcx> {
&'tcx AdtDef,
usize,
&'tcx Substs<'tcx>,
Option<CanonicalTy<'tcx>>,
Option<UserTypeAnnotation<'tcx>>,
Option<usize>,
),
@ -2392,7 +2392,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
/// this does not necessarily mean that they are "==" in Rust -- in
/// particular one must be wary of `NaN`!
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct Constant<'tcx> {
pub span: Span,
pub ty: Ty<'tcx>,
@ -2402,11 +2402,29 @@ pub struct Constant<'tcx> {
/// indicate that `Vec<_>` was explicitly specified.
///
/// Needed for NLL to impose user-given type constraints.
pub user_ty: Option<CanonicalTy<'tcx>>,
pub user_ty: Option<UserTypeAnnotation<'tcx>>,
pub literal: &'tcx ty::Const<'tcx>,
}
/// A user-given type annotation attached to a constant. These arise
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum UserTypeAnnotation<'tcx> {
Ty(CanonicalTy<'tcx>),
FnDef(DefId, CanonicalUserSubsts<'tcx>),
AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>),
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> {
(UserTypeAnnotation::Ty)(ty),
(UserTypeAnnotation::FnDef)(def, substs),
(UserTypeAnnotation::AdtDef)(def, substs),
}
}
newtype_index! {
pub struct Promoted {
DEBUG_FORMAT = "promoted[{}]"

View File

@ -10,7 +10,7 @@
use hir::def_id::DefId;
use ty::subst::Substs;
use ty::{CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty};
use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty};
use mir::*;
use syntax_pos::Span;
@ -147,9 +147,9 @@ macro_rules! make_mir_visitor {
fn visit_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
variance: & $($mutability)* ty::Variance,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
location: Location) {
self.super_ascribe_user_ty(place, variance, c_ty, location);
self.super_ascribe_user_ty(place, variance, user_ty, location);
}
fn visit_place(&mut self,
@ -214,8 +214,11 @@ macro_rules! make_mir_visitor {
self.super_ty(ty);
}
fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
self.super_canonical_ty(ty);
fn visit_user_type_annotation(
&mut self,
ty: & $($mutability)* UserTypeAnnotation<'tcx>,
) {
self.super_user_type_annotation(ty);
}
fn visit_region(&mut self,
@ -390,9 +393,9 @@ macro_rules! make_mir_visitor {
StatementKind::AscribeUserType(
ref $($mutability)* place,
ref $($mutability)* variance,
ref $($mutability)* c_ty,
ref $($mutability)* user_ty,
) => {
self.visit_ascribe_user_ty(place, variance, c_ty, location);
self.visit_ascribe_user_ty(place, variance, user_ty, location);
}
StatementKind::Nop => {}
}
@ -637,10 +640,10 @@ macro_rules! make_mir_visitor {
fn super_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
_variance: & $($mutability)* ty::Variance,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
user_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);
self.visit_user_ty(c_ty);
self.visit_user_type_annotation(user_ty);
}
fn super_place(&mut self,
@ -736,7 +739,7 @@ macro_rules! make_mir_visitor {
source_info: *source_info,
});
if let Some((user_ty, _)) = user_ty {
self.visit_user_ty(user_ty);
self.visit_user_type_annotation(user_ty);
}
self.visit_source_info(source_info);
self.visit_source_scope(visibility_scope);
@ -783,7 +786,10 @@ macro_rules! make_mir_visitor {
self.visit_source_scope(scope);
}
fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) {
fn super_user_type_annotation(
&mut self,
_ty: & $($mutability)* UserTypeAnnotation<'tcx>,
) {
}
fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {

View File

@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{self, Mir, interpret};
use mir::interpret::Allocation;
use ty::subst::{CanonicalSubsts, Kind, Substs, Subst};
use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst};
use ty::ReprOptions;
use traits;
use traits::{Clause, Clauses, GoalKind, Goal, Goals};
@ -383,7 +383,7 @@ pub struct TypeckTables<'tcx> {
/// If the user wrote `foo.collect::<Vec<_>>()`, then the
/// canonical substitutions would include only `for<X> { Vec<X>
/// }`.
user_substs: ItemLocalMap<CanonicalSubsts<'tcx>>,
user_substs: ItemLocalMap<CanonicalUserSubsts<'tcx>>,
adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
@ -573,14 +573,14 @@ impl<'tcx> TypeckTables<'tcx> {
self.node_substs.get(&id.local_id).cloned()
}
pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalSubsts<'tcx>> {
pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> {
LocalTableInContextMut {
local_id_root: self.local_id_root,
data: &mut self.user_substs
}
}
pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalSubsts<'tcx>> {
pub fn user_substs(&self, id: hir::HirId) -> Option<CanonicalUserSubsts<'tcx>> {
validate_hir_id_for_typeck_tables(self.local_id_root, id, false);
self.user_substs.get(&id.local_id).cloned()
}

View File

@ -323,33 +323,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
}
}
pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>;
impl<'gcx> CanonicalSubsts<'gcx> {
/// True if this represents a substitution like
///
/// ```text
/// [?0, ?1, ?2]
/// ```
///
/// i.e., each thing is mapped to a canonical variable with the same index.
pub fn is_identity(&self) -> bool {
self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
match kind.unpack() {
UnpackedKind::Type(ty) => match ty.sty {
ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
_ => false,
},
UnpackedKind::Lifetime(r) => match r {
ty::ReCanonical(cvar1) => cvar == *cvar1,
_ => false,
},
}
})
}
}
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
///////////////////////////////////////////////////////////////////////////
@ -564,3 +537,98 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
}
}
pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
impl CanonicalUserSubsts<'tcx> {
/// True if this represents a substitution like
///
/// ```text
/// [?0, ?1, ?2]
/// ```
///
/// i.e., each thing is mapped to a canonical variable with the same index.
pub fn is_identity(&self) -> bool {
if self.value.user_self_ty.is_some() {
return false;
}
self.value.substs.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| {
match kind.unpack() {
UnpackedKind::Type(ty) => match ty.sty {
ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1,
_ => false,
},
UnpackedKind::Lifetime(r) => match r {
ty::ReCanonical(cvar1) => cvar == *cvar1,
_ => false,
},
}
})
}
}
/// Stores the user-given substs to reach some fully qualified path
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UserSubsts<'tcx> {
/// The substitutions for the item as given by the user.
pub substs: &'tcx Substs<'tcx>,
/// The self-type, in the case of a `<T>::Item` path (when applied
/// to an inherent impl). See `UserSelfTy` below.
pub user_self_ty: Option<UserSelfTy<'tcx>>,
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserSubsts<'tcx> {
substs,
user_self_ty,
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for UserSubsts<'a> {
type Lifted = UserSubsts<'tcx>;
substs,
user_self_ty,
}
}
/// Specifies the user-given self-type. In the case of a path that
/// refers to a member in an inherent impl, this self-type is
/// sometimes needed to constrain the type parameters on the impl. For
/// example, in this code:
///
/// ```
/// struct Foo<T> { }
/// impl<A> Foo<A> { fn method() { } }
/// ```
///
/// when you then have a path like `<Foo<&'static u32>>::method`,
/// this struct would carry the def-id of the impl along with the
/// self-type `Foo<u32>`. Then we can instantiate the parameters of
/// the impl (with the substs from `UserSubsts`) and apply those to
/// the self-type, giving `Foo<?A>`. Finally, we unify that with
/// the self-type here, which contains `?A` to be `&'static u32`
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct UserSelfTy<'tcx> {
pub impl_def_id: DefId,
pub self_ty: Ty<'tcx>,
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for UserSelfTy<'tcx> {
impl_def_id,
self_ty,
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for UserSelfTy<'a> {
type Lifted = UserSelfTy<'tcx>;
impl_def_id,
self_ty,
}
}

View File

@ -18,9 +18,10 @@ use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue};
use rustc::mir::{Statement, Terminator};
use rustc::mir::UserTypeAnnotation;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid};
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid};
pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
@ -179,7 +180,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
_c_ty: &CanonicalTy<'tcx>,
_user_ty: &UserTypeAnnotation<'tcx>,
_location: Location,
) {
}

View File

@ -9,8 +9,8 @@
// except according to those terms.
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind, UserTypeAnnotation};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
@ -65,12 +65,12 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
debug!("visit_ty: ty={:?}", ty);
}
fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
// `user_ty` annotations represent the types that the user
fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) {
// User type annotations represent the types that the user
// wrote in the progarm. We don't want to erase the regions
// from these types: rather, we want to add them as
// constraints at type-check time.
debug!("visit_user_ty: skipping renumber");
debug!("visit_user_type_annotation: skipping renumber");
}
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {

View File

@ -43,7 +43,7 @@ use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{ObligationCause, PredicateObligations};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, UnpackedKind};
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
use std::rc::Rc;
use std::{fmt, iter};
use syntax_pos::{Span, DUMMY_SP};
@ -966,7 +966,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: CanonicalTy<'tcx>,
b: UserTypeAnnotation<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
@ -1837,7 +1837,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
/// If this rvalue supports a user-given type annotation, then
/// extract and return it. This represents the final type of the
/// rvalue and will be unified with the inferred type.
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotation<'tcx>> {
match rvalue {
Rvalue::Use(_)
| Rvalue::Repeat(..)

View File

@ -10,16 +10,14 @@
use borrow_check::nll::constraints::OutlivesConstraint;
use borrow_check::nll::type_check::{BorrowCheckContext, Locations};
use rustc::infer::canonical::{Canonical, CanonicalVarInfos, CanonicalVarValues};
use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc::mir::ConstraintCategory;
use rustc::mir::{ConstraintCategory, UserTypeAnnotation};
use rustc::traits::query::Fallible;
use rustc::ty::fold::{TypeFoldable, TypeVisitor};
use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc::ty::subst::Kind;
use rustc::ty::{self, CanonicalTy, CanonicalVar, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::relate::TypeRelation;
use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts};
use rustc::ty::{self, Ty, TypeFoldable};
use syntax_pos::DUMMY_SP;
/// Adds sufficient constraints to ensure that `a <: b`.
pub(super) fn sub_types<'tcx>(
@ -32,10 +30,9 @@ pub(super) fn sub_types<'tcx>(
) -> Fallible<()> {
debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
TypeRelating::new(
infcx.tcx,
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
ty::Variance::Covariant,
ty::List::empty(),
).relate(&a, &b)?;
Ok(())
}
@ -51,10 +48,9 @@ pub(super) fn eq_types<'tcx>(
) -> Fallible<()> {
debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations);
TypeRelating::new(
infcx.tcx,
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
ty::Variance::Invariant,
ty::List::empty(),
).relate(&a, &b)?;
Ok(())
}
@ -66,19 +62,15 @@ pub(super) fn relate_type_and_user_type<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
b: CanonicalTy<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
locations: Locations,
category: ConstraintCategory,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<Ty<'tcx>> {
debug!(
"sub_type_and_user_type(a={:?}, b={:?}, locations={:?})",
a, b, locations
"relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})",
a, v, user_ty, locations
);
let Canonical {
variables: b_variables,
value: b_value,
} = b;
// The `TypeRelating` code assumes that the "canonical variables"
// appear in the "a" side, so flip `Contravariant` ambient
@ -86,108 +78,75 @@ pub(super) fn relate_type_and_user_type<'tcx>(
let v1 = ty::Contravariant.xform(v);
let mut type_relating = TypeRelating::new(
infcx.tcx,
infcx,
NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
v1,
b_variables,
);
type_relating.relate(&b_value, &a)?;
Ok(b.substitute(
infcx.tcx,
&CanonicalVarValues {
var_values: type_relating
.canonical_var_values
.into_iter()
.map(|x| x.expect("unsubstituted canonical variable"))
.collect(),
},
))
}
match user_ty {
UserTypeAnnotation::Ty(canonical_ty) => {
let (ty, _) =
infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty);
type_relating.relate(&ty, &a)?;
Ok(ty)
}
UserTypeAnnotation::FnDef(def_id, canonical_substs) => {
let (
UserSubsts {
substs,
user_self_ty,
},
_,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
let ty = infcx.tcx.mk_fn_def(def_id, substs);
struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D>
where
D: TypeRelatingDelegate<'tcx>,
{
tcx: TyCtxt<'me, 'gcx, 'tcx>,
type_relating.relate(&ty, &a)?;
/// Callback to use when we deduce an outlives relationship
delegate: D,
if let Some(UserSelfTy {
impl_def_id,
self_ty,
}) = user_self_ty
{
let impl_self_ty = infcx.tcx.type_of(impl_def_id);
let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs);
/// How are we relating `a` and `b`?
///
/// - covariant means `a <: b`
/// - contravariant means `b <: a`
/// - invariant means `a == b
/// - bivariant means that it doesn't matter
ambient_variance: ty::Variance,
// There may be type variables in `substs` and hence
// in `impl_self_ty`, but they should all have been
// resolved to some fixed value during the first call
// to `relate`, above. Therefore, if we use
// `resolve_type_vars_if_possible` we should get to
// something without type variables. This is important
// because the `b` type in `relate_with_variance`
// below is not permitted to have inference variables.
let impl_self_ty = infcx.resolve_type_vars_if_possible(&impl_self_ty);
assert!(!impl_self_ty.has_infer_types());
/// When we pass through a set of binders (e.g., when looking into
/// a `fn` type), we push a new bound region scope onto here. This
/// will contain the instantiated region for each region in those
/// binders. When we then encounter a `ReLateBound(d, br)`, we can
/// use the debruijn index `d` to find the right scope, and then
/// bound region name `br` to find the specific instantiation from
/// within that scope. See `replace_bound_region`.
///
/// This field stores the instantiations for late-bound regions in
/// the `a` type.
a_scopes: Vec<BoundRegionScope<'tcx>>,
type_relating.relate_with_variance(
ty::Variance::Invariant,
&self_ty,
&impl_self_ty,
)?;
}
/// Same as `a_scopes`, but for the `b` type.
b_scopes: Vec<BoundRegionScope<'tcx>>,
Ok(ty)
}
UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => {
let (
UserSubsts {
substs,
user_self_ty,
},
_,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs);
/// As we execute, the type on the LHS *may* come from a canonical
/// source. In that case, we will sometimes find a constraint like
/// `?0 = B`, where `B` is a type from the RHS. The first time we
/// find that, we simply record `B` (and the list of scopes that
/// tells us how to *interpret* `B`). The next time we encounter
/// `?0`, then, we can read this value out and use it.
///
/// One problem: these variables may be in some other universe,
/// how can we enforce that? I guess I could add some kind of
/// "minimum universe constraint" that we can feed to the NLL checker.
/// --> also, we know this doesn't happen
canonical_var_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>>,
}
// We don't extract adt-defs with a self-type.
assert!(user_self_ty.is_none());
trait TypeRelatingDelegate<'tcx> {
/// Push a constraint `sup: sub` -- this constraint must be
/// satisfied for the two types to be related. `sub` and `sup` may
/// be regions from the type or new variables created through the
/// delegate.
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>);
/// Creates a new universe index. Used when instantiating placeholders.
fn create_next_universe(&mut self) -> ty::UniverseIndex;
/// Creates a new region variable representing a higher-ranked
/// region that is instantiated existentially. This creates an
/// inference variable, typically.
///
/// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
/// we will invoke this method to instantiate `'a` with an
/// inference variable (though `'b` would be instantiated first,
/// as a placeholder).
fn next_existential_region_var(&mut self) -> ty::Region<'tcx>;
/// Creates a new region variable representing a
/// higher-ranked region that is instantiated universally.
/// This creates a new region placeholder, typically.
///
/// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then
/// we will invoke this method to instantiate `'b` with a
/// placeholder region.
fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>;
/// Creates a new existential region in the given universe. This
/// is used when handling subtyping and type variables -- if we
/// have that `?X <: Foo<'a>`, for example, we would instantiate
/// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh
/// existential variable created by this function. We would then
/// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives
/// relation stating that `'?0: 'a`).
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
let ty = infcx.tcx.mk_adt(adt_def, substs);
type_relating.relate(&ty, &a)?;
Ok(ty)
}
}
}
struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> {
@ -256,585 +215,3 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> {
}
}
}
#[derive(Clone, Debug)]
struct ScopesAndKind<'tcx> {
scopes: Vec<BoundRegionScope<'tcx>>,
kind: Kind<'tcx>,
}
#[derive(Clone, Debug, Default)]
struct BoundRegionScope<'tcx> {
map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
}
#[derive(Copy, Clone)]
struct UniversallyQuantified(bool);
impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
fn new(
tcx: TyCtxt<'me, 'gcx, 'tcx>,
delegate: D,
ambient_variance: ty::Variance,
canonical_var_infos: CanonicalVarInfos<'tcx>,
) -> Self {
let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len());
Self {
tcx,
delegate,
ambient_variance,
canonical_var_values,
a_scopes: vec![],
b_scopes: vec![],
}
}
fn ambient_covariance(&self) -> bool {
match self.ambient_variance {
ty::Variance::Covariant | ty::Variance::Invariant => true,
ty::Variance::Contravariant | ty::Variance::Bivariant => false,
}
}
fn ambient_contravariance(&self) -> bool {
match self.ambient_variance {
ty::Variance::Contravariant | ty::Variance::Invariant => true,
ty::Variance::Covariant | ty::Variance::Bivariant => false,
}
}
fn create_scope(
&mut self,
value: &ty::Binder<impl TypeFoldable<'tcx>>,
universally_quantified: UniversallyQuantified,
) -> BoundRegionScope<'tcx> {
let mut scope = BoundRegionScope::default();
// Create a callback that creates (via the delegate) either an
// existential or placeholder region as needed.
let mut next_region = {
let delegate = &mut self.delegate;
let mut lazy_universe = None;
move |br: ty::BoundRegion| {
if universally_quantified.0 {
// The first time this closure is called, create a
// new universe for the placeholders we will make
// from here out.
let universe = lazy_universe.unwrap_or_else(|| {
let universe = delegate.create_next_universe();
lazy_universe = Some(universe);
universe
});
let placeholder = ty::Placeholder { universe, name: br };
delegate.next_placeholder_region(placeholder)
} else {
delegate.next_existential_region_var()
}
}
};
value.skip_binder().visit_with(&mut ScopeInstantiator {
next_region: &mut next_region,
target_index: ty::INNERMOST,
bound_region_scope: &mut scope,
});
scope
}
/// When we encounter binders during the type traversal, we record
/// the value to substitute for each of the things contained in
/// that binder. (This will be either a universal placeholder or
/// an existential inference variable.) Given the debruijn index
/// `debruijn` (and name `br`) of some binder we have now
/// encountered, this routine finds the value that we instantiated
/// the region with; to do so, it indexes backwards into the list
/// of ambient scopes `scopes`.
fn lookup_bound_region(
debruijn: ty::DebruijnIndex,
br: &ty::BoundRegion,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
// The debruijn index is a "reverse index" into the
// scopes listing. So when we have INNERMOST (0), we
// want the *last* scope pushed, and so forth.
let debruijn_index = debruijn.index() - first_free_index.index();
let scope = &scopes[scopes.len() - debruijn_index - 1];
// Find this bound region in that scope to map to a
// particular region.
scope.map[br]
}
/// If `r` is a bound region, find the scope in which it is bound
/// (from `scopes`) and return the value that we instantiated it
/// with. Otherwise just return `r`.
fn replace_bound_region(
&self,
r: ty::Region<'tcx>,
first_free_index: ty::DebruijnIndex,
scopes: &[BoundRegionScope<'tcx>],
) -> ty::Region<'tcx> {
if let ty::ReLateBound(debruijn, br) = r {
Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
} else {
r
}
}
/// Push a new outlives requirement into our output set of
/// constraints.
fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) {
debug!("push_outlives({:?}: {:?})", sup, sub);
self.delegate.push_outlives(sup, sub);
}
/// When we encounter a canonical variable `var` in the output,
/// equate it with `kind`. If the variable has been previously
/// equated, then equate it again.
fn relate_var(
&mut self,
var: CanonicalVar,
b_kind: Kind<'tcx>,
) -> RelateResult<'tcx, Kind<'tcx>> {
debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind);
let generalized_kind = match self.canonical_var_values[var] {
Some(v) => v,
None => {
let generalized_kind = self.generalize_value(b_kind);
self.canonical_var_values[var] = Some(generalized_kind);
generalized_kind
}
};
// The generalized values we extract from `canonical_var_values` have
// been fully instantiated and hence the set of scopes we have
// doesn't matter -- just to be sure, put an empty vector
// in there.
let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]);
// Relate the generalized kind to the original one.
let result = self.relate(&generalized_kind, &b_kind);
// Restore the old scopes now.
self.a_scopes = old_a_scopes;
debug!("equate_var: complete, result = {:?}", result);
return result;
}
fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> {
TypeGeneralizer {
tcx: self.tcx,
delegate: &mut self.delegate,
first_free_index: ty::INNERMOST,
ambient_variance: self.ambient_variance,
// These always correspond to an `_` or `'_` written by
// user, and those are always in the root universe.
universe: ty::UniverseIndex::ROOT,
}.relate(&kind, &kind)
.unwrap()
}
}
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
self.tcx
}
fn tag(&self) -> &'static str {
"nll::subtype"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
a: &T,
b: &T,
) -> RelateResult<'tcx, T> {
debug!(
"relate_with_variance(variance={:?}, a={:?}, b={:?})",
variance, a, b
);
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
debug!(
"relate_with_variance: ambient_variance = {:?}",
self.ambient_variance
);
let r = self.relate(a, b)?;
self.ambient_variance = old_ambient_variance;
debug!("relate_with_variance: r={:?}", r);
Ok(r)
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
// Watch out for the case that we are matching a `?T` against the
// right-hand side.
if let ty::Infer(ty::CanonicalTy(var)) = a.sty {
self.relate_var(var, b.into())?;
Ok(a)
} else {
debug!(
"tys(a={:?}, b={:?}, variance={:?})",
a, b, self.ambient_variance
);
relate::super_relate_tys(self, a, b)
}
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
if let ty::ReCanonical(var) = a {
self.relate_var(*var, b.into())?;
return Ok(a);
}
debug!(
"regions(a={:?}, b={:?}, variance={:?})",
a, b, self.ambient_variance
);
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
debug!("regions: v_a = {:?}", v_a);
debug!("regions: v_b = {:?}", v_b);
if self.ambient_covariance() {
// Covariance: a <= b. Hence, `b: a`.
self.push_outlives(v_b, v_a);
}
if self.ambient_contravariance() {
// Contravariant: b <= a. Hence, `a: b`.
self.push_outlives(v_a, v_b);
}
Ok(a)
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
b: &ty::Binder<T>,
) -> RelateResult<'tcx, ty::Binder<T>>
where
T: Relate<'tcx>,
{
// We want that
//
// ```
// for<'a> fn(&'a u32) -> &'a u32 <:
// fn(&'b u32) -> &'b u32
// ```
//
// but not
//
// ```
// fn(&'a u32) -> &'a u32 <:
// for<'b> fn(&'b u32) -> &'b u32
// ```
//
// We therefore proceed as follows:
//
// - Instantiate binders on `b` universally, yielding a universe U1.
// - Instantiate binders on `a` existentially in U1.
debug!(
"binders({:?}: {:?}, ambient_variance={:?})",
a, b, self.ambient_variance
);
if self.ambient_covariance() {
// Covariance, so we want `for<..> A <: for<..> B` --
// therefore we compare any instantiation of A (i.e., A
// instantiated with existentials) against every
// instantiation of B (i.e., B instantiated with
// universals).
let b_scope = self.create_scope(b, UniversallyQuantified(true));
let a_scope = self.create_scope(a, UniversallyQuantified(false));
debug!("binders: a_scope = {:?} (existential)", a_scope);
debug!("binders: b_scope = {:?} (universal)", b_scope);
self.b_scopes.push(b_scope);
self.a_scopes.push(a_scope);
// Reset the ambient variance to covariant. This is needed
// to correctly handle cases like
//
// for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32)
//
// Somewhat surprisingly, these two types are actually
// **equal**, even though the one on the right looks more
// polymorphic. The reason is due to subtyping. To see it,
// consider that each function can call the other:
//
// - The left function can call the right with `'b` and
// `'c` both equal to `'a`
//
// - The right function can call the left with `'a` set to
// `{P}`, where P is the point in the CFG where the call
// itself occurs. Note that `'b` and `'c` must both
// include P. At the point, the call works because of
// subtyping (i.e., `&'b u32 <: &{P} u32`).
let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
self.relate(a.skip_binder(), b.skip_binder())?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
if self.ambient_contravariance() {
// Contravariance, so we want `for<..> A :> for<..> B`
// -- therefore we compare every instantiation of A (i.e.,
// A instantiated with universals) against any
// instantiation of B (i.e., B instantiated with
// existentials). Opposite of above.
let a_scope = self.create_scope(a, UniversallyQuantified(true));
let b_scope = self.create_scope(b, UniversallyQuantified(false));
debug!("binders: a_scope = {:?} (universal)", a_scope);
debug!("binders: b_scope = {:?} (existential)", b_scope);
self.a_scopes.push(a_scope);
self.b_scopes.push(b_scope);
// Reset ambient variance to contravariance. See the
// covariant case above for an explanation.
let variance =
::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
self.relate(a.skip_binder(), b.skip_binder())?;
self.ambient_variance = variance;
self.b_scopes.pop().unwrap();
self.a_scopes.pop().unwrap();
}
Ok(a.clone())
}
}
/// When we encounter a binder like `for<..> fn(..)`, we actually have
/// to walk the `fn` value to find all the values bound by the `for`
/// (these are not explicitly present in the ty representation right
/// now). This visitor handles that: it descends the type, tracking
/// binder depth, and finds late-bound regions targeting the
/// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`.
struct ScopeInstantiator<'me, 'tcx: 'me> {
next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
// The debruijn index of the scope we are instantiating.
target_index: ty::DebruijnIndex,
bound_region_scope: &'me mut BoundRegionScope<'tcx>,
}
impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
self.target_index.shift_in(1);
t.super_visit_with(self);
self.target_index.shift_out(1);
false
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
let ScopeInstantiator {
bound_region_scope,
next_region,
..
} = self;
match r {
ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
bound_region_scope
.map
.entry(*br)
.or_insert_with(|| next_region(*br));
}
_ => {}
}
false
}
}
/// The "type generalize" is used when handling inference variables.
///
/// The basic strategy for handling a constraint like `?A <: B` is to
/// apply a "generalization strategy" to the type `B` -- this replaces
/// all the lifetimes in the type `B` with fresh inference
/// variables. (You can read more about the strategy in this [blog
/// post].)
///
/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
/// establishes `'0: 'x` as a constraint.
///
/// As a side-effect of this generalization procedure, we also replace
/// all the bound regions that we have traversed with concrete values,
/// so that the resulting generalized type is independent from the
/// scopes.
///
/// [blog post]: https://is.gd/0hKvIr
struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D>
where
D: TypeRelatingDelegate<'tcx> + 'me,
{
tcx: TyCtxt<'me, 'gcx, 'tcx>,
delegate: &'me mut D,
/// After we generalize this type, we are going to relative it to
/// some other type. What will be the variance at this point?
ambient_variance: ty::Variance,
first_free_index: ty::DebruijnIndex,
universe: ty::UniverseIndex,
}
impl<D> TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D>
where
D: TypeRelatingDelegate<'tcx>,
{
fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> {
self.tcx
}
fn tag(&self) -> &'static str {
"nll::generalizer"
}
fn a_is_expected(&self) -> bool {
true
}
fn relate_with_variance<T: Relate<'tcx>>(
&mut self,
variance: ty::Variance,
a: &T,
b: &T,
) -> RelateResult<'tcx, T> {
debug!(
"TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
variance, a, b
);
let old_ambient_variance = self.ambient_variance;
self.ambient_variance = self.ambient_variance.xform(variance);
debug!(
"TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
self.ambient_variance
);
let r = self.relate(a, b)?;
self.ambient_variance = old_ambient_variance;
debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
Ok(r)
}
fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("TypeGeneralizer::tys(a={:?})", a,);
match a.sty {
ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => {
bug!(
"unexpected inference variable encountered in NLL generalization: {:?}",
a
);
}
_ => relate::super_relate_tys(self, a, a),
}
}
fn regions(
&mut self,
a: ty::Region<'tcx>,
_: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("TypeGeneralizer::regions(a={:?})", a,);
if let ty::ReLateBound(debruijn, _) = a {
if *debruijn < self.first_free_index {
return Ok(a);
}
}
// For now, we just always create a fresh region variable to
// replace all the regions in the source type. In the main
// type checker, we special case the case where the ambient
// variance is `Invariant` and try to avoid creating a fresh
// region variable, but since this comes up so much less in
// NLL (only when users use `_` etc) it is much less
// important.
//
// As an aside, since these new variables are created in
// `self.universe` universe, this also serves to enforce the
// universe scoping rules.
//
// FIXME(#54105) -- if the ambient variance is bivariant,
// though, we may however need to check well-formedness or
// risk a problem like #41677 again.
let replacement_region_vid = self.delegate.generalize_existential(self.universe);
Ok(replacement_region_vid)
}
fn binders<T>(
&mut self,
a: &ty::Binder<T>,
_: &ty::Binder<T>,
) -> RelateResult<'tcx, ty::Binder<T>>
where
T: Relate<'tcx>,
{
debug!("TypeGeneralizer::binders(a={:?})", a,);
self.first_free_index.shift_in(1);
let result = self.relate(a.skip_binder(), a.skip_binder())?;
self.first_free_index.shift_out(1);
Ok(ty::Binder::bind(result))
}
}

View File

@ -20,7 +20,7 @@ use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
use hair::*;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, CanonicalTy, Ty};
use rustc::ty::{self, Ty};
use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::{Name, NodeId};
@ -491,7 +491,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn visit_bindings(
&mut self,
pattern: &Pattern<'tcx>,
mut pattern_user_ty: Option<(CanonicalTy<'tcx>, Span)>,
mut pattern_user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
f: &mut impl FnMut(
&mut Self,
Mutability,
@ -500,7 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
NodeId,
Span,
Ty<'tcx>,
Option<(CanonicalTy<'tcx>, Span)>,
Option<(UserTypeAnnotation<'tcx>, Span)>,
),
) {
match *pattern.kind {
@ -626,7 +626,7 @@ struct Binding<'tcx> {
struct Ascription<'tcx> {
span: Span,
source: Place<'tcx>,
user_ty: CanonicalTy<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
}
#[derive(Clone, Debug)]
@ -1470,7 +1470,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
num_patterns: usize,
var_id: NodeId,
var_ty: Ty<'tcx>,
user_var_ty: Option<(CanonicalTy<'tcx>, Span)>,
user_var_ty: Option<(UserTypeAnnotation<'tcx>, Span)>,
has_guard: ArmHasGuard,
opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
pat_span: Span,

View File

@ -86,12 +86,12 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let mut pattern = cx.pattern_from_hir(&local.pat);
if let Some(ty) = &local.ty {
if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
if let Some(&user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) {
pattern = Pattern {
ty: pattern.ty,
span: pattern.span,
kind: Box::new(PatternKind::AscribeUserType {
user_ty: *user_ty,
user_ty: UserTypeAnnotation::Ty(user_ty),
user_ty_span: ty.span,
subpattern: pattern
})

View File

@ -295,13 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let substs = cx.tables().node_substs(fun.hir_id);
let user_ty = cx.tables().user_substs(fun.hir_id)
.map(|user_substs| {
user_substs.unchecked_map(|user_substs| {
// Here, we just pair an `AdtDef` with the
// `user_substs`, so no new types etc are introduced.
cx.tcx().mk_adt(adt_def, user_substs)
})
});
.map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs));
let field_refs = args.iter()
.enumerate()
@ -725,9 +719,15 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
hir::ExprKind::Type(ref source, ref ty) => {
let user_provided_tys = cx.tables.user_provided_tys();
let user_ty = *user_provided_tys
.get(ty.hir_id)
.expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source));
let user_ty = UserTypeAnnotation::Ty(
*user_provided_tys
.get(ty.hir_id)
.expect(&format!(
"{:?} not found in user_provided_tys, source: {:?}",
ty,
source,
))
);
if source.is_place_expr() {
ExprKind::PlaceTypeAscription {
source: source.to_ref(),
@ -759,11 +759,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
}
}
fn user_annotated_ty_for_def(
fn user_substs_applied_to_def(
cx: &mut Cx<'a, 'gcx, 'tcx>,
hir_id: hir::HirId,
def: &Def,
) -> Option<CanonicalTy<'tcx>> {
) -> Option<UserTypeAnnotation<'tcx>> {
match def {
// A reference to something callable -- e.g., a fn, method, or
// a tuple-struct or tuple-variant. This has the type of a
@ -772,11 +772,7 @@ fn user_annotated_ty_for_def(
Def::Method(_) |
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) =>
Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
// Here, we just pair a `DefId` with the
// `user_substs`, so no new types etc are introduced.
cx.tcx().mk_fn_def(def.def_id(), user_substs)
})),
Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)),
Def::Const(_def_id) |
Def::AssociatedConst(_def_id) =>
@ -795,7 +791,7 @@ fn user_annotated_ty_for_def(
cx.user_substs_applied_to_ty_of_hir_id(hir_id),
_ =>
bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id)
}
}
@ -815,7 +811,7 @@ fn method_callee<'a, 'gcx, 'tcx>(
.unwrap_or_else(|| {
span_bug!(expr.span, "no type-dependent def for method callee")
});
let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, def);
let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def);
(def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty)
}
};
@ -882,7 +878,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) |
Def::SelfCtor(..) => {
let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def);
let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def);
ExprKind::Literal {
literal: ty::Const::zero_sized(
cx.tcx,

View File

@ -14,11 +14,11 @@
//! unit-tested and separated from the Rust source and compiler data
//! structures.
use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp};
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::ty::subst::Substs;
use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const};
use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const};
use rustc::hir;
use syntax::ast;
use syntax_pos::Span;
@ -268,7 +268,7 @@ pub enum ExprKind<'tcx> {
/// Optional user-given substs: for something like `let x =
/// Bar::<T> { ... }`.
user_ty: Option<CanonicalTy<'tcx>>,
user_ty: Option<UserTypeAnnotation<'tcx>>,
fields: Vec<FieldExprRef<'tcx>>,
base: Option<FruInfo<'tcx>>
@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> {
PlaceTypeAscription {
source: ExprRef<'tcx>,
/// Type that the user gave to this expression
user_ty: CanonicalTy<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
},
ValueTypeAscription {
source: ExprRef<'tcx>,
/// Type that the user gave to this expression
user_ty: CanonicalTy<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
},
Closure {
closure_id: DefId,
@ -291,13 +291,7 @@ pub enum ExprKind<'tcx> {
},
Literal {
literal: &'tcx Const<'tcx>,
/// Optional user-given type: for something like
/// `collect::<Vec<_>>`, this would be present and would
/// indicate that `Vec<_>` was explicitly specified.
///
/// Needed for NLL to impose user-given type constraints.
user_ty: Option<CanonicalTy<'tcx>>,
user_ty: Option<UserTypeAnnotation<'tcx>>,
},
InlineAsm {
asm: &'tcx hir::InlineAsm,

View File

@ -20,9 +20,9 @@ use const_eval::{const_field, const_variant_index};
use hair::util::UserAnnotatedTyHelpers;
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability, UserTypeAnnotation};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
use rustc::hir::def::{Def, CtorKind};
@ -69,7 +69,7 @@ pub enum PatternKind<'tcx> {
Wild,
AscribeUserType {
user_ty: CanonicalTy<'tcx>,
user_ty: UserTypeAnnotation<'tcx>,
subpattern: Pattern<'tcx>,
user_ty_span: Span,
},
@ -980,7 +980,7 @@ macro_rules! CloneImpls {
CloneImpls!{ <'tcx>
Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>,
Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx>
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>
}
impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> {

View File

@ -9,7 +9,8 @@
// except according to those terms.
use rustc::hir;
use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};
use rustc::mir::UserTypeAnnotation;
use rustc::ty::{self, AdtDef, TyCtxt};
crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
@ -20,32 +21,22 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
&self,
hir_id: hir::HirId,
adt_def: &'tcx AdtDef,
) -> Option<CanonicalTy<'tcx>> {
) -> Option<UserTypeAnnotation<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
Some(user_substs.unchecked_map(|user_substs| {
// Here, we just pair an `AdtDef` with the
// `user_substs`, so no new types etc are introduced.
self.tcx().mk_adt(adt_def, user_substs)
}))
Some(UserTypeAnnotation::AdtDef(adt_def, user_substs))
}
/// Looks up the type associated with this hir-id and applies the
/// user-given substitutions; the hir-id must map to a suitable
/// type.
fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option<CanonicalTy<'tcx>> {
fn user_substs_applied_to_ty_of_hir_id(
&self,
hir_id: hir::HirId,
) -> Option<UserTypeAnnotation<'tcx>> {
let user_substs = self.tables().user_substs(hir_id)?;
match &self.tables().node_id_to_type(hir_id).sty {
ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| {
// Ok to call `unchecked_map` because we just pair an
// `AdtDef` with the `user_substs`, so no new types
// etc are introduced.
self.tcx().mk_adt(adt_def, user_substs)
})),
ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
// Here, we just pair a `DefId` with the
// `user_substs`, so no new types etc are introduced.
self.tcx().mk_fn_def(*def_id, user_substs)
})),
ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)),
ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)),
sty => bug!(
"sty: {:?} should not have user-substs {:?} recorded ",
sty,

View File

@ -95,7 +95,8 @@ use rustc::infer::opaque_types::OpaqueTypeDecl;
use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region;
use rustc::mir::interpret::{ConstValue, GlobalId};
use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs};
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
UserSelfTy, UserSubsts};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
@ -2136,7 +2137,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
method.substs[i]
}
});
self.infcx.canonicalize_response(&just_method_substs)
self.infcx.canonicalize_response(&UserSubsts {
substs: just_method_substs,
user_self_ty: None, // not relevant here
})
});
debug!("write_method_call: user_substs = {:?}", user_substs);
@ -2163,7 +2167,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// This should be invoked **before any unifications have
/// occurred**, so that annotations like `Vec<_>` are preserved
/// properly.
pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
pub fn write_user_substs_from_substs(
&self,
hir_id: hir::HirId,
substs: &'tcx Substs<'tcx>,
user_self_ty: Option<UserSelfTy<'tcx>>,
) {
debug!(
"write_user_substs_from_substs({:?}, {:?}) in fcx {}",
hir_id,
@ -2172,13 +2181,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
);
if !substs.is_noop() {
let user_substs = self.infcx.canonicalize_response(&substs);
let user_substs = self.infcx.canonicalize_response(&UserSubsts {
substs,
user_self_ty,
});
debug!("instantiate_value_path: user_substs = {:?}", user_substs);
self.write_user_substs(hir_id, user_substs);
}
}
pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalSubsts<'tcx>) {
pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) {
debug!(
"write_user_substs({:?}, {:?}) in fcx {}",
hir_id,
@ -3617,7 +3629,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some((variant, did, substs)) = variant {
debug!("check_struct_path: did={:?} substs={:?}", did, substs);
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
self.write_user_substs_from_substs(hir_id, substs);
self.write_user_substs_from_substs(hir_id, substs, None);
// Check bounds on type arguments used in the path.
let bounds = self.instantiate_bounds(path_span, did, substs);
@ -5005,7 +5017,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let path_segs = self.def_ids_for_path_segments(segments, def);
let mut ufcs_associated = None;
let mut user_self_ty = None;
match def {
Def::Method(def_id) |
Def::AssociatedConst(def_id) => {
@ -5014,12 +5026,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
ty::TraitContainer(trait_did) => {
callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
}
ty::ImplContainer(_) => {}
}
if segments.len() == 1 {
// `<T>::assoc` will end up here, and so can `T::assoc`.
let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
ufcs_associated = Some((container, self_ty));
ty::ImplContainer(impl_def_id) => {
if segments.len() == 1 {
// `<T>::assoc` will end up here, and so
// can `T::assoc`. It this came from an
// inherent impl, we need to record the
// `T` for posterity (see `UserSelfTy` for
// details).
let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
user_self_ty = Some(UserSelfTy {
impl_def_id,
self_ty,
});
}
}
}
}
_ => {}
@ -5173,6 +5193,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
assert!(!substs.has_escaping_regions());
assert!(!ty.has_escaping_regions());
// Write the "user substs" down first thing for later.
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
self.write_user_substs_from_substs(hir_id, substs, user_self_ty);
// Add all the obligations that are required, substituting and
// normalized appropriately.
let bounds = self.instantiate_bounds(span, def_id, &substs);
@ -5184,7 +5208,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// the referenced item.
let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated {
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
// In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
// is inherent, there is no `Self` parameter, instead, the impl needs
// type parameters, which we can infer by unifying the provided `Self`
@ -5208,16 +5232,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("instantiate_value_path: type of {:?} is {:?}",
node_id,
ty_substituted);
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
self.write_substs(hir_id, substs);
debug!(
"instantiate_value_path: id={:?} substs={:?}",
node_id,
substs,
);
self.write_user_substs_from_substs(hir_id, substs);
(ty_substituted, new_def)
}

View File

@ -56,7 +56,7 @@ fn main() {
// StorageLive(_4);
// _4 = std::option::Option<std::boxed::Box<u32>>::None;
// FakeRead(ForLet, _4);
// AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> });
// AscribeUserType(_4, o, Ty(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }));
// StorageLive(_5);
// StorageLive(_6);
// _6 = move _4;

View File

@ -1,4 +1,4 @@
error: user substs: Canonical { variables: [], value: [u32] }
error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
--> $DIR/dump-adt-brace-struct.rs:28:5
|
LL | SomeStruct::<u32> { t: 22 }; //~ ERROR [u32]

View File

@ -1,22 +1,22 @@
error: user substs: Canonical { variables: [], value: [u32] }
error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } }
--> $DIR/dump-fn-method.rs:36:13
|
LL | let x = foo::<u32>; //~ ERROR [u32]
| ^^^^^^^^^^
error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, u32, ?1] }
error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, u32, ?1], user_self_ty: None } }
--> $DIR/dump-fn-method.rs:42:13
|
LL | let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [?0, u32, ?1]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: user substs: Canonical { variables: [], value: [u8, u16, u32] }
error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } }
--> $DIR/dump-fn-method.rs:46:13
|
LL | let x = <u8 as Bazoom<u16>>::method::<u32>; //~ ERROR [u8, u16, u32]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, ?1, u32] }
error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, ?1, u32], user_self_ty: None } }
--> $DIR/dump-fn-method.rs:54:5
|
LL | y.method::<u32>(44, 66); //~ ERROR [?0, ?1, u32]

View File

@ -0,0 +1,20 @@
#![feature(nll)]
// Check that substitutions given on the self type (here, `A`) carry
// through to NLL.
struct A<'a> { x: &'a u32 }
impl<'a> A<'a> {
fn new<'b, T>(x: &'a u32, y: T) -> Self {
Self { x }
}
}
fn foo<'a>() {
let v = 22;
let x = A::<'a>::new(&v, 22);
//~^ ERROR
}
fn main() {}

View File

@ -0,0 +1,18 @@
error[E0597]: `v` does not live long enough
--> $DIR/method-ufcs-inherent-1.rs:16:26
|
LL | let x = A::<'a>::new(&v, 22);
| ^^ borrowed value does not live long enough
LL | //~^ ERROR
LL | }
| - `v` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
--> $DIR/method-ufcs-inherent-1.rs:14:8
|
LL | fn foo<'a>() {
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,21 @@
#![feature(nll)]
// Check that substitutions given on the self type (here, `A`) can be
// used in combination with annotations given for method arguments.
struct A<'a> { x: &'a u32 }
impl<'a> A<'a> {
fn new<'b, T>(x: &'a u32, y: T) -> Self {
Self { x }
}
}
fn foo<'a>() {
let v = 22;
let x = A::<'a>::new::<&'a u32>(&v, &v);
//~^ ERROR
//~| ERROR
}
fn main() {}

View File

@ -0,0 +1,33 @@
error[E0597]: `v` does not live long enough
--> $DIR/method-ufcs-inherent-2.rs:16:37
|
LL | let x = A::<'a>::new::<&'a u32>(&v, &v);
| ^^ borrowed value does not live long enough
...
LL | }
| - `v` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
--> $DIR/method-ufcs-inherent-2.rs:14:8
|
LL | fn foo<'a>() {
| ^^
error[E0597]: `v` does not live long enough
--> $DIR/method-ufcs-inherent-2.rs:16:41
|
LL | let x = A::<'a>::new::<&'a u32>(&v, &v);
| ^^ borrowed value does not live long enough
...
LL | }
| - `v` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
--> $DIR/method-ufcs-inherent-2.rs:14:8
|
LL | fn foo<'a>() {
| ^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,20 @@
#![feature(nll)]
// Check that inherent methods invoked with `<T>::new` style
// carry their annotations through to NLL.
struct A<'a> { x: &'a u32 }
impl<'a> A<'a> {
fn new<'b, T>(x: &'a u32, y: T) -> Self {
Self { x }
}
}
fn foo<'a>() {
let v = 22;
let x = <A<'a>>::new(&v, 22);
//~^ ERROR
}
fn main() {}

View File

@ -0,0 +1,18 @@
error[E0597]: `v` does not live long enough
--> $DIR/method-ufcs-inherent-3.rs:16:26
|
LL | let x = <A<'a>>::new(&v, 22);
| ^^ borrowed value does not live long enough
LL | //~^ ERROR
LL | }
| - `v` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8...
--> $DIR/method-ufcs-inherent-3.rs:14:8
|
LL | fn foo<'a>() {
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0597`.

View File

@ -0,0 +1,22 @@
#![feature(nll)]
// Check that inherent methods invoked with `<T>::new` style
// carry their annotations through to NLL in connection with
// method type parameters.
struct A<'a> { x: &'a u32 }
impl<'a> A<'a> {
fn new<'b, T>(x: &'a u32, y: T) -> Self {
Self { x }
}
}
fn foo<'a>() {
let v = 22;
let x = <A<'a>>::new::<&'a u32>(&v, &v);
//~^ ERROR
//~| ERROR
}
fn main() {}

View File

@ -0,0 +1,33 @@
error[E0597]: `v` does not live long enough
--> $DIR/method-ufcs-inherent-4.rs:17:37
|
LL | let x = <A<'a>>::new::<&'a u32>(&v, &v);
| ^^ borrowed value does not live long enough
...
LL | }
| - `v` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8...
--> $DIR/method-ufcs-inherent-4.rs:15:8
|
LL | fn foo<'a>() {
| ^^
error[E0597]: `v` does not live long enough
--> $DIR/method-ufcs-inherent-4.rs:17:41
|
LL | let x = <A<'a>>::new::<&'a u32>(&v, &v);
| ^^ borrowed value does not live long enough
...
LL | }
| - `v` dropped here while still borrowed
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8...
--> $DIR/method-ufcs-inherent-4.rs:15:8
|
LL | fn foo<'a>() {
| ^^
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0597`.