/// 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) {
.collect();
match tys.len() {
+ _ if tys.references_error() => tcx.types.err,
0 => tcx.types.bool,
1 => tys[0],
_ => tcx.mk_tup(tys)
tcx.types.bool
}
- TyStr | TyTrait(..) | TySlice(_) => {
+ TyStr | TyTrait(..) | TySlice(_) | TyError => {
// these are never sized - return the target type
ty
}
}
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
}
}
- TyInfer(..) | TyError => {
+ TyInfer(..) => {
bug!("unexpected type `{:?}` in sized_constraint_for_ty",
ty)
}
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>>)
{
// 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) {} }
--- /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.
+
+// 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>();
+}