From eeb59f16a5f40e14dc29b95155b7f2569329e3ec Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 4 May 2024 22:31:30 -0700 Subject: [PATCH 1/6] rustdoc: dedup search form HTML This change constructs the search form HTML using JavaScript, instead of plain HTML. It uses a custom element because - the [parser]'s insert algorithm runs the connected callback synchronously, so we won't get layout jank - it requires very little HTML, so it's a real win in size [parser]: https://html.spec.whatwg.org/multipage/parsing.html#create-an-element-for-the-token This shrinks the standard library by about 60MiB, by my test. --- src/librustdoc/html/static/js/storage.js | 43 +++++++++++++++++++ src/librustdoc/html/templates/page.html | 27 ++---------- tests/rustdoc-gui/javascript-disabled.goml | 2 +- .../sidebar-source-code-display.goml | 2 +- 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 73c543567c078..4a27ca92fff38 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -239,3 +239,46 @@ window.addEventListener("pageshow", ev => { setTimeout(updateSidebarWidth, 0); } }); + +// Custom elements are used to insert some JS-dependent features into Rustdoc, +// because the [parser] runs the connected callback +// synchronously. It needs to be added synchronously so that nothing below it +// becomes visible until after it's done. Otherwise, you get layout jank. +// +// That's also why this is in storage.js and not main.js. +// +// [parser]: https://html.spec.whatwg.org/multipage/parsing.html +class RustdocSearchElement extends HTMLElement { + constructor() { + super(); + } + connectedCallback() { + const rootPath = getVar("root-path"); + const currentCrate = getVar("current-crate"); + this.innerHTML = ``; + } +} +window.customElements.define("rustdoc-search", RustdocSearchElement); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 1e01cd70b963f..cdf01fa7a97e8 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -117,30 +117,9 @@

Files

