Skip to content

Refactor AliasTy & AliasTerm to use Alias#156538

Open
Jamesbarford wants to merge 3 commits into
rust-lang:mainfrom
Jamesbarford:chore/merge-AliasTy-AliasTerm
Open

Refactor AliasTy & AliasTerm to use Alias#156538
Jamesbarford wants to merge 3 commits into
rust-lang:mainfrom
Jamesbarford:chore/merge-AliasTy-AliasTerm

Conversation

@Jamesbarford

Copy link
Copy Markdown
Contributor

Refactors AliasTy & AliasTerm to use Alias. To move around errors I had to manually implement Lift, TypeVisitable and TypeFoldable

Part of #156181

r? @lcnr

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) labels May 13, 2026
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Jamesbarford Jamesbarford force-pushed the chore/merge-AliasTy-AliasTerm branch from a630681 to 89cd50d Compare May 13, 2026 12:56
@lcnr

lcnr commented May 13, 2026

Copy link
Copy Markdown
Contributor

can you say more about the errors you had to work around? this feels odd to me and something we should fix in the derives instead of requiring manual impls here imo

Comment thread compiler/rustc_type_ir/src/ty_kind.rs Outdated
)]
pub struct AliasTy<I: Interner> {
/// The parameters of the associated or opaque type.
pub struct Alias<I: Interner, K> {

@lcnr lcnr May 13, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move Alias and AliasTerm in a separate rustc_type_ir/ty/alias module?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

667b095 👍, Only moved Alias & AliasTerm, not AliasTy

Comment thread compiler/rustc_type_ir/src/predicate.rs Outdated
@Jamesbarford

Jamesbarford commented May 13, 2026

Copy link
Copy Markdown
Contributor Author

Edit: I've been experimenting and think I've expanded Lift_Generic to be able to handle more use cases so I've collapsed my original message as it is a wall of text. But does contextualise what Lift_Generic can now do for us.

Original Message

I've whittled it down to only a manual Lift implementation for Alias as below.

(comments omitted for brevity)

#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner, K)]
#[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
    feature = "nightly",
    derive(Decodable_NoContext, Encodable_NoContext, StableHash_NoContext)
)]
pub struct Alias<I: Interner, K> {
    pub args: I::GenericArgs,

    pub kind: K,

    #[derive_where(skip(Debug))]
    #[type_visitable(ignore)]
    #[type_foldable(identity)]
    pub(crate) _use_alias_new_instead: (),
}

I get 2000+ errors of which fall into the following;

error[E0308]: mismatched types
error[E0521]: borrowed data escapes outside of associated function
error[E0521]: borrowed data escapes outside of function
error[E0521]: borrowed data escapes outside of method

A sample of errors being;

error[E0521]: borrowed data escapes outside of method
   --> compiler/rustc_middle/src/ty/trait_def.rs:229:13
    |
