// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ______________________________________________________________________
-// Type combining
+///////////////////////////////////////////////////////////////////////////
+// # Type combining
//
-// There are three type combiners: sub, lub, and glb. Each implements
-// the trait `Combine` and contains methods for combining two
-// instances of various things and yielding a new instance. These
-// combiner methods always yield a `result<T>`---failure is propagated
-// upward using `and_then()` methods. There is a lot of common code for
-// these operations, implemented as default methods on the `Combine`
-// trait.
+// There are four type combiners: equate, sub, lub, and glb. Each
+// implements the trait `Combine` and contains methods for combining
+// two instances of various things and yielding a new instance. These
+// combiner methods always yield a `Result<T>`. There is a lot of
+// common code for these operations, implemented as default methods on
+// the `Combine` trait.
//
-// In reality, the sub operation is rather different from lub/glb, but
-// they are combined into one trait to avoid duplication (they used to
-// be separate but there were many bugs because there were two copies
-// of most routines).
+// Each operation may have side-effects on the inference context,
+// though these can be unrolled using snapshots. On success, the
+// LUB/GLB operations return the appropriate bound. The Eq and Sub
+// operations generally return the first operand.
//
-// The differences are:
-//
-// - when making two things have a sub relationship, the order of the
-// arguments is significant (a <: b) and the return value of the
-// combine functions is largely irrelevant. The important thing is
-// whether the action succeeds or fails. If it succeeds, then side
-// effects have been committed into the type variables.
-//
-// - for GLB/LUB, the order of arguments is not significant (GLB(a,b) ==
-// GLB(b,a)) and the return value is important (it is the GLB). Of
-// course GLB/LUB may also have side effects.
-//
-// Contravariance
+// ## Contravariance
//
// When you are relating two things which have a contravariant
// relationship, you should use `contratys()` or `contraregions()`,
// rather than inversing the order of arguments! This is necessary
// because the order of arguments is not relevant for LUB and GLB. It
// is also useful to track which value is the "expected" value in
-// terms of error reporting, although we do not do that properly right
-// now.
+// terms of error reporting.
use middle::subst;
use middle::ty::{IntType, UintType};
use middle::ty::{BuiltinBounds};
use middle::ty;
-use middle::typeck::infer::{ToUres};
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::unify::InferCtxtMethodsForSimplyUnifiableTypes;
-use middle::typeck::infer::{InferCtxt, cres, ures};
-use middle::typeck::infer::{TypeTrace};
-use util::common::indent;
+use middle::typeck::infer::{InferCtxt, cres};
+use middle::typeck::infer::{MiscVariable, TypeTrace};
+use middle::typeck::infer::type_variable::{RelationDir, EqTo,
+ SubtypeOf, SupertypeOf};
+use middle::ty_fold::{RegionFolder, TypeFoldable};
use util::ppaux::Repr;
use std::result;
fn a_is_expected(&self) -> bool;
fn trace(&self) -> TypeTrace;
+ fn equate<'a>(&'a self) -> Equate<'a>;
fn sub<'a>(&'a self) -> Sub<'a>;
fn lub<'a>(&'a self) -> Lub<'a>;
fn glb<'a>(&'a self) -> Glb<'a>;
try!(result::fold_(as_
.iter()
.zip(bs.iter())
- .map(|(a, b)| eq_tys(self, *a, *b))));
+ .map(|(a, b)| self.equate().tys(*a, *b))));
Ok(Vec::from_slice(as_))
}
let b_r = b_rs[i];
let variance = variances[i];
let r = match variance {
- ty::Invariant => {
- eq_regions(this, a_r, b_r)
- .and_then(|()| Ok(a_r))
- }
+ ty::Invariant => this.equate().regions(a_r, b_r),
ty::Covariant => this.regions(a_r, b_r),
ty::Contravariant => this.contraregions(a_r, b_r),
ty::Bivariant => Ok(a_r),
}
}
-pub fn eq_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> ures {
- let suber = this.sub();
- this.infcx().try(|| {
- suber.tys(a, b).and_then(|_ok| suber.contratys(a, b)).to_ures()
- })
-}
-
-pub fn eq_regions<C:Combine>(this: &C, a: ty::Region, b: ty::Region)
- -> ures {
- debug!("eq_regions({}, {})",
- a.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx));
- let sub = this.sub();
- indent(|| {
- this.infcx().try(|| {
- sub.regions(a, b).and_then(|_r| sub.contraregions(a, b))
- }).or_else(|e| {
- // substitute a better error, but use the regions
- // found in the original error
- match e {
- ty::terr_regions_does_not_outlive(a1, b1) =>
- Err(ty::terr_regions_not_same(a1, b1)),
- _ => Err(e)
- }
- }).to_ures()
- })
-}
-
pub fn super_fn_sigs<C:Combine>(this: &C, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
fn argvecs<C:Combine>(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<Vec<ty::t> > {
// Relate floating-point variables to other types
(&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => {
- try!(this.infcx().simple_vars(this.a_is_expected(),
- a_id, b_id));
+ try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id));
Ok(a)
}
(&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => {
(&ty::ty_bool, _) |
(&ty::ty_int(_), _) |
(&ty::ty_uint(_), _) |
- (&ty::ty_float(_), _) => {
+ (&ty::ty_float(_), _) |
+ (&ty::ty_err, _) => {
if ty::get(a).sty == ty::get(b).sty {
Ok(a)
} else {
(&ty::ty_unboxed_closure(a_id, a_region),
&ty::ty_unboxed_closure(b_id, b_region))
if a_id == b_id => {
- let region = if_ok!(this.regions(a_region, b_region));
+ // All ty_unboxed_closure types with the same id represent
+ // the (anonymous) type of the same closure expression. So
+ // all of their regions should be equated.
+ let region = try!(this.equate().regions(a_region, b_region));
Ok(ty::mk_unboxed_closure(tcx, a_id, region))
}
Ok(ty::mk_mach_float(val))
}
}
+
+impl<'f> CombineFields<'f> {
+ pub fn switch_expected(&self) -> CombineFields<'f> {
+ CombineFields {
+ a_is_expected: !self.a_is_expected,
+ ..(*self).clone()
+ }
+ }
+
+ fn equate(&self) -> Equate<'f> {
+ Equate((*self).clone())
+ }
+
+ fn sub(&self) -> Sub<'f> {
+ Sub((*self).clone())
+ }
+
+ pub fn instantiate(&self,
+ a_ty: ty::t,
+ dir: RelationDir,
+ b_vid: ty::TyVid)
+ -> cres<()>
+ {
+ let tcx = self.infcx.tcx;
+ let mut stack = Vec::new();
+ stack.push((a_ty, dir, b_vid));
+ loop {
+ // For each turn of the loop, we extract a tuple
+ //
+ // (a_ty, dir, b_vid)
+ //
+ // to relate. Here dir is either SubtypeOf or
+ // SupertypeOf. The idea is that we should ensure that
+ // the type `a_ty` is a subtype or supertype (respectively) of the
+ // type to which `b_vid` is bound.
+ //
+ // If `b_vid` has not yet been instantiated with a type
+ // (which is always true on the first iteration, but not
+ // necessarily true on later iterations), we will first
+ // instantiate `b_vid` with a *generalized* version of
+ // `a_ty`. Generalization introduces other inference
+ // variables wherever subtyping could occur (at time of
+ // this writing, this means replacing free regions with
+ // region variables).
+ let (a_ty, dir, b_vid) = match stack.pop() {
+ None => break,
+ Some(e) => e,
+ };
+
+ debug!("instantiate(a_ty={} dir={} b_vid={})",
+ a_ty.repr(tcx),
+ dir,
+ b_vid.repr(tcx));
+
+ // Check whether `vid` has been instantiated yet. If not,
+ // make a generalized form of `ty` and instantiate with
+ // that.
+ let b_ty = self.infcx.type_variables.borrow().probe(b_vid);
+ let b_ty = match b_ty {
+ Some(t) => t, // ...already instantiated.
+ None => { // ...not yet instantiated:
+ // Generalize type if necessary.
+ let generalized_ty = match dir {
+ EqTo => a_ty,
+ SupertypeOf | SubtypeOf => self.generalize(a_ty)
+ };
+ debug!("instantiate(a_ty={}, dir={}, \
+ b_vid={}, generalized_ty={})",
+ a_ty.repr(tcx), dir, b_vid.repr(tcx),
+ generalized_ty.repr(tcx));
+ self.infcx.type_variables
+ .borrow_mut()
+ .instantiate_and_push(
+ b_vid, generalized_ty, &mut stack);
+ generalized_ty
+ }
+ };
+
+ // The original triple was `(a_ty, dir, b_vid)` -- now we have
+ // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`:
+ //
+ // FIXME: This code is non-ideal because all these subtype
+ // relations wind up attributed to the same spans. We need
+ // to associate causes/spans with each of the relations in
+ // the stack to get this right.
+ match dir {
+ EqTo => {
+ try!(self.equate().tys(a_ty, b_ty));
+ }
+
+ SubtypeOf => {
+ try!(self.sub().tys(a_ty, b_ty));
+ }
+
+ SupertypeOf => {
+ try!(self.sub().contratys(a_ty, b_ty));
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn generalize(&self, t: ty::t) -> ty::t {
+ // FIXME: This is non-ideal because we don't give a very descriptive
+ // origin for this region variable.
+
+ let infcx = self.infcx;
+ let span = self.trace.origin.span();
+ t.fold_with(
+ &mut RegionFolder::regions(
+ self.infcx.tcx,
+ |_| infcx.next_region_var(MiscVariable(span))))
+ }
+}
--- /dev/null
+// Copyright 2014 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.
+
+use middle::ty::{BuiltinBounds};
+use middle::ty;
+use middle::ty::TyVar;
+use middle::typeck::infer::combine::*;
+use middle::typeck::infer::{cres};
+use middle::typeck::infer::glb::Glb;
+use middle::typeck::infer::InferCtxt;
+use middle::typeck::infer::lub::Lub;
+use middle::typeck::infer::sub::Sub;
+use middle::typeck::infer::{TypeTrace, Subtype};
+use middle::typeck::infer::type_variable::{EqTo};
+use util::ppaux::{Repr};
+
+use syntax::ast::{Onceness, FnStyle};
+
+pub struct Equate<'f> {
+ fields: CombineFields<'f>
+}
+
+#[allow(non_snake_case_functions)]
+pub fn Equate<'f>(cf: CombineFields<'f>) -> Equate<'f> {
+ Equate { fields: cf }
+}
+
+impl<'f> Combine for Equate<'f> {
+ fn infcx<'a>(&'a self) -> &'a InferCtxt<'a> { self.fields.infcx }
+ fn tag(&self) -> String { "eq".to_string() }
+ fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
+
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
+ fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
+ fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
+ fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
+
+ fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
+ self.tys(a, b)
+ }
+
+ fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
+ self.regions(a, b)
+ }
+
+ fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
+ debug!("{}.regions({}, {})",
+ self.tag(),
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+ self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b);
+ Ok(a)
+ }
+
+ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
+ debug!("mts({} <: {})",
+ a.repr(self.fields.infcx.tcx),
+ b.repr(self.fields.infcx.tcx));
+
+ if a.mutbl != b.mutbl { return Err(ty::terr_mutability); }
+ let t = try!(self.tys(a.ty, b.ty));
+ Ok(ty::mt { mutbl: a.mutbl, ty: t })
+ }
+
+ fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
+ if a != b {
+ Err(ty::terr_fn_style_mismatch(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness> {
+ if a != b {
+ Err(ty::terr_onceness_mismatch(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn builtin_bounds(&self,
+ a: BuiltinBounds,
+ b: BuiltinBounds)
+ -> cres<BuiltinBounds>
+ {
+ // More bounds is a subtype of fewer bounds.
+ //
+ // e.g., fn:Copy() <: fn(), because the former is a function
+ // that only closes over copyable things, but the latter is
+ // any function at all.
+ if a != b {
+ Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+
+ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
+ debug!("{}.tys({}, {})", self.tag(),
+ a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+ if a == b { return Ok(a); }
+
+ let infcx = self.fields.infcx;
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
+ match (&ty::get(a).sty, &ty::get(b).sty) {
+ (&ty::ty_bot, &ty::ty_bot) => {
+ Ok(a)
+ }
+
+ (&ty::ty_bot, _) |
+ (_, &ty::ty_bot) => {
+ Err(ty::terr_sorts(expected_found(self, a, b)))
+ }
+
+ (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+ infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id);
+ Ok(a)
+ }
+
+ (&ty::ty_infer(TyVar(a_id)), _) => {
+ try!(self.fields.instantiate(b, EqTo, a_id));
+ Ok(a)
+ }
+
+ (_, &ty::ty_infer(TyVar(b_id))) => {
+ try!(self.fields.instantiate(a, EqTo, b_id));
+ Ok(a)
+ }
+
+ _ => {
+ super_tys(self, a, b)
+ }
+ }
+ }
+
+ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
+ try!(self.sub().fn_sigs(a, b));
+ self.sub().fn_sigs(b, a)
+ }
+}
use middle::ty::{BuiltinBounds};
use middle::ty::RegionVid;
use middle::ty;
-use middle::typeck::infer::then;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::lattice::*;
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::lub::Lub;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::{cres, InferCtxt};
/// "Greatest lower bound" (common subtype)
pub struct Glb<'f> {
- pub fields: CombineFields<'f>
+ fields: CombineFields<'f>
}
#[allow(non_snake_case_functions)]
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
mt_to_string(tcx, b));
match (a.mutbl, b.mutbl) {
- // If one side or both is mut, then the GLB must use
- // the precise type from the mut side.
- (MutMutable, MutMutable) => {
- eq_tys(self, a.ty, b.ty).then(|| {
- Ok(ty::mt {ty: a.ty, mutbl: MutMutable})
- })
- }
-
- // If one side or both is immutable, we can use the GLB of
- // both sides but mutbl must be `MutImmutable`.
- (MutImmutable, MutImmutable) => {
- self.tys(a.ty, b.ty).and_then(|t| {
+ // If one side or both is mut, then the GLB must use
+ // the precise type from the mut side.
+ (MutMutable, MutMutable) => {
+ let t = try!(self.equate().tys(a.ty, b.ty));
+ Ok(ty::mt {ty: t, mutbl: MutMutable})
+ }
+
+ // If one side or both is immutable, we can use the GLB of
+ // both sides but mutbl must be `MutImmutable`.
+ (MutImmutable, MutImmutable) => {
+ let t = try!(self.tys(a.ty, b.ty));
Ok(ty::mt {ty: t, mutbl: MutImmutable})
- })
- }
-
- // There is no mutual subtype of these combinations.
- (MutMutable, MutImmutable) |
- (MutImmutable, MutMutable) => {
- Err(ty::terr_mutability)
- }
+ }
+
+ // There is no mutual subtype of these combinations.
+ (MutMutable, MutImmutable) |
+ (MutImmutable, MutMutable) => {
+ Err(ty::terr_mutability)
+ }
}
}
use middle::ty::{RegionVid, TyVar};
use middle::ty;
-use middle::typeck::infer::{ToUres};
use middle::typeck::infer::*;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::unify::*;
-use middle::typeck::infer::sub::Sub;
use util::ppaux::Repr;
use std::collections::HashMap;
-trait LatticeValue : Clone + Repr + PartialEq {
- fn sub(cf: CombineFields, a: &Self, b: &Self) -> ures;
- fn lub(cf: CombineFields, a: &Self, b: &Self) -> cres<Self>;
- fn glb(cf: CombineFields, a: &Self, b: &Self) -> cres<Self>;
-}
-
-pub type LatticeOp<'a, T> =
- |cf: CombineFields, a: &T, b: &T|: 'a -> cres<T>;
-
-impl LatticeValue for ty::t {
- fn sub(cf: CombineFields, a: &ty::t, b: &ty::t) -> ures {
- Sub(cf).tys(*a, *b).to_ures()
- }
-
- fn lub(cf: CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
- Lub(cf).tys(*a, *b)
- }
-
- fn glb(cf: CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
- Glb(cf).tys(*a, *b)
- }
-}
-
-pub trait CombineFieldsLatticeMethods<T:LatticeValue, K:UnifyKey<Bounds<T>>> {
- /// make variable a subtype of variable
- fn var_sub_var(&self,
- a_id: K,
- b_id: K)
- -> ures;
-
- /// make variable a subtype of T
- fn var_sub_t(&self,
- a_id: K,
- b: T)
- -> ures;
-
- /// make T a subtype of variable
- fn t_sub_var(&self,
- a: T,
- b_id: K)
- -> ures;
-
- fn set_var_to_merged_bounds(&self,
- v_id: K,
- a: &Bounds<T>,
- b: &Bounds<T>,
- rank: uint)
- -> ures;
-}
-
-pub trait CombineFieldsLatticeMethods2<T:LatticeValue> {
- fn merge_bnd(&self,
- a: &Bound<T>,
- b: &Bound<T>,
- lattice_op: LatticeOp<T>)
- -> cres<Bound<T>>;
-
- fn bnds(&self, a: &Bound<T>, b: &Bound<T>) -> ures;
-}
-
-impl<'f,T:LatticeValue, K:UnifyKey<Bounds<T>>>
- CombineFieldsLatticeMethods<T,K> for CombineFields<'f>
-{
- fn var_sub_var(&self,
- a_id: K,
- b_id: K)
- -> ures
- {
- /*!
- * Make one variable a subtype of another variable. This is a
- * subtle and tricky process, as described in detail at the
- * top of infer.rs.
- */
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
-
- // Need to make sub_id a subtype of sup_id.
- let node_a = table.borrow_mut().get(tcx, a_id);
- let node_b = table.borrow_mut().get(tcx, b_id);
- let a_id = node_a.key.clone();
- let b_id = node_b.key.clone();
- let a_bounds = node_a.value.clone();
- let b_bounds = node_b.value.clone();
-
- debug!("vars({}={} <: {}={})",
- a_id, a_bounds.repr(tcx),
- b_id, b_bounds.repr(tcx));
-
- if a_id == b_id { return Ok(()); }
-
- // If both A's UB and B's LB have already been bound to types,
- // see if we can make those types subtypes.
- match (&a_bounds.ub, &b_bounds.lb) {
- (&Some(ref a_ub), &Some(ref b_lb)) => {
- let r = self.infcx.try(
- || LatticeValue::sub(self.clone(), a_ub, b_lb));
- match r {
- Ok(()) => {
- return Ok(());
- }
- Err(_) => { /*fallthrough */ }
- }
- }
- _ => { /*fallthrough*/ }
- }
-
- // Otherwise, we need to merge A and B so as to guarantee that
- // A remains a subtype of B. Actually, there are other options,
- // but that's the route we choose to take.
-
- let (new_root, new_rank) =
- table.borrow_mut().unify(tcx, &node_a, &node_b);
- self.set_var_to_merged_bounds(new_root,
- &a_bounds, &b_bounds,
- new_rank)
- }
-
- /// make variable a subtype of T
- fn var_sub_t(&self,
- a_id: K,
- b: T)
- -> ures
- {
- /*!
- * Make a variable (`a_id`) a subtype of the concrete type `b`.
- */
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
- let node_a = table.borrow_mut().get(tcx, a_id);
- let a_id = node_a.key.clone();
- let a_bounds = &node_a.value;
- let b_bounds = &Bounds { lb: None, ub: Some(b.clone()) };
-
- debug!("var_sub_t({}={} <: {})",
- a_id,
- a_bounds.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
-
- self.set_var_to_merged_bounds(
- a_id, a_bounds, b_bounds, node_a.rank)
- }
-
- fn t_sub_var(&self,
- a: T,
- b_id: K)
- -> ures
- {
- /*!
- * Make a concrete type (`a`) a subtype of the variable `b_id`
- */
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
- let a_bounds = &Bounds { lb: Some(a.clone()), ub: None };
- let node_b = table.borrow_mut().get(tcx, b_id);
- let b_id = node_b.key.clone();
- let b_bounds = &node_b.value;
-
- debug!("t_sub_var({} <: {}={})",
- a.repr(self.infcx.tcx),
- b_id,
- b_bounds.repr(self.infcx.tcx));
-
- self.set_var_to_merged_bounds(
- b_id, a_bounds, b_bounds, node_b.rank)
- }
-
- fn set_var_to_merged_bounds(&self,
- v_id: K,
- a: &Bounds<T>,
- b: &Bounds<T>,
- rank: uint)
- -> ures
- {
- /*!
- * Updates the bounds for the variable `v_id` to be the intersection
- * of `a` and `b`. That is, the new bounds for `v_id` will be
- * a bounds c such that:
- * c.ub <: a.ub
- * c.ub <: b.ub
- * a.lb <: c.lb
- * b.lb <: c.lb
- * If this cannot be achieved, the result is failure.
- */
-
- // Think of the two diamonds, we want to find the
- // intersection. There are basically four possibilities (you
- // can swap A/B in these pictures):
- //
- // A A
- // / \ / \
- // / B \ / B \
- // / / \ \ / / \ \
- // * * * * * / * *
- // \ \ / / \ / /
- // \ B / / \ / /
- // \ / * \ /
- // A \ / A
- // B
-
- let tcx = self.infcx.tcx;
- let table = UnifyKey::unification_table(self.infcx);
-
- debug!("merge({},{},{})",
- v_id,
- a.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
-
- // First, relate the lower/upper bounds of A and B.
- // Note that these relations *must* hold for us
- // to be able to merge A and B at all, and relating
- // them explicitly gives the type inferencer more
- // information and helps to produce tighter bounds
- // when necessary.
- let () = if_ok!(self.bnds(&a.lb, &b.ub));
- let () = if_ok!(self.bnds(&b.lb, &a.ub));
- let ub = if_ok!(self.merge_bnd(&a.ub, &b.ub, LatticeValue::glb));
- let lb = if_ok!(self.merge_bnd(&a.lb, &b.lb, LatticeValue::lub));
- let bounds = Bounds { lb: lb, ub: ub };
- debug!("merge({}): bounds={}",
- v_id,
- bounds.repr(self.infcx.tcx));
-
- // the new bounds must themselves
- // be relatable:
- let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub));
- table.borrow_mut().set(tcx, v_id, Root(bounds, rank));
- Ok(())
- }
-}
-
-impl<'f,T:LatticeValue>
- CombineFieldsLatticeMethods2<T> for CombineFields<'f>
-{
- fn merge_bnd(&self,
- a: &Bound<T>,
- b: &Bound<T>,
- lattice_op: LatticeOp<T>)
- -> cres<Bound<T>>
- {
- /*!
- * Combines two bounds into a more general bound.
- */
-
- debug!("merge_bnd({},{})",
- a.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
- match (a, b) {
- (&None, &None) => Ok(None),
- (&Some(_), &None) => Ok((*a).clone()),
- (&None, &Some(_)) => Ok((*b).clone()),
- (&Some(ref v_a), &Some(ref v_b)) => {
- lattice_op(self.clone(), v_a, v_b).and_then(|v| Ok(Some(v)))
- }
- }
- }
-
- fn bnds(&self,
- a: &Bound<T>,
- b: &Bound<T>)
- -> ures
- {
- debug!("bnds({} <: {})",
- a.repr(self.infcx.tcx),
- b.repr(self.infcx.tcx));
-
- match (a, b) {
- (&None, &None) |
- (&Some(_), &None) |
- (&None, &Some(_)) => {
- Ok(())
- }
- (&Some(ref t_a), &Some(ref t_b)) => {
- LatticeValue::sub(self.clone(), t_a, t_b)
- }
- }
- }
-}
-
-// ______________________________________________________________________
-// Lattice operations on variables
-//
-// This is common code used by both LUB and GLB to compute the LUB/GLB
-// for pairs of variables or for variables and values.
-
pub trait LatticeDir {
- fn combine_fields<'a>(&'a self) -> CombineFields<'a>;
- fn bnd<T:Clone>(&self, b: &Bounds<T>) -> Option<T>;
- fn with_bnd<T:Clone>(&self, b: &Bounds<T>, t: T) -> Bounds<T>;
-}
-
-pub trait TyLatticeDir {
+ // Relates the bottom type to `t` and returns LUB(t, _|_) or
+ // GLB(t, _|_) as appropriate.
fn ty_bot(&self, t: ty::t) -> cres<ty::t>;
-}
-impl<'f> LatticeDir for Lub<'f> {
- fn combine_fields<'a>(&'a self) -> CombineFields<'a> { self.fields.clone() }
- fn bnd<T:Clone>(&self, b: &Bounds<T>) -> Option<T> { b.ub.clone() }
- fn with_bnd<T:Clone>(&self, b: &Bounds<T>, t: T) -> Bounds<T> {
- Bounds { ub: Some(t), ..(*b).clone() }
- }
+ // Relates the type `v` to `a` and `b` such that `v` represents
+ // the LUB/GLB of `a` and `b` as appropriate.
+ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()>;
}
-impl<'f> TyLatticeDir for Lub<'f> {
+impl<'a> LatticeDir for Lub<'a> {
fn ty_bot(&self, t: ty::t) -> cres<ty::t> {
Ok(t)
}
-}
-impl<'f> LatticeDir for Glb<'f> {
- fn combine_fields<'a>(&'a self) -> CombineFields<'a> { self.fields.clone() }
- fn bnd<T:Clone>(&self, b: &Bounds<T>) -> Option<T> { b.lb.clone() }
- fn with_bnd<T:Clone>(&self, b: &Bounds<T>, t: T) -> Bounds<T> {
- Bounds { lb: Some(t), ..(*b).clone() }
+ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
+ let sub = self.sub();
+ try!(sub.tys(a, v));
+ try!(sub.tys(b, v));
+ Ok(())
}
}
-impl<'f> TyLatticeDir for Glb<'f> {
- fn ty_bot(&self, _t: ty::t) -> cres<ty::t> {
+impl<'a> LatticeDir for Glb<'a> {
+ fn ty_bot(&self, _: ty::t) -> cres<ty::t> {
Ok(ty::mk_bot())
}
+
+ fn relate_bound<'a>(&'a self, v: ty::t, a: ty::t, b: ty::t) -> cres<()> {
+ let sub = self.sub();
+ try!(sub.tys(v, a));
+ try!(sub.tys(v, b));
+ Ok(())
+ }
}
-pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
- a: ty::t,
- b: ty::t)
- -> cres<ty::t> {
+pub fn super_lattice_tys<L:LatticeDir+Combine>(this: &L,
+ a: ty::t,
+ b: ty::t)
+ -> cres<ty::t>
+{
debug!("{}.lattice_tys({}, {})",
this.tag(),
a.repr(this.infcx().tcx),
return Ok(a);
}
- let tcx = this.infcx().tcx;
-
+ let infcx = this.infcx();
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&ty::get(a).sty, &ty::get(b).sty) {
- (&ty::ty_bot, _) => { return this.ty_bot(b); }
- (_, &ty::ty_bot) => { return this.ty_bot(a); }
-
- (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
- let r = if_ok!(lattice_vars(this, a_id, b_id,
- |x, y| this.tys(*x, *y)));
- return match r {
- VarResult(v) => Ok(ty::mk_var(tcx, v)),
- ValueResult(t) => Ok(t)
- };
- }
-
- (&ty::ty_infer(TyVar(a_id)), _) => {
- return lattice_var_and_t(this, a_id, &b,
- |x, y| this.tys(*x, *y));
- }
-
- (_, &ty::ty_infer(TyVar(b_id))) => {
- return lattice_var_and_t(this, b_id, &a,
- |x, y| this.tys(*x, *y));
+ (&ty::ty_bot, _) => { this.ty_bot(b) }
+ (_, &ty::ty_bot) => { this.ty_bot(a) }
+
+ (&ty::ty_infer(TyVar(..)), _) |
+ (_, &ty::ty_infer(TyVar(..))) => {
+ let v = infcx.next_ty_var();
+ try!(this.relate_bound(v, a, b));
+ Ok(v)
}
_ => {
- return super_tys(this, a, b);
- }
- }
-}
-
-pub type LatticeDirOp<'a, T> = |a: &T, b: &T|: 'a -> cres<T>;
-
-#[deriving(Clone)]
-pub enum LatticeVarResult<K,T> {
- VarResult(K),
- ValueResult(T)
-}
-
-/**
- * Computes the LUB or GLB of two bounded variables. These could be any
- * sort of variables, but in the comments on this function I'll assume
- * we are doing an LUB on two type variables.
- *
- * This computation can be done in one of two ways:
- *
- * - If both variables have an upper bound, we may just compute the
- * LUB of those bounds and return that, in which case we are
- * returning a type. This is indicated with a `ValueResult` return.
- *
- * - If the variables do not both have an upper bound, we will unify
- * the variables and return the unified variable, in which case the
- * result is a variable. This is indicated with a `VarResult`
- * return. */
-pub fn lattice_vars<L:LatticeDir+Combine,
- T:LatticeValue,
- K:UnifyKey<Bounds<T>>>(
- this: &L, // defines whether we want LUB or GLB
- a_vid: K, // first variable
- b_vid: K, // second variable
- lattice_dir_op: LatticeDirOp<T>) // LUB or GLB operation on types
- -> cres<LatticeVarResult<K,T>>
-{
- let tcx = this.infcx().tcx;
- let table = UnifyKey::unification_table(this.infcx());
-
- let node_a = table.borrow_mut().get(tcx, a_vid);
- let node_b = table.borrow_mut().get(tcx, b_vid);
- let a_vid = node_a.key.clone();
- let b_vid = node_b.key.clone();
- let a_bounds = &node_a.value;
- let b_bounds = &node_b.value;
-
- debug!("{}.lattice_vars({}={} <: {}={})",
- this.tag(),
- a_vid, a_bounds.repr(tcx),
- b_vid, b_bounds.repr(tcx));
-
- // Same variable: the easy case.
- if a_vid == b_vid {
- return Ok(VarResult(a_vid));
- }
-
- // If both A and B have an UB type, then we can just compute the
- // LUB of those types:
- let (a_bnd, b_bnd) = (this.bnd(a_bounds), this.bnd(b_bounds));
- match (a_bnd, b_bnd) {
- (Some(ref a_ty), Some(ref b_ty)) => {
- match this.infcx().try(|| lattice_dir_op(a_ty, b_ty) ) {
- Ok(t) => return Ok(ValueResult(t)),
- Err(_) => { /*fallthrough */ }
- }
- }
- _ => {/*fallthrough*/}
- }
-
- // Otherwise, we need to merge A and B into one variable. We can
- // then use either variable as an upper bound:
- let cf = this.combine_fields();
- let () = try!(cf.var_sub_var(a_vid.clone(), b_vid.clone()));
- Ok(VarResult(a_vid.clone()))
-}
-
-pub fn lattice_var_and_t<L:LatticeDir+Combine,
- T:LatticeValue,
- K:UnifyKey<Bounds<T>>>(
- this: &L,
- a_id: K,
- b: &T,
- lattice_dir_op: LatticeDirOp<T>)
- -> cres<T>
-{
- let tcx = this.infcx().tcx;
- let table = UnifyKey::unification_table(this.infcx());
-
- let node_a = table.borrow_mut().get(tcx, a_id);
- let a_id = node_a.key.clone();
- let a_bounds = &node_a.value;
-
- // The comments in this function are written for LUB, but they
- // apply equally well to GLB if you inverse upper/lower/sub/super/etc.
-
- debug!("{}.lattice_var_and_t({}={} <: {})",
- this.tag(),
- a_id,
- a_bounds.repr(this.infcx().tcx),
- b.repr(this.infcx().tcx));
-
- match this.bnd(a_bounds) {
- Some(ref a_bnd) => {
- // If a has an upper bound, return the LUB(a.ub, b)
- debug!("bnd=Some({})", a_bnd.repr(this.infcx().tcx));
- lattice_dir_op(a_bnd, b)
- }
- None => {
- // If a does not have an upper bound, make b the upper bound of a
- // and then return b.
- debug!("bnd=None");
- let a_bounds = this.with_bnd(a_bounds, (*b).clone());
- let () = try!(this.combine_fields().bnds(&a_bounds.lb,
- &a_bounds.ub));
- table.borrow_mut().set(tcx,
- a_id.clone(),
- Root(a_bounds.clone(), node_a.rank));
- Ok((*b).clone())
+ super_tys(this, a, b)
}
}
}
-// ___________________________________________________________________________
+///////////////////////////////////////////////////////////////////////////
// Random utility functions used by LUB/GLB when computing LUB/GLB of
// fn types
use middle::ty::{BuiltinBounds};
use middle::ty::RegionVid;
use middle::ty;
-use middle::typeck::infer::then;
use middle::typeck::infer::combine::*;
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::lattice::*;
use middle::typeck::infer::sub::Sub;
/// "Least upper bound" (common supertype)
pub struct Lub<'f> {
- pub fields: CombineFields<'f>
+ fields: CombineFields<'f>
}
#[allow(non_snake_case_functions)]
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
let m = a.mutbl;
match m {
- MutImmutable => {
- self.tys(a.ty, b.ty).and_then(|t| Ok(ty::mt {ty: t, mutbl: m}) )
- }
-
- MutMutable => {
- self.fields.infcx.try(|| {
- eq_tys(self, a.ty, b.ty).then(|| {
- Ok(ty::mt {ty: a.ty, mutbl: m})
- })
- }).or_else(|e| Err(e))
- }
+ MutImmutable => {
+ let t = try!(self.tys(a.ty, b.ty));
+ Ok(ty::mt {ty: t, mutbl: m})
+ }
+
+ MutMutable => {
+ let t = try!(self.equate().tys(a.ty, b.ty));
+ Ok(ty::mt {ty: t, mutbl: m})
+ }
}
}
+++ /dev/null
-// Copyright 2012 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.
-
-#![macro_escape]
-
-macro_rules! if_ok(
- ($inp: expr) => (
- match $inp {
- Ok(v) => { v }
- Err(e) => { return Err(e); }
- }
- )
-)
use middle::ty_fold::TypeFolder;
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::infer::coercion::Coerce;
-use middle::typeck::infer::combine::{Combine, CombineFields, eq_tys};
-use middle::typeck::infer::region_inference::{RegionSnapshot};
-use middle::typeck::infer::region_inference::{RegionVarBindings};
+use middle::typeck::infer::combine::{Combine, CombineFields};
+use middle::typeck::infer::region_inference::{RegionVarBindings,
+ RegionSnapshot};
use middle::typeck::infer::resolve::{resolver};
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::sub::Sub;
use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::unify::{UnificationTable, Snapshot};
+use middle::typeck::infer::unify::{UnificationTable};
use middle::typeck::infer::error_reporting::ErrorReporting;
use std::cell::{RefCell};
use std::collections::HashMap;
use util::common::indent;
use util::ppaux::{bound_region_to_string, ty_to_string, trait_ref_to_string, Repr};
-pub mod doc;
-pub mod macros;
+pub mod coercion;
pub mod combine;
+pub mod doc;
+pub mod equate;
+pub mod error_reporting;
pub mod glb;
pub mod lattice;
pub mod lub;
pub mod region_inference;
pub mod resolve;
pub mod sub;
-pub mod unify;
-pub mod coercion;
-pub mod error_reporting;
pub mod test;
+pub mod type_variable;
+pub mod unify;
pub type Bound<T> = Option<T>;
// We instantiate UnificationTable with bounds<ty::t> because the
// types that might instantiate a general type variable have an
// order, represented by its upper and lower bounds.
- type_unification_table:
- RefCell<UnificationTable<ty::TyVid, Bounds<ty::t>>>,
+ type_variables: RefCell<type_variable::TypeVariableTable>,
// Map from integral variable to the kind of integer it represents
int_unification_table:
pub fn new_infer_ctxt<'a>(tcx: &'a ty::ctxt) -> InferCtxt<'a> {
InferCtxt {
tcx: tcx,
- type_unification_table: RefCell::new(UnificationTable::new()),
+ type_variables: RefCell::new(type_variable::TypeVariableTable::new()),
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(tcx),
origin: origin,
values: Types(expected_found(a_is_expected, a, b))
};
- let suber = cx.sub(a_is_expected, trace);
- eq_tys(&suber, a, b)
+ try!(cx.equate(a_is_expected, trace).tys(a, b));
+ Ok(())
})
}
}
pub struct CombinedSnapshot {
- type_snapshot: Snapshot<ty::TyVid>,
- int_snapshot: Snapshot<ty::IntVid>,
- float_snapshot: Snapshot<ty::FloatVid>,
+ type_snapshot: type_variable::Snapshot,
+ int_snapshot: unify::Snapshot<ty::IntVid>,
+ float_snapshot: unify::Snapshot<ty::FloatVid>,
region_vars_snapshot: RegionSnapshot,
}
trace: trace}
}
+ pub fn equate<'a>(&'a self, a_is_expected: bool, trace: TypeTrace) -> Equate<'a> {
+ Equate(self.combine_fields(a_is_expected, trace))
+ }
+
pub fn sub<'a>(&'a self, a_is_expected: bool, trace: TypeTrace) -> Sub<'a> {
Sub(self.combine_fields(a_is_expected, trace))
}
Lub(self.combine_fields(a_is_expected, trace))
}
- pub fn in_snapshot(&self) -> bool {
- self.region_vars.in_snapshot()
- }
-
fn start_snapshot(&self) -> CombinedSnapshot {
CombinedSnapshot {
- type_snapshot: self.type_unification_table.borrow_mut().snapshot(),
+ type_snapshot: self.type_variables.borrow_mut().snapshot(),
int_snapshot: self.int_unification_table.borrow_mut().snapshot(),
float_snapshot: self.float_unification_table.borrow_mut().snapshot(),
region_vars_snapshot: self.region_vars.start_snapshot(),
float_snapshot,
region_vars_snapshot } = snapshot;
- self.type_unification_table
+ self.type_variables
.borrow_mut()
.rollback_to(type_snapshot);
self.int_unification_table
float_snapshot,
region_vars_snapshot } = snapshot;
- self.type_unification_table
+ self.type_variables
.borrow_mut()
.commit(type_snapshot);
self.int_unification_table
impl<'a> InferCtxt<'a> {
pub fn next_ty_var_id(&self) -> TyVid {
- self.type_unification_table
+ self.type_variables
.borrow_mut()
- .new_key(Bounds { lb: None, ub: None })
+ .new_var()
}
pub fn next_ty_var(&self) -> ty::t {
}
}
- pub fn in_snapshot(&self) -> bool {
+ fn in_snapshot(&self) -> bool {
self.undo_log.borrow().len() > 0
}
}
}
+ pub fn make_eqregion(&self,
+ origin: SubregionOrigin,
+ sub: Region,
+ sup: Region) {
+ if sub != sup {
+ // Eventually, it would be nice to add direct support for
+ // equating regions.
+ self.make_subregion(origin.clone(), sub, sup);
+ self.make_subregion(origin, sup, sub);
+ }
+ }
+
pub fn make_subregion(&self,
origin: SubregionOrigin,
sub: Region,
use middle::ty::{FloatVar, FloatVid, IntVar, IntVid, RegionVid, TyVar, TyVid};
-use middle::ty::{type_is_bot, IntType, UintType};
+use middle::ty::{IntType, UintType};
use middle::ty;
use middle::ty_fold;
-use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt};
-use middle::typeck::infer::{unresolved_float_ty, unresolved_int_ty};
-use middle::typeck::infer::{unresolved_ty};
+use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt};
+use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty};
use syntax::codemap::Span;
use util::common::indent;
use util::ppaux::{Repr, ty_to_string};
assert!(self.v_seen.is_empty());
match self.err {
None => {
- debug!("Resolved to {} + {} (modes={:x})",
- ty_to_string(self.infcx.tcx, rty),
+ debug!("Resolved {} to {} (modes={:x})",
+ ty_to_string(self.infcx.tcx, typ),
ty_to_string(self.infcx.tcx, rty),
self.modes);
return Ok(rty);
// tend to carry more restrictions or higher
// perf. penalties, so it pays to know more.
- let node =
- self.infcx.type_unification_table.borrow_mut().get(tcx, vid);
- let t1 = match node.value {
- Bounds { ub:_, lb:Some(t) } if !type_is_bot(t) => {
- self.resolve_type(t)
- }
- Bounds { ub:Some(t), lb:_ } | Bounds { ub:_, lb:Some(t) } => {
- self.resolve_type(t)
- }
- Bounds { ub:None, lb:None } => {
- if self.should(force_tvar) {
- self.err = Some(unresolved_ty(vid));
+ let t1 = match self.infcx.type_variables.borrow().probe(vid) {
+ Some(t) => {
+ self.resolve_type(t)
+ }
+ None => {
+ if self.should(force_tvar) {
+ self.err = Some(unresolved_ty(vid));
+ }
+ ty::mk_var(tcx, vid)
}
- ty::mk_var(tcx, vid)
- }
};
self.v_seen.pop().unwrap();
return t1;
use middle::typeck::check::regionmanip::replace_late_bound_regions_in_fn_sig;
use middle::typeck::infer::combine::*;
use middle::typeck::infer::{cres, CresCompare};
+use middle::typeck::infer::equate::Equate;
use middle::typeck::infer::glb::Glb;
use middle::typeck::infer::InferCtxt;
-use middle::typeck::infer::lattice::CombineFieldsLatticeMethods;
use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::then;
use middle::typeck::infer::{TypeTrace, Subtype};
+use middle::typeck::infer::type_variable::{SubtypeOf, SupertypeOf};
use util::common::{indenter};
use util::ppaux::{bound_region_to_string, Repr};
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
fn trace(&self) -> TypeTrace { self.fields.trace.clone() }
+ fn equate<'a>(&'a self) -> Equate<'a> { Equate(self.fields.clone()) }
fn sub<'a>(&'a self) -> Sub<'a> { Sub(self.fields.clone()) }
fn lub<'a>(&'a self) -> Lub<'a> { Lub(self.fields.clone()) }
fn glb<'a>(&'a self) -> Glb<'a> { Glb(self.fields.clone()) }
fn contratys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
- let opp = CombineFields {
- a_is_expected: !self.fields.a_is_expected,
- ..self.fields.clone()
- };
- Sub(opp).tys(b, a)
+ Sub(self.fields.switch_expected()).tys(b, a)
}
fn contraregions(&self, a: ty::Region, b: ty::Region)
- -> cres<ty::Region>
- {
- let opp = CombineFields {
- a_is_expected: !self.fields.a_is_expected,
- ..self.fields.clone()
- };
- Sub(opp).regions(b, a)
- }
+ -> cres<ty::Region> {
+ let opp = CombineFields {
+ a_is_expected: !self.fields.a_is_expected,
+ ..self.fields.clone()
+ };
+ Sub(opp).regions(b, a)
+ }
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
debug!("{}.regions({}, {})",
}
match b.mutbl {
- MutMutable => {
- // If supertype is mut, subtype must match exactly
- // (i.e., invariant if mut):
- eq_tys(self, a.ty, b.ty).then(|| Ok(*a))
- }
- MutImmutable => {
- // Otherwise we can be covariant:
- self.tys(a.ty, b.ty).and_then(|_t| Ok(*a) )
- }
+ MutMutable => {
+ // If supertype is mut, subtype must match exactly
+ // (i.e., invariant if mut):
+ try!(self.equate().tys(a.ty, b.ty));
+ }
+ MutImmutable => {
+ // Otherwise we can be covariant:
+ try!(self.tys(a.ty, b.ty));
+ }
}
+
+ Ok(*a) // return is meaningless in sub, just return *a
}
fn fn_styles(&self, a: FnStyle, b: FnStyle) -> cres<FnStyle> {
debug!("{}.tys({}, {})", self.tag(),
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
if a == b { return Ok(a); }
- let _indenter = indenter();
+
+ let infcx = self.fields.infcx;
+ let a = infcx.type_variables.borrow().replace_if_possible(a);
+ let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&ty::get(a).sty, &ty::get(b).sty) {
(&ty::ty_bot, _) => {
Ok(a)
}
(&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
- if_ok!(self.fields.var_sub_var(a_id, b_id));
+ infcx.type_variables
+ .borrow_mut()
+ .relate_vars(a_id, SubtypeOf, b_id);
Ok(a)
}
// The vec/str check here and below is so that we don't unify
Err(ty::terr_sorts(expected_found(self, a, b)))
}
(&ty::ty_infer(TyVar(a_id)), _) => {
- if_ok!(self.fields.var_sub_t(a_id, b));
+ try!(self.fields
+ .switch_expected()
+ .instantiate(b, SupertypeOf, a_id));
Ok(a)
}
Err(ty::terr_sorts(expected_found(self, a, b)))
}
(_, &ty::ty_infer(TyVar(b_id))) => {
- if_ok!(self.fields.t_sub_var(a, b_id));
+ try!(self.fields.instantiate(a, SubtypeOf, b_id));
Ok(a)
}
--- /dev/null
+// Copyright 2014 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.
+
+use middle::ty;
+use std::mem;
+use util::snapshot_vec as sv;
+
+pub struct TypeVariableTable {
+ values: sv::SnapshotVec<TypeVariableData,UndoEntry,Delegate>,
+}
+
+struct TypeVariableData {
+ value: TypeVariableValue
+}
+
+enum TypeVariableValue {
+ Known(ty::t),
+ Bounded(Vec<Relation>),
+}
+
+pub struct Snapshot {
+ snapshot: sv::Snapshot
+}
+
+enum UndoEntry {
+ // The type of the var was specified.
+ SpecifyVar(ty::TyVid, Vec<Relation>),
+ Relate(ty::TyVid, ty::TyVid),
+}
+
+struct Delegate;
+
+type Relation = (RelationDir, ty::TyVid);
+
+#[deriving(PartialEq,Show)]
+pub enum RelationDir {
+ SubtypeOf, SupertypeOf, EqTo
+}
+
+impl RelationDir {
+ fn opposite(self) -> RelationDir {
+ match self {
+ SubtypeOf => SupertypeOf,
+ SupertypeOf => SubtypeOf,
+ EqTo => EqTo
+ }
+ }
+}
+
+impl TypeVariableTable {
+ pub fn new() -> TypeVariableTable {
+ TypeVariableTable { values: sv::SnapshotVec::new(Delegate) }
+ }
+
+ fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec<Relation> {
+ relations(self.values.get_mut(a.index))
+ }
+
+ pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) {
+ /*!
+ * Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`.
+ *
+ * Precondition: neither `a` nor `b` are known.
+ */
+
+ if a != b {
+ self.relations(a).push((dir, b));
+ self.relations(b).push((dir.opposite(), a));
+ self.values.record(Relate(a, b));
+ }
+ }
+
+ pub fn instantiate_and_push(
+ &mut self,
+ vid: ty::TyVid,
+ ty: ty::t,
+ stack: &mut Vec<(ty::t, RelationDir, ty::TyVid)>)
+ {
+ /*!
+ * Instantiates `vid` with the type `ty` and then pushes an
+ * entry onto `stack` for each of the relations of `vid` to
+ * other variables. The relations will have the form `(ty,
+ * dir, vid1)` where `vid1` is some other variable id.
+ */
+
+ let old_value = {
+ let value_ptr = &mut self.values.get_mut(vid.index).value;
+ mem::replace(value_ptr, Known(ty))
+ };
+
+ let relations = match old_value {
+ Bounded(b) => b,
+ Known(_) => fail!("Asked to instantiate variable that is \
+ already instantiated")
+ };
+
+ for &(dir, vid) in relations.iter() {
+ stack.push((ty, dir, vid));
+ }
+
+ self.values.record(SpecifyVar(vid, relations));
+ }
+
+ pub fn new_var(&mut self) -> ty::TyVid {
+ let index =
+ self.values.push(
+ TypeVariableData { value: Bounded(Vec::new()) });
+ ty::TyVid { index: index }
+ }
+
+ pub fn probe(&self, vid: ty::TyVid) -> Option<ty::t> {
+ match self.values.get(vid.index).value {
+ Bounded(..) => None,
+ Known(t) => Some(t)
+ }
+ }
+
+ pub fn replace_if_possible(&self, t: ty::t) -> ty::t {
+ match ty::get(t).sty {
+ ty::ty_infer(ty::TyVar(v)) => {
+ match self.probe(v) {
+ None => t,
+ Some(u) => u
+ }
+ }
+ _ => t,
+ }
+ }
+
+ pub fn snapshot(&mut self) -> Snapshot {
+ Snapshot { snapshot: self.values.start_snapshot() }
+ }
+
+ pub fn rollback_to(&mut self, s: Snapshot) {
+ self.values.rollback_to(s.snapshot);
+ }
+
+ pub fn commit(&mut self, s: Snapshot) {
+ self.values.commit(s.snapshot);
+ }
+}
+
+impl sv::SnapshotVecDelegate<TypeVariableData,UndoEntry> for Delegate {
+ fn reverse(&mut self,
+ values: &mut Vec<TypeVariableData>,
+ action: UndoEntry) {
+ match action {
+ SpecifyVar(vid, relations) => {
+ values.get_mut(vid.index).value = Bounded(relations);
+ }
+
+ Relate(a, b) => {
+ relations(values.get_mut(a.index)).pop();
+ relations(values.get_mut(b.index)).pop();
+ }
+ }
+ }
+}
+
+fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec<Relation> {
+ match v.value {
+ Known(_) => fail!("var_sub_var: variable is known"),
+ Bounded(ref mut relations) => relations
+ }
+}
+
use middle::ty::{expected_found, IntVarValue};
use middle::ty;
-use middle::typeck::infer::{Bounds, uok, ures};
+use middle::typeck::infer::{uok, ures};
use middle::typeck::infer::InferCtxt;
use std::cell::RefCell;
use std::fmt::Show;
/**
* This trait is implemented by any type that can serve as a type
* variable. We call such variables *unification keys*. For example,
- * this trait is implemented by `TyVid`, which represents normal
- * type variables, and `IntVid`, which represents integral variables.
+ * this trait is implemented by `IntVid`, which represents integral
+ * variables.
*
- * Each key type has an associated value type `V`. For example,
- * for `TyVid`, this is `Bounds<ty::t>`, representing a pair of
- * upper- and lower-bound types.
+ * Each key type has an associated value type `V`. For example, for
+ * `IntVid`, this is `Option<IntVarValue>`, representing some
+ * (possibly not yet known) sort of integer.
*
* Implementations of this trait are at the end of this file.
*/
}
/**
- * Trait for valid types that a type variable can be set to. Note
- * that this is typically not the end type that the value will
- * take on, but rather some wrapper: for example, for normal type
- * variables, the associated type is not `ty::t` but rather
- * `Bounds<ty::t>`.
+ * Trait for valid types that a type variable can be set to. Note that
+ * this is typically not the end type that the value will take on, but
+ * rather an `Option` wrapper (where `None` represents a variable
+ * whose value is not yet set).
*
* Implementations of this trait are at the end of this file.
*/
pub struct Delegate;
// We can't use V:LatticeValue, much as I would like to,
-// because frequently the pattern is that V=Bounds<U> for some
+// because frequently the pattern is that V=Option<U> for some
// other type parameter U, and we have no way to say
-// Bounds<U>:
+// Option<U>:LatticeValue.
impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
pub fn new() -> UnificationTable<K,V> {
///////////////////////////////////////////////////////////////////////////
-// General type keys
-
-impl UnifyKey<Bounds<ty::t>> for ty::TyVid {
- fn index(&self) -> uint { self.index }
-
- fn from_index(i: uint) -> ty::TyVid { ty::TyVid { index: i } }
-
- fn unification_table<'v>(infcx: &'v InferCtxt)
- -> &'v RefCell<UnificationTable<ty::TyVid, Bounds<ty::t>>>
- {
- return &infcx.type_unification_table;
- }
-
- fn tag(_: Option<ty::TyVid>) -> &'static str {
- "TyVid"
- }
-}
-
-impl UnifyValue for Bounds<ty::t> { }
-
// Integral type keys
impl UnifyKey<Option<IntVarValue>> for ty::IntVid {
// except according to those terms.
fn test<'x>(x: &'x int) {
- drop::< <'z>|&'z int| -> &'z int>(|z| {
+ drop::< <'z>|&'z int| -> &'z int >(|z| {
x
//~^ ERROR cannot infer an appropriate lifetime
});
let x = [1,2];
let y = match x {
[] => None,
-//~^ ERROR expected `[<generic integer #1>, .. 2]`, found a fixed vector pattern of size 0
+//~^ ERROR expected `[<generic integer #0>, .. 2]`, found a fixed vector pattern of size 0
[a,_] => Some(a)
};
}
fn main() {
let Slice { data: data, len: len } = "foo";
- //~^ ERROR mismatched types: expected `&'static str`, found a structure pattern
+ //~^ ERROR mismatched types: expected `&str`, found a structure pattern
}
}
fn main() {
["hi"].bind(|x| [x] );
- //~^ ERROR type `[&'static str, .. 1]` does not implement any method in scope named `bind`
+ //~^ ERROR type `[&str, .. 1]` does not implement any method in scope named `bind`
}
--- /dev/null
+// Copyright 2014 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.
+
+// Test which object types are considered sendable. This test
+// is broken into two parts because some errors occur in distinct
+// phases in the compiler. See kindck-send-object2.rs as well!
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+
+// careful with object types, who knows what they close over...
+fn test51<'a>() {
+ assert_send::<&'a Dummy>(); //~ ERROR does not fulfill the required lifetime
+}
+fn test52<'a>() {
+ assert_send::<&'a Dummy+Send>(); //~ ERROR does not fulfill the required lifetime
+}
+
+// ...unless they are properly bounded
+fn test60() {
+ assert_send::<&'static Dummy+Send>();
+}
+fn test61() {
+ assert_send::<Box<Dummy+Send>>();
+}
+
+// closure and object types can have lifetime bounds which make
+// them not ok
+fn test_70<'a>() {
+ assert_send::<proc():'a>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn test_71<'a>() {
+ assert_send::<Box<Dummy+'a>>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 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.
+
+// Continue kindck-send-object1.rs.
+
+fn assert_send<T:Send>() { }
+trait Dummy { }
+
+fn test50() {
+ assert_send::<&'static Dummy>(); //~ ERROR does not fulfill `Send`
+}
+
+fn test53() {
+ assert_send::<Box<Dummy>>(); //~ ERROR does not fulfill `Send`
+}
+
+// ...unless they are properly bounded
+fn test60() {
+ assert_send::<&'static Dummy+Send>();
+}
+fn test61() {
+ assert_send::<Box<Dummy+Send>>();
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 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.
+
+// Test which of the builtin types are considered sendable.
+
+fn assert_send<T:Send>() { }
+
+// owned content are ok
+fn test30() { assert_send::<Box<int>>(); }
+fn test31() { assert_send::<String>(); }
+fn test32() { assert_send::<Vec<int> >(); }
+
+// but not if they own a bad thing
+fn test40<'a>(_: &'a int) {
+ assert_send::<Box<&'a int>>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 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.
+
+// Test that borrowed pointers are not sendable unless 'static.
+
+fn assert_send<T:Send>() { }
+
+// lifetime pointers with 'static lifetime are ok
+fn test01() { assert_send::<&'static int>(); }
+fn test02() { assert_send::<&'static str>(); }
+fn test03() { assert_send::<&'static [int]>(); }
+
+// whether or not they are mutable
+fn test10() { assert_send::<&'static mut int>(); }
+
+// otherwise lifetime pointers are not ok
+fn test20<'a>(_: &'a int) {
+ assert_send::<&'a int>(); //~ ERROR does not fulfill the required lifetime
+}
+fn test21<'a>(_: &'a int) {
+ assert_send::<&'a str>(); //~ ERROR does not fulfill the required lifetime
+}
+fn test22<'a>(_: &'a int) {
+ assert_send::<&'a [int]>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 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.
+
+fn assert_send<T:Send>() { }
+
+// unsafe ptrs are ok unless they point at unsendable things
+fn test70() {
+ assert_send::<*mut int>();
+}
+fn test71<'a>() {
+ assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime
+}
+
+fn main() {
+}
fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> {
return e; //~ ERROR mismatched types: expected `an_enum<'b>`, found `an_enum<'a>`
- //~^ ERROR cannot infer
}
fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> {
return e; //~ ERROR mismatched types: expected `a_class<'b>`, found `a_class<'a>`
- //~^ ERROR cannot infer
}
fn main() { }
fn main() {
let mut x = None;
- //~^ ERROR lifetime of variable does not enclose its declaration
- //~^^ ERROR type of expression contains references that are not valid during the expression
with_int(|y| x = Some(y));
+ //~^ ERROR cannot infer
}
}
fn main() {
- let mut x: Option<&int> = None; //~ ERROR cannot infer
- with_int(|y| x = Some(y));
+ let mut x: Option<&int> = None;
+ with_int(|y| x = Some(y)); //~ ERROR cannot infer
}
}
fn return_it() -> int {
- with(|o| o) //~ ERROR cannot infer an appropriate lifetime
+ with(|o| o) //~ ERROR cannot infer
}
fn main() {
fn take1<'a>(p: parameterized1) -> parameterized1<'a> { p }
//~^ ERROR mismatched types
-//~^^ ERROR cannot infer
fn take3(p: not_parameterized1) -> not_parameterized1 { p }
fn take4(p: not_parameterized2) -> not_parameterized2 { p }
// covariant with respect to its parameter 'a.
let _: Contravariant<'long> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// contravariant with respect to its parameter 'a.
let _: Covariant<'short> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
}
fn take_direct<'a,'b>(p: direct<'a>) -> direct<'b> { p } //~ ERROR mismatched types
-//~^ ERROR cannot infer
fn take_indirect1(p: indirect1) -> indirect1 { p }
fn take_indirect2<'a,'b>(p: indirect2<'a>) -> indirect2<'b> { p } //~ ERROR mismatched types
-//~^ ERROR cannot infer
fn main() {}
}
trait set_f<'a> {
- fn set_f_ok(&self, b: Gc<b<'a>>);
- fn set_f_bad(&self, b: Gc<b>);
+ fn set_f_ok(&mut self, b: Gc<b<'a>>);
+ fn set_f_bad(&mut self, b: Gc<b>);
}
impl<'a> set_f<'a> for c<'a> {
- fn set_f_ok(&self, b: Gc<b<'a>>) {
+ fn set_f_ok(&mut self, b: Gc<b<'a>>) {
self.f = b;
}
- fn set_f_bad(&self, b: Gc<b>) {
+ fn set_f_bad(&mut self, b: Gc<b>) {
self.f = b; //~ ERROR mismatched types: expected `Gc<Gc<&'a int>>`, found `Gc<Gc<&int>>`
- //~^ ERROR cannot infer
}
}
// Issue #8624. Test for reborrowing with 3 levels, not just two.
fn copy_borrowed_ptr<'a, 'b, 'c>(p: &'a mut &'b mut &'c mut int) -> &'b mut int {
- &mut ***p //~ ERROR lifetime of `p` is too short to guarantee its contents
+ &mut ***p //~ ERROR cannot infer
}
fn main() {
fn return_it<'a>() -> &'a int {
with(|o| o)
//~^ ERROR cannot infer
- //~^^ ERROR not valid during the expression
- //~^^^ ERROR not valid at this point
}
fn main() {
fn return_it<'a>() -> &'a int {
with(|o| o)
//~^ ERROR cannot infer
- //~^^ ERROR not valid during the expression
- //~^^^ ERROR not valid at this point
}
fn main() {
// covariant with respect to its parameter 'a.
let _: S<'long, 'long> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// covariant with respect to its parameter 'a.
let _: Contravariant<'long> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
// contravariant with respect to its parameter 'a.
let _: Covariant<'short> = c; //~ ERROR mismatched types
- //~^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
--- /dev/null
+// Copyright 2014 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 is an example where the older inference algorithm failed. The
+// specifics of why it failed are somewhat, but not entirely, tailed
+// to the algorithm. Ultimately the problem is that when computing the
+// mutual supertype of both sides of the `if` it would be faced with a
+// choice of tightening bounds or unifying variables and it took the
+// wrong path. The new algorithm avoids this problem and hence this
+// example typechecks correctly.
+
+enum ScopeChain<'a> {
+ Link(Scope<'a>),
+ End
+}
+
+type Scope<'a> = &'a ScopeChain<'a>;
+
+struct OuterContext;
+
+struct Context<'a> {
+ foo: &'a OuterContext
+}
+
+impl<'a> Context<'a> {
+ fn foo(&mut self, scope: Scope) {
+ let link = if 1i < 2 {
+ let l = Link(scope);
+ self.take_scope(&l);
+ l
+ } else {
+ Link(scope)
+ };
+ self.take_scope(&link);
+ }
+
+ fn take_scope(&mut self, x: Scope) {
+ }
+}
+
+fn main() { }