{# #} {# #}
{# #} {% if page.css_class != "src" %}
{% endif %} - {# #} + {# defined in storage.js to avoid duplicating complex UI across every page #} + {# and because the search form only works if JS is enabled anyway #} + {# #}
{{ content|safe }}
{# #} {% if page.css_class != "src" %}
{% endif %}
{# #} diff --git a/tests/rustdoc-gui/javascript-disabled.goml b/tests/rustdoc-gui/javascript-disabled.goml index a7579ef7ec14d..c6a7ad94b3fd7 100644 --- a/tests/rustdoc-gui/javascript-disabled.goml +++ b/tests/rustdoc-gui/javascript-disabled.goml @@ -4,7 +4,7 @@ javascript: false go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" show-text: true -assert-css: (".sub", {"display": "none"}) +assert-false: ".sub" // Even though JS is disabled, we should still have themes applied. Links are never black-colored // if styles are applied so we check that they are not. diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 3bfbe820b8dfe..7ce3be8a5b355 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -4,7 +4,7 @@ javascript: false go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // Since the javascript is disabled, there shouldn't be a toggle. wait-for-css: (".sidebar", {"display": "none"}) -assert-css: ("#sidebar-button", {"display": "none"}) +assert-false: "#sidebar-button" // Let's retry with javascript enabled. javascript: true From f9bb5df5a0655190ed4f0d33cebbe6116c3f2eb1 Mon Sep 17 00:00:00 2001 From: Lin Yihai Date: Tue, 7 May 2024 11:02:28 +0800 Subject: [PATCH 2/6] narrow down visibilities in `rustc_parse::lexer` --- compiler/rustc_parse/src/lexer/diagnostics.rs | 8 ++++---- compiler/rustc_parse/src/lexer/mod.rs | 2 +- compiler/rustc_parse/src/lexer/unicode_chars.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 993ff1b97f5e8..1247e2e44fb13 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -5,7 +5,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::Span; #[derive(Default)] -pub struct TokenTreeDiagInfo { +pub(super) struct TokenTreeDiagInfo { /// Stack of open delimiters and their spans. Used for error message. pub open_braces: Vec<(Delimiter, Span)>, pub unmatched_delims: Vec, @@ -21,7 +21,7 @@ pub struct TokenTreeDiagInfo { pub matching_block_spans: Vec<(Span, Span)>, } -pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { +pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) { (Some(open_padding), Some(close_padding)) => open_padding == close_padding, _ => false, @@ -30,7 +30,7 @@ pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> // When we get a `)` or `]` for `{`, we should emit help message here // it's more friendly compared to report `unmatched error` in later phase -pub fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool { +fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool { let mut reported_missing_open = false; for unmatch_brace in unmatched_delims.iter() { if let Some(delim) = unmatch_brace.found_delim @@ -51,7 +51,7 @@ pub fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[Unmatch reported_missing_open } -pub fn report_suspicious_mismatch_block( +pub(super) fn report_suspicious_mismatch_block( err: &mut Diag<'_>, diag_info: &TokenTreeDiagInfo, sm: &SourceMap, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 1abb1d29562d9..d2d200a91aff2 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -112,7 +112,7 @@ struct StringReader<'psess, 'src> { } impl<'psess, 'src> StringReader<'psess, 'src> { - pub fn dcx(&self) -> &'psess DiagCtxt { + fn dcx(&self) -> &'psess DiagCtxt { &self.psess.dcx } diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 6b055fc844ae1..c9470151a7baf 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -9,7 +9,7 @@ use crate::{ use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks -pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ +pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('
', "Line Separator", " "), ('
', "Paragraph Separator", " "), (' ', "Ogham Space mark", " "), From 926281619479776ab56870424c16a8a968ed637d Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 6 May 2024 21:50:27 -0700 Subject: [PATCH 3/6] rustdoc: allow custom element rustdoc-search --- src/tools/html-checker/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs index 9b4d2c5259806..e74f72608efc8 100644 --- a/src/tools/html-checker/main.rs +++ b/src/tools/html-checker/main.rs @@ -29,6 +29,8 @@ fn check_html_file(file: &Path) -> usize { .arg("-quiet") .arg("--mute-id") // this option is useful in case we want to mute more warnings .arg("yes") + .arg("--new-blocklevel-tags") + .arg("rustdoc-search") // custom elements .arg("--mute") .arg(&to_mute_s) .arg(file); From 1d87efc1daa466223652aff66fabe218abdebdc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 May 2024 14:52:42 +0200 Subject: [PATCH 4/6] replace another Option by DUMMY_SP --- compiler/rustc_const_eval/src/const_eval/error.rs | 12 ++++++------ .../rustc_const_eval/src/const_eval/eval_queries.rs | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 763344207c467..2c9eb393e4a14 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, Symbol}; use super::CompileTimeInterpreter; use crate::errors::{self, FrameNote, ReportErrorExt}; @@ -121,7 +121,7 @@ where pub(super) fn report<'tcx, C, F, E>( tcx: TyCtxt<'tcx>, error: InterpError<'tcx>, - span: Option, + span: Span, get_span_and_frames: C, mk: F, ) -> ErrorHandled @@ -135,16 +135,16 @@ where // Don't emit a new diagnostic for these errors, they are already reported elsewhere or // should remain silent. err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP)) + ErrorHandled::TooGeneric(span) } - err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)), + err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span), err_inval!(Layout(LayoutError::ReferencesError(guar))) => { - ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP)) + ErrorHandled::Reported(guar.into(), span) } // Report remaining errors. _ => { let (our_span, frames) = get_span_and_frames(); - let span = span.unwrap_or(our_span); + let span = span.substitute_dummy(our_span); let err = mk(span, frames); let mut err = tcx.dcx().create_err(err); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 40afd9f162f4e..71a41e9cfe410 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, Abi}; use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter}; @@ -298,7 +298,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( super::report( tcx, error.into_kind(), - Some(span), + span, || (span, vec![]), |span, _| errors::NullaryIntrinsicError { span }, ) @@ -406,7 +406,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( super::report( *ecx.tcx, error, - None, + DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, ) @@ -461,7 +461,7 @@ fn report_validation_error<'mir, 'tcx>( crate::const_eval::report( *ecx.tcx, error, - None, + DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes }, ) From b58f5a780061c44c793d6c87a4d7eb6cfb3be743 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 7 May 2024 11:12:29 -0400 Subject: [PATCH 5/6] Don't ICE when we cannot eval a const to a valtree in the new solver --- .../rustc_trait_selection/src/solve/eval_ctxt/mod.rs | 6 +++--- .../canonical/const-region-infer-to-static-in-binder.rs | 3 ++- .../const-region-infer-to-static-in-binder.stderr | 9 ++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 55ade5e3e2f9f..98aac581c6eba 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1052,12 +1052,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty: Ty<'tcx>, ) -> Option> { use rustc_middle::mir::interpret::ErrorHandled; - match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, DUMMY_SP) { - Ok(ct) => Some(ct), + match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { + Ok(Some(val)) => Some(ty::Const::new_value(self.tcx(), val, ty)), + Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => { Some(ty::Const::new_error(self.tcx(), e.into(), ty)) } - Err(ErrorHandled::TooGeneric(_)) => None, } } diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs index 33a6d7aa78304..26d63fdde993c 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs @@ -1,8 +1,9 @@ -//@ compile-flags: -Znext-solver=coherence +//@ compile-flags: -Znext-solver #[derive(Debug)] struct X; //~^ ERROR using function pointers as const generic parameters is forbidden //~| ERROR using function pointers as const generic parameters is forbidden +//~| ERROR type annotations needed fn main() {} diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr index 4eef8c0ab6c03..044c24fd2b211 100644 --- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -1,3 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 + | +LL | struct X; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{ || {} }` + error: using function pointers as const generic parameters is forbidden --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 | @@ -15,5 +21,6 @@ LL | struct X; = note: the only supported types are integers, `bool` and `char` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0282`. From 690d5aa417f5d8f8d6157e5a897df5d7dd2ef59a Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 6 May 2024 21:33:57 +0000 Subject: [PATCH 6/6] generalize hr alias: avoid unconstrainable infer vars --- compiler/rustc_hir_typeck/src/closure.rs | 32 ++++-------- .../src/infer/relate/generalize.rs | 44 ++++++++++++++-- .../src/solve/inspect/build.rs | 5 +- .../hr-alias-non-hr-alias-self-ty-1.rs | 36 +++++++++++++ .../hr-alias-non-hr-alias-self-ty-2.rs | 32 ++++++++++++ .../hr-alias-universe-lowering-ambiguity.rs | 51 +++++++++++++++++++ .../generalize/occurs-check-nested-alias.rs | 1 + 7 files changed, 175 insertions(+), 26 deletions(-) create mode 100644 tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs create mode 100644 tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs create mode 100644 tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 4883c7aff8bc4..8652692e7f721 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -31,6 +31,7 @@ struct ExpectedSig<'tcx> { sig: ty::PolyFnSig<'tcx>, } +#[derive(Debug)] struct ClosureSignatures<'tcx> { /// The signature users of the closure see. bound_sig: ty::PolyFnSig<'tcx>, @@ -713,25 +714,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 self.commit_if_ok(|_| { let mut all_obligations = vec![]; - let inputs: Vec<_> = iter::zip( - decl.inputs, - supplied_sig.inputs().skip_binder(), // binder moved to (*) below - ) - .map(|(hir_ty, &supplied_ty)| { - // Instantiate (this part of..) S to S', i.e., with fresh variables. - self.instantiate_binder_with_fresh_vars( - hir_ty.span, - BoundRegionConversionTime::FnCall, - // (*) binder moved to here - supplied_sig.inputs().rebind(supplied_ty), - ) - }) - .collect(); + let supplied_sig = self.instantiate_binder_with_fresh_vars( + self.tcx.def_span(expr_def_id), + BoundRegionConversionTime::FnCall, + supplied_sig, + ); // The liberated version of this signature should be a subtype // of the liberated form of the expectation. for ((hir_ty, &supplied_ty), expected_ty) in iter::zip( - iter::zip(decl.inputs, &inputs), + iter::zip(decl.inputs, supplied_sig.inputs()), expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'. ) { // Check that E' = S'. @@ -744,11 +736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { all_obligations.extend(obligations); } - let supplied_output_ty = self.instantiate_binder_with_fresh_vars( - decl.output.span(), - BoundRegionConversionTime::FnCall, - supplied_sig.output(), - ); + let supplied_output_ty = supplied_sig.output(); let cause = &self.misc(decl.output.span()); let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq( DefineOpaqueTypes::Yes, @@ -757,7 +745,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )?; all_obligations.extend(obligations); - let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty)); + let inputs = + supplied_sig.inputs().into_iter().map(|&ty| self.resolve_vars_if_possible(ty)); expected_sigs.liberated_sig = self.tcx.mk_fn_sig( inputs, @@ -1013,6 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result } + #[instrument(level = "debug", skip(self), ret)] fn closure_sigs( &self, expr_def_id: LocalDefId, diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 74929daffe247..fb9198b4c952e 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -350,7 +350,13 @@ impl<'tcx> Generalizer<'_, 'tcx> { &mut self, alias: ty::AliasTy<'tcx>, ) -> Result, TypeError<'tcx>> { - if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() { + // We do not eagerly replace aliases with inference variables if they have + // escaping bound vars, see the method comment for details. However, when we + // are inside of an alias with escaping bound vars replacing nested aliases + // with inference variables can cause incorrect ambiguity. + // + // cc trait-system-refactor-initiative#110 + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { return Ok(self.infcx.next_ty_var_in_universe( TypeVariableOrigin { param_def_id: None, span: self.span }, self.for_universe, @@ -492,9 +498,30 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let origin = inner.type_variables().var_origin(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); - let u = Ty::new_var(self.tcx(), new_var_id); - debug!("replacing original vid={:?} with new={:?}", vid, u); - Ok(u) + // If we're in the new solver and create a new inference + // variable inside of an alias we eagerly constrain that + // inference variable to prevent unexpected ambiguity errors. + // + // This is incomplete as it pulls down the universe of the + // original inference variable, even though the alias could + // normalize to a type which does not refer to that type at + // all. I don't expect this to cause unexpected errors in + // practice. + // + // We only need to do so for type and const variables, as + // region variables do not impact normalization, and will get + // correctly constrained by `AliasRelate` later on. + // + // cc trait-system-refactor-initiative#108 + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + inner.type_variables().equate(vid, new_var_id); + } + + debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); + Ok(Ty::new_var(self.tcx(), new_var_id)) } } } @@ -614,6 +641,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { universe: self.for_universe, }) .vid; + + // See the comment for type inference variables + // for more details. + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + variable_table.union(vid, new_var_id); + } Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 466d0d8006018..a6aebc8d65a47 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -372,7 +372,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> { ( DebugSolver::GoalEvaluation(goal_evaluation), DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation), - ) => goal_evaluation.evaluation = Some(canonical_goal_evaluation), + ) => { + let prev = goal_evaluation.evaluation.replace(canonical_goal_evaluation); + assert_eq!(prev, None); + } _ => unreachable!(), } } diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs new file mode 100644 index 0000000000000..3be118a5b3940 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs @@ -0,0 +1,36 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Generalizing an alias referencing escaping bound variables +// is hard. We previously didn't replace this alias with inference +// variables but did replace nested alias which do not reference +// any bound variables. This caused us to stall with the following +// goal, which cannot make any progress: +// +// <::Refl as HigherRanked>::Output<'a> +// alias-relate +// ::Output<'a> +// +// +// cc trait-system-refactor-initiative#110 + +#![allow(unused)] +trait HigherRanked { + type Output<'a>; +} +trait Id { + type Refl: HigherRanked; +} + +fn foo() -> for<'a> fn(<::Refl as HigherRanked>::Output<'a>) { + todo!() +} + +fn bar() { + // we generalize here + let x = foo::(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs new file mode 100644 index 0000000000000..560eb34a977d8 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs @@ -0,0 +1,32 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// A minimization of an ambiguity error in `icu_provider`. +// +// cc trait-system-refactor-initiative#110 + +trait Yokeable<'a> { + type Output; +} +trait Id { + type Refl; +} + +fn into_deserialized() -> M +where + M::Refl: for<'a> Yokeable<'a>, +{ + try_map_project::(|_| todo!()) +} + +fn try_map_project(_f: F) -> M +where + M::Refl: for<'a> Yokeable<'a>, + F: for<'a> FnOnce(&'a ()) -> <::Refl as Yokeable<'a>>::Output, +{ + todo!() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs new file mode 100644 index 0000000000000..1e2ba81129dba --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs @@ -0,0 +1,51 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for a fairly subtle issue with how we +// generalize aliases referencing higher-ranked regions +// which previously caused unexpected ambiguity errors. +// +// The explanations in the test may end up being out of date +// in the future as we may refine our approach to generalization +// going forward. +// +// cc trait-system-refactor-initiative#108 +trait Trait<'a> { + type Assoc; +} + +impl<'a> Trait<'a> for () { + type Assoc = (); +} + +fn foo Trait<'a>>(x: T) -> for<'a> fn(>::Assoc) { + |_| () +} + +fn unconstrained() -> T { + todo!() +} + +fn main() { + // create `?x.0` in the root universe + let mut x = unconstrained(); + + // bump the current universe of the inference context + let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| (); + let _: for<'a> fn(&'a (), &'a ()) = bump; + + // create `?y.1` in a higher universe + let mut y = Default::default(); + + // relate `?x.0` with `for<'a> fn(>::Assoc)` + // -> instantiate `?x.0` with `for<'a> fn(>::Assoc)` + x = foo(y); + + // Constrain `?y.1` to `()` + let _: () = y; + + // `AliasRelate(>::Assoc, <() as Trait<'a>>::Assoc)` + // remains ambiguous unless we somehow constrain `?y_new.0` during + // generalization to be equal to `?y.1`, which is exactly what we + // did to fix this issue. +} diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs index 536e7e97c40de..00dc7a9d337d9 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs @@ -1,5 +1,6 @@ //@ revisions: old next //@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass // case 3 of https://github.com/rust-lang/trait-system-refactor-initiative/issues/8.