181 | impl<'tcx> TyCtxt<'tcx> {
    |      ---- lifetime `'tcx` defined here
...
223 |         self,
    |         ---- `self` is a reference that is only valid in the method body
...
229 |             fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |             |
    |             `self` escapes the method body here
    |             argument requires that `'tcx` must outlive `'static`
    |
    = note: requirement occurs because of the type `context::TyCtxt<'_>`, which makes the generic argument `'_` invariant
    = note: the struct `context::TyCtxt<'tcx>` is invariant over the parameter `'tcx`
    = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
note: due to a current limitation of the type system, this implies a `'static` lifetime
   --> compiler/rustc_middle/src/ty/print/mod.rs:416:15
    |
416 |     T: Copy + for<'a, 'tcx> Lift<TyCtxt<'tcx>, Lifted: Print<FmtPrinter<'a, 'tcx>>>,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

...

error[E0308]: mismatched types
   --> compiler/rustc_middle/src/ty/trait_def.rs:229:13
    |
229 |             fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
    = note: expected enum `rustc_type_ir::AliasTyKind<context::TyCtxt<'tcx>>`
               found enum `rustc_type_ir::AliasTyKind<context::TyCtxt<'_>>`
note: the lifetime requirement is introduced here
   --> compiler/rustc_type_ir/src/interner.rs:25:7
    |
 25 |     + IrPrint<ty::AliasTy<Self>>
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: implementation of `Interner` is not general enough
   --> compiler/rustc_middle/src/ty/trait_def.rs:229:13
    |
229 |             fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Interner` is not general enough
    |
    = note: `Interner` would have to be implemented for the type `context::TyCtxt<'tcx>`
    = note: ...but `Interner` is actually implemented for the type `context::TyCtxt<'0>`, for some specific lifetime `'0`


...pub struct Placeholder

error[E0308]: mismatched types
   --> compiler/rustc_middle/src/ty/trait_def.rs:229:13
    |
229 |             fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
    |
    = note: expected enum `rustc_type_ir::AliasTermKind<context::TyCtxt<'tcx>>`
               found enum `rustc_type_ir::AliasTermKind<context::TyCtxt<'_>>`
note: the lifetime requirement is introduced here
   --> compiler/rustc_type_ir/src/interner.rs:33:7
    |
 33 |     + IrPrint<ty::NormalizesTo<Self>>
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

...

error[E0308]: mismatched types
   --> compiler/rustc_middle/src/ty/relate.rs:55:12
    |
 55 | impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
    |            ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected enum `rustc_type_ir::AliasTermKind<context::TyCtxt<'tcx>>`
               found enum `rustc_type_ir::AliasTermKind<context::TyCtxt<'tcx>>`
note: the required lifetime does not necessarily outlive the lifetime `'tcx` as defined here
   --> compiler/rustc_middle/src/ty/relate.rs:55:6
    |
 55 | impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
    |      ^^^^
note: the lifetime requirement is introduced here
   --> compiler/rustc_type_ir/src/relate.rs:116:21
    |
116 | pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy {
    |                     ^^^^^^^^

And so on... This was similar to pub struct Placeholder<I: Interner, T> where I think the the generic parameter T required manually implementing Lift. Though this is a superficial understanding

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Jamesbarford Jamesbarford force-pushed the chore/merge-AliasTy-AliasTerm branch from 667b095 to b7965ca Compare May 21, 2026 08:30
@rustbot

This comment has been minimized.

@Jamesbarford

Jamesbarford commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

The latest commits expand Lift_Generic to be able to handle:

pub struct Binder<I: Interner, T> {
    //
}

and then

pub struct Binder<I: Interner, T = SomeKind<I>> {
    //
}

e83546d, fbf009a Not sure if these would be best in a separate PR that also clean up binder.rs then this PR can be solely focused on Alias refactoring?

Which I then used to clean up pub struct Binder {} which is out of scope for these changes but was satisfying to remove a FIXME: e2ba945

I can't get Eq to work for Alias, error bellow;

Eq Error
error[E0277]: the trait bound `AliasTyKind<rustc_middle::ty::TyCtxt<'tcx>>: std::cmp::Eq` is not satisfied
   --> compiler/rustc_infer/src/infer/region_constraints/mod.rs:191:11
    |
187 | #[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
    |                                  -- in this derive macro expansion
...
191 |     Alias(ty::AliasTy<'tcx>),
    |           ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `AliasTyKind<rustc_middle::ty::TyCtxt<'tcx>>`
    |
   --> /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/cmp.rs:364:0
    |
    = note: in this expansion of `#[derive(Eq)]`
help: the trait `std::cmp::Eq` is implemented for `rustc_type_ir::Alias<I, K>`
   --> compiler/rustc_type_ir/src/ty/alias.rs:15:1

edit: Actually we can remove the empty implementation if we make AliasTyKind derive Eq

@rust-bors

This comment has been minimized.

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jun 4, 2026
…ric-capabilities, r=lcnr

Support generic params in `Lift_Generic`

Handle generic type parameters, including nested occurrences, when deriving `Lift_Generic`.

This lets types like `Binder<I, T>` use `#[derive(Lift_Generic)]` instead of requiring a manual `Lift` impl.

Concretely it can now handle structs as follows;

```rs
// Generic type parameter
struct Binder<I: Interner, T> {
    // body
}

// Nested generic type parameter
pub struct Binder<I: Interner, T = SomeKind<I>> {
    //
}
```

Split off from the `Alias` refactor work; rust-lang#156538

r? @lcnr
rust-timer added a commit that referenced this pull request Jun 4, 2026
Rollup merge of #156956 - Jamesbarford:feat/extend-lift-generic-capabilities, r=lcnr

Support generic params in `Lift_Generic`

Handle generic type parameters, including nested occurrences, when deriving `Lift_Generic`.

This lets types like `Binder<I, T>` use `#[derive(Lift_Generic)]` instead of requiring a manual `Lift` impl.

Concretely it can now handle structs as follows;

```rs
// Generic type parameter
struct Binder<I: Interner, T> {
    // body
}

// Nested generic type parameter
pub struct Binder<I: Interner, T = SomeKind<I>> {
    //
}
```

Split off from the `Alias` refactor work; #156538

r? @lcnr
@Jamesbarford Jamesbarford force-pushed the chore/merge-AliasTy-AliasTerm branch from e2ba945 to c3bdf72 Compare June 5, 2026 08:16
@rustbot

rustbot commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Jamesbarford Jamesbarford force-pushed the chore/merge-AliasTy-AliasTerm branch from 71c7efb to bf409af Compare June 5, 2026 08:42
Comment on lines +24 to +36
/// The parameters of the associated, opaque, or constant alias.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: I::GenericArgs,

pub kind: K,

@lcnr lcnr Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The parameters of the associated, opaque, or constant alias.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: I::GenericArgs,
pub kind: K,
pub kind: K,
/// The parameters of the associated, opaque, or constant alias.
///
/// For a projection, these are the generic parameters for the trait and the
/// GAT parameters, if there are any.
///
/// For an inherent projection, they consist of the self type and the GAT parameters,
/// if there are any.
///
/// For RPIT the generic parameters are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub args: I::GenericArgs,

personal style preference

View changes since the review

interner.debug_assert_args_compatible(kind.into(), args);
Alias { kind, args, _use_alias_new_instead: () }
}
}

@lcnr lcnr Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, could we change this to

trait AliasKind<I: Interner>: Copy {
    fn assert_args_compatible(self, cx: I, args: I::GenericArgs);

    #[inline]
    fn debug_assert_args_compatible(self, cx: I, args: I::GenericArgs) {
        if cfg!(debug_assertions) { self.assert... }
    }
}

impl<I: Interner, K: AliasKind> Alias<I, K> {
    pub fn new(
        cx: I,
        kind: K,
        args: I::GenericArgs,
    ) -> Self {
        kind.debug_assert_args_compatible(interner, args);
        Alias { kind, args, _use_alias_new_instead: () }
    }

    pub fn new_from_iter(
        cx: I,
        kind: K,
        args: impl IntoIterator<...>,
    ) -> Self { ... }
}

View changes since the review

fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
NormalizesTo { alias: self.alias.fold_with(folder), term: self.term.fold_with(folder) }
}
}

