Skip to content

Commit 3ed4a42

Browse files
committed
Introduce new inference scheme: variables are now instantiated with at most one type, and region variables are introduced as needed
1 parent d6e5797 commit 3ed4a42

36 files changed

+797
-709
lines changed

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

+145-69
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,29 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ______________________________________________________________________
12-
// Type combining
11+
///////////////////////////////////////////////////////////////////////////
12+
// # Type combining
1313
//
14-
// There are three type combiners: sub, lub, and glb. Each implements
15-
// the trait `Combine` and contains methods for combining two
16-
// instances of various things and yielding a new instance. These
17-
// combiner methods always yield a `result<T>`---failure is propagated
18-
// upward using `and_then()` methods. There is a lot of common code for
19-
// these operations, implemented as default methods on the `Combine`
20-
// trait.
14+
// There are four type combiners: equate, sub, lub, and glb. Each
15+
// implements the trait `Combine` and contains methods for combining
16+
// two instances of various things and yielding a new instance. These
17+
// combiner methods always yield a `Result<T>`. There is a lot of
18+
// common code for these operations, implemented as default methods on
19+
// the `Combine` trait.
2120
//
22-
// In reality, the sub operation is rather different from lub/glb, but
23-
// they are combined into one trait to avoid duplication (they used to
24-
// be separate but there were many bugs because there were two copies
25-
// of most routines).
21+
// Each operation may have side-effects on the inference context,
22+
// though these can be unrolled using snapshots. On success, the
23+
// LUB/GLB operations return the appropriate bound. The Eq and Sub
24+
// operations generally return the first operand.
2625
//
27-
// The differences are:
28-
//
29-
// - when making two things have a sub relationship, the order of the
30-
// arguments is significant (a <: b) and the return value of the
31-
// combine functions is largely irrelevant. The important thing is
32-
// whether the action succeeds or fails. If it succeeds, then side
33-
// effects have been committed into the type variables.
34-
//
35-
// - for GLB/LUB, the order of arguments is not significant (GLB(a,b) ==
36-
// GLB(b,a)) and the return value is important (it is the GLB). Of
37-
// course GLB/LUB may also have side effects.
38-
//
39-
// Contravariance
26+
// ## Contravariance
4027
//
4128
// When you are relating two things which have a contravariant
4229
// relationship, you should use `contratys()` or `contraregions()`,
4330
// rather than inversing the order of arguments! This is necessary
4431
// because the order of arguments is not relevant for LUB and GLB. It
4532
// is also useful to track which value is the "expected" value in
46-
// terms of error reporting, although we do not do that properly right
47-
// now.
33+
// terms of error reporting.
4834

4935

5036
use middle::subst;
@@ -53,14 +39,16 @@ use middle::ty::{FloatVar, FnSig, IntVar, TyVar};
5339
use middle::ty::{IntType, UintType};
5440
use middle::ty::{BuiltinBounds};
5541
use middle::ty;
56-
use middle::typeck::infer::{ToUres};
42+
use middle::typeck::infer::equate::Equate;
5743
use middle::typeck::infer::glb::Glb;
5844
use middle::typeck::infer::lub::Lub;
5945
use middle::typeck::infer::sub::Sub;
6046
use middle::typeck::infer::unify::InferCtxtMethodsForSimplyUnifiableTypes;
61-
use middle::typeck::infer::{InferCtxt, cres, ures};
62-
use middle::typeck::infer::{TypeTrace};
63-
use util::common::indent;
47+
use middle::typeck::infer::{InferCtxt, cres};
48+
use middle::typeck::infer::{MiscVariable, TypeTrace};
49+
use middle::typeck::infer::type_variable::{RelationDir, EqTo,
50+
SubtypeOf, SupertypeOf};
51+
use middle::ty_fold::{RegionFolder, TypeFoldable};
6452
use util::ppaux::Repr;
6553

