Auto merge of #42527 - qnighy:unsized-tuple-coercions, r=arielb1

Unsized tuple coercions

Part of #18469. Fixes #32702.

#37685 and #34451 might also be related.

This PR does the following:

- Introduce explicit `Sized` constraints on tuple initializers, similar to that of record-struct initializers. Not much relevant to the main contribution but I noticed this when making tests for unsized tuple coercions.
- Implement `(.., T): Unsize<(.., U)>` where `T: Unsize<U>`.
- Assume `(.., T)` is MaybeUnsizedUnivariant.
- Modify `src/librustc/ty/util.rs` and `src/librustc_trans/glue.rs` so that tuples and structs are uniformly traversed when translating.
This commit is contained in:
bors 2017-06-29 15:04:31 +00:00
commit 686ec28cea
26 changed files with 707 additions and 19 deletions

View file

@ -0,0 +1,27 @@
# `unsized_tuple_coercion`
The tracking issue for this feature is: [#42877]
[#42877]: https://github.com/rust-lang/rust/issues/42877
------------------------
This is a part of [RFC0401]. According to the RFC, there should be an implementation like this:
```rust
impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {}
```
This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:
```rust
#![feature(unsized_tuple_coercion)]
fn main() {
let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);
let y : &([i32; 3], [i32]) = &x;
assert_eq!(y.1[0], 4);
}
```
[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md

View file

@ -1060,7 +1060,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
err.note("slice and array elements must have `Sized` type");
}
ObligationCauseCode::TupleElem => {
err.note("tuple elements must have `Sized` type");
err.note("only the last element of a tuple may have a dynamically sized type");
}
ObligationCauseCode::ProjectionWf(data) => {
err.note(&format!("required so that the projection `{}` is well-formed",
@ -1097,6 +1097,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
}
ObligationCauseCode::TupleInitializerSized => {
err.note("tuples must have a statically known size to be initialized");
}
ObligationCauseCode::StructInitializerSized => {
err.note("structs must have a statically known size to be initialized");
}

View file

@ -121,6 +121,8 @@ pub enum ObligationCauseCode<'tcx> {
// Various cases where expressions must be sized/copy/etc:
/// L = X implies that L is Sized
AssignmentLhsSized,
/// (x1, .., xn) must be Sized
TupleInitializerSized,
/// S { ... } must be Sized
StructInitializerSized,
/// Type of each variable must be Sized

View file

@ -1651,6 +1651,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
def_id_a == def_id_b
}
// (.., T) -> (.., U).
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
tys_a.len() == tys_b.len()
}
_ => false
};
@ -2591,8 +2596,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let inner_source = field.subst(tcx, substs_a);
let inner_target = field.subst(tcx, substs_b);
// Check that the source structure with the target's
// type parameters is a subtype of the target.
// Check that the source struct with the target's
// unsized parameters is equal to the target.
let params = substs_a.iter().enumerate().map(|(i, &k)| {
if ty_params.contains(i) {
Kind::from(substs_b.type_at(i))
@ -2617,6 +2622,37 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
&[inner_target]));
}
// (.., T) -> (.., U).
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
assert_eq!(tys_a.len(), tys_b.len());
// The last field of the tuple has to exist.
let (a_last, a_mid) = if let Some(x) = tys_a.split_last() {
x
} else {
return Err(Unimplemented);
};
let b_last = tys_b.last().unwrap();
// Check that the source tuple with the target's
// last element is equal to the target.
let new_tuple = tcx.mk_tup(a_mid.iter().chain(Some(b_last)), false);
let InferOk { obligations, .. } =
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(target, new_tuple)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
// Construct the nested T: Unsize<U> predicate.
nested.push(tcx.predicate_for_trait_def(
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
a_last,
&[b_last]));
}
_ => bug!()
};

View file

@ -189,6 +189,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
tcx.lift(&ty).map(super::ObjectCastObligation)
}
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
super::TupleInitializerSized => Some(super::TupleInitializerSized),
super::StructInitializerSized => Some(super::StructInitializerSized),
super::VariableType(id) => Some(super::VariableType(id)),
super::ReturnType(id) => Some(super::ReturnType(id)),
@ -476,6 +477,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::TupleElem |
super::ItemObligation(_) |
super::AssignmentLhsSized |
super::TupleInitializerSized |
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType(_) |
@ -523,6 +525,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::TupleElem |
super::ItemObligation(_) |
super::AssignmentLhsSized |
super::TupleInitializerSized |
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType(_) |

View file

@ -1220,12 +1220,16 @@ impl<'a, 'tcx> Layout {
}
ty::TyTuple(tys, _) => {
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
// See the univariant case below to learn how.
let kind = if tys.len() == 0 {
StructKind::AlwaysSizedUnivariant
} else {
StructKind::MaybeUnsizedUnivariant
};
let st = Struct::new(dl,
&tys.iter().map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
&ReprOptions::default(), kind, ty)?;
Univariant { variant: st, non_zero: false }
}

View file

@ -317,15 +317,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
target: Ty<'tcx>)
-> (Ty<'tcx>, Ty<'tcx>) {
let (mut a, mut b) = (source, target);
while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) {
if a_def != b_def || !a_def.is_struct() {
break;
}
match a_def.struct_variant().fields.last() {
Some(f) => {
a = f.ty(self, a_substs);
b = f.ty(self, b_substs);
}
loop {
match (&a.sty, &b.sty) {
(&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs))
if a_def == b_def && a_def.is_struct() => {
if let Some(f) = a_def.struct_variant().fields.last() {
a = f.ty(self, a_substs);
b = f.ty(self, b_substs);
} else {
break;
}
},
(&TyTuple(a_tys, _), &TyTuple(b_tys, _))
if a_tys.len() == b_tys.len() => {
if let Some(a_last) = a_tys.last() {
a = a_last;
b = b_tys.last().unwrap();
} else {
break;
}
},
_ => break,
}
}

View file

@ -76,7 +76,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
}
assert!(!info.is_null());
match t.sty {
ty::TyAdt(def, substs) => {
ty::TyAdt(..) | ty::TyTuple(..) => {
let ccx = bcx.ccx;
// First get the size of all statically known fields.
// Don't use size_of because it also rounds up to alignment, which we
@ -101,8 +101,14 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
// Recurse to get the size of the dynamically sized field (must be
// the last field).
let last_field = def.struct_variant().fields.last().unwrap();
let field_ty = monomorphize::field_ty(bcx.tcx(), substs, last_field);
let field_ty = match t.sty {
ty::TyAdt(def, substs) => {
let last_field = def.struct_variant().fields.last().unwrap();
monomorphize::field_ty(bcx.tcx(), substs, last_field)
},
ty::TyTuple(tys, _) => tys.last().unwrap(),
_ => unreachable!(),
};
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
// FIXME (#26403, #27023): We should be adding padding

View file

@ -76,6 +76,7 @@ use rustc::ty::relate::RelateResult;
use rustc::ty::subst::Subst;
use errors::DiagnosticBuilder;
use syntax::abi;
use syntax::feature_gate;
use syntax::ptr::P;
use syntax_pos;
@ -520,6 +521,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
coerce_source,
&[coerce_target]));
let mut has_unsized_tuple_coercion = false;
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
// inference might unify those two inner type variables later.
@ -527,7 +530,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
while let Some(obligation) = queue.pop_front() {
debug!("coerce_unsized resolve step: {:?}", obligation);
let trait_ref = match obligation.predicate {
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
if unsize_did == tr.def_id() {
if let ty::TyTuple(..) = tr.0.input_types().nth(1).unwrap().sty {
debug!("coerce_unsized: found unsized tuple coercion");
has_unsized_tuple_coercion = true;
}
}
tr.clone()
}
_ => {
coercion.obligations.push(obligation);
continue;
@ -557,6 +568,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
}
}
if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion {
feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
"unsized_tuple_coercion",
self.cause.span,
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION);
}
Ok(coercion)
}

View file

@ -3854,6 +3854,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if tuple.references_error() {
tcx.types.err
} else {
self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
tuple
}
}

View file

@ -357,6 +357,9 @@ declare_features! (
// Allows a test to fail without failing the whole suite
(active, allow_fail, "1.19.0", Some(42219)),
// Allows unsized tuple coercion.
(active, unsized_tuple_coercion, "1.20.0", Some(42877)),
);
declare_features! (
@ -1041,6 +1044,9 @@ pub const EXPLAIN_VIS_MATCHER: &'static str =
pub const EXPLAIN_PLACEMENT_IN: &'static str =
"placement-in expression syntax is experimental and subject to change.";
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
"Unsized tuple coercion is not stable enough for use and is subject to change";
struct PostExpansionVisitor<'a> {
context: &'a Context<'a>,
}

View file

@ -0,0 +1,50 @@
// 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.
// Forbid assignment into a dynamically sized type.
#![feature(unsized_tuple_coercion)]
type Fat<T: ?Sized> = (isize, &'static str, T);
//~^ WARNING trait bounds are not (yet) enforced
#[derive(PartialEq,Eq)]
struct Bar;
#[derive(PartialEq,Eq)]
struct Bar1 {
f: isize
}
trait ToBar {
fn to_bar(&self) -> Bar;
fn to_val(&self) -> isize;
}
impl ToBar for Bar1 {
fn to_bar(&self) -> Bar {
Bar
}
fn to_val(&self) -> isize {
self.f
}
}
pub fn main() {
// Assignment.
let f5: &mut Fat<ToBar> = &mut (5, "some str", Bar1 {f :42});
let z: Box<ToBar> = Box::new(Bar1 {f: 36});
f5.2 = Bar1 {f: 36};
//~^ ERROR mismatched types
//~| expected type `ToBar`
//~| found type `Bar1`
//~| expected trait ToBar, found struct `Bar1`
//~| ERROR `ToBar: std::marker::Sized` is not satisfied
}

View file

@ -10,6 +10,8 @@
// Attempt to change the type as well as unsizing.
#![feature(unsized_tuple_coercion)]
struct Fat<T: ?Sized> {
ptr: T
}
@ -29,4 +31,16 @@ pub fn main() {
let f2: &Fat<Foo> = &f1;
let f3: &Fat<Bar> = f2;
//~^ ERROR `Foo: Bar` is not satisfied
// Tuple with a vec of isize.
let f1 = ([1, 2, 3],);
let f2: &([isize; 3],) = &f1;
let f3: &([usize],) = f2;
//~^ ERROR mismatched types
// Tuple with a trait.
let f1 = (Foo,);
let f2: &(Foo,) = &f1;
let f3: &(Bar,) = f2;
//~^ ERROR `Foo: Bar` is not satisfied
}

View file

@ -28,4 +28,14 @@ pub fn main() {
let f1 = Fat { ptr: Foo };
let f2: &Fat<Foo> = &f1;
let f3: &mut Fat<Bar> = f2; //~ ERROR mismatched types
// Tuple with a vec of ints.
let f1 = ([1, 2, 3],);
let f2: &([isize; 3],) = &f1;
let f3: &mut ([isize],) = f2; //~ ERROR mismatched types
// Tuple with a trait.
let f1 = (Foo,);
let f2: &(Foo,) = &f1;
let f3: &mut (Bar,) = f2; //~ ERROR mismatched types
}

View file

@ -10,6 +10,8 @@
// Attempt to extend the lifetime as well as unsizing.
#![feature(unsized_tuple_coercion)]
struct Fat<T: ?Sized> {
ptr: T
}
@ -28,6 +30,16 @@ fn baz<'a>() {
let f1 = Fat { ptr: Foo };
let f2: &Fat<Foo> = &f1; //~ ERROR `f1` does not live long enough
let f3: &'a Fat<Bar> = f2;
// Tuple with a vec of ints.
let f1 = ([1, 2, 3],);
let f2: &([isize; 3],) = &f1; //~ ERROR `f1` does not live long enough
let f3: &'a ([isize],) = f2;
// Tuple with a trait.
let f1 = (Foo,);
let f2: &(Foo,) = &f1; //~ ERROR `f1` does not live long enough
let f3: &'a (Bar,) = f2;
}
pub fn main() {

View file

@ -10,6 +10,8 @@
// Attempt to coerce from unsized to sized.
#![feature(unsized_tuple_coercion)]
struct Fat<T: ?Sized> {
ptr: T
}
@ -22,4 +24,12 @@ pub fn main() {
//~| expected type `&Fat<[isize; 3]>`
//~| found type `&Fat<[isize]>`
//~| expected array of 3 elements, found slice
// Tuple with a vec of isizes.
let f1: &([isize],) = &([1, 2, 3],);
let f2: &([isize; 3],) = f1;
//~^ ERROR mismatched types
//~| expected type `&([isize; 3],)`
//~| found type `&([isize],)`
//~| expected array of 3 elements, found slice
}

View file

@ -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.
// Try to initialise a DST struct where the lost information is deeply nested.
// This is an error because it requires an unsized rvalue. This is a problem
// because it would require stack allocation of an unsized temporary (*g in the
// test).
#![feature(unsized_tuple_coercion)]
pub fn main() {
let f: ([isize; 3],) = ([5, 6, 7],);
let g: &([isize],) = &f;
let h: &(([isize],),) = &(*g,);
//~^ ERROR `[isize]: std::marker::Sized` is not satisfied
}

View file

@ -0,0 +1,14 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn main() {
let _ : &(Send,) = &((),);
//~^ ERROR Unsized tuple coercion is not stable enough
}

View file

@ -54,6 +54,7 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) {
fn f10<X: ?Sized>(x1: Box<S<X>>) {
f5(&(32, *x1));
//~^ ERROR `X: std::marker::Sized` is not satisfied
//~| ERROR `X: std::marker::Sized` is not satisfied
}
pub fn main() {

View file

@ -0,0 +1,34 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(unsized_tuple_coercion)]
static mut DROP_RAN: bool = false;
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
unsafe { DROP_RAN = true; }
}
}
trait Trait { fn dummy(&self) { } }
impl Trait for Foo {}
pub fn main() {
{
let _x: Box<(i32, Trait)> = Box::<(i32, Foo)>::new((42, Foo));
}
unsafe {
assert!(DROP_RAN);
}
}

