]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #15113 : pnkfelix/rust/fsk-add-regression-test-for-ice-from-10846,...
authorbors <bors@rust-lang.org>
Tue, 24 Jun 2014 12:01:50 +0000 (12:01 +0000)
committerbors <bors@rust-lang.org>
Tue, 24 Jun 2014 12:01:50 +0000 (12:01 +0000)
Includes a bit more comments than usual for a regression test; I felt like documenting Niko's diagnosis of the original problem here.

Fix #15111

r? anyone.

88 files changed:
src/doc/guide-unsafe.md
src/doc/rust.md
src/doc/tutorial.md
src/etc/2014-06-rewrite-bytes-macros.py
src/etc/vim/syntax/rust.vim
src/liballoc/lib.rs
src/libarena/lib.rs
src/libcollections/lib.rs
src/libcore/lib.rs
src/libnative/lib.rs
src/librlibc/lib.rs
src/librustc/front/feature_gate.rs
src/librustc/lib.rs
src/librustc/middle/resolve.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/infer/coercion.rs
src/librustc/middle/typeck/infer/combine.rs
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/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/test.rs
src/librustc/middle/typeck/infer/to_str.rs [deleted file]
src/librustc/middle/typeck/infer/unify.rs
src/librustc/util/ppaux.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/librustrt/lib.rs
src/libstd/lib.rs
src/libsync/lib.rs
src/libsyntax/lib.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/snapshots.txt
src/test/auxiliary/cci_intrinsic.rs
src/test/auxiliary/lang-item-public.rs
src/test/compile-fail/attr.rs
src/test/compile-fail/bad-mid-path-type-params.rs
src/test/compile-fail/bind-struct-early-modifiers.rs
src/test/compile-fail/borrowck-match-binding-is-assignment.rs
src/test/compile-fail/borrowck-move-error-with-note.rs
src/test/compile-fail/borrowck-move-out-of-struct-with-dtor.rs
src/test/compile-fail/feature-gate-intrinsics-and-lang-items.rs [new file with mode: 0644]
src/test/compile-fail/issue-2123.rs [deleted file]
src/test/compile-fail/issue-3907-2.rs [new file with mode: 0644]
src/test/compile-fail/issue-3907.rs
src/test/compile-fail/issue-3973.rs
src/test/compile-fail/issue-3993-3.rs [deleted file]
src/test/compile-fail/issue-5035-2.rs [new file with mode: 0644]
src/test/compile-fail/issue-5035.rs
src/test/compile-fail/lint-dead-code-1.rs
src/test/compile-fail/match-struct.rs
src/test/compile-fail/non-exhaustive-pattern-witness.rs
src/test/compile-fail/privacy1.rs
src/test/compile-fail/struct-literal-in-for.rs [new file with mode: 0644]
src/test/compile-fail/struct-literal-in-if.rs [new file with mode: 0644]
src/test/compile-fail/struct-literal-in-match-discriminant.rs [new file with mode: 0644]
src/test/compile-fail/struct-literal-in-while.rs [new file with mode: 0644]
src/test/compile-fail/struct-no-fields-2.rs
src/test/compile-fail/struct-no-fields-3.rs
src/test/compile-fail/struct-no-fields-4.rs
src/test/compile-fail/struct-no-fields-5.rs
src/test/compile-fail/struct-no-fields-enumlike.rs [new file with mode: 0644]
src/test/compile-fail/type-mismatch.rs [deleted file]
src/test/debuginfo/lexical-scope-in-match.rs
src/test/run-fail/binop-fail-2.rs [deleted file]
src/test/run-pass/deriving-meta-multiple.rs
src/test/run-pass/guards.rs
src/test/run-pass/intrinsic-alignment.rs
src/test/run-pass/intrinsic-atomics.rs
src/test/run-pass/intrinsic-move-val.rs
src/test/run-pass/intrinsic-uninit.rs
src/test/run-pass/intrinsics-integer.rs
src/test/run-pass/intrinsics-math.rs
src/test/run-pass/match-in-macro.rs
src/test/run-pass/nested-exhaustive-match.rs
src/test/run-pass/nested-patterns.rs
src/test/run-pass/new-unsafe-pointers.rs [new file with mode: 0644]
src/test/run-pass/rec-align-u32.rs
src/test/run-pass/rec-align-u64.rs
src/test/run-pass/smallest-hello-world.rs
src/test/run-pass/struct_variant_xc_match.rs
src/test/run-pass/unique-decl-move-temp.rs [deleted file]

index def96c62deb006c4e658b9984d1bf0acbe340a5f..d069cb4d09363514ebe820fac75f6d63717cf876 100644 (file)
@@ -451,6 +451,7 @@ in the same format as a C:
 
 ```
 #![no_std]
+#![feature(lang_items)]
 
 // Pull in the system libc library for what crt0.o likely requires
 extern crate libc;
@@ -477,6 +478,7 @@ compiler's name mangling too:
 ```ignore
 #![no_std]
 #![no_main]
+#![feature(lang_items)]
 
 extern crate libc;
 
@@ -528,6 +530,7 @@ vectors provided from C, using idiomatic Rust practices.
 ```
 #![no_std]
 #![feature(globs)]
+#![feature(lang_items)]
 
 # extern crate libc;
 extern crate core;
@@ -619,6 +622,9 @@ perform efficient pointer arithmetic, one would import those functions
 via a declaration like
 
 ```
+# #![feature(intrinsics)]
+# fn main() {}
+
 extern "rust-intrinsic" {
     fn transmute<T, U>(x: T) -> U;
 
@@ -647,6 +653,7 @@ sugar for dynamic allocations via `malloc` and `free`:
 
 ```
 #![no_std]
+#![feature(lang_items)]
 
 extern crate libc;
 
index e7b6941b622e81475ae9024b265666eb3f1fe28f..b2c56c3a3ca4c769178c7dc5769732b929ca037d 100644 (file)
@@ -160,7 +160,7 @@ block_comment_body : [block_comment | character] * ;
 line_comment : "//" non_eol * ;
 ~~~~
 
-Comments in Rust code follow the general C++ style of line and block-comment forms. 
+Comments in Rust code follow the general C++ style of line and block-comment forms.
 Nested block comments are supported.
 
 Line comments beginning with exactly _three_ slashes (`///`), and block
@@ -3004,7 +3004,7 @@ ten_times(|j| println!("hello, {}", j));
 ### While loops
 
 ~~~~ {.ebnf .gram}
-while_expr : "while" expr '{' block '}' ;
+while_expr : "while" no_struct_literal_expr '{' block '}' ;
 ~~~~
 
 A `while` loop begins by evaluating the boolean loop conditional expression.
@@ -3071,7 +3071,7 @@ A `continue` expression is only permitted in the body of a loop.
 ### For expressions
 
 ~~~~ {.ebnf .gram}
-for_expr : "for" pat "in" expr '{' block '}' ;
+for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
 ~~~~
 
 A `for` expression is a syntactic construct for looping over elements
@@ -3105,7 +3105,7 @@ for i in range(0u, 256) {
 ### If expressions
 
 ~~~~ {.ebnf .gram}
-if_expr : "if" expr '{' block '}'
+if_expr : "if" no_struct_literal_expr '{' block '}'
           else_tail ? ;
 
 else_tail : "else" [ if_expr
@@ -3126,7 +3126,7 @@ then any `else` block is executed.
 ### Match expressions
 
 ~~~~ {.ebnf .gram}
-match_expr : "match" expr '{' match_arm * '}' ;
+match_expr : "match" no_struct_literal_expr '{' match_arm * '}' ;
 
 match_arm : attribute * match_pat "=>" [ expr "," | '{' block '}' ] ;
 
@@ -3563,10 +3563,11 @@ There are four varieties of pointer in Rust:
 
 * Raw pointers (`*`)
   : Raw pointers are pointers without safety or liveness guarantees.
-    Raw pointers are written `*content`,
-    for example `*int` means a raw pointer to an integer.
-    Copying or dropping a raw pointer has no effect on the lifecycle of any other value.
-    Dereferencing a raw pointer or converting it to any other pointer type is an [`unsafe` operation](#unsafe-functions).
+    Raw pointers are written as `*const T` or `*mut T`,
+    for example `*const int` means a raw pointer to an integer.
+    Copying or dropping a raw pointer has no effect on the lifecycle of any
+    other value.  Dereferencing a raw pointer or converting it to any other
+    pointer type is an [`unsafe` operation](#unsafe-functions).
     Raw pointers are generally discouraged in Rust code;
     they exist to support interoperability with foreign code,
     and writing performance-critical or low-level functions.
index e6d9cef7a31083296eb27206df9616c7b8db6c2b..67a153a65849694cf078a1e20b50cc7364c9d924 100644 (file)
@@ -2522,7 +2522,7 @@ fn sendable_foo(f: Box<Foo + Send>) { /* ... */ }
 fn shareable_bar<T: Share>(b: &Bar<T> + Share) { /* ... */ }
 ~~~
 
-When no colon is specified (such as the type `~Foo`), it is inferred that the
+When no colon is specified (such as the type `Box<Foo>`), it is inferred that the
 value ascribes to no bounds. They must be added manually if any bounds are
 necessary for usage.
 
@@ -2579,7 +2579,7 @@ fn radius_times_area<T: Circle>(c: T) -> f64 {
 
 Likewise, supertrait methods may also be called on trait objects.
 
-~~~ {.ignore}
+~~~
 use std::f64::consts::PI;
 # trait Shape { fn area(&self) -> f64; }
 # trait Circle : Shape { fn radius(&self) -> f64; }
@@ -2587,9 +2587,10 @@ use std::f64::consts::PI;
 # struct CircleStruct { center: Point, radius: f64 }
 # impl Circle for CircleStruct { fn radius(&self) -> f64 { (self.area() / PI).sqrt() } }
 # impl Shape for CircleStruct { fn area(&self) -> f64 { PI * square(self.radius) } }
+# fn square(x: f64) -> f64 { x * x }
 
-let concrete = ~CircleStruct{center:Point{x:3.0,y:4.0},radius:5.0};
-let mycircle: ~Circle = concrete as ~Circle;
+let concrete = box CircleStruct{center:Point{x:3.0,y:4.0},radius:5.0};
+let mycircle: Box<Circle> = concrete as Box<Circle>;
 let nonsense = mycircle.radius() * mycircle.area();
 ~~~
 
index ceda4bf6fe253cf69f8d2db4eb2bf390fef2730d..73ddfcb04cb2f0bc96302e3d5e2504b1d09e15b5 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/env python
+#!/usr/bin/env python
 #
 # Copyright 2014 The Rust Project Developers. See the COPYRIGHT
 # file at the top-level directory of this distribution and at
index 8ef03f87b5b391b7e9fa8855ff79fc10d5697e7a..d8f00ac6b30facb057958d4dcbcefdef9e474912 100644 (file)
@@ -30,8 +30,7 @@ syn keyword   rustKeyword     unsafe virtual while
 syn keyword   rustKeyword     use nextgroup=rustModPath skipwhite skipempty
 " FIXME: Scoped impl's name is also fallen in this category
 syn keyword   rustKeyword     mod trait struct enum type nextgroup=rustIdentifier skipwhite skipempty
-syn keyword   rustStorage     mut ref static
-syn keyword   rustObsoleteStorage const
+syn keyword   rustStorage     mut ref static const
 
 syn keyword   rustInvalidBareKeyword crate
 
index 53a79217241bac76cce5d349e7120550b687086e..e89a9c019bb7a2ce1b67dec3514a152683c41ec8 100644 (file)
@@ -69,7 +69,7 @@
        html_root_url = "http://doc.rust-lang.org/")]
 
 #![no_std]
-#![feature(phase, unsafe_destructor)]
+#![feature(lang_items, phase, unsafe_destructor)]
 #![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)]
index 5ddb088c8c840d4a351b86fe9ddd66b1bb7cb380..ee1e0fd72cfe18c42fcec54445e486eb97699a1a 100644 (file)
@@ -30,7 +30,6 @@
 
 #![feature(unsafe_destructor)]
 #![allow(missing_doc)]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 use std::cell::{Cell, RefCell};
 use std::cmp;
index ca7de131dc212c902736c87281ac7d60a9cc9238..c5b8704439850e76ea3154b004a0c707cf7db5bb 100644 (file)
@@ -24,7 +24,6 @@
 #![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
 #![feature(unsafe_destructor)]
 #![no_std]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
index 3d2382e6208b421f7122f8224c42c76cd846fe2b..aa55f204f459fd5ddf0ae1b1defc0fe509f778fc 100644 (file)
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![no_std]
-#![feature(globs, macro_rules, managed_boxes, phase, simd, unsafe_destructor)]
+#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
+#![feature(simd, unsafe_destructor)]
 #![deny(missing_doc)]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
+#![allow(unknown_features)] // NOTE: remove after stage0 snapshot
 
 #[cfg(test)] extern crate realcore = "core";
 #[cfg(test)] extern crate libc;
index b44673a24ef053a84851dc975ffeb3a5d497bdd9..3438661ffb3e3ae34a88dac7027ca70bbf56214d 100644 (file)
        html_root_url = "http://doc.rust-lang.org/")]
 
 #![deny(unused_result, unused_must_use)]
-#![allow(non_camel_case_types)]
-#![allow(deprecated)]
+#![allow(non_camel_case_types, deprecated)]
 #![allow(unknown_features)] // NOTE: remove after a stage0 snap
-#![feature(default_type_params)]
+#![feature(default_type_params, lang_items)]
 
 // NB this crate explicitly does *not* allow glob imports, please seriously
 //    consider whether they're needed before adding that feature here (the
 //    answer is that you don't need them)
-#![feature(macro_rules, unsafe_destructor)]
+#![feature(macro_rules, unsafe_destructor, default_type_params)]
 
 extern crate alloc;
 extern crate libc;
index 8c804d4d254e122d72663e2693b7e06ba8891dad..0d917e20c25c6e15feec8f880c91554b9b43df60 100644 (file)
@@ -26,6 +26,8 @@
 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/")]
+#![feature(intrinsics)]
+#![allow(unknown_features)] // NOTE: remove after stage0 snapshot
 
 #![no_std]
 #![experimental]
index 07715684db3ef3f2fa5a41a7663ba0210f67db82..59e52b9359f50c4fce71e08b0c3419dafb489d79 100644 (file)
@@ -20,6 +20,8 @@
 
 use middle::lint;
 
+use syntax::abi::RustIntrinsic;
+use syntax::ast::NodeId;
 use syntax::ast;
 use syntax::attr;
 use syntax::attr::AttrMetaMethods;
@@ -51,6 +53,8 @@
     ("trace_macros", Active),
     ("concat_idents", Active),
     ("unsafe_destructor", Active),
+    ("intrinsics", Active),
+    ("lang_items", Active),
 
     ("simd", Active),
     ("default_type_params", Active),
@@ -187,13 +191,18 @@ fn visit_item(&mut self, i: &ast::Item, _:()) {
                 }
             }
 
-            ast::ItemForeignMod(..) => {
+            ast::ItemForeignMod(ref foreign_module) => {
                 if attr::contains_name(i.attrs.as_slice(), "link_args") {
                     self.gate_feature("link_args", i.span,
                                       "the `link_args` attribute is not portable \
                                        across platforms, it is recommended to \
                                        use `#[link(name = \"foo\")]` instead")
                 }
+                if foreign_module.abi == RustIntrinsic {
+                    self.gate_feature("intrinsics",
+                                      i.span,
+                                      "intrinsics are subject to change")
+                }
             }
 
             ast::ItemFn(..) => {
@@ -283,14 +292,10 @@ fn visit_mac(&mut self, macro: &ast::Mac, _: ()) {
     }
 
     fn visit_foreign_item(&mut self, i: &ast::ForeignItem, _: ()) {
-        match i.node {
-            ast::ForeignItemFn(..) | ast::ForeignItemStatic(..) => {
-                if attr::contains_name(i.attrs.as_slice(), "linkage") {
-                    self.gate_feature("linkage", i.span,
-                                      "the `linkage` attribute is experimental \
-                                       and not portable across platforms")
-                }
-            }
+        if attr::contains_name(i.attrs.as_slice(), "linkage") {
+            self.gate_feature("linkage", i.span,
+                              "the `linkage` attribute is experimental \
+                               and not portable across platforms")
         }
         visit::walk_foreign_item(self, i, ())
     }
@@ -338,6 +343,32 @@ fn visit_generics(&mut self, generics: &ast::Generics, _: ()) {
         }
         visit::walk_generics(self, generics, ());
     }
+
+    fn visit_attribute(&mut self, attr: &ast::Attribute, _: ()) {
+        if attr::contains_name([*attr], "lang") {
+            self.gate_feature("lang_items",
+                              attr.span,
+                              "language items are subject to change");
+        }
+    }
+
+    fn visit_fn(&mut self,
+                fn_kind: &visit::FnKind,
+                fn_decl: &ast::FnDecl,
+                block: &ast::Block,
+                span: Span,
+                _: NodeId,
+                (): ()) {
+        match *fn_kind {
+            visit::FkItemFn(_, _, _, ref abi) if *abi == RustIntrinsic => {
+                self.gate_feature("intrinsics",
+                                  span,
+                                  "intrinsics are subject to change")
+            }
+            _ => {}
+        }
+        visit::walk_fn(self, fn_kind, fn_decl, block, span, ());
+    }
 }
 
 pub fn check_crate(sess: &Session, krate: &ast::Crate) {
index e311d1e9b15bb43c6436576d9d3eb5fe7a9d77e1..34e70f4eb1a821cfa2986f6de9dd9083d7fa6fdf 100644 (file)
@@ -29,7 +29,6 @@
       html_root_url = "http://doc.rust-lang.org/")]
 
 #![allow(deprecated)]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 #![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
 #![feature(default_type_params, phase, unsafe_destructor)]
 
index 5ce63b94b2499b6f9cf4fdb06c502c0f4e1184f9..ee6c5e1f9bc318ce0a65585e3023737ab917b611 100644 (file)
@@ -3894,8 +3894,31 @@ fn resolve_trait_reference(&mut self,
                 self.resolve_error(trait_reference.path.span, msg.as_slice());
             }
             Some(def) => {
-                debug!("(resolving trait) found trait def: {:?}", def);
-                self.record_def(trait_reference.ref_id, def);
+                match def {
+                    (DefTrait(_), _) => {
+                        debug!("(resolving trait) found trait def: {:?}", def);
+                        self.record_def(trait_reference.ref_id, def);
+                    }
+                    (def, _) => {
+                        self.resolve_error(trait_reference.path.span,
+                                           format!("`{}` is not a trait",
+                                                   self.path_idents_to_str(
+                                                        &trait_reference.path)));
+
+                        // If it's a typedef, give a note
+                        match def {
+                            DefTy(_) => {
+                                self.session.span_note(
+                                                trait_reference.path.span,
+                                                format!("`type` aliases cannot \
+                                                        be used for traits")
+                                                        .as_slice());
+                            }
+                            _ => {}
+                        }
+                    }
+                }
+
             }
         }
     }
@@ -4021,6 +4044,9 @@ fn resolve_implementation(&mut self,
 
                 this.with_current_self_type(self_type, |this| {
                     for method in methods.iter() {
+                        // If this is a trait impl, ensure the method exists in trait
+                        this.check_trait_method(&**method);
+
                         // We also need a new scope for the method-specific type parameters.
                         this.resolve_method(MethodRibKind(id, Provided(method.id)),
                                             &**method);
@@ -4030,6 +4056,21 @@ fn resolve_implementation(&mut self,
         });
     }
 
+    fn check_trait_method(&self, method: &Method) {
+        // If there is a TraitRef in scope for an impl, then the method must be in the trait.
+        for &(did, ref trait_ref) in self.current_trait_ref.iter() {
+            let method_name = method.ident.name;
+
+            if self.method_map.borrow().find(&(method_name, did)).is_none() {
+                let path_str = self.path_idents_to_str(&trait_ref.path);
+                self.resolve_error(method.span,
+                                    format!("method `{}` is not a member of trait `{}`",
+                                            token::get_name(method_name),
+                                            path_str).as_slice());
+            }
+        }
+    }
+
     fn resolve_module(&mut self, module: &Mod, _span: Span,
                       _name: Ident, id: NodeId) {
         // Write the implementations in scope into the module metadata.
index 3ef2f7a0480dc7b09ecf18e90ae758f3882c5f34..00a0e8fc39bd6d92c68a803ce9a48f512eb02825 100644 (file)
@@ -850,17 +850,23 @@ fn from_uint(v: uint) -> BuiltinBound {
 }
 
 #[deriving(Clone, PartialEq, Eq, Hash)]
-pub struct TyVid(pub uint);
+pub struct TyVid {
+    pub index: uint
+}
 
 #[deriving(Clone, PartialEq, Eq, Hash)]
-pub struct IntVid(pub uint);
+pub struct IntVid {
+    pub index: uint
+}
 
 #[deriving(Clone, PartialEq, Eq, Hash)]
-pub struct FloatVid(pub uint);
+pub struct FloatVid {
+    pub index: uint
+}
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
 pub struct RegionVid {
-    pub id: uint
+    pub index: uint
 }
 
 #[deriving(Clone, PartialEq, Eq, Hash)]
@@ -893,47 +899,27 @@ fn ne(&self, other: &InferRegion) -> bool {
     }
 }
 
-pub trait Vid {
-    fn to_uint(&self) -> uint;
-}
-
-impl Vid for TyVid {
-    fn to_uint(&self) -> uint { let TyVid(v) = *self; v }
-}
-
 impl fmt::Show for TyVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
-        write!(f, "<generic #{}>", self.to_uint())
+        write!(f, "<generic #{}>", self.index)
     }
 }
 
