diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2016-04-16 15:16:36 +0300 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2016-05-03 18:30:10 +0300 |
| commit | 4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0 (patch) | |
| tree | 253a373c13cf5275d1c22d3b002b7f9649c32b6f | |
| parent | 73f39a026a5a4e7ac37eb4f4840a9cf25ac5d0a5 (diff) | |
| download | rust-4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0.tar.gz rust-4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0.zip | |
add comments and tests
| -rw-r--r-- | src/librustc/ty/mod.rs | 38 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-17431-2.rs | 1 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-26548.rs | 3 | ||||
| -rw-r--r-- | src/test/compile-fail/range-1.rs | 1 | ||||
| -rw-r--r-- | src/test/compile-fail/sized-cycle-note.rs | 7 | ||||
| -rw-r--r-- | src/test/run-pass/issue-31299.rs | 36 |
6 files changed, 73 insertions, 13 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index b3ca120bd9f..d2b7354abb9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1721,6 +1721,17 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> { /// Returns a simpler type such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. + /// + /// This is generally the `struct_tail` if this is a struct, or a + /// tuple of them if this is an enum. + /// + /// Oddly enough, checking that the sized-constraint is Sized is + /// actually more expressive than checking all members: + /// the Sized trait is inductive, so an associated type that references + /// Self would prevent its containing ADT from being Sized. + /// + /// Due to normalization being eager, this applies even if + /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> { let dep_node = DepNode::SizedConstraint(self.did); match self.sized_constraint.get(dep_node) { @@ -1749,6 +1760,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { .collect(); match tys.len() { + _ if tys.references_error() => tcx.types.err, 0 => tcx.types.bool, 1 => tys[0], _ => tcx.mk_tup(tys) @@ -1768,7 +1780,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { tcx.types.bool } - TyStr | TyTrait(..) | TySlice(_) => { + TyStr | TyTrait(..) | TySlice(_) | TyError => { // these are never sized - return the target type ty } @@ -1797,6 +1809,10 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { } TyParam(..) => { + // perf hack: if there is a `T: Sized` bound, then + // we know that `T` is Sized and do not need to check + // it on the impl. + let sized_trait = match tcx.lang_items.sized_trait() { Some(x) => x, _ => return ty @@ -1815,7 +1831,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { } } - TyInfer(..) | TyError => { + TyInfer(..) => { bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty) } @@ -1824,9 +1840,21 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> { result } - /// Calculates the Sized-constraint. This replaces all always-Sized - /// types with bool. I could have made the TyIVar an Option, but that - /// would have been so much code. + /// Calculates the Sized-constraint. + /// + /// As the Sized-constraint of enums can be a *set* of types, + /// the Sized-constraint may need to be a set also. Because introducing + /// a new type of IVar is currently a complex affair, the Sized-constraint + /// may be a tuple. + /// + /// In fact, there are only a few options for the constraint: + /// - `bool`, if the type is always Sized + /// - an obviously-unsized type + /// - a type parameter or projection whose Sizedness can't be known + /// - a tuple of type parameters or projections, if there are multiple + /// such. + /// - a TyError, if a type contained itself. The representability + /// check should catch this case. fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>, stack: &mut Vec<AdtDefMaster<'tcx>>) { diff --git a/src/test/compile-fail/issue-17431-2.rs b/src/test/compile-fail/issue-17431-2.rs index edbc8c82432..f39fb0e31c6 100644 --- a/src/test/compile-fail/issue-17431-2.rs +++ b/src/test/compile-fail/issue-17431-2.rs @@ -9,6 +9,7 @@ // except according to those terms. struct Baz { q: Option<Foo> } +//~^ ERROR recursive type `Baz` has infinite size struct Foo { q: Option<Baz> } //~^ ERROR recursive type `Foo` has infinite size diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index 28080ae09e5..2919b0b3cac 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// error-pattern: overflow representing the type `S` + trait Mirror { type It: ?Sized; } impl<T: ?Sized> Mirror for T { type It = Self; } struct S(Option<<S as Mirror>::It>); -//~^ ERROR recursive type `S` has infinite size fn main() { let _s = S(None); diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs index 895d2450cfe..2a0773af73b 100644 --- a/src/test/compile-fail/range-1.rs +++ b/src/test/compile-fail/range-1.rs @@ -23,5 +23,4 @@ pub fn main() { let arr: &[_] = &[1, 2, 3]; let range = *arr..; //~^ ERROR `[_]: std::marker::Sized` is not satisfied - //~| ERROR `[_]: std::marker::Sized` is not satisfied } diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs index 3d7c4868e96..712b4ac22f0 100644 --- a/src/test/compile-fail/sized-cycle-note.rs +++ b/src/test/compile-fail/sized-cycle-note.rs @@ -17,14 +17,9 @@ // 2. it should elaborate the steps that led to the cycle. struct Baz { q: Option<Foo> } - +//~^ ERROR recursive type `Baz` has infinite size struct Foo { q: Option<Baz> } //~^ ERROR recursive type `Foo` has infinite size -//~| NOTE type `Foo` is embedded within `std::option::Option<Foo>`... -//~| NOTE ...which in turn is embedded within `std::option::Option<Foo>`... -//~| NOTE ...which in turn is embedded within `Baz`... -//~| NOTE ...which in turn is embedded within `std::option::Option<Baz>`... -//~| NOTE ...which in turn is embedded within `Foo`, completing the cycle. impl Foo { fn bar(&self) {} } diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs new file mode 100644 index 00000000000..e49e13c458f --- /dev/null +++ b/src/test/run-pass/issue-31299.rs @@ -0,0 +1,36 @@ +// 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. + +// Regression test for #31299. This was generating an overflow error +// because of eager normalization: +// +// proving `M: Sized` requires +// - proving `PtrBack<Vec<M>>: Sized` requis +// - normalizing `Vec<<Vec<M> as Front>::Back>>: Sized` requires +// - proving `Vec<M>: Front` requires +// - `M: Sized` <-- cycle! +// +// If we skip the normalization step, though, everything goes fine. + +trait Front { + type Back; +} + +impl<T> Front for Vec<T> { + type Back = Vec<T>; +} + +struct PtrBack<T: Front>(Vec<T::Back>); + +struct M(PtrBack<Vec<M>>); + +fn main() { + std::mem::size_of::<M>(); +} |
