]> git.lizzy.rs Git - rust.git/commitdiff
Introduce new inference scheme: variables are now instantiated with at most one type...
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 22 Jul 2014 11:46:36 +0000 (07:46 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Fri, 29 Aug 2014 14:21:54 +0000 (10:21 -0400)
37 files changed:
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/equate.rs [new file with mode: 0644]
src/librustc/middle/typeck/infer/glb.rs
src/librustc/middle/typeck/infer/lattice.rs
src/librustc/middle/typeck/infer/lub.rs
src/librustc/middle/typeck/infer/macros.rs [deleted file]
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/region_inference/mod.rs
src/librustc/middle/typeck/infer/resolve.rs
src/librustc/middle/typeck/infer/sub.rs
src/librustc/middle/typeck/infer/type_variable.rs [new file with mode: 0644]
src/librustc/middle/typeck/infer/unify.rs
src/test/compile-fail/issue-10291.rs
src/test/compile-fail/issue-13482.rs
src/test/compile-fail/issue-16338.rs
src/test/compile-fail/issue-2149.rs
src/test/compile-fail/kindck-send-object1.rs [new file with mode: 0644]
src/test/compile-fail/kindck-send-object2.rs [new file with mode: 0644]
src/test/compile-fail/kindck-send-owned.rs [new file with mode: 0644]
src/test/compile-fail/kindck-send-region-pointers.rs [new file with mode: 0644]
src/test/compile-fail/kindck-send-unsafe.rs [new file with mode: 0644]
src/test/compile-fail/regions-bounds.rs
src/test/compile-fail/regions-escape-bound-fn-2.rs
src/test/compile-fail/regions-escape-bound-fn.rs
src/test/compile-fail/regions-escape-via-trait-or-not.rs
src/test/compile-fail/regions-infer-at-fn-not-param.rs
src/test/compile-fail/regions-infer-contravariance-due-to-decl.rs
src/test/compile-fail/regions-infer-covariance-due-to-decl.rs
src/test/compile-fail/regions-infer-not-param.rs
src/test/compile-fail/regions-infer-paramd-indirect.rs
src/test/compile-fail/regions-reborrow-from-shorter-mut-ref-mut-ref.rs
src/test/compile-fail/regions-ret-borrowed-1.rs
src/test/compile-fail/regions-ret-borrowed.rs
src/test/compile-fail/regions-variance-contravariant-use-covariant-in-second-position.rs
src/test/compile-fail/regions-variance-contravariant-use-covariant.rs
src/test/compile-fail/regions-variance-covariant-use-contravariant.rs
src/test/run-pass/regions-scope-chain-example.rs [new file with mode: 0644]

index c6506b145214f66c065662d8978ba319a738d31c..0c6143ea7337670e1e7dbdc4b073964176311477 100644 (file)
@@ -8,43 +8,29 @@
 // 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;
@@ -75,6 +63,7 @@ pub trait Combine {
     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>;
@@ -101,7 +90,7 @@ fn tps(&self,
         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_))
     }
 
@@ -177,10 +166,7 @@ fn relate_region_params<C:Combine>(this: &C,
                 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),
@@ -334,34 +320,6 @@ pub fn expected_found<C:Combine,T>(
     }
 }
 
-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> > {
@@ -453,8 +411,7 @@ fn check_ptr_to_unsized<C:Combine>(this: &C,
 
         // 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)) => {
@@ -469,7 +426,8 @@ fn check_ptr_to_unsized<C:Combine>(this: &C,
       (&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 {
@@ -512,7 +470,10 @@ fn check_ptr_to_unsized<C:Combine>(this: &C,
       (&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))
       }
 
@@ -609,3 +570,118 @@ fn unify_float_variable<C:Combine>(
         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))))
+    }
+}
diff --git a/src/librustc/middle/typeck/infer/equate.rs b/src/librustc/middle/typeck/infer/equate.rs
new file mode 100644 (file)
index 0000000..391027f
--- /dev/null
@@ -0,0 +1,149 @@
+// 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)
+    }
+}
index 0b89e7274e7277e28bf4d1668a882242dd646eb6..68b8031a04b68a730f389bbff5587673bf9c9c34 100644 (file)
@@ -12,9 +12,9 @@
 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};
@@ -31,7 +31,7 @@
 
 /// "Greatest lower bound" (common subtype)
 pub struct Glb<'f> {
-    pub fields: CombineFields<'f>
+    fields: CombineFields<'f>
 }
 
 #[allow(non_snake_case_functions)]
@@ -45,6 +45,7 @@ fn tag(&self) -> String { "glb".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()) }
@@ -58,27 +59,25 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
                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)
+            }
         }
     }
 
index 8a40021ea96760c66b7bfad86f61b8bef4dfb906..f09773d30b5149feb7b91046f6ae46d0c4d0cd52 100644 (file)
 
 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),
@@ -382,156 +91,27 @@ pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
         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
 
index 650987612accf0f1367dcf142ba54a60fe873a85..9c6c0763ad45ec8a5389ead7800daa34f8edc306 100644 (file)
@@ -11,8 +11,8 @@
 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;
@@ -30,7 +30,7 @@
 
 /// "Least upper bound" (common supertype)
 pub struct Lub<'f> {
-    pub fields: CombineFields<'f>
+    fields: CombineFields<'f>
 }
 
 #[allow(non_snake_case_functions)]
@@ -44,6 +44,7 @@ fn tag(&self) -> String { "lub".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()) }
@@ -62,17 +63,15 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
 
         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})
+            }
         }
     }
 
diff --git a/src/librustc/middle/typeck/infer/macros.rs b/src/librustc/middle/typeck/infer/macros.rs
deleted file mode 100644 (file)
index d3e81f0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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); }
-        }
-    )
-)
index e672b8b310f5dc0be9801aec02321920dc9bd3f3..f86857f97f6546db85cadd6156d8e9d3e930638a 100644 (file)
 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>;
 
@@ -79,8 +81,7 @@ pub struct InferCtxt<'a> {
     // 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:
@@ -293,7 +294,7 @@ pub fn fixup_err_to_string(f: fixup_err) -> String {
 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),
@@ -395,8 +396,8 @@ pub fn mk_eqty(cx: &InferCtxt,
             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(())
     })
 }
 
@@ -511,9 +512,9 @@ pub fn uok() -> ures {
 }
 
 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,
 }
 
@@ -525,6 +526,10 @@ pub fn combine_fields<'a>(&'a self, a_is_expected: bool, trace: TypeTrace)
                        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))
     }
@@ -533,13 +538,9 @@ pub fn lub<'a>(&'a self, a_is_expected: bool, trace: TypeTrace) -> Lub<'a> {
         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(),
@@ -553,7 +554,7 @@ fn rollback_to(&self, snapshot: CombinedSnapshot) {
                                float_snapshot,
                                region_vars_snapshot } = snapshot;
 
-        self.type_unification_table
+        self.type_variables
             .borrow_mut()
             .rollback_to(type_snapshot);
         self.int_unification_table
@@ -573,7 +574,7 @@ fn commit_from(&self, snapshot: CombinedSnapshot) {
                                float_snapshot,
                                region_vars_snapshot } = snapshot;
 
-        self.type_unification_table
+        self.type_variables
             .borrow_mut()
             .commit(type_snapshot);
         self.int_unification_table
@@ -636,9 +637,9 @@ pub fn add_given(&self,
 
 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 {
index ff42dd817fb9404b3d843177258ec1afe361906a..f34894346f64afbc42e5d7a485267f2d5d65c902 100644 (file)
@@ -234,7 +234,7 @@ pub fn new(tcx: &'a ty::ctxt) -> RegionVarBindings<'a> {
         }
     }
 
-    pub fn in_snapshot(&self) -> bool {
+    fn in_snapshot(&self) -> bool {
         self.undo_log.borrow().len() > 0
     }
 
@@ -406,6 +406,18 @@ pub fn add_given(&self,
         }
     }
 
+    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,
index 2ae95309d41d98a76e6c00b8f254ddffd415a08c..f9742c522dac4a6d0d5ff753467e27f546a01b11 100644 (file)
 
 
 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};
@@ -132,8 +131,8 @@ pub fn resolve_type_chk(&mut self,
         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);
@@ -219,21 +218,16 @@ pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t {
             // 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;
index 1b83ee299bc7cad36610bb44d54d71bb9d4daf92..cc3abc279bf34da83a4547fc193764a5d668d0f4 100644 (file)
 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};
 
@@ -43,27 +43,23 @@ fn tag(&self) -> String { "sub".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> {
-        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({}, {})",
@@ -84,16 +80,18 @@ fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
         }
 
         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> {
@@ -126,14 +124,19 @@ 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 _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
@@ -145,7 +148,9 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
                 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)
             }
 
@@ -154,7 +159,7 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
                 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)
             }
 
