Skip to content

lazy param_env normalization causes ambiguity due to different region constraints #265

@lcnr

Description

@lcnr
trait Trait {
    type Assoc<'a>
    where
        Self: 'a;
}

trait Bound<'a> {}
fn impls_bound<'a, T: Bound<'a>>() {}
fn foo<'a, T: 'a>()
where
    T: Trait<Assoc<'a> = T> + Bound<'a>,
    // This env candidate has the additional region constraint: `T: 'a`
    // from normalization, while both candidates constrain `'_` to `'a`.
    T::Assoc<'a>: Bound<'a>,
{
    impls_bound::<'_, T>();
}

affects algar, thanks @adwinwhite for minimizing this issue https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/crater.20triage.20.3A3/near/569445167

This does not affect the following example as there the first candidate has no region constraints, so we simply choose that one

trait Trait {
    type Assoc<'a>
    where
        Self: 'a;
}

trait Bound<'a> {}
fn impls_bound<T: Bound<>() {}
fn foo<'a, T: 'a>()
where
    T: Trait<Assoc<'a> = T> + Bound,
    T::Assoc<'a>: Bound,
{
    impls_bound::<'_, T>();
}

The behavior is implemented in https://github.com/rust-lang/rust/blob/c6936c309add33a7008747866aee081ff5289946/compiler/rustc_next_trait_solver/src/solve/mod.rs#L256-L278

We could prefer candidates over others if they only differ in region constraints and the constraints of one are a strict subset of the others, solving this (and probably a bunch of related) issues.

This is somewhat annoying to implement as we end up unifying regions if they are constrained to be equal, so we can't simply check that all constraits of one candidate are present in the other candidate. Implementing this still doesn't seem too bad.

The other question is whether we want this stronger candidate unification behavior. Slightly unsure about this rn

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions