Skip to content

Reordering where clauses can change program behavior #41756

Open
@aturon

Description

@aturon

Here's a contrived example:

use std::fmt::Debug;

trait Left<T> {}
trait Right<T> {}

trait Join<U> {
    fn test();
}

// With the reordering,
//   impl<T, U> Join<U> for T where T: Right<U>, T: Left<U>, U: Default + Debug {
// you'll get a different output
impl<T, U> Join<U> for T where T: Left<U>, T: Right<U>, U: Default + Debug {
    fn test() {
        println!("{:?}", U::default())
    }
}

impl<T, U: Default + Debug> Left<U> for T {}
impl<T, U: Default + Debug> Right<U> for T {}

fn try_it<T: Default + Debug>() where T: Left<bool>, T: Right<()> {
    <T as Join<_>>::test()
}

fn main() {
    try_it::<u8>() // the type here is irrelevant
}

In the order given, the output is false. If you swap the order as suggested in the comment, the output is ().

What's happening here is a combination of a few things. The Join impl creates obligations in order of its where clauses, and the solution to each obligation informs inference, which affects future obligations. At the same time, when it comes time to show T: Left<U>, for example, it can be proved either by virtue of the blanket impl or the where clause on try_it. We currently give preference to the where clause, which then drives inference.

The same mechanisms also lead to cases where:

  1. Adding a valid where clause can cause code to stop compiling.
  2. Adding a where clause can change program behavior.

These issues seem fairly fundamental to the where clause preference approach, which is something we likely cannot change backwards compatibly (and there were good reasons for it in the first place). So it's possible that we will just have to live with these consequences. But I wanted to file a bug for posterity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Status

    Rejected/Not lang

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions