-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type mismatch in salsa
-generated code
#9990
Comments
salsa
salsa
-generated code
Updated with a self-contained repro, but it's still pretty convoluted. And I could swear I've done this before 😕. |
Thanks for the minimization -- I looked into this a bit and it looks like a Chalk problem where it on the one hand correctly determines that |
I did log with So I wrote it by myself, not sure it reflects ra's vision of the example precisely: #[test]
fn coerce_ra_issue_9990() {
test!(
program {
#[object_safe]
#[lang(sized)]
trait Sized {}
#[object_safe]
#[lang(unsize)]
trait Unsize<T> {}
#[object_safe]
#[lang(coerce_unsized)]
trait CoerceUnsized<T> {}
impl<T, U> CoerceUnsized<&'static U> for &'static T where T: Unsize<U> {}
#[object_safe]
trait Database {}
#[object_safe]
trait QueryGroup
where
Self: Sized,
{
type DynDb: Database + HasQueryGroup<Self>;
}
#[object_safe]
trait HasQueryGroup<G>
where
Self: Database,
G: QueryGroup,
G: Sized,
{ }
#[object_safe]
trait HelloWorld
where
Self: HasQueryGroup<HelloWorldStorage>,
{ }
struct HelloWorldStorage {}
impl QueryGroup for HelloWorldStorage {
type DynDb = dyn HelloWorld + 'static;
}
impl<DB> HelloWorld for DB
where
DB: Database,
DB: HasQueryGroup<HelloWorldStorage>,
DB: Sized,
{ }
}
goal {
exists<T> {
if (FromEnv(T: Database); FromEnv(T: HasQueryGroup<HelloWorldStorage>); FromEnv(T: Sized)) {
&'static T: CoerceUnsized<&'static dyn HelloWorld + 'static>
}
}
} yields {
"Unique; substitution [], lifetime constraints [InEnvironment { environment: Env([]), goal: !1_0: 'static }]"
}
);
} (Note: ra marks all traits This test fails with Hmm, after some playing I'm even more in doubt of it's precision: removing |
Well, that's not really surprising: https://github.com/rust-analyzer/rust-analyzer/blob/ae36af2bd43906ddb1eeff96d76754f012c0a2c7/crates/hir_ty/src/chalk_db.rs#L288-L291 |
I think the example can be simplified further by getting rid of |
simplifiedtest!(
program {
#[upstream]
#[non_enumerable]
#[lang(sized)]
trait Sized {}
#[non_enumerable]
#[object_safe]
trait Database {}
#[non_enumerable]
trait QueryGroup
where
Self: Sized,
{
type DynDb: Database + HasQueryGroup<Self>;
}
#[non_enumerable]
#[object_safe]
trait HasQueryGroup<G>
where
Self: Database,
G: QueryGroup,
G: Sized,
{ }
#[non_enumerable]
#[object_safe]
trait HelloWorld
where
Self: HasQueryGroup<HelloWorldStorage>,
{ }
struct HelloWorldStorage {}
impl QueryGroup for HelloWorldStorage {
type DynDb = dyn HelloWorld + 'static;
}
impl<DB> HelloWorld for DB
where
DB: Database,
DB: HasQueryGroup<HelloWorldStorage>,
DB: Sized,
{ }
}
goal {
exists<T> {
if (FromEnv(T: Database); FromEnv(T: HasQueryGroup<HelloWorldStorage>); FromEnv(T: Sized)) {
T: HelloWorld
}
}
} yields[SolverChoice::slg_default()] { // fails: "Ambiguous; no inference guidance"
"Unique"
} yields[SolverChoice::recursive_default()] { // fails: "Ambiguous; no inference guidance"
"Unique"
}
goal {
exists<T> {
if (FromEnv(T: Database); FromEnv(T: HasQueryGroup<HelloWorldStorage>); FromEnv(T: Sized)) {
T: Database
}
}
} yields[SolverChoice::slg_default()] { // ok
"Unique"
} yields[SolverChoice::recursive_default()] { // fails: "Ambiguous; no inference guidance"
"Unique"
}
goal {
exists<T> {
if (FromEnv(T: Database); FromEnv(T: HasQueryGroup<HelloWorldStorage>); FromEnv(T: Sized)) {
HelloWorldStorage: Sized
}
}
} yields[SolverChoice::slg_default()] { // ok
"Unique"
} yields[SolverChoice::recursive_default()] { // fails: "Ambiguous; no inference guidance"
"Unique"
}
); |
Also the queries differ. Chalk test's query looks like this:
But the RA query uses
Is this query correct? In |
Yes, the test doesn't match the Rust code -- the equivalent of a type parameter You can simplify the Rust version further as well by turning fn __shim(_db: &(dyn HelloWorld + '_)) {} into something like fn __shim<T: HelloWorld>(_db: &T) {} . I think it should still fail, and get rid of the |
Ok, this is closer now: test!(
program {
#[upstream] #[non_enumerable] #[lang(sized)]
trait Sized {}
#[non_enumerable] #[object_safe]
trait Database {}
#[non_enumerable]
trait QueryGroup
where
Self: Sized,
{
type DynDb: Database + HasQueryGroup<Self>;
}
#[non_enumerable] #[object_safe]
trait HasQueryGroup<G>
where
Self: Database,
G: QueryGroup,
G: Sized,
{ }
#[non_enumerable] #[object_safe]
trait HelloWorld
where
Self: HasQueryGroup<HelloWorldStorage>,
{ }
struct HelloWorldStorage {}
impl QueryGroup for HelloWorldStorage {
type DynDb = dyn HelloWorld + 'static;
}
impl<DB> HelloWorld for DB
where
DB: Database,
DB: HasQueryGroup<HelloWorldStorage>,
DB: Sized,
{ }
}
goal {
forall<T> {
if (FromEnv(T: Database); FromEnv(T: HasQueryGroup<HelloWorldStorage>); FromEnv(T: Sized)) {
T: HelloWorld
}
}
} yields[SolverChoice::slg_default()] { // ok
"Unique"
} yields[SolverChoice::recursive_default()] { // fails: "Ambiguous; no inference guidance"
"Unique"
}
); The query lowers to this:
Removing In logs both solvers report cycles but SLG does the job. Do we hit limitations/bug in recursive solver here? As a workaround we could switch to the SLG solver when the recursive failed. |
Ah well, failed obligations from type parameters don't lead to mismatches... |
Bug yes, I don't see any reason why it should be a limitation. I would rather investigate the actual problem than involve the SLG solver, which would just lead to failures in even more obscure cases (and also probably greatly slow down inference). I think the next step would be to report this to the Chalk team so they're aware of it (and maybe someone will look into it). |
CC #8961
The text was updated successfully, but these errors were encountered: