Package rustc's mingw dependencies into Windows installer to avoid requiring a separate mingw install.
Closes #11782
# 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
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
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
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
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
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
~~~~
[1i, 2, 3, 4];
["a", "b", "c", "d"];
-[0i, ..128]; // vector with 128 zeros
+[0i, ..128]; // array with 128 zeros
[0u8, 0u8, 0u8, 0u8];
~~~~
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
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.
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;
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
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:
~~~~
~~~~
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
(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`.
* 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;
### 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
// 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;
/// 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)
}
("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
"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, ());
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) {
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)
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());
}
}
ast::ExprCast(e, _) |
ast::ExprUnary(_, e) |
ast::ExprParen(e) |
- ast::ExprField(e, _, _) => {
+ ast::ExprField(e, _, _) |
+ ast::ExprTupField(e, _, _) => {
self.straightline(expr, pred, [e])
}
ExprAddrOf(MutImmutable, _) |
ExprParen(..) |
ExprField(..) |
+ ExprTupField(..) |
ExprIndex(..) |
ExprTup(..) |
ExprRepeat(..) |
}
match e.node {
- ast::ExprField(..) | ast::ExprVec(..) |
+ ast::ExprField(..) | ast::ExprTupField(..) | ast::ExprVec(..) |
ast::ExprBlock(..) | ast::ExprTup(..) => {
visit::walk_expr(self, e, is_const);
}
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)),
}
}
+ 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,
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);
+ }
_ => ()
}
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);
}
// otherwise, live nodes are not required:
- ExprIndex(..) | ExprField(..) | ExprVec(..) |
+ ExprIndex(..) | ExprField(..) | ExprTupField(..) | ExprVec(..) |
ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
ExprBinary(..) | ExprAddrOf(..) |
ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
self.propagate_through_expr(&**e, succ)
}
+ ExprTupField(ref e, _, _) => {
+ self.propagate_through_expr(&**e, succ)
+ }
+
ExprFnBlock(_, _, ref blk) |
ExprProc(_, ref blk) |
ExprUnboxedFn(_, _, _, ref blk) => {
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)
}
}
// 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(..) |
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) {
})
}
+ 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)
}
_ => {}
}
}
+ 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) {
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)
"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
(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);
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),
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;
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())
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))
}
}
}
-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");
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,
}
})
+
+}
+
+/// 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>,
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 {
};
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
}
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>`
ast::ExprUnary(ast::UnDeref, _) |
ast::ExprField(..) |
+ ast::ExprTupField(..) |
ast::ExprIndex(..) => {
LvalueExpr
}
}
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",
}
}
+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)
}).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,
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 {
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,
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);
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;
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;
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>;
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),
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,
+ }
}
}
+
+
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)
}
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 {:?}; \
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;
infcx: &'a InferCtxt<'a, 'tcx>,
modes: uint,
err: Option<fixup_err>,
- v_seen: Vec<TyVid> ,
type_depth: uint,
}
infcx: infcx,
modes: modes,
err: None,
- v_seen: Vec::new(),
type_depth: 0,
}
}
// 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})",
}
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 {
SawExprLoop(Option<token::InternedString>),
SawExprField(token::InternedString),
+ SawExprTupField(uint),
SawExprBreak(Option<token::InternedString>),
SawExprAgain(Option<token::InternedString>),
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),
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
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,
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))
}
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)
}
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),
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))
}
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};
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)
}
}
}
+ 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;
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, "["));
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))
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())
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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`
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::gc::GC;
+
+fn main() {
+ let f;
+ let g;
+ g = f;
+ f = box(GC) g; //~ ERROR cyclic type of infinite size
+}
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
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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)`
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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);
+}
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());
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![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);
+
+}