diff --git a/src/librustc/middle/typeck/infer/type_variable.rs b/src/librustc/middle/typeck/infer/type_variable.rs
new file mode 100644 (file)
index 0000000..5f67f8a
--- /dev/null
@@ -0,0 +1,173 @@
+// 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
+    }
+}
+
index fd722d369663871a67af60f707d319d17f66902f..adf0a25ce4002e5f8069c59e27afe1a4b679abaa 100644 (file)
@@ -12,7 +12,7 @@
 
 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.
  */
@@ -48,11 +48,10 @@ fn unification_table<'v>(infcx: &'v InferCtxt)
 }
 
 /**
- * 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.
  */
@@ -109,9 +108,9 @@ pub struct Node<K,V> {
 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> {
@@ -375,26 +374,6 @@ fn simple_var_t(&self,
 
 ///////////////////////////////////////////////////////////////////////////
 
-// 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 {
index 8ae20dfde9123e68e869ee3a6e53a176de7b5032..995ae7b3d44e70632669f9bc53a91942b38de75b 100644 (file)
@@ -9,7 +9,7 @@
 // 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
     });
index 7159aa17623c086f862dbeb3c24f91c3b274ec11..2d7458944269cb24efe2ed5796c76b944e59fc0c 100644 (file)
@@ -12,7 +12,7 @@ fn main() {
   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)
   };
 }
index d4b31066e5ac216f8e0375481c9f623af2f2fde8..305b1fe2ad7ded015e6c6b79eba5fdf60ded30de 100644 (file)
@@ -12,6 +12,6 @@
 
 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
 }
 
