Fix bug in higher-ranked code that would sometimes leak skolemized regions and/or cause incorrect results.
This commit is contained in:
parent
514dfdbf12
commit
3efc9d2c55
17 changed files with 443 additions and 228 deletions
|
@ -286,7 +286,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
|
||||
r_borrow,
|
||||
ty::mt{ty: ty, mutbl: mt_b.mutbl});
|
||||
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
|
||||
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
|
@ -309,7 +309,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
|
||||
ty::mt{ty: ty, mutbl: mt_b.mutbl});
|
||||
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
|
||||
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
|
@ -327,7 +327,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
match self.unsize_ty(t_a, sty_a, t_b) {
|
||||
Some((ty, kind)) => {
|
||||
let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
|
||||
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
|
||||
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoUnsizeUniq({}))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
|
@ -384,7 +384,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
let mut result = None;
|
||||
let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
|
||||
for (i, (tp_a, tp_b)) in tps {
|
||||
if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
|
||||
if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() {
|
||||
continue;
|
||||
}
|
||||
match
|
||||
|
@ -397,7 +397,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
let mut new_substs = substs_a.clone();
|
||||
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
|
||||
let ty = ty::mk_struct(tcx, did_a, new_substs);
|
||||
if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() {
|
||||
if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() {
|
||||
debug!("Unsized type parameter '{}', but still \
|
||||
could not match types {} and {}",
|
||||
ppaux::ty_to_string(tcx, *tp_a),
|
||||
|
|
|
@ -706,14 +706,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
|
|||
|
||||
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
|
||||
match r {
|
||||
ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
|
||||
_ if self.make_region_vars => {
|
||||
// FIXME: This is non-ideal because we don't give a
|
||||
// very descriptive origin for this region variable.
|
||||
self.infcx.next_region_var(MiscVariable(self.span))
|
||||
// Never make variables for regions bound within the type itself.
|
||||
ty::ReLateBound(..) => { return r; }
|
||||
|
||||
// Early-bound regions should really have been substituted away before
|
||||
// we get to this point.
|
||||
ty::ReEarlyBound(..) => {
|
||||
self.tcx().sess.span_bug(
|
||||
self.span,
|
||||
format!("Encountered early bound region when generalizing: {}",
|
||||
r.repr(self.tcx()))[]);
|
||||
}
|
||||
|
||||
// Always make a fresh region variable for skolemized regions;
|
||||
// the higher-ranked decision procedures rely on this.
|
||||
ty::ReInfer(ty::ReSkolemized(..)) => { }
|
||||
|
||||
// For anything else, we make a region variable, unless we
|
||||
// are *equating*, in which case it's just wasteful.
|
||||
ty::ReEmpty |
|
||||
ty::ReStatic |
|
||||
ty::ReScope(..) |
|
||||
ty::ReInfer(ty::ReVar(..)) |
|
||||
ty::ReFree(..) => {
|
||||
if !self.make_region_vars {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
_ => r,
|
||||
}
|
||||
|
||||
// FIXME: This is non-ideal because we don't give a
|
||||
// very descriptive origin for this region variable.
|
||||
self.infcx.next_region_var(MiscVariable(self.span))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1640,7 +1640,7 @@ pub trait Resolvable<'tcx> {
|
|||
|
||||
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
|
||||
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> {
|
||||
infcx.resolve_type_vars_if_possible(*self)
|
||||
infcx.resolve_type_vars_if_possible(self)
|
||||
}
|
||||
fn contains_error(&self) -> bool {
|
||||
ty::type_is_error(*self)
|
||||
|
@ -1650,7 +1650,7 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
|
|||
impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
|
||||
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
|
||||
-> Rc<ty::TraitRef<'tcx>> {
|
||||
Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self))
|
||||
Rc::new(infcx.resolve_type_vars_if_possible(&**self))
|
||||
}
|
||||
fn contains_error(&self) -> bool {
|
||||
ty::trait_ref_contains_error(&**self)
|
||||
|
|
|
@ -249,19 +249,21 @@
|
|||
//! in T and try to, in some cases, replace them with bound regions to
|
||||
//! yield the final result.
|
||||
//!
|
||||
//! To decide whether to replace a region `R` that appears in `T` with a
|
||||
//! bound region, the algorithms make use of two bits of information.
|
||||
//! First is a set `V` that contains all region variables created as part
|
||||
//! of the LUB/GLB computation. `V` will contain the region variables
|
||||
//! created to replace the bound regions in the input types, but it also
|
||||
//! contains 'intermediate' variables created to represent the LUB/GLB of
|
||||
//! individual regions. Basically, when asked to compute the LUB/GLB of a
|
||||
//! region variable with another region, the inferencer cannot oblige
|
||||
//! immediately since the values of that variables are not known.
|
||||
//! Therefore, it creates a new variable that is related to the two
|
||||
//! regions. For example, the LUB of two variables `$x` and `$y` is a
|
||||
//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y
|
||||
//! <= $z`. So `V` will contain these intermediate variables as well.
|
||||
//! To decide whether to replace a region `R` that appears in `T` with
|
||||
//! a bound region, the algorithms make use of two bits of
|
||||
//! information. First is a set `V` that contains all region
|
||||
//! variables created as part of the LUB/GLB computation (roughly; see
|
||||
//! `region_vars_confined_to_snapshot()` for full details). `V` will
|
||||
//! contain the region variables created to replace the bound regions
|
||||
//! in the input types, but it also contains 'intermediate' variables
|
||||
//! created to represent the LUB/GLB of individual regions.
|
||||
//! Basically, when asked to compute the LUB/GLB of a region variable
|
||||
//! with another region, the inferencer cannot oblige immediately
|
||||
//! since the values of that variables are not known. Therefore, it
|
||||
//! creates a new variable that is related to the two regions. For
|
||||
//! example, the LUB of two variables `$x` and `$y` is a fresh
|
||||
//! variable `$z` that is constrained such that `$x <= $z` and `$y <=
|
||||
//! $z`. So `V` will contain these intermediate variables as well.
|
||||
//!
|
||||
//! The other important factor in deciding how to replace a region in T is
|
||||
//! the function `Tainted($r)` which, for a region variable, identifies
|
||||
|
|
|
@ -11,14 +11,13 @@
|
|||
//! Helper routines for higher-ranked things. See the `doc` module at
|
||||
//! the end of the file for details.
|
||||
|
||||
use super::{combine, cres, InferCtxt, HigherRankedType};
|
||||
use super::{combine, CombinedSnapshot, cres, InferCtxt, HigherRankedType};
|
||||
use super::combine::Combine;
|
||||
use super::region_inference::{RegionMark};
|
||||
|
||||
use middle::ty::{mod, Ty, replace_late_bound_regions};
|
||||
use middle::ty_fold::{mod, HigherRankedFoldable, TypeFoldable};
|
||||
use syntax::codemap::Span;
|
||||
use util::nodemap::FnvHashMap;
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
use util::ppaux::{bound_region_to_string, Repr};
|
||||
|
||||
pub trait HigherRankedCombineable<'tcx>: HigherRankedFoldable<'tcx> +
|
||||
|
@ -37,6 +36,14 @@ pub trait HigherRankedRelations<'tcx> {
|
|||
where T : HigherRankedCombineable<'tcx>;
|
||||
}
|
||||
|
||||
trait InferCtxtExt<'tcx> {
|
||||
fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region>;
|
||||
|
||||
fn region_vars_confined_to_snapshot(&self,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> Vec<ty::RegionVid>;
|
||||
}
|
||||
|
||||
impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
||||
where C : Combine<'tcx>
|
||||
{
|
||||
|
@ -54,114 +61,115 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
|||
// please see the large comment at the end of the file in the (inlined) module
|
||||
// `doc`.
|
||||
|
||||
// Make a mark so we can examine "all bindings that were
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
let mark = self.infcx().region_vars.mark();
|
||||
return self.infcx().try(|snapshot| {
|
||||
// First, we instantiate each bound region in the subtype with a fresh
|
||||
// region variable.
|
||||
let (a_prime, _) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(),
|
||||
HigherRankedType,
|
||||
a);
|
||||
|
||||
// First, we instantiate each bound region in the subtype with a fresh
|
||||
// region variable.
|
||||
let (a_prime, _) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(),
|
||||
HigherRankedType,
|
||||
a);
|
||||
// Second, we instantiate each bound region in the supertype with a
|
||||
// fresh concrete region.
|
||||
let (b_prime, skol_map) = {
|
||||
replace_late_bound_regions(self.tcx(), b, |br, _| {
|
||||
let skol = self.infcx().region_vars.new_skolemized(br);
|
||||
debug!("Bound region {} skolemized to {}",
|
||||
bound_region_to_string(self.tcx(), "", false, br),
|
||||
skol);
|
||||
skol
|
||||
})
|
||||
};
|
||||
|
||||
// Second, we instantiate each bound region in the supertype with a
|
||||
// fresh concrete region.
|
||||
let (b_prime, skol_map) = {
|
||||
replace_late_bound_regions(self.tcx(), b, |br, _| {
|
||||
let skol = self.infcx().region_vars.new_skolemized(br);
|
||||
debug!("Bound region {} skolemized to {}",
|
||||
bound_region_to_string(self.tcx(), "", false, br),
|
||||
skol);
|
||||
skol
|
||||
})
|
||||
};
|
||||
debug!("a_prime={}", a_prime.repr(self.tcx()));
|
||||
debug!("b_prime={}", b_prime.repr(self.tcx()));
|
||||
|
||||
debug!("a_prime={}", a_prime.repr(self.tcx()));
|
||||
debug!("b_prime={}", b_prime.repr(self.tcx()));
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime));
|
||||
|
||||
// Compare types now that bound regions have been replaced.
|
||||
let result = try!(HigherRankedCombineable::super_combine(self, &a_prime, &b_prime));
|
||||
// Presuming type comparison succeeds, we need to check
|
||||
// that the skolemized regions do not "leak".
|
||||
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
|
||||
for (&skol_br, &skol) in skol_map.iter() {
|
||||
let tainted = self.infcx().tainted_regions(snapshot, skol);
|
||||
for tainted_region in tainted.iter() {
|
||||
// Each skolemized should only be relatable to itself
|
||||
// or new variables:
|
||||
match *tainted_region {
|
||||
ty::ReInfer(ty::ReVar(ref vid)) => {
|
||||
if new_vars.iter().any(|x| x == vid) { continue; }
|
||||
}
|
||||
_ => {
|
||||
if *tainted_region == skol { continue; }
|
||||
}
|
||||
};
|
||||
|
||||
// Presuming type comparison succeeds, we need to check
|
||||
// that the skolemized regions do not "leak".
|
||||
let new_vars =
|
||||
self.infcx().region_vars.vars_created_since_mark(mark);
|
||||
for (&skol_br, &skol) in skol_map.iter() {
|
||||
let tainted = self.infcx().region_vars.tainted(mark, skol);
|
||||
for tainted_region in tainted.iter() {
|
||||
// Each skolemized should only be relatable to itself
|
||||
// or new variables:
|
||||
match *tainted_region {
|
||||
ty::ReInfer(ty::ReVar(ref vid)) => {
|
||||
if new_vars.iter().any(|x| x == vid) { continue; }
|
||||
// A is not as polymorphic as B:
|
||||
if self.a_is_expected() {
|
||||
debug!("Not as polymorphic!");
|
||||
return Err(ty::terr_regions_insufficiently_polymorphic(skol_br,
|
||||
*tainted_region));
|
||||
} else {
|
||||
debug!("Overly polymorphic!");
|
||||
return Err(ty::terr_regions_overly_polymorphic(skol_br,
|
||||
*tainted_region));
|
||||
}
|
||||
_ => {
|
||||
if *tainted_region == skol { continue; }
|
||||
}
|
||||
};
|
||||
|
||||
// A is not as polymorphic as B:
|
||||
if self.a_is_expected() {
|
||||
debug!("Not as polymorphic!");
|
||||
return Err(ty::terr_regions_insufficiently_polymorphic(
|
||||
skol_br, *tainted_region));
|
||||
} else {
|
||||
debug!("Overly polymorphic!");
|
||||
return Err(ty::terr_regions_overly_polymorphic(
|
||||
skol_br, *tainted_region));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("higher_ranked_sub: OK result={}",
|
||||
result.repr(self.tcx()));
|
||||
debug!("higher_ranked_sub: OK result={}",
|
||||
result.repr(self.tcx()));
|
||||
|
||||
return Ok(result);
|
||||
Ok(result)
|
||||
});
|
||||
}
|
||||
|
||||
fn higher_ranked_lub<T>(&self, a: &T, b: &T) -> cres<'tcx, T>
|
||||
where T : HigherRankedCombineable<'tcx>
|
||||
{
|
||||
// Make a mark so we can examine "all bindings that were
|
||||
// Start a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
let mark = self.infcx().region_vars.mark();
|
||||
return self.infcx().try(|snapshot| {
|
||||
// Instantiate each bound region with a fresh region variable.
|
||||
let span = self.trace().origin.span();
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span, HigherRankedType, a);
|
||||
let (b_with_fresh, _) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span, HigherRankedType, b);
|
||||
|
||||
// Instantiate each bound region with a fresh region variable.
|
||||
let span = self.trace().origin.span();
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span, HigherRankedType, a);
|
||||
let (b_with_fresh, _) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
span, HigherRankedType, b);
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
|
||||
let result0 =
|
||||
self.infcx().resolve_type_vars_if_possible(&result0);
|
||||
debug!("lub result0 = {}", result0.repr(self.tcx()));
|
||||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
|
||||
debug!("lub result0 = {}", result0.repr(self.tcx()));
|
||||
// Generalize the regions appearing in result0 if possible
|
||||
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace().origin.span();
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
|
||||
new_vars.as_slice(), &a_map, r));
|
||||
|
||||
// Generalize the regions appearing in result0 if possible
|
||||
let new_vars = self.infcx().region_vars.vars_created_since_mark(mark);
|
||||
let span = self.trace().origin.span();
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx(), span, mark, debruijn,
|
||||
new_vars.as_slice(), &a_map, r));
|
||||
debug!("lub({},{}) = {}",
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()),
|
||||
result1.repr(self.tcx()));
|
||||
|
||||
debug!("lub({},{}) = {}",
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()),
|
||||
result1.repr(self.tcx()));
|
||||
|
||||
return Ok(result1);
|
||||
Ok(result1)
|
||||
});
|
||||
|
||||
fn generalize_region(infcx: &InferCtxt,
|
||||
span: Span,
|
||||
mark: RegionMark,
|
||||
snapshot: &CombinedSnapshot,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
new_vars: &[ty::RegionVid],
|
||||
a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
|
||||
|
@ -174,7 +182,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
|||
return r0;
|
||||
}
|
||||
|
||||
let tainted = infcx.region_vars.tainted(mark, r0);
|
||||
let tainted = infcx.tainted_regions(snapshot, r0);
|
||||
|
||||
// Variables created during LUB computation which are
|
||||
// *related* to regions that pre-date the LUB computation
|
||||
|
@ -215,47 +223,49 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
|||
debug!("{}.higher_ranked_glb({}, {})",
|
||||
self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
|
||||
|
||||
// Make a mark so we can examine "all bindings that were
|
||||
// Make a snapshot so we can examine "all bindings that were
|
||||
// created as part of this type comparison".
|
||||
let mark = self.infcx().region_vars.mark();
|
||||
return self.infcx().try(|snapshot| {
|
||||
// Instantiate each bound region with a fresh region variable.
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(), HigherRankedType, a);
|
||||
let (b_with_fresh, b_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(), HigherRankedType, b);
|
||||
let a_vars = var_ids(self, &a_map);
|
||||
let b_vars = var_ids(self, &b_map);
|
||||
|
||||
// Instantiate each bound region with a fresh region variable.
|
||||
let (a_with_fresh, a_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(), HigherRankedType, a);
|
||||
let (b_with_fresh, b_map) =
|
||||
self.infcx().replace_late_bound_regions_with_fresh_var(
|
||||
self.trace().origin.span(), HigherRankedType, b);
|
||||
let a_vars = var_ids(self, &a_map);
|
||||
let b_vars = var_ids(self, &b_map);
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
|
||||
let result0 =
|
||||
self.infcx().resolve_type_vars_if_possible(&result0);
|
||||
debug!("glb result0 = {}", result0.repr(self.tcx()));
|
||||
|
||||
// Collect constraints.
|
||||
let result0 =
|
||||
try!(HigherRankedCombineable::super_combine(self, &a_with_fresh, &b_with_fresh));
|
||||
debug!("glb result0 = {}", result0.repr(self.tcx()));
|
||||
// Generalize the regions appearing in fn_ty0 if possible
|
||||
let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot);
|
||||
let span = self.trace().origin.span();
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn,
|
||||
new_vars.as_slice(),
|
||||
&a_map, a_vars.as_slice(), b_vars.as_slice(),
|
||||
r));
|
||||
|
||||
// Generalize the regions appearing in fn_ty0 if possible
|
||||
let new_vars = self.infcx().region_vars.vars_created_since_mark(mark);
|
||||
let span = self.trace().origin.span();
|
||||
let result1 =
|
||||
fold_regions_in(
|
||||
self.tcx(),
|
||||
&result0,
|
||||
|r, debruijn| generalize_region(self.infcx(), span, mark, debruijn,
|
||||
new_vars.as_slice(),
|
||||
&a_map, a_vars.as_slice(), b_vars.as_slice(),
|
||||
r));
|
||||
debug!("glb({},{}) = {}",
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()),
|
||||
result1.repr(self.tcx()));
|
||||
|
||||
debug!("glb({},{}) = {}",
|
||||
a.repr(self.tcx()),
|
||||
b.repr(self.tcx()),
|
||||
result1.repr(self.tcx()));
|
||||
|
||||
return Ok(result1);
|
||||
Ok(result1)
|
||||
});
|
||||
|
||||
fn generalize_region(infcx: &InferCtxt,
|
||||
span: Span,
|
||||
mark: RegionMark,
|
||||
snapshot: &CombinedSnapshot,
|
||||
debruijn: ty::DebruijnIndex,
|
||||
new_vars: &[ty::RegionVid],
|
||||
a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
|
||||
|
@ -267,7 +277,7 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C
|
|||
return r0;
|
||||
}
|
||||
|
||||
let tainted = infcx.region_vars.tainted(mark, r0);
|
||||
let tainted = infcx.tainted_regions(snapshot, r0);
|
||||
|
||||
let mut a_r = None;
|
||||
let mut b_r = None;
|
||||
|
@ -443,3 +453,86 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, value: &T, mut fldr: F) ->
|
|||
}))
|
||||
}
|
||||
|
||||
impl<'a,'tcx> InferCtxtExt<'tcx> for InferCtxt<'a,'tcx> {
|
||||
fn tainted_regions(&self, snapshot: &CombinedSnapshot, r: ty::Region) -> Vec<ty::Region> {
|
||||
self.region_vars.tainted(&snapshot.region_vars_snapshot, r)
|
||||
}
|
||||
|
||||
fn region_vars_confined_to_snapshot(&self,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> Vec<ty::RegionVid>
|
||||
{
|
||||
/*!
|
||||
* Returns the set of region variables that do not affect any
|
||||
* types/regions which existed before `snapshot` was
|
||||
* started. This is used in the sub/lub/glb computations. The
|
||||
* idea here is that when we are computing lub/glb of two
|
||||
* regions, we sometimes create intermediate region variables.
|
||||
* Those region variables may touch some of the skolemized or
|
||||
* other "forbidden" regions we created to replace bound
|
||||
* regions, but they don't really represent an "external"
|
||||
* constraint.
|
||||
*
|
||||
* However, sometimes fresh variables are created for other
|
||||
* purposes too, and those *may* represent an external
|
||||
* constraint. In particular, when a type variable is
|
||||
* instantiated, we create region variables for all the
|
||||
* regions that appear within, and if that type variable
|
||||
* pre-existed the snapshot, then those region variables
|
||||
* represent external constraints.
|
||||
*
|
||||
* An example appears in the unit test
|
||||
* `sub_free_bound_false_infer`. In this test, we want to
|
||||
* know whether
|
||||
*
|
||||
* ```rust
|
||||
* fn(_#0t) <: for<'a> fn(&'a int)
|
||||
* ```
|
||||
*
|
||||
* Note that the subtype has a type variable. Because the type
|
||||
* variable can't be instantiated with a region that is bound
|
||||
* in the fn signature, this comparison ought to fail. But if
|
||||
* we're not careful, it will succeed.
|
||||
*
|
||||
* The reason is that when we walk through the subtyping
|
||||
* algorith, we begin by replacing `'a` with a skolemized
|
||||
* variable `'0`. We then have `fn(_#0t) <: fn(&'0 int)`. This
|
||||
* can be made true by unifying `_#0t` with `&'0 int`. In the
|
||||
* process, we create a fresh variable for the skolemized
|
||||
* region, `'$0`, and hence we have that `_#0t == &'$0
|
||||
* int`. However, because `'$0` was created during the sub
|
||||
* computation, if we're not careful we will erroneously
|
||||
* assume it is one of the transient region variables
|
||||
* representing a lub/glb internally. Not good.
|
||||
*
|
||||
* To prevent this, we check for type variables which were
|
||||
* unified during the snapshot, and say that any region
|
||||
* variable created during the snapshot but which finds its
|
||||
* way into a type variable is considered to "escape" the
|
||||
* snapshot.
|
||||
*/
|
||||
|
||||
let mut region_vars =
|
||||
self.region_vars.vars_created_since_snapshot(&snapshot.region_vars_snapshot);
|
||||
|
||||
let escaping_types =
|
||||
self.type_variables.borrow().types_escaping_snapshot(&snapshot.type_snapshot);
|
||||
|
||||
let escaping_region_vars: FnvHashSet<_> =
|
||||
escaping_types
|
||||
.iter()
|
||||
.flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter())
|
||||
.collect();
|
||||
|
||||
region_vars.retain(|®ion_vid| {
|
||||
let r = ty::ReInfer(ty::ReVar(region_vid));
|
||||
!escaping_region_vars.contains(&r)
|
||||
});
|
||||
|
||||
debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}",
|
||||
region_vars.repr(self.tcx),
|
||||
escaping_types.repr(self.tcx));
|
||||
|
||||
region_vars
|
||||
}
|
||||
}
|
||||
|
|
|
@ -520,6 +520,7 @@ pub fn uok<'tcx>() -> ures<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[must_use = "once you start a snapshot, you should always consume it"]
|
||||
pub struct CombinedSnapshot {
|
||||
type_snapshot: type_variable::Snapshot,
|
||||
int_snapshot: unify::Snapshot<ty::IntVid>,
|
||||
|
@ -629,16 +630,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> where
|
||||
F: FnOnce() -> Result<T, E>
|
||||
{
|
||||
self.commit_unconditionally(move || self.try(move || f()))
|
||||
self.commit_unconditionally(move || self.try(move |_| f()))
|
||||
}
|
||||
|
||||
/// Execute `f`, unroll bindings on panic
|
||||
pub fn try<T, E, F>(&self, f: F) -> Result<T, E> where
|
||||
F: FnOnce() -> Result<T, E>
|
||||
F: FnOnce(&CombinedSnapshot) -> Result<T, E>
|
||||
{
|
||||
debug!("try()");
|
||||
let snapshot = self.start_snapshot();
|
||||
let r = f();
|
||||
let r = f(&snapshot);
|
||||
debug!("try() -- r.is_ok() = {}", r.is_ok());
|
||||
match r {
|
||||
Ok(_) => {
|
||||
|
@ -821,7 +822,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
|
||||
ty_to_string(self.tcx,
|
||||
self.resolve_type_vars_if_possible(t))
|
||||
self.resolve_type_vars_if_possible(&t))
|
||||
}
|
||||
|
||||
pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
|
||||
|
@ -830,7 +831,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn trait_ref_to_string(&self, t: &Rc<ty::TraitRef<'tcx>>) -> String {
|
||||
let t = self.resolve_type_vars_in_trait_ref_if_possible(&**t);
|
||||
let t = self.resolve_type_vars_if_possible(&**t);
|
||||
trait_ref_to_string(self.tcx, &t)
|
||||
}
|
||||
|
||||
|
@ -867,35 +868,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn resolve_type_vars_if_possible(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match resolve_type(self,
|
||||
None,
|
||||
typ, resolve_nested_tvar | resolve_ivar) {
|
||||
Ok(new_type) => new_type,
|
||||
Err(_) => typ
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_type_vars_in_trait_ref_if_possible(&self,
|
||||
trait_ref: &ty::TraitRef<'tcx>)
|
||||
-> ty::TraitRef<'tcx> {
|
||||
// make up a dummy type just to reuse/abuse the resolve machinery
|
||||
let dummy0 = ty::mk_trait(self.tcx,
|
||||
(*trait_ref).clone(),
|
||||
ty::region_existential_bound(ty::ReStatic));
|
||||
let dummy1 = self.resolve_type_vars_if_possible(dummy0);
|
||||
match dummy1.sty {
|
||||
ty::ty_trait(box ty::TyTrait { ref principal, .. }) => {
|
||||
(*principal).clone()
|
||||
}
|
||||
_ => {
|
||||
self.tcx.sess.bug(
|
||||
format!("resolve_type_vars_if_possible() yielded {} \
|
||||
when supplied with {}",
|
||||
self.ty_to_string(dummy0),
|
||||
self.ty_to_string(dummy1)).as_slice());
|
||||
}
|
||||
}
|
||||
pub fn resolve_type_vars_if_possible<T:TypeFoldable<'tcx>>(&self, value: &T) -> T {
|
||||
let mut r = resolve::DeepTypeResolver::new(self);
|
||||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
// [Note-Type-error-reporting]
|
||||
|
@ -929,9 +904,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
{
|
||||
debug!("hi! expected_ty = {}, actual_ty = {}", expected_ty, actual_ty);
|
||||
|
||||
let resolved_expected = expected_ty.map(|e_ty| {
|
||||
self.resolve_type_vars_if_possible(e_ty)
|
||||
});
|
||||
let resolved_expected = expected_ty.map(|e_ty| self.resolve_type_vars_if_possible(&e_ty));
|
||||
|
||||
match resolved_expected {
|
||||
Some(t) if ty::type_is_error(t) => (),
|
||||
|
@ -958,7 +931,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
err: Option<&ty::type_err<'tcx>>) where
|
||||
M: FnOnce(String) -> String,
|
||||
{
|
||||
let actual_ty = self.resolve_type_vars_if_possible(actual_ty);
|
||||
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
|
||||
|
||||
// Don't report an error if actual type is ty_err.
|
||||
if ty::type_is_error(actual_ty) {
|
||||
|
|
|
@ -81,7 +81,6 @@ impl Copy for TwoRegions {}
|
|||
pub enum UndoLogEntry {
|
||||
OpenSnapshot,
|
||||
CommitedSnapshot,
|
||||
Mark,
|
||||
AddVar(RegionVid),
|
||||
AddConstraint(Constraint),
|
||||
AddVerify(uint),
|
||||
|
@ -225,19 +224,11 @@ pub struct RegionVarBindings<'a, 'tcx: 'a> {
|
|||
}
|
||||
|
||||
#[deriving(Show)]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct RegionSnapshot {
|
||||
length: uint
|
||||
}
|
||||
|
||||
impl Copy for RegionSnapshot {}
|
||||
|
||||
#[deriving(Show)]
|
||||
pub struct RegionMark {
|
||||
length: uint
|
||||
}
|
||||
|
||||
impl Copy for RegionMark {}
|
||||
|
||||
impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
||||
pub fn new(tcx: &'a ty::ctxt<'tcx>) -> RegionVarBindings<'a, 'tcx> {
|
||||
RegionVarBindings {
|
||||
|
@ -266,13 +257,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
RegionSnapshot { length: length }
|
||||
}
|
||||
|
||||
pub fn mark(&self) -> RegionMark {
|
||||
let length = self.undo_log.borrow().len();
|
||||
debug!("RegionVarBindings: mark({})", length);
|
||||
self.undo_log.borrow_mut().push(Mark);
|
||||
RegionMark { length: length }
|
||||
}
|
||||
|
||||
pub fn commit(&self, snapshot: RegionSnapshot) {
|
||||
debug!("RegionVarBindings: commit({})", snapshot.length);
|
||||
assert!(self.undo_log.borrow().len() > snapshot.length);
|
||||
|
@ -296,7 +280,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
OpenSnapshot => {
|
||||
panic!("Failure to observe stack discipline");
|
||||
}
|
||||
Mark | CommitedSnapshot => { }
|
||||
CommitedSnapshot => { }
|
||||
AddVar(vid) => {
|
||||
let mut var_origins = self.var_origins.borrow_mut();
|
||||
var_origins.pop().unwrap();
|
||||
|
@ -597,8 +581,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
ReInfer(ReVar(c))
|
||||
}
|
||||
|
||||
pub fn vars_created_since_mark(&self, mark: RegionMark)
|
||||
-> Vec<RegionVid>
|
||||
pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot)
|
||||
-> Vec<RegionVid>
|
||||
{
|
||||
self.undo_log.borrow()
|
||||
.slice_from(mark.length)
|
||||
|
@ -613,7 +597,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
/// Computes all regions that have been related to `r0` in any way since the mark `mark` was
|
||||
/// made---`r0` itself will be the first entry. This is used when checking whether skolemized
|
||||
/// regions are being improperly related to other regions.
|
||||
pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec<Region> {
|
||||
pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> {
|
||||
debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx));
|
||||
let _indenter = indenter();
|
||||
|
||||
|
@ -668,7 +652,6 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
&AddCombination(..) |
|
||||
&Mark |
|
||||
&AddVar(..) |
|
||||
&OpenSnapshot |
|
||||
&CommitedSnapshot => {
|
||||
|
|
|
@ -258,3 +258,38 @@ impl<'a, 'tcx> ResolveState<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// DEEP TYPE RESOLVER
|
||||
///
|
||||
/// This kind of resolver can be used at any time. It simply replaces
|
||||
/// type variables that have been unified with the things they have
|
||||
/// been unified with (similar to `shallow_resolve`, but deep). This is
|
||||
/// useful for printing messages etc but also required at various
|
||||
/// points for correctness.
|
||||
pub struct DeepTypeResolver<'a, 'tcx:'a> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> DeepTypeResolver<'a, 'tcx> {
|
||||
pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> DeepTypeResolver<'a, 'tcx> {
|
||||
DeepTypeResolver { infcx: infcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for DeepTypeResolver<'a, 'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !ty::type_has_ty_infer(t) {
|
||||
t // micro-optimize -- if there is nothing in this type that this fold affects...
|
||||
} else {
|
||||
let t0 = self.infcx.shallow_resolve(t);
|
||||
ty_fold::super_fold_ty(self, t0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@ use self::TypeVariableValue::*;
|
|||
use self::UndoEntry::*;
|
||||
|
||||
use middle::ty::{mod, Ty};
|
||||
use std::cmp::min;
|
||||
use std::mem;
|
||||
use std::uint;
|
||||
use util::snapshot_vec as sv;
|
||||
|
||||
pub struct TypeVariableTable<'tcx> {
|
||||
|
@ -78,7 +80,6 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||
///
|
||||
/// Precondition: neither `a` nor `b` are known.
|
||||
pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) {
|
||||
|
||||
if a != b {
|
||||
self.relations(a).push((dir, b));
|
||||
self.relations(b).push((dir.opposite(), a));
|
||||
|
@ -151,6 +152,49 @@ impl<'tcx> TypeVariableTable<'tcx> {
|
|||
pub fn commit(&mut self, s: Snapshot) {
|
||||
self.values.commit(s.snapshot);
|
||||
}
|
||||
|
||||
pub fn types_escaping_snapshot(&self, s: &Snapshot) -> Vec<Ty<'tcx>> {
|
||||
/*!
|
||||
* Find the set of type variables that existed *before* `s`
|
||||
* but which have only been unified since `s` started, and
|
||||
* return the types with which they were unified. So if we had
|
||||
* a type variable `V0`, then we started the snapshot, then we
|
||||
* created a type variable `V1`, unifed `V0` with `T0`, and
|
||||
* unified `V1` with `T1`, this function would return `{T0}`.
|
||||
*/
|
||||
|
||||
let mut new_elem_threshold = uint::MAX;
|
||||
let mut escaping_types = Vec::new();
|
||||
let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot);
|
||||
debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len());
|
||||
for action in actions_since_snapshot.iter() {
|
||||
match *action {
|
||||
sv::UndoLog::NewElem(index) => {
|
||||
// if any new variables were created during the
|
||||
// snapshot, remember the lower index (which will
|
||||
// always be the first one we see). Note that this
|
||||
// action must precede those variables being
|
||||
// specified.
|
||||
new_elem_threshold = min(new_elem_threshold, index);
|
||||
debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
|
||||
}
|
||||
|
||||
sv::UndoLog::Other(SpecifyVar(vid, _)) => {
|
||||
if vid.index < new_elem_threshold {
|
||||
// quick check to see if this variable was
|
||||
// created since the snapshot started or not.
|
||||
let escaping_type = self.probe(vid).unwrap();
|
||||
escaping_types.push(escaping_type);
|
||||
}
|
||||
debug!("SpecifyVar({}) new_elem_threshold={}", vid, new_elem_threshold);
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
escaping_types
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> sv::SnapshotVecDelegate<TypeVariableData<'tcx>,UndoEntry> for Delegate {
|
||||
|
|
|
@ -790,6 +790,17 @@ impl<'a, 'tcx, F> RegionFolder<'a, 'tcx, F> where F: FnMut(ty::Region, uint) ->
|
|||
}
|
||||
}
|
||||
|
||||
pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region>
|
||||
where T : TypeFoldable<'tcx>
|
||||
{
|
||||
let mut vec = Vec::new();
|
||||
{
|
||||
let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r });
|
||||
value.fold_with(&mut folder);
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, F> TypeFolder<'tcx> for RegionFolder<'a, 'tcx, F> where
|
||||
F: FnMut(ty::Region, uint) -> ty::Region,
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@ use self::UndoLog::*;
|
|||
use std::mem;
|
||||
|
||||
#[deriving(PartialEq)]
|
||||
enum UndoLog<T,U> {
|
||||
pub enum UndoLog<T,U> {
|
||||
/// Indicates where a snapshot started.
|
||||
OpenSnapshot,
|
||||
|
||||
|
@ -113,6 +113,12 @@ impl<T,U,D:SnapshotVecDelegate<T,U>> SnapshotVec<T,U,D> {
|
|||
Snapshot { length: length }
|
||||
}
|
||||
|
||||
pub fn actions_since_snapshot(&self,
|
||||
snapshot: &Snapshot)
|
||||
-> &[UndoLog<T,U>] {
|
||||
self.undo_log[snapshot.length..]
|
||||
}
|
||||
|
||||
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
|
||||
// Or else there was a failure to follow a stack discipline:
|
||||
assert!(self.undo_log.len() > snapshot.length);
|
||||
|
|
|
@ -502,6 +502,26 @@ fn sub_free_bound_false_infer() {
|
|||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_free_bound_infer() {
|
||||
//! Test result of:
|
||||
//!
|
||||
//! LUB(fn(_#1), for<'b> fn(&'b int))
|
||||
//!
|
||||
//! This should yield `fn(&'_ int)`. We check
|
||||
//! that it yields `fn(&'x int)` for some free `'x`,
|
||||
//! anyhow.
|
||||
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_infer1 = env.infcx.next_ty_var();
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_rptr_free1 = env.t_rptr_free(0, 1);
|
||||
env.check_lub(env.t_fn(&[t_infer1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_free1], ty::mk_int()));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lub_bound_bound() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
|
@ -605,6 +625,28 @@ fn glb_bound_free() {
|
|||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_bound_free_infer() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
let t_rptr_bound1 = env.t_rptr_late_bound(1);
|
||||
let t_infer1 = env.infcx.next_ty_var();
|
||||
|
||||
// compute GLB(fn(_) -> int, for<'b> fn(&'b int) -> int),
|
||||
// which should yield for<'b> fn(&'b int) -> int
|
||||
env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
|
||||
env.t_fn(&[t_infer1], ty::mk_int()),
|
||||
env.t_fn(&[t_rptr_bound1], ty::mk_int()));
|
||||
|
||||
// as a side-effect, computing GLB should unify `_` with
|
||||
// `&'_ int`
|
||||
let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
|
||||
match t_resolve1.sty {
|
||||
ty::ty_rptr(..) => { }
|
||||
_ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glb_bound_static() {
|
||||
test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
|
||||
|
|
|
@ -196,7 +196,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
|
|||
debug!("found object type {}", kind);
|
||||
|
||||
let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0);
|
||||
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty);
|
||||
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
|
||||
debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
|
||||
|
||||
let input_tys = match arg_param_ty.sty {
|
||||
|
@ -206,7 +206,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
|
|||
debug!("input_tys {}", input_tys.repr(tcx));
|
||||
|
||||
let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1);
|
||||
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty);
|
||||
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
|
||||
debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
|
||||
|
||||
let fn_sig = ty::FnSig {
|
||||
|
|
|
@ -100,7 +100,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
call_expr.repr(fcx.tcx()),
|
||||
self_expr.repr(fcx.tcx()));
|
||||
|
||||
let self_ty = fcx.infcx().resolve_type_vars_if_possible(self_ty);
|
||||
let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
|
||||
let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id));
|
||||
Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
|
||||
}
|
||||
|
|
|
@ -1638,7 +1638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn default_diverging_type_variables_to_nil(&self) {
|
||||
for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() {
|
||||
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) {
|
||||
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) {
|
||||
demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx()));
|
||||
}
|
||||
}
|
||||
|
@ -2486,7 +2486,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
let method_type = match method {
|
||||
Some(ref method) => method.ty,
|
||||
None => {
|
||||
let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type);
|
||||
let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type);
|
||||
|
||||
if !ty::type_is_error(true_expr_type) {
|
||||
let ty_string = fcx.infcx().ty_to_string(true_expr_type);
|
||||
|
@ -3976,7 +3976,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
vtable::select_new_fcx_obligations(fcx);
|
||||
|
||||
debug!("ExprForLoop each item has type {}",
|
||||
fcx.infcx().resolve_type_vars_if_possible(typ).repr(fcx.tcx()));
|
||||
fcx.infcx().resolve_type_vars_if_possible(&typ).repr(fcx.tcx()));
|
||||
|
||||
let pcx = pat_ctxt {
|
||||
fcx: fcx,
|
||||
|
@ -4371,11 +4371,11 @@ impl<'tcx> Expectation<'tcx> {
|
|||
}
|
||||
ExpectCastableToType(t) => {
|
||||
ExpectCastableToType(
|
||||
fcx.infcx().resolve_type_vars_if_possible(t))
|
||||
fcx.infcx().resolve_type_vars_if_possible(&t))
|
||||
}
|
||||
ExpectHasType(t) => {
|
||||
ExpectHasType(
|
||||
fcx.infcx().resolve_type_vars_if_possible(t))
|
||||
fcx.infcx().resolve_type_vars_if_possible(&t))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -331,7 +331,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref);
|
||||
fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
|
@ -341,8 +341,8 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
let a = fcx.infcx().resolve_type_vars_if_possible(a);
|
||||
let b = fcx.infcx().resolve_type_vars_if_possible(b);
|
||||
let a = fcx.infcx().resolve_type_vars_if_possible(&a);
|
||||
let b = fcx.infcx().resolve_type_vars_if_possible(&b);
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
format!(
|
||||
|
@ -373,8 +373,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
let trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
&**trait_ref);
|
||||
fcx.infcx().resolve_type_vars_if_possible(&**trait_ref);
|
||||
if !ty::type_is_error(trait_ref.self_ty()) {
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
|
@ -387,8 +386,8 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
ty::Predicate::Equate(a, b) => {
|
||||
let a = fcx.infcx().resolve_type_vars_if_possible(a);
|
||||
let b = fcx.infcx().resolve_type_vars_if_possible(b);
|
||||
let a = fcx.infcx().resolve_type_vars_if_possible(&a);
|
||||
let b = fcx.infcx().resolve_type_vars_if_possible(&b);
|
||||
let err = infer::can_mk_eqty(fcx.infcx(), a, b).unwrap_err();
|
||||
fcx.tcx().sess.span_err(
|
||||
obligation.cause.span,
|
||||
|
@ -413,10 +412,10 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
OutputTypeParameterMismatch(ref expected_trait_ref, ref actual_trait_ref, ref e) => {
|
||||
let expected_trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
fcx.infcx().resolve_type_vars_if_possible(
|
||||
&**expected_trait_ref);
|
||||
let actual_trait_ref =
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
|
||||
fcx.infcx().resolve_type_vars_if_possible(
|
||||
&**actual_trait_ref);
|
||||
if !ty::type_is_error(actual_trait_ref.self_ty()) {
|
||||
fcx.tcx().sess.span_err(
|
||||
|
@ -443,7 +442,7 @@ pub fn maybe_report_ambiguity<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
|
||||
let trait_ref = match obligation.trait_ref {
|
||||
ty::Predicate::Trait(ref trait_ref) => {
|
||||
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(&**trait_ref)
|
||||
fcx.infcx().resolve_type_vars_if_possible(&**trait_ref)
|
||||
}
|
||||
_ => {
|
||||
fcx.tcx().sess.span_bug(
|
||||
|
|
|
@ -14,3 +14,6 @@ fn main() {
|
|||
let int x = 5;
|
||||
match x;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue