Skip to content

Commit ab54fa7

Browse files
committed
Add unsized tuple coercions.
1 parent 34241d0 commit ab54fa7

18 files changed

+549
-18
lines changed

src/librustc/traits/error_reporting.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10581058
err.note("slice and array elements must have `Sized` type");
10591059
}
10601060
ObligationCauseCode::TupleElem => {
1061-
err.note("tuple elements must have `Sized` type");
1061+
err.note("only the last element of a tuple may have a dynamically sized type");
10621062
}
10631063
ObligationCauseCode::ProjectionWf(data) => {
10641064
err.note(&format!("required so that the projection `{}` is well-formed",

src/librustc/traits/select.rs

+36
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
16551655
def_id_a == def_id_b
16561656
}
16571657

1658+
// (.., T) -> (.., U).
1659+
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
1660+
tys_a.len() == tys_b.len()
1661+
}
1662+
16581663
_ => false
16591664
};
16601665

@@ -2614,6 +2619,37 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
26142619
&[inner_target]));
26152620
}
26162621

2622+
// (.., T) -> (.., U).
2623+
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
2624+
assert_eq!(tys_a.len(), tys_b.len());
2625+
2626+
// The last field of the tuple has to exist.
2627+
let (a_last, a_mid) = if let Some(x) = tys_a.split_last() {
2628+
x
2629+
} else {
2630+
return Err(Unimplemented);
2631+
};
2632+
let b_last = tys_b.last().unwrap();
2633+
2634+
// Check that the source tuple with the target's
2635+
// last element is a subtype of the target.
2636+
let new_tuple = tcx.mk_tup(a_mid.iter().chain(Some(b_last)), false);
2637+
let InferOk { obligations, .. } =
2638+
self.infcx.at(&obligation.cause, obligation.param_env)
2639+
.eq(target, new_tuple)
2640+
.map_err(|_| Unimplemented)?;
2641+
self.inferred_obligations.extend(obligations);
2642+
2643+
// Construct the nested T: Unsize<U> predicate.
2644+
nested.push(tcx.predicate_for_trait_def(
2645+
obligation.param_env,
2646+
obligation.cause.clone(),
2647+
obligation.predicate.def_id(),
2648+
obligation.recursion_depth + 1,
2649+
a_last,
2650+
&[b_last]));
2651+
}
2652+
26172653
_ => bug!()
26182654
};
26192655

src/librustc/ty/layout.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1220,12 +1220,16 @@ impl<'a, 'tcx> Layout {
12201220
}
12211221

12221222
ty::TyTuple(tys, _) => {
1223-
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
1224-
// See the univariant case below to learn how.
1223+
let kind = if tys.len() == 0 {
1224+
StructKind::AlwaysSizedUnivariant
1225+
} else {
1226+
StructKind::MaybeUnsizedUnivariant
1227+
};
1228+
12251229
let st = Struct::new(dl,
12261230
&tys.iter().map(|ty| ty.layout(tcx, param_env))
12271231
.collect::<Result<Vec<_>, _>>()?,
1228-
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
1232+
&ReprOptions::default(), kind, ty)?;
12291233
Univariant { variant: st, non_zero: false }
12301234
}
12311235

src/librustc/ty/util.rs

