Skip to content

Add new alias kind Ambiguous and renormalize instantiated binders#156453

Draft
adwinwhite wants to merge 38 commits into
rust-lang:mainfrom
adwinwhite:renormalize-binder
Draft

Add new alias kind Ambiguous and renormalize instantiated binders#156453
adwinwhite wants to merge 38 commits into
rust-lang:mainfrom
adwinwhite:renormalize-binder

Conversation

@adwinwhite
Copy link
Copy Markdown
Contributor

@adwinwhite adwinwhite commented May 11, 2026

View all comments

Still WIP.
- fix rustdoc
- also normalize for diagnostics and assert the remaining instantiation doesn't need renormalization.
- remove the accidental staged cargo submodule

But maybe you wanna have a quick look first.
r? lcnr

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. 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 11, 2026
@adwinwhite
Copy link
Copy Markdown
Contributor Author

@bors try @rust-timer queue

@rust-timer
Copy link
Copy Markdown
Collaborator

Awaiting bors try build completion.

@rustbot label: +S-waiting-on-perf

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label May 11, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request May 11, 2026
Add new alias kind `Ambiguous` and renormalize instantiated binders
@rust-log-analyzer

This comment has been minimized.

@adwinwhite
Copy link
Copy Markdown
Contributor Author

@bors try cancel

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented May 11, 2026

Try build cancelled. Cancelled workflows:

@adwinwhite
Copy link
Copy Markdown
Contributor Author

Ignore tools failures for now.

@bors try @rust-timer queue

@rust-timer
Copy link
Copy Markdown
Collaborator

This pull request is already queued and waiting for a try build to finish.

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request May 11, 2026
Add new alias kind `Ambiguous` and renormalize instantiated binders
@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented May 11, 2026

💔 Test for 1c015e6 failed: CI. Failed job:

@rust-log-analyzer

This comment has been minimized.


// Placeholders (all printed as `_` to uniformize them).
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. })
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

Unnormalized::new_wip(unnormalized_external_impl_sig),
);
let external_impl_sig =
ocx.normalize(&norm_cause, param_env, Unnormalized::new(unnormalized_external_impl_sig));
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

Suggested change
ocx.normalize(&norm_cause, param_env, Unnormalized::new(unnormalized_external_impl_sig));
ocx.normalize(&norm_cause, param_env, Unnormalized::new_wip(unnormalized_external_impl_sig));

ideally this should be a map_unnormalized call in which we instantiate the binder

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.

Doesn't Unnormalized::map keep the wrapper? Or you mean something like Unnormalized::normalize_with?

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.

my idea would be to rewrite these to the following longterm

    let unnormalized_external_impl_sig = tcx.fn_sig(external_impl)
        .instantiate(
            tcx,
            infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()),
        )
        .map(|sig| infcx.instantiate_binder_with_fresh_vars(
            external_impl_span,
            infer::BoundRegionConversionTime::HigherRankedType,
            sig
        ));
    let external_impl_sig = ocx.normalize(
        &norm_cause,
        param_env,
        unnormalized_external_impl_sig,
    );

Comment thread compiler/rustc_hir_analysis/src/coherence/orphan.rs

// Placeholders (all printed as `_` to uniformize them).
ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. })
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

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 also make ty::Infer unreachable?

Comment on lines +49 to +50
// Now that we perform eager normalization inside the solver in some places,
// The aliases might be normalized away.
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

when do we do eager norm for the inputs of alias relate goals? 🤔

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.

I added normalize_ambiguous_aliases in EvalCtxt::enter_forall which is used in EvalCtxt::compute_goal.

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.

alias relate should only ever relate non ambiguous aliases :3 so i think if entering binders only ever renormalizes these, alias relate stays as is

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.

Yeah, currently we don't renormalize in binder relating. That should the cause of this. Unsure how to do that 🤔

Copy link
Copy Markdown
Contributor

@lcnr lcnr May 13, 2026

Choose a reason for hiding this comment

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

the easiest is to normalize by looking at all ambiguous aliases which no longer has bound vars, replace it with an infer var, emit Projection(contained_Alias, ?infer) as nested goal

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.

not the ideal end-state, but definitely fine as the temporary solution until this has all settled down a bit more and we can think about how to clean it up

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.

Got it. Something like ReplaceAliasWithInfer but for ambiguous aliases only.

Comment thread compiler/rustc_type_ir/src/predicate.rs Outdated
/// next solver. See `NormalizationFolder`.
///
/// The def_id and args are the same as the original alias.
AmbiguousTy { def_id: I::DefId },
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

why does this contain the def_id

View changes since the review

Comment thread compiler/rustc_infer/src/infer/mod.rs Outdated
}
}

pub fn instantiate_binder_with_fresh_vars_and_normalize_with<T, F>(
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

hmm, this is different from what I'd imagine 🤔

I would expect us to have

fn instantiate_binder_no_ambig_aliases(x: Binder<T>) -> T {
    instantiate_binder_renormalize_ambig_aliases(x, |_| unreachable!())
}

fn instantiate_binder_renormalize_ambig_aliases(x: Binder<T>, normalize: impl FnMut(AliasTerm<'tcx>) -> Term<'tcx>) -> T {
    instantiate binder
    walk with renormalize ambig aliases folder
}

I'd then keep the borrowck code etc the same as rn while using instantiate_binder_no_ambig_aliases and use instantiate_binder_renormalize_ambig_aliases only in the places that can encounter ambig aliases

View changes since the review

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.

where all the old solver exclusive code can just use instantiate_binder_no_ambig_aliases

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.

and the new solver places that currently can't easily use a normalization routine can just recreate the ty::Alias or ConstKind::Alias with a FIXME that they should instead normalize

self.print_def_path(def_id, args)?;
ty::Alias(ref data @ ty::AliasTy { kind, args, .. }) => match kind
.reveal_ambiguous(self.tcx())
{
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

hmm, instead of reeal_ambiguous Ambiguous aliases can just forward to their contained alias?

View changes since the review

Comment thread compiler/rustc_type_ir/src/predicate.rs Outdated
Comment on lines +660 to +667
// Convert `AmbiguousTy` into its original kind.
pub fn reveal_ambiguous(self, interner: I) -> Self {
if let AliasTermKind::AmbiguousTy { def_id } = self {
interner.alias_term_kind_from_def_id(def_id)
} else {
self
}
}
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

ah, so what you do is ty::Alias(Projection { def_id }, [Self, T]) to ty::Alias(Ambiguous { def_id }, [Self, T]) instead of

ty::Alias(Projection { def_id }, [Self, T]) to ty::Alias(Ambiguous, ty::Alias(Projection { def_id }, [Self, T])]) which is what I would have expected 🤔

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.

I considered storing the original alias as the first generic arg at first.
The problem is that AliasTyKind expects an DefId now.
And we can't synthesize def_id on the fly in typeck, I think?

Copy link
Copy Markdown
Contributor Author

@adwinwhite adwinwhite May 12, 2026

Choose a reason for hiding this comment

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

Oh I see, calls to def_id are on the way to be removed with the AliasTy refactor. I'll remove the def_id and wrap the original alias in generic arg then.

Copy link
Copy Markdown
Contributor

@lcnr lcnr May 12, 2026

Choose a reason for hiding this comment

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

yeah, ICE when calling def_id for ambiguous aliases

Copy link
Copy Markdown
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

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

u accidentally commited cargo

View changes since this review

) -> InferOk<'tcx, T> {
if self.infcx.next_trait_solver() {
let Normalized { value, obligations } =
crate::solve::normalize(*self, value, NormalizationScope::AmbiguousAlias);
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 11, 2026

Choose a reason for hiding this comment

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

i would not add support for this to the old trait solver at all 🤔 i would only ever use ambiguous aliases in the new solver, so here ambiguous aliases should be unreachable

View changes since the review

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@lcnr lcnr force-pushed the renormalize-binder branch from 34dd6a7 to 72555b9 Compare May 14, 2026 21:09
// We shouldn't register predicates to fcx in `probe()` as they're not rollbacked.
// Although it probably doesn't matter much for diagnostics.
let ocx = ObligationCtxt::new(&self.infcx);
let fty = ocx.normalize(&ObligationCause::dummy(), self.param_env, fty);
Copy link
Copy Markdown
Contributor

@lcnr lcnr May 14, 2026

Choose a reason for hiding this comment

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

impacts behavior, but diagnostics only code afaict

View changes since the review

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rustbot rustbot added the A-attributes Area: Attributes (`#[…]`, `#![…]`) label May 14, 2026
@rust-log-analyzer
Copy link
Copy Markdown
Collaborator

The job tidy failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
fmt: checked 6862 files
tidy check
tidy [rustdoc_json (src)]: `rustdoc-json-types` modified, checking format version
tidy: Skipping binary file check, read-only filesystem
tidy [style (compiler)]: /checkout/compiler/rustc_middle/src/ty/fold.rs:335: 3-line comment block with odd number of backticks
tidy [style (compiler)]: /checkout/compiler/rustc_middle/src/ty/context.rs:2067: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (compiler)]: /checkout/compiler/rustc_middle/src/ty/context.rs:2269: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (compiler)]: /checkout/compiler/rustc_type_ir/src/unnormalized.rs:171: TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME
tidy [style (compiler)]: FAIL
removing old virtual environment
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'venv'
creating virtual environment at '/checkout/obj/build/venv' using 'python3.10' and 'virtualenv'
Requirement already satisfied: pip in ./build/venv/lib/python3.10/site-packages (26.0.1)
Collecting pip
---
linting javascript files
Running eslint on rustdoc JS files
info: ES-Check: there were no ES version matching errors!  🎉
typechecking javascript files
tidy: The following check failed: style (compiler)
Command `/checkout/obj/build/x86_64-unknown-linux-gnu/stage1-tools-bin/rust-tidy --root-path=/checkout --cargo-path=/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo --output-dir=/checkout/obj/build --concurrency=4 --npm-path=/node/bin/yarn --ci=true --extra-checks=py,cpp,js,spellcheck` failed with exit code 1
Created at: src/bootstrap/src/core/build_steps/tool.rs:1618:23
Executed at: src/bootstrap/src/core/build_steps/test.rs:1417:29

