Skip to content

Commit e7e15c3

Browse files
committed
Auto merge of #790 - lowr:fix/gat-in-alias-in-alias-eq, r=jackh726
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.
2 parents 808257c + aa036e6 commit e7e15c3

File tree

4 files changed

+32
-8
lines changed

4 files changed

+32
-8
lines changed

book/src/types/rust_types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ types. The intention is that, at least when transitioning, rustc would
168168
implement the `Interner` trait and would map from the [`TyKind`][Rustc-TyKind]
169169
enum to chalk's [`TyKind`] on the fly, when `data()` is invoked.
170170

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

173173
| rustc type | chalk variant (and some notes) |
174174
| ------------- | ------------------ |

chalk-solve/src/clauses.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -820,13 +820,14 @@ fn push_alias_alias_eq_clause<I: Interner>(
820820
// <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
821821
// }
822822
builder.push_binders(binders, |builder, bound_var| {
823+
let (_, trait_args, assoc_args) = builder.db.split_projection(&projection_ty);
823824
let fresh_self_subst = Substitution::from_iter(
824825
interner,
825-
std::iter::once(bound_var.clone().cast(interner)).chain(
826-
projection_ty.substitution.as_slice(interner)[1..]
827-
.iter()
828-
.cloned(),
829-
),
826+
assoc_args
827+
.iter()
828+
.cloned()
829+
.chain(std::iter::once(bound_var.clone().cast(interner)))
830+
.chain(trait_args[1..].iter().cloned()),
830831
);
831832
let fresh_alias = AliasTy::Projection(ProjectionTy {
832833
associated_ty_id: projection_ty.associated_ty_id,

chalk-solve/src/rust_ir.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,10 @@ pub struct FnDefDatumBound<I: Interner> {
214214
}
215215

216216
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
217-
// FIXME: unignore the doctest below when GATs hit stable.
218217
/// A rust intermediate representation (rust_ir) of a Trait Definition. For
219218
/// example, given the following rust code:
220219
///
221-
/// ```ignore
220+
/// ```
222221
/// use std::fmt::Debug;
223222
///
224223
/// trait Foo<T>

tests/test/projection.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,30 @@ fn normalize_gat_with_higher_ranked_trait_bound() {
609609
}
610610
}
611611

612+
#[test]
613+
fn gat_in_alias_in_alias_eq() {
614+
test! {
615+
program {
616+
trait Foo {
617+
type Rebind<U>: Foo;
618+
}
619+
620+
struct S<T> { }
621+
impl<T> Foo for S<T> {
622+
type Rebind<U> = S<U>;
623+
}
624+
}
625+
626+
goal {
627+
exists<T> {
628+
<<S<u32> as Foo>::Rebind<i32> as Foo>::Rebind<usize>: Foo
629+
}
630+
} yields {
631+
expect![[r#"Unique"#]]
632+
}
633+
}
634+
}
635+
612636
#[test]
613637
fn forall_projection() {
614638
test! {

0 commit comments

Comments
 (0)