@lcnr lcnr Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do the derives not work?

View changes since the review

@Jamesbarford Jamesbarford Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In essence a similar problem that hampered Lift_Generic and the work needs to be done to get it working is similar to what we did for Lift_Generic, I can open another PR for this?

goal.predicate.alias.args,
);
let alias = ty::AliasTerm::from(uv);
let goal = goal.with(cx, ty::NormalizesTo { alias, term: goal.predicate.term });

@khyperia khyperia Jun 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm extremely on board with the style of thing that lcnr said with

with this we can now update NormalizesTo to also be generic over the kind, and e.g. for normalize_anon_const have the argument be Goal<I, ty::NormalizesTo<I, I::UnevaluatedConstId>>

there's a lot of places in the code that could hugely benefit from this (e.g. there's a large number of unwraps in #157653 that could be avoided), but this particular case with normalize_anon_const is a bit gross, and I would prefer keeping this as NormalizesTo<I, K = AliasTermKind<I>> (at least until additional refactorings happen that would e.g. allow evaluate_const_and_instantiate_normalizes_to_term to be more generic)

(this is just my code style opinion though, up to you!)


edit: just want to clarify, that PR has a lot of unwraps of the form:

let def_id = match inherent.kind {
    ty::AliasTermKind::InherentTy { def_id } => def_id.into(),
    ty::AliasTermKind::InherentConst { def_id } => def_id.into(),
    kind => panic!("expected inherent alias, found {kind:?}"),
};

having the Alias have a more specific Kind in all the cases that PR does that style of unwrap (it's so common that projections already have a helper method for it, expect_projection_def_id) would be super nice, but yeah

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jun 11, 2026
…able-generic, r=lcnr

Extend capabilities of `TypeFoldable_Generic`

Split from rust-lang#156538.

- Lets `TypeFoldable_Generic` derive structural folding for types with extra generic parameters by adding the necessary `T: TypeFoldable<I>` bounds automatically
- Means in rust-lang#156538 we can remove the manual `TypeFoldable` implementation for `NormalizesTo`
- Refactors shared traversal logic between `Lift_Generic` and `TypeFoldable_Generic` into a shared helper with a callback.

r? @lcnr
@rust-bors

rust-bors Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #157739) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants