Skip to content

evaluate: projection obligations are accepted in otherwise coinductive cycles #106040

Open
@lcnr

Description

@lcnr

The following compiles but should not

use std::marker::Unpin;

fn is_unpin<T: Unpin>() {}

trait OtherTrait {
    type Assoc
    where
        Self: Unpin;
}

struct LocalTy;
impl Unpin for LocalTy
where
    Self: OtherTrait<Assoc = LocalTy>,
{}

impl<T> OtherTrait for T {
    type Assoc = T
    where
        Self: Unpin;
}

fn main() {
    is_unpin::<LocalTy>()
}

proving LocalTy: Unpin results in the following cycle:

  • LocalTy: Unpin
    • LocalTy: OtherTrait (trivially true)
    • <LocalTy as OtherTrait>::Assoc = LocalTy
      • LocalTy: Unpin (cycle!)

While it's sound for this cycle to be coinductive, with our current rules it should not be. The new solver will also start out with this being inductive. Fulfill correctly detects this as an inductive cycle. Evaluate does not.

Note that using that is incredibly fragile as it depends on the following performance optimization to avoid fulfill:

if obligation.predicate.is_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if infcx.predicate_must_hold_considering_regions(obligation) {
debug!(
"selecting trait at depth {} evaluated to holds",
obligation.recursion_depth
);
return ProcessResult::Changed(vec![]);
}
}

So the following code does result in the expected error 😁

use std::marker::Unpin;

fn is_unpin<T: Unpin>() {}

trait OtherTrait {
    type Assoc
    where
        Self: Unpin;
}

struct LocalTy<'a>(&'a ());
impl<'a> Unpin for LocalTy<'a>
where
    Self: OtherTrait<Assoc = LocalTy<'a>>,
{}

impl<T> OtherTrait for T {
    type Assoc = T
    where
        Self: Unpin;
}

fn main() {
    is_unpin::<LocalTy<'static>>()
}
error[E0275]: overflow evaluating the requirement `LocalTy<'_>: OtherTrait`
  --> src/main.rs:12:10
   |
12 | impl<'a> Unpin for LocalTy<'a>
   |          ^^^^^
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`test1`)
note: required for `LocalTy<'_>` to implement `Unpin`
  --> src/main.rs:12:10
   |
12 | impl<'a> Unpin for LocalTy<'a>
   |          ^^^^^     ^^^^^^^^^^^
note: required by a bound in `OtherTrait::Assoc`
  --> src/main.rs:8:15
   |
6  |     type Assoc
   |          ----- required by a bound in this
7  |     where
8  |         Self: Unpin;
   |               ^^^^^ required by this bound in `OtherTrait::Assoc`

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.WG-trait-system-refactorThe Rustc Trait System Refactor Initiative (-Znext-solver)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions