Skip to content

Commit 4799098

Browse files
committed
Fix bug in higher-ranked code that would sometimes leak skolemized regions and/or cause incorrect results.
1 parent 9e93224 commit 4799098

File tree

16 files changed

+456
-233
lines changed

16 files changed

+456
-233
lines changed

src/librustc/middle/ty_fold.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,17 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
779779
}
780780
}
781781

782+
pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region>
783+
where T : TypeFoldable<'tcx>
784+
{
785+
let mut vec = Vec::new();
786+
{
787+
let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r });
788+
value.fold_with(&mut folder);
789+
}
790+
vec
791+
}
792+
782793
impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
783794
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx }
784795

src/librustc/middle/typeck/check/closure.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
199199
debug!("found object type {}", kind);
200200

201201
let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0);
202-
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty);
202+
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
203203
debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
204204

205205
let input_tys = match arg_param_ty.sty {
@@ -209,7 +209,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
209209
debug!("input_tys {}", input_tys.repr(tcx));
210210

211211
let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1);
212-
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty);
212+
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
213213
debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
214214

215215
let fn_sig = ty::FnSig {

src/librustc/middle/typeck/check/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,7 +1626,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
16261626

16271627
pub fn default_diverging_type_variables_to_nil(&self) {
16281628
for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() {
1629-
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) {
1629+
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) {
16301630
demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx()));
16311631
}
16321632
}
@@ -2563,7 +2563,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
25632563
let method_type = match method {
25642564
Some(ref method) => method.ty,
25652565
None => {
2566-
let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type);
2566+
let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type);
25672567

25682568
if !ty::type_is_error(true_expr_type) {
25692569
let ty_string = fcx.infcx().ty_to_string(true_expr_type);
@@ -4468,11 +4468,11 @@ impl<'tcx> Expectation<'tcx> {
44684468
}
44694469
ExpectCastableToType(t) => {
44704470
ExpectCastableToType(
4471-
fcx.infcx().resolve_type_vars_if_possible(t))
4471+
fcx.infcx().resolve_type_vars_if_possible(&t))
44724472
}
44734473
ExpectHasType(t) => {
44744474
ExpectHasType(
4475-
fcx.infcx().resolve_type_vars_if_possible(t))
4475+
fcx.infcx().resolve_type_vars_if_possible(&t))
44764476
}
44774477
}
44784478
}