+20-9
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
317317
target: Ty<'tcx>)
318318
-> (Ty<'tcx>, Ty<'tcx>) {
319319
let (mut a, mut b) = (source, target);
320-
while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) {
321-
if a_def != b_def || !a_def.is_struct() {
322-
break;
323-
}
324-
match a_def.struct_variant().fields.last() {
325-
Some(f) => {
326-
a = f.ty(self, a_substs);
327-
b = f.ty(self, b_substs);
328-
}
320+
loop {
321+
match (&a.sty, &b.sty) {
322+
(&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs))
323+
if a_def == b_def && a_def.is_struct() => {
324+
if let Some(f) = a_def.struct_variant().fields.last() {
325+
a = f.ty(self, a_substs);
326+
b = f.ty(self, b_substs);
327+
} else {
328+
break;
329+
}
330+
},
331+
(&TyTuple(a_tys, _), &TyTuple(b_tys, _))
332+
if a_tys.len() == b_tys.len() => {
333+
if let Some(a_last) = a_tys.last() {
334+
a = a_last;
335+
b = b_tys.last().unwrap();
336+
} else {
337+
break;
338+
}
339+
},
329340
_ => break,
330341
}
331342
}

src/librustc_trans/glue.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
7676
}
7777
assert!(!info.is_null());
7878
match t.sty {
79-
ty::TyAdt(def, substs) => {
79+
ty::TyAdt(..) | ty::TyTuple(..) => {
8080
let ccx = bcx.ccx;
8181
// First get the size of all statically known fields.
8282
// 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
101101

102102
// Recurse to get the size of the dynamically sized field (must be
103103
// the last field).
104-
let last_field = def.struct_variant().fields.last().unwrap();
105-
let field_ty = monomorphize::field_ty(bcx.tcx(), substs, last_field);
104+
let field_ty = match t.sty {
105+
ty::TyAdt(def, substs) => {
106+
let last_field = def.struct_variant().fields.last().unwrap();
107+
monomorphize::field_ty(bcx.tcx(), substs, last_field)
108+
},
109+
ty::TyTuple(tys, _) => tys.last().unwrap(),
110+
_ => unreachable!(),
111+
};
106112
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
107113

108114
// FIXME (#26403, #27023): We should be adding padding
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Forbid assignment into a dynamically sized type.
12+
13+
type Fat<T: ?Sized> = (isize, &'static str, T);
14+
//~^ WARNING trait bounds are not (yet) enforced
15+
16+
#[derive(PartialEq,Eq)]
17+
struct Bar;
18+
19+
#[derive(PartialEq,Eq)]
20+
struct Bar1 {
21+
f: isize
22+
}
23+
24+
trait ToBar {
25+
fn to_bar(&self) -> Bar;
26+
fn to_val(&self) -> isize;
27+
}
28+
29+
impl ToBar for Bar1 {
30+
fn to_bar(&self) -> Bar {
31+
Bar
32+
}
33+
fn to_val(&self) -> isize {
34+
self.f
35+
}
36+
}
37+
38+
pub fn main() {
39+
// Assignment.
40+
let f5: &mut Fat<ToBar> = &mut (5, "some str", Bar1 {f :42});
41+
let z: Box<ToBar> = Box::new(Bar1 {f: 36});
42+
f5.2 = Bar1 {f: 36};
43+
//~^ ERROR mismatched types
44+
//~| expected type `ToBar`
45+
//~| found type `Bar1`
46+
//~| expected trait ToBar, found struct `Bar1`
47+
//~| ERROR `ToBar: std::marker::Sized` is not satisfied
48+
}

src/test/compile-fail/dst-bad-coerce1.rs

+12
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,16 @@ pub fn main() {
2929
let f2: &Fat<Foo> = &f1;
3030
let f3: &Fat<Bar> = f2;
3131
//~^ ERROR `Foo: Bar` is not satisfied
32+
33+
// Tuple with a vec of isize.
34+
let f1 = ([1, 2, 3],);
35+
let f2: &([isize; 3],) = &f1;
36+
let f3: &([usize],) = f2;
37+
//~^ ERROR mismatched types
38+
39+
// Tuple with a trait.
40+
let f1 = (Foo,);
41+
let f2: &(Foo,) = &f1;
42+
let f3: &(Bar,) = f2;
43+
//~^ ERROR `Foo: Bar` is not satisfied
3244
}

src/test/compile-fail/dst-bad-coerce2.rs

+10
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,14 @@ pub fn main() {
2828
let f1 = Fat { ptr: Foo };
2929
let f2: &Fat<Foo> = &f1;
3030
let f3: &mut Fat<Bar> = f2; //~ ERROR mismatched types
31+
32+
// Tuple with a vec of ints.
33+
let f1 = ([1, 2, 3],);
34+
let f2: &([isize; 3],) = &f1;
35+
let f3: &mut ([isize],) = f2; //~ ERROR mismatched types
36+
37+
// Tuple with a trait.
38+
let f1 = (Foo,);
39+
let f2: &(Foo,) = &f1;
40+
let f3: &mut (Bar,) = f2; //~ ERROR mismatched types
3141
}

src/test/compile-fail/dst-bad-coerce3.rs

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ fn baz<'a>() {
2828
let f1 = Fat { ptr: Foo };
2929
let f2: &Fat<Foo> = &f1; //~ ERROR `f1` does not live long enough
3030
let f3: &'a Fat<Bar> = f2;
31+
32+
// Tuple with a vec of ints.
33+
let f1 = ([1, 2, 3],);
34+
let f2: &([isize; 3],) = &f1; //~ ERROR `f1` does not live long enough
35+
let f3: &'a ([isize],) = f2;
36+
37+
// Tuple with a trait.
38+
let f1 = (Foo,);
39+
let f2: &(Foo,) = &f1; //~ ERROR `f1` does not live long enough
40+
let f3: &'a (Bar,) = f2;
3141
}
3242

3343
pub fn main() {

src/test/compile-fail/dst-bad-coerce4.rs

+8
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,12 @@ pub fn main() {
2222
//~| expected type `&Fat<[isize; 3]>`
2323
//~| found type `&Fat<[isize]>`
2424
//~| expected array of 3 elements, found slice
25+
26+
// Tuple with a vec of isizes.
27+
let f1: &([isize],) = &([1, 2, 3],);
28+
let f2: &([isize; 3],) = f1;
29+
//~^ ERROR mismatched types
30+
//~| expected type `&([isize; 3],)`
31+
//~| found type `&([isize],)`
32+
//~| expected array of 3 elements, found slice
2533
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Try to initialise a DST struct where the lost information is deeply nested.
12+
// This is an error because it requires an unsized rvalue. This is a problem
13+
// because it would require stack allocation of an unsized temporary (*g in the
14+
// test).
15+
16+
pub fn main() {
17+
let f: ([isize; 3],) = ([5, 6, 7],);
18+
let g: &([isize],) = &f;
19+
let h: &(([isize],),) = &(*g,);
20+
//~^ ERROR `[isize]: std::marker::Sized` is not satisfied
21+
}

src/test/run-pass-valgrind/dst-dtor-1.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ struct Fat<T: ?Sized> {
2828

2929
pub fn main() {
3030
{
31-
let _x: Box<Fat<Trait>> = Box::<Fat<Foo>>::new(Fat { f: Foo });
31+
let _x: Box<(i32, Fat<Trait>)> =
32+
Box::<(i32, Fat<Foo>)>::new((42, Fat { f: Foo }));
3233
}
3334
unsafe {
3435
assert!(DROP_RAN);

src/test/run-pass-valgrind/dst-dtor-2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ struct Fat<T: ?Sized> {
2525

2626
pub fn main() {
2727
{
28-
let _x: Box<Fat<[Foo]>> = Box::<Fat<[Foo; 3]>>::new(Fat { f: [Foo, Foo, Foo] });
28+
let _x: Box<(Fat<[Foo]>,)> =
29+
Box::<(Fat<[Foo; 3]>,)>::new((Fat { f: [Foo, Foo, Foo] },));
2930
}
3031
unsafe {
3132
assert_eq!(DROP_RAN, 3);

src/test/run-pass/dst-irrefutable-bind.rs

+10
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,14 @@ fn main() {
2121
let slice = &[1,2,3];
2222
let x = Test(&slice);
2323
let Test(&_slice) = x;
24+
25+
26+
let x = (10, [1,2,3]);
27+
let x : &(i32, [i32]) = &x;
28+
29+
let & ref _y = x;
30+
31+
let slice = &[1,2,3];
32+
let x = (10, &slice);
33+
let (_, &_slice) = x;
2434
}

src/test/run-pass/dst-raw.rs

+32
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ pub fn main() {
4545
};
4646
assert_eq!(r, 42);
4747

48+
// raw DST tuple
49+
let p = (A { f: 42 },);
50+
let o: *const (Trait,) = &p;
51+
let r = unsafe {
52+
(&*o).0.foo()
53+
};
54+
assert_eq!(r, 42);
55+
4856
// raw slice
4957
let a: *const [_] = &[1, 2, 3];
5058
unsafe {
@@ -72,6 +80,15 @@ pub fn main() {
7280
assert_eq!(len, 3);
7381
}
7482

83+
// raw DST tuple with slice
84+
let c: *const ([_],) = &([1, 2, 3],);
85+
unsafe {
86+
let b = (&*c).0[0];
87+
assert_eq!(b, 1);
88+
let len = (&*c).0.len();
89+
assert_eq!(len, 3);
90+
}
91+
7592
// all of the above with *mut
7693
let mut x = A { f: 42 };
7794
let z: *mut Trait = &mut x;
@@ -87,6 +104,13 @@ pub fn main() {
87104
};
88105
assert_eq!(r, 42);
89106

107+
let mut p = (A { f: 42 },);
108+
let o: *mut (Trait,) = &mut p;
109+
let r = unsafe {
110+
(&*o).0.foo()
111+
};
112+
assert_eq!(r, 42);
113+
90114
let a: *mut [_] = &mut [1, 2, 3];
91115
unsafe {
92116
let b = (*a)[2];
@@ -110,4 +134,12 @@ pub fn main() {
110134
let len = (&*c).f.len();
111135
assert_eq!(len, 3);
112136
}
137+
138+
let c: *mut ([_],) = &mut ([1, 2, 3],);
139+
unsafe {
140+
let b = (&*c).0[0];
141+
assert_eq!(b, 1);
142+
let len = (&*c).0.len();
143+
assert_eq!(len, 3);
144+
}
113145
}

0 commit comments

Comments
 (0)