]> git.lizzy.rs Git - rust.git/commitdiff
auto merge of #16957 : vadimcn/rust/package-gcc, r=brson
authorbors <bors@rust-lang.org>
Thu, 11 Sep 2014 21:55:42 +0000 (21:55 +0000)
committerbors <bors@rust-lang.org>
Thu, 11 Sep 2014 21:55:42 +0000 (21:55 +0000)
Package rustc's mingw dependencies into Windows installer to avoid requiring a separate mingw install.

Closes #11782

45 files changed:
mk/docs.mk
src/doc/index.md
src/doc/rust.md
src/liballoc/heap.rs
src/librustc/front/feature_gate.rs
src/librustc/front/show_span.rs
src/librustc/lint/builtin.rs
src/librustc/middle/borrowck/mod.rs
src/librustc/middle/cfg/construct.rs
src/librustc/middle/check_const.rs
src/librustc/middle/check_static.rs
src/librustc/middle/const_eval.rs
src/librustc/middle/dead.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/privacy.rs
src/librustc/middle/region.rs
src/librustc/middle/save/mod.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/debuginfo.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/tvec.rs
src/librustc/middle/ty.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/resolve.rs
src/librustc_back/svh.rs
src/libsyntax/ast.rs
src/libsyntax/ext/build.rs
src/libsyntax/fold.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/compile-fail/borrow-tuple-fields.rs [new file with mode: 0644]
src/test/compile-fail/move-out-of-tuple-field.rs [new file with mode: 0644]
src/test/compile-fail/occurs-check-2.rs [new file with mode: 0644]
src/test/compile-fail/occurs-check.rs
src/test/compile-fail/tuple-index-not-tuple.rs [new file with mode: 0644]
src/test/compile-fail/tuple-index-out-of-bounds.rs [new file with mode: 0644]
src/test/run-pass/borrow-tuple-fields.rs [new file with mode: 0644]
src/test/run-pass/empty-allocation-non-null.rs
src/test/run-pass/tuple-index-fat-types.rs [new file with mode: 0644]
src/test/run-pass/tuple-index.rs [new file with mode: 0644]

index 8a0c17de27aa0a3e92841a6098d1907bb2fa23f9..db0de4bde5b8a20df66618aaa4c3ca3435cf2dfb 100644 (file)
@@ -76,21 +76,22 @@ endif
 
 # Check for the various external utilities for the EPUB/PDF docs:
 
-ifeq ($(CFG_PDFLATEX),)
-  $(info cfg: no pdflatex found, deferring to xelatex)
+ifeq ($(CFG_LUALATEX),)
+  $(info cfg: no lualatex found, deferring to xelatex)
   ifeq ($(CFG_XELATEX),)
-    $(info cfg: no xelatex found, deferring to lualatex)
-    ifeq ($(CFG_LUALATEX),)
-      $(info cfg: no lualatex found, disabling LaTeX docs)
+    $(info cfg: no xelatex found, deferring to pdflatex)
+    ifeq ($(CFG_PDFLATEX),)
+      $(info cfg: no pdflatex found, disabling LaTeX docs)
       NO_PDF_DOCS = 1
        else
-      CFG_LATEX := $(CFG_LUALATEX)
+      CFG_LATEX := $(CFG_PDFLATEX)
     endif
   else
     CFG_LATEX := $(CFG_XELATEX)
+    XELATEX = 1
   endif
 else
-  CFG_LATEX := $(CFG_PDFLATEX)
+  CFG_LATEX := $(CFG_LUALATEX)
 endif
 
 
@@ -187,12 +188,25 @@ doc/$(1).tex: $$(D)/$(1).md doc/footer.tex doc/version.tex | doc/
 ifneq ($(NO_PDF_DOCS),1)
 ifeq ($$(SHOULD_BUILD_PDF_DOC_$(1)),1)
 DOC_TARGETS += doc/$(1).pdf
+ifneq ($(XELATEX),1)
 doc/$(1).pdf: doc/$(1).tex
        @$$(call E, latex compiler: $$@)
        $$(Q)$$(CFG_LATEX) \
        -interaction=batchmode \
        -output-directory=doc \
        $$<
+else
+# The version of xelatex on the snap bots seemingly ingores -output-directory
+# So we'll output to . and move to the doc directory manually.
+# This will leave some intermediate files in the build directory.
+doc/$(1).pdf: doc/$(1).tex
+       @$$(call E, latex compiler: $$@)
+       $$(Q)$$(CFG_LATEX) \
+       -interaction=batchmode \
+       -output-directory=. \
+       $$<
+       $$(Q)mv ./$(1).pdf $$@
+endif # XELATEX
 endif # SHOULD_BUILD_PDF_DOCS_$(1)
 endif # NO_PDF_DOCS
 
