Skip to content

Commit

Permalink
Auto merge of #790 - lowr:fix/gat-in-alias-in-alias-eq, r=jackh726
Browse files Browse the repository at this point in the history
Fix projection substitution order considering GATs

When an `AliasEq` goal contains another alias as its self type, we generate the following clause: `<<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T`, with `T` being a new variable. We've been building `<T as Z>::B` by swapping the first argument in the original projection's substitution with `T`, but it's not the self type when the associated type `B` has generic parameters, leading to wrong subgoals.

The added test would yield "No possible solution" in current master.

Also removes `ignore` attribute on a doctest that was added in #778 as GATs hit stable.

Spotted in rust-lang/rust-analyzer#14164.
  • Loading branch information
bors committed Mar 12, 2023
2 parents 808257c + aa036e6 commit e7e15c3
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 8 deletions.
2 changes: 1 addition & 1 deletion book/src/types/rust_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ types. The intention is that, at least when transitioning, rustc would
implement the `Interner` trait and would map from the [`TyKind`][Rustc-TyKind]
enum to chalk's [`TyKind`] on the fly, when `data()` is invoked.

[Rustc-TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
[Rustc-TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html

| rustc type | chalk variant (and some notes) |
| ------------- | ------------------ |
Expand Down
11 changes: 6 additions & 5 deletions chalk-solve/src/clauses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,13 +820,14 @@ fn push_alias_alias_eq_clause<I: Interner>(
// <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
// }
builder.push_binders(binders, |builder, bound_var| {
let (_, trait_args, assoc_args) = builder.db.split_projection(&projection_ty);
let fresh_self_subst = Substitution::from_iter(
interner,
std::iter::once(bound_var.clone().cast(interner)).chain(
projection_ty.substitution.as_slice(interner)[1..]
.iter()
.cloned(),
),
assoc_args
.iter()
.cloned()
.chain(std::iter::once(bound_var.clone().cast(interner)))
.chain(trait_args[1..].iter().cloned()),
);
let fresh_alias = AliasTy::Projection(ProjectionTy {
associated_ty_id: projection_ty.associated_ty_id,
Expand Down
3 changes: 1 addition & 2 deletions chalk-solve/src/rust_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,10 @@ pub struct FnDefDatumBound<I: Interner> {
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
// FIXME: unignore the doctest below when GATs hit stable.
/// A rust intermediate representation (rust_ir) of a Trait Definition. For
/// example, given the following rust code:
///
/// ```ignore
/// ```
/// use std::fmt::Debug;
///
/// trait Foo<T>
Expand Down
24 changes: 24 additions & 0 deletions tests/test/projection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,30 @@ fn normalize_gat_with_higher_ranked_trait_bound() {
}
}

#[test]
fn gat_in_alias_in_alias_eq() {
test! {
program {
trait Foo {
type Rebind<U>: Foo;
}

struct S<T> { }
impl<T> Foo for S<T> {
type Rebind<U> = S<U>;
}
}

goal {
exists<T> {
<<S<u32> as Foo>::Rebind<i32> as Foo>::Rebind<usize>: Foo
}
} yields {
expect![[r#"Unique"#]]
}
}
}

#[test]
fn forall_projection() {
test! {
Expand Down

0 comments on commit e7e15c3

Please sign in to comment.