6654
use std::result;
@@ -75,6 +63,7 @@ pub trait Combine {
7563
fn a_is_expected(&self) -> bool;
7664
fn trace(&self) -> TypeTrace;
7765

66+
fn equate<'a>(&'a self) -> Equate<'a>;
7867
fn sub<'a>(&'a self) -> Sub<'a>;
7968
fn lub<'a>(&'a self) -> Lub<'a>;
8069
fn glb<'a>(&'a self) -> Glb<'a>;
@@ -101,7 +90,7 @@ pub trait Combine {
10190
try!(result::fold_(as_
10291
.iter()
10392
.zip(bs.iter())
104-
.map(|(a, b)| eq_tys(self, *a, *b))));
93+
.map(|(a, b)| self.equate().tys(*a, *b))));
10594
Ok(Vec::from_slice(as_))
10695
}
10796

@@ -177,10 +166,7 @@ pub trait Combine {
177166
let b_r = b_rs[i];
178167
let variance = variances[i];
179168
let r = match variance {
180-
ty::Invariant => {
181-
eq_regions(this, a_r, b_r)
182-
.and_then(|()| Ok(a_r))
183-
}
169+
ty::Invariant => this.equate().regions(a_r, b_r),
184170
ty::Covariant => this.regions(a_r, b_r),
185171
ty::Contravariant => this.contraregions(a_r, b_r),
186172
ty::Bivariant => Ok(a_r),
@@ -334,34 +320,6 @@ pub fn expected_found<C:Combine,T>(
334320
}
335321
}
336322

337-
pub fn eq_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> ures {
338-
let suber = this.sub();
339-
this.infcx().try(|| {
340-
suber.tys(a, b).and_then(|_ok| suber.contratys(a, b)).to_ures()
341-
})
342-
}
343-
344-
pub fn eq_regions<C:Combine>(this: &C, a: ty::Region, b: ty::Region)
345-
-> ures {
346-
debug!("eq_regions({}, {})",
347-
a.repr(this.infcx().tcx),
348-
b.repr(this.infcx().tcx));
349-
let sub = this.sub();
350-
indent(|| {
351-
this.infcx().try(|| {
352-
sub.regions(a, b).and_then(|_r| sub.contraregions(a, b))
353-
}).or_else(|e| {
354-
// substitute a better error, but use the regions
355-
// found in the original error
356-
match e {
357-
ty::terr_regions_does_not_outlive(a1, b1) =>
358-
Err(ty::terr_regions_not_same(a1, b1)),
359-
_ => Err(e)
360-
}
361-
}).to_ures()
362-
})
363-
}
364-
365323
pub fn super_fn_sigs<C:Combine>(this: &C, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
366324

367325
fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<Vec<ty::t> > {
@@ -453,8 +411,7 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
453411

454412
// Relate floating-point variables to other types
455413
(&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
456-
try!(this.infcx().simple_vars(this.a_is_expected(),
457-
a_id, b_id));
414+
try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
458415
Ok(a)
459416
}
460417
(&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
@@ -469,7 +426,8 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
469426
(&ty::ty_bool, _) |
470427
(&ty::ty_int(_), _) |
471428
(&ty::ty_uint(_), _) |
472-
(&ty::ty_float(_), _) => {
429+
(&ty::ty_float(_), _) |
430+
(&ty::ty_err, _) => {
473431
if ty::get(a).sty == ty::get(b).sty {
474432
Ok(a)
475433
} else {
@@ -512,7 +470,10 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
512470
(&ty::ty_unboxed_closure(a_id, a_region),
513471
&ty::ty_unboxed_closure(b_id, b_region))
514472
if a_id == b_id => {
515-
let region = if_ok!(this.regions(a_region, b_region));
473+
// All ty_unboxed_closure types with the same id represent
474+
// the (anonymous) type of the same closure expression. So
475+
// all of their regions should be equated.
476+
let region = try!(this.equate().regions(a_region, b_region));
516477
Ok(ty::mk_unboxed_closure(tcx, a_id, region))
517478
}
518479

@@ -609,3 +570,118 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
609570
Ok(ty::mk_mach_float(val))
610571
}
611572
}
573+
574+
impl<'f> CombineFields<'f> {
575+
pub fn switch_expected(&self) -> CombineFields<'f> {
576+
CombineFields {
577+
a_is_expected: !self.a_is_expected,
578+
..(*self).clone()
579+
}
580+
}
581+
582+
fn equate(&self) -> Equate<'f> {
583+
Equate((*self).clone())
584+
}
585+
586+
fn sub(&self) -> Sub<'f> {
587+
Sub((*self).clone())
588+
}
589+
590+
pub fn instantiate(&self,
591+
a_ty: ty::t,
592+
dir: RelationDir,
593+
b_vid: ty::TyVid)
594+
-> cres<()>
595+
{
596+
let tcx = self.infcx.tcx;
597+
let mut stack = Vec::new();
598+
stack.push((a_ty, dir, b_vid));
599+
loop {
600+
// For each turn of the loop, we extract a tuple
601+
//
602+
// (a_ty, dir, b_vid)
603+
//
604+
// to relate. Here dir is either SubtypeOf or
605+
// SupertypeOf. The idea is that we should ensure that
606+
// the type `a_ty` is a subtype or supertype (respectively) of the
607+
// type to which `b_vid` is bound.
608+
//
609+
// If `b_vid` has not yet been instantiated with a type
610+
// (which is always true on the first iteration, but not
611+
// necessarily true on later iterations), we will first
612+
// instantiate `b_vid` with a *generalized* version of
613+
// `a_ty`. Generalization introduces other inference
614+
// variables whereever subtyping could occur (at time of
615+
// this writing, this means replacing free regions with
616+
// region variables).
617+
let (a_ty, dir, b_vid) = match stack.pop() {
618+
None => break,
619+
Some(e) => e,
620+
};
621+
622+
debug!("instantiate(a_ty={} dir={} b_vid={})",
623+
a_ty.repr(tcx),
624+
dir,
625+
b_vid.repr(tcx));
626+
627+
// Check whether `vid` has been instantiated yet. If not,
628+
// make a generalized form of `ty` and instantiate with
629+
// that.
630+
let b_ty = self.infcx.type_variables.borrow().probe(b_vid);
631+
let b_ty = match b_ty {
632+
Some(t) => t, // ...already instantiated.
633+
None => { // ...not yet instantiated:
634+
// Generalize type if necessary.
635+
let generalized_ty = match dir {
636+
EqTo => a_ty,
637+
SupertypeOf | SubtypeOf => self.generalize(a_ty)
638+
};
639+
debug!("instantiate(a_ty={}, dir={}, \
640+
b_vid={}, generalized_ty={})",
641+
a_ty.repr(tcx), dir, b_vid.repr(tcx),
642+
generalized_ty.repr(tcx));
643+
self.infcx.type_variables
644+
.borrow_mut()
645+
.instantiate_and_push(
646+
b_vid, generalized_ty, &mut stack);
647+
generalized_ty
648+
}
649+
};
650+
651+
// The original triple was `(a_ty, dir, b_vid)` -- now we have
652+
// resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`:
653+
//
654+
// FIXME: This code is non-ideal because all these subtype
655+
// relations wind up attributed to the same spans. We need
656+
// to associate causes/spans with each of the relations in
657+
// the stack to get this right.
658+
match dir {
659+
EqTo => {
660+
try!(self.equate().tys(a_ty, b_ty));
661+
}
662+
663+
SubtypeOf => {
664+
try!(self.sub().tys(a_ty, b_ty));
665+
}
666+
667+
SupertypeOf => {
668+
try!(self.sub().contratys(a_ty, b_ty));
669+
}
670+
}
671+
}
672+
673+
Ok(())
674+
}
675+
676+
fn generalize(&self, t: ty::t) -> ty::t {
677+
// FIXME: This is non-ideal because we don't give a very descriptive
678+
// origin for this region variable.
679+
680+
let infcx = self.infcx;
681+
let span = self.trace.origin.span();
682+
t.fold_with(
683+
&mut RegionFolder::regions(
684+
self.infcx.tcx,
685+
|_| infcx.next_region_var(MiscVariable(span))))
686+
}
687+
}

0 commit comments

Comments
 (0)