index afb413584a4814e01bf87a902252393c1375e91d..5d07472afbb2572ea7b1f4b13ed9803304c5a086 100644 (file)
@@ -22,5 +22,5 @@ fn bind<B>(&self, f: |A| -> Vec<B> ) {
 }
 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`
 }
diff --git a/src/test/compile-fail/kindck-send-object1.rs b/src/test/compile-fail/kindck-send-object1.rs
new file mode 100644 (file)
index 0000000..6a90fd5
--- /dev/null
@@ -0,0 +1,44 @@
+// 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() { }
diff --git a/src/test/compile-fail/kindck-send-object2.rs b/src/test/compile-fail/kindck-send-object2.rs
new file mode 100644 (file)
index 0000000..7500647
--- /dev/null
@@ -0,0 +1,32 @@
+// 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() { }
diff --git a/src/test/compile-fail/kindck-send-owned.rs b/src/test/compile-fail/kindck-send-owned.rs
new file mode 100644 (file)
index 0000000..0eed056
--- /dev/null
@@ -0,0 +1,25 @@
+// 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() { }
diff --git a/src/test/compile-fail/kindck-send-region-pointers.rs b/src/test/compile-fail/kindck-send-region-pointers.rs
new file mode 100644 (file)
index 0000000..cc46d7f
--- /dev/null
@@ -0,0 +1,34 @@
+// 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() { }
diff --git a/src/test/compile-fail/kindck-send-unsafe.rs b/src/test/compile-fail/kindck-send-unsafe.rs
new file mode 100644 (file)
index 0000000..a9bbfcf
--- /dev/null
@@ -0,0 +1,22 @@
+// 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() {
+}
index 68e198ea5b7a070f8efca32169eb3bec80b48042..e13a6b211a5038b7526b532bcb9adde394c2c02f 100644 (file)
@@ -17,12 +17,10 @@ struct a_class<'a> { x:&'a int }
 
 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() { }
index d752bc97cac79b2cf5d814378a0cf966d5efb059..66103eb95888ac941e1cf123c8641d2b0978c584 100644 (file)
@@ -15,7 +15,6 @@ fn with_int(f: |x: &int|) {
 
 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
 }
index eb72b4b0c53219a532c62ea42451f3302417d09b..fee84cf9656d1ceaae73f4fb5d02a75c55a63579 100644 (file)
@@ -14,6 +14,6 @@ fn with_int(f: |x: &int|) {
 }
 
 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
 }
index adef1f901fd0adf4e15f655cd5c57103b5f72de8..b73b5e0649ff5a76a6a7afd612c613183786acbc 100644 (file)
@@ -27,7 +27,7 @@ fn with<R:Deref>(f: |x: &int| -> R) -> int {
 }
 
 fn return_it() -> int {
-    with(|o| o) //~ ERROR cannot infer an appropriate lifetime
+    with(|o| o) //~ ERROR cannot infer
 }
 
 fn main() {
index e5444aadc1ca64d650992cf50ca746a7e337a714..8af341e3ace42b9d949319d92199f98008180d8b 100644 (file)
@@ -22,7 +22,6 @@ struct not_parameterized2 {
 
 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 }
index d3e9c1f6ea848478afa3bbe7a0ac1f1fc7a75e57..4dd028b78845996e18acfdb6f65d1a0446260bac 100644 (file)
@@ -33,7 +33,6 @@ fn use_<'short,'long>(c: Contravariant<'short>,
     // covariant with respect to its parameter 'a.
 
     let _: Contravariant<'long> = c; //~ ERROR mismatched types
-    //~^ ERROR  cannot infer an appropriate lifetime
 }
 
 fn main() {}
index 2d3ca17301220ed81aa7af9249e3abaeeb536517..93c06aecd30ecffdaf5ad5d732071fa44c06f59b 100644 (file)
@@ -30,7 +30,6 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // contravariant with respect to its parameter 'a.
 
     let _: Covariant<'short> = c; //~ ERROR mismatched types
-    //~^ ERROR  cannot infer an appropriate lifetime
 }
 
 fn main() {}
index cadf66c3286869fdc72776e5f97682a1769323cd..b84f13ec37feb44d16654af4e6bf795c965046f3 100644 (file)
@@ -23,11 +23,9 @@ struct indirect2<'a> {
 }
 
 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() {}
index 519223e97535e58e06bfdbf03de6ea3317c945a5..e862b36dcd1680a2ddd7d8408fd921c13676a125 100644 (file)
@@ -22,18 +22,17 @@ struct c<'a> {
 }
 
 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
     }
 }
 
index 50ea8b1f2ed126708fb6085a9b4661beaf8b8f97..783009f6dcbfca4ae240e83f81517911d598d353 100644 (file)
@@ -11,7 +11,7 @@
 // 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() {
index aac81a2af6b1f3ef3448070908512d7525b2ce30..6d9b2619171057fd632f836e258d478965f2c584 100644 (file)
@@ -19,8 +19,6 @@ fn with<R>(f: <'a>|x: &'a int| -> R) -> R {
 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() {
index dd9421ee2ef2cdf20cf69ae252d07c8f05a19bda..465f4410fbbccb2d05451c0db6240e5433815a9f 100644 (file)
@@ -22,8 +22,6 @@ fn with<R>(f: |x: &int| -> R) -> R {
 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() {
index 77a54fec7bf7c6204699aefceea5e85a0cb9616a..14ead8da1587b12189c23015e1f09414c5765de3 100644 (file)
@@ -33,7 +33,6 @@ fn use_<'short,'long>(c: S<'long, 'short>,
     // covariant with respect to its parameter 'a.
 
     let _: S<'long, 'long> = c; //~ ERROR mismatched types
-    //~^ ERROR  cannot infer an appropriate lifetime
 }
 
 fn main() {}
index 0fab89264606b3a48e963c123c5b34c92c0b5ded..3fc58071d2ce86c421b8e4cb09774224881ee8f4 100644 (file)
@@ -31,7 +31,6 @@ fn use_<'short,'long>(c: Contravariant<'short>,
     // covariant with respect to its parameter 'a.
 
     let _: Contravariant<'long> = c; //~ ERROR mismatched types
-    //~^ ERROR  cannot infer an appropriate lifetime
 }
 
 fn main() {}
index 7dcdc9875e3954c46086c40192c37e8409bf68cf..844c8151a642ae31f59ba28ef922f524da989894 100644 (file)
@@ -31,7 +31,6 @@ fn use_<'short,'long>(c: Covariant<'long>,
     // contravariant with respect to its parameter 'a.
 
     let _: Covariant<'short> = c; //~ ERROR mismatched types
-    //~^ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() {}
diff --git a/src/test/run-pass/regions-scope-chain-example.rs b/src/test/run-pass/regions-scope-chain-example.rs
new file mode 100644 (file)
index 0000000..0eacb27
--- /dev/null
@@ -0,0 +1,48 @@
+// 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() { }