Rollup merge of #100386 - compiler-errors:sized-coinductive-redux, r=lcnr
Make `Sized` coinductive, again A revival of #83647 --- What exactly makes co-induction sound? Better question: are there any unsoundness risks from this? `Sized` can't be implemented by custom `impl` blocks, nor can it be conditionally implemented based on anything other than child fields being `Sized`, right? r? `@nikomatsakis` for whenever he gets back from vacation
This commit is contained in:
commit
76ce198128
@ -2506,6 +2506,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.trait_def(trait_def_id).has_auto_impl
|
||||
}
|
||||
|
||||
pub fn trait_is_coinductive(self, trait_def_id: DefId) -> bool {
|
||||
self.trait_is_auto(trait_def_id) || self.lang_items().sized_trait() == Some(trait_def_id)
|
||||
}
|
||||
|
||||
/// Returns layout of a generator. Layout might be unavailable if the
|
||||
/// generator is tainted by errors.
|
||||
pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> {
|
||||
|
@ -959,7 +959,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
|
||||
let result = match predicate.kind().skip_binder() {
|
||||
ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
|
||||
ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_coinductive(data.def_id()),
|
||||
ty::PredicateKind::WellFormed(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
@ -1,7 +1,4 @@
|
||||
// check-fail
|
||||
// known-bug: #80626
|
||||
|
||||
// This should pass, but it requires `Sized` to be coinductive.
|
||||
// check-pass
|
||||
|
||||
trait Allocator {
|
||||
type Allocated<T>;
|
||||
@ -9,7 +6,7 @@ trait Allocator {
|
||||
|
||||
enum LinkedList<A: Allocator> {
|
||||
Head,
|
||||
Next(A::Allocated<Self>)
|
||||
Next(A::Allocated<Self>),
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,15 +0,0 @@
|
||||
error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized`
|
||||
--> $DIR/issue-80626.rs:12:10
|
||||
|
|
||||
LL | Next(A::Allocated<Self>)
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: required by a bound in `Allocator::Allocated`
|
||||
--> $DIR/issue-80626.rs:7:20
|
||||
|
|
||||
LL | type Allocated<T>;
|
||||
| ^ required by this bound in `Allocator::Allocated`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
@ -1,3 +1,5 @@
|
||||
// check-pass
|
||||
|
||||
trait PointerFamily {
|
||||
type Pointer<T>;
|
||||
}
|
||||
@ -10,11 +12,13 @@ impl PointerFamily for RcFamily {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum Node<T, P: PointerFamily> where P::Pointer<Node<T, P>>: Sized {
|
||||
enum Node<T, P: PointerFamily>
|
||||
where
|
||||
P::Pointer<Node<T, P>>: Sized,
|
||||
{
|
||||
Cons(P::Pointer<Node<T, P>>),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _list: <RcFamily as PointerFamily>::Pointer<Node<i32, RcFamily>>;
|
||||
//~^ ERROR overflow evaluating the requirement `Node<i32, RcFamily>: Sized`
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
error[E0275]: overflow evaluating the requirement `Node<i32, RcFamily>: Sized`
|
||||
--> $DIR/issue-87750.rs:18:16
|
||||
|
|
||||
LL | let _list: <RcFamily as PointerFamily>::Pointer<Node<i32, RcFamily>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
@ -21,6 +21,7 @@ impl<T> Foo for Number<T> {
|
||||
// ```
|
||||
// which it is :)
|
||||
type Item = [T] where [T]: Sized;
|
||||
//~^ ERROR overflow evaluating the requirement `<Number<T> as Foo>::Item == _`
|
||||
}
|
||||
|
||||
struct OnlySized<T> where T: Sized { f: T }
|
||||
@ -40,7 +41,6 @@ impl<T> Bar for T where T: Foo {
|
||||
// can use the bound on `Foo::Item` for this, but that requires
|
||||
// `wf(<T as Foo>::Item)`, which is an invalid cycle.
|
||||
type Assoc = OnlySized<<T as Foo>::Item>;
|
||||
//~^ ERROR overflow evaluating the requirement `<T as Foo>::Item: Sized`
|
||||
}
|
||||
|
||||
fn foo<T: Print>() {
|
||||
|
@ -1,14 +1,8 @@
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
|
||||
--> $DIR/projection-bound-cycle-generic.rs:42:18
|
||||
error[E0275]: overflow evaluating the requirement `<Number<T> as Foo>::Item == _`
|
||||
--> $DIR/projection-bound-cycle-generic.rs:23:5
|
||||
|
|
||||
LL | type Assoc = OnlySized<<T as Foo>::Item>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: required by a bound in `OnlySized`
|
||||
--> $DIR/projection-bound-cycle-generic.rs:26:18
|
||||
|
|
||||
LL | struct OnlySized<T> where T: Sized { f: T }
|
||||
| ^ required by this bound in `OnlySized`
|
||||
LL | type Item = [T] where [T]: Sized;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -24,6 +24,7 @@ impl Foo for Number {
|
||||
// ```
|
||||
// which it is :)
|
||||
type Item = str where str: Sized;
|
||||
//~^ ERROR overflow evaluating the requirement `<Number as Foo>::Item == _`
|
||||
}
|
||||
|
||||
struct OnlySized<T> where T: Sized { f: T }
|
||||
@ -43,7 +44,6 @@ impl<T> Bar for T where T: Foo {
|
||||
// can use the bound on `Foo::Item` for this, but that requires
|
||||
// `wf(<T as Foo>::Item)`, which is an invalid cycle.
|
||||
type Assoc = OnlySized<<T as Foo>::Item>;
|
||||
//~^ ERROR overflow evaluating the requirement `<T as Foo>::Item: Sized`
|
||||
}
|
||||
|
||||
fn foo<T: Print>() {
|
||||
|
@ -1,14 +1,8 @@
|
||||
error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
|
||||
--> $DIR/projection-bound-cycle.rs:45:18
|
||||
error[E0275]: overflow evaluating the requirement `<Number as Foo>::Item == _`
|
||||
--> $DIR/projection-bound-cycle.rs:26:5
|
||||
|
|
||||
LL | type Assoc = OnlySized<<T as Foo>::Item>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: required by a bound in `OnlySized`
|
||||
--> $DIR/projection-bound-cycle.rs:29:18
|
||||
|
|
||||
LL | struct OnlySized<T> where T: Sized { f: T }
|
||||
| ^ required by this bound in `OnlySized`
|
||||
LL | type Item = str where str: Sized;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
14
src/test/ui/sized/coinductive-1-gat.rs
Normal file
14
src/test/ui/sized/coinductive-1-gat.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
struct Node<C: Trait>(C::Assoc::<Self>);
|
||||
|
||||
trait Trait {
|
||||
type Assoc<T>;
|
||||
}
|
||||
|
||||
impl Trait for Vec<()> {
|
||||
type Assoc<T> = Vec<T>;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Node::<Vec<()>>(Vec::new());
|
||||
}
|
14
src/test/ui/sized/coinductive-1.rs
Normal file
14
src/test/ui/sized/coinductive-1.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
struct Node<C: Trait<Self>>(C::Assoc);
|
||||
|
||||
trait Trait<T> {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
impl<T> Trait<T> for Vec<()> {
|
||||
type Assoc = Vec<T>;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Node::<Vec<()>>(Vec::new());
|
||||
}
|
28
src/test/ui/sized/coinductive-2.rs
Normal file
28
src/test/ui/sized/coinductive-2.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// run-pass
|
||||
struct Node<C: CollectionFactory<Self>> {
|
||||
_children: C::Collection,
|
||||
}
|
||||
|
||||
trait CollectionFactory<T> {
|
||||
type Collection;
|
||||
}
|
||||
|
||||
impl<T> CollectionFactory<T> for Vec<()> {
|
||||
type Collection = Vec<T>;
|
||||
}
|
||||
|
||||
trait Collection<T>: Sized {
|
||||
fn push(&mut self, v: T);
|
||||
}
|
||||
|
||||
impl<T> Collection<T> for Vec<T> {
|
||||
fn push(&mut self, v: T) {
|
||||
self.push(v)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Node::<Vec<()>> {
|
||||
_children: Vec::new(),
|
||||
};
|
||||
}
|
10
src/test/ui/sized/recursive-type-1.rs
Normal file
10
src/test/ui/sized/recursive-type-1.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// check-pass
|
||||
trait A { type Assoc; }
|
||||
|
||||
impl A for () {
|
||||
// FIXME: it would be nice for this to at least cause a warning.
|
||||
type Assoc = Foo<()>;
|
||||
}
|
||||
struct Foo<T: A>(T::Assoc);
|
||||
|
||||
fn main() {}
|
13
src/test/ui/sized/recursive-type-2.rs
Normal file
13
src/test/ui/sized/recursive-type-2.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// build-fail
|
||||
//~^ ERROR cycle detected when computing layout of `Foo<()>`
|
||||
|
||||
trait A { type Assoc: ?Sized; }
|
||||
|
||||
impl A for () {
|
||||
type Assoc = Foo<()>;
|
||||
}
|
||||
struct Foo<T: A>(T::Assoc);
|
||||
|
||||
fn main() {
|
||||
let x: Foo<()>;
|
||||
}
|
13
src/test/ui/sized/recursive-type-2.stderr
Normal file
13
src/test/ui/sized/recursive-type-2.stderr
Normal file
@ -0,0 +1,13 @@
|
||||
error[E0391]: cycle detected when computing layout of `Foo<()>`
|
||||
|
|
||||
= note: ...which requires computing layout of `<() as A>::Assoc`...
|
||||
= note: ...which again requires computing layout of `Foo<()>`, completing the cycle
|
||||
note: cycle used when elaborating drops for `main`
|
||||
--> $DIR/recursive-type-2.rs:11:1
|
||||
|
|
||||
LL | fn main() {
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0391`.
|
@ -1,10 +1,12 @@
|
||||
// check-pass
|
||||
|
||||
trait A<Y, N> {
|
||||
type B;
|
||||
}
|
||||
|
||||
type MaybeBox<T> = <T as A<T, Box<T>>>::B;
|
||||
struct P {
|
||||
t: MaybeBox<P>, //~ ERROR: overflow evaluating the requirement `P: Sized`
|
||||
t: MaybeBox<P>,
|
||||
}
|
||||
|
||||
impl<Y, N> A<Y, N> for P {
|
||||
|
@ -1,15 +0,0 @@
|
||||
error[E0275]: overflow evaluating the requirement `P: Sized`
|
||||
--> $DIR/issue-82830.rs:7:8
|
||||
|
|
||||
LL | t: MaybeBox<P>,
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
note: required for `P` to implement `A<P, Box<P>>`
|
||||
--> $DIR/issue-82830.rs:10:12
|
||||
|
|
||||
LL | impl<Y, N> A<Y, N> for P {
|
||||
| ^^^^^^^ ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
Loading…
x
Reference in New Issue
Block a user