View file

@ -0,0 +1,31 @@
// 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.
// no-prefer-dynamic
#![feature(unsized_tuple_coercion)]
static mut DROP_RAN: isize = 0;
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
unsafe { DROP_RAN += 1; }
}
}
pub fn main() {
{
let _x: Box<(i32, [Foo])> = Box::<(i32, [Foo; 3])>::new((42, [Foo, Foo, Foo]));
}
unsafe {
assert_eq!(DROP_RAN, 3);
}
}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unsized_tuple_coercion)]
struct Test<T: ?Sized>(T);
fn main() {
@ -21,4 +23,14 @@ fn main() {
let slice = &[1,2,3];
let x = Test(&slice);
let Test(&_slice) = x;
let x = (10, [1,2,3]);
let x : &(i32, [i32]) = &x;
let & ref _y = x;
let slice = &[1,2,3];
let x = (10, &slice);
let (_, &_slice) = x;
}

View file

@ -11,6 +11,8 @@
// Test DST raw pointers
#![feature(unsized_tuple_coercion)]
trait Trait {
fn foo(&self) -> isize;
}
@ -45,6 +47,14 @@ pub fn main() {
};
assert_eq!(r, 42);
// raw DST tuple
let p = (A { f: 42 },);
let o: *const (Trait,) = &p;
let r = unsafe {
(&*o).0.foo()
};
assert_eq!(r, 42);
// raw slice
let a: *const [_] = &[1, 2, 3];
unsafe {
@ -72,6 +82,15 @@ pub fn main() {
assert_eq!(len, 3);
}
// raw DST tuple with slice
let c: *const ([_],) = &([1, 2, 3],);
unsafe {
let b = (&*c).0[0];
assert_eq!(b, 1);
let len = (&*c).0.len();
assert_eq!(len, 3);
}
// all of the above with *mut
let mut x = A { f: 42 };
let z: *mut Trait = &mut x;
@ -87,6 +106,13 @@ pub fn main() {
};
assert_eq!(r, 42);
let mut p = (A { f: 42 },);
let o: *mut (Trait,) = &mut p;
let r = unsafe {
(&*o).0.foo()
};
assert_eq!(r, 42);
let a: *mut [_] = &mut [1, 2, 3];
unsafe {
let b = (*a)[2];
@ -110,4 +136,12 @@ pub fn main() {
let len = (&*c).f.len();
assert_eq!(len, 3);
}
let c: *mut ([_],) = &mut ([1, 2, 3],);
unsafe {
let b = (&*c).0[0];
assert_eq!(b, 1);
let len = (&*c).0.len();
assert_eq!(len, 3);
}
}

View file

@ -0,0 +1,111 @@
// 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.
#![allow(unused_features)]
#![feature(box_syntax)]
#![feature(unsized_tuple_coercion)]
type Fat<T: ?Sized> = (isize, &'static str, T);
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Bar;
#[derive(Copy, Clone, PartialEq, Eq)]
struct Bar1 {
f: isize
}
trait ToBar {
fn to_bar(&self) -> Bar;
fn to_val(&self) -> isize;
}
impl ToBar for Bar {
fn to_bar(&self) -> Bar {
*self
}
fn to_val(&self) -> isize {
0
}
}
impl ToBar for Bar1 {
fn to_bar(&self) -> Bar {
Bar
}
fn to_val(&self) -> isize {
self.f
}
}
// x is a fat pointer
fn foo(x: &Fat<ToBar>) {
assert_eq!(x.0, 5);
assert_eq!(x.1, "some str");
assert_eq!(x.2.to_bar(), Bar);
assert_eq!(x.2.to_val(), 42);
let y = &x.2;
assert_eq!(y.to_bar(), Bar);
assert_eq!(y.to_val(), 42);
}
fn bar(x: &ToBar) {
assert_eq!(x.to_bar(), Bar);
assert_eq!(x.to_val(), 42);
}
fn baz(x: &Fat<Fat<ToBar>>) {
assert_eq!(x.0, 5);
assert_eq!(x.1, "some str");
assert_eq!((x.2).0, 8);
assert_eq!((x.2).1, "deep str");
assert_eq!((x.2).2.to_bar(), Bar);
assert_eq!((x.2).2.to_val(), 42);
let y = &(x.2).2;
assert_eq!(y.to_bar(), Bar);
assert_eq!(y.to_val(), 42);
}
pub fn main() {
let f1 = (5, "some str", Bar1 {f :42});
foo(&f1);
let f2 = &f1;
foo(f2);
let f3: &Fat<ToBar> = f2;
foo(f3);
let f4: &Fat<ToBar> = &f1;
foo(f4);
let f5: &Fat<ToBar> = &(5, "some str", Bar1 {f :42});
foo(f5);
// Zero size object.
let f6: &Fat<ToBar> = &(5, "some str", Bar);
assert_eq!(f6.2.to_bar(), Bar);
// &*
//
let f7: Box<ToBar> = Box::new(Bar1 {f :42});
bar(&*f7);
// Deep nesting
let f1 = (5, "some str", (8, "deep str", Bar1 {f :42}));
baz(&f1);
let f2 = &f1;
baz(f2);
let f3: &Fat<Fat<ToBar>> = f2;
baz(f3);
let f4: &Fat<Fat<ToBar>> = &f1;
baz(f4);
let f5: &Fat<Fat<ToBar>> = &(5, "some str", (8, "deep str", Bar1 {f :42}));
baz(f5);
}

View file

@ -0,0 +1,85 @@
// 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.
// As dst-tuple.rs, but the unsized field is the only field in the tuple.
#![feature(unsized_tuple_coercion)]
type Fat<T: ?Sized> = (T,);
// x is a fat pointer
fn foo(x: &Fat<[isize]>) {
let y = &x.0;
assert_eq!(x.0.len(), 3);
assert_eq!(y[0], 1);
assert_eq!(x.0[1], 2);
}
fn foo2<T:ToBar>(x: &Fat<[T]>) {
let y = &x.0;
let bar = Bar;
assert_eq!(x.0.len(), 3);
assert_eq!(y[0].to_bar(), bar);
assert_eq!(x.0[1].to_bar(), bar);
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Bar;
trait ToBar {
fn to_bar(&self) -> Bar;
}
impl ToBar for Bar {
fn to_bar(&self) -> Bar {
*self
}
}
pub fn main() {
// With a vec of ints.
let f1 = ([1, 2, 3],);
foo(&f1);
let f2 = &f1;
foo(f2);
let f3: &Fat<[isize]> = f2;
foo(f3);
let f4: &Fat<[isize]> = &f1;
foo(f4);
let f5: &Fat<[isize]> = &([1, 2, 3],);
foo(f5);
// With a vec of Bars.
let bar = Bar;
let f1 = ([bar, bar, bar],);
foo2(&f1);
let f2 = &f1;
foo2(f2);
let f3: &Fat<[Bar]> = f2;
foo2(f3);
let f4: &Fat<[Bar]> = &f1;
foo2(f4);
let f5: &Fat<[Bar]> = &([bar, bar, bar],);
foo2(f5);
// Assignment.
let f5: &mut Fat<[isize]> = &mut ([1, 2, 3],);
f5.0[1] = 34;
assert_eq!(f5.0[0], 1);
assert_eq!(f5.0[1], 34);
assert_eq!(f5.0[2], 3);
// Zero size vec.
let f5: &Fat<[isize]> = &([],);
assert!(f5.0.is_empty());
let f5: &Fat<[Bar]> = &([],);
assert!(f5.0.is_empty());
}

View file

@ -0,0 +1,129 @@
// 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.
#![allow(unknown_features)]
#![feature(box_syntax)]
#![feature(unsized_tuple_coercion)]
type Fat<T: ?Sized> = (isize, &'static str, T);
// x is a fat pointer
fn foo(x: &Fat<[isize]>) {
let y = &x.2;
assert_eq!(x.2.len(), 3);
assert_eq!(y[0], 1);
assert_eq!(x.2[1], 2);
assert_eq!(x.0, 5);
assert_eq!(x.1, "some str");
}
fn foo2<T:ToBar>(x: &Fat<[T]>) {
let y = &x.2;
let bar = Bar;
assert_eq!(x.2.len(), 3);
assert_eq!(y[0].to_bar(), bar);
assert_eq!(x.2[1].to_bar(), bar);
assert_eq!(x.0, 5);
assert_eq!(x.1, "some str");
}
fn foo3(x: &Fat<Fat<[isize]>>) {
let y = &(x.2).2;
assert_eq!(x.0, 5);
assert_eq!(x.1, "some str");
assert_eq!((x.2).0, 8);
assert_eq!((x.2).1, "deep str");
assert_eq!((x.2).2.len(), 3);
assert_eq!(y[0], 1);
assert_eq!((x.2).2[1], 2);
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Bar;
trait ToBar {
fn to_bar(&self) -> Bar;
}
impl ToBar for Bar {
fn to_bar(&self) -> Bar {
*self
}
}
pub fn main() {
// With a vec of ints.
let f1 = (5, "some str", [1, 2, 3]);
foo(&f1);
let f2 = &f1;
foo(f2);
let f3: &Fat<[isize]> = f2;
foo(f3);
let f4: &Fat<[isize]> = &f1;
foo(f4);
let f5: &Fat<[isize]> = &(5, "some str", [1, 2, 3]);
foo(f5);
// With a vec of Bars.
let bar = Bar;
let f1 = (5, "some str", [bar, bar, bar]);
foo2(&f1);
let f2 = &f1;
foo2(f2);
let f3: &Fat<[Bar]> = f2;
foo2(f3);
let f4: &Fat<[Bar]> = &f1;
foo2(f4);
let f5: &Fat<[Bar]> = &(5, "some str", [bar, bar, bar]);
foo2(f5);
// Assignment.
let f5: &mut Fat<[isize]> = &mut (5, "some str", [1, 2, 3]);
f5.2[1] = 34;
assert_eq!(f5.2[0], 1);
assert_eq!(f5.2[1], 34);
assert_eq!(f5.2[2], 3);
// Zero size vec.
let f5: &Fat<[isize]> = &(5, "some str", []);
assert!(f5.2.is_empty());
let f5: &Fat<[Bar]> = &(5, "some str", []);
assert!(f5.2.is_empty());
// Deeply nested.
let f1 = (5, "some str", (8, "deep str", [1, 2, 3]));
foo3(&f1);
let f2 = &f1;
foo3(f2);
let f3: &Fat<Fat<[isize]>> = f2;
foo3(f3);
let f4: &Fat<Fat<[isize]>> = &f1;
foo3(f4);
let f5: &Fat<Fat<[isize]>> = &(5, "some str", (8, "deep str", [1, 2, 3]));
foo3(f5);
// Box.
let f1 = Box::new([1, 2, 3]);
assert_eq!((*f1)[1], 2);
let f2: Box<[isize]> = f1;
assert_eq!((*f2)[1], 2);
// Nested Box.
let f1 : Box<Fat<[isize; 3]>> = box (5, "some str", [1, 2, 3]);
foo(&*f1);
let f2 : Box<Fat<[isize]>> = f1;
foo(&*f2);
let f3 : Box<Fat<[isize]>> =
Box::<Fat<[_; 3]>>::new((5, "some str", [1, 2, 3]));
foo(&*f3);
}