--- BACKTRACE vvv
   0: <bootstrap::utils::exec::DeferredCommand>::finish_process
             at /checkout/src/bootstrap/src/utils/exec.rs:939:17
   1: <bootstrap::utils::exec::DeferredCommand>::wait_for_output::<&bootstrap::utils::exec::ExecutionContext>
             at /checkout/src/bootstrap/src/utils/exec.rs:831:21
   2: <bootstrap::utils::exec::ExecutionContext>::run
             at /checkout/src/bootstrap/src/utils/exec.rs:741:45
   3: <bootstrap::utils::exec::BootstrapCommand>::run::<&bootstrap::core::builder::Builder>
             at /checkout/src/bootstrap/src/utils/exec.rs:339:27
   4: <bootstrap::core::build_steps::test::Tidy as bootstrap::core::builder::Step>::run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:1417:29
   5: <bootstrap::core::builder::Builder>::ensure::<bootstrap::core::build_steps::test::Tidy>
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1595:36
   6: <bootstrap::core::build_steps::test::Tidy as bootstrap::core::builder::Step>::make_run
             at /checkout/src/bootstrap/src/core/build_steps/test.rs:1339:21
   7: <bootstrap::core::builder::StepDescription>::maybe_run
             at /checkout/src/bootstrap/src/core/builder/mod.rs:476:13
   8: bootstrap::core::builder::cli_paths::match_paths_to_steps_and_run
             at /checkout/src/bootstrap/src/core/builder/cli_paths.rs:232:18
   9: <bootstrap::core::builder::Builder>::run_step_descriptions
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1138:9
  10: <bootstrap::core::builder::Builder>::execute_cli
             at /checkout/src/bootstrap/src/core/builder/mod.rs:1117:14
  11: <bootstrap::Build>::build
             at /checkout/src/bootstrap/src/lib.rs:803:25
  12: bootstrap::main
             at /checkout/src/bootstrap/src/bin/main.rs:130:11
  13: <fn() as core::ops::function::FnOnce<()>>::call_once
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/ops/function.rs:250:5
  14: std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/sys/backtrace.rs:166:18
  15: std::rt::lang_start::<()>::{closure#0}
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/rt.rs:206:18
  16: <&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe as core::ops::function::FnOnce<()>>::call_once
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/core/src/ops/function.rs:287:21
  17: std::panicking::catch_unwind::do_call::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
  18: std::panicking::catch_unwind::<i32, &dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:544:19
  19: std::panic::catch_unwind::<&dyn core::ops::function::Fn<(), Output = i32> + core::marker::Sync + core::panic::unwind_safe::RefUnwindSafe, i32>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panic.rs:359:14
  20: std::rt::lang_start_internal::{closure#0}
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/rt.rs:175:24
  21: std::panicking::catch_unwind::do_call::<std::rt::lang_start_internal::{closure#0}, isize>
             at /rustc/ef0fb8a2563200e322fa4419f09f65a63742038c/library/std/src/panicking.rs:581:40
---
  28: __libc_start_main
  29: _start


Command has failed. Rerun with -v to see more details.
Bootstrap failed while executing `test src/tools/tidy tidyselftest --extra-checks=py,cpp,js,spellcheck`
Build completed unsuccessfully in 0:02:35
  local time: Fri May 15 00:00:59 UTC 2026
  network time: Fri, 15 May 2026 00:00:59 GMT
##[error]Process completed with exit code 1.

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

Labels

A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-perf Status: Waiting on a perf run to be completed. T-clippy Relevant to the Clippy team. 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