index a479164c505029f105992f514bed13b2490a3847..66f69d62e788f2043d6a9c0ab3fe989920903a56 100644 (file)
@@ -43,6 +43,10 @@ discussion about Rust.
 There is also a [developer forum](http://discuss.rust-lang.org/), where the
 development of Rust itself is discussed.
 
+# Specification
+
+Rust does not have an exact specification, but an effort to describe as much of
+the language in as much detail as possible is in [the manual](rust.html).
 
 # Guides
 
index eb97a75e7660b0ef192a99a1c2662980666c4a2c..2ef595a06524e99aacb2bf11a3d53b9a9dd46216 100644 (file)
@@ -349,7 +349,7 @@ enclosed within two `U+0022` (double-quote) characters,
 with the exception of `U+0022` itself,
 which must be _escaped_ by a preceding `U+005C` character (`\`),
 or a _raw byte string literal_.
-It is equivalent to a `&'static [u8]` borrowed vector of unsigned 8-bit integers.
+It is equivalent to a `&'static [u8]` borrowed array of unsigned 8-bit integers.
 
 Some additional _escapes_ are available in either byte or non-raw byte string
 literals. An escape starts with a `U+005C` (`\`) and continues with one of
@@ -2555,6 +2555,8 @@ The currently implemented features of the reference compiler are:
                         which is considered wildly unsafe and will be
                         obsoleted by language improvements.
 
+* `tuple_indexing` - Allows use of tuple indexing (expressions like `expr.0`)
+
 If a feature is promoted to a language feature, then all existing programs will
 start to receive compilation warnings about #[feature] directives which enabled
 the new feature (because the directive is no longer necessary). However, if
@@ -2809,16 +2811,17 @@ When the type providing the field inherits mutabilty, it can be [assigned](#assi
 Also, if the type of the expression to the left of the dot is a pointer,
 it is automatically dereferenced to make the field access possible.
 
-### Vector expressions
+### Array expressions
 
 ~~~~ {.ebnf .gram}
-vec_expr : '[' "mut" ? vec_elems? ']' ;
+array_expr : '[' "mut" ? vec_elems? ']' ;
 
-vec_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
+array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
 ~~~~
 
-A [_vector_](#vector-types) _expression_ is written by enclosing zero or
-more comma-separated expressions of uniform type in square brackets.
+An [array](#vector,-array,-and-slice-types) _expression_ is written by
+enclosing zero or more comma-separated expressions of uniform type in square
+brackets.
 
 In the `[expr ',' ".." expr]` form, the expression after the `".."`
 must be a constant expression that can be evaluated at compile time, such
@@ -2827,7 +2830,7 @@ as a [literal](#literals) or a [static item](#static-items).
 ~~~~
 [1i, 2, 3, 4];
 ["a", "b", "c", "d"];
-[0i, ..128];             // vector with 128 zeros
+[0i, ..128];             // array with 128 zeros
 [0u8, 0u8, 0u8, 0u8];
 ~~~~
 
@@ -2837,9 +2840,9 @@ as a [literal](#literals) or a [static item](#static-items).
 idx_expr : expr '[' expr ']' ;
 ~~~~
 
-[Vector](#vector-types)-typed expressions can be indexed by writing a
+[Array](#vector,-array,-and-slice-types)-typed expressions can be indexed by writing a
 square-bracket-enclosed expression (the index) after them. When the
-vector is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to.
+array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to.
 
 Indices are zero-based, and may be of any integral type. Vector access
 is bounds-checked at run-time. When the check fails, it will put the
@@ -2900,7 +2903,7 @@ This means that arithmetic operators can be overridden for user-defined types.
 The default meaning of the operators on standard types is given here.
 
 * `+`
-  : Addition and vector/string concatenation.
+  : Addition and array/string concatenation.
     Calls the `add` method on the `std::ops::Add` trait.
 * `-`
   : Subtraction.
@@ -3203,7 +3206,7 @@ for_expr : "for" pat "in" no_struct_literal_expr '{' block '}' ;
 A `for` expression is a syntactic construct for looping over elements
 provided by an implementation of `std::iter::Iterator`.
 
-An example of a for loop over the contents of a vector:
+An example of a for loop over the contents of an array:
 
 ~~~~
 # type Foo = int;
@@ -3261,7 +3264,7 @@ match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
 
 A `match` expression branches on a *pattern*. The exact form of matching that
 occurs depends on the pattern. Patterns consist of some combination of
-literals, destructured vectors or enum constructors, structures and
+literals, destructured arrays or enum constructors, structures and
 tuples, variable binding specifications, wildcards (`..`), and placeholders
 (`_`). A `match` expression has a *head expression*, which is the value to
 compare to the patterns. The type of the patterns must equal the type of the
@@ -3290,11 +3293,11 @@ between `_` and `..` is that the pattern `C(_)` is only type-correct if `C` has
 exactly one argument, while the pattern `C(..)` is type-correct for any enum
 variant `C`, regardless of how many arguments `C` has.
 
-Used inside a vector pattern, `..` stands for any number of elements, when the
+Used inside a array pattern, `..` stands for any number of elements, when the
 `advanced_slice_patterns` feature gate is turned on. This wildcard can be used
-at most once for a given vector, which implies that it cannot be used to
+at most once for a given array, which implies that it cannot be used to
 specifically match elements that are at an unknown distance from both ends of a
-vector, like `[.., 42, ..]`.  If followed by a variable name, it will bind the
+array, like `[.., 42, ..]`.  If followed by a variable name, it will bind the
 corresponding slice to the variable.  Example:
 
 ~~~~
@@ -3427,7 +3430,7 @@ let message = match x {
 ~~~~
 
 Range patterns only work on scalar types
-(like integers and characters; not like vectors and structs, which have sub-components).
+(like integers and characters; not like arrays and structs, which have sub-components).
 A range pattern may not be a sub-range of another range pattern inside the same `match`.
 
 Finally, match patterns can accept *pattern guards* to further refine the
@@ -3535,10 +3538,10 @@ http://www.unicode.org/glossary/#unicode_scalar_value)
 (ie. a code point that is not a surrogate),
 represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF
 or 0xE000 to 0x10FFFF range.
-A `[char]` vector is effectively an UCS-4 / UTF-32 string.
+A `[char]` array is effectively an UCS-4 / UTF-32 string.
 
 A value of type `str` is a Unicode string,
-represented as a vector of 8-bit unsigned bytes holding a sequence of UTF-8 codepoints.
+represented as a array of 8-bit unsigned bytes holding a sequence of UTF-8 codepoints.
 Since `str` is of unknown size, it is not a _first class_ type,
 but can only be instantiated through a pointer type,
 such as `&str` or `String`.
@@ -3649,7 +3652,7 @@ Such recursion has restrictions:
 
 * Recursive types must include a nominal type in the recursion
   (not mere [type definitions](#type-definitions),
-   or other structural types such as [vectors](#vector-types) or [tuples](#tuple-types)).
+   or other structural types such as [arrays](#vector,-array,-and-slice-types) or [tuples](#tuple-types)).
 * A recursive `enum` item must have at least one non-recursive constructor
   (in order to give the recursion a basis case).
 * The size of a recursive type must be finite;
@@ -4153,7 +4156,7 @@ heap data.
 ### Built in types
 
 The runtime provides C and Rust code to assist with various built-in types,
-such as vectors, strings, and the low level communication system (ports,
+such as arrays, strings, and the low level communication system (ports,
 channels, tasks).
 
 Support for other built-in types such as simple types, tuples and
index 62010ca8916d0f686cf5e54f1c44aa79fa0bae97..c7bc1bb973330f87653d7d06c734f97bf90b4d5f 100644 (file)
@@ -12,7 +12,6 @@
 // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
 //                and `nonnull`
 
-use core::ptr::RawPtr;
 #[cfg(not(test))] use core::raw;
 #[cfg(stage0, not(test))] use util;
 
@@ -70,11 +69,6 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
 /// the value returned by `usable_size` for the requested size.
 #[inline]
 pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
-    // FIXME(14395) This is only required for DST ~[T], it should be removed once
-    // we fix that representation to not use null pointers.
-    if ptr.is_null() {
-        return;
-    }
     imp::deallocate(ptr, size, align)
 }
 
index c83b81660d58fb296231cd22d37bb74673c6512b..225fc28cd6d9888b8a2ff022f6e4566a9b4509ee 100644 (file)
@@ -70,6 +70,7 @@
     ("unboxed_closures", Active),
     ("import_shadowing", Active),
     ("advanced_slice_patterns", Active),
+    ("tuple_indexing", Active),
 
     // if you change this list without updating src/doc/rust.md, cmr will be sad
 
@@ -338,6 +339,11 @@ fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
                                   "unboxed closures are a work-in-progress \
                                    feature with known bugs");
             }
+            ast::ExprTupField(..) => {
+                self.gate_feature("tuple_indexing",
+                                  e.span,
+                                  "tuple indexing is experimental");
+            }
             _ => {}
         }
         visit::walk_expr(self, e, ());
index 36db4e422c11d2bc679e490d5102f5e615d7696d..1a59b3603de58b53a8102b6cad6a4bf572ca8060 100644 (file)
@@ -28,6 +28,10 @@ fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
         self.sess.span_note(e.span, "expression");
         visit::walk_expr(self, e, ());
     }
+
+    fn visit_mac(&mut self, macro: &ast::Mac, e: ()) {
+        visit::walk_mac(self, macro, e);
+    }
 }
 
 pub fn run(sess: &Session, krate: &ast::Crate) {
index 721e5f296e2e7b7f218d9de42d96ea1b189c6550..138947e8a873b5cdbf754e24d628f0e4bb711a30 100644 (file)
@@ -1056,6 +1056,7 @@ fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
                 ast::ExprUnary(_, ref x) |
                 ast::ExprCast(ref x, _) |
                 ast::ExprField(ref x, _, _) |
+                ast::ExprTupField(ref x, _, _) |
                 ast::ExprIndex(ref x, _) => {
                     // &X { y: 1 }, X { y: 1 }.y
                     contains_exterior_struct_lit(&**x)
index f4d3678271c0ded7c8d6c26a980f60b9ce947688..5969e7e0c42d5a8a286035d370be9d324e5e04fa 100644 (file)
@@ -807,7 +807,7 @@ pub fn append_loan_path_to_string(&self,
                         out.push_str(token::get_name(fname).get());
                     }
                     mc::PositionalField(idx) => {
-                        out.push_char('#'); // invent a notation here
+                        out.push_char('.');
                         out.push_str(idx.to_string().as_slice());
                     }
                 }
index ec414b858187aae059be33986fa1f50f468abe1f..6e9b27655af79a1b9e4c59f507872f593b1e7169 100644 (file)
@@ -467,7 +467,8 @@ fn expr(&mut self, expr: Gc<ast::Expr>, pred: CFGIndex) -> CFGIndex {
             ast::ExprCast(e, _) |
             ast::ExprUnary(_, e) |
             ast::ExprParen(e) |
-            ast::ExprField(e, _, _) => {
+            ast::ExprField(e, _, _) |
+            ast::ExprTupField(e, _, _) => {
                 self.straightline(expr, pred, [e])
             }
 
index 3c8db8d048076cae439776cbb65957c76a6692da..a9a3d94ded897a0ce2bede4f0738b6260b582725 100644 (file)
@@ -173,6 +173,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
           ExprAddrOf(MutImmutable, _) |
           ExprParen(..) |
           ExprField(..) |
+          ExprTupField(..) |
           ExprIndex(..) |
           ExprTup(..) |
           ExprRepeat(..) |
index 7b00bb4589c71e8983c2aaaea38d992b8d655d44..ca58b4b6e60a40d8f498880c7b4c24d5d48b7e2a 100644 (file)
@@ -106,7 +106,7 @@ fn visit_expr(&mut self, e: &ast::Expr, is_const: bool) {
         }
 
         match e.node {
-            ast::ExprField(..) | ast::ExprVec(..) |
+            ast::ExprField(..) | ast::ExprTupField(..) | ast::ExprVec(..) |
             ast::ExprBlock(..) | ast::ExprTup(..)  => {
                 visit::walk_expr(self, e, is_const);
             }
index 605c90a49c6674a375a6611e3199a819a8e7b4f5..2b4b6756f9f859ce046b06e4084a5461423f2f2f 100644 (file)
@@ -225,6 +225,8 @@ fn classify(&mut self, e: &Expr) -> constness {
 
             ast::ExprField(ref base, _, _) => self.classify(&**base),
 
+            ast::ExprTupField(ref base, _, _) => self.classify(&**base),
+
             ast::ExprIndex(ref base, ref idx) =>
                 join(self.classify(&**base), self.classify(&**idx)),
 
index b7cddd0c23f964876451b05e06c22b815d9070af..f275c818716599a9fee9ad6577c3ed8aea074299 100644 (file)
@@ -145,6 +145,17 @@ fn handle_field_access(&mut self, lhs: &ast::Expr, name: &ast::Ident) {
         }
     }
 
+    fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: uint) {
+        match ty::get(ty::expr_ty_adjusted(self.tcx, lhs)).sty {
+            ty::ty_struct(id, _) => {
+                let fields = ty::lookup_struct_fields(self.tcx, id);
+                let field_id = fields[idx].id;
+                self.live_symbols.insert(field_id.node);
+            },
+            _ => ()
+        }
+    }
+
     fn handle_field_pattern_match(&mut self, lhs: &ast::Pat, pats: &[ast::FieldPat]) {
         let id = match self.tcx.def_map.borrow().get(&lhs.id) {
             &def::DefVariant(_, id, _) => id,
@@ -255,6 +266,9 @@ fn visit_expr(&mut self, expr: &ast::Expr, ctxt: MarkSymbolVisitorContext) {
             ast::ExprField(ref lhs, ref ident, _) => {
                 self.handle_field_access(&**lhs, &ident.node);
             }
+            ast::ExprTupField(ref lhs, idx, _) => {
+                self.handle_tup_field_access(&**lhs, idx.node);
+            }
             _ => ()
         }
 
index 207620b182907b9229985313f9a998bdf3ea29f4..d2362b7e9429b3291801da7dc058878e8ce63275 100644 (file)
@@ -324,6 +324,10 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
                 self.select_from_expr(&**base);
             }
 
+            ast::ExprTupField(ref base, _, _) => {         // base.<n>
+                self.select_from_expr(&**base);
+            }
+
             ast::ExprIndex(ref lhs, ref rhs) => {           // lhs[rhs]
                 if !self.walk_overloaded_operator(expr, &**lhs, [rhs.clone()]) {
                     self.select_from_expr(&**lhs);
index 26aa51b909944cff987fa77254b257d98d59f700..84fc8ff2c38cae28d24d06b6887f1e6afd08c9f9 100644 (file)
@@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
       }
 
       // otherwise, live nodes are not required:
-      ExprIndex(..) | ExprField(..) | ExprVec(..) |
+      ExprIndex(..) | ExprField(..) | ExprTupField(..) | ExprVec(..) |
       ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
       ExprBinary(..) | ExprAddrOf(..) |
       ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
@@ -965,6 +965,10 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
               self.propagate_through_expr(&**e, succ)
           }
 
+          ExprTupField(ref e, _, _) => {
+              self.propagate_through_expr(&**e, succ)
+          }
+
           ExprFnBlock(_, _, ref blk) |
           ExprProc(_, ref blk) |
           ExprUnboxedFn(_, _, _, ref blk) => {
@@ -1271,6 +1275,7 @@ fn propagate_through_lvalue_components(&mut self,
         match expr.node {
             ExprPath(_) => succ,
             ExprField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
+            ExprTupField(ref e, _, _) => self.propagate_through_expr(&**e, succ),
             _ => self.propagate_through_expr(expr, succ)
         }
     }
@@ -1445,7 +1450,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
       // no correctness conditions related to liveness
       ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
       ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
-      ExprVec(..) | ExprTup(..) | ExprBinary(..) |
+      ExprTupField(..) | ExprVec(..) | ExprTup(..) | ExprBinary(..) |
       ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
       ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
       ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
index abed04c8f33acf7cf90f98d4dc151af9521822b2..0d3dd8f91d9672128e5f9dee0b4ec8a821dd6fdf 100644 (file)
@@ -465,6 +465,11 @@ pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt> {
             Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
           }
 
+          ast::ExprTupField(ref base, idx, _) => {
+            let base_cmt = if_ok!(self.cat_expr(&**base));
+            Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
+          }
+
           ast::ExprIndex(ref base, _) => {
             let method_call = typeck::MethodCall::expr(expr.id());
             match self.typer.node_method_ty(method_call) {
@@ -737,6 +742,21 @@ pub fn cat_field<N:ast_node>(&self,
         })
     }
 
+    pub fn cat_tup_field<N:ast_node>(&self,
+                                     node: &N,
+                                     base_cmt: cmt,
+                                     f_idx: uint,
+                                     f_ty: ty::t)
+                                     -> cmt {
+        Rc::new(cmt_ {
+            id: node.id(),
+            span: node.span(),
+            mutbl: base_cmt.mutbl.inherit(),
+            cat: cat_interior(base_cmt, InteriorField(PositionalField(f_idx))),
+            ty: f_ty
+        })
+    }
+
     pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt {
         self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
     }
index 6017444267a4f2b7583962b05c162e0b60ebfab6..cdb7d114af90306c792fd289eea0574c2d46a1bf 100644 (file)
@@ -819,6 +819,14 @@ fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
                     _ => {}
                 }
             }
+            ast::ExprTupField(ref base, idx, _) => {
+                match ty::get(ty::expr_ty_adjusted(self.tcx, &**base)).sty {
+                    ty::ty_struct(id, _) => {
+                        self.check_field(expr.span, id, UnnamedField(idx.node));
+                    }
+                    _ => {}
+                }
+            }
             ast::ExprMethodCall(ident, _, _) => {
                 let method_call = MethodCall::expr(expr.id);
                 match self.tcx.method_map.borrow().find(&method_call) {
index 21bfcfeec70b51603e6f32ab31fb03a7051dfaf0..0db3864a06bb8fefeb48ac74da23014b0670da5e 100644 (file)
@@ -779,6 +779,7 @@ fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor,
                 ast::ExprAddrOf(_, ref subexpr) |
                 ast::ExprUnary(ast::UnDeref, ref subexpr) |
                 ast::ExprField(ref subexpr, _, _) |
+                ast::ExprTupField(ref subexpr, _, _) |
                 ast::ExprIndex(ref subexpr, _) |
                 ast::ExprParen(ref subexpr) => {
                     let subexpr: &'a Gc<Expr> = subexpr; // FIXME(#11586)
index 7c7960e0918f46fb1213cc39b77ddb792258e4d4..7350413643c8da460fb03b10e250c2b47f7fff9b 100644 (file)
@@ -1314,6 +1314,34 @@ fn visit_expr(&mut self, ex: &ast::Expr, e: DxrVisitorEnv) {
                                             "Expected struct type, but not ty_struct"),
                 }
             },
+            ast::ExprTupField(sub_ex, idx, _) => {
+                if generated_code(sub_ex.span) {
+                    return
+                }
+
+                self.visit_expr(&*sub_ex, e);
+
+                let t = ty::expr_ty_adjusted(&self.analysis.ty_cx, &*sub_ex);
+                let t_box = ty::get(t);
+                match t_box.sty {
+                    ty::ty_struct(def_id, _) => {
+                        let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
+                        for (i, f) in fields.iter().enumerate() {
+                            if i == idx.node {
+                                let sub_span = self.span.span_for_last_ident(ex.span);
+                                self.fmt.ref_str(recorder::VarRef,
+                                                 ex.span,
+                                                 sub_span,
+                                                 f.id,
+                                                 e.cur_scope);
+                                break;
+                            }
+                        }
+                    },
+                    _ => self.sess.span_bug(ex.span,
+                                            "Expected struct type, but not ty_struct"),
+                }
+            },
             ast::ExprFnBlock(_, decl, body) => {
                 if generated_code(body.span) {
                     return
index bd5132ea4273660ea8f128ecb07e76b8c1957b5d..8f6a3864b37ea12a1e9af93148faa35692877107 100644 (file)
@@ -440,6 +440,13 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
                   (adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
               })
           }
+          ast::ExprTupField(ref base, idx, _) => {
+              let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
+              let brepr = adt::represent_type(cx, bt);
+              expr::with_field_tys(cx.tcx(), bt, None, |discr, _| {
+                  (adt::const_get_field(cx, &*brepr, bv, discr, idx.node), inlineable)
+              })
+          }
 
           ast::ExprIndex(ref base, ref index) => {
               let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
index b640f9ef5af11dfb5cb6640666de6bd6824e1fc7..e1c7ef4d50f0a45b4791f29cffcb03622664ada9 100644 (file)
@@ -3457,6 +3457,7 @@ fn walk_expr(cx: &CrateContext,
             ast::ExprCast(ref sub_exp, _)     |
             ast::ExprAddrOf(_, ref sub_exp)  |
             ast::ExprField(ref sub_exp, _, _) |
+            ast::ExprTupField(ref sub_exp, _, _) |
             ast::ExprParen(ref sub_exp) =>
                 walk_expr(cx, &**sub_exp, scope_stack, scope_map),
 
index 0421aef45ef9c4617d866f1e1f99c1889ebd62c7..bfcf4a11bc207bdf630d33457a317426dc529cc8 100644 (file)
@@ -62,7 +62,7 @@
 use middle::trans::inline;
 use middle::trans::tvec;
 use middle::trans::type_of;
-use middle::ty::struct_fields;
+use middle::ty::{struct_fields, tup_fields};
 use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe};
 use middle::ty::{AutoPtr};
 use middle::ty;
@@ -412,29 +412,11 @@ fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None));
         let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique");
 
-        if len == 0 {
-            Store(bcx,
-                  C_null(type_of::type_of(bcx.ccx(), unit_ty).ptr_to()),
-                  get_dataptr(bcx, scratch.val));
-        } else {
-            // Box<[(), ..n]> will not allocate, but ~[()] expects an
-            // allocation of n bytes, so we must allocate here (yuck).
-            let llty = type_of::type_of(bcx.ccx(), unit_ty);
-            if llsize_of_alloc(bcx.ccx(), llty) == 0 {
-                let ptr_unit_ty = type_of::type_of(bcx.ccx(), unit_ty).ptr_to();
-                let align = C_uint(bcx.ccx(), 8);
-                let alloc_result = malloc_raw_dyn(bcx, ptr_unit_ty, vec_ty, ll_len, align);
-                bcx = alloc_result.bcx;
-                let base = get_dataptr(bcx, scratch.val);
-                Store(bcx, alloc_result.val, base);
-            } else {
-                let base = get_dataptr(bcx, scratch.val);
-                let base = PointerCast(bcx,
-                                       base,
-                                       type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
-                bcx = lval.store_to(bcx, base);
-            }
-        }
+        let base = get_dataptr(bcx, scratch.val);
+        let base = PointerCast(bcx,
+                               base,
+                               type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
+        bcx = lval.store_to(bcx, base);
 
         Store(bcx, ll_len, get_len(bcx, scratch.val));
         DatumBlock::new(bcx, scratch.to_expr_datum())
@@ -593,6 +575,9 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         ast::ExprField(ref base, ident, _) => {
             trans_rec_field(bcx, &**base, ident.node)
         }
+        ast::ExprTupField(ref base, idx, _) => {
+            trans_rec_tup_field(bcx, &**base, idx.node)
+        }
         ast::ExprIndex(ref base, ref idx) => {
             trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
         }
@@ -666,12 +651,10 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-                               base: &ast::Expr,
-                               field: ast::Ident)
-                               -> DatumBlock<'blk, 'tcx, Expr> {
-    //! Translates `base.field`.
-
+fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                           base: &ast::Expr,
+                           get_idx: |&'blk ty::ctxt<'tcx>, &[ty::field]| -> uint)
+                           -> DatumBlock<'blk, 'tcx, Expr> {
     let mut bcx = bcx;
     let _icx = push_ctxt("trans_rec_field");
 
@@ -679,7 +662,7 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let bare_ty = ty::unopen_type(base_datum.ty);
     let repr = adt::represent_type(bcx.ccx(), bare_ty);
     with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| {
-        let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
+        let ix = get_idx(bcx.tcx(), field_tys);
         let d = base_datum.get_element(
             bcx,
             field_tys[ix].mt.ty,
@@ -697,6 +680,23 @@ fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
         }
     })
+
+}
+
+/// Translates `base.field`.
+fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                               base: &ast::Expr,
+                               field: ast::Ident)
+                               -> DatumBlock<'blk, 'tcx, Expr> {
+    trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys))
+}
+
+/// Translates `base.<idx>`.
+fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+                                   base: &ast::Expr,
+                                   idx: uint)
+                                   -> DatumBlock<'blk, 'tcx, Expr> {
+    trans_field(bcx, base, |_, _| idx)
 }
 
 fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@@ -1238,6 +1238,10 @@ pub fn with_field_tys<R>(tcx: &ty::ctxt,
             op(0, struct_fields(tcx, did, substs).as_slice())
         }
 
+        ty::ty_tup(ref v) => {
+            op(0, tup_fields(v.as_slice()).as_slice())
+        }
+
         ty::ty_enum(_, ref substs) => {
             // We want the *variant* ID here, not the enum ID.
             match node_id_opt {
index 00b9977c7523ce46a47c750bfd5234a4bf47e4c6..c0d19b31cb8ede9d3d1d428f0bfbf04caeef34b2 100644 (file)
@@ -72,14 +72,19 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         };
 
         if should_deallocate {
-            let not_null = IsNotNull(bcx, dataptr);
-            with_cond(bcx, not_null, |bcx| {
-                let llty = type_of::type_of(ccx, unit_ty);
-                let llsize = machine::llsize_of(ccx, llty);
-                let llalign = C_uint(ccx, machine::llalign_of_min(ccx, llty) as uint);
-                let size = Mul(bcx, llsize, get_len(bcx, vptr));
-                glue::trans_exchange_free_dyn(bcx, dataptr, size, llalign)
-            })
+            let llty = type_of::type_of(ccx, unit_ty);
+            let unit_size = llsize_of_alloc(ccx, llty);
+            if unit_size != 0 {
+                let len = get_len(bcx, vptr);
+                let not_empty = ICmp(bcx, llvm::IntNE, len, C_uint(ccx, 0));
+                with_cond(bcx, not_empty, |bcx| {
+                    let llalign = C_uint(ccx, machine::llalign_of_min(ccx, llty) as uint);
+                    let size = Mul(bcx, C_uint(ccx, unit_size as uint), len);
+                    glue::trans_exchange_free_dyn(bcx, dataptr, size, llalign)
+                })
+            } else {
+                bcx
+            }
         } else {
             bcx
         }
index feed76233d68aaf1b2e384e85d1a2d62119c37c1..e196304b82ac39a6b65ae086bbef84e8b480884e 100644 (file)
@@ -1002,7 +1002,8 @@ pub enum type_err {
     terr_float_mismatch(expected_found<ast::FloatTy>),
     terr_traits(expected_found<ast::DefId>),
     terr_builtin_bounds(expected_found<BuiltinBounds>),
-    terr_variadic_mismatch(expected_found<bool>)
+    terr_variadic_mismatch(expected_found<bool>),
+    terr_cyclic_ty,
 }
 
 /// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
@@ -3599,6 +3600,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
 
         ast::ExprUnary(ast::UnDeref, _) |
         ast::ExprField(..) |
+        ast::ExprTupField(..) |
         ast::ExprIndex(..) => {
             LvalueExpr
         }
@@ -3790,6 +3792,7 @@ fn tstore_to_closure(s: &TraitStore) -> String {
     }
 
     match *err {
+        terr_cyclic_ty => "cyclic type of infinite size".to_string(),
         terr_mismatch => "types differ".to_string(),
         terr_fn_style_mismatch(values) => {
             format!("expected {} fn, found {} fn",
@@ -4527,6 +4530,11 @@ pub fn lookup_struct_fields(cx: &ctxt, did: ast::DefId) -> Vec<field_ty> {
     }
 }
 
+pub fn is_tuple_struct(cx: &ctxt, did: ast::DefId) -> bool {
+    let fields = lookup_struct_fields(cx, did);
+    !fields.is_empty() && fields.iter().all(|f| f.name == token::special_names::unnamed_field)
+}
+
 pub fn lookup_struct_field(cx: &ctxt,
                            parent: ast::DefId,
                            field_id: ast::DefId)
@@ -4554,6 +4562,21 @@ pub fn struct_fields(cx: &ctxt, did: ast::DefId, substs: &Substs)
     }).collect()
 }
 
+// Returns a list of fields corresponding to the tuple's items. trans uses
+// this.
+pub fn tup_fields(v: &[t]) -> Vec<field> {
+    v.iter().enumerate().map(|(i, &f)| {
+       field {
+            // FIXME #6993: change type of field to Name and get rid of new()
+            ident: ast::Ident::new(token::intern(i.to_string().as_slice())),
+            mt: mt {
+                ty: f,
+                mutbl: MutImmutable
+            }
+        }
+    }).collect()
+}
+
 pub struct UnboxedClosureUpvar {
     pub def: def::Def,
     pub span: Span,
index 01b5fd6e429eeaec1e675f1c7b5f3774b70c06d2..4f0f6121904a128e5d4011bbfc2f8fc655bb3247 100644 (file)
@@ -2603,6 +2603,16 @@ pub fn lookup_field_ty(tcx: &ty::ctxt,
     o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
 }
 
+pub fn lookup_tup_field_ty(tcx: &ty::ctxt,
+                           class_id: ast::DefId,
+                           items: &[ty::field_ty],
+                           idx: uint,
+                           substs: &subst::Substs) -> Option<ty::t> {
+
+    let o_field = if idx < items.len() { Some(&items[idx]) } else { None };
+    o_field.map(|f| ty::lookup_field_type(tcx, class_id, f.id, substs))
+}
+
 // Controls whether the arguments are automatically referenced. This is useful
 // for overloaded binary and unary operators.
 pub enum DerefArgs {
@@ -3286,6 +3296,68 @@ fn check_field(fcx: &FnCtxt,
         fcx.write_error(expr.id);
     }
 
+    // Check tuple index expressions
+    fn check_tup_field(fcx: &FnCtxt,
+                       expr: &ast::Expr,
+                       lvalue_pref: LvaluePreference,
+                       base: &ast::Expr,
+                       idx: codemap::Spanned<uint>,
+                       _tys: &[ast::P<ast::Ty>]) {
+        let tcx = fcx.ccx.tcx;
+        check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
+        let expr_t = structurally_resolved_type(fcx, expr.span,
+                                                fcx.expr_ty(base));
+        let mut tuple_like = false;
+        // FIXME(eddyb) #12808 Integrate privacy into this auto-deref loop.
+        let (_, autoderefs, field_ty) =
+            autoderef(fcx, expr.span, expr_t, Some(base.id), lvalue_pref, |base_t, _| {
+                match ty::get(base_t).sty {
+                    ty::ty_struct(base_id, ref substs) => {
+                        tuple_like = ty::is_tuple_struct(tcx, base_id);
+                        if tuple_like {
+                            debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t));
+                            let fields = ty::lookup_struct_fields(tcx, base_id);
+                            lookup_tup_field_ty(tcx, base_id, fields.as_slice(),
+                                                idx.node, &(*substs))
+                        } else {
+                            None
+                        }
+                    }
+                    ty::ty_tup(ref v) => {
+                        tuple_like = true;
+                        if idx.node < v.len() { Some(v[idx.node]) } else { None }
+                    }
+                    _ => None
+                }
+            });
+        match field_ty {
+            Some(field_ty) => {
+                fcx.write_ty(expr.id, field_ty);
+                fcx.write_autoderef_adjustment(base.id, autoderefs);
+                return;
+            }
+            None => {}
+        }
+        fcx.type_error_message(
+            expr.span,
+            |actual| {
+                if tuple_like {
+                    format!("attempted out-of-bounds tuple index `{}` on \
+                                    type `{}`",
+                                   idx.node,
+                                   actual)
+                } else {
+                    format!("attempted tuple index `{}` on type `{}`, but the \
+                                     type was not a tuple or tuple struct",
+                                    idx.node,
+                                    actual)
+                }
+            },
+            expr_t, None);
+
+        fcx.write_error(expr.id);
+    }
+
     fn check_struct_or_variant_fields(fcx: &FnCtxt,
                                       struct_ty: ty::t,
                                       span: Span,
@@ -4065,6 +4137,9 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
       ast::ExprField(ref base, ref field, ref tys) => {
         check_field(fcx, expr, lvalue_pref, &**base, field, tys.as_slice());
       }
+      ast::ExprTupField(ref base, idx, ref tys) => {
+        check_tup_field(fcx, expr, lvalue_pref, &**base, idx, tys.as_slice());
+      }
       ast::ExprIndex(ref base, ref idx) => {
           check_expr_with_lvalue_pref(fcx, &**base, lvalue_pref);
           check_expr(fcx, &**idx);
index 66caf10cb408ca59794fcefdf16f144f7a2434cc..17e7aa8ddc34cf3085f870be1aa8d127d635bc6c 100644 (file)
@@ -39,6 +39,7 @@
 use middle::ty::{IntType, UintType};
 use middle::ty::{BuiltinBounds};
 use middle::ty;
+use middle::ty_fold;
 use middle::typeck::infer::equate::Equate;
 use middle::typeck::infer::glb::Glb;
 use middle::typeck::infer::lub::Lub;
@@ -48,7 +49,7 @@
 use middle::typeck::infer::{MiscVariable, TypeTrace};
 use middle::typeck::infer::type_variable::{RelationDir, EqTo,
                                            SubtypeOf, SupertypeOf};
-use middle::ty_fold::{RegionFolder, TypeFoldable};
+use middle::ty_fold::{TypeFoldable};
 use util::ppaux::Repr;
 
 use std::result;
@@ -56,6 +57,7 @@
 use syntax::ast::{Onceness, FnStyle};
 use syntax::ast;
 use syntax::abi;
+use syntax::codemap::Span;
 
 pub trait Combine<'tcx> {
     fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx>;
@@ -637,10 +639,14 @@ pub fn instantiate(&self,
                 Some(t) => t, // ...already instantiated.
                 None => {     // ...not yet instantiated:
                     // Generalize type if necessary.
-                    let generalized_ty = match dir {
-                        EqTo => a_ty,
-                        SupertypeOf | SubtypeOf => self.generalize(a_ty)
-                    };
+                    let generalized_ty = try!(match dir {
+                        EqTo => {
+                            self.generalize(a_ty, b_vid, false)
+                        }
+                        SupertypeOf | SubtypeOf => {
+                            self.generalize(a_ty, b_vid, true)
+                        }
+                    });
                     debug!("instantiate(a_ty={}, dir={}, \
                                         b_vid={}, generalized_ty={})",
                            a_ty.repr(tcx), dir, b_vid.repr(tcx),
@@ -678,15 +684,85 @@ pub fn instantiate(&self,
         Ok(())
     }
 
-    fn generalize(&self, t: ty::t) -> ty::t {
-        // FIXME(#16847): This is non-ideal because we don't give a
-        // very descriptive origin for this region variable.
+    fn generalize(&self,
+                  ty: ty::t,
+                  for_vid: ty::TyVid,
+                  make_region_vars: bool)
+                  -> cres<ty::t>
+    {
+        /*!
+         * Attempts to generalize `ty` for the type variable
+         * `for_vid`.  This checks for cycle -- that is, whether the
+         * type `ty` references `for_vid`. If `make_region_vars` is
+         * true, it will also replace all regions with fresh
+         * variables. Returns `ty_err` in the case of a cycle, `Ok`
+         * otherwise.
+         */
+
+        let mut generalize = Generalizer { infcx: self.infcx,
+                                           span: self.trace.origin.span(),
+                                           for_vid: for_vid,
+                                           make_region_vars: make_region_vars,
+                                           cycle_detected: false };
+        let u = ty.fold_with(&mut generalize);
+        if generalize.cycle_detected {
+            Err(ty::terr_cyclic_ty)
+        } else {
+            Ok(u)
+        }
+    }
+}
 
-        let infcx = self.infcx;
-        let span = self.trace.origin.span();
-        t.fold_with(
-            &mut RegionFolder::regions(
-                self.infcx.tcx,
-                |_| infcx.next_region_var(MiscVariable(span))))
+struct Generalizer<'cx, 'tcx:'cx> {
+    infcx: &'cx InferCtxt<'cx, 'tcx>,
+    span: Span,
+    for_vid: ty::TyVid,
+    make_region_vars: bool,
+    cycle_detected: bool,
+}
+
+impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> {
+    fn tcx(&self) -> &ty::ctxt<'tcx> {
+        self.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, t: ty::t) -> ty::t {
+        // Check to see whether the type we are genealizing references
+        // `vid`. At the same time, also update any type variables to
+        // the values that they are bound to. This is needed to truly
+        // check for cycles, but also just makes things readable.
+        //
+        // (In particular, you could have something like `$0 = Box<$1>`
+        //  where `$1` has already been instantiated with `Box<$0>`)
+        match ty::get(t).sty {
+            ty::ty_infer(ty::TyVar(vid)) => {
+                if vid == self.for_vid {
+                    self.cycle_detected = true;
+                    ty::mk_err()
+                } else {
+                    match self.infcx.type_variables.borrow().probe(vid) {
+                        Some(u) => self.fold_ty(u),
+                        None => t,
+                    }
+                }
+            }
+            _ => {
+                ty_fold::super_fold_ty(self, t)
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+        match r {
+            ty::ReLateBound(..) | ty::ReEarlyBound(..) => r,
+            _ if self.make_region_vars => {
+                // FIXME: This is non-ideal because we don't give a
+                // very descriptive origin for this region variable.
+                self.infcx.next_region_var(MiscVariable(self.span))
+            }
+            _ => r,
+        }
     }
 }
+
+
index 44ee7ba2de6e4beefdfe74e1b4169fe596ab7d05..f917ced08ce9435c94dc59f984417f997c137a9d 100644 (file)
@@ -266,7 +266,6 @@ pub enum fixup_err {
     unresolved_int_ty(IntVid),
     unresolved_float_ty(FloatVid),
     unresolved_ty(TyVid),
-    cyclic_ty(TyVid),
     unresolved_region(RegionVid),
     region_var_bound_by_region_var(RegionVid, RegionVid)
 }
@@ -282,7 +281,6 @@ pub fn fixup_err_to_string(f: fixup_err) -> String {
            the type explicitly".to_string()
       }
       unresolved_ty(_) => "unconstrained type".to_string(),
-      cyclic_ty(_) => "cyclic type of infinite size".to_string(),
       unresolved_region(_) => "unconstrained region".to_string(),
       region_var_bound_by_region_var(r1, r2) => {
         format!("region var {:?} bound by another region var {:?}; \
index dcdae7ed29c8d33a306af5c94a6bb4f3cda26ebf..569206f6754f9917679e64c87b043ee7d060a7e7 100644 (file)
@@ -51,7 +51,7 @@
 use middle::ty::{IntType, UintType};
 use middle::ty;
 use middle::ty_fold;
-use middle::typeck::infer::{cyclic_ty, fixup_err, fres, InferCtxt};
+use middle::typeck::infer::{fixup_err, fres, InferCtxt};
 use middle::typeck::infer::{unresolved_int_ty,unresolved_float_ty,unresolved_ty};
 use syntax::codemap::Span;
 use util::common::indent;
@@ -78,7 +78,6 @@ pub struct ResolveState<'a, 'tcx: 'a> {
     infcx: &'a InferCtxt<'a, 'tcx>,
     modes: uint,
     err: Option<fixup_err>,
-    v_seen: Vec<TyVid> ,
     type_depth: uint,
 }
 
@@ -90,7 +89,6 @@ pub fn resolver<'a, 'tcx>(infcx: &'a InferCtxt<'a, 'tcx>,
         infcx: infcx,
         modes: modes,
         err: None,
-        v_seen: Vec::new(),
         type_depth: 0,
     }
 }
@@ -126,9 +124,7 @@ pub fn resolve_type_chk(&mut self,
         // n.b. This is a hokey mess because the current fold doesn't
         // allow us to pass back errors in any useful way.
 
-        assert!(self.v_seen.is_empty());
-        let rty = indent(|| self.resolve_type(typ) );
-        assert!(self.v_seen.is_empty());
+        let rty = self.resolve_type(typ);
         match self.err {
           None => {
             debug!("Resolved {} to {} (modes={:x})",
@@ -205,33 +201,19 @@ pub fn resolve_region_var(&mut self, rid: RegionVid) -> ty::Region {
     }
 
     pub fn resolve_ty_var(&mut self, vid: TyVid) -> ty::t {
-        if self.v_seen.contains(&vid) {
-            self.err = Some(cyclic_ty(vid));
-            return ty::mk_var(self.infcx.tcx, vid);
-        } else {
-            self.v_seen.push(vid);
-            let tcx = self.infcx.tcx;
-
-            // Nonobvious: prefer the most specific type
-            // (i.e., the lower bound) to the more general
-            // one.  More general types in Rust (e.g., fn())
-            // tend to carry more restrictions or higher
-            // perf. penalties, so it pays to know more.
-
-            let t1 = match self.infcx.type_variables.borrow().probe(vid) {
-                Some(t) => {
-                    self.resolve_type(t)
-                }
-                None => {
-                    if self.should(force_tvar) {
-                        self.err = Some(unresolved_ty(vid));
-                    }
-                    ty::mk_var(tcx, vid)
+        let tcx = self.infcx.tcx;
+        let t1 = match self.infcx.type_variables.borrow().probe(vid) {
+            Some(t) => {
+                self.resolve_type(t)
+            }
+            None => {
+                if self.should(force_tvar) {
+                    self.err = Some(unresolved_ty(vid));
                 }
-            };
-            self.v_seen.pop().unwrap();
-            return t1;
-        }
+                ty::mk_var(tcx, vid)
+            }
+        };
+        return t1;
     }
 
     pub fn resolve_int_var(&mut self, vid: IntVid) -> ty::t {
index 6af19d948e0e8b467c153ae03fb825d3394ae441..8e24fc1ad5bff80de9df5e5a5443f0ddd24bf2b4 100644 (file)
@@ -222,6 +222,7 @@ pub enum SawExprComponent<'a> {
 
         SawExprLoop(Option<token::InternedString>),
         SawExprField(token::InternedString),
+        SawExprTupField(uint),
         SawExprBreak(Option<token::InternedString>),
         SawExprAgain(Option<token::InternedString>),
 
@@ -276,6 +277,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
             ExprAssign(..)           => SawExprAssign,
             ExprAssignOp(op, _, _)   => SawExprAssignOp(op),
             ExprField(_, id, _)      => SawExprField(content(id.node)),
+            ExprTupField(_, id, _)   => SawExprTupField(id.node),
             ExprIndex(..)            => SawExprIndex,
             ExprPath(..)             => SawExprPath,
             ExprAddrOf(m, _)         => SawExprAddrOf(m),
index 68a1c521f1942e3be312a816969d38811a35c75b..4e65082fe3ad23f83b61f47206c71867aff1392a 100644 (file)
@@ -540,6 +540,7 @@ pub enum Expr_ {
     ExprAssign(Gc<Expr>, Gc<Expr>),
     ExprAssignOp(BinOp, Gc<Expr>, Gc<Expr>),
     ExprField(Gc<Expr>, SpannedIdent, Vec<P<Ty>>),
+    ExprTupField(Gc<Expr>, Spanned<uint>, Vec<P<Ty>>),
     ExprIndex(Gc<Expr>, Gc<Expr>),
 
     /// Variable reference, possibly containing `::` and/or
index 64ab0e5cb191f442b448cabd015443baacff3fb6..6bd1fba4b58a390997ce0a08b5ea9cd67bdbc6fe 100644 (file)
@@ -120,6 +120,8 @@ fn expr_binary(&self, sp: Span, op: ast::BinOp,
     fn expr_mut_addr_of(&self, sp: Span, e: Gc<ast::Expr>) -> Gc<ast::Expr>;
     fn expr_field_access(&self, span: Span, expr: Gc<ast::Expr>,
                          ident: ast::Ident) -> Gc<ast::Expr>;
+    fn expr_tup_field_access(&self, sp: Span, expr: Gc<ast::Expr>,
+                             idx: uint) -> Gc<ast::Expr>;
     fn expr_call(&self, span: Span, expr: Gc<ast::Expr>,
                  args: Vec<Gc<ast::Expr>>) -> Gc<ast::Expr>;
     fn expr_call_ident(&self, span: Span, id: ast::Ident,
@@ -605,6 +607,16 @@ fn expr_field_access(&self, sp: Span, expr: Gc<ast::Expr>, ident: ast::Ident) ->
         let id = Spanned { node: ident, span: field_span };
         self.expr(sp, ast::ExprField(expr, id, Vec::new()))
     }
+    fn expr_tup_field_access(&self, sp: Span, expr: Gc<ast::Expr>, idx: uint) -> Gc<ast::Expr> {
+        let field_span = Span {
+            lo: sp.lo - Pos::from_uint(idx.to_string().len()),
+            hi: sp.hi,
+            expn_info: sp.expn_info,
+        };
+
+        let id = Spanned { node: idx, span: field_span };
+        self.expr(sp, ast::ExprTupField(expr, id, Vec::new()))
+    }
     fn expr_addr_of(&self, sp: Span, e: Gc<ast::Expr>) -> Gc<ast::Expr> {
         self.expr(sp, ast::ExprAddrOf(ast::MutImmutable, e))
     }
index 7deabed04b824505eb4c754f9ce60f35f2bffa5b..30b7317fa56f181df008ded97ff8f3e4540deeab 100644 (file)
@@ -134,6 +134,10 @@ fn fold_ident(&mut self, i: Ident) -> Ident {
         noop_fold_ident(i, self)
     }
 
+    fn fold_uint(&mut self, i: uint) -> uint {
+        noop_fold_uint(i, self)
+    }
+
     fn fold_path(&mut self, p: &Path) -> Path {
         noop_fold_path(p, self)
     }
@@ -466,6 +470,10 @@ pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
     i
 }
 
+pub fn noop_fold_uint<T: Folder>(i: uint, _: &mut T) -> uint {
+    i
+}
+
 pub fn noop_fold_path<T: Folder>(p: &Path, fld: &mut T) -> Path {
     ast::Path {
         span: fld.new_span(p.span),
@@ -1180,6 +1188,11 @@ pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
                       respan(id.span, folder.fold_ident(id.node)),
                       tys.iter().map(|&x| folder.fold_ty(x)).collect())
         }
+        ExprTupField(el, id, ref tys) => {
+            ExprTupField(folder.fold_expr(el),
+                      respan(id.span, folder.fold_uint(id.node)),
+                      tys.iter().map(|&x| folder.fold_ty(x)).collect())
+        }
         ExprIndex(el, er) => {
             ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
         }
index 073e88bc4a1b58102c131106897c5b7de78bc847..328bdf883356c9234c28d98f52e3791d7786be0b 100644 (file)
@@ -23,7 +23,7 @@
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
 use ast::{ExprBreak, ExprCall, ExprCast};
-use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
+use ast::{ExprField, ExprTupField, ExprFnBlock, ExprIf, ExprIndex};
 use ast::{ExprLit, ExprLoop, ExprMac};
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
@@ -1937,6 +1937,11 @@ pub fn mk_field(&mut self, expr: Gc<Expr>, ident: ast::SpannedIdent,
         ExprField(expr, ident, tys)
     }
 
+    pub fn mk_tup_field(&mut self, expr: Gc<Expr>, idx: codemap::Spanned<uint>,
+                    tys: Vec<P<Ty>>) -> ast::Expr_ {
+        ExprTupField(expr, idx, tys)
+    }
+
     pub fn mk_assign_op(&mut self, binop: ast::BinOp,
                         lhs: Gc<Expr>, rhs: Gc<Expr>) -> ast::Expr_ {
         ExprAssignOp(binop, lhs, rhs)
@@ -2286,6 +2291,41 @@ pub fn parse_dot_or_call_expr_with(&mut self, e0: Gc<Expr>) -> Gc<Expr> {
                         }
                     }
                   }
+                  token::LIT_INTEGER(n) => {
+                    let index = n.as_str();
+                    let dot = self.last_span.hi;
+                    hi = self.span.hi;
+                    self.bump();
+                    let (_, tys) = if self.eat(&token::MOD_SEP) {
+                        self.expect_lt();
+                        self.parse_generic_values_after_lt()
+                    } else {
+                        (Vec::new(), Vec::new())
+                    };
+
+                    let num = from_str::<uint>(index);
+                    match num {
+                        Some(n) => {
+                            let id = spanned(dot, hi, n);
+                            let field = self.mk_tup_field(e, id, tys);
+                            e = self.mk_expr(lo, hi, field);
+                        }
+                        None => {
+                            let last_span = self.last_span;
+                            self.span_err(last_span, "invalid tuple or tuple struct index");
+                        }
+                    }
+                  }
+                  token::LIT_FLOAT(n) => {
+                    self.bump();
+                    let last_span = self.last_span;
+                    self.span_err(last_span,
+                                  format!("unexpected token: `{}`", n.as_str()).as_slice());
+                    self.span_note(last_span,
+                                   "try parenthesizing the first index; e.g., `(foo.0).1`");
+                    self.abort_if_errors();
+
+                  }
                   _ => self.unexpected()
                 }
                 continue;
index eaeb6aaab8a75134d2cc159eb30e8b023caa6ff3..a4dff45ad359f96f31bf40b58c049e1f9e4e422d 100644 (file)
@@ -1607,6 +1607,18 @@ pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
                     try!(word(&mut self.s, ">"));
                 }
             }
+            ast::ExprTupField(ref expr, id, ref tys) => {
+                try!(self.print_expr(&**expr));
+                try!(word(&mut self.s, "."));
+                try!(self.print_uint(id.node));
+                if tys.len() > 0u {
+                    try!(word(&mut self.s, "::<"));
+                    try!(self.commasep(
+                        Inconsistent, tys.as_slice(),
+                        |s, ty| s.print_type_ref(ty)));
+                    try!(word(&mut self.s, ">"));
+                }
+            }
             ast::ExprIndex(ref expr, ref index) => {
                 try!(self.print_expr(&**expr));
                 try!(word(&mut self.s, "["));
@@ -1738,6 +1750,10 @@ pub fn print_ident(&mut self, ident: ast::Ident) -> IoResult<()> {
         self.ann.post(self, NodeIdent(&ident))
     }
 
+    pub fn print_uint(&mut self, i: uint) -> IoResult<()> {
+        word(&mut self.s, i.to_string().as_slice())
+    }
+
     pub fn print_name(&mut self, name: ast::Name) -> IoResult<()> {
         try!(word(&mut self.s, token::get_name(name).get()));
         self.ann.post(self, NodeName(&name))
index 65e192e8437f3a6e9490b73d7f5401ea698097c3..50b42ea2c0fd90fcd8df36e514ca24318f8b96fe 100644 (file)
@@ -830,6 +830,12 @@ pub fn walk_expr<E: Clone, V: Visitor<E>>(visitor: &mut V, expression: &Expr, en
                 visitor.visit_ty(&**typ, env.clone())
             }
         }
+        ExprTupField(ref subexpression, _, ref types) => {
+            visitor.visit_expr(&**subexpression, env.clone());
+            for typ in types.iter() {
+                visitor.visit_ty(&**typ, env.clone())
+            }
+        }
         ExprIndex(ref main_expression, ref index_expression) => {
             visitor.visit_expr(&**main_expression, env.clone());
             visitor.visit_expr(&**index_expression, env.clone())
diff --git a/src/test/compile-fail/borrow-tuple-fields.rs b/src/test/compile-fail/borrow-tuple-fields.rs
new file mode 100644 (file)
index 0000000..519bad4
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+#![feature(tuple_indexing)]
+
+struct Foo(Box<int>, int);
+
+struct Bar(int, int);
+
+fn main() {
+    let x = (box 1i, 2i);
+    let r = &x.0;
+    let y = x; //~ ERROR cannot move out of `x` because it is borrowed
+
+    let mut x = (1i, 2i);
+    let a = &x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
+
+    let mut x = (1i, 2i);
+    let a = &mut x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
+
+
+    let x = Foo(box 1i, 2i);
+    let r = &x.0;
+    let y = x; //~ ERROR cannot move out of `x` because it is borrowed
+
+    let mut x = Bar(1i, 2i);
+    let a = &x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable because it is also borrowed as
+
+    let mut x = Bar(1i, 2i);
+    let a = &mut x.0;
+    let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
+}
diff --git a/src/test/compile-fail/move-out-of-tuple-field.rs b/src/test/compile-fail/move-out-of-tuple-field.rs
new file mode 100644 (file)
index 0000000..7f55a78
--- /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.
+
+#![feature(tuple_indexing)]
+
+struct Foo(Box<int>);
+
+fn main() {
+    let x = (box 1i,);
+    let y = x.0;
+    let z = x.0; //~ ERROR use of moved value: `x.0`
+
+    let x = Foo(box 1i);
+    let y = x.0;
+    let z = x.0; //~ ERROR use of moved value: `x.0`
+}
diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs
new file mode 100644 (file)
index 0000000..69c012e
--- /dev/null
@@ -0,0 +1,18 @@
+// 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 std::gc::GC;
+
+fn main() {
+    let f;
+    let g;
+    g = f;
+    f = box(GC) g; //~ ERROR cyclic type of infinite size
+}
index a2148c07187e8a9d27d5669912af3daad2946784..a00528616c3e5e3d0f4cdb5ac0edbf83a23bbcb9 100644 (file)
@@ -12,6 +12,6 @@
 use std::gc::GC;
 
 fn main() {
-    let f; //~ ERROR cyclic type of infinite size
-    f = box(GC) f;
+    let f;
+    f = box(GC) f; //~ ERROR cyclic type of infinite size
 }
diff --git a/src/test/compile-fail/tuple-index-not-tuple.rs b/src/test/compile-fail/tuple-index-not-tuple.rs
new file mode 100644 (file)
index 0000000..d4ef0e2
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(tuple_indexing)]
+
+struct Point { x: int, y: int }
+struct Empty;
+
+fn main() {
+    let origin = Point { x: 0, y: 0 };
+    origin.0;
+    //~^ ERROR attempted tuple index `0` on type `Point`, but the type was not
+    Empty.0;
+    //~^ ERROR attempted tuple index `0` on type `Empty`, but the type was not
+}
diff --git a/src/test/compile-fail/tuple-index-out-of-bounds.rs b/src/test/compile-fail/tuple-index-out-of-bounds.rs
new file mode 100644 (file)
index 0000000..d16f950
--- /dev/null
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(tuple_indexing)]
+
+struct Point(int, int);
+
+fn main() {
+    let origin = Point(0, 0);
+    origin.0;
+    origin.1;
+    origin.2;
+    //~^ ERROR attempted out-of-bounds tuple index `2` on type `Point`
+    let tuple = (0i, 0i);
+    tuple.0;
+    tuple.1;
+    tuple.2;
+    //~^ ERROR attempted out-of-bounds tuple index `2` on type `(int,int)`
+}
diff --git a/src/test/run-pass/borrow-tuple-fields.rs b/src/test/run-pass/borrow-tuple-fields.rs
new file mode 100644 (file)
index 0000000..046d76c
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(tuple_indexing)]
+
+struct Foo(int, int);
+
+fn main() {
+    let x = (1i, 2i);
+    let a = &x.0;
+    let b = &x.0;
+    assert_eq!(*a, 1);
+    assert_eq!(*b, 1);
+
+    let mut x = (1i, 2i);
+    {
+        let a = &x.0;
+        let b = &mut x.1;
+        *b = 5;
+        assert_eq!(*a, 1);
+    }
+    assert_eq!(x.0, 1);
+    assert_eq!(x.1, 5);
+
+
+    let x = Foo(1i, 2i);
+    let a = &x.0;
+    let b = &x.0;
+    assert_eq!(*a, 1);
+    assert_eq!(*b, 1);
+
+    let mut x = Foo(1i, 2i);
+    {
+        let a = &x.0;
+        let b = &mut x.1;
+        *b = 5;
+        assert_eq!(*a, 1);
+    }
+    assert_eq!(x.0, 1);
+    assert_eq!(x.1, 5);
+}
index 15544468ae992a7ecdc4cbbce137c92ee54bbfbc..56eb340ef59acc922235790df8b2dc2b5ea882bd 100644 (file)
 pub fn main() {
     assert!(Some(box() ()).is_some());
 
+    let xs: Box<[()]> = box [];
+    assert!(Some(xs).is_some());
+
     struct Foo;
     assert!(Some(box Foo).is_some());
+
+    let ys: Box<[Foo]> = box [];
+    assert!(Some(ys).is_some());
 }
diff --git a/src/test/run-pass/tuple-index-fat-types.rs b/src/test/run-pass/tuple-index-fat-types.rs
new file mode 100644 (file)
index 0000000..fdee1d9
--- /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.
+
+#![feature(tuple_indexing)]
+
+struct Foo<'a>(&'a [int]);
+
+fn main() {
+    let x: &[int] = &[1i, 2, 3];
+    let y = (x,);
+    assert_eq!(y.0, x);
+
+    let x: &[int] = &[1i, 2, 3];
+    let y = Foo(x);
+    assert_eq!(y.0, x);
+}
diff --git a/src/test/run-pass/tuple-index.rs b/src/test/run-pass/tuple-index.rs
new file mode 100644 (file)
index 0000000..107dc40
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+#![feature(tuple_indexing)]
+
+struct Point(int, int);
+
+fn main() {
+    let mut x = Point(3, 2);
+    assert_eq!(x.0, 3);
+    assert_eq!(x.1, 2);
+    x.0 += 5;
+    assert_eq!(x.0, 8);
+    {
+        let ry = &mut x.1;
+        *ry -= 2;
+        x.0 += 3;
+        assert_eq!(x.0, 11);
+    }
+    assert_eq!(x.1, 0);
+
+    let mut x = (3i, 2i);
+    assert_eq!(x.0, 3);
+    assert_eq!(x.1, 2);
+    x.0 += 5;
+    assert_eq!(x.0, 8);
+    {
+        let ry = &mut x.1;
+        *ry -= 2;
+        x.0 += 3;
+        assert_eq!(x.0, 11);
+    }
+    assert_eq!(x.1, 0);
+
+}