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:
commit
01ca85becd
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 });
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
736
src/librustc/infer/nll_relate/mod.rs
Normal file
736
src/librustc/infer/nll_relate/mod.rs
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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[{}]"
|
||||
|
@ -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>) {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
) {
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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(..)
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
|
@ -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]
|
||||
|
20
src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs
Normal file
20
src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs
Normal 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() {}
|
@ -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`.
|
21
src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
Normal file
21
src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs
Normal 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() {}
|
@ -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`.
|
20
src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs
Normal file
20
src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs
Normal 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() {}
|
@ -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`.
|
22
src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
Normal file
22
src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs
Normal 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() {}
|
@ -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`.
|
Loading…
x
Reference in New Issue
Block a user