-impl Vid for IntVid {
-    fn to_uint(&self) -> uint { let IntVid(v) = *self; v }
-}
-
 impl fmt::Show for IntVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "<generic integer #{}>", self.to_uint())
+        write!(f, "<generic integer #{}>", self.index)
     }
 }
 
-impl Vid for FloatVid {
-    fn to_uint(&self) -> uint { let FloatVid(v) = *self; v }
-}
-
 impl fmt::Show for FloatVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "<generic float #{}>", self.to_uint())
+        write!(f, "<generic float #{}>", self.index)
     }
 }
 
-impl Vid for RegionVid {
-    fn to_uint(&self) -> uint { self.id }
-}
-
 impl fmt::Show for RegionVid {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.id.fmt(f)
+        write!(f, "'<generic lifetime #{}>", self.index)
     }
 }
 
index 1c5cfc45afdb80061d77729245512533794b4ad2..04db13feff65489ea77c69ca0fba4a4289631f99 100644 (file)
@@ -784,7 +784,8 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt,
                                     &impl_trait_ref.substs);
             }
             None => {
-                tcx.sess.span_err(
+                // This is span_bug as it should have already been caught in resolve.
+                tcx.sess.span_bug(
                     impl_method.span,
                     format!(
                         "method `{}` is not a member of trait `{}`",
index cbd1479ef0930310acea44ac74c15d2f9ec1ba44..e6f79362cf2762fd5398f239d3c16078d14ce041 100644 (file)
@@ -519,7 +519,8 @@ fn universally_quantify_polytype(&self, polytype: Polytype)
     fn can_unify_universally_quantified<'a>(&self,
                                             a: &'a UniversalQuantificationResult,
                                             b: &'a UniversalQuantificationResult)
-                                            -> bool {
+                                            -> bool
+    {
         infer::can_mk_subty(&self.inference_context,
                             a.monotype,
                             b.monotype).is_ok()
index 0568542472b791c161b17a9761cf5e15dde2c4f1..9317563da934f1ab6c01bebc475a19dc86fa67ba 100644 (file)
@@ -71,9 +71,9 @@ fn foo<A>(a: A, b: A) { ... }
 use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
 use middle::typeck::infer::combine::{CombineFields, Combine};
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
 use util::common::indenter;
+use util::ppaux::Repr;
 
 use syntax::abi;
 use syntax::ast::MutImmutable;
@@ -91,8 +91,8 @@ pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> {
 
     pub fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
         debug!("Coerce.tys({} => {})",
-               a.inf_str(self.get_ref().infcx),
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx),
+               b.repr(self.get_ref().infcx.tcx));
         let _indent = indenter();
 
         // Examine the supertype and consider auto-borrowing.
@@ -233,8 +233,8 @@ pub fn coerce_borrowed_pointer(&self,
                                    mt_b: ty::mt)
                                    -> CoerceResult {
         debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx), mt_b);
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx), mt_b);
 
         // If we have a parameter of type `&M T_a` and the value
         // provided is `expr`, we will be adding an implicit borrow,
@@ -270,8 +270,8 @@ pub fn coerce_borrowed_string(&self,
                                   b: ty::t)
                                   -> CoerceResult {
         debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx));
 
         match *sty_a {
             ty::ty_uniq(t) => match ty::get(t).sty {
@@ -300,8 +300,8 @@ pub fn coerce_borrowed_vector(&self,
                                   mutbl_b: ast::Mutability)
                                   -> CoerceResult {
         debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx));
 
         let sub = Sub(self.get_ref().clone());
         let coercion = Coercion(self.get_ref().trace.clone());
@@ -336,8 +336,8 @@ fn coerce_borrowed_object(&self,
                               b_mutbl: ast::Mutability) -> CoerceResult
     {
         debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx));
 
         let tcx = self.get_ref().infcx.tcx;
         let coercion = Coercion(self.get_ref().trace.clone());
@@ -376,8 +376,8 @@ pub fn coerce_borrowed_fn(&self,
                               b: ty::t)
                               -> CoerceResult {
         debug!("coerce_borrowed_fn(a={}, sty_a={:?}, b={})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx));
 
         match *sty_a {
             ty::ty_bare_fn(ref f) => {
@@ -400,7 +400,7 @@ fn coerce_from_bare_fn(&self, a: ty::t, fn_ty_a: &ty::BareFnTy, b: ty::t)
         self.unpack_actual_value(b, |sty_b| {
 
             debug!("coerce_from_bare_fn(a={}, b={})",
-                   a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+                   a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
 
             if fn_ty_a.abi != abi::Rust || fn_ty_a.fn_style != ast::NormalFn {
                 return self.subtype(a, b);
@@ -429,8 +429,8 @@ pub fn coerce_unsafe_ptr(&self,
                              mt_b: ty::mt)
                              -> CoerceResult {
         debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx));
 
         let mt_a = match *sty_a {
             ty::ty_rptr(_, mt) => mt,
@@ -462,8 +462,8 @@ pub fn coerce_object(&self,
                          bounds: ty::BuiltinBounds) -> CoerceResult {
 
         debug!("coerce_object(a={}, sty_a={:?}, b={})",
-               a.inf_str(self.get_ref().infcx), sty_a,
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), sty_a,
+               b.repr(self.get_ref().infcx.tcx));
 
         Ok(Some(ty::AutoObject(trait_store, bounds,
                                trait_def_id, trait_substs.clone())))
index cc898ab9c66926fef84d69a6e4ac594c2b45d666..844a37d366ee53b1bd436740e19fee6c96f78468 100644 (file)
@@ -57,8 +57,7 @@
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::InferStr;
-use middle::typeck::infer::unify::InferCtxtMethods;
+use middle::typeck::infer::unify::InferCtxtMethodsForSimplyUnifiableTypes;
 use middle::typeck::infer::{InferCtxt, cres, ures};
 use middle::typeck::infer::{TypeTrace};
 use util::common::indent;
@@ -263,7 +262,7 @@ fn trait_stores(&self,
                     a: ty::TraitStore,
                     b: ty::TraitStore)
                     -> cres<ty::TraitStore> {
-        debug!("{}.trait_stores(a={:?}, b={:?})", self.tag(), a, b);
+        debug!("{}.trait_stores(a={}, b={})", self.tag(), a, b);
 
         match (a, b) {
             (ty::RegionTraitStore(a_r, a_m),
@@ -409,8 +408,8 @@ fn check_ptr_to_unsized<C:Combine>(this: &C,
         tcx.sess.bug(
             format!("{}: bot and var types should have been handled ({},{})",
                     this.tag(),
-                    a.inf_str(this.infcx()),
-                    b.inf_str(this.infcx())).as_slice());
+                    a.repr(this.infcx().tcx),
+                    b.repr(this.infcx().tcx)).as_slice());
       }
 
         // Relate integral variables to other types
index 18cfd2595139fecca3626de2ee5a09fbbe1a717c..d2c27330a94ade27e266e64a360615ac46b8d28a 100644 (file)
 use middle::typeck::infer::lattice::*;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::infer::{cres, InferCtxt};
 use middle::typeck::infer::{TypeTrace, Subtype};
 use middle::typeck::infer::fold_regions_in_sig;
+use middle::typeck::infer::region_inference::RegionMark;
 use syntax::ast::{Many, Once, MutImmutable, MutMutable};
 use syntax::ast::{NormalFn, UnsafeFn, NodeId};
 use syntax::ast::{Onceness, FnStyle};
 use std::collections::HashMap;
 use util::common::{indenter};
 use util::ppaux::mt_to_str;
+use util::ppaux::Repr;
 
 pub struct Glb<'f>(pub CombineFields<'f>);  // "greatest lower bound" (common subtype)
 
@@ -104,8 +105,8 @@ fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
         debug!("{}.regions({:?}, {:?})",
                self.tag(),
-               a.inf_str(self.get_ref().infcx),
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx),
+               b.repr(self.get_ref().infcx.tcx));
 
         Ok(self.get_ref().infcx.region_vars.glb_regions(Subtype(self.trace()), a, b))
     }
@@ -124,14 +125,12 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         // please see the large comment in `region_inference.rs`.
 
         debug!("{}.fn_sigs({:?}, {:?})",
-               self.tag(), a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+               self.tag(), a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
         let _indenter = indenter();
 
-        // Take a snapshot.  We'll never roll this back, but in later
-        // phases we do want to be able to examine "all bindings that
-        // were created as part of this type comparison", and making a
-        // snapshot is a convenient way to do that.
-        let snapshot = self.get_ref().infcx.region_vars.start_snapshot();
+        // Make a mark so we can examine "all bindings that were
+        // created as part of this type comparison".
+        let mark = self.get_ref().infcx.region_vars.mark();
 
         // Instantiate each bound region with a fresh region variable.
         let (a_with_fresh, a_map) =
@@ -145,18 +144,18 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
 
         // Collect constraints.
         let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
-        debug!("sig0 = {}", sig0.inf_str(self.get_ref().infcx));
+        debug!("sig0 = {}", sig0.repr(self.get_ref().infcx.tcx));
 
         // Generalize the regions appearing in fn_ty0 if possible
         let new_vars =
-            self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
+            self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
         let sig1 =
             fold_regions_in_sig(
                 self.get_ref().infcx.tcx,
                 &sig0,
                 |r| {
                 generalize_region(self,
-                                  snapshot,
+                                  mark,
                                   new_vars.as_slice(),
                                   sig0.binder_id,
                                   &a_map,
@@ -164,11 +163,11 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
                                   b_vars.as_slice(),
                                   r)
             });
-        debug!("sig1 = {}", sig1.inf_str(self.get_ref().infcx));
+        debug!("sig1 = {}", sig1.repr(self.get_ref().infcx.tcx));
         return Ok(sig1);
 
         fn generalize_region(this: &Glb,
-                             snapshot: uint,
+                             mark: RegionMark,
                              new_vars: &[RegionVid],
                              new_binder_id: NodeId,
                              a_map: &HashMap<ty::BoundRegion, ty::Region>,
@@ -180,7 +179,7 @@ fn generalize_region(this: &Glb,
                 return r0;
             }
 
-            let tainted = this.get_ref().infcx.region_vars.tainted(snapshot, r0);
+            let tainted = this.get_ref().infcx.region_vars.tainted(mark, r0);
 
             let mut a_r = None;
             let mut b_r = None;
index 6455344cb1351de4a88e00c10cd76dfb91cabcc1..1b3d96e474e4b5f051aae01b892f3eb4c9a959fd 100644 (file)
  * a lattice.
  */
 
-
-use middle::ty::{RegionVid, TyVar, Vid};
+use middle::ty::{RegionVid, TyVar};
 use middle::ty;
-use middle::typeck::infer::{then, ToUres};
+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::unify::{Root, UnifyKey};
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::InferStr;
-use util::common::indenter;
+use util::ppaux::Repr;
 
 use std::collections::HashMap;
 
-trait LatticeValue {
+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>;
@@ -70,72 +68,73 @@ fn glb(cf: CombineFields, a: &ty::t, b: &ty::t) -> cres<ty::t> {
     }
 }
 
-pub trait CombineFieldsLatticeMethods {
-    fn var_sub_var<T:Clone + InferStr + LatticeValue,
-                   V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(&self,
-                                                                     a_id: V,
-                                                                     b_id: V)
-                                                                     -> ures;
+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<T:Clone + InferStr + LatticeValue,
-                 V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
-                 &self,
-                 a_id: V,
+    fn var_sub_t(&self,
+                 a_id: K,
                  b: T)
                  -> ures;
-    fn t_sub_var<T:Clone + InferStr + LatticeValue,
-                 V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
-                 &self,
+
+    /// make T a subtype of variable
+    fn t_sub_var(&self,
                  a: T,
-                 b_id: V)
+                 b_id: K)
                  -> ures;
-    fn merge_bnd<T:Clone + InferStr + LatticeValue>(
-                 &self,
-                 a: &Bound<T>,
-                 b: &Bound<T>,
-                 lattice_op: LatticeOp<T>)
-                 -> cres<Bound<T>>;
-    fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
-                                V:Clone+PartialEq+ToStr+Vid+UnifyVid<Bounds<T>>>(
-                                &self,
-                                v_id: V,
+
+    fn set_var_to_merged_bounds(&self,
+                                v_id: K,
                                 a: &Bounds<T>,
                                 b: &Bounds<T>,
                                 rank: uint)
                                 -> ures;
-    fn bnds<T:Clone + InferStr + LatticeValue>(
-            &self,
-            a: &Bound<T>,
-            b: &Bound<T>)
-            -> ures;
 }
 
-impl<'f> CombineFieldsLatticeMethods for CombineFields<'f> {
-    fn var_sub_var<T:Clone + InferStr + LatticeValue,
-                   V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
-                   &self,
-                   a_id: V,
-                   b_id: V)
-                   -> 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*/
+         * 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 = self.infcx.get(a_id);
-        let node_b = self.infcx.get(b_id);
-        let a_id = node_a.root.clone();
-        let b_id = node_b.root.clone();
-        let a_bounds = node_a.possible_types.clone();
-        let b_bounds = node_b.possible_types.clone();
+        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.to_str(), a_bounds.inf_str(self.infcx),
-               b_id.to_str(), b_bounds.inf_str(self.infcx));
+               a_id, a_bounds.repr(tcx),
+               b_id, b_bounds.repr(tcx));
 
-        if a_id == b_id { return uok(); }
+        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.
@@ -157,96 +156,72 @@ fn var_sub_var<T:Clone + InferStr + LatticeValue,
         // 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) = self.infcx.unify(&node_a, &node_b);
+        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<T:Clone + InferStr + LatticeValue,
-                 V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
-                 &self,
-                 a_id: V,
+    fn var_sub_t(&self,
+                 a_id: K,
                  b: T)
-                 -> ures {
+                 -> ures
+    {
         /*!
-         *
-         * Make a variable (`a_id`) a subtype of the concrete type `b` */
-
-        let node_a = self.infcx.get(a_id);
-        let a_id = node_a.root.clone();
-        let a_bounds = &node_a.possible_types;
+         * 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.to_str(),
-               a_bounds.inf_str(self.infcx),
-               b.inf_str(self.infcx));
+               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<T:Clone + InferStr + LatticeValue,
-                 V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
-                 &self,
+    fn t_sub_var(&self,
                  a: T,
-                 b_id: V)
-                 -> ures {
+                 b_id: K)
+                 -> ures
+    {
         /*!
-         *
-         * Make a concrete type (`a`) a subtype of the variable `b_id` */
+         * 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 = self.infcx.get(b_id);
-        let b_id = node_b.root.clone();
-        let b_bounds = &node_b.possible_types;
+        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.inf_str(self.infcx),
-               b_id.to_str(),
-               b_bounds.inf_str(self.infcx));
+               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 merge_bnd<T:Clone + InferStr + LatticeValue>(
-                 &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.inf_str(self.infcx),
-               b.inf_str(self.infcx));
-        let _r = indenter();
-
-        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 set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
-                                V:Clone+PartialEq+ToStr+Vid+UnifyVid<Bounds<T>>>(
-                                &self,
-                                v_id: V,
+    fn set_var_to_merged_bounds(&self,
+                                v_id: K,
                                 a: &Bounds<T>,
                                 b: &Bounds<T>,
                                 rank: uint)
-                                -> ures {
+                                -> 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:
@@ -254,7 +229,8 @@ fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
          *    c.ub <: b.ub
          *    a.lb <: c.lb
          *    b.lb <: c.lb
-         * If this cannot be achieved, the result is failure. */
+         * 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
@@ -271,11 +247,13 @@ fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
         //       A     \ / A
         //              B
 
+        let tcx = self.infcx.tcx;
+        let table = UnifyKey::unification_table(self.infcx);
+
         debug!("merge({},{},{})",
-               v_id.to_str(),
-               a.inf_str(self.infcx),
-               b.inf_str(self.infcx));
-        let _indent = indenter();
+               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
@@ -289,29 +267,57 @@ fn set_var_to_merged_bounds<T:Clone + InferStr + LatticeValue,
         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.to_str(),
-               bounds.inf_str(self.infcx));
+               v_id,
+               bounds.repr(self.infcx.tcx));
 
         // the new bounds must themselves
         // be relatable:
         let () = if_ok!(self.bnds(&bounds.lb, &bounds.ub));
-        self.infcx.set(v_id, Root(bounds, rank));
-        uok()
+        table.borrow_mut().set(tcx, v_id, Root(bounds, rank));
+        Ok(())
     }
+}
 
-    fn bnds<T:Clone + InferStr + LatticeValue>(&self,
-                                               a: &Bound<T>,
-                                               b: &Bound<T>)
-                                               -> ures {
-        debug!("bnds({} <: {})", a.inf_str(self.infcx),
-               b.inf_str(self.infcx));
-        let _r = indenter();
+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(_)) => {
-                uok()
+                Ok(())
             }
             (&Some(ref t_a), &Some(ref t_b)) => {
                 LatticeValue::sub(self.clone(), t_a, t_b)
@@ -368,9 +374,10 @@ pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
                                                             a: ty::t,
                                                             b: ty::t)
                                                             -> cres<ty::t> {
-    debug!("{}.lattice_tys({}, {})", this.tag(),
-           a.inf_str(this.infcx()),
-           b.inf_str(this.infcx()));
+    debug!("{}.lattice_tys({}, {})",
+           this.tag(),
+           a.repr(this.infcx().tcx),
+           b.repr(this.infcx().tcx));
 
     if a == b {
         return Ok(a);
@@ -410,8 +417,8 @@ pub fn super_lattice_tys<L:LatticeDir+TyLatticeDir+Combine>(this: &L,
 pub type LatticeDirOp<'a, T> = |a: &T, b: &T|: 'a -> cres<T>;
 
 #[deriving(Clone)]
-pub enum LatticeVarResult<V,T> {
-    VarResult(V),
+pub enum LatticeVarResult<K,T> {
+    VarResult(K),
     ValueResult(T)
 }
 
@@ -429,26 +436,31 @@ pub enum LatticeVarResult<V,T> {
  * - 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:Clone + InferStr + LatticeValue,
-                    V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
+ *   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: V,                          // first variable
-    b_vid: V,                          // second variable
+    a_vid: K,                           // first variable
+    b_vid: K,                           // second variable
     lattice_dir_op: LatticeDirOp<T>)    // LUB or GLB operation on types
-    -> cres<LatticeVarResult<V,T>> {
-    let nde_a = this.infcx().get(a_vid);
-    let nde_b = this.infcx().get(b_vid);
-    let a_vid = nde_a.root.clone();
-    let b_vid = nde_b.root.clone();
-    let a_bounds = &nde_a.possible_types;
-    let b_bounds = &nde_b.possible_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.to_str(), a_bounds.inf_str(this.infcx()),
-           b_vid.to_str(), b_bounds.inf_str(this.infcx()));
+           a_vid, a_bounds.repr(tcx),
+           b_vid, b_bounds.repr(tcx));
 
     // Same variable: the easy case.
     if a_vid == b_vid {
@@ -471,36 +483,39 @@ pub fn lattice_vars<L:LatticeDir + Combine,
     // 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();
-    cf.var_sub_var(a_vid.clone(), b_vid.clone()).then(|| {
-        Ok(VarResult(a_vid.clone()))
-    })
+    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:Clone + InferStr + LatticeValue,
-                         V:Clone + PartialEq + ToStr + Vid + UnifyVid<Bounds<T>>>(
+pub fn lattice_var_and_t<L:LatticeDir+Combine,
+                         T:LatticeValue,
+                         K:UnifyKey<Bounds<T>>>(
     this: &L,
-    a_id: V,
+    a_id: K,
     b: &T,
     lattice_dir_op: LatticeDirOp<T>)
-    -> cres<T> {
-    let nde_a = this.infcx().get(a_id);
-    let a_id = nde_a.root.clone();
-    let a_bounds = &nde_a.possible_types;
+    -> 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.to_str(),
-           a_bounds.inf_str(this.infcx()),
-           b.inf_str(this.infcx()));
+           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.inf_str(this.infcx()));
+            debug!("bnd=Some({})", a_bnd.repr(this.infcx().tcx));
             lattice_dir_op(a_bnd, b)
         }
         None => {
@@ -508,11 +523,12 @@ pub fn lattice_var_and_t<L:LatticeDir + Combine,
             // and then return b.
             debug!("bnd=None");
             let a_bounds = this.with_bnd(a_bounds, (*b).clone());
-            this.combine_fields().bnds(&a_bounds.lb, &a_bounds.ub).then(|| {
-                this.infcx().set(a_id.clone(),
-                                 Root(a_bounds.clone(), nde_a.rank));
-                Ok((*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())
         }
     }
 }
index 41784c9b8d94455fd3d3b1ff45a507fbb4c820ad..7ccffdfeb062fc1ffa4ba2d735784ba41798c354 100644 (file)
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lattice::*;
 use middle::typeck::infer::sub::Sub;
-use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::infer::{cres, InferCtxt};
 use middle::typeck::infer::fold_regions_in_sig;
 use middle::typeck::infer::{TypeTrace, Subtype};
+use middle::typeck::infer::region_inference::RegionMark;
 use std::collections::HashMap;
 use syntax::ast::{Many, Once, NodeId};
 use syntax::ast::{NormalFn, UnsafeFn};
 use syntax::ast::{Onceness, FnStyle};
 use syntax::ast::{MutMutable, MutImmutable};
 use util::ppaux::mt_to_str;
+use util::ppaux::Repr;
 
 pub struct Lub<'f>(pub CombineFields<'f>);  // least-upper-bound: common supertype
 
@@ -101,10 +102,10 @@ fn contraregions(&self, a: ty::Region, b: ty::Region)
     }
 
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
-        debug!("{}.regions({:?}, {:?})",
+        debug!("{}.regions({}, {})",
                self.tag(),
-               a.inf_str(self.get_ref().infcx),
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx),
+               b.repr(self.get_ref().infcx.tcx));
 
         Ok(self.get_ref().infcx.region_vars.lub_regions(Subtype(self.trace()), a, b))
     }
@@ -113,11 +114,9 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         // Note: this is a subtle algorithm.  For a full explanation,
         // please see the large comment in `region_inference.rs`.
 
-        // Take a snapshot.  We'll never roll this back, but in later
-        // phases we do want to be able to examine "all bindings that
-        // were created as part of this type comparison", and making a
-        // snapshot is a convenient way to do that.
-        let snapshot = self.get_ref().infcx.region_vars.start_snapshot();
+        // Make a mark so we can examine "all bindings that were
+        // created as part of this type comparison".
+        let mark = self.get_ref().infcx.region_vars.mark();
 
         // Instantiate each bound region with a fresh region variable.
         let (a_with_fresh, a_map) =
@@ -129,21 +128,21 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
 
         // Collect constraints.
         let sig0 = if_ok!(super_fn_sigs(self, &a_with_fresh, &b_with_fresh));
-        debug!("sig0 = {}", sig0.inf_str(self.get_ref().infcx));
+        debug!("sig0 = {}", sig0.repr(self.get_ref().infcx.tcx));
 
         // Generalize the regions appearing in sig0 if possible
         let new_vars =
-            self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
+            self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
         let sig1 =
             fold_regions_in_sig(
                 self.get_ref().infcx.tcx,
                 &sig0,
-                |r| generalize_region(self, snapshot, new_vars.as_slice(),
+                |r| generalize_region(self, mark, new_vars.as_slice(),
                                       sig0.binder_id, &a_map, r));
         return Ok(sig1);
 
         fn generalize_region(this: &Lub,
-                             snapshot: uint,
+                             mark: RegionMark,
                              new_vars: &[RegionVid],
                              new_scope: NodeId,
                              a_map: &HashMap<ty::BoundRegion, ty::Region>,
@@ -156,7 +155,7 @@ fn generalize_region(this: &Lub,
                 return r0;
             }
 
-            let tainted = this.get_ref().infcx.region_vars.tainted(snapshot, r0);
+            let tainted = this.get_ref().infcx.region_vars.tainted(mark, r0);
 
             // Variables created during LUB computation which are
             // *related* to regions that pre-date the LUB computation
index 7a7dbaa549a5cff0b515814be3b9a17925c8b1e5..bb458d27d17ac5688230b6046192b6ad91ded9a2 100644 (file)
 
 use middle::subst;
 use middle::subst::Substs;
-use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, Vid};
+use middle::ty::{TyVid, IntVid, FloatVid, RegionVid};
 use middle::ty;
 use middle::ty_fold;
 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::{RegionVarBindings};
+use middle::typeck::infer::region_inference::{RegionVarBindings,
+                                              RegionSnapshot};
 use middle::typeck::infer::resolve::{resolver};
 use middle::typeck::infer::sub::Sub;
 use middle::typeck::infer::lub::Lub;
-use middle::typeck::infer::to_str::InferStr;
-use middle::typeck::infer::unify::{ValsAndBindings, Root};
+use middle::typeck::infer::unify::{UnificationTable, Snapshot};
 use middle::typeck::infer::error_reporting::ErrorReporting;
-use std::cell::{Cell, RefCell};
+use std::cell::{RefCell};
 use std::collections::HashMap;
 use std::rc::Rc;
 use syntax::ast;
 pub mod region_inference;
 pub mod resolve;
 pub mod sub;
-pub mod to_str;
 pub mod unify;
 pub mod coercion;
 pub mod error_reporting;
+pub mod test;
 
 pub type Bound<T> = Option<T>;
 
-#[deriving(Clone)]
+#[deriving(PartialEq,Clone)]
 pub struct Bounds<T> {
-    lb: Bound<T>,
-    ub: Bound<T>
+    pub lb: Bound<T>,
+    pub ub: Bound<T>
 }
 
 pub type cres<T> = Result<T,ty::type_err>; // "combine result"
@@ -76,24 +76,23 @@ pub struct Bounds<T> {
 pub struct InferCtxt<'a> {
     pub tcx: &'a ty::ctxt,
 
-    // We instantiate ValsAndBindings with bounds<ty::t> because the
+    // 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.
-    pub ty_var_bindings: RefCell<ValsAndBindings<ty::TyVid, Bounds<ty::t>>>,
-    pub ty_var_counter: Cell<uint>,
+    type_unification_table:
+        RefCell<UnificationTable<ty::TyVid, Bounds<ty::t>>>,
 
     // Map from integral variable to the kind of integer it represents
-    pub int_var_bindings: RefCell<ValsAndBindings<ty::IntVid,
-                                              Option<IntVarValue>>>,
-    pub int_var_counter: Cell<uint>,
+    int_unification_table:
+        RefCell<UnificationTable<ty::IntVid, Option<IntVarValue>>>,
 
     // Map from floating variable to the kind of float it represents
-    pub float_var_bindings: RefCell<ValsAndBindings<ty::FloatVid,
-                                                Option<ast::FloatTy>>>,
-    pub float_var_counter: Cell<uint>,
+    float_unification_table:
+        RefCell<UnificationTable<ty::FloatVid, Option<ast::FloatTy>>>,
 
     // For region variables.
-    pub region_vars: RegionVarBindings<'a>,
+    region_vars:
+        RegionVarBindings<'a>,
 }
 
 /// Why did we require that the two types be related?
@@ -261,16 +260,9 @@ pub fn fixup_err_to_str(f: fixup_err) -> String {
 pub fn new_infer_ctxt<'a>(tcx: &'a ty::ctxt) -> InferCtxt<'a> {
     InferCtxt {
         tcx: tcx,
-
-        ty_var_bindings: RefCell::new(ValsAndBindings::new()),
-        ty_var_counter: Cell::new(0),
-
-        int_var_bindings: RefCell::new(ValsAndBindings::new()),
-        int_var_counter: Cell::new(0),
-
-        float_var_bindings: RefCell::new(ValsAndBindings::new()),
-        float_var_counter: Cell::new(0),
-
+        type_unification_table: RefCell::new(UnificationTable::new()),
+        int_unification_table: RefCell::new(UnificationTable::new()),
+        float_unification_table: RefCell::new(UnificationTable::new()),
         region_vars: RegionVarBindings::new(tcx),
     }
 }
@@ -280,20 +272,23 @@ pub fn common_supertype(cx: &InferCtxt,
                         a_is_expected: bool,
                         a: ty::t,
                         b: ty::t)
-                        -> ty::t {
+                        -> ty::t
+{
     /*!
      * Computes the least upper-bound of `a` and `b`. If this is
      * not possible, reports an error and returns ty::err.
      */
 
-    debug!("common_supertype({}, {})", a.inf_str(cx), b.inf_str(cx));
+    debug!("common_supertype({}, {})",
+           a.repr(cx.tcx), b.repr(cx.tcx));
 
     let trace = TypeTrace {
         origin: origin,
         values: Types(expected_found(a_is_expected, a, b))
     };
 
-    let result = cx.commit(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
+    let result =
+        cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b));
     match result {
         Ok(t) => t,
         Err(ref err) => {
@@ -309,9 +304,9 @@ pub fn mk_subty(cx: &InferCtxt,
                 a: ty::t,
                 b: ty::t)
              -> ures {
-    debug!("mk_subty({} <: {})", a.inf_str(cx), b.inf_str(cx));
+    debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
     indent(|| {
-        cx.commit(|| {
+        cx.commit_if_ok(|| {
             let trace = TypeTrace {
                 origin: origin,
                 values: Types(expected_found(a_is_expected, a, b))
@@ -322,15 +317,13 @@ pub fn mk_subty(cx: &InferCtxt,
 }
 
 pub fn can_mk_subty(cx: &InferCtxt, a: ty::t, b: ty::t) -> ures {
-    debug!("can_mk_subty({} <: {})", a.inf_str(cx), b.inf_str(cx));
-    indent(|| {
-        cx.probe(|| {
-            let trace = TypeTrace {
-                origin: Misc(codemap::DUMMY_SP),
-                values: Types(expected_found(true, a, b))
-            };
-            cx.sub(true, trace).tys(a, b)
-        })
+    debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    cx.probe(|| {
+        let trace = TypeTrace {
+            origin: Misc(codemap::DUMMY_SP),
+            values: Types(expected_found(true, a, b))
+        };
+        cx.sub(true, trace).tys(a, b)
     }).to_ures()
 }
 
@@ -339,10 +332,10 @@ pub fn mk_subr(cx: &InferCtxt,
                origin: SubregionOrigin,
                a: ty::Region,
                b: ty::Region) {
-    debug!("mk_subr({} <: {})", a.inf_str(cx), b.inf_str(cx));
-    cx.region_vars.start_snapshot();
+    debug!("mk_subr({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    let snapshot = cx.region_vars.start_snapshot();
     cx.region_vars.make_subregion(origin, a, b);
-    cx.region_vars.commit();
+    cx.region_vars.commit(snapshot);
 }
 
 pub fn mk_eqty(cx: &InferCtxt,
@@ -350,18 +343,17 @@ pub fn mk_eqty(cx: &InferCtxt,
                origin: TypeOrigin,
                a: ty::t,
                b: ty::t)
-            -> ures {
-    debug!("mk_eqty({} <: {})", a.inf_str(cx), b.inf_str(cx));
-    indent(|| {
-        cx.commit(|| {
-            let trace = TypeTrace {
-                origin: origin,
-                values: Types(expected_found(a_is_expected, a, b))
-            };
-            let suber = cx.sub(a_is_expected, trace);
-            eq_tys(&suber, a, b)
-        })
-    }).to_ures()
+            -> ures
+{
+    debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+    cx.commit_if_ok(|| {
+        let trace = TypeTrace {
+            origin: origin,
+            values: Types(expected_found(a_is_expected, a, b))
+        };
+        let suber = cx.sub(a_is_expected, trace);
+        eq_tys(&suber, a, b)
+    })
 }
 
 pub fn mk_sub_trait_refs(cx: &InferCtxt,
@@ -372,9 +364,9 @@ pub fn mk_sub_trait_refs(cx: &InferCtxt,
     -> ures
 {
     debug!("mk_sub_trait_refs({} <: {})",
-           a.inf_str(cx), b.inf_str(cx));
+           a.repr(cx.tcx), b.repr(cx.tcx));
     indent(|| {
-        cx.commit(|| {
+        cx.commit_if_ok(|| {
             let trace = TypeTrace {
                 origin: origin,
                 values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
@@ -401,9 +393,9 @@ pub fn mk_coercety(cx: &InferCtxt,
                    a: ty::t,
                    b: ty::t)
                 -> CoerceResult {
-    debug!("mk_coercety({} -> {})", a.inf_str(cx), b.inf_str(cx));
+    debug!("mk_coercety({} -> {})", a.repr(cx.tcx), b.repr(cx.tcx));
     indent(|| {
-        cx.commit(|| {
+        cx.commit_if_ok(|| {
             let trace = TypeTrace {
                 origin: origin,
                 values: Types(expected_found(a_is_expected, a, b))
@@ -417,13 +409,15 @@ pub fn mk_coercety(cx: &InferCtxt,
 pub fn resolve_type(cx: &InferCtxt,
                     a: ty::t,
                     modes: uint)
-                 -> fres<ty::t> {
+                 -> fres<ty::t>
+{
     let mut resolver = resolver(cx, modes);
-    resolver.resolve_type_chk(a)
+    cx.commit_unconditionally(|| resolver.resolve_type_chk(a))
 }
 
 pub fn resolve_region(cx: &InferCtxt, r: ty::Region, modes: uint)
-                   -> fres<ty::Region> {
+                   -> fres<ty::Region>
+{
     let mut resolver = resolver(cx, modes);
     resolver.resolve_region_chk(r)
 }
@@ -473,19 +467,11 @@ pub fn uok() -> ures {
     Ok(())
 }
 
-fn rollback_to<V:Clone + Vid,T:Clone>(vb: &mut ValsAndBindings<V, T>,
-                                      len: uint) {
-    while vb.bindings.len() != len {
-        let (vid, old_v) = vb.bindings.pop().unwrap();
-        vb.vals.insert(vid.to_uint(), old_v);
-    }
-}
-
-pub struct Snapshot {
-    ty_var_bindings_len: uint,
-    int_var_bindings_len: uint,
-    float_var_bindings_len: uint,
-    region_vars_snapshot: uint,
+pub struct CombinedSnapshot {
+    type_snapshot: Snapshot<ty::TyVid>,
+    int_snapshot: Snapshot<ty::IntVid>,
+    float_snapshot: Snapshot<ty::FloatVid>,
+    region_vars_snapshot: RegionSnapshot,
 }
 
 impl<'a> InferCtxt<'a> {
@@ -508,40 +494,67 @@ pub fn in_snapshot(&self) -> bool {
         self.region_vars.in_snapshot()
     }
 
-    pub fn start_snapshot(&self) -> Snapshot {
-        Snapshot {
-            ty_var_bindings_len: self.ty_var_bindings.borrow().bindings.len(),
-            int_var_bindings_len: self.int_var_bindings.borrow().bindings.len(),
-            float_var_bindings_len: self.float_var_bindings.borrow().bindings.len(),
+    fn start_snapshot(&self) -> CombinedSnapshot {
+        CombinedSnapshot {
+            type_snapshot: self.type_unification_table.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(),
         }
     }
 
-    pub fn rollback_to(&self, snapshot: &Snapshot) {
+    fn rollback_to(&self, snapshot: CombinedSnapshot) {
         debug!("rollback!");
-        rollback_to(&mut *self.ty_var_bindings.borrow_mut(),
-                    snapshot.ty_var_bindings_len);
-        rollback_to(&mut *self.int_var_bindings.borrow_mut(),
-                    snapshot.int_var_bindings_len);
-        rollback_to(&mut *self.float_var_bindings.borrow_mut(),
-                    snapshot.float_var_bindings_len);
-
-        self.region_vars.rollback_to(snapshot.region_vars_snapshot);
+        let CombinedSnapshot { type_snapshot,
+                               int_snapshot,
+                               float_snapshot,
+                               region_vars_snapshot } = snapshot;
+
+        self.type_unification_table
+            .borrow_mut()
+            .rollback_to(self.tcx, type_snapshot);
+        self.int_unification_table
+            .borrow_mut()
+            .rollback_to(self.tcx, int_snapshot);
+        self.float_unification_table
+            .borrow_mut()
+            .rollback_to(self.tcx, float_snapshot);
+        self.region_vars
+            .rollback_to(region_vars_snapshot);
+    }
+
+    fn commit_from(&self, snapshot: CombinedSnapshot) {
+        debug!("commit_from!");
+        let CombinedSnapshot { type_snapshot,
+                               int_snapshot,
+                               float_snapshot,
+                               region_vars_snapshot } = snapshot;
+
+        self.type_unification_table
+            .borrow_mut()
+            .commit(type_snapshot);
+        self.int_unification_table
+            .borrow_mut()
+            .commit(int_snapshot);
+        self.float_unification_table
+            .borrow_mut()
+            .commit(float_snapshot);
+        self.region_vars
+            .commit(region_vars_snapshot);
+    }
+
+    /// Execute `f` and commit the bindings
+    pub fn commit_unconditionally<R>(&self, f: || -> R) -> R {
+        debug!("commit()");
+        let snapshot = self.start_snapshot();
+        let r = f();
+        self.commit_from(snapshot);
+        r
     }
 
     /// Execute `f` and commit the bindings if successful
-    pub fn commit<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
-        assert!(!self.in_snapshot());
-
-        debug!("commit()");
-        indent(|| {
-            let r = self.try(|| f());
-
-            self.ty_var_bindings.borrow_mut().bindings.truncate(0);
-            self.int_var_bindings.borrow_mut().bindings.truncate(0);
-            self.region_vars.commit();
-            r
-        })
+    pub fn commit_if_ok<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
+        self.commit_unconditionally(|| self.try(|| f()))
     }
 
     /// Execute `f`, unroll bindings on failure
@@ -549,11 +562,13 @@ pub fn try<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
         debug!("try()");
         let snapshot = self.start_snapshot();
         let r = f();
+        debug!("try() -- r.is_ok() = {}", r.is_ok());
         match r {
-            Ok(_) => { debug!("success"); }
-            Err(ref e) => {
-                debug!("error: {:?}", *e);
-                self.rollback_to(&snapshot)
+            Ok(_) => {
+                self.commit_from(snapshot);
+            }
+            Err(_) => {
+                self.rollback_to(snapshot);
             }
         }
         r
@@ -562,36 +577,18 @@ pub fn try<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
     /// Execute `f` then unroll any bindings it creates
     pub fn probe<T,E>(&self, f: || -> Result<T,E>) -> Result<T,E> {
         debug!("probe()");
-        indent(|| {
-            let snapshot = self.start_snapshot();
-            let r = f();
-            self.rollback_to(&snapshot);
-            r
-        })
+        let snapshot = self.start_snapshot();
+        let r = f();
+        self.rollback_to(snapshot);
+        r
     }
 }
 
-fn next_simple_var<V:Clone,T:Clone>(counter: &mut uint,
-                                    bindings: &mut ValsAndBindings<V,
-                                                                   Option<T>>)
-                                    -> uint {
-    let id = *counter;
-    *counter += 1;
-    bindings.vals.insert(id, Root(None, 0));
-    return id;
-}
-
 impl<'a> InferCtxt<'a> {
     pub fn next_ty_var_id(&self) -> TyVid {
-        let id = self.ty_var_counter.get();
-        self.ty_var_counter.set(id + 1);
-        {
-            let mut ty_var_bindings = self.ty_var_bindings.borrow_mut();
-            let vals = &mut ty_var_bindings.vals;
-            vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u));
-        }
-        debug!("created type variable {}", TyVid(id));
-        return TyVid(id);
+        self.type_unification_table
+            .borrow_mut()
+            .new_key(Bounds { lb: None, ub: None })
     }
 
     pub fn next_ty_var(&self) -> ty::t {
@@ -603,21 +600,15 @@ pub fn next_ty_vars(&self, n: uint) -> Vec<ty::t> {
     }
 
     pub fn next_int_var_id(&self) -> IntVid {
-        let mut int_var_counter = self.int_var_counter.get();
-        let mut int_var_bindings = self.int_var_bindings.borrow_mut();
-        let result = IntVid(next_simple_var(&mut int_var_counter,
-                                            &mut *int_var_bindings));
-        self.int_var_counter.set(int_var_counter);
-        result
+        self.int_unification_table
+            .borrow_mut()
+            .new_key(None)
     }
 
     pub fn next_float_var_id(&self) -> FloatVid {
-        let mut float_var_counter = self.float_var_counter.get();
-        let mut float_var_bindings = self.float_var_bindings.borrow_mut();
-        let result = FloatVid(next_simple_var(&mut float_var_counter,
-                                              &mut *float_var_bindings));
-        self.float_var_counter.set(float_var_counter);
-        result
+        self.float_unification_table
+            .borrow_mut()
+            .new_key(None)
     }
 
     pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
index 8ea15d2542047d50ace71e012b02a66c55ab0e5a..c81d4b17d9ba226b3939506507adf2b76c7287c8 100644 (file)
@@ -12,7 +12,7 @@
 
 
 use middle::ty;
-use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid, Vid};
+use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
 use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound,
                  ReLateBound};
 use middle::ty::{ReScope, ReVar, ReSkolemized, BrFresh};
@@ -45,13 +45,17 @@ pub struct TwoRegions {
     b: Region,
 }
 
+#[deriving(PartialEq)]
 pub enum UndoLogEntry {
-    Snapshot,
+    OpenSnapshot,
+    CommitedSnapshot,
+    Mark,
     AddVar(RegionVid),
     AddConstraint(Constraint),
     AddCombination(CombineMapType, TwoRegions)
 }
 
+#[deriving(PartialEq)]
 pub enum CombineMapType {
     Lub, Glb
 }
@@ -131,16 +135,27 @@ pub struct RegionVarBindings<'a> {
     // The undo log records actions that might later be undone.
     //
     // Note: when the undo_log is empty, we are not actively
-    // snapshotting.  When the `start_snapshot()` method is called, we
-    // push a Snapshot entry onto the list to indicate that we are now
-    // actively snapshotting.  The reason for this is that otherwise
-    // we end up adding entries for things like the lower bound on
-    // a variable and so forth, which can never be rolled back.
-    undo_log: RefCell<Vec<UndoLogEntry> >,
+    // snapshotting. When the `start_snapshot()` method is called, we
+    // push an OpenSnapshot entry onto the list to indicate that we
+    // are now actively snapshotting. The reason for this is that
+    // otherwise we end up adding entries for things like the lower
+    // bound on a variable and so forth, which can never be rolled
+    // back.
+    undo_log: RefCell<Vec<UndoLogEntry>>,
 
     // This contains the results of inference.  It begins as an empty
     // option and only acquires a value after inference is complete.
-    values: RefCell<Option<Vec<VarValue> >>,
+    values: RefCell<Option<Vec<VarValue>>>,
+}
+
+#[deriving(Show)]
+pub struct RegionSnapshot {
+    length: uint
+}
+
+#[deriving(Show)]
+pub struct RegionMark {
+    length: uint
 }
 
 impl<'a> RegionVarBindings<'a> {
@@ -162,48 +177,62 @@ pub fn in_snapshot(&self) -> bool {
         self.undo_log.borrow().len() > 0
     }
 
-    pub fn start_snapshot(&self) -> uint {
-        debug!("RegionVarBindings: start_snapshot()");
-        if self.in_snapshot() {
-            self.undo_log.borrow().len()
-        } else {
-            self.undo_log.borrow_mut().push(Snapshot);
-            0
-        }
+    pub fn start_snapshot(&self) -> RegionSnapshot {
+        let length = self.undo_log.borrow().len();
+        debug!("RegionVarBindings: start_snapshot({})", length);
+        self.undo_log.borrow_mut().push(OpenSnapshot);
+        RegionSnapshot { length: length }
+    }
+
+    pub fn mark(&self) -> RegionMark {
+        let length = self.undo_log.borrow().len();
+        debug!("RegionVarBindings: mark({})", length);
+        self.undo_log.borrow_mut().push(Mark);
+        RegionMark { length: length }
     }
 
-    pub fn commit(&self) {
+    pub fn commit(&self, snapshot: RegionSnapshot) {
         debug!("RegionVarBindings: commit()");
+        assert!(self.undo_log.borrow().len() > snapshot.length);
+        assert!(*self.undo_log.borrow().get(snapshot.length) == OpenSnapshot);
+
         let mut undo_log = self.undo_log.borrow_mut();
-        while undo_log.len() > 0 {
-            undo_log.pop().unwrap();
+        if snapshot.length == 0 {
+            undo_log.truncate(0);
+        } else {
+            *undo_log.get_mut(snapshot.length) = CommitedSnapshot;
         }
     }
 
-    pub fn rollback_to(&self, snapshot: uint) {
+    pub fn rollback_to(&self, snapshot: RegionSnapshot) {
         debug!("RegionVarBindings: rollback_to({})", snapshot);
         let mut undo_log = self.undo_log.borrow_mut();
-        while undo_log.len() > snapshot {
-            let undo_item = undo_log.pop().unwrap();
-            debug!("undo_item={:?}", undo_item);
-            match undo_item {
-              Snapshot => {}
-              AddVar(vid) => {
-                let mut var_origins = self.var_origins.borrow_mut();
-                assert_eq!(var_origins.len(), vid.to_uint() + 1);
-                var_origins.pop().unwrap();
-              }
-              AddConstraint(ref constraint) => {
-                self.constraints.borrow_mut().remove(constraint);
-              }
-              AddCombination(Glb, ref regions) => {
-                self.glbs.borrow_mut().remove(regions);
-              }
-              AddCombination(Lub, ref regions) => {
-                self.lubs.borrow_mut().remove(regions);
-              }
+        assert!(undo_log.len() > snapshot.length);
+        assert!(*undo_log.get(snapshot.length) == OpenSnapshot);
+        while undo_log.len() > snapshot.length + 1 {
+            match undo_log.pop().unwrap() {
+                OpenSnapshot => {
+                    fail!("Failure to observe stack discipline");
+                }
+                Mark | CommitedSnapshot => { }
+                AddVar(vid) => {
+                    let mut var_origins = self.var_origins.borrow_mut();
+                    assert_eq!(var_origins.len(), vid.index + 1);
+                    var_origins.pop().unwrap();
+                }
+                AddConstraint(ref constraint) => {
+                    self.constraints.borrow_mut().remove(constraint);
+                }
+                AddCombination(Glb, ref regions) => {
+                    self.glbs.borrow_mut().remove(regions);
+                }
+                AddCombination(Lub, ref regions) => {
+                    self.lubs.borrow_mut().remove(regions);
+                }
             }
         }
+        let c = undo_log.pop().unwrap();
+        assert!(c == OpenSnapshot);
     }
 
     pub fn num_vars(&self) -> uint {
@@ -213,7 +242,7 @@ pub fn num_vars(&self) -> uint {
     pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid {
         let id = self.num_vars();
         self.var_origins.borrow_mut().push(origin.clone());
-        let vid = RegionVid { id: id };
+        let vid = RegionVid { index: id };
         if self.in_snapshot() {
             self.undo_log.borrow_mut().push(AddVar(vid));
         }
@@ -368,15 +397,15 @@ pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
         let v = match *self.values.borrow() {
             None => {
                 self.tcx.sess.span_bug(
-                    self.var_origins.borrow().get(rid.to_uint()).span(),
+                    self.var_origins.borrow().get(rid.index).span(),
                     "attempt to resolve region variable before values have \
                      been computed!")
             }
-            Some(ref values) => *values.get(rid.to_uint())
+            Some(ref values) => *values.get(rid.index)
         };
 
         debug!("RegionVarBindings: resolve_var({:?}={})={:?}",
-               rid, rid.to_uint(), v);
+               rid, rid.index, v);
         match v {
             Value(r) => r,
 
@@ -427,9 +456,12 @@ pub fn combine_vars(&self,
         ReInfer(ReVar(c))
     }
 
-    pub fn vars_created_since_snapshot(&self, snapshot: uint)
-                                       -> Vec<RegionVid> {
-        self.undo_log.borrow().slice_from(snapshot).iter()
+    pub fn vars_created_since_mark(&self, mark: RegionMark)
+                                   -> Vec<RegionVid>
+    {
+        self.undo_log.borrow()
+            .slice_from(mark.length)
+            .iter()
             .filter_map(|&elt| match elt {
                 AddVar(vid) => Some(vid),
                 _ => None
@@ -437,20 +469,18 @@ pub fn vars_created_since_snapshot(&self, snapshot: uint)
             .collect()
     }
 
-    pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
+    pub fn tainted(&self, mark: RegionMark, r0: Region) -> Vec<Region> {
         /*!
          * Computes all regions that have been related to `r0` in any
-         * way since the snapshot `snapshot` was taken---`r0` itself
-         * will be the first entry. This is used when checking whether
+         * way since the mark `mark` was made---`r0` itself will be
+         * the first entry. This is used when checking whether
          * skolemized regions are being improperly related to other
          * regions.
          */
 
-        debug!("tainted(snapshot={}, r0={:?})", snapshot, r0);
+        debug!("tainted(mark={}, r0={})", mark, r0.repr(self.tcx));
         let _indenter = indenter();
 
-        let undo_len = self.undo_log.borrow().len();
-
         // `result_set` acts as a worklist: we explore all outgoing
         // edges and add any new regions we find to result_set.  This
         // is not a terribly efficient implementation.
@@ -459,16 +489,14 @@ pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
         while result_index < result_set.len() {
             // nb: can't use uint::range() here because result_set grows
             let r = *result_set.get(result_index);
-
             debug!("result_index={}, r={:?}", result_index, r);
 
-            let mut undo_index = snapshot;
-            while undo_index < undo_len {
-                // nb: can't use uint::range() here as we move result_set
-                let regs = match self.undo_log.borrow().get(undo_index) {
+            for undo_entry in
+                self.undo_log.borrow().slice_from(mark.length).iter()
+            {
+                let regs = match undo_entry {
                     &AddConstraint(ConstrainVarSubVar(ref a, ref b)) => {
-                        Some((ReInfer(ReVar(*a)),
-                              ReInfer(ReVar(*b))))
+                        Some((ReInfer(ReVar(*a)), ReInfer(ReVar(*b))))
                     }
                     &AddConstraint(ConstrainRegSubVar(ref a, ref b)) => {
                         Some((*a, ReInfer(ReVar(*b))))
@@ -479,7 +507,11 @@ pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
                     &AddConstraint(ConstrainRegSubReg(a, b)) => {
                         Some((a, b))
                     }
-                    _ => {
+                    &AddCombination(..) |
+                    &Mark |
+                    &AddVar(..) |
+                    &OpenSnapshot |
+                    &CommitedSnapshot => {
                         None
                     }
                 };
@@ -493,8 +525,6 @@ pub fn tainted(&self, snapshot: uint, r0: Region) -> Vec<Region> {
                             consider_adding_edge(result_set, r, r2, r1);
                     }
                 }
-
-                undo_index += 1;
             }
 
             result_index += 1;
@@ -559,7 +589,7 @@ fn lub_concrete_regions(&self, a: Region, b: Region) -> Region {
 
           (ReInfer(ReVar(v_id)), _) | (_, ReInfer(ReVar(v_id))) => {
             self.tcx.sess.span_bug(
-                self.var_origins.borrow().get(v_id.to_uint()).span(),
+                self.var_origins.borrow().get(v_id.index).span(),
                 format!("lub_concrete_regions invoked with \
                          non-concrete regions: {:?}, {:?}",
                         a,
@@ -665,7 +695,7 @@ fn glb_concrete_regions(&self,
             (ReInfer(ReVar(v_id)), _) |
             (_, ReInfer(ReVar(v_id))) => {
                 self.tcx.sess.span_bug(
-                    self.var_origins.borrow().get(v_id.to_uint()).span(),
+                    self.var_origins.borrow().get(v_id.index).span(),
                     format!("glb_concrete_regions invoked with \
                              non-concrete regions: {:?}, {:?}",
                             a,
@@ -804,14 +834,14 @@ fn expansion(&self, var_data: &mut [VarData]) {
         self.iterate_until_fixed_point("Expansion", |constraint| {
             match *constraint {
               ConstrainRegSubVar(a_region, b_vid) => {
-                let b_data = &mut var_data[b_vid.to_uint()];
+                let b_data = &mut var_data[b_vid.index];
                 self.expand_node(a_region, b_vid, b_data)
               }
               ConstrainVarSubVar(a_vid, b_vid) => {
-                match var_data[a_vid.to_uint()].value {
+                match var_data[a_vid.index].value {
                   NoValue | ErrorValue => false,
                   Value(a_region) => {
-                    let b_node = &mut var_data[b_vid.to_uint()];
+                    let b_node = &mut var_data[b_vid.index];
                     self.expand_node(a_region, b_vid, b_node)
                   }
                 }
@@ -873,16 +903,16 @@ fn contraction(&self,
                 false
               }
               ConstrainVarSubVar(a_vid, b_vid) => {
-                match var_data[b_vid.to_uint()].value {
+                match var_data[b_vid.index].value {
                   NoValue | ErrorValue => false,
                   Value(b_region) => {
-                    let a_data = &mut var_data[a_vid.to_uint()];
+                    let a_data = &mut var_data[a_vid.index];
                     self.contract_node(a_vid, a_data, b_region)
                   }
                 }
               }
               ConstrainVarSubReg(a_vid, b_region) => {
-                let a_data = &mut var_data[a_vid.to_uint()];
+                let a_data = &mut var_data[a_vid.index];
                 self.contract_node(a_vid, a_data, b_region)
               }
               ConstrainRegSubReg(..) => {
@@ -1054,7 +1084,7 @@ fn extract_values_and_collect_conflicts(
                     }
                     let graph = opt_graph.get_ref();
 
-                    let node_vid = RegionVid { id: idx };
+                    let node_vid = RegionVid { index: idx };
                     match var_data[idx].classification {
                         Expanding => {
                             self.collect_error_for_expanding_node(
@@ -1091,17 +1121,17 @@ fn construct_graph(&self) -> RegionGraph {
         for (constraint, _) in constraints.iter() {
             match *constraint {
                 ConstrainVarSubVar(a_id, b_id) => {
-                    graph.add_edge(NodeIndex(a_id.to_uint()),
-                                   NodeIndex(b_id.to_uint()),
+                    graph.add_edge(NodeIndex(a_id.index),
+                                   NodeIndex(b_id.index),
                                    *constraint);
                 }
                 ConstrainRegSubVar(_, b_id) => {
                     graph.add_edge(dummy_idx,
-                                   NodeIndex(b_id.to_uint()),
+                                   NodeIndex(b_id.index),
                                    *constraint);
                 }
                 ConstrainVarSubReg(a_id, _) => {
-                    graph.add_edge(NodeIndex(a_id.to_uint()),
+                    graph.add_edge(NodeIndex(a_id.index),
                                    dummy_idx,
                                    *constraint);
                 }
@@ -1157,7 +1187,7 @@ fn free_regions_first(a: &RegionAndOrigin,
                 if !self.is_subregion_of(lower_bound.region,
                                          upper_bound.region) {
                     errors.push(SubSupConflict(
-                        self.var_origins.borrow().get(node_idx.to_uint()).clone(),
+                        self.var_origins.borrow().get(node_idx.index).clone(),
                         lower_bound.origin.clone(),
                         lower_bound.region,
                         upper_bound.origin.clone(),
@@ -1168,7 +1198,7 @@ fn free_regions_first(a: &RegionAndOrigin,
         }
 
         self.tcx.sess.span_bug(
-            self.var_origins.borrow().get(node_idx.to_uint()).span(),
+            self.var_origins.borrow().get(node_idx.index).span(),
             format!("collect_error_for_expanding_node() could not find error \
                   for var {:?}, lower_bounds={}, upper_bounds={}",
                  node_idx,
@@ -1207,7 +1237,7 @@ fn collect_error_for_contracting_node(
                   Ok(_) => {}
                   Err(_) => {
                     errors.push(SupSupConflict(
-                        self.var_origins.borrow().get(node_idx.to_uint()).clone(),
+                        self.var_origins.borrow().get(node_idx.index).clone(),
                         upper_bound_1.origin.clone(),
                         upper_bound_1.region,
                         upper_bound_2.origin.clone(),
@@ -1219,7 +1249,7 @@ fn collect_error_for_contracting_node(
         }
 
         self.tcx.sess.span_bug(
-            self.var_origins.borrow().get(node_idx.to_uint()).span(),
+            self.var_origins.borrow().get(node_idx.index).span(),
             format!("collect_error_for_contracting_node() could not find error \
                   for var {:?}, upper_bounds={}",
                  node_idx,
@@ -1256,12 +1286,12 @@ struct WalkState {
 
         while !state.stack.is_empty() {
             let node_idx = state.stack.pop().unwrap();
-            let classification = var_data[node_idx.to_uint()].classification;
+            let classification = var_data[node_idx.index].classification;
 
             // check whether we've visited this node on some previous walk
-            if dup_vec[node_idx.to_uint()] == uint::MAX {
-                dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint();
-            } else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() {
+            if dup_vec[node_idx.index] == uint::MAX {
+                dup_vec[node_idx.index] = orig_node_idx.index;
+            } else if dup_vec[node_idx.index] != orig_node_idx.index {
                 state.dup_found = true;
             }
 
@@ -1289,7 +1319,7 @@ fn process_edges(this: &RegionVarBindings,
                          dir: Direction) {
             debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
 
-            let source_node_index = NodeIndex(source_vid.to_uint());
+            let source_node_index = NodeIndex(source_vid.index);
             graph.each_adjacent_edge(source_node_index, dir, |_, edge| {
                 match edge.data {
                     ConstrainVarSubVar(from_vid, to_vid) => {
index 9df610dc7bc2a57d30fee71223f442436bd1dcdb..ae7578957f890f14646dc8a721d48b58f49d5b19 100644 (file)
 use middle::ty_fold;
 use middle::typeck::infer::{Bounds, cyclic_ty, fixup_err, fres, InferCtxt};
 use middle::typeck::infer::unresolved_ty;
-use middle::typeck::infer::to_str::InferStr;
-use middle::typeck::infer::unify::{Root, UnifyInferCtxtMethods};
-use util::common::{indent, indenter};
-use util::ppaux::ty_to_str;
+use middle::typeck::infer::unify::Root;
+use util::common::{indent};
+use util::ppaux::{ty_to_str, Repr};
 
 use syntax::ast;
 
@@ -150,8 +149,7 @@ pub fn resolve_region_chk(&mut self, orig: ty::Region)
     }
 
     pub fn resolve_type(&mut self, typ: ty::t) -> ty::t {
-        debug!("resolve_type({})", typ.inf_str(self.infcx));
-        let _i = indenter();
+        debug!("resolve_type({})", typ.repr(self.infcx.tcx));
 
         if !ty::type_needs_infer(typ) {
             return typ;
@@ -188,7 +186,7 @@ pub fn resolve_type(&mut self, typ: ty::t) -> ty::t {
     }
 
     pub fn resolve_region(&mut self, orig: ty::Region) -> ty::Region {
-        debug!("Resolve_region({})", orig.inf_str(self.infcx));
+        debug!("Resolve_region({})", orig.repr(self.infcx.tcx));
         match orig {
           ty::ReInfer(ty::ReVar(rid)) => self.resolve_region_var(rid),
           _ => orig
@@ -216,14 +214,15 @@ 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 nde = self.infcx.get(vid);
-            let bounds = nde.possible_types;
-
-            let t1 = match bounds {
-              Bounds { ub:_, lb:Some(t) } if !type_is_bot(t)
-                => self.resolve_type(t),
-              Bounds { ub:Some(t), lb:_ } => self.resolve_type(t),
-              Bounds { ub:_, lb:Some(t) } => self.resolve_type(t),
+            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));
@@ -241,15 +240,18 @@ pub fn resolve_int_var(&mut self, vid: IntVid) -> ty::t {
             return ty::mk_int_var(self.infcx.tcx, vid);
         }
 
-        let node = self.infcx.get(vid);
-        match node.possible_types {
+        let tcx = self.infcx.tcx;
+        let table = &self.infcx.int_unification_table;
+        let node = table.borrow_mut().get(tcx, vid);
+        match node.value {
           Some(IntType(t)) => ty::mk_mach_int(t),
           Some(UintType(t)) => ty::mk_mach_uint(t),
           None => {
             if self.should(force_ivar) {
                 // As a last resort, default to int.
                 let ty = ty::mk_int();
-                self.infcx.set(vid, Root(Some(IntType(ast::TyI)), node.rank));
+                table.borrow_mut().set(
+                    tcx, node.key, Root(Some(IntType(ast::TyI)), node.rank));
                 ty
             } else {
                 ty::mk_int_var(self.infcx.tcx, vid)
@@ -263,14 +265,17 @@ pub fn resolve_float_var(&mut self, vid: FloatVid) -> ty::t {
             return ty::mk_float_var(self.infcx.tcx, vid);
         }
 
-        let node = self.infcx.get(vid);
-        match node.possible_types {
+        let tcx = self.infcx.tcx;
+        let table = &self.infcx.float_unification_table;
+        let node = table.borrow_mut().get(tcx, vid);
+        match node.value {
           Some(t) => ty::mk_mach_float(t),
           None => {
             if self.should(force_fvar) {
                 // As a last resort, default to f64.
                 let ty = ty::mk_f64();
-                self.infcx.set(vid, Root(Some(ast::TyF64), node.rank));
+                table.borrow_mut().set(
+                    tcx, node.key, Root(Some(ast::TyF64), node.rank));
                 ty
             } else {
                 ty::mk_float_var(self.infcx.tcx, vid)
index a543cf18d565a19114115dca69c698ff8d1d467e..856237c4bcaa4c3634468e23839267db6a4d74f3 100644 (file)
 use middle::typeck::infer::lattice::CombineFieldsLatticeMethods;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::then;
-use middle::typeck::infer::to_str::InferStr;
 use middle::typeck::infer::{TypeTrace, Subtype};
 use util::common::{indenter};
-use util::ppaux::bound_region_to_str;
+use util::ppaux::{bound_region_to_str, Repr};
 
 use syntax::ast::{Onceness, FnStyle, MutImmutable, MutMutable};
 
@@ -63,14 +62,16 @@ fn contraregions(&self, a: ty::Region, b: ty::Region)
     fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> {
         debug!("{}.regions({}, {})",
                self.tag(),
-               a.inf_str(self.get_ref().infcx),
-               b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx),
+               b.repr(self.get_ref().infcx.tcx));
         self.get_ref().infcx.region_vars.make_subregion(Subtype(self.trace()), a, b);
         Ok(a)
     }
 
     fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
-        debug!("mts({} <: {})", a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+        debug!("mts({} <: {})",
+               a.repr(self.get_ref().infcx.tcx),
+               b.repr(self.get_ref().infcx.tcx));
 
         if a.mutbl != b.mutbl {
             return Err(ty::terr_mutability);
@@ -116,7 +117,7 @@ fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> {
 
     fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
         debug!("{}.tys({}, {})", self.tag(),
-               a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
         if a == b { return Ok(a); }
         let _indenter = indenter();
         match (&ty::get(a).sty, &ty::get(b).sty) {
@@ -149,7 +150,7 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
 
     fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         debug!("fn_sigs(a={}, b={})",
-               a.inf_str(self.get_ref().infcx), b.inf_str(self.get_ref().infcx));
+               a.repr(self.get_ref().infcx.tcx), b.repr(self.get_ref().infcx.tcx));
         let _indenter = indenter();
 
         // Rather than checking the subtype relationship between `a` and `b`
@@ -159,11 +160,9 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         // Note: this is a subtle algorithm.  For a full explanation,
         // please see the large comment in `region_inference.rs`.
 
-        // Take a snapshot.  We'll never roll this back, but in later
-        // phases we do want to be able to examine "all bindings that
-        // were created as part of this type comparison", and making a
-        // snapshot is a convenient way to do that.
-        let snapshot = self.get_ref().infcx.region_vars.start_snapshot();
+        // Make a mark so we can examine "all bindings that were
+        // created as part of this type comparison".
+        let mark = self.get_ref().infcx.region_vars.mark();
 
         // First, we instantiate each bound region in the subtype with a fresh
         // region variable.
@@ -183,8 +182,8 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
             })
         };
 
-        debug!("a_sig={}", a_sig.inf_str(self.get_ref().infcx));
-        debug!("b_sig={}", b_sig.inf_str(self.get_ref().infcx));
+        debug!("a_sig={}", a_sig.repr(self.get_ref().infcx.tcx));
+        debug!("b_sig={}", b_sig.repr(self.get_ref().infcx.tcx));
 
         // Compare types now that bound regions have been replaced.
         let sig = if_ok!(super_fn_sigs(self, &a_sig, &b_sig));
@@ -192,9 +191,9 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         // Presuming type comparison succeeds, we need to check
         // that the skolemized regions do not "leak".
         let new_vars =
-            self.get_ref().infcx.region_vars.vars_created_since_snapshot(snapshot);
+            self.get_ref().infcx.region_vars.vars_created_since_mark(mark);
         for (&skol_br, &skol) in skol_map.iter() {
-            let tainted = self.get_ref().infcx.region_vars.tainted(snapshot, skol);
+            let tainted = self.get_ref().infcx.region_vars.tainted(mark, skol);
             for tainted_region in tainted.iter() {
                 // Each skolemized should only be relatable to itself
                 // or new variables:
@@ -209,9 +208,11 @@ fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
 
                 // A is not as polymorphic as B:
                 if self.a_is_expected() {
+                    debug!("Not as polymorphic!");
                     return Err(ty::terr_regions_insufficiently_polymorphic(
                             skol_br, *tainted_region));
                 } else {
+                    debug!("Overly polymorphic!");
                     return Err(ty::terr_regions_overly_polymorphic(
                             skol_br, *tainted_region));
                 }
index e4636e1c7c6d721d32ae97faf60527cecf790bc5..f08cbb06c9e3166c21b83d5d4c1bbc52140f408e 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-/**
+/*!
 
 # Standalone Tests for the Inference Module
 
-Note: This module is only compiled when doing unit testing.
-
 */
 
+// This is only used by tests, hence allow dead code.
+#![allow(dead_code)]
+
+use driver::config;
 use driver::diagnostic;
-use driver::driver::{optgroups, build_session_options, build_session};
-use driver::driver::{str_input, build_configuration};
-use middle::lang_items::{LanguageItems, language_items};
-use middle::ty::{FnTyBase, FnMeta, FnSig};
-use util::ppaux::ty_to_str;
-
-use extra::oldmap::HashMap;
-use getopts::{optopt, optmulti, optflag, optflagopt, getopts};
-use getopts::opt_present;
-use syntax::codemap::DUMMY_SP;
-use syntax::parse::parse_crate_from_source_str;
-use syntax::{ast, attr, parse};
-
-struct Env {
-    krate: @ast::Crate,
-    tcx: ty::ctxt,
-    infcx: infer::infer_ctxt,
-    err_messages: @DVec<String>
+use driver::diagnostic::Emitter;
+use driver::driver;
+use driver::session;
+use middle::freevars;
+use middle::lang_items;
+use middle::region;
+use middle::resolve;
+use middle::resolve_lifetime;
+use middle::stability;
+use middle::ty;
+use middle::typeck::infer::combine::Combine;
+use middle::typeck::infer;
+use middle::typeck::infer::lub::Lub;
+use middle::typeck::infer::glb::Glb;
+use syntax::codemap;
+use syntax::codemap::{Span, CodeMap, DUMMY_SP};
+use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note};
+use syntax::ast;
+use syntax::crateid::CrateId;
+use util::ppaux::{ty_to_str, UserString};
+
+struct Env<'a> {
+    krate: ast::Crate,
+    tcx: &'a ty::ctxt,
+    infcx: &'a infer::InferCtxt<'a>,
+}
+
+struct RH<'a> {
+    id: ast::NodeId,
+    sub: &'a [RH<'a>]
 }
 
-struct RH {
-    id: ast::node_id,
-    sub: &[RH]
+static EMPTY_SOURCE_STR: &'static str = "#![no_std]";
+
+struct ExpectErrorEmitter {
+    messages: Vec<String>
 }
 
-static EMPTY_SOURCE_STR: &str = "/* Hello, world! */";
-
-fn setup_env(test_name: &str, source_string: &str) -> Env {
-    let messages = @DVec();
-    let matches = getopts(vec!("-Z".to_string(), "verbose".to_string()), optgroups()).get();
-    let diag = diagnostic::collect(messages);
-    let sessopts = build_session_options("rustc".to_string(), &matches, diag);
-    let sess = build_session(sessopts, None, diag);
-    let cfg = build_configuration(sess, "whatever".to_string(), str_input("".to_string()));
-    let dm = HashMap();
-    let amap = HashMap();
-    let freevars = HashMap();
-    let region_paramd_items = HashMap();
-    let region_map = HashMap();
-    let lang_items = LanguageItems::new();
-
-    let parse_sess = parse::new_parse_sess(None);
-    let krate = parse_crate_from_source_str(
-        test_name.to_str(), @source_string.to_str(),
-        cfg, parse_sess);
-
-    let tcx = ty::mk_ctxt(sess, dm, amap, freevars, region_map,
-                          region_paramd_items, lang_items);
-
-    let infcx = infer::new_infer_ctxt(tcx);
-
-    return Env {krate: krate,
-                tcx: tcx,
-                infcx: infcx,
-                err_messages: messages};
+fn remove_message(e: &mut ExpectErrorEmitter, msg: &str, lvl: Level) {
+    match lvl {
+        Bug | Fatal | Error => { }
+        Warning | Note => { return; }
+    }
+
+    debug!("Error: {}", msg);
+    match e.messages.iter().position(|m| msg.contains(m.as_slice())) {
+        Some(i) => {
+            e.messages.remove(i);
+        }
+        None => {
+            fail!("Unexpected error: {} Expected: {}",
+                  msg, e.messages);
+        }
+    }
 }
 
-impl Env {
+impl Emitter for ExpectErrorEmitter {
+    fn emit(&mut self,
+            _cmsp: Option<(&codemap::CodeMap, Span)>,
+            msg: &str,
+            lvl: Level)
+    {
+        remove_message(self, msg, lvl);
+    }
+
+    fn custom_emit(&mut self,
+                   _cm: &codemap::CodeMap,
+                   _sp: RenderSpan,
+                   msg: &str,
+                   lvl: Level)
+    {
+        remove_message(self, msg, lvl);
+    }
+}
+
+fn errors(msgs: &[&str]) -> (Box<Emitter+Send>, uint) {
+    let v = Vec::from_fn(msgs.len(), |i| msgs[i].to_owned());
+    (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
+}
+
+fn test_env(_test_name: &str,
+            source_string: &str,
+            (emitter, expected_err_count): (Box<Emitter+Send>, uint),
+            body: |Env|) {
+    let options =
+        config::basic_options();
+    let codemap =
+        CodeMap::new();
+    let diagnostic_handler =
+        diagnostic::mk_handler(emitter);
+    let span_diagnostic_handler =
+        diagnostic::mk_span_handler(diagnostic_handler, codemap);
+
+    let sess = session::build_session_(options, None, span_diagnostic_handler);
+    let krate_config = Vec::new();
+    let input = driver::StrInput(source_string.to_owned());
+    let krate = driver::phase_1_parse_input(&sess, krate_config, &input);
+    let krate_id = CrateId { path: "test".to_owned(),
+                             name: "test".to_owned(),
+                             version: None };
+    let (krate, ast_map) =
+        driver::phase_2_configure_and_expand(&sess, krate, &krate_id);
+
+    // run just enough stuff to build a tcx:
+    let lang_items = lang_items::collect_language_items(&krate, &sess);
+    let resolve::CrateMap { def_map: def_map, .. } =
+        resolve::resolve_crate(&sess, &lang_items, &krate);
+    let freevars_map = freevars::annotate_freevars(&def_map, &krate);
+    let named_region_map = resolve_lifetime::krate(&sess, &krate);
+    let region_map = region::resolve_crate(&sess, &krate);
+    let stability_index = stability::Index::build(&krate);
+    let tcx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
+                          freevars_map, region_map, lang_items, stability_index);
+    let infcx = infer::new_infer_ctxt(&tcx);
+    let env = Env {krate: krate,
+                   tcx: &tcx,
+                   infcx: &infcx};
+    body(env);
+    infcx.resolve_regions_and_report_errors();
+    assert_eq!(tcx.sess.err_count(), expected_err_count);
+}
+
+impl<'a> Env<'a> {
     pub fn create_region_hierarchy(&self, rh: &RH) {
         for child_rh in rh.sub.iter() {
             self.create_region_hierarchy(child_rh);
-            self.tcx.region_map.insert(child_rh.id, rh.id);
+            self.tcx.region_maps.record_encl_scope(child_rh.id, rh.id);
         }
     }
 
@@ -93,37 +160,39 @@ pub fn create_simple_region_hierarchy(&self) {
                             sub: &[]}]});
     }
 
-    pub fn lookup_item(&self, names: &[String]) -> ast::node_id {
-        return match search_mod(self, &self.krate.node.module, 0, names) {
+    pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
+        return match search_mod(self, &self.krate.module, 0, names) {
             Some(id) => id,
             None => {
-                fail!("no item found: `%s`", names.connect("::"));
+                fail!("no item found: `{}`", names.connect("::"));
             }
         };
 
-        fn search_mod(self: &Env,
+        fn search_mod(this: &Env,
                       m: &ast::Mod,
                       idx: uint,
-                      names: &[String]) -> Option<ast::node_id> {
+                      names: &[String])
+                      -> Option<ast::NodeId> {
             assert!(idx < names.len());
             for item in m.items.iter() {
-                if self.tcx.sess.str_of(item.ident) == names[idx] {
-                    return search(self, *item, idx+1, names);
+                if item.ident.user_string(this.tcx) == names[idx] {
+                    return search(this, *item, idx+1, names);
                 }
             }
             return None;
         }
 
-        fn search(self: &Env,
-                  it: @ast::Item,
+        fn search(this: &Env,
+                  it: &ast::Item,
                   idx: uint,
-                  names: &[String]) -> Option<ast::node_id> {
+                  names: &[String])
+                  -> Option<ast::NodeId> {
             if idx == names.len() {
                 return Some(it.id);
             }
 
             return match it.node {
-                ast::ItemConst(..) | ast::ItemFn(..) |
+                ast::ItemStatic(..) | ast::ItemFn(..) |
                 ast::ItemForeignMod(..) | ast::ItemTy(..) => {
                     None
                 }
@@ -135,12 +204,20 @@ fn search(self: &Env,
                 }
 
                 ast::ItemMod(ref m) => {
-                    search_mod(self, m, idx, names)
+                    search_mod(this, m, idx, names)
                 }
             };
         }
     }
 
+    pub fn make_subtype(&self, a: ty::t, b: ty::t) -> bool {
+        match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
+            Ok(_) => true,
+            Err(ref e) => fail!("Encountered error: {}",
+                                ty::type_err_to_str(self.tcx, e))
+        }
+    }
+
     pub fn is_subtype(&self, a: ty::t, b: ty::t) -> bool {
         match infer::can_mk_subty(self.infcx, a, b) {
             Ok(_) => true,
@@ -150,7 +227,7 @@ pub fn is_subtype(&self, a: ty::t, b: ty::t) -> bool {
 
     pub fn assert_subtype(&self, a: ty::t, b: ty::t) {
         if !self.is_subtype(a, b) {
-            fail!("%s is not a subtype of %s, but it should be",
+            fail!("{} is not a subtype of {}, but it should be",
                   self.ty_to_str(a),
                   self.ty_to_str(b));
         }
@@ -158,17 +235,12 @@ pub fn assert_subtype(&self, a: ty::t, b: ty::t) {
 
     pub fn assert_not_subtype(&self, a: ty::t, b: ty::t) {
         if self.is_subtype(a, b) {
-            fail!("%s is a subtype of %s, but it shouldn't be",
+            fail!("{} is a subtype of {}, but it shouldn't be",
                   self.ty_to_str(a),
                   self.ty_to_str(b));
         }
     }
 
-    pub fn assert_strict_subtype(&self, a: ty::t, b: ty::t) {
-        self.assert_subtype(a, b);
-        self.assert_not_subtype(b, a);
-    }
-
     pub fn assert_eq(&self, a: ty::t, b: ty::t) {
         self.assert_subtype(a, b);
         self.assert_subtype(b, a);
@@ -178,36 +250,29 @@ pub fn ty_to_str(&self, a: ty::t) -> String {
         ty_to_str(self.tcx, a)
     }
 
-    pub fn t_fn(&self, input_tys: &[ty::t], output_ty: ty::t) -> ty::t {
-        let inputs = input_tys.map(|t| {mode: ast::expl(ast::by_copy),
-                                        ty: *t});
-        ty::mk_fn(self.tcx, FnTyBase {
-            meta: FnMeta {fn_style: ast::NormalFn,
-                          proto: ast::ProtoBare,
-                          onceness: ast::Many,
-                          region: ty::ReStatic,
-                          bounds: @Vec::new()},
-            sig: FnSig {
-                inputs: inputs,
-                output: output_ty,
-                variadic: false
-            }
-        })
+    pub fn t_fn(&self,
+                binder_id: ast::NodeId,
+                input_tys: &[ty::t],
+                output_ty: ty::t)
+                -> ty::t
+    {
+        ty::mk_ctor_fn(self.tcx, binder_id, input_tys, output_ty)
     }
 
     pub fn t_int(&self) -> ty::t {
-        ty::mk_int(self.tcx)
+        ty::mk_int()
     }
 
-    pub fn t_rptr_bound(&self, id: uint) -> ty::t {
-        ty::mk_imm_rptr(self.tcx, ty::re_bound(ty::BrAnon(id)), self.t_int())
+    pub fn t_rptr_late_bound(&self, binder_id: ast::NodeId, id: uint) -> ty::t {
+        ty::mk_imm_rptr(self.tcx, ty::ReLateBound(binder_id, ty::BrAnon(id)),
+                        self.t_int())
     }
 
-    pub fn t_rptr_scope(&self, id: ast::node_id) -> ty::t {
+    pub fn t_rptr_scope(&self, id: ast::NodeId) -> ty::t {
         ty::mk_imm_rptr(self.tcx, ty::ReScope(id), self.t_int())
     }
 
-    pub fn t_rptr_free(&self, nid: ast::node_id, id: uint) -> ty::t {
+    pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> ty::t {
         ty::mk_imm_rptr(self.tcx,
                         ty::ReFree(ty::FreeRegion {scope_id: nid,
                                                     bound_region: ty::BrAnon(id)}),
@@ -218,51 +283,60 @@ pub fn t_rptr_static(&self) -> ty::t {
         ty::mk_imm_rptr(self.tcx, ty::ReStatic, self.t_int())
     }
 
-    pub fn lub() -> Lub { Lub(self.infcx.combine_fields(true, DUMMY_SP)) }
+    pub fn dummy_type_trace(&self) -> infer::TypeTrace {
+        infer::TypeTrace {
+            origin: infer::Misc(DUMMY_SP),
+            values: infer::Types(ty::expected_found {
+                expected: ty::mk_err(),
+                found: ty::mk_err(),
+            })
+        }
+    }
+
+    pub fn lub(&self) -> Lub<'a> {
+        let trace = self.dummy_type_trace();
+        Lub(self.infcx.combine_fields(true, trace))
+    }
 
-    pub fn glb() -> Glb { Glb(self.infcx.combine_fields(true, DUMMY_SP)) }
+    pub fn glb(&self) -> Glb<'a> {
+        let trace = self.dummy_type_trace();
+        Glb(self.infcx.combine_fields(true, trace))
+    }
 
-    pub fn resolve_regions(exp_count: uint) {
-        debug!("resolve_regions(%u)", exp_count);
+    pub fn resolve_regions(&self) {
+        self.infcx.resolve_regions_and_report_errors();
+    }
 
-        self.infcx.resolve_regions();
-        if self.err_messages.len() != exp_count {
-            for msg in self.err_messages.iter() {
-                debug!("Error encountered: %s", *msg);
-            }
-            format!("resolving regions encountered %u errors but expected %u!",
-                 self.err_messages.len(),
-                 exp_count);
+    pub fn make_lub_ty(&self, t1: ty::t, t2: ty::t) -> ty::t {
+        match self.lub().tys(t1, t2) {
+            Ok(t) => t,
+            Err(ref e) => fail!("unexpected error computing LUB: {:?}",
+                                ty::type_err_to_str(self.tcx, e))
         }
     }
 
     /// Checks that `LUB(t1,t2) == t_lub`
     pub fn check_lub(&self, t1: ty::t, t2: ty::t, t_lub: ty::t) {
         match self.lub().tys(t1, t2) {
-            Err(e) => {
-                fail!("unexpected error computing LUB: %?", e)
-            }
             Ok(t) => {
                 self.assert_eq(t, t_lub);
-
-                // sanity check for good measure:
-                self.assert_subtype(t1, t);
-                self.assert_subtype(t2, t);
-
-                self.resolve_regions(0);
+            }
+            Err(ref e) => {
+                fail!("unexpected error in LUB: {}",
+                      ty::type_err_to_str(self.tcx, e))
             }
         }
     }
 
     /// Checks that `GLB(t1,t2) == t_glb`
     pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) {
-        debug!("check_glb(t1=%s, t2=%s, t_glb=%s)",
+        debug!("check_glb(t1={}, t2={}, t_glb={})",
                self.ty_to_str(t1),
                self.ty_to_str(t2),
                self.ty_to_str(t_glb));
         match self.glb().tys(t1, t2) {
             Err(e) => {
-                fail!("unexpected error computing LUB: %?", e)
+                fail!("unexpected error computing LUB: {:?}", e)
             }
             Ok(t) => {
                 self.assert_eq(t, t_glb);
@@ -270,8 +344,6 @@ pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) {
                 // sanity check for good measure:
                 self.assert_subtype(t, t1);
                 self.assert_subtype(t, t2);
-
-                self.resolve_regions(0);
             }
         }
     }
@@ -281,7 +353,7 @@ pub fn check_no_lub(&self, t1: ty::t, t2: ty::t) {
         match self.lub().tys(t1, t2) {
             Err(_) => {}
             Ok(t) => {
-                fail!("unexpected success computing LUB: %?", self.ty_to_str(t))
+                fail!("unexpected success computing LUB: {}", self.ty_to_str(t))
             }
         }
     }
@@ -291,120 +363,151 @@ pub fn check_no_glb(&self, t1: ty::t, t2: ty::t) {
         match self.glb().tys(t1, t2) {
             Err(_) => {}
             Ok(t) => {
-                fail!("unexpected success computing GLB: %?", self.ty_to_str(t))
+                fail!("unexpected success computing GLB: {}", self.ty_to_str(t))
             }
         }
     }
 }
 
 #[test]
-fn contravariant_region_ptr() {
-    let env = setup_env("contravariant_region_ptr", EMPTY_SOURCE_STR);
-    env.create_simple_region_hierarchy();
-    let t_rptr1 = env.t_rptr_scope(1);
-    let t_rptr10 = env.t_rptr_scope(10);
-    env.assert_eq(t_rptr1, t_rptr1);
-    env.assert_eq(t_rptr10, t_rptr10);
-    env.assert_strict_subtype(t_rptr1, t_rptr10);
+fn contravariant_region_ptr_ok() {
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        env.create_simple_region_hierarchy();
+        let t_rptr1 = env.t_rptr_scope(1);
+        let t_rptr10 = env.t_rptr_scope(10);
+        env.assert_eq(t_rptr1, t_rptr1);
+        env.assert_eq(t_rptr10, t_rptr10);
+        env.make_subtype(t_rptr1, t_rptr10);
+    })
+}
+
+#[test]
+fn contravariant_region_ptr_err() {
+    test_env("contravariant_region_ptr",
+             EMPTY_SOURCE_STR,
+             errors(["lifetime mismatch"]),
+             |env| {
+                 env.create_simple_region_hierarchy();
+                 let t_rptr1 = env.t_rptr_scope(1);
+                 let t_rptr10 = env.t_rptr_scope(10);
+                 env.assert_eq(t_rptr1, t_rptr1);
+                 env.assert_eq(t_rptr10, t_rptr10);
+
+                 // will cause an error when regions are resolved
+                 env.make_subtype(t_rptr10, t_rptr1);
+             })
 }
 
 #[test]
 fn lub_bound_bound() {
-    let env = setup_env("lub_bound_bound", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_bound2 = env.t_rptr_bound(2);
-    env.check_lub(env.t_fn([t_rptr_bound1], env.t_int()),
-                  env.t_fn([t_rptr_bound2], env.t_int()),
-                  env.t_fn([t_rptr_bound1], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
+        env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
+                      env.t_fn(22, [t_rptr_bound2], env.t_int()),
+                      env.t_fn(22, [t_rptr_bound1], env.t_int()));
+    })
 }
 
 #[test]
 fn lub_bound_free() {
-    let env = setup_env("lub_bound_free", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_free1 = env.t_rptr_free(0, 1);
-    env.check_lub(env.t_fn([t_rptr_bound1], env.t_int()),
-                  env.t_fn([t_rptr_free1], env.t_int()),
-                  env.t_fn([t_rptr_free1], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
+                      env.t_fn(22, [t_rptr_free1], env.t_int()),
+                      env.t_fn(22, [t_rptr_free1], env.t_int()));
+    })
 }
 
 #[test]
 fn lub_bound_static() {
-    let env = setup_env("lub_bound_static", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_static = env.t_rptr_static();
-    env.check_lub(env.t_fn([t_rptr_bound1], env.t_int()),
-                  env.t_fn([t_rptr_static], env.t_int()),
-                  env.t_fn([t_rptr_static], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_static = env.t_rptr_static();
+        env.check_lub(env.t_fn(22, [t_rptr_bound1], env.t_int()),
+                      env.t_fn(22, [t_rptr_static], env.t_int()),
+                      env.t_fn(22, [t_rptr_static], env.t_int()));
+    })
 }
 
 #[test]
 fn lub_bound_bound_inverse_order() {
-    let env = setup_env("lub_bound_bound_inverse_order", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_bound2 = env.t_rptr_bound(2);
-    env.check_lub(env.t_fn([t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
-                  env.t_fn([t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
-                  env.t_fn([t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
+        env.check_lub(env.t_fn(22, [t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
+                      env.t_fn(22, [t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
+                      env.t_fn(22, [t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
+    })
 }
 
 #[test]
 fn lub_free_free() {
-    let env = setup_env("lub_free_free", EMPTY_SOURCE_STR);
-    let t_rptr_free1 = env.t_rptr_free(0, 1);
-    let t_rptr_free2 = env.t_rptr_free(0, 2);
-    let t_rptr_static = env.t_rptr_static();
-    env.check_lub(env.t_fn([t_rptr_free1], env.t_int()),
-                  env.t_fn([t_rptr_free2], env.t_int()),
-                  env.t_fn([t_rptr_static], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free2 = env.t_rptr_free(0, 2);
+        let t_rptr_static = env.t_rptr_static();
+        env.check_lub(env.t_fn(22, [t_rptr_free1], env.t_int()),
+                      env.t_fn(22, [t_rptr_free2], env.t_int()),
+                      env.t_fn(22, [t_rptr_static], env.t_int()));
+    })
 }
 
 #[test]
 fn lub_returning_scope() {
-    let env = setup_env("lub_returning_scope", EMPTY_SOURCE_STR);
-    let t_rptr_scope10 = env.t_rptr_scope(10);
-    let t_rptr_scope11 = env.t_rptr_scope(11);
-    env.check_no_lub(env.t_fn([], t_rptr_scope10),
-                     env.t_fn([], t_rptr_scope11));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR,
+             errors(["cannot infer an appropriate lifetime"]), |env| {
+                 let t_rptr_scope10 = env.t_rptr_scope(10);
+                 let t_rptr_scope11 = env.t_rptr_scope(11);
+
+                 // this should generate an error when regions are resolved
+                 env.make_lub_ty(env.t_fn(22, [], t_rptr_scope10),
+                                 env.t_fn(22, [], t_rptr_scope11));
+             })
 }
 
 #[test]
 fn glb_free_free_with_common_scope() {
-    let env = setup_env("glb_free_free", EMPTY_SOURCE_STR);
-    let t_rptr_free1 = env.t_rptr_free(0, 1);
-    let t_rptr_free2 = env.t_rptr_free(0, 2);
-    let t_rptr_scope = env.t_rptr_scope(0);
-    env.check_glb(env.t_fn([t_rptr_free1], env.t_int()),
-                  env.t_fn([t_rptr_free2], env.t_int()),
-                  env.t_fn([t_rptr_scope], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        let t_rptr_free2 = env.t_rptr_free(0, 2);
+        let t_rptr_scope = env.t_rptr_scope(0);
+        env.check_glb(env.t_fn(22, [t_rptr_free1], env.t_int()),
+                      env.t_fn(22, [t_rptr_free2], env.t_int()),
+                      env.t_fn(22, [t_rptr_scope], env.t_int()));
+    })
 }
 
 #[test]
 fn glb_bound_bound() {
-    let env = setup_env("glb_bound_bound", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_bound2 = env.t_rptr_bound(2);
-    env.check_glb(env.t_fn([t_rptr_bound1], env.t_int()),
-                  env.t_fn([t_rptr_bound2], env.t_int()),
-                  env.t_fn([t_rptr_bound1], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
+        env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
+                      env.t_fn(22, [t_rptr_bound2], env.t_int()),
+                      env.t_fn(22, [t_rptr_bound1], env.t_int()));
+    })
 }
 
 #[test]
 fn glb_bound_free() {
-    let env = setup_env("glb_bound_free", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_free1 = env.t_rptr_free(0, 1);
-    env.check_glb(env.t_fn([t_rptr_bound1], env.t_int()),
-                  env.t_fn([t_rptr_free1], env.t_int()),
-                  env.t_fn([t_rptr_bound1], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
+                      env.t_fn(22, [t_rptr_free1], env.t_int()),
+                      env.t_fn(22, [t_rptr_bound1], env.t_int()));
+    })
 }
 
 #[test]
 fn glb_bound_static() {
-    let env = setup_env("glb_bound_static", EMPTY_SOURCE_STR);
-    let t_rptr_bound1 = env.t_rptr_bound(1);
-    let t_rptr_static = env.t_rptr_static();
-    env.check_glb(env.t_fn([t_rptr_bound1], env.t_int()),
-                  env.t_fn([t_rptr_static], env.t_int()),
-                  env.t_fn([t_rptr_bound1], env.t_int()));
+    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors([]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+        let t_rptr_static = env.t_rptr_static();
+        env.check_glb(env.t_fn(22, [t_rptr_bound1], env.t_int()),
+                      env.t_fn(22, [t_rptr_static], env.t_int()),
+                      env.t_fn(22, [t_rptr_bound1], env.t_int()));
+    })
 }
diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs
deleted file mode 100644 (file)
index 097c5dc..0000000
+++ /dev/null
@@ -1,96 +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.
-
-
-use middle::ty::{FnSig, Vid};
-use middle::ty::IntVarValue;
-use middle::ty;
-use middle::typeck::infer::{Bound, Bounds};
-use middle::typeck::infer::InferCtxt;
-use middle::typeck::infer::unify::{Redirect, Root, VarValue};
-use util::ppaux::{mt_to_str, ty_to_str, trait_ref_to_str};
-
-use syntax::ast;
-
-pub trait InferStr {
-    fn inf_str(&self, cx: &InferCtxt) -> String;
-}
-
-impl InferStr for ty::t {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        ty_to_str(cx.tcx, *self)
-    }
-}
-
-impl InferStr for FnSig {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        format!("({}) -> {}",
-                self.inputs.iter()
-                    .map(|a| a.inf_str(cx))
-                    .collect::<Vec<String>>().connect(", "),
-                self.output.inf_str(cx))
-    }
-}
-
-impl InferStr for ty::mt {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        mt_to_str(cx.tcx, self)
-    }
-}
-
-impl InferStr for ty::Region {
-    fn inf_str(&self, _cx: &InferCtxt) -> String {
-        format!("{:?}", *self)
-    }
-}
-
-impl<V:InferStr> InferStr for Bound<V> {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        match *self {
-            Some(ref v) => v.inf_str(cx),
-            None => "none".to_string()
-        }
-    }
-}
-
-impl<T:InferStr> InferStr for Bounds<T> {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        format!("{{{} <: {}}}", self.lb.inf_str(cx), self.ub.inf_str(cx))
-    }
-}
-
-impl<V:Vid + ToStr,T:InferStr> InferStr for VarValue<V, T> {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        match *self {
-          Redirect(ref vid) => format!("Redirect({})", vid.to_str()),
-          Root(ref pt, rk) => {
-              format!("Root({}, {})", pt.inf_str(cx), rk)
-          }
-        }
-    }
-}
-
-impl InferStr for IntVarValue {
-    fn inf_str(&self, _cx: &InferCtxt) -> String {
-        self.to_str()
-    }
-}
-
-impl InferStr for ast::FloatTy {
-    fn inf_str(&self, _cx: &InferCtxt) -> String {
-        self.to_str()
-    }
-}
-
-impl InferStr for ty::TraitRef {
-    fn inf_str(&self, cx: &InferCtxt) -> String {
-        trait_ref_to_str(cx.tcx, self)
-    }
-}
index 78c841afa609bbf318e8e86904fc6e48cb71d664..f106ce18a4adb579bbed9edf275acd10b430d746 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::kinds::marker;
 
-use std::collections::SmallIntMap;
-
-use middle::ty::{Vid, expected_found, IntVarValue};
+use middle::ty::{expected_found, IntVarValue};
 use middle::ty;
 use middle::typeck::infer::{Bounds, uok, ures};
 use middle::typeck::infer::InferCtxt;
-use middle::typeck::infer::to_str::InferStr;
 use std::cell::RefCell;
+use std::fmt::Show;
+use std::mem;
 use syntax::ast;
+use util::ppaux::Repr;
+
+/**
+ * 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.
+ *
+ * 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.
+ *
+ * Implementations of this trait are at the end of this file.
+ */
+pub trait UnifyKey<V> : Clone + Show + PartialEq + Repr {
+    fn index(&self) -> uint;
+
+    fn from_index(u: uint) -> Self;
+
+    /**
+     * Given an inference context, returns the unification table
+     * appropriate to this key type.
+     */
+    fn unification_table<'v>(infcx: &'v InferCtxt)
+                             -> &'v RefCell<UnificationTable<Self,V>>;
+
+    fn tag(k: Option<Self>) -> &'static str;
+}
 
-#[deriving(Clone)]
-pub enum VarValue<V, T> {
-    Redirect(V),
-    Root(T, uint),
+/**
+ * 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>`.
+ *
+ * Implementations of this trait are at the end of this file.
+ */
+pub trait UnifyValue : Clone + Repr + PartialEq {
 }
 
-pub struct ValsAndBindings<V, T> {
-    pub vals: SmallIntMap<VarValue<V, T>>,
-    pub bindings: Vec<(V, VarValue<V, T>)> ,
+/**
+ * Value of a unification key. We implement Tarjan's union-find
+ * algorithm: when two keys are unified, one of them is converted
+ * into a "redirect" pointing at the other. These redirects form a
+ * DAG: the roots of the DAG (nodes that are not redirected) are each
+ * associated with a value of type `V` and a rank. The rank is used
+ * to keep the DAG relatively balanced, which helps keep the running
+ * time of the algorithm under control. For more information, see
+ * <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>.
+ */
+#[deriving(PartialEq,Clone)]
+pub enum VarValue<K,V> {
+    Redirect(K),
+    Root(V, uint),
 }
 
-impl<V:Clone, T:Clone> ValsAndBindings<V, T> {
-    pub fn new() -> ValsAndBindings<V, T> {
-        ValsAndBindings {
-            vals: SmallIntMap::new(),
-            bindings: Vec::new()
-        }
-    }
+/**
+ * Table of unification keys and their values.
+ */
+pub struct UnificationTable<K,V> {
+    /**
+     * Indicates the current value of each key.
+     */
+    values: Vec<VarValue<K,V>>,
+
+    /**
+     * When a snapshot is active, logs each change made to the table
+     * so that they can be unrolled.
+     */
+    undo_log: Vec<UndoLog<K,V>>,
 }
 
-pub struct Node<V, T> {
-    pub root: V,
-    pub possible_types: T,
-    pub rank: uint,
+/**
+ * At any time, users may snapshot a unification table.  The changes
+ * made during the snapshot may either be *commited* or *rolled back*.
+ */
+pub struct Snapshot<K> {
+    // Ensure that this snapshot is keyed to the table type.
+    marker1: marker::CovariantType<K>,
+
+    // Snapshots are tokens that should be created/consumed linearly.
+    marker2: marker::NoCopy,
+
+    // Length of the undo log at the time the snapshot was taken.
+    length: uint,
 }
 
-pub trait UnifyVid<T> {
-    fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
-                                     -> &'v RefCell<ValsAndBindings<Self, T>>;
+#[deriving(PartialEq)]
+enum UndoLog<K,V> {
+    /// Indicates where a snapshot started.
+    OpenSnapshot,
+
+    /// Indicates a snapshot that has been committed.
+    CommittedSnapshot,
+
+    /// New variable with given index was created.
+    NewVar(uint),
+
+    /// Variable with given index was changed *from* the given value.
+    SetVar(uint, VarValue<K,V>),
 }
 
-pub trait UnifyInferCtxtMethods {
-    fn get<T:Clone,
-           V:Clone + PartialEq + Vid + UnifyVid<T>>(
-           &self,
-           vid: V)
-           -> Node<V, T>;
-    fn set<T:Clone + InferStr,
-           V:Clone + Vid + ToStr + UnifyVid<T>>(
-           &self,
-           vid: V,
-           new_v: VarValue<V, T>);
-    fn unify<T:Clone + InferStr,
-             V:Clone + Vid + ToStr + UnifyVid<T>>(
-             &self,
-             node_a: &Node<V, T>,
-             node_b: &Node<V, T>)
-             -> (V, uint);
+/**
+ * Internal type used to represent the result of a `get()` operation.
+ * Conveys the current root and value of the key.
+ */
+pub struct Node<K,V> {
+    pub key: K,
+    pub value: V,
+    pub rank: uint,
 }
 
-impl<'a> UnifyInferCtxtMethods for InferCtxt<'a> {
-    fn get<T:Clone,
-           V:Clone + PartialEq + Vid + UnifyVid<T>>(
-           &self,
-           vid: V)
-           -> Node<V, T> {
+// We can't use V:LatticeValue, much as I would like to,
+// because frequently the pattern is that V=Bounds<U> for some
+// other type parameter U, and we have no way to say
+// Bounds<U>:
+
+impl<V:PartialEq+Clone+Repr,K:UnifyKey<V>> UnificationTable<K,V> {
+    pub fn new() -> UnificationTable<K,V> {
+        UnificationTable {
+            values: Vec::new(),
+            undo_log: Vec::new()
+        }
+    }
+
+    pub fn in_snapshot(&self) -> bool {
+        /*! True if a snapshot has been started. */
+
+        self.undo_log.len() > 0
+    }
+
+    /**
+     * Starts a new snapshot. Each snapshot must be either
+     * rolled back or commited in a "LIFO" (stack) order.
+     */
+    pub fn snapshot(&mut self) -> Snapshot<K> {
+        let length = self.undo_log.len();
+        debug!("{}: snapshot at length {}",
+               UnifyKey::tag(None::<K>),
+               length);
+        self.undo_log.push(OpenSnapshot);
+        Snapshot { length: length,
+                   marker1: marker::CovariantType,
+                   marker2: marker::NoCopy }
+    }
+
+    fn assert_open_snapshot(&self, snapshot: &Snapshot<K>) {
+        // Or else there was a failure to follow a stack discipline:
+        assert!(self.undo_log.len() > snapshot.length);
+
+        // Invariant established by start_snapshot():
+        assert!(*self.undo_log.get(snapshot.length) == OpenSnapshot);
+    }
+
+    /**
+     * Reverses all changes since the last snapshot. Also
+     * removes any keys that have been created since then.
+     */
+    pub fn rollback_to(&mut self, tcx: &ty::ctxt, snapshot: Snapshot<K>) {
+        debug!("{}: rollback_to({})",
+               UnifyKey::tag(None::<K>),
+               snapshot.length);
+
+        self.assert_open_snapshot(&snapshot);
+
+        while self.undo_log.len() > snapshot.length + 1 {
+            match self.undo_log.pop().unwrap() {
+                OpenSnapshot => {
+                    // This indicates a failure to obey the stack discipline.
+                    tcx.sess.bug("Cannot rollback an uncommited snapshot");
+                }
+
+                CommittedSnapshot => {
+                    // This occurs when there are nested snapshots and
+                    // the inner is commited but outer is rolled back.
+                }
+
+                NewVar(i) => {
+                    assert!(self.values.len() == i);
+                    self.values.pop();
+                }
+
+                SetVar(i, v) => {
+                    *self.values.get_mut(i) = v;
+                }
+            }
+        }
+
+        let v = self.undo_log.pop().unwrap();
+        assert!(v == OpenSnapshot);
+        assert!(self.undo_log.len() == snapshot.length);
+    }
+
+    /**
+     * Commits all changes since the last snapshot. Of course, they
+     * can still be undone if there is a snapshot further out.
+     */
+    pub fn commit(&mut self, snapshot: Snapshot<K>) {
+        debug!("{}: commit({})",
+               UnifyKey::tag(None::<K>),
+               snapshot.length);
+
+        self.assert_open_snapshot(&snapshot);
+
+        if snapshot.length == 0 {
+            // The root snapshot.
+            self.undo_log.truncate(0);
+        } else {
+            *self.undo_log.get_mut(snapshot.length) = CommittedSnapshot;
+        }
+    }
+
+    pub fn new_key(&mut self, value: V) -> K {
+        let index = self.values.len();
+
+        if self.in_snapshot() {
+            self.undo_log.push(NewVar(index));
+        }
+
+        self.values.push(Root(value, 0));
+        let k = UnifyKey::from_index(index);
+        debug!("{}: created new key: {}",
+               UnifyKey::tag(None::<K>),
+               k);
+        k
+    }
+
+    fn swap_value(&mut self,
+                  index: uint,
+                  new_value: VarValue<K,V>)
+                  -> VarValue<K,V>
+    {
+        /*!
+         * Primitive operation to swap a value in the var array.
+         * Caller should update the undo log if we are in a snapshot.
+         */
+
+        let loc = self.values.get_mut(index);
+        mem::replace(loc, new_value)
+    }
+
+    pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node<K,V> {
         /*!
-         *
          * Find the root node for `vid`. This uses the standard
          * union-find algorithm with path compression:
          * http://en.wikipedia.org/wiki/Disjoint-set_data_structure
          */
 
-        let tcx = self.tcx;
-        let vb = UnifyVid::appropriate_vals_and_bindings(self);
-        return helper(tcx, &mut *vb.borrow_mut(), vid);
-
-        fn helper<T:Clone, V:Clone+PartialEq+Vid>(
-            tcx: &ty::ctxt,
-            vb: &mut ValsAndBindings<V,T>,
-            vid: V) -> Node<V, T>
-        {
-            let vid_u = vid.to_uint();
-            let var_val = match vb.vals.find(&vid_u) {
-                Some(&ref var_val) => (*var_val).clone(),
-                None => {
-                    tcx.sess.bug(format!(
-                        "failed lookup of vid `{}`", vid_u).as_slice());
-                }
-            };
-            match var_val {
-                Redirect(vid) => {
-                    let node: Node<V,T> = helper(tcx, vb, vid.clone());
-                    if node.root != vid {
-                        // Path compression
-                        vb.vals.insert(vid.to_uint(),
-                                       Redirect(node.root.clone()));
+        let index = vid.index();
+        let value = (*self.values.get(index)).clone();
+        match value {
+            Redirect(redirect) => {
+                let node: Node<K,V> = self.get(tcx, redirect.clone());
+                if node.key != redirect {
+                    // Path compression
+                    let old_value =
+                        self.swap_value(index, Redirect(node.key.clone()));
+
+                    // If we are in a snapshot, record this compression,
+                    // because it's possible that the unification which
+                    // caused it will be rolled back later.
+                    if self.in_snapshot() {
+                        self.undo_log.push(SetVar(index, old_value));
                     }
-                    node
-                }
-                Root(pt, rk) => {
-                    Node {root: vid, possible_types: pt, rank: rk}
                 }
+                node
             }
+            Root(value, rank) => {
+                Node { key: vid, value: value, rank: rank }
+            }
+        }
+    }
+
+    fn is_root(&self, key: &K) -> bool {
+        match *self.values.get(key.index()) {
+            Redirect(..) => false,
+            Root(..) => true,
         }
     }
 
-    fn set<T:Clone + InferStr,
-           V:Clone + Vid + ToStr + UnifyVid<T>>(
-           &self,
-           vid: V,
-           new_v: VarValue<V, T>) {
+    pub fn set(&mut self,
+               tcx: &ty::ctxt,
+               key: K,
+               new_value: VarValue<K,V>)
+    {
         /*!
-         *
-         * Sets the value for `vid` to `new_v`.  `vid` MUST be a root node!
+         * Sets the value for `vid` to `new_value`. `vid` MUST be a
+         * root node! Also, we must be in the middle of a snapshot.
          */
 
+        assert!(self.is_root(&key));
+        assert!(self.in_snapshot());
+
         debug!("Updating variable {} to {}",
-               vid.to_str(), new_v.inf_str(self));
+               key.repr(tcx),
+               new_value.repr(tcx));
 
-        let vb = UnifyVid::appropriate_vals_and_bindings(self);
-        let mut vb = vb.borrow_mut();
-        let old_v = (*vb.vals.get(&vid.to_uint())).clone();
-        vb.bindings.push((vid.clone(), old_v));
-        vb.vals.insert(vid.to_uint(), new_v);
+        let index = key.index();
+        let old_value = self.swap_value(index, new_value);
+        self.undo_log.push(SetVar(index, old_value));
     }
 
-    fn unify<T:Clone + InferStr,
-             V:Clone + Vid + ToStr + UnifyVid<T>>(
-             &self,
-             node_a: &Node<V, T>,
-             node_b: &Node<V, T>)
-             -> (V, uint) {
-        // Rank optimization: if you don't know what it is, check
-        // out <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
+    pub fn unify(&mut self,
+                 tcx: &ty::ctxt,
+                 node_a: &Node<K,V>,
+                 node_b: &Node<K,V>)
+                 -> (K, uint)
+    {
+        /*!
+         * Either redirects node_a to node_b or vice versa, depending
+         * on the relative rank. Returns the new root and rank.  You
+         * should then update the value of the new root to something
+         * suitable.
+         */
 
-        debug!("unify(node_a(id={:?}, rank={:?}), \
-                node_b(id={:?}, rank={:?}))",
-               node_a.root, node_a.rank,
-               node_b.root, node_b.rank);
+        debug!("unify(node_a(id={}, rank={}), node_b(id={}, rank={}))",
+               node_a.key.repr(tcx),
+               node_a.rank,
+               node_b.key.repr(tcx),
+               node_b.rank);
 
         if node_a.rank > node_b.rank {
             // a has greater rank, so a should become b's parent,
             // i.e., b should redirect to a.
-            self.set(node_b.root.clone(), Redirect(node_a.root.clone()));
-            (node_a.root.clone(), node_a.rank)
+            self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
+            (node_a.key.clone(), node_a.rank)
         } else if node_a.rank < node_b.rank {
             // b has greater rank, so a should redirect to b.
-            self.set(node_a.root.clone(), Redirect(node_b.root.clone()));
-            (node_b.root.clone(), node_b.rank)
+            self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone()));
+            (node_b.key.clone(), node_b.rank)
         } else {
             // If equal, redirect one to the other and increment the
             // other's rank.
             assert_eq!(node_a.rank, node_b.rank);
-            self.set(node_b.root.clone(), Redirect(node_a.root.clone()));
-            (node_a.root.clone(), node_a.rank + 1)
+            self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone()));
+            (node_a.key.clone(), node_a.rank + 1)
         }
     }
-
 }
 
-// ______________________________________________________________________
-// Code to handle simple variables like ints, floats---anything that
+///////////////////////////////////////////////////////////////////////////
+// Code to handle simple keys like ints, floats---anything that
 // doesn't have a subtyping relationship we need to worry about.
 
-pub trait SimplyUnifiable {
+/**
+ * Indicates a type that does not have any kind of subtyping
+ * relationship.
+ */
+pub trait SimplyUnifiable : Clone + PartialEq + Repr {
     fn to_type_err(expected_found<Self>) -> ty::type_err;
 }
 
-pub fn mk_err<T:SimplyUnifiable>(a_is_expected: bool,
-                                 a_t: T,
-                                 b_t: T) -> ures {
+pub fn err<V:SimplyUnifiable>(a_is_expected: bool,
+                              a_t: V,
+                              b_t: V) -> ures {
     if a_is_expected {
         Err(SimplyUnifiable::to_type_err(
             ty::expected_found {expected: a_t, found: b_t}))
@@ -190,111 +383,141 @@ pub fn mk_err<T:SimplyUnifiable>(a_is_expected: bool,
     }
 }
 
-pub trait InferCtxtMethods {
-    fn simple_vars<T:Clone + PartialEq + InferStr + SimplyUnifiable,
-                   V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
-                   &self,
+pub trait InferCtxtMethodsForSimplyUnifiableTypes<V:SimplyUnifiable,
+                                                  K:UnifyKey<Option<V>>> {
+    fn simple_vars(&self,
                    a_is_expected: bool,
-                   a_id: V,
-                   b_id: V)
+                   a_id: K,
+                   b_id: K)
                    -> ures;
-    fn simple_var_t<T:Clone + PartialEq + InferStr + SimplyUnifiable,
-                    V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
-                    &self,
+    fn simple_var_t(&self,
                     a_is_expected: bool,
-                    a_id: V,
-                    b: T)
+                    a_id: K,
+                    b: V)
                     -> ures;
 }
 
-impl<'a> InferCtxtMethods for InferCtxt<'a> {
-    fn simple_vars<T:Clone + PartialEq + InferStr + SimplyUnifiable,
-                   V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
-                   &self,
+impl<'tcx,V:SimplyUnifiable,K:UnifyKey<Option<V>>>
+    InferCtxtMethodsForSimplyUnifiableTypes<V,K> for InferCtxt<'tcx>
+{
+    fn simple_vars(&self,
                    a_is_expected: bool,
-                   a_id: V,
-                   b_id: V)
-                   -> ures {
+                   a_id: K,
+                   b_id: K)
+                   -> ures
+    {
         /*!
-         *
-         * Unifies two simple variables.  Because simple variables do
-         * not have any subtyping relationships, if both variables
+         * Unifies two simple keys.  Because simple keys do
+         * not have any subtyping relationships, if both keys
          * have already been associated with a value, then those two
-         * values must be the same. */
+         * values must be the same.
+         */
 
-        let node_a = self.get(a_id);
-        let node_b = self.get(b_id);
-        let a_id = node_a.root.clone();
-        let b_id = node_b.root.clone();
+        let tcx = self.tcx;
+        let table = UnifyKey::unification_table(self);
+        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();
 
         if a_id == b_id { return uok(); }
 
-        let combined = match (&node_a.possible_types, &node_b.possible_types)
-        {
-            (&None, &None) => None,
-            (&Some(ref v), &None) | (&None, &Some(ref v)) => {
-                Some((*v).clone())
-            }
-            (&Some(ref v1), &Some(ref v2)) => {
-                if *v1 != *v2 {
-                    return mk_err(a_is_expected, (*v1).clone(), (*v2).clone())
+        let combined = {
+            match (&node_a.value, &node_b.value) {
+                (&None, &None) => {
+                    None
+                }
+                (&Some(ref v), &None) | (&None, &Some(ref v)) => {
+                    Some((*v).clone())
+                }
+                (&Some(ref v1), &Some(ref v2)) => {
+                    if *v1 != *v2 {
+                        return err(a_is_expected, (*v1).clone(), (*v2).clone())
+                    }
+                    Some((*v1).clone())
                 }
-                Some((*v1).clone())
             }
         };
 
-        let (new_root, new_rank) = self.unify(&node_a, &node_b);
-        self.set(new_root, Root(combined, new_rank));
-        return uok();
+        let (new_root, new_rank) = table.borrow_mut().unify(tcx,
+                                                            &node_a,
+                                                            &node_b);
+        table.borrow_mut().set(tcx, new_root, Root(combined, new_rank));
+        return Ok(())
     }
 
-    fn simple_var_t<T:Clone + PartialEq + InferStr + SimplyUnifiable,
-                    V:Clone + PartialEq + Vid + ToStr + UnifyVid<Option<T>>>(
-                    &self,
+    fn simple_var_t(&self,
                     a_is_expected: bool,
-                    a_id: V,
-                    b: T)
-                    -> ures {
+                    a_id: K,
+                    b: V)
+                    -> ures
+    {
         /*!
-         *
-         * Sets the value of the variable `a_id` to `b`.  Because
-         * simple variables do not have any subtyping relationships,
+         * Sets the value of the key `a_id` to `b`.  Because
+         * simple keys do not have any subtyping relationships,
          * if `a_id` already has a value, it must be the same as
-         * `b`. */
+         * `b`.
+         */
 
-        let node_a = self.get(a_id);
-        let a_id = node_a.root.clone();
+        let tcx = self.tcx;
+        let table = UnifyKey::unification_table(self);
+        let node_a = table.borrow_mut().get(tcx, a_id);
+        let a_id = node_a.key.clone();
 
-        match node_a.possible_types {
+        match node_a.value {
             None => {
-                self.set(a_id, Root(Some(b), node_a.rank));
-                return uok();
+                table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank));
+                return Ok(());
             }
 
             Some(ref a_t) => {
                 if *a_t == b {
-                    return uok();
+                    return Ok(());
                 } else {
-                    return mk_err(a_is_expected, (*a_t).clone(), b);
+                    return err(a_is_expected, (*a_t).clone(), b);
                 }
             }
         }
     }
 }
 
-// ______________________________________________________________________
+///////////////////////////////////////////////////////////////////////////
+
+// 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 } }
 
-impl UnifyVid<Bounds<ty::t>> for ty::TyVid {
-    fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
-        -> &'v RefCell<ValsAndBindings<ty::TyVid, Bounds<ty::t>>> {
-        return &infcx.ty_var_bindings;
+    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 UnifyVid<Option<IntVarValue>> for ty::IntVid {
-    fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
-        -> &'v RefCell<ValsAndBindings<ty::IntVid, Option<IntVarValue>>> {
-        return &infcx.int_var_bindings;
+impl UnifyValue for Bounds<ty::t> { }
+
+// Integral type keys
+
+impl UnifyKey<Option<IntVarValue>> for ty::IntVid {
+    fn index(&self) -> uint { self.index }
+
+    fn from_index(i: uint) -> ty::IntVid { ty::IntVid { index: i } }
+
+    fn unification_table<'v>(infcx: &'v InferCtxt)
+        -> &'v RefCell<UnificationTable<ty::IntVid, Option<IntVarValue>>>
+    {
+        return &infcx.int_unification_table;
+    }
+
+    fn tag(_: Option<ty::IntVid>) -> &'static str {
+        "IntVid"
     }
 }
 
@@ -304,13 +527,29 @@ fn to_type_err(err: expected_found<IntVarValue>) -> ty::type_err {
     }
 }
 
-impl UnifyVid<Option<ast::FloatTy>> for ty::FloatVid {
-    fn appropriate_vals_and_bindings<'v>(infcx: &'v InferCtxt)
-        -> &'v RefCell<ValsAndBindings<ty::FloatVid, Option<ast::FloatTy>>> {
-        return &infcx.float_var_bindings;
+impl UnifyValue for Option<IntVarValue> { }
+
+// Floating point type keys
+
+impl UnifyKey<Option<ast::FloatTy>> for ty::FloatVid {
+    fn index(&self) -> uint { self.index }
+
+    fn from_index(i: uint) -> ty::FloatVid { ty::FloatVid { index: i } }
+
+    fn unification_table<'v>(infcx: &'v InferCtxt)
+        -> &'v RefCell<UnificationTable<ty::FloatVid, Option<ast::FloatTy>>>
+    {
+        return &infcx.float_unification_table;
+    }
+
+    fn tag(_: Option<ty::FloatVid>) -> &'static str {
+        "FloatVid"
     }
 }
 
+impl UnifyValue for Option<ast::FloatTy> {
+}
+
 impl SimplyUnifiable for ast::FloatTy {
     fn to_type_err(err: expected_found<ast::FloatTy>) -> ty::type_err {
         return ty::terr_float_mismatch(err);
index 6aeae544746d8425644ad11eb93042c3a0845cc6..1c91b41b270e7bd89b3914e26a27d56b6378a67f 100644 (file)
 use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
 use middle::ty;
 use middle::typeck;
+use middle::typeck::infer;
+use middle::typeck::infer::unify;
+use VV = middle::typeck::infer::unify::VarValue;
+use middle::typeck::infer::region_inference;
 
 use std::rc::Rc;
 use std::gc::Gc;
@@ -574,6 +578,12 @@ fn repr(&self, tcx: &ctxt) -> String {
     }
 }
 
+impl Repr for ty::mt {
+    fn repr(&self, tcx: &ctxt) -> String {
+        mt_to_str(tcx, self)
+    }
+}
+
 impl Repr for subst::Substs {
     fn repr(&self, tcx: &ctxt) -> String {
         format!("Substs[types={}, regions={}]",
@@ -707,7 +717,7 @@ fn repr(&self, tcx: &ctxt) -> String {
             }
 
             ty::ReInfer(ReVar(ref vid)) => {
-                format!("ReInfer({})", vid.id)
+                format!("ReInfer({})", vid.index)
             }
 
             ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
@@ -878,13 +888,6 @@ fn repr(&self, tcx: &ctxt) -> String {
     }
 }
 
-
-impl Repr for ty::RegionVid {
-    fn repr(&self, _tcx: &ctxt) -> String {
-        format!("{:?}", *self)
-    }
-}
-
 impl Repr for ty::TraitStore {
     fn repr(&self, tcx: &ctxt) -> String {
         trait_store_to_str(tcx, *self)
@@ -998,3 +1001,83 @@ fn repr(&self, tcx: &ctxt) -> String {
                 self.region.repr(tcx))
     }
 }
+
+impl Repr for ty::IntVid {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{}", self)
+    }
+}
+
+impl Repr for ty::FloatVid {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{}", self)
+    }
+}
+
+impl Repr for ty::RegionVid {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{}", self)
+    }
+}
+
+impl Repr for ty::TyVid {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{}", self)
+    }
+}
+
+impl Repr for ty::IntVarValue {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{:?}", *self)
+    }
+}
+
+impl Repr for ast::IntTy {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{:?}", *self)
+    }
+}
+
+impl Repr for ast::UintTy {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{:?}", *self)
+    }
+}
+
+impl Repr for ast::FloatTy {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        format!("{:?}", *self)
+    }
+}
+
+impl<T:Repr> Repr for infer::Bounds<T> {
+    fn repr(&self, tcx: &ctxt) -> String {
+        format!("({} <= {})",
+                self.lb.repr(tcx),
+                self.ub.repr(tcx))
+    }
+}
+
+impl<K:Repr,V:Repr> Repr for VV<K,V> {
+    fn repr(&self, tcx: &ctxt) -> String {
+        match *self {
+            unify::Redirect(ref k) =>
+                format!("Redirect({})", k.repr(tcx)),
+            unify::Root(ref v, r) =>
+                format!("Root({}, {})", v.repr(tcx), r)
+        }
+    }
+}
+
+impl Repr for region_inference::VarValue {
+    fn repr(&self, tcx: &ctxt) -> String {
+        match *self {
+            infer::region_inference::NoValue =>
+                format!("NoValue"),
+            infer::region_inference::Value(r) =>
+                format!("Value({})", r.repr(tcx)),
+            infer::region_inference::ErrorValue =>
+                format!("ErrorValue"),
+        }
+    }
+}
index 5e84a90121f26a903bdc7195f527dda43cfa8d4c..66d0b5c2857ed47d57ec01cb268bddbcd8379a67 100644 (file)
@@ -40,7 +40,7 @@
 
 /// A stable identifier to the particular version of JSON output.
 /// Increment this when the `Crate` and related structures change.
-pub static SCHEMA_VERSION: &'static str = "0.8.2";
+pub static SCHEMA_VERSION: &'static str = "0.8.3";
 
 mod inline;
 
@@ -449,6 +449,7 @@ pub struct TyParam {
     pub name: String,
     pub did: ast::DefId,
     pub bounds: Vec<TyParamBound>,
+    pub default: Option<Type>
 }
 
 impl Clean<TyParam> for ast::TyParam {
@@ -457,6 +458,7 @@ fn clean(&self) -> TyParam {
             name: self.ident.clean(),
             did: ast::DefId { krate: ast::LOCAL_CRATE, node: self.id },
             bounds: self.bounds.clean().move_iter().collect(),
+            default: self.default.clean()
         }
     }
 }
@@ -470,6 +472,7 @@ fn clean(&self) -> TyParam {
             name: self.ident.clean(),
             did: self.def_id,
             bounds: self.bounds.clean(),
+            default: self.default.clean()
         }
     }
 }
index 0ba776e903a426bffbfccc858bd8e8ba5127ff94..1173f6eb5b8b49b8946f90ddee885f6e63e9748c 100644 (file)
@@ -82,6 +82,11 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                         try!(write!(f, "{}", *bound));
                     }
                 }
+
+                match tp.default {
+                    Some(ref ty) => { try!(write!(f, " = {}", ty)); },
+                    None => {}
+                };
             }
         }
         try!(f.write("&gt;".as_bytes()));
index f5521886f52df2e70b9b15b374497f94f60d2564..34898ea64acf7d31e513a04ebe0ff13f0613bf6e 100644 (file)
        html_root_url = "http://doc.rust-lang.org/")]
 
 #![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
-#![feature(linkage, unsafe_destructor)]
+#![feature(linkage, lang_items, unsafe_destructor)]
+#![allow(unknown_features)] // NOTE: remove after stage0 snapshot
 #![no_std]
 #![experimental]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
index a99fa016aef1d3cff0cfe3d1d96742f8fdc2e424..8106d516dad6e96c9ef7462ba89cb97cc8b653b8 100644 (file)
        html_root_url = "http://doc.rust-lang.org/",
        html_playground_url = "http://play.rust-lang.org/")]
 
-#![feature(macro_rules, globs, managed_boxes)]
-#![feature(linkage, default_type_params, phase, unsafe_destructor)]
+#![feature(macro_rules, globs, managed_boxes, linkage)]
+#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
 
 // Don't link to std. We are std.
 #![no_std]
 
 #![allow(deprecated)]
+#![allow(unknown_features)] // NOTE: remove after stage0 snapshot
 #![deny(missing_doc)]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 // When testing libstd, bring in libuv as the I/O backend so tests can print
 // things and all of the std::io tests have an I/O interface to run on top
index a2f22bcaa681682ff43ce01cbf27c195688a139c..beb75bab3f6ab6c8d1d83ee24176c53cb7b879b2 100644 (file)
@@ -30,7 +30,6 @@
 #![feature(phase, globs, macro_rules, unsafe_destructor)]
 #![deny(missing_doc)]
 #![no_std]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 #[phase(plugin, link)] extern crate core;
 extern crate alloc;
index 1fbc6e41e55c9b032a728fad75dab0f42bfc3d78..0d6821fb30c08810471035c1c7593d3a117e257f 100644 (file)
@@ -30,7 +30,6 @@
 #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
 #![feature(quote, unsafe_destructor)]
 #![allow(deprecated)]
-#![allow(unknown_features)] // NOTE: remove after a stage0 snap
 
 extern crate serialize;
 extern crate term;
index 043ce3bf5b07e75650366bc80b56f7a46044743e..e1319304e04e9af02045d047a52e20d15645b8b4 100644 (file)
@@ -88,6 +88,7 @@ pub enum restriction {
     RESTRICT_STMT_EXPR,
     RESTRICT_NO_BAR_OP,
     RESTRICT_NO_BAR_OR_DOUBLEBAR_OP,
+    RESTRICT_NO_STRUCT_LITERAL,
 }
 
 type ItemInfo = (Ident, Item_, Option<Vec<Attribute> >);
@@ -1364,7 +1365,7 @@ pub fn parse_ty(&mut self, plus_allowed: bool) -> P<Ty> {
         } else if self.token == token::BINOP(token::STAR) {
             // STAR POINTER (bare pointer?)
             self.bump();
-            TyPtr(self.parse_mt())
+            TyPtr(self.parse_ptr())
         } else if self.token == token::LBRACKET {
             // VECTOR
             self.expect(&token::LBRACKET);
@@ -1441,6 +1442,19 @@ pub fn parse_borrowed_pointee(&mut self) -> Ty_ {
         return TyRptr(opt_lifetime, mt);
     }
 
+    pub fn parse_ptr(&mut self) -> MutTy {
+        let mutbl = if self.eat_keyword(keywords::Mut) {
+            MutMutable
+        } else if self.eat_keyword(keywords::Const) {
+            MutImmutable
+        } else {
+            // NOTE: after a stage0 snap this should turn into a span_err.
+            MutImmutable
+        };
+        let t = self.parse_ty(true);
+        MutTy { ty: t, mutbl: mutbl }
+    }
+
     pub fn is_named_argument(&mut self) -> bool {
         let offset = match self.token {
             token::BINOP(token::AND) => 1,
@@ -2024,8 +2038,9 @@ pub fn parse_bottom_expr(&mut self) -> Gc<Expr> {
 
                 return self.mk_mac_expr(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT));
             } else if self.token == token::LBRACE {
-                // This might be a struct literal.
-                if self.looking_at_struct_literal() {
+                // This is a struct literal, unless we're prohibited from
+                // parsing struct literals here.
+                if self.restriction != RESTRICT_NO_STRUCT_LITERAL {
                     // It's a struct literal.
                     self.bump();
                     let mut fields = Vec::new();
@@ -2042,6 +2057,14 @@ pub fn parse_bottom_expr(&mut self) -> Gc<Expr> {
                                          &[token::COMMA], &[token::RBRACE]);
                     }
 
+                    if fields.len() == 0 && base.is_none() {
+                        let last_span = self.last_span;
+                        self.span_err(last_span,
+                                      "structure literal must either have at \
+                                       least one field or use functional \
+                                       structure update syntax");
+                    }
+
                     hi = self.span.hi;
                     self.expect(&token::RBRACE);
                     ex = ExprStruct(pth, fields, base);
@@ -2548,7 +2571,7 @@ pub fn parse_assign_expr(&mut self) -> Gc<Expr> {
     // parse an 'if' expression ('if' token already eaten)
     pub fn parse_if_expr(&mut self) -> Gc<Expr> {
         let lo = self.last_span.lo;
-        let cond = self.parse_expr();
+        let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
         let thn = self.parse_block();
         let mut els: Option<Gc<Expr>> = None;
         let mut hi = thn.span.hi;
@@ -2633,7 +2656,7 @@ pub fn parse_for_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {
         let lo = self.last_span.lo;
         let pat = self.parse_pat();
         self.expect_keyword(keywords::In);
-        let expr = self.parse_expr();
+        let expr = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
         let loop_block = self.parse_block();
         let hi = self.span.hi;
 
@@ -2642,7 +2665,7 @@ pub fn parse_for_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {
 
     pub fn parse_while_expr(&mut self) -> Gc<Expr> {
         let lo = self.last_span.lo;
-        let cond = self.parse_expr();
+        let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
         let body = self.parse_block();
         let hi = body.span.hi;
         return self.mk_expr(lo, hi, ExprWhile(cond, body));
@@ -2655,17 +2678,9 @@ pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::Ident>) -> Gc<Expr> {
         self.mk_expr(lo, hi, ExprLoop(body, opt_ident))
     }
 
-    // For distinguishing between struct literals and blocks
-    fn looking_at_struct_literal(&mut self) -> bool {
-        self.token == token::LBRACE &&
-        ((self.look_ahead(1, |t| token::is_plain_ident(t)) &&
-          self.look_ahead(2, |t| *t == token::COLON))
-         || self.look_ahead(1, |t| *t == token::DOTDOT))
-    }
-
     fn parse_match_expr(&mut self) -> Gc<Expr> {
         let lo = self.last_span.lo;
-        let discriminant = self.parse_expr();
+        let discriminant = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
         self.commit_expr_expecting(discriminant, token::LBRACE);
         let mut arms: Vec<Arm> = Vec::new();
         while self.token != token::RBRACE {
@@ -4116,6 +4131,11 @@ fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
                 };
                 spanned(lo, p.span.hi, struct_field_)
             });
+            if fields.len() == 0 {
+                self.fatal(format!("unit-like struct definition should be \
+                                    written as `struct {};`",
+                                   token::get_ident(class_name)).as_slice());
+            }
             self.expect(&token::SEMI);
         } else if self.eat(&token::SEMI) {
             // It's a unit-like struct.
index a2af417ed79a82055ec86c8defc389994ea1788c..8e36339b0e5e360dcfe44ed6d4cc9f6c95670539 100644 (file)
@@ -512,11 +512,11 @@ pub mod keywords {
         (40,                         Continue,   "continue");
         (41,                         Proc,       "proc");
         (42,                         Box,        "box");
+        (43,                         Const,      "const");
 
         'reserved:
-        (43,                         Alignof,    "alignof");
-        (44,                         Be,         "be");
-        (45,                         Const,      "const");
+        (44,                         Alignof,    "alignof");
+        (45,                         Be,         "be");
         (46,                         Offsetof,   "offsetof");
         (47,                         Priv,       "priv");
         (48,                         Pure,       "pure");
index e46c99cf4f0dd9c943ab85acb4381d33e87d165c..ac11d94d2e604394189490aa45bd7bb0212082a9 100644 (file)
@@ -1,3 +1,11 @@
+S 2014-06-21 db9af1d
+  freebsd-x86_64 ef2bd0fc0b0efa2bd6f5c1eaa60a2ec8df533254
+  linux-i386 84339ea0f796ae468ef86797ef4587274bec19ea
+  linux-x86_64 bd8a6bc1f28845b7f4b768f6bfa06e7fbdcfcaae
+  macos-i386 3f25b2680efbab16ad074477a19d49dcce475977
+  macos-x86_64 4a8c2e1b7634d73406bac32a1a97893ec3ed818d
+  winnt-i386 0bf4e101d979ce116977d660ef149d03fbc90b99
+
 S 2014-06-18 d6736a1
   freebsd-x86_64 c1479bb3dc0ae3d8ba9193ff2caf92c805a95c51
   linux-i386 bb1543b21235a51e81460b9419e112396ccf1d20
index 35d987480c0786be72ce1ae6884012c07ac58be4..a3a3dbac2b5515ca0b5d4eb3aff5f659c7bb615f 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(intrinsics)]
+
 pub mod rusti {
     extern "rust-intrinsic" {
         pub fn atomic_xchg<T>(dst: *mut T, src: T) -> T;
index 4b19d291b85ddfc40c4deeefa945c5544f715932..7b84e11ef31f020b9d1db86cd3fb1a91cbdd4a8d 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![no_std]
+#![feature(lang_items)]
 
 #[lang="fail_"]
 fn fail(_: &'static str, _: &'static str, _: uint) -> ! { loop {} }
index b1f7a791f0958100416f3ecfa4e3a30429d90ff1..4bd61412731418a82d6d13257cf8b4b201eb6f4e 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(lang_items)]
+
 fn main() {}
 
 #![lang(foo)] //~ ERROR an inner attribute is not permitted in this context
index 7ce6f7188b84f5484d25331b86cb586260e29d26..3a2a75586576ead6e8a0fa34d377103b8d8539d3 100644 (file)
@@ -11,6 +11,7 @@
 // ignore-tidy-linelength
 
 #![no_std]
+#![feature(lang_items)]
 
 #[lang="sized"]
 pub trait Sized {}
index b9ae0d341d9a261e42ea736e24ec90bdd415db57..3671cf110d81e2bb43e61117760f8bee81f03af8 100644 (file)
@@ -10,7 +10,7 @@
 
 fn main() {
     struct Foo { x: int }
-    match Foo { x: 10 } {
+    match (Foo { x: 10 }) {
         Foo { ref x: ref x } => {}, //~ ERROR unexpected `:`
         _ => {}
     }
index 72d9afd4d2b2be8f51718ebfa486ab435b883248..6b5dd570e34e250151c66b4ee5f0ce7399e8a90e 100644 (file)
@@ -31,7 +31,7 @@ pub fn main() {
         }
     }
 
-    match S { bar: 1 } {
+    match (S { bar: 1 }) {
         S { bar: x } => {
             x += 1; //~ ERROR re-assignment of immutable variable `x`
         }
index 976a574a18f7d00dbe657b64f7c19865e7824448..167e78d7ed09ea72623cfbe681ef282e48dfe9a1 100644 (file)
@@ -34,7 +34,7 @@ impl Drop for S {
 }
 
 fn move_in_match() {
-    match S {f: "foo".to_string(), g: "bar".to_string()} {
+    match (S {f: "foo".to_string(), g: "bar".to_string()}) {
         S {         //~ ERROR cannot move out of type `S`, which defines the `Drop` trait
             f: _s,  //~ NOTE attempting to move value to here
             g: _t   //~ NOTE and here
index e6cb2d67324a4c3a45dd3eb223bff774b2b8f3dc..3d13cbe30c5a21c0249f39dee46732032426db85 100644 (file)
@@ -14,7 +14,7 @@ impl Drop for S {
 }
 
 fn move_in_match() {
-    match S {f:"foo".to_string()} {
+    match (S {f:"foo".to_string()}) {
         S {f:_s} => {}
         //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
     }
diff --git a/src/test/compile-fail/feature-gate-intrinsics-and-lang-items.rs b/src/test/compile-fail/feature-gate-intrinsics-and-lang-items.rs
new file mode 100644 (file)
index 0000000..986d52b
--- /dev/null
@@ -0,0 +1,23 @@
+// 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.
+
+#[lang="foo"]   //~ ERROR language items are subject to change
+trait Foo {}
+
+extern "rust-intrinsic" {   //~ ERROR intrinsics are subject to change
+    fn bar();
+}
+
+extern "rust-intrinsic" fn baz() {  //~ ERROR intrinsics are subject to change
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/issue-2123.rs b/src/test/compile-fail/issue-2123.rs
deleted file mode 100644 (file)
index 335012c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2012-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 x = m::f; //~ ERROR unresolved import `m::f`. There is no `f` in `m`
-
-mod m {}
-
-fn main() {}
diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs
new file mode 100644 (file)
index 0000000..795e48c
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2013-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.
+
+// aux-build:issue_3907.rs
+extern crate issue_3907;
+
+type Foo = issue_3907::Foo; //~ ERROR: reference to trait
+
+struct S {
+    name: int
+}
+
+fn main() {}
index 767e674fcda171e890f8f00152c0bb3b244fe86b..a2faef59fd8286d605c0a610e5a8ed2cba07a9a5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
 // aux-build:issue_3907.rs
 extern crate issue_3907;
 
-type Foo = issue_3907::Foo; //~ ERROR: reference to trait
+type Foo = issue_3907::Foo;
 
 struct S {
     name: int
 }
 
 impl Foo for S { //~ ERROR: `Foo` is not a trait
+    //~^ NOTE: `type` aliases cannot be used for traits
     fn bar() { }
 }
 
index 7fe7778c1a59e981aeb2fa5a4c72697c9ce6082f..9b77d62a065292f74c68a264fa58da80565db02c 100644 (file)
@@ -8,26 +8,29 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-test
-
-use std::io;
-
 struct Point {
     x: f64,
     y: f64,
 }
 
-impl ToStr for Point { //~ ERROR implements a method not defined in the trait
+trait NewTrait {
+    fn a(&self) -> String;
+}
+
+impl NewTrait for Point {
     fn new(x: f64, y: f64) -> Point {
+    //~^ ERROR method `new` is not a member of trait `NewTrait`
         Point { x: x, y: y }
     }
 
-    fn to_str(&self) -> String {
+    fn a(&self) -> String {
         format!("({}, {})", self.x, self.y)
     }
 }
 
 fn main() {
     let p = Point::new(0.0, 0.0);
-    println!("{}", p.to_str());
+    //~^ ERROR unresolved name `Point::new`
+    //~^^ ERROR failed to resolve. Use of undeclared module `Point`
+    println!("{}", p.a());
 }
diff --git a/src/test/compile-fail/issue-3993-3.rs b/src/test/compile-fail/issue-3993-3.rs
deleted file mode 100644 (file)
index fae5eb5..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.
-
-use zoo::fly; //~ ERROR: function `fly` is private
-
-mod zoo {
-    fn fly() {}
-}
-
-
-fn main() {
-    fly();
-}
diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs
new file mode 100644 (file)
index 0000000..8d9116d
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2013-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.
+
+trait I {}
+type K = I; //~ ERROR: reference to trait
+
+fn main() {}
index 94110f077623b680d815c414a616cdc137a2383c..8ffe308a669399d35b704ccde339221f1bd9a058 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 trait I {}
-type K = I; //~ ERROR: reference to trait
+type K = I;
 impl K for int {} //~ ERROR: `K` is not a trait
+//~^ NOTE: `type` aliases cannot be used for traits
 fn main() {}
index bca2a5d7edc864cb871726e4603157fbe8bdc424..b68a2241e1a39a9dc63d6d1fea0e4f86e386b729 100644 (file)
@@ -13,6 +13,7 @@
 #![allow(non_camel_case_types)]
 #![allow(visible_private_types)]
 #![deny(dead_code)]
+#![feature(lang_items)]
 
 #![crate_type="lib"]
 
@@ -37,7 +38,7 @@ mod foo2 {
 static STATIC_USED_IN_ENUM_DISCRIMINANT: uint = 10;
 
 pub type typ = *UsedStruct4;
-pub struct PubStruct();
+pub struct PubStruct;
 struct PrivStruct; //~ ERROR: code is never used
 struct UsedStruct1 {
     #[allow(dead_code)]
index 1ebb8ed5ddc62d0231871935264f44e7bf0a7a2d..4956528856b66d3c85d25f10fbdd01f0b1e58b82 100644 (file)
@@ -13,7 +13,7 @@ struct S { a: int }
 enum E { C(int) }
 
 fn main() {
-    match S { a: 1 } {
+    match (S { a: 1 }) {
         C(_) => (), //~ ERROR mismatched types: expected `S` but found `E`
         _ => ()
     }
index 22e93d70858e4deb68220fabdfd0f9cc6adbea50..d0f51bf2da43b8d8c0c0628061875c20a054feab 100644 (file)
@@ -22,7 +22,7 @@ enum Color {
 }
 
 fn struct_with_a_nested_enum_and_vector() {
-    match Foo { first: true, second: None } {
+    match (Foo { first: true, second: None }) {
     //~^ ERROR non-exhaustive patterns: `Foo{first: false, second: Some([_, _, _, _])}` not covered
         Foo { first: true, second: None } => (),
         Foo { first: true, second: Some(_) } => (),
@@ -71,4 +71,4 @@ fn main() {
     struct_with_a_nested_enum_and_vector();
     enum_with_multiple_missing_variants();
     enum_struct_variant();
-}
\ No newline at end of file
+}
index 83141020b29e49226e317351d49f4ac9abb6fbae..6df52c394fc0ed7b7dc3eb0bfdd7af2d3a0e969a 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(globs)]
+#![feature(globs, lang_items)]
 #![no_std] // makes debugging this test *a lot* easier (during resolve)
 
 #[lang="sized"]
diff --git a/src/test/compile-fail/struct-literal-in-for.rs b/src/test/compile-fail/struct-literal-in-for.rs
new file mode 100644 (file)
index 0000000..ccd711d
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+struct Foo {
+    x: int,
+}
+
+impl Foo {
+    fn hi(&self) -> bool {
+        true
+    }
+}
+
+fn main() {
+    for x in Foo {
+        x: 3    //~ ERROR expected one of `;`, `}`
+    }.hi() {
+        println!("yo");
+    }
+}
+
diff --git a/src/test/compile-fail/struct-literal-in-if.rs b/src/test/compile-fail/struct-literal-in-if.rs
new file mode 100644 (file)
index 0000000..d63c216
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+struct Foo {
+    x: int,
+}
+
+impl Foo {
+    fn hi(&self) -> bool {
+        true
+    }
+}
+
+fn main() {
+    if Foo {
+        x: 3    //~ ERROR expected one of `;`, `}`
+    }.hi() {
+        println!("yo");
+    }
+}
+
diff --git a/src/test/compile-fail/struct-literal-in-match-discriminant.rs b/src/test/compile-fail/struct-literal-in-match-discriminant.rs
new file mode 100644 (file)
index 0000000..c740ba0
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+struct Foo {
+    x: int,
+}
+
+fn main() {
+    match Foo {
+        x: 3    //~ ERROR expected `=>`
+    } {
+        Foo {
+            x: x
+        } => {}
+    }
+}
+
diff --git a/src/test/compile-fail/struct-literal-in-while.rs b/src/test/compile-fail/struct-literal-in-while.rs
new file mode 100644 (file)
index 0000000..7b2c11e
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+struct Foo {
+    x: int,
+}
+
+impl Foo {
+    fn hi(&self) -> bool {
+        true
+    }
+}
+
+fn main() {
+    while Foo {
+        x: 3    //~ ERROR expected one of `;`, `}`
+    }.hi() {
+        println!("yo");
+    }
+}
+
index cd555f8d917882cf403381a36cdcfde3eea1da5a..4f973f81b1641b4e7e8635a7caa6522860ea658f 100644 (file)
@@ -12,7 +12,7 @@
 
 fn f2() {
     let _end_stmt     = Foo { };
-    //~^ ERROR: unit-like struct construction is written with no trailing `{ }`
+    //~^ ERROR: structure literal must either have at least one field
 }
 
 fn main() {}
index 2595c5e8acf87374a8efd5a886135a2d6b327b23..e594683feed173dfadc36b6658a7cbc1271b3629 100644 (file)
@@ -12,7 +12,7 @@
 
 fn g3() {
     let _mid_tuple    = (Foo { }, 2);
-    //~^ ERROR: unit-like struct construction is written with no trailing `{ }`
+    //~^ ERROR: structure literal must either have at least one field
 }
 
 fn main() {}
index fee5c35e85005fca39aa7f0eb07c318c0ad188da..60a0a85d0abf1be3298455331be6431c6dddf37c 100644 (file)
@@ -12,7 +12,7 @@
 
 fn h4() {
     let _end_of_tuple = (3, Foo { });
-    //~^ ERROR: unit-like struct construction is written with no trailing `{ }`
+    //~^ ERROR: structure literal must either have at least one field
 }
 
 fn main() {}
index bd196e881aa35cc5c6ba64f6b38acd07a941d771..940fa9c7f273f5ec9d79078614ae62fe3ca56bf6 100644 (file)
@@ -12,7 +12,7 @@
 
 fn i5() {
     let _end_of_block = { Foo { } };
-    //~^ ERROR: unit-like struct construction is written with no trailing `{ }`
+    //~^ ERROR: structure literal must either have at least one field
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/struct-no-fields-enumlike.rs b/src/test/compile-fail/struct-no-fields-enumlike.rs
new file mode 100644 (file)
index 0000000..379d310
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+
+struct Foo(); //~ ERROR unit-like struct definition should be written as `struct Foo;`
+
+fn main() {}
diff --git a/src/test/compile-fail/type-mismatch.rs b/src/test/compile-fail/type-mismatch.rs
deleted file mode 100644 (file)
index c5e3781..0000000
+++ /dev/null
@@ -1,18 +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.
-
-// issue #516
-
-fn main() {
-    let x = true;
-    let y = 1;
-    let z = x + y;
-    //~^ ERROR binary operation `+` cannot be applied to type `bool`
-}
index 5f13c780ba865d6a047dac55d13a6805a71cf67d..b347afbbbcdb541f9a49579b9a59987061a58cdd 100644 (file)
@@ -105,7 +105,7 @@ fn main() {
         _ => {}
     }
 
-    match Struct { x: 237, y: 238 } {
+    match (Struct { x: 237, y: 238 }) {
         Struct { x: shadowed, y: local_to_arm } => {
 
             zzz();
@@ -113,7 +113,7 @@ fn main() {
         }
     }
 
-    match Struct { x: 239, y: 240 } {
+    match (Struct { x: 239, y: 240 }) {
         // ignored field
         Struct { x: shadowed, .. } => {
 
@@ -122,7 +122,7 @@ fn main() {
         }
     }
 
-    match Struct { x: 241, y: 242 } {
+    match (Struct { x: 241, y: 242 }) {
         // with literal
         Struct { x: shadowed, y: 242 } => {
 
diff --git a/src/test/run-fail/binop-fail-2.rs b/src/test/run-fail/binop-fail-2.rs
deleted file mode 100644 (file)
index 1ae520b..0000000
+++ /dev/null
@@ -1,13 +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.
-
-// error-pattern:quux
-fn my_err(s: String) -> ! { println!("{}", s); fail!("quux"); }
-fn main() { 3u == my_err("bye".to_string()); }
index 61df7bf508860eec4858d355736e82ecde3317be..27e0b99888259839722b83b85088ee697d2070d1 100644 (file)
 
 use std::hash::hash;
 
-#[deriving(PartialEq, Clone, Hash)]
+// testing mulptiple separate deriving attributes
+#[deriving(PartialEq)]
+#[deriving(Clone)]
+#[deriving(Hash)]
 struct Foo {
     bar: uint,
     baz: int
index bf29fa603c7ecd2f01c201e05fd432575e36bce3..8fa4af528567b9357be38a2e7c74a231c3c47345 100644 (file)
@@ -16,7 +16,7 @@ pub fn main() {
     assert_eq!(a, 2);
 
     let b =
-        match Pair {x: 10, y: 20} {
+        match (Pair {x: 10, y: 20}) {
           x if x.x < 5 && x.y < 5 => { 1 }
           Pair {x: x, y: y} if x == 10 && y == 20 => { 2 }
           Pair {x: _x, y: _y} => { 3 }
index 12385a26437b2978288202c589c2bca25c040b81..84593ececd0af6a23005bfca1bac0e7ca5e3e657 100644 (file)
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(intrinsics)]
 
 mod rusti {
     extern "rust-intrinsic" {
index 8fa89303fa9504405464d61ef8ee9a4977ce1cd9..8a856b14eae02bff853bc6345ca9866ed62ca744 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(intrinsics)]
+
 mod rusti {
     extern "rust-intrinsic" {
         pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> T;
index 752c9464cf62008776c05801e3661fdecb84e023..84b80d43f0902ba3dcf5e69f99672f10ae55113c 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(intrinsics)]
+
 use std::mem::transmute;
 
 mod rusti {
index ab6904927e87065ff06378a5f0677a7e09fba272..34fd8effd4912de05a826f1a6002ba0491017ee9 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(intrinsics)]
+
 mod rusti {
     extern "rust-intrinsic" {
         pub fn uninit<T>() -> T;
index e31b941f956eb6893f2a36fc06ab3235aad1531d..5121e2185cb7ba2eb0d06adb3c0d2dd77e9fe9af 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(globs)]
+#![feature(globs, intrinsics)]
 
 mod rusti {
     extern "rust-intrinsic" {
index 94d53f139cfa8d77e39d6aa4c4d76f32126cc39b..164a6845a9f0b308e4e2ab77de12e6d203032249 100644 (file)
@@ -9,7 +9,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(globs, macro_rules)]
+#![feature(globs, macro_rules, intrinsics)]
 
 macro_rules! assert_approx_eq(
     ($a:expr, $b:expr) => ({
index 5772a2c437adb91c49fda0df00a22a8dc2a3e064..c30c4a714b39d92ac4257bcae36258738f36efef 100644 (file)
@@ -16,7 +16,7 @@ enum Foo {
 
 macro_rules! match_inside_expansion(
     () => (
-        match B { b1:29 , bb1: 100} {
+        match (B { b1:29 , bb1: 100}) {
             B { b1:b2 , bb1:bb2 } => b2+bb2
         }
     )
index e09ac9450ba3c973a12779064e090192dd7a87fe..b2a47e0ccb88b0145113f4c17ef84dab4cc59d74 100644 (file)
@@ -11,7 +11,7 @@
 struct Foo { foo: bool, bar: Option<int>, baz: int }
 
 pub fn main() {
-    match Foo{foo: true, bar: Some(10), baz: 20} {
+    match (Foo{foo: true, bar: Some(10), baz: 20}) {
       Foo{foo: true, bar: Some(_), ..} => {}
       Foo{foo: false, bar: None, ..} => {}
       Foo{foo: true, bar: None, ..} => {}
index 1cbed9c29ece21957e636cc18c603d48389b61a5..08816d345b400563463233cb38bee09c5176e4ea 100644 (file)
@@ -14,7 +14,7 @@ struct D { a: int, d: C }
 struct C { c: int }
 
 pub fn main() {
-    match A {a: 10, b: 20} {
+    match (A {a: 10, b: 20}) {
         x@A {a, b: 20} => { assert!(x.a == 10); assert!(a == 10); }
         A {b: _b, ..} => { fail!(); }
     }
diff --git a/src/test/run-pass/new-unsafe-pointers.rs b/src/test/run-pass/new-unsafe-pointers.rs
new file mode 100644 (file)
index 0000000..96ccb1a
--- /dev/null
@@ -0,0 +1,14 @@
+// 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 main() {
+    let _a: *const int = 3 as *const int;
+    let _a: *mut int = 3 as *mut int;
+}
index 69a4c1cd05374a522056d106af309f0521d28852..d741b80ef5e4946c2b754f0aa8ad9e7fd79fc4c9 100644 (file)
@@ -10,6 +10,8 @@
 
 // Issue #2303
 
+#![feature(intrinsics)]
+
 extern crate debug;
 
 use std::mem;
index 399f947df06cf862e89379695cd9968647709623..cf254d54793a44f0584e1bac4c287efbe5df45eb 100644 (file)
@@ -10,6 +10,8 @@
 
 // Issue #2303
 
+#![feature(intrinsics)]
+
 extern crate debug;
 
 use std::mem;
index 0dbd4c67530767f6e1bab8de5845039a0c1d34d9..bdba5aa9cfe153d7384d1b72b1e4a94cd60688d9 100644 (file)
@@ -13,6 +13,7 @@
 // Smallest "hello world" with a libc runtime
 
 #![no_std]
+#![feature(intrinsics, lang_items)]
 
 extern crate libc;
 
index 8cb1cdd2a7ff379d27183cf23e89ec6b685a6292..e7bc61c1fb99c74b259848673fd9492d25d7d07f 100644 (file)
@@ -14,7 +14,7 @@
 use struct_variant_xc_aux::{StructVariant, Variant};
 
 pub fn main() {
-    let arg = match StructVariant { arg: 42 } {
+    let arg = match (StructVariant { arg: 42 }) {
         Variant(_) => unreachable!(),
         StructVariant { arg } => arg
     };
diff --git a/src/test/run-pass/unique-decl-move-temp.rs b/src/test/run-pass/unique-decl-move-temp.rs
deleted file mode 100644 (file)
index 346b7d0..0000000
+++ /dev/null
@@ -1,14 +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.
-
-pub fn main() {
-    let i = box 100;
-    assert_eq!(*i, 100);
-}