src/librustc/middle/typeck/check/vtable.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,7 @@ fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &Obligation<'
316316
-> (Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)
317317
{
318318
let trait_ref =
319-
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
320-
&*obligation.trait_ref);
319+
fcx.infcx().resolve_type_vars_if_possible(&*obligation.trait_ref);
321320
let self_ty =
322321
trait_ref.substs.self_ty().unwrap();
323322
(Rc::new(trait_ref), self_ty)
@@ -371,8 +370,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
371370
}
372371
OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
373372
let expected_trait_ref =
374-
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
375-
&**expected_trait_ref);
373+
fcx.infcx().resolve_type_vars_if_possible(&**expected_trait_ref);
376374
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
377375
if !ty::type_is_error(self_ty) {
378376
fcx.tcx().sess.span_err(

src/librustc/middle/typeck/infer/coercion.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
284284
let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
285285
r_borrow,
286286
ty::mt{ty: ty, mutbl: mt_b.mutbl});
287-
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
287+
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
288288
debug!("Success, coerced with AutoDerefRef(1, \
289289
AutoPtr(AutoUnsize({})))", kind);
290290
Ok(Some(AdjustDerefRef(AutoDerefRef {
@@ -307,7 +307,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
307307

308308
let ty = ty::mk_ptr(self.get_ref().infcx.tcx,
309309
ty::mt{ty: ty, mutbl: mt_b.mutbl});
310-
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
310+
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
311311
debug!("Success, coerced with AutoDerefRef(1, \
312312
AutoPtr(AutoUnsize({})))", kind);
313313
Ok(Some(AdjustDerefRef(AutoDerefRef {
@@ -325,7 +325,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
325325
match self.unsize_ty(t_a, sty_a, t_b) {
326326
Some((ty, kind)) => {
327327
let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
328-
try!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
328+
try!(self.get_ref().infcx.try(|_| sub.tys(ty, b)));
329329
debug!("Success, coerced with AutoDerefRef(1, \
330330
AutoUnsizeUniq({}))", kind);
331331
Ok(Some(AdjustDerefRef(AutoDerefRef {
@@ -382,7 +382,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
382382
let mut result = None;
383383
let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
384384
for (i, (tp_a, tp_b)) in tps {
385-
if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
385+
if self.get_ref().infcx.try(|_| sub.tys(*tp_a, *tp_b)).is_ok() {
386386
continue;
387387
}
388388
match
@@ -395,7 +395,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
395395
let mut new_substs = substs_a.clone();
396396
new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp;
397397
let ty = ty::mk_struct(tcx, did_a, new_substs);
398-
if self.get_ref().infcx.try(|| sub.tys(ty, ty_b)).is_err() {
398+
if self.get_ref().infcx.try(|_| sub.tys(ty, ty_b)).is_err() {
399399
debug!("Unsized type parameter '{}', but still \
400400
could not match types {} and {}",
401401
ppaux::ty_to_string(tcx, *tp_a),

src/librustc/middle/typeck/infer/combine.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -707,14 +707,38 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
707707

708708
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
709709
match r {
710-
ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
711-
_ if self.make_region_vars => {
712-
// FIXME: This is non-ideal because we don't give a
713-
// very descriptive origin for this region variable.
714-
self.infcx.next_region_var(MiscVariable(self.span))
710+
// Never make variables for regions bound within the type itself.
711+
ty::ReLateBound(..) => { return r; }
712+
713+
// Early-bound regions should really have been substituted away before
714+
// we get to this point.
715+
ty::ReEarlyBound(..) => {
716+
self.tcx().sess.span_bug(
717+
self.span,
718+
format!("Encountered early bound region when generalizing: {}",
719+
r.repr(self.tcx()))[]);
720+
}
721+
722+
// Always make a fresh region variable for skolemized regions;
723+
// the higher-ranked decision procedures rely on this.
724+
ty::ReInfer(ty::ReSkolemized(..)) => { }
725+
726+
// For anything else, we make a region variable, unless we
727+
// are *equating*, in which case it's just wasteful.
728+
ty::ReEmpty |
729+
ty::ReStatic |
730+
ty::ReScope(..) |
731+
ty::ReInfer(ty::ReVar(..)) |
732+
ty::ReFree(..) => {
733+
if !self.make_region_vars {
734+
return r;
735+
}
715736
}
716-
_ => r,
717737
}
738+
739+
// FIXME: This is non-ideal because we don't give a
740+
// very descriptive origin for this region variable.
741+
self.infcx.next_region_var(MiscVariable(self.span))
718742
}
719743
}
720744

src/librustc/middle/typeck/infer/error_reporting.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,7 +1676,7 @@ pub trait Resolvable<'tcx> {
16761676

16771677
impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
16781678
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>) -> Ty<'tcx> {
1679-
infcx.resolve_type_vars_if_possible(*self)
1679+
infcx.resolve_type_vars_if_possible(self)
16801680
}
16811681
fn contains_error(&self) -> bool {
16821682
ty::type_is_error(*self)
@@ -1686,7 +1686,7 @@ impl<'tcx> Resolvable<'tcx> for Ty<'tcx> {
16861686
impl<'tcx> Resolvable<'tcx> for Rc<ty::TraitRef<'tcx>> {
16871687
fn resolve<'a>(&self, infcx: &InferCtxt<'a, 'tcx>)
16881688
-> Rc<ty::TraitRef<'tcx>> {
1689-
Rc::new(infcx.resolve_type_vars_in_trait_ref_if_possible(&**self))
1689+
Rc::new(infcx.resolve_type_vars_if_possible(&**self))
16901690
}
16911691
fn contains_error(&self) -> bool {
16921692
ty::trait_ref_contains_error(&**self)

src/librustc/middle/typeck/infer/higher_ranked/doc.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -249,19 +249,21 @@
249249
//! in T and try to, in some cases, replace them with bound regions to
250250
//! yield the final result.
251251
//!
252-
//! To decide whether to replace a region `R` that appears in `T` with a
253-
//! bound region, the algorithms make use of two bits of information.
254-
//! First is a set `V` that contains all region variables created as part
255-
//! of the LUB/GLB computation. `V` will contain the region variables
256-
//! created to replace the bound regions in the input types, but it also
257-
//! contains 'intermediate' variables created to represent the LUB/GLB of
258-
//! individual regions. Basically, when asked to compute the LUB/GLB of a
259-
//! region variable with another region, the inferencer cannot oblige
260-
//! immediately since the values of that variables are not known.
261-
//! Therefore, it creates a new variable that is related to the two
262-
//! regions. For example, the LUB of two variables `$x` and `$y` is a
263-
//! fresh variable `$z` that is constrained such that `$x <= $z` and `$y
264-
//! <= $z`. So `V` will contain these intermediate variables as well.
252+
//! To decide whether to replace a region `R` that appears in `T` with
253+
//! a bound region, the algorithms make use of two bits of
254+
//! information. First is a set `V` that contains all region
255+
//! variables created as part of the LUB/GLB computation (roughly; see
256+
//! `region_vars_confined_to_snapshot()` for full details). `V` will
257+
//! contain the region variables created to replace the bound regions
258+
//! in the input types, but it also contains 'intermediate' variables
259+
//! created to represent the LUB/GLB of individual regions.
260+
//! Basically, when asked to compute the LUB/GLB of a region variable
261+
//! with another region, the inferencer cannot oblige immediately
262+
//! since the values of that variables are not known. Therefore, it
263+
//! creates a new variable that is related to the two regions. For
264+
//! example, the LUB of two variables `$x` and `$y` is a fresh
265+
//! variable `$z` that is constrained such that `$x <= $z` and `$y <=
266+
//! $z`. So `V` will contain these intermediate variables as well.
265267
//!
266268
//! The other important factor in deciding how to replace a region in T is
267269
//! the function `Tainted($r)` which, for a region variable, identifies

0 commit comments

Comments
 (0)