chalk icon indicating copy to clipboard operation
chalk copied to clipboard

Prefer clauses from the environment

Open flodiebold opened this issue 4 years ago • 5 comments

The following code compiles in rustc:

fn f<T: Into<String>>(u: T) {
    let x = u.into();
    x.as_str();
}

This works even though there are other (blanket) impls that could apply for the into() call. rust-analyzer on the other hand can't resolve the type of x because the T: Into<?> goal is ambiguous. Note that if we have a struct S that impls Into<String> instead of the type parameter T, we get an ambiguity error (see this playground).

This works because rustc eagerly selects clauses from the environment, before looking at other impls. I think the old recursive solver actually handled this, but we removed the code because we didn't have / come up with a test case for it.

(CC rust-analyzer/rust-analyzer#5514)

flodiebold avatar Jul 25 '20 13:07 flodiebold

Yeah, the plan for chalk was to try and push a "more pure" approach, where we would consider it ambiguous, but return "guidance", and leave it up to the rust-analyzer to decide when to apply that guidance.

nikomatsakis avatar Jul 31 '20 14:07 nikomatsakis

I would definitely prefer to try this approach (guidance) before anything else, it's great that we can use rust-analyzer to see how well it works.

nikomatsakis avatar Jul 31 '20 15:07 nikomatsakis

So, would this be something like Guidance::Suggested? And then RA would basically detect when trying to resolve x.as_str that it can't make progress, and apply the suggested guidance?

flodiebold avatar Jul 31 '20 19:07 flodiebold

Hello @nikomatsakis, I've done a little investigation on the interation of Rust Analyzer with Chalk to infer types. But it would be great to have a confirmation if I'm following the right way. Rust Analyzer utilizes the unification via InferenceTable::relate. The method does a quick union via Unifier::relate, then returns RelationResult::goals which later is used in Rust Analyzer. At this point Unifier::relate doesn't utilize Environment, which has the data to infer the type of Into. Is this correct?

ANtlord avatar Jan 13 '23 23:01 ANtlord

@nikomatsakis I disagree with the "more pure"/"guidance" approach. IMHO chalk should try its best to match what ructc would do in this situation. In this case, that would be to eagerly infer that x is a String.

For example, this same principle applies to my use case:

mod some_lib {
    pub fn a_to_b(b_compat: &(impl Into<String> + Clone)) -> impl Into<String> {
        b_compat.clone()
    }
}

fn main() {
    let a = "8";
    let b = some_lib::a_to_b(&a).into(); // this is type String but rust-analyzer says the type is {unknown}
    let c = b.replace("8", "9");
    println!("b = {}, c = {}", b, c);
}

a is correctly inferred, but b and c, which are interpreted as Strings by rustc, are interpreted as {unknown} in chalk.

Geo25rey avatar Aug 28 '23 13:08 Geo25rey