diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index bac3661ec51ad..e38266aa8186c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1082,7 +1082,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let typeck_results = tcx.typeck(self.mir_def_id()); // We don't use `ty.peel_refs()` to get the number of `*`s needed to get the root type. - let liberated_sig = tcx.liberate_late_bound_regions(closure_def_id.to_def_id(), args.sig()); + let liberated_sig = tcx + .liberate_late_bound_regions( + closure_def_id.to_def_id(), + ty::Unnormalized::new_wip(args.sig()), + ) + .skip_norm_wip(); let mut peeled_ty = liberated_sig.output(); let mut count = 0; while let ty::Ref(_, ref_ty, _) = *peeled_ty.kind() { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 963f902b71fcb..e12ceb69f3901 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -418,8 +418,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { // Get the parent fn's signature with liberated late-bound regions, // so we have `ReLateParam` instead of `ReBound`. - let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity().skip_norm_wip(); - let liberated_sig = tcx.liberate_late_bound_regions(parent_def_id, parent_fn_sig); + let parent_fn_sig = tcx.fn_sig(parent_def_id).instantiate_identity(); + let liberated_sig = + tcx.liberate_late_bound_regions(parent_def_id, parent_fn_sig).skip_norm_wip(); let parent_param_ty = *liberated_sig.inputs().get(param_index)?; // Get the upvar's NLL type (with ReVar regions from renumbering). diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8b9f4291603a9..c8d6b7c02a6f4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -32,7 +32,8 @@ use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::{ - InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, + BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, + TyCtxtInferExt, }; use rustc_middle::mir::*; use rustc_middle::query::Providers; @@ -707,6 +708,20 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { next_region } + + /// We expect all aliases to already be fully normalized during borrowck, + /// so we can redefine this method to just unwrap the unnormalized alias binder. + pub(crate) fn instantiate_binder_with_fresh_vars( + &self, + span: Span, + lbrct: BoundRegionConversionTime, + value: ty::Binder<'tcx, T>, + ) -> T + where + T: TypeFoldable> + Copy, + { + self.infcx.instantiate_binder_with_fresh_vars(span, lbrct, value).no_ambiguous_aliases() + } } impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 13983f349d6a5..b6a9322db96f2 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -811,6 +811,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { region_ctxt_fn, ) }); + let unnormalized_sig = unnormalized_sig.no_ambiguous_aliases(); debug!(?unnormalized_sig); // IMPORTANT: We have to prove well formed for the function signature before // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc` diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index f18884df0b44d..8f80081859016 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -173,7 +173,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { T: ty::TypeFoldable> + Copy, { let value = if let Some(inner) = binder.no_bound_vars() { - inner + ty::UnnormalizedAmbiguous::dummy(inner) } else { let infcx = self.type_checker.infcx; let mut lazy_universe = None; @@ -207,7 +207,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { }; debug!(?value); - f(self, value) + f(self, value.no_ambiguous_aliases()) } #[instrument(skip(self), level = "debug")] @@ -245,7 +245,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> { let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate); debug!(?replaced); - replaced + replaced.no_ambiguous_aliases() } fn create_next_universe(&mut self) -> ty::UniverseIndex { diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 804d2757cf998..d2a2e124eb9eb 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -892,7 +892,7 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { ty::Region::new_late_param(self.tcx, all_outlive_scope.to_def_id(), kind); ty::Region::new_var(self.tcx, indices.to_region_vid(liberated_region)) }); - value + value.no_ambiguous_aliases() } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index b0ce3833446d3..92132db2fe6da 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -128,18 +128,15 @@ pub fn validate_trivial_unsize<'tcx>( tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized()); let universe = infcx.universe(); let ocx = ObligationCtxt::new(&infcx); - infcx.enter_forall(hr_target_principal, |target_principal| { - let source_principal = infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, + let cause = ObligationCause::dummy(); + ocx.enter_forall(&cause, param_env, hr_target_principal, |target_principal| { + let source_principal = ocx.instantiate_binder_with_fresh_vars( + &cause, BoundRegionConversionTime::HigherRankedType, + param_env, hr_source_principal, ); - let Ok(()) = ocx.eq( - &ObligationCause::dummy(), - param_env, - target_principal, - source_principal, - ) else { + let Ok(()) = ocx.eq(&cause, param_env, target_principal, source_principal) else { return false; }; if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index f1bca03218e07..e215c49b6fffc 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -45,7 +45,7 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { | ty::UnsafeBinder(_) => self.pretty_print_type(ty), // Placeholders (all printed as `_` to uniformize them). - ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => { + ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Error(_) => { write!(self, "_")?; Ok(()) } @@ -63,13 +63,12 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { | ty::Coroutine(def_id, args) => self.print_def_path(def_id, args), ty::Foreign(def_id) => self.print_def_path(def_id, &[]), - ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => { - bug!("type_name: unexpected free alias") - } - ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => { - bug!("type_name: unexpected inherent projection") - } - ty::CoroutineWitness(..) => bug!("type_name: unexpected `CoroutineWitness`"), + ty::Infer(_) + | ty::Alias(ty::AliasTy { + kind: ty::Free { .. } | ty::Inherent { .. } | ty::Ambiguous, + .. + }) + | ty::CoroutineWitness(..) => bug!("type_name: unexpected type: {ty:?}"), } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 1bcdfd9f25a5b..8e916991e2c25 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -68,25 +68,22 @@ pub(crate) fn compare_eii_function_types<'tcx>( let mut wf_tys = FxIndexSet::default(); let norm_cause = ObligationCause::misc(external_impl_span, external_impl); - let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity().skip_norm_wip(); - let declaration_sig = tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig); + let declaration_sig = tcx.fn_sig(foreign_item).instantiate_identity(); + let declaration_sig = + tcx.liberate_late_bound_regions(external_impl.into(), declaration_sig).skip_norm_wip(); debug!(?declaration_sig); - let unnormalized_external_impl_sig = infcx.instantiate_binder_with_fresh_vars( + // We need to check wf of the unnormalized sig. + let unnormalized_external_impl_sig = infcx.instantiate_unnormalized_binder_with_fresh_vars( external_impl_span, infer::BoundRegionConversionTime::HigherRankedType, - tcx.fn_sig(external_impl) - .instantiate( - tcx, - infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), - ) - .skip_norm_wip(), - ); - let external_impl_sig = ocx.normalize( - &norm_cause, - param_env, - Unnormalized::new_wip(unnormalized_external_impl_sig), + tcx.fn_sig(external_impl).instantiate( + tcx, + infcx.fresh_args_for_item(external_impl_span, external_impl.to_def_id()), + ), ); + let external_impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_external_impl_sig); + debug!(?external_impl_sig); // Next, add all inputs and output as well-formed tys. Importantly, @@ -125,7 +122,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( } if !(declaration_sig, external_impl_sig).references_error() { - for ty in unnormalized_external_impl_sig.inputs_and_output { + for ty in unnormalized_external_impl_sig.skip_normalization().inputs_and_output { ocx.register_obligation(traits::Obligation::new( infcx.tcx, cause.clone(), diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 234231ed37fed..b221e2bc7c5b3 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -326,19 +326,20 @@ fn compare_method_predicate_entailment<'tcx>( let mut wf_tys = FxIndexSet::default(); - let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars( + // We need to check wf of unnormalized sig. + let unnormalized_impl_sig = infcx.instantiate_unnormalized_binder_with_fresh_vars( impl_m_span, BoundRegionConversionTime::HigherRankedType, - tcx.fn_sig(impl_m.def_id).instantiate_identity().skip_norm_wip(), + tcx.fn_sig(impl_m.def_id).instantiate_identity(), ); let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); - let impl_sig = - ocx.normalize(&norm_cause, param_env, Unnormalized::new_wip(unnormalized_impl_sig)); + let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig); + debug!(?impl_sig); - let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args).skip_norm_wip(); - let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); + let trait_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args); + let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig).skip_norm_wip(); // Next, add all inputs and output as well-formed tys. Importantly, // we have to do this before normalization, since the normalized ty may @@ -375,7 +376,7 @@ fn compare_method_predicate_entailment<'tcx>( } if !(impl_sig, trait_sig).references_error() { - for ty in unnormalized_impl_sig.inputs_and_output { + for ty in unnormalized_impl_sig.skip_normalization().inputs_and_output { ocx.register_obligation(traits::Obligation::new( infcx.tcx, cause.clone(), @@ -534,15 +535,12 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // Normalize the impl signature with fresh variables for lifetime inference. let misc_cause = ObligationCause::misc(return_span, impl_m_def_id); - let impl_sig = ocx.normalize( - &misc_cause, - param_env, - Unnormalized::new_wip(infcx.instantiate_binder_with_fresh_vars( - return_span, - BoundRegionConversionTime::HigherRankedType, - tcx.fn_sig(impl_m.def_id).instantiate_identity().skip_norm_wip(), - )), + let impl_sig = infcx.instantiate_unnormalized_binder_with_fresh_vars( + return_span, + BoundRegionConversionTime::HigherRankedType, + tcx.fn_sig(impl_m.def_id).instantiate_identity(), ); + let impl_sig = ocx.normalize(&misc_cause, param_env, impl_sig); impl_sig.error_reported()?; let impl_return_ty = impl_sig.output(); @@ -554,8 +552,9 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let unnormalized_trait_sig = tcx .liberate_late_bound_regions( impl_m.def_id, - tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args).skip_norm_wip(), + tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_to_impl_args), ) + .skip_norm_wip() .fold_with(&mut collector); let trait_sig = @@ -1259,12 +1258,12 @@ fn check_region_late_boundedness<'tcx>( .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, impl_m.def_id)); let impl_m_args = infcx.fresh_args_for_item(DUMMY_SP, impl_m.def_id); - let impl_m_sig = tcx.fn_sig(impl_m.def_id).instantiate(tcx, impl_m_args).skip_norm_wip(); - let impl_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, impl_m_sig); + let impl_m_sig = tcx.fn_sig(impl_m.def_id).instantiate(tcx, impl_m_args); + let impl_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, impl_m_sig).skip_norm_wip(); let trait_m_args = infcx.fresh_args_for_item(DUMMY_SP, trait_m.def_id); - let trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_args).skip_norm_wip(); - let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_m_sig); + let trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_args); + let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_m_sig).skip_norm_wip(); let ocx = ObligationCtxt::new(&infcx); @@ -1515,11 +1514,12 @@ fn compare_self_type<'tcx>( } ty::AssocContainer::Trait => tcx.types.self_param, }; - let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip().input(0); + let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().map(|sig| sig.input(0)); let (infcx, param_env) = tcx .infer_ctxt() .build_with_typing_env(ty::TypingEnv::non_body_analysis(tcx, method.def_id)); - let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty); + let self_arg_ty = + tcx.liberate_late_bound_regions(method.def_id, self_arg_ty).skip_norm_wip(); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty); get_self_string(self_arg_ty, can_eq_self) }; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index cdda54f7eb943..c7ca008b43d52 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -44,23 +44,23 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>( let impl_def_id = impl_m.container_id(tcx); let impl_m_args = ty::GenericArgs::identity_for_item(tcx, impl_m.def_id); let trait_m_to_impl_m_args = impl_m_args.rebase_onto(tcx, impl_def_id, impl_trait_ref.args); - let bound_trait_m_sig = - tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args).skip_norm_wip(); - let trait_m_sig = tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig); + let bound_trait_m_sig = tcx.fn_sig(trait_m.def_id).instantiate(tcx, trait_m_to_impl_m_args); + let trait_m_sig = + tcx.liberate_late_bound_regions(impl_m.def_id, bound_trait_m_sig).skip_norm_wip(); // replace the self type of the trait ref with `Self` so that diagnostics render better. - let trait_m_sig_with_self_for_diag = tcx.liberate_late_bound_regions( - impl_m.def_id, - tcx.fn_sig(trait_m.def_id) - .instantiate( + let trait_m_sig_with_self_for_diag = tcx + .liberate_late_bound_regions( + impl_m.def_id, + tcx.fn_sig(trait_m.def_id).instantiate( tcx, tcx.mk_args_from_iter( [tcx.types.self_param.into()] .into_iter() .chain(trait_m_to_impl_m_args.iter().skip(1)), ), - ) - .skip_norm_wip(), - ); + ), + ) + .skip_norm_wip(); let Ok(hidden_tys) = tcx.collect_return_position_impl_trait_in_trait_tys(impl_m.def_id) else { // Error already emitted, no need to delay another. diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 30d3e109a0080..e56cdfed6d646 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -538,8 +538,9 @@ fn suggestion_signature<'tcx>( tcx, tcx.liberate_late_bound_regions( assoc.def_id, - tcx.fn_sig(assoc.def_id).instantiate(tcx, args).skip_norm_wip(), - ), + tcx.fn_sig(assoc.def_id).instantiate(tcx, args), + ) + .skip_norm_wip(), assoc.ident(tcx), tcx.predicates_of(assoc.def_id) .instantiate_own(tcx, args) diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index dd506dd2b7fc9..8b732ed6e78dc 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -425,10 +425,12 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // For methods, we check the function signature's return type for any GATs // to constrain. In the `into_iter` case, we see that the return type // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from. - let sig: ty::FnSig<'_> = tcx.liberate_late_bound_regions( - item_def_id.to_def_id(), - tcx.fn_sig(item_def_id).instantiate_identity().skip_norm_wip(), - ); + let sig = tcx + .liberate_late_bound_regions( + item_def_id.to_def_id(), + tcx.fn_sig(item_def_id).instantiate_identity(), + ) + .skip_norm_wip(); gather_gat_bounds( tcx, param_env, @@ -1014,7 +1016,7 @@ pub(crate) fn check_associated_item( Ok(()) } ty::AssocKind::Fn { .. } => { - let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + let sig = tcx.fn_sig(def_id).instantiate_identity(); let hir_sig = tcx.hir_node_by_def_id(def_id).fn_sig().expect("bad signature for method"); check_fn_or_method(wfcx, sig, hir_sig.decl, def_id); @@ -1233,7 +1235,7 @@ fn check_item_fn( enter_wf_checking_ctxt(tcx, def_id, |wfcx| { check_eiis_fn(tcx, def_id); - let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + let sig = tcx.fn_sig(def_id).instantiate_identity(); check_fn_or_method(wfcx, sig, decl, def_id); Ok(()) }) @@ -1701,12 +1703,12 @@ pub(super) fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, def_id: #[instrument(level = "debug", skip(wfcx, hir_decl))] fn check_fn_or_method<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, - sig: ty::PolyFnSig<'tcx>, + sig: ty::Unnormalized<'tcx, ty::PolyFnSig<'tcx>>, hir_decl: &hir::FnDecl<'_>, def_id: LocalDefId, ) { let tcx = wfcx.tcx(); - let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + let mut sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig).skip_norm_wip(); // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` @@ -1812,8 +1814,8 @@ fn check_method_receiver<'tcx>( let span = fn_sig.decl.inputs[0].span; let loc = Some(WellFormedLoc::Param { function: method.def_id.expect_local(), param_idx: 0 }); - let sig = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip(); - let sig = tcx.liberate_late_bound_regions(method.def_id, sig); + let sig = tcx.fn_sig(method.def_id).instantiate_identity(); + let sig = tcx.liberate_late_bound_regions(method.def_id, sig).skip_norm_wip(); let sig = wfcx.normalize(DUMMY_SP, loc, Unnormalized::new_wip(sig)); debug!("check_method_receiver: sig={:?}", sig); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 52567667b0fe6..5fd4feea31010 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -210,7 +210,8 @@ impl<'tcx> InherentCollect<'tcx> { | ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) | ty::Bound(..) | ty::Placeholder(_) - | ty::Infer(_) => { + | ty::Infer(_) + | ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) => { bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty); } // We could bail out here, but that will silence other useful errors. diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index bacc1f1549973..a3e647d85db11 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -180,6 +180,19 @@ pub(crate) fn orphan_check_impl( NonlocalImpl::DisallowOther, ), + ty::FnDef(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Infer(..) + | ty::Alias(ty::AliasTy { kind: ty::Ambiguous, .. }) => { + let sp = tcx.def_span(impl_def_id); + span_bug!(sp, "weird self type for autotrait impl") + } + ty::Alias(ty::AliasTy { kind, .. }) => { let problematic_kind = match kind { // trait Id { type This: ?Sized; } @@ -203,6 +216,7 @@ pub(crate) fn orphan_check_impl( // ``` // FIXME(inherent_associated_types): The example code above currently leads to a cycle ty::Inherent { .. } => "associated type", + ty::Ambiguous { .. } => unreachable!("handled in arm above"), }; (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) } @@ -223,18 +237,6 @@ pub(crate) fn orphan_check_impl( | ty::Tuple(..) | ty::UnsafeBinder(_) => (LocalImpl::Allow, NonlocalImpl::DisallowOther), - ty::FnDef(..) - | ty::Closure(..) - | ty::CoroutineClosure(..) - | ty::Coroutine(..) - | ty::CoroutineWitness(..) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(..) => { - let sp = tcx.def_span(impl_def_id); - span_bug!(sp, "weird self type for autotrait impl") - } - ty::Error(..) => (LocalImpl::Allow, NonlocalImpl::Allow), }; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8c182f9165e13..3a8b9892edad9 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -471,7 +471,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { name: Symbol::intern(<_name), }) } - ), + ).no_ambiguous_aliases(), ), }); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 6e2c7a82af3b1..f0c00c92e0917 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -840,7 +840,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } else { return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit { span: path_span, - ty: tcx.liberate_late_bound_regions(item_def_id, output), + ty: tcx + .liberate_late_bound_regions(item_def_id, ty::Unnormalized::new_wip(output)) + .skip_norm_wip(), fn_span: tcx.hir_span_if_local(item_def_id), note: (), })); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5a86e8186a5aa..c81852d40e47c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -3687,16 +3687,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_ref.def_id, )?; + let fn_sig = tcx.fn_sig(assoc.def_id).instantiate( + tcx, + trait_ref.args.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), + ); let fn_sig = tcx - .fn_sig(assoc.def_id) - .instantiate( - tcx, - trait_ref - .args - .extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)), - ) + .liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig) .skip_norm_wip(); - let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig); Some(if let Some(arg_idx) = arg_idx { *fn_sig.inputs().get(arg_idx)? diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index a45856937a8e0..39269876f1c84 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -327,7 +327,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // types, where we use Error as the Self type } - ty::Placeholder(..) | ty::CoroutineWitness(..) | ty::Bound(..) | ty::Infer(..) => { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) + | ty::Placeholder(..) + | ty::CoroutineWitness(..) + | ty::Bound(..) + | ty::Infer(..) => { bug!("unexpected type encountered in variance inference: {}", ty); } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index e15c9fe661641..623d259677ece 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -12,7 +12,7 @@ use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, Unnormalized}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; @@ -544,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { ty::FnDef(def_id, args) => { self.enforce_context_effects(Some(call_expr.hir_id), call_expr.span, def_id, args); - let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args).skip_norm_wip(); + let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args); // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output @@ -574,7 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // FIXME(const_trait_impl): these arms should error because we can't enforce them - ty::FnPtr(sig_tys, hdr) => (sig_tys.with(hdr), None), + ty::FnPtr(sig_tys, hdr) => (ty::Unnormalized::new_wip(sig_tys.with(hdr)), None), _ => unreachable!(), }; @@ -584,12 +584,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // renormalize the associated types at this point, since they // previously appeared within a `Binder<>` and hence would not // have been normalized before. - let fn_sig = self.instantiate_binder_with_fresh_vars( + let fn_sig = self.instantiate_unnormalized_binder_with_fresh_vars( call_expr.span, BoundRegionConversionTime::FnCall, fn_sig, ); - let fn_sig = self.normalize(call_expr.span, Unnormalized::new_wip(fn_sig)); + let fn_sig = self.normalize(call_expr.span, fn_sig); self.check_argument_types( call_expr.span, diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 763d2a27e6cc0..7f510b0f6fdf8 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -20,6 +20,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::traits::ArgKind; use rustc_trait_selection::traits; +use rustc_trait_selection::traits::NormalizeExt; use tracing::{debug, instrument, trace}; use super::{CoroutineTypes, Expectation, FnCtxt, check_fn}; @@ -249,18 +250,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // coroutine. To do so, we use the `CoroutineClosureSignature` to compute // the coroutine type, filling in the tupled_upvars_ty and kind_ty with infer // vars which will get constrained during upvar analysis. - let coroutine_output_ty = tcx.liberate_late_bound_regions( - expr_def_id.to_def_id(), - closure_args.coroutine_closure_sig().map_bound(|sig| { - sig.to_coroutine( - tcx, - parent_args, - coroutine_kind_ty, - tcx.coroutine_for_closure(expr_def_id), - coroutine_upvars_ty, - ) - }), - ); + let coroutine_output_ty = tcx + .liberate_late_bound_regions( + expr_def_id.to_def_id(), + ty::Unnormalized::new_wip(closure_args.coroutine_closure_sig().map_bound( + |sig| { + sig.to_coroutine( + tcx, + parent_args, + coroutine_kind_ty, + tcx.coroutine_for_closure(expr_def_id), + coroutine_upvars_ty, + ) + }, + )), + ) + .skip_norm_wip(); liberated_sig = tcx.mk_fn_sig( liberated_sig.inputs().iter().copied(), coroutine_output_ty, @@ -823,12 +828,17 @@ 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 = PredicateObligations::new(); - let supplied_sig = self.instantiate_binder_with_fresh_vars( + let supplied_sig = self.infcx.instantiate_binder_with_fresh_vars( self.tcx.def_span(expr_def_id), BoundRegionConversionTime::FnCall, supplied_sig, ); + let cause = self.misc(self.tcx.def_span(expr_def_id)); + let InferOk { value: supplied_sig, obligations } = + self.at(&cause, self.param_env).renormalize_ambiguous_aliases(supplied_sig); + all_obligations.extend(obligations); + // 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( @@ -1112,8 +1122,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_def_id: LocalDefId, bound_sig: ty::PolyFnSig<'tcx>, ) -> ClosureSignatures<'tcx> { - let liberated_sig = - self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig); + let liberated_sig = self + .tcx() + .liberate_late_bound_regions( + expr_def_id.to_def_id(), + ty::Unnormalized::new_wip(bound_sig), + ) + .skip_norm_wip(); let liberated_sig = self.normalize(self.tcx.def_span(expr_def_id), Unnormalized::new_wip(liberated_sig)); ClosureSignatures { bound_sig, liberated_sig } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index db5994bca3d3d..d9bb8492871e0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -20,7 +20,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, DerefAdjustKind, @@ -435,6 +435,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } + pub(crate) fn instantiate_binder_with_fresh_vars( + &self, + span: Span, + lbrct: BoundRegionConversionTime, + value: ty::Binder<'tcx, T>, + ) -> T + where + T: TypeFoldable> + Copy, + { + let value = self.infcx.instantiate_binder_with_fresh_vars(span, lbrct, value); + self.register_infer_ok_obligations( + self.at(&self.misc(span), self.param_env).renormalize_ambiguous_aliases(value), + ) + } + pub(crate) fn require_type_meets( &self, ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 5fea7454e57ea..0fc0611177af2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -394,6 +394,8 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { + // FIXME(#155345): We don't expect ambiguous aliases here as actually + // the `poly_trait_ref` is expected to be unnormalized. let trait_ref = self.instantiate_binder_with_fresh_vars( span, // FIXME(mgca): `item_def_id` can be an AssocConst; rename this variant. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 55a01ddfba779..856da8221f92f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -142,18 +142,26 @@ fn typeck_with_inspect<'tcx>( // type that has an infer in it, lower the type directly so that it'll // be correctly filled with infer. We'll use this inference to provide // a suggestion later on. - fcx.lowerer().lower_fn_ty(id, header.safety(), header.abi, decl, None, None) + ty::Unnormalized::new_wip(fcx.lowerer().lower_fn_ty( + id, + header.safety(), + header.abi, + decl, + None, + None, + )) } else { - tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip() + tcx.fn_sig(def_id).instantiate_identity() }; - check_abi(tcx, id, span, fn_sig.abi()); + check_abi(tcx, id, span, fn_sig.skip_norm_wip().abi()); check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span); loops::check(tcx, def_id, body); // Compute the function signature from point of view of inside the fn. - let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); + let mut fn_sig = + tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig).skip_norm_wip(); // Normalize the input and output types one at a time, using a different // `WellFormedLoc` for each. We cannot call `normalize_associated_types` diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 49126ff0e964c..1b25e3c3600a0 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::{BoundRegionConversionTime, InferOk}; use rustc_infer::traits::PredicateObligations; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt, Unnormalized, + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TypeVisitableExt, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; @@ -421,15 +421,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // N.B., instantiate late-bound regions before normalizing the // function signature so that normalization does not need to deal // with bound regions. - let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args).skip_norm_wip(); - let fn_sig = self.instantiate_binder_with_fresh_vars( + let fn_sig = tcx.fn_sig(def_id).instantiate(self.tcx, args); + let fn_sig = self.instantiate_unnormalized_binder_with_fresh_vars( obligation.cause.span, BoundRegionConversionTime::FnCall, fn_sig, ); - let InferOk { value: fn_sig, obligations: o } = - self.at(&obligation.cause, self.param_env).normalize(Unnormalized::new_wip(fn_sig)); + self.at(&obligation.cause, self.param_env).normalize(fn_sig); obligations.extend(o); // Register obligations for the parameters. This will include the diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4258896deec70..ecf1d80ca2c7d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1073,13 +1073,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { match method.kind { ty::AssocKind::Fn { .. } => self.probe(|_| { let args = self.fresh_args_for_item(self.span, method.def_id); - let fty = - self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args).skip_norm_wip(); - let fty = self.instantiate_binder_with_fresh_vars( + let fty = self.instantiate_unnormalized_binder_with_fresh_vars( self.span, BoundRegionConversionTime::FnCall, - fty, + self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args), ); + // 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); + if !ocx.try_evaluate_obligations().is_empty() { + return false; + } + self.can_eq(self.param_env, fty.output(), expected) }), _ => false, @@ -2035,13 +2041,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - let trait_ref = self.instantiate_binder_with_fresh_vars( - self.span, + let trait_ref = ocx.instantiate_binder_with_fresh_vars( + cause, BoundRegionConversionTime::FnCall, + self.param_env, poly_trait_ref, ); - let trait_ref = - ocx.normalize(cause, self.param_env, Unnormalized::new_wip(trait_ref)); (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = @@ -2100,9 +2105,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { trait_predicate = Some(trait_ref.upcast(self.tcx)); } ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { - let trait_ref = self.instantiate_binder_with_fresh_vars( - self.span, + let trait_ref = ocx.instantiate_binder_with_fresh_vars( + cause, BoundRegionConversionTime::FnCall, + self.param_env, poly_trait_ref, ); (xform_self_ty, xform_ret_ty) = diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 7bebe72971a9e..cae3572856373 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2285,13 +2285,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // not methods because they don’t have an instance of the struct to work with. if def_kind == DefKind::AssocFn { let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id); - let fn_sig = - tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args).skip_norm_wip(); - let fn_sig = self.instantiate_binder_with_fresh_vars( + let fn_sig = self.instantiate_unnormalized_binder_with_fresh_vars( span, BoundRegionConversionTime::FnCall, - fn_sig, + tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args), ); + let fn_sig = self.normalize(span, fn_sig); if similar_candidate.is_method() { if let Some(args) = args && fn_sig.inputs()[1..].len() == args.len() @@ -2369,16 +2368,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inherent_method.container_id(self.tcx), adt_args, ); - let fn_sig = self - .tcx - .fn_sig(inherent_method.def_id) - .instantiate(self.tcx, args) - .skip_norm_wip(); - let fn_sig = self.instantiate_binder_with_fresh_vars( + let fn_sig = + self.tcx.fn_sig(inherent_method.def_id).instantiate(self.tcx, args); + let fn_sig = self.instantiate_unnormalized_binder_with_fresh_vars( item_name.span, BoundRegionConversionTime::FnCall, fn_sig, ); + let fn_sig = self.normalize(item_name.span, fn_sig); let name = inherent_method.name(); let inputs = fn_sig.inputs(); let expected_inputs = diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index fc0c4bb0d5f5e..0a13969fd8c37 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -201,7 +201,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn instantiate_binder_with_infer> + Copy>( &self, value: ty::Binder<'tcx, T>, - ) -> T { + ) -> ty::UnnormalizedAmbiguous<'tcx, T> { self.instantiate_binder_with_fresh_vars( DUMMY_SP, BoundRegionConversionTime::HigherRankedType, @@ -212,7 +212,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { fn enter_forall>, U>( &self, value: ty::Binder<'tcx, T>, - f: impl FnOnce(T) -> U, + f: impl FnOnce(ty::UnnormalizedAmbiguous<'tcx, T>) -> U, ) -> U { self.enter_forall(value, f) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c0029719c6e12..ad23cfdddddc9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -850,7 +850,8 @@ impl<'tcx> InferCtxt<'tcx> { _ => {} } - self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| { + self.enter_forall(predicate, |pred| { + let ty::SubtypePredicate { a_is_expected, a, b } = pred.no_ambiguous_aliases(); if a_is_expected { Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b)) } else { @@ -1376,24 +1377,50 @@ impl<'tcx> InferCtxt<'tcx> { } } - // Instantiates the bound variables in a given binder with fresh inference - // variables in the current universe. - // - // Use this method if you'd like to find some generic parameters of the binder's - // variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] - // that corresponds to your use case, consider whether or not you should - // use [`InferCtxt::enter_forall`] instead. - pub fn instantiate_binder_with_fresh_vars( + /// Instantiates the bound variables in a given binder with fresh inference + /// variables in the current universe. + /// + /// Use this method if you'd like to find some generic parameters of the binder's + /// variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] + /// that corresponds to your use case, consider whether or not you should + /// use [`InferCtxt::enter_forall`] instead. + pub fn instantiate_unnormalized_binder_with_fresh_vars( + &self, + span: Span, + lbrct: BoundRegionConversionTime, + value: ty::Unnormalized<'tcx, ty::Binder<'tcx, T>>, + ) -> ty::Unnormalized<'tcx, T> + where + T: TypeFoldable> + Copy, + { + value + .map(|v| self.instantiate_binder_with_fresh_vars(span, lbrct, v).no_ambiguous_aliases()) + } + + pub fn instantiate_binder_with_fresh_vars_old_solver( &self, span: Span, lbrct: BoundRegionConversionTime, value: ty::Binder<'tcx, T>, ) -> T + where + T: TypeFoldable> + Copy, + { + debug_assert!(!self.next_trait_solver()); + self.instantiate_binder_with_fresh_vars(span, lbrct, value).no_ambiguous_aliases() + } + + pub fn instantiate_binder_with_fresh_vars( + &self, + span: Span, + lbrct: BoundRegionConversionTime, + value: ty::Binder<'tcx, T>, + ) -> ty::UnnormalizedAmbiguous<'tcx, T> where T: TypeFoldable> + Copy, { if let Some(inner) = value.no_bound_vars() { - return inner; + return ty::UnnormalizedAmbiguous::new(inner); } let bound_vars = value.bound_vars(); diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 3d2d617cfdb29..8075438d4bbab 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -210,6 +210,9 @@ impl<'tcx> InferCtxt<'tcx> { | ty::AliasTermKind::UnevaluatedConst { .. } => { return Err(TypeError::CyclicConst(source_term.expect_const())); } + ty::AliasTermKind::AmbiguousTy { .. } => { + unreachable!("We shouldn't have `AmbiguousTy` in the old solver") + } } } } else { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 324725a079bbe..59f5a99e0dff8 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -9,6 +9,13 @@ use crate::infer::InferCtxt; use crate::infer::snapshot::CombinedSnapshot; impl<'tcx> InferCtxt<'tcx> { + pub fn enter_forall_and_leak_universe_old_solver(&self, binder: ty::Binder<'tcx, T>) -> T + where + T: TypeFoldable>, + { + debug_assert!(!self.next_trait_solver()); + self.enter_forall_and_leak_universe(binder).no_ambiguous_aliases() + } /// Replaces all bound variables (lifetimes, types, and constants) bound by /// `binder` with placeholder variables in a new universe. This means that the /// new placeholders can only be named by inference variables created after @@ -21,13 +28,16 @@ impl<'tcx> InferCtxt<'tcx> { /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[instrument(level = "debug", skip(self), ret)] - pub fn enter_forall_and_leak_universe(&self, binder: ty::Binder<'tcx, T>) -> T + pub fn enter_forall_and_leak_universe( + &self, + binder: ty::Binder<'tcx, T>, + ) -> ty::UnnormalizedAmbiguous<'tcx, T> where T: TypeFoldable>, { // Inlined `no_bound_vars`. if !binder.as_ref().skip_binder().has_escaping_bound_vars() { - return binder.skip_binder(); + return ty::UnnormalizedAmbiguous::dummy(binder.skip_binder()); } let next_universe = self.create_next_universe(); @@ -62,8 +72,15 @@ impl<'tcx> InferCtxt<'tcx> { /// This method should be preferred over `fn enter_forall_and_leak_universe`. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html + /// + /// Check `renormalize_ambiguous_aliases` methods for handling the + /// `UnnormalizedAmbiguous` wrapper. #[instrument(level = "debug", skip(self, f))] - pub fn enter_forall(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U + pub fn enter_forall( + &self, + forall: ty::Binder<'tcx, T>, + f: impl FnOnce(ty::UnnormalizedAmbiguous<'tcx, T>) -> U, + ) -> U where T: TypeFoldable>, { @@ -76,6 +93,21 @@ impl<'tcx> InferCtxt<'tcx> { f(value) } + #[instrument(level = "debug", skip(self, f))] + pub fn enter_forall_old_solver( + &self, + forall: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U + where + T: TypeFoldable>, + { + debug_assert!(!self.next_trait_solver()); + let value = self.enter_forall_and_leak_universe(forall); + debug!(?value); + f(value.no_ambiguous_aliases()) + } + /// See [RegionConstraintCollector::leak_check][1]. We only check placeholder /// leaking into `outer_universe`, i.e. placeholders which cannot be named by that /// universe. diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 595392fcfb524..009424efcefe7 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -299,14 +299,22 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, 'tcx> { // // [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html ty::Covariant => { - infcx.enter_forall(b, |b| { - let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a); + infcx.enter_forall_old_solver(b, |b| { + let a = infcx.instantiate_binder_with_fresh_vars_old_solver( + span, + HigherRankedType, + a, + ); self.relate(a, b) })?; } ty::Contravariant => { - infcx.enter_forall(a, |a| { - let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b); + infcx.enter_forall_old_solver(a, |a| { + let b = infcx.instantiate_binder_with_fresh_vars_old_solver( + span, + HigherRankedType, + b, + ); self.relate(a, b) })?; } @@ -322,14 +330,22 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, 'tcx> { // `exists<..> A == for<..> B` and `exists<..> B == for<..> A`. // Check if `exists<..> A == for<..> B` ty::Invariant => { - infcx.enter_forall(b, |b| { - let a = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, a); + infcx.enter_forall_old_solver(b, |b| { + let a = infcx.instantiate_binder_with_fresh_vars_old_solver( + span, + HigherRankedType, + a, + ); self.relate(a, b) })?; // Check if `exists<..> B == for<..> A`. - infcx.enter_forall(a, |a| { - let b = infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, b); + infcx.enter_forall_old_solver(a, |a| { + let b = infcx.instantiate_binder_with_fresh_vars_old_solver( + span, + HigherRankedType, + b, + ); self.relate(a, b) })?; } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 65dfa8b93de78..035cf09fda242 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -142,7 +142,7 @@ enum ParamKind { } fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { - let sig = tcx.fn_sig(parent_def_id).instantiate_identity().skip_norm_wip(); + let sig = tcx.fn_sig(parent_def_id).instantiate_identity(); let mut in_scope_parameters = FxIndexMap::default(); // Populate the in_scope_parameters list first with all of the generics in scope @@ -163,7 +163,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) { in_scope_parameters.insert(def_id, ParamKind::Free(def_id)); } - let sig = tcx.liberate_late_bound_regions(parent_def_id.to_def_id(), sig); + let sig = tcx.liberate_late_bound_regions(parent_def_id.to_def_id(), sig).skip_norm_wip(); // Then visit the signature to walk through all the binders (incl. the late-bound // vars on the function itself, which we need to count too). diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 6b19aa17c6d6c..f04d670c33f59 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { .map(Unnormalized::skip_norm_wip) { infcx.enter_forall(pred.kind(), |predicate| { - let ty::ClauseKind::Projection(proj) = predicate else { + let ty::ClauseKind::Projection(proj) = predicate.no_ambiguous_aliases() else { return; }; // Only check types, since those are the only things that may diff --git a/compiler/rustc_lint/src/types/improper_ctypes.rs b/compiler/rustc_lint/src/types/improper_ctypes.rs index a1020962faedf..7b7b8bec4f43b 100644 --- a/compiler/rustc_lint/src/types/improper_ctypes.rs +++ b/compiler/rustc_lint/src/types/improper_ctypes.rs @@ -896,7 +896,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Param(..) | ty::Alias(ty::AliasTy { - kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }, + kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. } | ty::Ambiguous, .. }) | ty::Infer(..) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 7421024bba0cc..a313cb0764f85 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -194,6 +194,10 @@ impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { Const::new_unevaluated(interner, uv) } + fn new_value(interner: TyCtxt<'tcx>, value: ty::Value<'tcx>) -> Self { + Const::new_value(interner, value.valtree, value.ty) + } + fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self { Const::new_expr(interner, expr) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e756277b92d76..59f14e697cde5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2064,6 +2064,22 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { + // TODO + match binder.skip_binder() { + ty::PredicateKind::AliasRelate(lhs, rhs, ..) => { + assert!( + lhs.to_alias_term(self) + .filter(|a| !matches!(a.kind, ty::AliasTermKind::AmbiguousTy)) + .is_some() + || rhs + .to_alias_term(self) + .filter(|a| !matches!(a.kind, ty::AliasTermKind::AmbiguousTy)) + .is_some(), + "{binder:?}" + ) + } + _ => {} + } self.interners.intern_predicate(binder) } @@ -2134,6 +2150,64 @@ impl<'tcx> TyCtxt<'tcx> { true } + pub fn debug_assert_alias_ty_args_compatible( + self, + alias_ty: ty::AliasTyKind<'tcx>, + args: &'tcx [ty::GenericArg<'tcx>], + ) { + if cfg!(debug_assertions) { + match alias_ty { + ty::AliasTyKind::Projection { def_id } + | ty::AliasTyKind::Inherent { def_id } + | ty::AliasTyKind::Opaque { def_id } + | ty::AliasTyKind::Free { def_id } => { + self.debug_assert_args_compatible(def_id, args) + } + ty::AliasTyKind::Ambiguous => { + assert_eq!(args.len(), 1); + match args[0].expect_ty().kind() { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, args: _, .. }) => { + unreachable!() + } + ty::Alias(_) => {} + _ => unreachable!(), + } + } + } + } + } + + pub fn debug_assert_alias_term_args_compatible( + self, + alias_term: ty::AliasTermKind<'tcx>, + args: &'tcx [ty::GenericArg<'tcx>], + ) { + if cfg!(debug_assertions) { + match alias_term { + rustc_type_ir::AliasTermKind::ProjectionTy { def_id } + | rustc_type_ir::AliasTermKind::InherentTy { def_id } + | rustc_type_ir::AliasTermKind::OpaqueTy { def_id } + | rustc_type_ir::AliasTermKind::FreeTy { def_id } + | rustc_type_ir::AliasTermKind::UnevaluatedConst { def_id } + | rustc_type_ir::AliasTermKind::ProjectionConst { def_id } + | rustc_type_ir::AliasTermKind::FreeConst { def_id } + | rustc_type_ir::AliasTermKind::InherentConst { def_id } => { + self.debug_assert_args_compatible(def_id, args) + } + ty::AliasTermKind::AmbiguousTy => { + assert_eq!(args.len(), 1); + match args[0].expect_ty().kind() { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, args: _, .. }) => { + unreachable!() + } + ty::Alias(_) => {} + _ => unreachable!(), + } + } + } + } + } + /// With `cfg(debug_assertions)`, assert that args are compatible with their generics, /// and print out the args if not. pub fn debug_assert_args_compatible(self, def_id: DefId, args: &'tcx [ty::GenericArg<'tcx>]) { @@ -2192,6 +2266,17 @@ impl<'tcx> TyCtxt<'tcx> { #[allow(rustc::usage_of_ty_tykind)] #[inline] pub fn mk_ty_from_kind(self, st: TyKind<'tcx>) -> Ty<'tcx> { + // TODO + match st { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, args, .. }) => { + match args.type_at(0).kind() { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, .. }) => unreachable!(), + ty::Alias(_) => {} + _ => unreachable!(), + } + } + _ => {} + } self.interners.intern_ty(st) } diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index 7f1eeda4ad1d6..b41cc716ef866 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -277,6 +277,22 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.debug_assert_args_compatible(def_id, args); } + fn debug_assert_alias_ty_args_compatible( + self, + alias_ty: ty::AliasTyKind<'tcx>, + args: ty::GenericArgsRef<'tcx>, + ) { + self.debug_assert_alias_ty_args_compatible(alias_ty, args); + } + + fn debug_assert_alias_term_args_compatible( + self, + alias_ty: ty::AliasTermKind<'tcx>, + args: ty::GenericArgsRef<'tcx>, + ) { + self.debug_assert_alias_term_args_compatible(alias_ty, args); + } + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` /// are compatible with the `DefId`. Since we're missing a `Self` type, stick on /// a dummy self type and forward to `debug_assert_args_compatible`. diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 52f37ed4a9eac..0ce7e9819523b 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -213,6 +213,7 @@ impl<'tcx> Ty<'tcx> { ty::Alias(ty::AliasTy { kind: ty::Free { .. }, .. }) => "type alias".into(), ty::Param(_) => "type parameter".into(), ty::Alias(ty::AliasTy { kind: ty::Opaque { .. }, .. }) => "opaque type".into(), + ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) => "ambiguous alias".into(), } } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3d9148d6ed7ba..403e3f45d8ed3 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -207,7 +207,7 @@ impl<'tcx> TyCtxt<'tcx> { self, value: Binder<'tcx, T>, mut fld_r: F, - ) -> (T, FxIndexMap, ty::Region<'tcx>>) + ) -> (ty::UnnormalizedAmbiguous<'tcx, T>, FxIndexMap, ty::Region<'tcx>>) where F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>, T: TypeFoldable>, @@ -223,14 +223,14 @@ impl<'tcx> TyCtxt<'tcx> { self, value: Binder<'tcx, T>, mut replace_regions: F, - ) -> T + ) -> ty::UnnormalizedAmbiguous<'tcx, T> where F: FnMut(ty::BoundRegion<'tcx>) -> ty::Region<'tcx>, T: TypeFoldable>, { let value = value.skip_binder(); if !value.has_escaping_bound_vars() { - value + ty::UnnormalizedAmbiguous::dummy(value) } else { let delegate = FnMutDelegate { regions: &mut replace_regions, @@ -238,7 +238,7 @@ impl<'tcx> TyCtxt<'tcx> { consts: &mut |b| bug!("unexpected bound ct in binder: {b:?}"), }; let mut replacer = BoundVarReplacer::new(self, delegate); - value.fold_with(&mut replacer) + ty::UnnormalizedAmbiguous::new(value.fold_with(&mut replacer)) } } @@ -265,17 +265,16 @@ impl<'tcx> TyCtxt<'tcx> { self, value: Binder<'tcx, T>, delegate: impl BoundVarReplacerDelegate<'tcx>, - ) -> T { - self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate) + ) -> ty::UnnormalizedAmbiguous<'tcx, T> { + let value = self.replace_escaping_bound_vars_uncached(value.skip_binder(), delegate); + ty::UnnormalizedAmbiguous::new(value) } - /// Replaces any late-bound regions bound in `value` with - /// free variants attached to `all_outlive_scope`. - pub fn liberate_late_bound_regions( + pub fn liberate_late_bound_regions_normalized( self, all_outlive_scope: DefId, value: ty::Binder<'tcx, T>, - ) -> T + ) -> ty::UnnormalizedAmbiguous<'tcx, T> where T: TypeFoldable>, { @@ -285,6 +284,25 @@ impl<'tcx> TyCtxt<'tcx> { }) } + /// Replaces any late-bound regions bound in `value` with + /// free variants attached to `all_outlive_scope`. + pub fn liberate_late_bound_regions( + self, + all_outlive_scope: DefId, + value: ty::Unnormalized<'tcx, ty::Binder<'tcx, T>>, + ) -> ty::Unnormalized<'tcx, T> + where + T: TypeFoldable>, + { + value.map(|value| { + self.instantiate_bound_regions_uncached(value, |br| { + let kind = ty::LateParamRegionKind::from_bound(br.var, br.kind); + ty::Region::new_late_param(self, all_outlive_scope, kind) + }) + .no_ambiguous_aliases() + }) + } + pub fn shift_bound_var_indices(self, bound_vars: usize, value: T) -> T where T: TypeFoldable>, @@ -314,13 +332,14 @@ impl<'tcx> TyCtxt<'tcx> { ) } - /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also - /// method lookup and a few other places where precise region relationships are not required. + /// Replaces any late-bound regions bound in `value` with `'erased`. This should + /// generally only be used in codegen and does not expect any ambiguous aliases + /// in `value``. pub fn instantiate_bound_regions_with_erased(self, value: Binder<'tcx, T>) -> T where T: TypeFoldable>, { - self.instantiate_bound_regions(value, |_| self.lifetimes.re_erased).0 + self.instantiate_bound_regions(value, |_| self.lifetimes.re_erased).0.no_ambiguous_aliases() } /// Anonymize all bound variables in `value`, this is mostly used to improve caching. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 74f9e75fb48c0..ce63e699b4243 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -109,7 +109,7 @@ pub use self::sty::{ BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, FnSigKind, InlineConstArgs, InlineConstArgsParts, ParamConst, ParamTy, PlaceholderConst, PlaceholderRegion, PlaceholderType, PolyFnSig, TyKind, TypeAndMut, TypingMode, - TypingModeEqWrapper, Unnormalized, UpvarArgs, + TypingModeEqWrapper, Unnormalized, UnnormalizedAmbiguous, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index daead99b977c1..89a9979f02b1c 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -819,6 +819,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } ty::Foreign(def_id) => self.print_def_path(def_id, &[])?, + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, args, .. }) => { + self.pretty_print_type(args.type_at(0))? + } ty::Alias( ref data @ ty::AliasTy { kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }, @@ -3173,6 +3176,7 @@ define_print! { | ty::AliasTermKind::ProjectionConst { def_id } => { p.print_def_path(def_id, self.args)?; } + ty::AliasTermKind::AmbiguousTy { .. } => self.args.type_at(0).print(p)?, } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 14bce52fefe63..eef3034072be8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -3,8 +3,8 @@ #![allow(rustc::usage_of_ty_tykind)] use std::borrow::Cow; -use std::debug_assert_matches; use std::ops::{ControlFlow, Range}; +use std::{assert_matches, debug_assert_matches}; use hir::def::{CtorKind, DefKind}; use rustc_abi::{FIRST_VARIANT, FieldIdx, NumScalableVectors, ScalableElt, VariantIdx}; @@ -43,6 +43,7 @@ pub type FnSigKind<'tcx> = ir::FnSigKind>; pub type Binder<'tcx, T> = ir::Binder, T>; pub type EarlyBinder<'tcx, T> = ir::EarlyBinder, T>; pub type Unnormalized<'tcx, T> = ir::Unnormalized, T>; +pub type UnnormalizedAmbiguous<'tcx, T> = ir::UnnormalizedAmbiguous, T>; pub type TypingMode<'tcx, S = MayBeErased> = ir::TypingMode, S>; pub type TypingModeEqWrapper<'tcx> = ir::TypingModeEqWrapper>; pub type Placeholder<'tcx, T> = ir::Placeholder, T>; @@ -477,12 +478,16 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_alias(tcx: TyCtxt<'tcx>, alias_ty: ty::AliasTy<'tcx>) -> Ty<'tcx> { - debug_assert_matches!( - (alias_ty.kind, tcx.def_kind(alias_ty.kind.def_id())), - (ty::Opaque { .. }, DefKind::OpaqueTy) - | (ty::Projection { .. } | ty::Inherent { .. }, DefKind::AssocTy) - | (ty::Free { .. }, DefKind::TyAlias) - ); + if cfg!(debug_assertions) { + match alias_ty.kind { + ty::Opaque { def_id } => assert_matches!(tcx.def_kind(def_id), DefKind::OpaqueTy), + ty::Projection { def_id } | ty::Inherent { def_id } => { + assert_matches!(tcx.def_kind(def_id), DefKind::AssocTy) + } + ty::Free { def_id } => assert_matches!(tcx.def_kind(def_id), DefKind::TyAlias), + ty::Ambiguous => {} + } + } Ty::new(tcx, Alias(alias_ty)) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 99da2da391151..c68c6d57c866f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -927,6 +927,7 @@ impl<'tcx> TyCtxt<'tcx> { } } ty::AliasTermKind::OpaqueTy { def_id } => Some(self.variances_of(def_id)), + ty::AliasTermKind::AmbiguousTy => Some(&[ty::Variance::Covariant]), ty::AliasTermKind::InherentTy { .. } | ty::AliasTermKind::InherentConst { .. } | ty::AliasTermKind::FreeTy { .. } diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index e9f9da9c8cd91..477b623c5dca9 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -626,10 +626,12 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - (vec![], tcx.type_of(def_id).instantiate_identity().skip_norm_wip(), None) } DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => { - let sig = tcx.liberate_late_bound_regions( - def_id.to_def_id(), - tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(), - ); + let sig = tcx + .liberate_late_bound_regions( + def_id.to_def_id(), + tcx.fn_sig(def_id).instantiate_identity(), + ) + .skip_norm_wip(); (sig.inputs().to_vec(), sig.output(), None) } DefKind::Closure => { @@ -637,7 +639,12 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - match closure_ty.kind() { ty::Closure(_, args) => { let args = args.as_closure(); - let sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), args.sig()); + let sig = tcx + .liberate_late_bound_regions( + def_id.to_def_id(), + ty::Unnormalized::new_wip(args.sig()), + ) + .skip_norm_wip(); let self_ty = match args.kind() { ty::ClosureKind::Fn => { Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty) @@ -670,10 +677,12 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - } ty::CoroutineClosure(did, args) => { let args = args.as_coroutine_closure(); - let sig = tcx.liberate_late_bound_regions( - def_id.to_def_id(), - args.coroutine_closure_sig(), - ); + let sig = tcx + .liberate_late_bound_regions( + def_id.to_def_id(), + ty::Unnormalized::dummy(args.coroutine_closure_sig()), + ) + .skip_normalization(); let self_ty = match args.kind() { ty::ClosureKind::Fn => { Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, closure_ty) diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 8052ee26df841..8a1eeda1acb15 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -152,11 +152,18 @@ impl<'tcx> TailCallCkVisitor<'_, 'tcx> { self.report_signature_mismatch( expr.span, - self.tcx.liberate_late_bound_regions( - CRATE_DEF_ID.to_def_id(), - caller_ty.fn_sig(self.tcx), - ), - self.tcx.liberate_late_bound_regions(CRATE_DEF_ID.to_def_id(), ty.fn_sig(self.tcx)), + self.tcx + .liberate_late_bound_regions( + CRATE_DEF_ID.to_def_id(), + ty::Unnormalized::new_wip(caller_ty.fn_sig(self.tcx)), + ) + .skip_norm_wip(), + self.tcx + .liberate_late_bound_regions( + CRATE_DEF_ID.to_def_id(), + ty::Unnormalized::new_wip(ty.fn_sig(self.tcx)), + ) + .skip_norm_wip(), ); } diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index b47e7bd168678..a1bcce7d3dddc 100644 --- a/compiler/rustc_mir_transform/src/check_call_recursion.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -52,8 +52,13 @@ impl<'tcx> MirLint<'tcx> for CheckDropRecursion { { // It was. Now figure out for what type `Drop` is implemented and then // check for recursion. - if let ty::Ref(_, dropped_ty, _) = - tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() + if let ty::Ref(_, dropped_ty, _) = tcx + .liberate_late_bound_regions( + def_id.to_def_id(), + ty::Unnormalized::new_wip(sig.input(0)), + ) + .skip_norm_wip() + .kind() { check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 7f92199dec455..efe0354759b1d 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -1182,7 +1182,9 @@ fn build_construct_coroutine_by_move_shim<'tcx>( sig.fn_sig_kind, ) }); - let sig = tcx.liberate_late_bound_regions(coroutine_closure_def_id, poly_sig); + let sig = tcx + .liberate_late_bound_regions(coroutine_closure_def_id, ty::Unnormalized::dummy(poly_sig)) + .skip_normalization(); let ty::Coroutine(coroutine_def_id, coroutine_args) = *sig.output().kind() else { bug!(); }; diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index 589d055192029..ec1066623ff77 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -377,7 +377,8 @@ where self.found_uncovered_ty_param(ty) } } - _ => self.found_uncovered_ty_param(ty), + ty::Inherent { .. } | ty::Opaque { .. } | ty::Free { .. } => self.found_uncovered_ty_param(ty), + ty::AliasTyKind::Ambiguous => unreachable!(), }, InCrate::Remote => { // The inference variable might be unified with a local diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index 7506591d6fb5d..8befa77971836 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -1,6 +1,9 @@ +use std::fmt::Debug; +use std::marker::PhantomData; + use rustc_type_ir::data_structures::ensure_sufficient_stack; use rustc_type_ir::inherent::*; -use rustc_type_ir::solve::{Goal, NoSolution}; +use rustc_type_ir::solve::Goal; use rustc_type_ir::{ self as ty, Binder, FallibleTypeFolder, InferConst, InferCtxtLike, InferTy, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -13,8 +16,12 @@ use crate::placeholder::{BoundVarReplacer, PlaceholderReplacer}; /// This folder normalizes value and collects ambiguous goals. /// /// Note that for ambiguous alias which contains escaping bound vars, -/// we just return the original alias and don't collect the ambiguous goal. -pub struct NormalizationFolder<'a, Infcx, I, F> +/// we just return the original alias wrapped in `Ambiguous` alias and +/// don't collect the ambiguous goal. +/// +/// `Ambiguous` aliases are expected to be normalized away by +/// `BinderRenormalizer`. Though this folder can handle them as well. +pub struct NormalizationFolder<'a, Infcx, I, F, E> where Infcx: InferCtxtLike, I: Interner, @@ -23,6 +30,7 @@ where universes: Vec>, stalled_goals: Vec>, normalize: F, + _error: PhantomData, } #[derive(PartialEq, Eq)] @@ -31,6 +39,12 @@ enum HasEscapingBoundVars { No, } +#[derive(PartialEq, Eq)] +pub enum NormalizationScope { + All, + AmbiguousAlias, +} + /// Finds the max universe present in infer vars. struct MaxUniverse<'a, Infcx, I> where @@ -97,11 +111,18 @@ where } } -impl<'a, Infcx, I, F> NormalizationFolder<'a, Infcx, I, F> +#[derive(PartialEq, Eq)] +enum NeedRenormalization { + Yes, + No, +} + +impl<'a, Infcx, I, F, E> NormalizationFolder<'a, Infcx, I, F, E> where Infcx: InferCtxtLike, I: Interner, - F: FnMut(I::Term) -> Result<(I::Term, Option>), NoSolution>, + F: FnMut(I::Term) -> Result<(I::Term, Option>), E>, + E: Debug, { pub fn new( infcx: &'a Infcx, @@ -109,7 +130,7 @@ where stalled_goals: Vec>, normalize: F, ) -> Self { - Self { infcx, universes, stalled_goals, normalize } + Self { infcx, universes, stalled_goals, normalize, _error: PhantomData } } pub fn stalled_goals(self) -> Vec> { @@ -120,12 +141,12 @@ where &mut self, alias_term: I::Term, has_escaping: HasEscapingBoundVars, - ) -> Result { + ) -> Result<(I::Term, NeedRenormalization), E> { let current_universe = self.infcx.universe(); self.infcx.create_next_universe(); let (normalized, ambig_goal) = (self.normalize)(alias_term)?; - + self.stalled_goals.extend(ambig_goal); // Return ambiguous higher ranked alias as is, if // - it contains escaping vars, and // - the normalized term contains infer vars newly created @@ -139,22 +160,22 @@ where normalized.visit_with(&mut visitor); let max_universe = visitor.max_universe(); if current_universe.cannot_name(max_universe) { - return Ok(alias_term); + return Ok((alias_term, NeedRenormalization::Yes)); } } - self.stalled_goals.extend(ambig_goal); - Ok(normalized) + Ok((normalized, NeedRenormalization::No)) } } -impl<'a, Infcx, I, F> FallibleTypeFolder for NormalizationFolder<'a, Infcx, I, F> +impl<'a, Infcx, I, F, E> FallibleTypeFolder for NormalizationFolder<'a, Infcx, I, F, E> where Infcx: InferCtxtLike, I: Interner, - F: FnMut(I::Term) -> Result<(I::Term, Option>), NoSolution>, + F: FnMut(I::Term) -> Result<(I::Term, Option>), E>, + E: Debug, { - type Error = NoSolution; + type Error = E; fn cx(&self) -> I { self.infcx.cx() @@ -177,30 +198,47 @@ where return Ok(ty); } - // With eager normalization, we should normalize the args of alias before - // normalizing the alias itself. - let ty = ty.try_super_fold_with(self)?; - let ty::Alias(..) = ty.kind() else { return Ok(ty) }; + let ty = match ty.kind() { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, args, .. }) => { + // FIXME: long term we shouldn't ever normalize types containing ambiguous aliases, + // but for now we just try to renormalize the contained alias. + return Ok(args.type_at(0).try_fold_with(self)?); + } + ty::Alias(..) => ty.try_super_fold_with(self)?, + _ => return Ok(ty.try_super_fold_with(self)?), + }; if ty.has_escaping_bound_vars() { let (ty, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty); - let result = ensure_sufficient_stack(|| { + let (normalized_term, need_renormalization) = ensure_sufficient_stack(|| { self.normalize_alias_term(ty.into(), HasEscapingBoundVars::Yes) - })? - .expect_ty(); - Ok(PlaceholderReplacer::replace_placeholders( + })?; + let normalized_ty = PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, mapped_consts, &self.universes, - result, - )) + normalized_term.expect_ty(), + ); + if need_renormalization == NeedRenormalization::Yes { + Ok(I::Ty::new_alias( + self.cx(), + ty::AliasTy::new_from_args( + self.cx(), + ty::AliasTyKind::Ambiguous, + self.cx().mk_args(&[normalized_ty.into()]), + ), + )) + } else { + Ok(normalized_ty) + } } else { Ok(ensure_sufficient_stack(|| { self.normalize_alias_term(ty.into(), HasEscapingBoundVars::No) })? + .0 .expect_ty()) } } @@ -223,6 +261,7 @@ where let result = ensure_sufficient_stack(|| { self.normalize_alias_term(ct.into(), HasEscapingBoundVars::Yes) })? + .0 .expect_const(); Ok(PlaceholderReplacer::replace_placeholders( infcx, @@ -236,7 +275,121 @@ where Ok(ensure_sufficient_stack(|| { self.normalize_alias_term(ct.into(), HasEscapingBoundVars::No) })? + .0 .expect_const()) } } + + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) } + } +} + +/// As a perf optimization, we only need to normalize aliases of `Ambiguous` +/// kind after instantiating binders, assuming other kinds of aliases have +/// been normalized before. +pub struct BinderRenormalizer<'a, Infcx, I, F, E> +where + Infcx: InferCtxtLike, + I: Interner, +{ + infcx: &'a Infcx, + stalled_goals: Vec>, + normalize: F, + _error: PhantomData, +} + +impl<'a, Infcx, I, F, E> BinderRenormalizer<'a, Infcx, I, F, E> +where + Infcx: InferCtxtLike, + I: Interner, + F: FnMut(I::Term) -> Result<(I::Term, Option>), E>, + E: Debug, +{ + pub fn new(infcx: &'a Infcx, stalled_goals: Vec>, normalize: F) -> Self { + Self { infcx, stalled_goals, normalize, _error: PhantomData } + } + + pub fn stalled_goals(self) -> Vec> { + self.stalled_goals + } + + fn normalize_alias_term(&mut self, alias_term: I::Term) -> Result { + let (normalized, ambig_goal) = (self.normalize)(alias_term)?; + + self.stalled_goals.extend(ambig_goal); + Ok(normalized) + } +} + +impl<'a, Infcx, I, F, E> FallibleTypeFolder for BinderRenormalizer<'a, Infcx, I, F, E> +where + Infcx: InferCtxtLike, + I: Interner, + F: FnMut(I::Term) -> Result<(I::Term, Option>), E>, + E: Debug, +{ + type Error = E; + + fn cx(&self) -> I { + self.infcx.cx() + } + + fn try_fold_binder>( + &mut self, + t: Binder, + ) -> Result, Self::Error> { + // It's possible that we have ambiguous aliases which only reference + // outer instantiated bound vars in the nested inner binder. + // We should normalize those as well. + if t.has_ambiguous_aliases() { t.try_super_fold_with(self) } else { Ok(t) } + } + + #[instrument(level = "trace", skip(self), ret)] + fn try_fold_ty(&mut self, ty: I::Ty) -> Result { + if !ty.has_ambiguous_aliases() { + return Ok(ty); + } + + // With eager normalization, we should normalize the args of alias before + // normalizing the alias itself. + let ty = ty.try_super_fold_with(self)?; + let ty::Alias(ty::AliasTy { kind: ty::AliasTyKind::Ambiguous, args, .. }) = ty.kind() + else { + return Ok(ty); + }; + + let original_alias = args.type_at(0); + if original_alias.has_escaping_bound_vars() { + Ok(ty) + } else { + Ok(ensure_sufficient_stack(|| self.normalize_alias_term(original_alias.into()))? + .expect_ty()) + } + } + + #[instrument(level = "trace", skip(self), ret)] + fn try_fold_const(&mut self, ct: I::Const) -> Result { + debug_assert!(!ct.has_escaping_bound_vars()); + if !ct.has_ambiguous_aliases() { + return Ok(ct); + } + + // With eager normalization, we should normalize the args of alias before + // normalizing the alias itself. + let ct = ct.try_super_fold_with(self)?; + let ty::ConstKind::Unevaluated(..) = ct.kind() else { return Ok(ct) }; + // FIXME: add an new `Ambiguous` kind to `UnevaluatedConst` as well. + // As a field or a new kind on `ConstKind`? + Ok(ct) + } + + fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + if p.allow_normalization() { + p.try_super_fold_with(self) + } else { + assert!(!p.has_ambiguous_aliases()); + Ok(p) + } + } } diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 47d33985f9d36..2abbabaabf774 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -44,7 +44,8 @@ where lhs.to_alias_term(self.cx()).is_some() || rhs.to_alias_term(self.cx()).is_some() || lhs.is_error() - || rhs.is_error() + || rhs.is_error(), + "{lhs:?} {rhs:?}", ); // Structurally normalize the lhs. diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 7f3627c6db54e..ec495d15b15aa 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -23,6 +23,7 @@ use tracing::{debug, instrument}; use super::trait_goals::TraitGoalProvenVia; use super::{has_only_region_constraints, inspect}; use crate::delegate::SolverDelegate; +use crate::solve::assembly::structural_traits::Ambiguous; use crate::solve::inspect::ProbeKind; use crate::solve::{ BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource, @@ -116,9 +117,10 @@ where ecx.add_goals(GoalSource::ImplWhereBound, requirements); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - Err(_) => { + Err(Ok(Ambiguous)) => { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } + Err(Err(err)) => return Err(err), } }) } @@ -767,7 +769,9 @@ where | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Error(_) => return Ok(()), - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => { + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) + | ty::Bound(..) + | ty::Alias(AliasTy { kind: ty::Ambiguous { .. }, .. }) => { panic!("unexpected self type for `{goal:?}`") } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 660f1ec706aa8..467ed9e2a2355 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -5,8 +5,8 @@ use derive_where::derive_where; use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::{SolverProjectionLangItem, SolverTraitLangItem}; -use rustc_type_ir::solve::SizedTraitKind; use rustc_type_ir::solve::inspect::ProbeKind; +use rustc_type_ir::solve::{NoSolutionOrRerunNonErased, SizedTraitKind}; use rustc_type_ir::{ self as ty, Binder, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable, TypeSuperFoldable, Unnormalized, Upcast as _, elaborate, @@ -50,7 +50,8 @@ where ty::Dynamic(..) | ty::Param(..) | ty::Alias(ty::AliasTy { - kind: ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }, + kind: + ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. } | ty::Ambiguous { .. }, .. }) | ty::Placeholder(..) @@ -878,13 +879,14 @@ pub(in crate::solve) fn predicates_for_object_candidate( param_env: I::ParamEnv, trait_ref: Binder>, object_bounds: I::BoundExistentialPredicates, -) -> Result>, Ambiguous> +) -> Result>, Result> where D: SolverDelegate, I: Interner, { let cx = ecx.cx(); - let trait_ref = ecx.instantiate_binder_with_infer(trait_ref); + let trait_ref = + ecx.instantiate_binder_with_infer(param_env, trait_ref).map_err(|err| Err(err))?; let mut requirements = vec![]; // Elaborating all supertrait outlives obligations here is not soundness critical, // since if we just used the unelaborated set, then the transitive supertraits would @@ -940,12 +942,13 @@ where nested: vec![], }; - let requirements = requirements.try_fold_with(&mut folder)?; - Ok(folder - .nested - .into_iter() - .chain(requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause))) - .collect()) + requirements.try_fold_with(&mut folder).map(|requirements| { + folder + .nested + .into_iter() + .chain(requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause))) + .collect() + }) } struct ReplaceProjectionWith<'a, 'b, I: Interner, D: SolverDelegate> { @@ -971,7 +974,8 @@ where .ecx .probe(|_| ProbeKind::ProjectionCompatibility) .enter_without_propagated_nested_goals(|ecx| { - let source_projection = ecx.instantiate_binder_with_infer(source_projection); + let source_projection = + ecx.instantiate_binder_with_infer(self.param_env, source_projection)?; ecx.eq(self.param_env, source_projection.projection_term, target_projection)?; ecx.try_evaluate_added_goals() }) @@ -985,7 +989,7 @@ where fn try_eagerly_replace_alias( &mut self, alias_term: ty::AliasTerm, - ) -> Result, Ambiguous> { + ) -> Result, Result> { if alias_term.self_ty() != self.self_ty { return Ok(None); } @@ -1009,10 +1013,13 @@ where // If there's more than one projection that we can unify here, then we // need to stall until inference constrains things so that there's only // one choice. - return Err(Ambiguous); + return Err(Ok(Ambiguous)); } - let replacement = self.ecx.instantiate_binder_with_infer(*replacement); + let replacement = self + .ecx + .instantiate_binder_with_infer(self.param_env, *replacement) + .map_err(|e| Err(e))?; self.nested.extend( self.ecx .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term) @@ -1031,13 +1038,16 @@ where D: SolverDelegate, I: Interner, { - type Error = Ambiguous; + type Error = Result; fn cx(&self) -> I { self.ecx.cx() } - fn try_fold_ty(&mut self, ty: I::Ty) -> Result { + fn try_fold_ty( + &mut self, + ty: I::Ty, + ) -> Result> { if let ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Projection { .. }, .. }) = ty.kind() && let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? { diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 0a260f97e5164..8a0f6c9bc74d8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -66,7 +66,8 @@ where ) -> QueryResultOrRerunNonErased { let host_clause = assumption.as_host_effect_clause().unwrap(); - let assumption_trait_pred = ecx.instantiate_binder_with_infer(host_clause); + let assumption_trait_pred = + ecx.instantiate_binder_with_infer(goal.param_env, host_clause)?; ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?; then(ecx) @@ -271,7 +272,8 @@ where ) }), ); - }); + Ok(()) + })?; ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -295,7 +297,8 @@ where let self_ty = goal.predicate.self_ty(); let (inputs_and_output, def_id, args) = structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?; - let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output); + let (inputs, output) = + ecx.instantiate_binder_with_infer(goal.param_env, inputs_and_output)?; // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) @@ -374,7 +377,7 @@ where _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolutionOrRerunNonErased> { - todo!("Iterator is not yet const") + Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) } fn consider_builtin_fused_iterator_candidate( diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 54d306466cf5b..e5725cfbf7457 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -28,6 +28,7 @@ use crate::canonical::{ }; use crate::coherence; use crate::delegate::SolverDelegate; +use crate::normalize::{BinderRenormalizer, NormalizationFolder, NormalizationScope}; use crate::placeholder::BoundVarReplacer; use crate::resolve::eager_resolve_vars; use crate::solve::search_graph::SearchGraph; @@ -879,6 +880,7 @@ where } }) }) + .map_err(Into::into) } // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning @@ -1320,11 +1322,15 @@ where Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?) } + /// Same as the infcx one except we renormalize possible ambiguous aliases + /// in the instantiated binder. pub(super) fn instantiate_binder_with_infer + Copy>( - &self, + &mut self, + param_env: I::ParamEnv, value: ty::Binder, - ) -> T { - self.delegate.instantiate_binder_with_infer(value) + ) -> Result { + let instantiated = self.delegate.instantiate_binder_with_infer(value); + self.renormalize_ambiguous_aliases(param_env, instantiated) } /// `enter_forall`, but takes `&mut self` and passes it back through the @@ -1333,14 +1339,18 @@ where /// The `param_env` is used to *compute* the assumptions of the binder, not *as* the /// assumptions associated with the binder. /// + /// We renormalize possible ambiguous aliases in the instantiated binder + /// before doing anything else. + /// /// FIXME(inherent_associated_types): fix this? pub(super) fn enter_forall_with_assumptions, U>( &mut self, value: ty::Binder, param_env: I::ParamEnv, - f: impl FnOnce(&mut Self, T) -> U, - ) -> U { + f: impl FnOnce(&mut Self, T) -> Result, + ) -> Result { self.delegate.enter_forall(value, |value| { + let value = self.renormalize_ambiguous_aliases(param_env, value)?; let u = self.delegate.universe(); let assumptions = if self.cx().assumptions_on_binders() { self.region_assumptions_for_placeholders_in_universe(value.clone(), u, param_env) @@ -1460,12 +1470,24 @@ where &mut self, param_env: I::ParamEnv, uv: ty::UnevaluatedConst, - ) -> Result, RerunNonErased> { + ) -> Result, NoSolutionOrRerunNonErased> { if self.typing_mode().is_erased_not_coherence() { self.opaque_accesses.rerun_always(RerunReason::EvaluateConst)?; } - Ok(self.delegate.evaluate_const(param_env, uv)) + if let Some(ct) = self.delegate.evaluate_const(param_env, uv) { + Ok(Some(match ct.kind() { + // FIXME(adt_const_params): `evaluate_const` currently does not normalize the type + // of const values. + ty::ConstKind::Value(value) => Const::new_value( + self.cx(), + self.normalize(param_env, ty::Unnormalized::new_wip(value))?, + ), + _ => ct, + })) + } else { + Ok(None) + } } pub(super) fn evaluate_const_and_instantiate_normalizes_to_term( @@ -1731,6 +1753,79 @@ where ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } } + + /// Normalizes aliases in a value as much as we can. + /// + /// Ambiguous goals are added to eval_ctxt. + pub fn normalize>( + &mut self, + param_env: I::ParamEnv, + value: ty::Unnormalized, + ) -> Result { + self.normalize_inner(param_env, value.skip_normalization(), NormalizationScope::All) + } + + /// Only normalizes aliases of `AmbiguousTy` kind. + /// + /// Ambiguous goals are added to eval_ctxt. + /// + /// This should be used after instantiating binders to improve perf, assuming that + /// other normalizable aliases have been normalized before. + pub fn renormalize_ambiguous_aliases>( + &mut self, + param_env: I::ParamEnv, + value: ty::UnnormalizedAmbiguous, + ) -> Result { + self.normalize_inner(param_env, value.do_normalize(), NormalizationScope::AmbiguousAlias) + } + + fn normalize_inner>( + &mut self, + param_env: I::ParamEnv, + value: T, + scope: NormalizationScope, + ) -> Result { + let value = self.delegate.resolve_vars_if_possible(value); + // To drop the mutable borrow of self early. + let (normalized, stalled_goals) = { + let infcx = self.delegate.deref(); + let normalize_term = |alias_term| -> Result<_, NoSolutionOrRerunNonErased> { + let delegate = self.delegate; + let infer_term = self.next_term_infer_of_kind(alias_term); + let predicate = ty::PredicateKind::AliasRelate( + alias_term.into(), + infer_term.into(), + ty::AliasRelationDirection::Equate, + ); + let goal = Goal::new(self.delegate.cx(), param_env, predicate); + let result = self.evaluate_goal(GoalSource::Misc, goal, None)?; + let normalized = delegate.resolve_vars_if_possible(infer_term); + let stalled_goal = match result.certainty { + Certainty::Yes => None, + Certainty::Maybe { .. } => Some(delegate.resolve_vars_if_possible(result.goal)), + }; + Ok((normalized, stalled_goal)) + }; + match scope { + NormalizationScope::All => { + let mut folder = + NormalizationFolder::new(infcx, vec![], Default::default(), normalize_term); + let value = value.try_fold_with(&mut folder)?; + (value, folder.stalled_goals()) + } + NormalizationScope::AmbiguousAlias => { + let mut folder = + BinderRenormalizer::new(infcx, Default::default(), normalize_term); + let value = value.try_fold_with(&mut folder)?; + (value, folder.stalled_goals()) + } + } + }; + + // FIXME: what goal source should we use? + self.add_goals(GoalSource::Misc, stalled_goals); + Ok(normalized) + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index e9a4d7e5919ad..b94b86eac6d5e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -52,6 +52,9 @@ where ty::AliasTermKind::UnevaluatedConst { def_id } => { self.normalize_anon_const(goal, def_id).map_err(Into::into) } + ty::AliasTermKind::AmbiguousTy { .. } => { + unreachable!("`AmbiguousTy` should be eliminated when renormalizing binders") + } } } @@ -189,7 +192,8 @@ where ) -> QueryResultOrRerunNonErased { let cx = ecx.cx(); let projection_pred = assumption.as_projection_clause().unwrap(); - let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); + let assumption_projection_pred = + ecx.instantiate_binder_with_infer(goal.param_env, projection_pred)?; ecx.eq(goal.param_env, goal.predicate.alias, assumption_projection_pred.projection_term)?; ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term); @@ -490,7 +494,8 @@ where else { return ecx.forced_ambiguity(MaybeInfo::AMBIGUOUS); }; - let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); + let (inputs, output) = + ecx.instantiate_binder_with_infer(goal.param_env, tupled_inputs_and_output)?; // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) @@ -541,7 +546,10 @@ where tupled_inputs_ty, output_coroutine_ty, coroutine_return_ty, - } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine); + } = ecx.instantiate_binder_with_infer( + goal.param_env, + tupled_inputs_and_output_and_coroutine, + )?; // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index f3ace5a70c69c..f81393dbfa099 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -192,7 +192,8 @@ where return Self::match_assumption(ecx, goal, meta_sized_clause, then); } - let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause); + let assumption_trait_pred = + ecx.instantiate_binder_with_infer(goal.param_env, trait_clause)?; ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?; then(ecx) @@ -381,7 +382,8 @@ where else { return ecx.forced_ambiguity(MaybeInfo::AMBIGUOUS); }; - let (inputs, output) = ecx.instantiate_binder_with_infer(tupled_inputs_and_output); + let (inputs, output) = + ecx.instantiate_binder_with_infer(goal.param_env, tupled_inputs_and_output)?; // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) @@ -423,7 +425,10 @@ where tupled_inputs_ty, output_coroutine_ty, coroutine_return_ty: _, - } = ecx.instantiate_binder_with_infer(tupled_inputs_and_output_and_coroutine); + } = ecx.instantiate_binder_with_infer( + goal.param_env, + tupled_inputs_and_output_and_coroutine, + )?; // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) @@ -1076,8 +1081,10 @@ where target_projection, param_env, |ecx, target_projection| { - let source_projection = - ecx.instantiate_binder_with_infer(source_projection); + let source_projection = ecx.instantiate_binder_with_infer( + param_env, + source_projection, + )?; ecx.eq(param_env, source_projection, target_projection)?; ecx.try_evaluate_added_goals() }, @@ -1100,7 +1107,7 @@ where param_env, |ecx, target_principal| { let source_principal = - ecx.instantiate_binder_with_infer(source_principal); + ecx.instantiate_binder_with_infer(param_env, source_principal)?; ecx.eq(param_env, source_principal, target_principal)?; ecx.try_evaluate_added_goals() }, @@ -1131,8 +1138,8 @@ where target_projection, param_env, |ecx, target_projection| { - let source_projection = - ecx.instantiate_binder_with_infer(source_projection); + let source_projection = ecx + .instantiate_binder_with_infer(param_env, source_projection)?; ecx.eq(param_env, source_projection, target_projection)?; ecx.try_evaluate_added_goals() }, @@ -1365,13 +1372,14 @@ where constituent_tys(ecx, goal.predicate.self_ty())?, goal.param_env, |ecx, tys| { - tys.into_iter() + Ok(tys + .into_iter() .map(|ty| { goal.with(ecx.cx(), goal.predicate.with_replaced_self_ty(ecx.cx(), ty)) }) - .collect::>() + .collect::>()) }, - ); + )?; ecx.add_goals(GoalSource::ImplWhereBound, goals); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f6765d604acb3..67e9bb39d0eea 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1580,10 +1580,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let span = tcx.def_span(def_id); let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id()); - let sig = tcx.liberate_late_bound_regions( - def_id.to_def_id(), - tcx.fn_sig(def_id).instantiate(tcx, fresh_args).skip_norm_wip(), - ); + let sig = tcx + .liberate_late_bound_regions( + def_id.to_def_id(), + tcx.fn_sig(def_id).instantiate(tcx, fresh_args), + ) + .skip_norm_wip(); let mut cause = ObligationCause::misc(span, def_id); let sig = ocx.normalize(&cause, param_env, Unnormalized::new_wip(sig)); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6a792e5a803b7..1c80da38df889 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -243,7 +243,7 @@ where match kind { ty::Inherent { .. } | ty::Projection { .. } => "associated type", ty::Free { .. } => "type alias", - ty::Opaque { .. } => unreachable!(), + ty::Opaque { .. } | ty::Ambiguous { .. } => unreachable!(), }, &LazyDefPathStr { def_id, tcx }, )); @@ -308,7 +308,9 @@ where | ty::Bound(..) | ty::Error(_) | ty::CoroutineWitness(..) => {} - ty::Placeholder(..) | ty::Infer(..) => { + ty::Placeholder(..) + | ty::Infer(..) + | ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) => { bug!("unexpected type: {:?}", ty) } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index c4f1da14da23e..fbbf833a87aa4 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -20,6 +20,7 @@ impl<'tcx> Stable<'tcx> for ty::AliasTyKind<'tcx> { ty::Inherent { .. } => crate::ty::AliasKind::Inherent, ty::Opaque { .. } => crate::ty::AliasKind::Opaque, ty::Free { .. } => crate::ty::AliasKind::Free, + ty::Ambiguous { .. } => unreachable!(), } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 3ec97ce76ef07..689dd04526e46 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -66,9 +66,9 @@ pub fn find_param_with_region<'tcx>( let owner_id = tcx.hir_body_owner(body.id()); let fn_decl = tcx.hir_fn_decl_by_hir_id(owner_id)?; - let poly_fn_sig = tcx.fn_sig(id).instantiate_identity().skip_norm_wip(); + let poly_fn_sig = tcx.fn_sig(id).instantiate_identity(); - let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig); + let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig).skip_norm_wip(); body.params .iter() .take(if fn_sig.c_variadic() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 9d2eb42496e2f..3ed1135d20942 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -738,6 +738,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ty::Free { .. } => format!("the type alias `{bound_kind}`"), ty::Opaque { .. } => format!("the opaque type `{bound_kind}`"), + ty::Ambiguous { .. } => format!("the ambiguous alias `{bound_kind}`"), }, }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 108262d507ef7..6dabb32116393 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -40,93 +40,107 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( let impl_may_apply = |impl_def_id| { let ocx = ObligationCtxt::new(infcx); - infcx.enter_forall(obligation.predicate, |placeholder_obligation| { - let obligation_trait_ref = ocx.normalize( - &ObligationCause::dummy(), - param_env, - Unnormalized::new_wip(placeholder_obligation.trait_ref), - ); - - let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); - let impl_trait_ref = - tcx.impl_trait_ref(impl_def_id).instantiate(tcx, impl_args).skip_norm_wip(); - let impl_trait_ref = ocx.normalize( - &ObligationCause::dummy(), - param_env, - Unnormalized::new_wip(impl_trait_ref), - ); - - if let Err(_) = - ocx.eq(&ObligationCause::dummy(), param_env, obligation_trait_ref, impl_trait_ref) - { - return false; - } + ocx.enter_forall( + &ObligationCause::dummy(), + param_env, + obligation.predicate, + |placeholder_obligation| { + let obligation_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + Unnormalized::new_wip(placeholder_obligation.trait_ref), + ); - let impl_trait_header = tcx.impl_trait_header(impl_def_id); - let impl_polarity = impl_trait_header.polarity; + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = + tcx.impl_trait_ref(impl_def_id).instantiate(tcx, impl_args).skip_norm_wip(); + let impl_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + Unnormalized::new_wip(impl_trait_ref), + ); - match (impl_polarity, predicate_polarity) { - (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive) - | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {} - _ => return false, - } + if let Err(_) = ocx.eq( + &ObligationCause::dummy(), + param_env, + obligation_trait_ref, + impl_trait_ref, + ) { + return false; + } - let obligations = tcx - .predicates_of(impl_def_id) - .instantiate(tcx, impl_args) - .into_iter() - .map(|(predicate, _)| { - Obligation::new( - tcx, - ObligationCause::dummy(), - param_env, - predicate.skip_norm_wip(), - ) - }) - // Kinda hacky, but let's just throw away obligations that overflow. - // This may reduce the accuracy of this check (if the obligation guides - // inference or it actually resulted in error after others are processed) - // ... but this is diagnostics code. - .filter(|obligation| { - infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok() - }); - ocx.register_obligations(obligations); - - ocx.try_evaluate_obligations().is_empty() - }) + let impl_trait_header = tcx.impl_trait_header(impl_def_id); + let impl_polarity = impl_trait_header.polarity; + + match (impl_polarity, predicate_polarity) { + (ty::ImplPolarity::Positive, ty::PredicatePolarity::Positive) + | (ty::ImplPolarity::Negative, ty::PredicatePolarity::Negative) => {} + _ => return false, + } + + let obligations = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_args) + .into_iter() + .map(|(predicate, _)| { + Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + predicate.skip_norm_wip(), + ) + }) + // Kinda hacky, but let's just throw away obligations that overflow. + // This may reduce the accuracy of this check (if the obligation guides + // inference or it actually resulted in error after others are processed) + // ... but this is diagnostics code. + .filter(|obligation| { + infcx.next_trait_solver() || infcx.evaluate_obligation(obligation).is_ok() + }); + ocx.register_obligations(obligations); + + ocx.try_evaluate_obligations().is_empty() + }, + ) }; let param_env_candidate_may_apply = |poly_trait_predicate: ty::PolyTraitPredicate<'tcx>| { - let ocx = ObligationCtxt::new(infcx); - infcx.enter_forall(obligation.predicate, |placeholder_obligation| { - let obligation_trait_ref = ocx.normalize( - &ObligationCause::dummy(), - param_env, - Unnormalized::new_wip(placeholder_obligation.trait_ref), - ); - - let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - poly_trait_predicate, - ); - let param_env_trait_ref = ocx.normalize( - &ObligationCause::dummy(), - param_env, - Unnormalized::new_wip(param_env_predicate.trait_ref), - ); - - if let Err(_) = ocx.eq( - &ObligationCause::dummy(), - param_env, - obligation_trait_ref, - param_env_trait_ref, - ) { - return false; - } + let ocx: ObligationCtxt<'_, '_> = ObligationCtxt::new(infcx); + ocx.enter_forall( + &ObligationCause::dummy(), + param_env, + obligation.predicate, + |placeholder_obligation| { + let obligation_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + Unnormalized::new_wip(placeholder_obligation.trait_ref), + ); + + let param_env_predicate = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), + BoundRegionConversionTime::HigherRankedType, + param_env, + poly_trait_predicate, + ); + let param_env_trait_ref = ocx.normalize( + &ObligationCause::dummy(), + param_env, + Unnormalized::new_wip(param_env_predicate.trait_ref), + ); + + if let Err(_) = ocx.eq( + &ObligationCause::dummy(), + param_env, + obligation_trait_ref, + param_env_trait_ref, + ) { + return false; + } - ocx.try_evaluate_obligations().is_empty() - }) + ocx.try_evaluate_obligations().is_empty() + }, + ) }; let mut ambiguities = Vec::new(); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4b67cada078a4..05b633167c127 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -833,11 +833,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { diag.downgrade_to_delayed_bug(); } - if let Ok(Some(ImplSource::UserDefined(impl_data))) = - self.enter_forall(trait_ref, |trait_ref_for_select| { + let ocx = ObligationCtxt::new(self); + let impl_source = ocx.enter_forall( + &ObligationCause::dummy(), + obligation.param_env, + trait_ref, + |trait_ref_for_select| { SelectionContext::new(self).select(&obligation.with(self.tcx, trait_ref_for_select)) - }) - { + }, + ); + if let Ok(Some(ImplSource::UserDefined(impl_data))) = impl_source { let impl_did = impl_data.impl_def_id; let trait_did = trait_ref.def_id(); let impl_span = self.tcx.def_span(impl_did); @@ -958,11 +963,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Verify that the arguments are compatible. If the signature is // mismatched, then we have a totally different error to report. - if self.enter_forall(found_args, |found_args| { - self.enter_forall(expected_args, |expected_args| { - !self.can_eq(obligation.param_env, expected_args, found_args) - }) - }) { + let ocx = ObligationCtxt::new(self); + if ocx.enter_forall( + &ObligationCause::dummy(), + obligation.param_env, + found_args, + |found_args| { + ocx.enter_forall( + &ObligationCause::dummy(), + obligation.param_env, + expected_args, + |expected_args| !self.can_eq(obligation.param_env, expected_args, found_args), + ) + }, + ) { return None; } @@ -1402,7 +1416,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut pred = obligation.predicate.as_trait_clause(); while let Some((next_code, next_pred)) = code.parent_with_predicate() { if let Some(pred) = pred { - self.enter_forall(pred, |pred| { + let ocx = ObligationCtxt::new(self); + ocx.enter_forall(&ObligationCause::dummy(), obligation.param_env, pred, |pred| { let ty = self.tcx.short_string(pred.self_ty(), diag.long_ty_path()); let trait_path = self .tcx @@ -1421,6 +1436,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_trait( &self, + ocx: &ObligationCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, goal: ty::TraitPredicate<'tcx>, assumption: ty::PolyTraitPredicate<'tcx>, @@ -1430,9 +1446,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; } - let trait_assumption = self.instantiate_binder_with_fresh_vars( - DUMMY_SP, + let trait_assumption = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), infer::BoundRegionConversionTime::HigherRankedType, + param_env, assumption, ); @@ -1441,13 +1458,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_host_effect( &self, + ocx: &ObligationCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, goal: ty::HostEffectPredicate<'tcx>, assumption: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, ) -> bool { - let assumption = self.instantiate_binder_with_fresh_vars( - DUMMY_SP, + let assumption = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), infer::BoundRegionConversionTime::HigherRankedType, + param_env, assumption, ); @@ -1466,13 +1485,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_projection( &self, + ocx: &ObligationCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, goal: ty::ProjectionPredicate<'tcx>, assumption: ty::PolyProjectionPredicate<'tcx>, ) -> bool { - let assumption = self.instantiate_binder_with_fresh_vars( - DUMMY_SP, + let assumption = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), infer::BoundRegionConversionTime::HigherRankedType, + param_env, assumption, ); @@ -1500,23 +1521,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let param_env = error.param_env; + let ocx = ObligationCtxt::new(self); if let Some(error) = error.predicate.as_trait_clause() { - self.enter_forall(error, |error| { + ocx.enter_forall(&ObligationCause::dummy(), param_env, error, |error| { elaborate(self.tcx, std::iter::once(cond.predicate)) .filter_map(|implied| implied.as_trait_clause()) - .any(|implied| self.can_match_trait(param_env, error, implied)) + .any(|implied| self.can_match_trait(&ocx, param_env, error, implied)) }) } else if let Some(error) = Self::as_host_effect_clause(error.predicate) { - self.enter_forall(error, |error| { + ocx.enter_forall(&ObligationCause::dummy(), param_env, error, |error| { elaborate(self.tcx, std::iter::once(cond.predicate)) .filter_map(Self::as_host_effect_clause) - .any(|implied| self.can_match_host_effect(param_env, error, implied)) + .any(|implied| self.can_match_host_effect(&ocx, param_env, error, implied)) }) } else if let Some(error) = error.predicate.as_projection_clause() { - self.enter_forall(error, |error| { + ocx.enter_forall(&ObligationCause::dummy(), param_env, error, |error| { elaborate(self.tcx, std::iter::once(cond.predicate)) .filter_map(|implied| implied.as_projection_clause()) - .any(|implied| self.can_match_projection(param_env, error, implied)) + .any(|implied| self.can_match_projection(&ocx, param_env, error, implied)) }) } else { false @@ -1545,14 +1567,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => { let ocx = ObligationCtxt::new(self); - let data = self.instantiate_binder_with_fresh_vars( - obligation.cause.span, + let data = ocx.instantiate_binder_with_fresh_vars( + &obligation.cause, infer::BoundRegionConversionTime::HigherRankedType, + obligation.param_env, bound_predicate.rebind(data), ); let unnormalized_term = data.projection_term.to_term(self.tcx); - // FIXME(-Znext-solver): For diagnostic purposes, it would be nice - // to deeply normalize this type. let normalized_term = ocx.normalize( &obligation.cause, obligation.param_env, @@ -1606,7 +1627,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(lhs) = lhs.to_alias_term(self.tcx) && let ty::AliasTermKind::ProjectionTy { .. } - | ty::AliasTermKind::ProjectionConst { .. } = lhs.kind(self.tcx) + | ty::AliasTermKind::ProjectionConst { .. } = lhs.kind && let Some((better_type_err, expected_term)) = derive_better_type_error(lhs, rhs) { @@ -1616,7 +1637,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } else if let Some(rhs) = rhs.to_alias_term(self.tcx) && let ty::AliasTermKind::ProjectionTy { .. } - | ty::AliasTermKind::ProjectionConst { .. } = rhs.kind(self.tcx) + | ty::AliasTermKind::ProjectionConst { .. } = rhs.kind && let Some((better_type_err, expected_term)) = derive_better_type_error(rhs, lhs) { @@ -1686,7 +1707,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let trait_ref = self.enter_forall_and_leak_universe( + let ocx = ObligationCtxt::new(self); + let trait_ref = ocx.enter_forall_and_leak_universe( + &ObligationCause::dummy(), + obligation.param_env, predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), ); let Ok(Some(ImplSource::UserDefined(impl_data))) = @@ -1861,7 +1885,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty::CoroutineClosure(..) => Some(21), ty::Pat(..) => Some(22), ty::UnsafeBinder(..) => Some(23), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, + ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) + | ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(..) + | ty::Error(_) => None, } } @@ -2071,11 +2099,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // that failed. This should uncover a better hint for what *is* implemented. if self.probe(|_| { let ocx = ObligationCtxt::new(self); - - self.enter_forall(trait_pred, |obligation_trait_ref| { + let cause = &ObligationCause::dummy(); + ocx.enter_forall(&cause, param_env, trait_pred, |obligation_trait_ref| { let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id); let impl_trait_ref = ocx.normalize( - &ObligationCause::dummy(), + &cause, param_env, ty::EarlyBinder::bind(single.trait_ref).instantiate(self.tcx, impl_args), ); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 26139926dae41..ffd8e8dd88525 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -713,9 +713,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - // We `instantiate_bound_regions_with_erased` here because `make_subregion` does not handle - // `ReBound`, and we don't particularly care about the regions. - let real_ty = self.tcx.instantiate_bound_regions_with_erased(real_trait_pred.self_ty()); + let ocx = ObligationCtxt::new(self); + let real_ty = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), + BoundRegionConversionTime::HigherRankedType, + obligation.param_env, + real_trait_pred.self_ty(), + ); if !self.can_eq(obligation.param_env, real_ty, arg_ty) { return false; } @@ -1014,9 +1018,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; } - let self_ty = self.instantiate_binder_with_fresh_vars( - DUMMY_SP, + let ocx = ObligationCtxt::new(self); + let self_ty = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), BoundRegionConversionTime::FnCall, + obligation.param_env, trait_pred.self_ty(), ); @@ -1345,8 +1351,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { + let ocx = ObligationCtxt::new(self); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - self.enter_forall(self_ty, |ty: Ty<'_>| { + ocx.enter_forall(&ObligationCause::dummy(), obligation.param_env, self_ty, |ty: Ty<'_>| { let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else { return false; }; @@ -1558,18 +1565,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let output = self.instantiate_binder_with_fresh_vars( - DUMMY_SP, + let ocx = ObligationCtxt::new(self); + let output = ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), BoundRegionConversionTime::FnCall, + param_env, output, ); let inputs = inputs .skip_binder() .iter() .map(|ty| { - self.instantiate_binder_with_fresh_vars( - DUMMY_SP, + ocx.instantiate_binder_with_fresh_vars( + &ObligationCause::dummy(), BoundRegionConversionTime::FnCall, + param_env, inputs.rebind(*ty), ) }) @@ -4845,10 +4855,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let Some(failed_pred) = failed_pred.as_trait_clause() && where_pred.def_id() == failed_pred.def_id() { - self.enter_forall(where_pred, |where_pred| { - let failed_pred = self.instantiate_binder_with_fresh_vars( - expr.span, + let ocx = ObligationCtxt::new(self); + let cause = ObligationCause::dummy(); + ocx.enter_forall(&cause, param_env, where_pred, |where_pred| { + let failed_pred = ocx.instantiate_binder_with_fresh_vars( + &cause, BoundRegionConversionTime::FnCall, + param_env, failed_pred, ); @@ -4857,7 +4870,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { for (expected, actual) in zipped { self.probe(|_| { match self - .at(&ObligationCause::misc(expr.span, body_id), param_env) + .at(&cause, param_env) // Doesn't actually matter if we define opaque types here, this is just used for // diagnostics, and the result is never kept around. .eq(DefineOpaqueTypes::Yes, expected, actual) @@ -5588,7 +5601,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { self.probe(|_| { let ocx = ObligationCtxt::new(self); - self.enter_forall(pred, |pred| { + ocx.enter_forall(&ObligationCause::dummy(), param_env, pred, |pred| { let pred = ocx.normalize( &ObligationCause::dummy(), param_env, @@ -6060,14 +6073,23 @@ fn hint_missing_borrow<'tcx>( return; } + let ocx = ObligationCtxt::new(infcx); let found_args = match found.kind() { - ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()), + ty::FnPtr(sig_tys, _) => { + ocx.enter_forall(&ObligationCause::dummy(), param_env, *sig_tys, |sig_tys| { + sig_tys.inputs().iter() + }) + } kind => { span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind) } }; let expected_args = match expected.kind() { - ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()), + ty::FnPtr(sig_tys, _) => { + ocx.enter_forall(&ObligationCause::dummy(), param_env, *sig_tys, |sig_tys| { + sig_tys.inputs().iter() + }) + } kind => { span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind) } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 12dfe730aa303..139562ccd79c1 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -9,7 +9,7 @@ use rustc_infer::traits::{ }; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_next_trait_solver::solve::{GoalEvaluation, MaybeInfo, SolverDelegateEvalExt as _}; use tracing::{instrument, trace}; @@ -58,17 +58,13 @@ pub(super) fn fulfillment_error_for_no_solution<'tcx>( ty::PredicateKind::AliasRelate(_, _, _) => { FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) } - ty::PredicateKind::Subtype(pred) => { - let (a, b) = infcx.enter_forall_and_leak_universe( - obligation.predicate.kind().rebind((pred.a, pred.b)), - ); + ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => { + assert!(!(a, b).has_escaping_bound_vars()); let expected_found = ExpectedFound::new(a, b); FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) } - ty::PredicateKind::Coerce(pred) => { - let (a, b) = infcx.enter_forall_and_leak_universe( - obligation.predicate.kind().rebind((pred.a, pred.b)), - ); + ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + assert!(!(a, b).has_escaping_bound_vars()); let expected_found = ExpectedFound::new(b, a); FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) } @@ -393,7 +389,6 @@ impl<'tcx> BestObligation<'tcx> { &mut self, goal: &inspect::InspectGoal<'_, 'tcx>, ) -> ControlFlow> { - let tcx = goal.infcx().tcx; let pred_kind = goal.goal().predicate.kind(); match pred_kind.no_bound_vars() { @@ -402,7 +397,7 @@ impl<'tcx> BestObligation<'tcx> { } Some(ty::PredicateKind::NormalizesTo(pred)) if let ty::AliasTermKind::ProjectionTy { .. } - | ty::AliasTermKind::ProjectionConst { .. } = pred.alias.kind(tcx) => + | ty::AliasTermKind::ProjectionConst { .. } = pred.alias.kind => { self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?; self.detect_non_well_formed_assoc_item(goal, pred.alias)?; @@ -469,7 +464,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } ty::PredicateKind::NormalizesTo(normalizes_to) if matches!( - normalizes_to.alias.kind(tcx), + normalizes_to.alias.kind, ty::AliasTermKind::ProjectionTy { .. } | ty::AliasTermKind::ProjectionConst { .. } ) => diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 7c21dc161a1ec..b6c7630f14055 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::infer::at::At; -use rustc_infer::traits::solve::Goal; +use rustc_infer::traits::solve::{Goal, NoSolution}; use rustc_infer::traits::{ FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, }; @@ -9,7 +9,9 @@ use rustc_middle::ty::{ self, Binder, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, Unnormalized, }; -use rustc_next_trait_solver::normalize::NormalizationFolder; +use rustc_next_trait_solver::normalize::{ + BinderRenormalizer, NormalizationFolder, NormalizationScope, +}; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use super::{FulfillmentCtxt, NextSolverError}; @@ -17,11 +19,15 @@ use crate::solve::{Certainty, SolverDelegate}; use crate::traits::{BoundVarReplacer, ScrubbedTraitError}; /// see `normalize_with_universes`. -pub fn normalize<'tcx, T>(at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>) -> Normalized<'tcx, T> +pub fn normalize<'tcx, T>( + at: At<'_, 'tcx>, + value: Unnormalized<'tcx, T>, + scope: NormalizationScope, +) -> Normalized<'tcx, T> where T: TypeFoldable>, { - normalize_with_universes(at, value, vec![]) + normalize_with_universes(at, value, vec![], scope) } /// Like `deeply_normalize`, but we handle ambiguity and inference variables in this routine. @@ -35,6 +41,7 @@ fn normalize_with_universes<'tcx, T>( at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>, universes: Vec>, + scope: NormalizationScope, ) -> Normalized<'tcx, T> where T: TypeFoldable>, @@ -43,27 +50,42 @@ where let value = value.skip_normalization(); let value = infcx.resolve_vars_if_possible(value); let original_value = value.clone(); - let mut folder = - NormalizationFolder::new(infcx, universes.clone(), Default::default(), |alias_term| { - let delegate = <&SolverDelegate<'tcx>>::from(infcx); - let infer_term = delegate.next_term_var_of_kind(alias_term, at.cause.span); - let predicate = ty::PredicateKind::AliasRelate( - alias_term.into(), - infer_term.into(), - ty::AliasRelationDirection::Equate, + let normalize_term = |alias_term| -> Result<_, NoSolution> { + let delegate = <&SolverDelegate<'tcx>>::from(infcx); + let infer_term = delegate.next_term_var_of_kind(alias_term, at.cause.span); + let predicate = ty::PredicateKind::AliasRelate( + alias_term.into(), + infer_term.into(), + ty::AliasRelationDirection::Equate, + ); + let goal = Goal::new(infcx.tcx, at.param_env, predicate); + let result = delegate.evaluate_root_goal(goal, at.cause.span, None)?; + let normalized = infcx.resolve_vars_if_possible(infer_term); + let stalled_goal = match result.certainty { + Certainty::Yes => None, + Certainty::Maybe { .. } => Some(infcx.resolve_vars_if_possible(result.goal)), + }; + Ok((normalized, stalled_goal)) + }; + let (normalized, stalled_goals) = match scope { + NormalizationScope::All => { + let mut folder = NormalizationFolder::new( + infcx, + universes.clone(), + Default::default(), + normalize_term, ); - let goal = Goal::new(infcx.tcx, at.param_env, predicate); - let result = delegate.evaluate_root_goal(goal, at.cause.span, None)?; - let normalized = infcx.resolve_vars_if_possible(infer_term); - let stalled_goal = match result.certainty { - Certainty::Yes => None, - Certainty::Maybe { .. } => Some(infcx.resolve_vars_if_possible(result.goal)), - }; - Ok((normalized, stalled_goal)) - }); - if let Ok(value) = value.try_fold_with(&mut folder) { - let obligations = folder - .stalled_goals() + let normalized = value.try_fold_with(&mut folder); + (normalized, folder.stalled_goals()) + } + NormalizationScope::AmbiguousAlias => { + let mut folder = BinderRenormalizer::new(infcx, Default::default(), normalize_term); + let normalized = value.try_fold_with(&mut folder); + (normalized, folder.stalled_goals()) + } + }; + if let Ok(value) = normalized { + let obligations = stalled_goals .into_iter() .map(|goal| { Obligation::new(infcx.tcx, at.cause.clone(), goal.param_env, goal.predicate) @@ -122,8 +144,13 @@ impl<'me, 'tcx> TypeFolder> for ReplaceAliasWithInfer<'me, 'tcx> { return ty; } - let ty = ty.super_fold_with(self); - let ty::Alias(..) = *ty.kind() else { return ty }; + let ty = match ty.kind() { + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, args, .. }) => { + return args.type_at(0).fold_with(self); + } + ty::Alias(_) => ty.super_fold_with(self), + _ => return ty.super_fold_with(self), + }; if ty.has_escaping_bound_vars() { let (replaced, ..) = @@ -152,6 +179,10 @@ impl<'me, 'tcx> TypeFolder> for ReplaceAliasWithInfer<'me, 'tcx> { self.term_to_infer(ct.into()).expect_const() } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() { p.super_fold_with(self) } else { p } + } } /// Deeply normalize all aliases in `value`. This does not handle inference and expects @@ -210,7 +241,8 @@ where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, { - let Normalized { value, obligations } = normalize_with_universes(at, value, universes); + let Normalized { value, obligations } = + normalize_with_universes(at, value, universes, NormalizationScope::All); let mut fulfill_cx = FulfillmentCtxt::new(at.infcx); for pred in obligations { @@ -233,6 +265,10 @@ where return Err(errors); } + assert!( + !value.has_ambiguous_aliases(), + "unexpected ambig aliases after normalizing: {value:?}" + ); Ok((value, stalled_coroutine_goals)) } @@ -285,4 +321,8 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, Err(_) => ct.super_fold_with(self), } } + + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() { p.super_fold_with(self) } else { p } + } } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 646945990a1d5..afe7cb4b36e96 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -739,7 +739,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); - selcx.infcx.enter_forall(binder, |pred| { + selcx.infcx.enter_forall_old_solver(binder, |pred| { selcx.infcx.register_region_outlives_constraint(pred, ty::VisibleForLeakCheck::Yes,&dummy_cause); }); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 49cc2833cd978..06852149e88ca 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -748,7 +748,12 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { // For bound predicates we simply call `infcx.enter_forall` // and then prove the resulting predicate as a nested goal. let Goal { param_env, predicate } = goal.goal(); - let predicate_kind = goal.infcx().enter_forall_and_leak_universe(predicate.kind()); + let ocx = ObligationCtxt::new(infcx); + let predicate_kind = ocx.enter_forall_and_leak_universe( + &ObligationCause::dummy(), + param_env, + predicate.kind(), + ); let trait_ref = match predicate_kind { ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.trait_ref, ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index b81d466f9106a..dd73551149283 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -416,6 +416,8 @@ fn virtual_call_violations_for_method<'tcx>( trait_def_id: DefId, method: ty::AssocItem, ) -> Vec { + // FIXME(#155345): Pretty much all of this function intentionally uses + // unnormalized types and should track this properly. let sig = tcx.fn_sig(method.def_id).instantiate_identity().skip_norm_wip(); // The method's first parameter must be named `self` @@ -488,7 +490,9 @@ fn virtual_call_violations_for_method<'tcx>( errors.push(MethodViolation::Generic); } - let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); + let receiver_ty = tcx + .liberate_late_bound_regions(method.def_id, ty::Unnormalized::new_wip(sig.input(0))) + .skip_norm_wip(); // `self: Self` can't be dispatched on. // However, this is considered dyn compatible. We allow it as a special case here. @@ -924,7 +928,8 @@ fn contains_illegal_impl_trait_in_trait<'tcx>( fn_def_id: DefId, ty: ty::Binder<'tcx, Ty<'tcx>>, ) -> Option { - let ty = tcx.liberate_late_bound_regions(fn_def_id, ty); + let ty = + tcx.liberate_late_bound_regions(fn_def_id, ty::Unnormalized::new_wip(ty)).skip_norm_wip(); if tcx.asyncness(fn_def_id).is_async() { // Rendering the error as a separate `async-specific` message is better. diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 8681a92f57ecb..b7924c1e18356 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -89,7 +89,7 @@ fn match_candidate<'tcx>( return Err(NoSolution); } - let mut candidate = selcx.infcx.instantiate_binder_with_fresh_vars( + let mut candidate = selcx.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, candidate, diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 6cddd79544906..2f83d7b95dd9f 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -8,7 +8,10 @@ use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; +use rustc_infer::infer::{ + BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, + TypeTrace, +}; use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; @@ -119,6 +122,16 @@ where self.register_infer_ok_obligations(infer_ok) } + pub fn renormalize_ambiguous_aliases>>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::UnnormalizedAmbiguous<'tcx, T>, + ) -> T { + let infer_ok = self.infcx.at(cause, param_env).renormalize_ambiguous_aliases(value); + self.register_infer_ok_obligations(infer_ok) + } + pub fn eq>( &self, cause: &ObligationCause<'tcx>, @@ -351,6 +364,45 @@ where self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) } + pub fn enter_forall>, U>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.infcx.enter_forall(value, |value| { + f(self.renormalize_ambiguous_aliases(cause, param_env, value)) + }) + } + + pub fn enter_forall_and_leak_universe( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + binder: ty::Binder<'tcx, T>, + ) -> T + where + T: TypeFoldable>, + { + let value = self.infcx.enter_forall_and_leak_universe(binder); + self.renormalize_ambiguous_aliases(cause, param_env, value) + } + + pub fn instantiate_binder_with_fresh_vars( + &self, + cause: &ObligationCause<'tcx>, + lbrct: BoundRegionConversionTime, + param_env: ty::ParamEnv<'tcx>, + value: ty::Binder<'tcx, T>, + ) -> T + where + T: TypeFoldable> + Copy, + { + let value = self.infcx.instantiate_binder_with_fresh_vars(cause.span, lbrct, value); + self.renormalize_ambiguous_aliases(cause, param_env, value) + } + pub fn structurally_normalize_ty( &self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index ce8f05637f9a6..c67491ee94f9a 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -450,7 +450,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // pred instead of just instantiating it with placeholders b/c of // higher-ranked implied bound issues in the old solver. | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => { - let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe(binder)); + let pred = ty::Binder::dummy(infcx.enter_forall_and_leak_universe_old_solver(binder)); let mut obligations = PredicateObligations::with_capacity(1); obligations.push(obligation.with(infcx.tcx, pred)); diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 84dbd53de83f2..12ad674143cf6 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{ self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingMode, Unnormalized, }; +use rustc_next_trait_solver::normalize::NormalizationScope; use tracing::{debug, instrument}; use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project}; @@ -33,7 +34,8 @@ impl<'tcx> At<'_, 'tcx> { value: Unnormalized<'tcx, T>, ) -> InferOk<'tcx, T> { if self.infcx.next_trait_solver() { - let Normalized { value, obligations } = crate::solve::normalize(*self, value); + let Normalized { value, obligations } = + crate::solve::normalize(*self, value, NormalizationScope::All); InferOk { value, obligations } } else { let value = value.skip_normalization(); @@ -44,6 +46,26 @@ impl<'tcx> At<'_, 'tcx> { } } + /// Normalize aliases of `Ambiguous` kind in a value. + /// + /// We should use this after instantiating binders to improve perf. + fn renormalize_ambiguous_aliases>>( + &self, + value: ty::UnnormalizedAmbiguous<'tcx, T>, + ) -> InferOk<'tcx, T> { + if self.infcx.next_trait_solver() { + let Normalized { value, obligations } = crate::solve::normalize( + *self, + Unnormalized::new(value.do_normalize()), + NormalizationScope::AmbiguousAlias, + ); + InferOk { value, obligations } + } else { + // We won't have ambiguous aliases in old solver so no-op. + InferOk { value: value.no_ambiguous_aliases(), obligations: Default::default() } + } + } + /// Deeply normalizes `value`, replacing all aliases which can by normalized in /// the current environment. In the new solver this errors in case normalization /// fails or is ambiguous. @@ -441,6 +463,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx ty::Projection { .. } => self.normalize_trait_projection(data.into()).expect_type(), ty::Inherent { .. } => self.normalize_inherent_projection(data.into()).expect_type(), ty::Free { .. } => self.normalize_free_alias(data.into()).expect_type(), + ty::Ambiguous { .. } => unreachable!(), } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 900d55cc556fc..003c274e076d8 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -178,7 +178,8 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( ) -> ProjectAndUnifyResult<'tcx> { let infcx = selcx.infcx; let r = infcx.commit_if_ok(|_snapshot| { - let placeholder_predicate = infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate); match project_and_unify_term(selcx, &placeholder_obligation) { @@ -473,6 +474,7 @@ fn normalize_to_error<'a, 'tcx>( | ty::AliasTermKind::ProjectionConst { .. } => { selcx.infcx.next_const_var(cause.span).into() } + ty::AliasTermKind::AmbiguousTy { .. } => unreachable!(), }; let mut obligations = PredicateObligations::new(); obligations.push(Obligation { @@ -1909,7 +1911,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let cause = &obligation.cause; let param_env = obligation.param_env; - let cache_entry = infcx.instantiate_binder_with_fresh_vars( + let cache_entry = infcx.instantiate_binder_with_fresh_vars_old_solver( cause.span, BoundRegionConversionTime::HigherRankedType, poly_cache_entry, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e8c5d10c78ce3..6410e7ccd59a0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -259,6 +259,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { kind @ (ty::Projection { .. } | ty::Inherent { .. } | ty::Free { .. }) => self .try_fold_free_or_assoc(ty::AliasTerm::new(self.cx(), kind.into(), data.args))? .expect_type(), + ty::Ambiguous { .. } => unreachable!(), }; self.cache.insert(ty, res); @@ -339,6 +340,7 @@ impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { tcx.normalize_canonicalized_inherent_projection(c_term) } kind @ (ty::AliasTermKind::OpaqueTy { .. } + | ty::AliasTermKind::AmbiguousTy { .. } | ty::AliasTermKind::UnevaluatedConst { .. }) => { unreachable!("did not expect {kind:?} due to match arm above") } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3b599db8ff1c2..486cc3cb8b3d0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -207,7 +207,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.probe(|_| { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); let placeholder_trait_predicate = - self.infcx.enter_forall_and_leak_universe(poly_trait_predicate); + self.infcx.enter_forall_and_leak_universe_old_solver(poly_trait_predicate); // The bounds returned by `item_bounds` may contain duplicates after // normalization, so try to deduplicate when possible to avoid @@ -863,6 +863,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) => unreachable!(), + ty::CoroutineWitness(..) => { candidates.vec.push(AutoImplCandidate); } @@ -922,57 +924,60 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.probe(|_snapshot| { let poly_trait_predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); - self.infcx.enter_forall(poly_trait_predicate, |placeholder_trait_predicate| { - let self_ty = placeholder_trait_predicate.self_ty(); - let principal_trait_ref = match self_ty.kind() { - ty::Dynamic(data, ..) => { - if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { - debug!( - "assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate" - ); - candidates.vec.push(BuiltinObjectCandidate); - return; - } + self.infcx.enter_forall_old_solver( + poly_trait_predicate, + |placeholder_trait_predicate| { + let self_ty = placeholder_trait_predicate.self_ty(); + let principal_trait_ref = match self_ty.kind() { + ty::Dynamic(data, ..) => { + if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { + debug!( + "assemble_candidates_from_object_ty: matched builtin bound, \ + pushing candidate" + ); + candidates.vec.push(BuiltinObjectCandidate); + return; + } - if let Some(principal) = data.principal() { - principal.with_self_ty(self.tcx(), self_ty) - } else { - // Only auto trait bounds exist. + if let Some(principal) = data.principal() { + principal.with_self_ty(self.tcx(), self_ty) + } else { + // Only auto trait bounds exist. + return; + } + } + ty::Infer(ty::TyVar(_)) => { + debug!("assemble_candidates_from_object_ty: ambiguous"); + candidates.ambiguous = true; // could wind up being an object type return; } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return; - } - _ => return, - }; - - debug!(?principal_trait_ref, "assemble_candidates_from_object_ty"); + _ => return, + }; - // Count only those upcast versions that match the trait-ref - // we are looking for. Specifically, do not only check for the - // correct trait, but also the correct type parameters. - // For example, we may be trying to upcast `Foo` to `Bar`, - // but `Foo` is declared as `trait Foo: Bar`. - let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref) - .enumerate() - .filter(|&(_, upcast_trait_ref)| { - self.infcx.probe(|_| { - self.match_normalize_trait_ref( - obligation, - placeholder_trait_predicate.trait_ref, - upcast_trait_ref, - ) - .is_ok() + debug!(?principal_trait_ref, "assemble_candidates_from_object_ty"); + + // Count only those upcast versions that match the trait-ref + // we are looking for. Specifically, do not only check for the + // correct trait, but also the correct type parameters. + // For example, we may be trying to upcast `Foo` to `Bar`, + // but `Foo` is declared as `trait Foo: Bar`. + let candidate_supertraits = util::supertraits(self.tcx(), principal_trait_ref) + .enumerate() + .filter(|&(_, upcast_trait_ref)| { + self.infcx.probe(|_| { + self.match_normalize_trait_ref( + obligation, + placeholder_trait_predicate.trait_ref, + upcast_trait_ref, + ) + .is_ok() + }) }) - }) - .map(|(idx, _)| ObjectCandidate(idx)); + .map(|(idx, _)| ObjectCandidate(idx)); - candidates.vec.extend(candidate_supertraits); - }) + candidates.vec.extend(candidate_supertraits); + }, + ) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 11ce6235eb7ff..b0344aa15376a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -147,7 +147,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { idx: usize, ) -> Result, SelectionError<'tcx>> { let placeholder_trait_predicate = - self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref; + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate).trait_ref; let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty()); let candidate_predicate = self .for_each_item_bound( @@ -171,7 +171,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let candidate = candidate_predicate.map_bound(|t| t.trait_ref); - let candidate = self.infcx.instantiate_binder_with_fresh_vars( + let candidate = self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, candidate, @@ -236,7 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); let trait_def = obligation.predicate.def_id(); let self_ty = self.infcx.shallow_resolve( - self.infcx.enter_forall_and_leak_universe(obligation.predicate.self_ty()), + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate.self_ty()), ); let types = match tcx.as_lang_item(trait_def) { Some(LangItem::Sized) => self.sizedness_conditions(self_ty, SizedTraitKind::Sized), @@ -267,7 +267,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) => ty::Binder::dummy(vec![]), other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"), }; - let types = self.infcx.enter_forall_and_leak_universe(types); + let types = self.infcx.enter_forall_and_leak_universe_old_solver(types); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); self.collect_predicates_for_types( @@ -348,7 +348,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let predicate = self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let mut assume = predicate.trait_ref.args.const_at(2); if self.tcx().features().generic_const_exprs() { @@ -389,10 +389,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); - let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); + let self_ty = self.infcx.enter_forall_and_leak_universe_old_solver(self_ty); let constituents = self.constituent_types_for_auto_trait(self_ty)?; - let constituents = self.infcx.enter_forall_and_leak_universe(constituents); + let constituents = self.infcx.enter_forall_and_leak_universe_old_solver(constituents); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); let mut obligations = self.collect_predicates_for_types( @@ -490,7 +490,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); debug!(?obligation, ?index, "confirm_object_candidate"); - let trait_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let trait_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); let ty::Dynamic(data, ..) = *self_ty.kind() else { span_bug!(obligation.cause.span, "object candidate with non-object"); @@ -499,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let object_trait_ref = data.principal().unwrap_or_else(|| { span_bug!(obligation.cause.span, "object candidate with no principal") }); - let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( + let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, object_trait_ref, @@ -512,7 +513,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let unnormalized_upcast_trait_ref = supertraits.nth(index).expect("supertraits iterator no longer has as many elements"); - let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( + let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, unnormalized_upcast_trait_ref, @@ -598,7 +599,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { debug!(?obligation, "confirm_fn_pointer_candidate"); - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let tcx = self.tcx(); @@ -617,7 +619,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); // Confirm the `type Output: Sized;` bound that is present on `FnOnce` - let output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); + let output_ty = self.infcx.enter_forall_and_leak_universe_old_solver(sig.output()); let output_ty = normalize_with_depth_to( self, obligation.param_env, @@ -642,7 +644,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> PredicateObligations<'tcx> { debug!(?obligation, "confirm_trait_alias_candidate"); - let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let predicate = self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let trait_ref = predicate.trait_ref; let trait_def_id = trait_ref.def_id; let args = trait_ref.args; @@ -665,7 +667,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); @@ -695,7 +698,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); @@ -725,7 +729,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); @@ -755,7 +760,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { bug!("closure candidate for non-closure {:?}", obligation); @@ -786,7 +792,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let trait_ref = match *self_ty.kind() { @@ -815,7 +822,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result, SelectionError<'tcx>> { - let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); + let placeholder_predicate = + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); let tcx = self.tcx(); @@ -881,7 +889,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We must additionally check that the return type impls `Future + Sized`. let future_trait_def_id = tcx.require_lang_item(LangItem::Future, obligation.cause.span); - let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); + let placeholder_output_ty = + self.infcx.enter_forall_and_leak_universe_old_solver(sig.output()); nested.push(obligation.with( tcx, ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), @@ -962,7 +971,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: TraitObligation<'tcx>, found_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result, SelectionError<'tcx>> { - let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( + let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, found_trait_ref, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index eadc937639f20..c056544d431b6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -625,7 +625,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => { - self.infcx.enter_forall(bound_predicate.rebind(data), |data| { + self.infcx.enter_forall_old_solver(bound_predicate.rebind(data), |data| { match effects::evaluate_host_effect_obligation( self, &obligation.with(self.tcx(), data), @@ -1721,7 +1721,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - let trait_bound = self.infcx.instantiate_binder_with_fresh_vars( + let trait_bound = self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, HigherRankedType, trait_bound, @@ -1778,7 +1778,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug_assert_eq!(obligation.predicate.def_id(), env_predicate.item_def_id()); let mut nested_obligations = PredicateObligations::new(); - let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( + let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, BoundRegionConversionTime::HigherRankedType, env_predicate, @@ -2438,6 +2438,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { }) } } + ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) => unreachable!(), }) } @@ -2531,7 +2532,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation: &PolyTraitObligation<'tcx>, ) -> Result>, ()> { let placeholder_obligation = - self.infcx.enter_forall_and_leak_universe(obligation.predicate); + self.infcx.enter_forall_and_leak_universe_old_solver(obligation.predicate); let placeholder_obligation_trait_ref = placeholder_obligation.trait_ref; let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); @@ -2622,9 +2623,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { nested.extend( self.infcx - .enter_forall(hr_target_principal, |target_principal| { + .enter_forall_old_solver(hr_target_principal, |target_principal| { let source_principal = - self.infcx.instantiate_binder_with_fresh_vars( + self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, HigherRankedType, hr_source_principal, @@ -2659,26 +2660,30 @@ impl<'tcx> SelectionContext<'_, 'tcx> { hr_source_projection.item_def_id() == hr_target_projection.item_def_id() && self.infcx.probe(|_| { self.infcx - .enter_forall(hr_target_projection, |target_projection| { - let source_projection = - self.infcx.instantiate_binder_with_fresh_vars( - obligation.cause.span, - HigherRankedType, - hr_source_projection, - ); - self.infcx - .at(&obligation.cause, obligation.param_env) - .eq_trace( - DefineOpaqueTypes::Yes, - ToTrace::to_trace( - &obligation.cause, - hr_target_projection, + .enter_forall_old_solver( + hr_target_projection, + |target_projection| { + let source_projection = self + .infcx + .instantiate_binder_with_fresh_vars_old_solver( + obligation.cause.span, + HigherRankedType, hr_source_projection, - ), - target_projection, - source_projection, - ) - }) + ); + self.infcx + .at(&obligation.cause, obligation.param_env) + .eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + hr_target_projection, + hr_source_projection, + ), + target_projection, + source_projection, + ) + }, + ) .is_ok() }) }); @@ -2691,9 +2696,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } nested.extend( self.infcx - .enter_forall(hr_target_projection, |target_projection| { + .enter_forall_old_solver(hr_target_projection, |target_projection| { let source_projection = - self.infcx.instantiate_binder_with_fresh_vars( + self.infcx.instantiate_binder_with_fresh_vars_old_solver( obligation.cause.span, HigherRankedType, hr_source_projection, @@ -2752,12 +2757,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation: &PolyTraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result, ()> { - let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); - let trait_ref = self.infcx.instantiate_binder_with_fresh_vars( - obligation.cause.span, - HigherRankedType, - poly_trait_ref, - ); + let predicate = + self.infcx.enter_forall_and_leak_universe(obligation.predicate).no_ambiguous_aliases(); + let trait_ref = self + .infcx + .instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + poly_trait_ref, + ) + .no_ambiguous_aliases(); self.infcx .at(&obligation.cause, obligation.param_env) .eq(DefineOpaqueTypes::No, predicate.trait_ref, trait_ref) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fdf32d32e9058..e3d77b6da262d 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -815,6 +815,11 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { return; // Subtree handled by compute_inherent_projection. } + // Ambiguous aliases only wrap another higher-ranked alias whose + // normalization is currently ambiguous, we will handle that alias + // when recursing into args. + ty::Alias(ty::AliasTy { kind: ty::Ambiguous { .. }, .. }) => {} + ty::Adt(def, args) => { // WfNominalType let obligations = self.nominal_obligations(def.did(), args); diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 659229a58d539..e78037abf493e 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -24,16 +24,18 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' let kind = tcx.def_kind(def_id); match kind { DefKind::Fn => { - let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); - let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + let sig = tcx.fn_sig(def_id).instantiate_identity(); + let liberated_sig = + tcx.liberate_late_bound_regions(def_id.to_def_id(), sig).skip_norm_wip(); tcx.arena.alloc_from_iter(itertools::zip_eq( liberated_sig.inputs_and_output, fn_sig_spans(tcx, def_id), )) } DefKind::AssocFn => { - let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); - let liberated_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), sig); + let sig = tcx.fn_sig(def_id).instantiate_identity(); + let liberated_sig = + tcx.liberate_late_bound_regions(def_id.to_def_id(), sig).skip_norm_wip(); let mut assumed_wf_types: Vec<_> = tcx.assumed_wf_types(tcx.local_parent(def_id)).into(); assumed_wf_types.extend(itertools::zip_eq( diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 19c59df0604c3..8a6f840cbc641 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -82,6 +82,9 @@ bitflags::bitflags! { /// Does this have `ConstKind::Unevaluated`? const HAS_CT_PROJECTION = 1 << 14; + /// Does this have `Ambiguous` aliases? + const HAS_AMBIGUOUS_ALIAS = 1 << 15; + /// Does this have `Alias` or `ConstKind::Unevaluated`? /// /// Rephrased, could this term be normalized further? @@ -89,26 +92,27 @@ bitflags::bitflags! { | TypeFlags::HAS_TY_FREE_ALIAS.bits() | TypeFlags::HAS_TY_OPAQUE.bits() | TypeFlags::HAS_TY_INHERENT.bits() - | TypeFlags::HAS_CT_PROJECTION.bits(); + | TypeFlags::HAS_CT_PROJECTION.bits() + | TypeFlags::HAS_AMBIGUOUS_ALIAS.bits(); /// Is a type or const error reachable? - const HAS_NON_REGION_ERROR = 1 << 15; + const HAS_NON_REGION_ERROR = 1 << 16; /// Is a region error reachable? - const HAS_RE_ERROR = 1 << 16; + const HAS_RE_ERROR = 1 << 17; /// Is an error type/lifetime/const reachable? const HAS_ERROR = TypeFlags::HAS_NON_REGION_ERROR.bits() | TypeFlags::HAS_RE_ERROR.bits(); /// Does this have any region that "appears free" in the type? /// Basically anything but `ReBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 17; + const HAS_FREE_REGIONS = 1 << 18; /// Does this have any `ReBound` regions? - const HAS_RE_BOUND = 1 << 18; + const HAS_RE_BOUND = 1 << 19; /// Does this have any `Bound` types? - const HAS_TY_BOUND = 1 << 19; + const HAS_TY_BOUND = 1 << 20; /// Does this have any `ConstKind::Bound` consts? - const HAS_CT_BOUND = 1 << 20; + const HAS_CT_BOUND = 1 << 21; /// Does this have any bound variables? /// Used to check if a global bound is safe to evaluate. const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits() @@ -116,7 +120,7 @@ bitflags::bitflags! { | TypeFlags::HAS_CT_BOUND.bits(); /// Does this have any `ReErased` regions? - const HAS_RE_ERASED = 1 << 21; + const HAS_RE_ERASED = 1 << 22; /// Does this have any regions of any kind? const HAS_REGIONS = TypeFlags::HAS_FREE_REGIONS.bits() @@ -133,19 +137,19 @@ bitflags::bitflags! { | TypeFlags::HAS_CT_INFER.bits(); /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? - const HAS_TY_FRESH = 1 << 22; + const HAS_TY_FRESH = 1 << 23; /// Does this value have `InferConst::Fresh`? - const HAS_CT_FRESH = 1 << 23; + const HAS_CT_FRESH = 1 << 24; /// Does this have any binders with bound vars (e.g. that need to be anonymized)? - const HAS_BINDER_VARS = 1 << 24; + const HAS_BINDER_VARS = 1 << 25; /// Does this type have any coroutines in it? - const HAS_TY_CORO = 1 << 25; + const HAS_TY_CORO = 1 << 26; /// Does this have a `Bound(BoundVarIndexKind::Canonical, _)`? - const HAS_CANONICAL_BOUND = 1 << 26; + const HAS_CANONICAL_BOUND = 1 << 27; } } @@ -301,6 +305,7 @@ impl FlagComputation { ty::Free { .. } => TypeFlags::HAS_TY_FREE_ALIAS, ty::Opaque { .. } => TypeFlags::HAS_TY_OPAQUE, ty::Inherent { .. } => TypeFlags::HAS_TY_INHERENT, + ty::Ambiguous { .. } => TypeFlags::HAS_AMBIGUOUS_ALIAS, }); self.add_alias_ty(alias); diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 7957bacda5677..c00e2e7922915 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -391,12 +391,12 @@ pub trait InferCtxtLike: Sized { fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder, - ) -> T; + ) -> ty::UnnormalizedAmbiguous; fn enter_forall, U>( &self, value: ty::Binder, - f: impl FnOnce(T) -> U, + f: impl FnOnce(ty::UnnormalizedAmbiguous) -> U, ) -> U; fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 8859ab7c037b0..b33b80900a8b4 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -278,6 +278,8 @@ pub trait Const>: fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; + fn new_value(interner: I, value: I::ValueConst) -> Self; + fn new_expr(interner: I, expr: I::ExprConst) -> Self; fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; @@ -296,7 +298,9 @@ pub trait Const>: } #[rust_analyzer::prefer_underscore_import] -pub trait ValueConst>: Copy + Debug + Hash + Eq { +pub trait ValueConst>: + TypeFoldable + Copy + Debug + Hash + Eq +{ fn ty(self) -> I::Ty; fn valtree(self) -> I::ValTree; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 09def0212a153..50294abf8f4f7 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -264,6 +264,18 @@ pub trait Interner: fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); + fn debug_assert_alias_ty_args_compatible( + self, + alias_ty: ty::AliasTyKind, + args: Self::GenericArgs, + ); + + fn debug_assert_alias_term_args_compatible( + self, + alias_ty: ty::AliasTermKind, + args: Self::GenericArgs, + ); + /// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection` /// are compatible with the `DefId`. fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index d9906795dfba6..7ca1565f68f07 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -82,7 +82,7 @@ pub use rustc_ast_ir::{FloatTy, IntTy, Movability, Mutability, Pinnedness, UintT use rustc_type_ir_macros::GenericTypeVisitable; pub use ty_info::*; pub use ty_kind::*; -pub use unnormalized::Unnormalized; +pub use unnormalized::*; pub use upcast::*; pub use visit::*; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 301cf7dbf1087..30344af15438e 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -593,6 +593,15 @@ pub enum AliasTermKind { /// Can always be normalized away. FreeTy { def_id: I::FreeTyAliasId }, + /// A wrapper that indicates the alias needs to be re-normalized. + /// + /// It's specific to ambiguous aliases that contain escaping bound vars. + /// This is an optimization for binder renormalization and is only used in the + /// next solver. See `NormalizationFolder`. + /// + /// The original alias is stored in the first generic arg. + AmbiguousTy, + /// An unevaluated anonymous constants. UnevaluatedConst { def_id: I::UnevaluatedConstId }, /// An unevaluated const coming from an associated const. @@ -614,6 +623,7 @@ impl AliasTermKind { AliasTermKind::FreeTy { .. } => "type alias", AliasTermKind::FreeConst { .. } => "unevaluated constant", AliasTermKind::UnevaluatedConst { .. } => "unevaluated constant", + AliasTermKind::AmbiguousTy => "ambiguous alias type", } } @@ -622,7 +632,8 @@ impl AliasTermKind { AliasTermKind::ProjectionTy { .. } | AliasTermKind::InherentTy { .. } | AliasTermKind::OpaqueTy { .. } - | AliasTermKind::FreeTy { .. } => true, + | AliasTermKind::FreeTy { .. } + | AliasTermKind::AmbiguousTy => true, AliasTermKind::UnevaluatedConst { .. } | AliasTermKind::ProjectionConst { .. } @@ -638,6 +649,7 @@ impl AliasTermKind { AliasTermKind::InherentTy { def_id } => def_id.into(), AliasTermKind::OpaqueTy { def_id } => def_id.into(), AliasTermKind::FreeTy { def_id } => def_id.into(), + AliasTermKind::AmbiguousTy => unreachable!("this method is expected to be removed"), AliasTermKind::UnevaluatedConst { def_id } => def_id.into(), AliasTermKind::ProjectionConst { def_id } => def_id.into(), AliasTermKind::FreeConst { def_id } => def_id.into(), @@ -653,6 +665,7 @@ impl From> for AliasTermKind { ty::Opaque { def_id } => AliasTermKind::OpaqueTy { def_id }, ty::Free { def_id } => AliasTermKind::FreeTy { def_id }, ty::Inherent { def_id } => AliasTermKind::InherentTy { def_id }, + ty::Ambiguous => AliasTermKind::AmbiguousTy, } } } @@ -698,7 +711,7 @@ impl AliasTerm { kind: AliasTermKind, args: I::GenericArgs, ) -> AliasTerm { - interner.debug_assert_args_compatible(kind.def_id(), args); + interner.debug_assert_alias_term_args_compatible(kind, args); AliasTerm { kind, args, _use_alias_term_new_instead: () } } @@ -727,6 +740,7 @@ impl AliasTerm { AliasTermKind::InherentTy { def_id } => AliasTyKind::Inherent { def_id }, AliasTermKind::OpaqueTy { def_id } => AliasTyKind::Opaque { def_id }, AliasTermKind::FreeTy { def_id } => AliasTyKind::Free { def_id }, + AliasTermKind::AmbiguousTy => AliasTyKind::Ambiguous, kind @ (AliasTermKind::InherentConst { .. } | AliasTermKind::FreeConst { .. } | AliasTermKind::UnevaluatedConst { .. } @@ -746,7 +760,8 @@ impl AliasTerm { kind @ (AliasTermKind::ProjectionTy { .. } | AliasTermKind::InherentTy { .. } | AliasTermKind::OpaqueTy { .. } - | AliasTermKind::FreeTy { .. }) => { + | AliasTermKind::FreeTy { .. } + | AliasTermKind::AmbiguousTy) => { panic!("Cannot turn `{}` into `UnevaluatedConst`", kind.descr()) } }; @@ -777,6 +792,7 @@ impl AliasTerm { AliasTermKind::InherentTy { def_id } => ty::Inherent { def_id }, AliasTermKind::OpaqueTy { def_id } => ty::Opaque { def_id }, AliasTermKind::FreeTy { def_id } => ty::Free { def_id }, + AliasTermKind::AmbiguousTy => ty::Ambiguous, }; Ty::new_alias(interner, ty::AliasTy::new_from_args(interner, alias_ty_kind, self.args)) @@ -802,25 +818,22 @@ impl AliasTerm { ) } - fn projection_def_id(self) -> Option { + fn projection_def_id(self) -> I::TraitAssocTermId { match self.kind { - AliasTermKind::ProjectionTy { def_id } => Some(def_id.into()), - AliasTermKind::ProjectionConst { def_id } => Some(def_id.into()), + AliasTermKind::ProjectionTy { def_id } => def_id.into(), + AliasTermKind::ProjectionConst { def_id } => def_id.into(), AliasTermKind::InherentTy { .. } | AliasTermKind::OpaqueTy { .. } | AliasTermKind::FreeTy { .. } | AliasTermKind::UnevaluatedConst { .. } | AliasTermKind::FreeConst { .. } - | AliasTermKind::InherentConst { .. } => None, + | AliasTermKind::InherentConst { .. } + | AliasTermKind::AmbiguousTy => unreachable!(), } } - fn expect_projection_def_id(self) -> I::TraitAssocTermId { - self.projection_def_id().expect("expected a projection") - } - pub fn trait_def_id(self, interner: I) -> I::TraitId { - interner.projection_parent(self.expect_projection_def_id()) + interner.projection_parent(self.projection_def_id()) } /// Extracts the underlying trait reference and own args from this projection. @@ -828,7 +841,7 @@ impl AliasTerm { /// then this function would return a `T: StreamingIterator` trait reference and /// `['a]` as the own args. pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef, I::GenericArgsSlice) { - interner.trait_ref_and_own_args_for_alias(self.expect_projection_def_id(), self.args) + interner.trait_ref_and_own_args_for_alias(self.projection_def_id(), self.args) } /// Extracts the underlying trait reference from this projection. @@ -927,7 +940,7 @@ impl ProjectionPredicate { } pub fn def_id(self) -> I::TraitAssocTermId { - self.projection_term.expect_projection_def_id() + self.projection_term.projection_def_id() } } diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index ab9553da42f89..ea08067ef66aa 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1096,13 +1096,14 @@ fn alias_outlives_candidates_from_assumptions let prev_universe = infcx.universe(); // FIXME(-Zassumptions-on-binders): Handle the assumptions on this binder - infcx.enter_forall(bound_outlives, |(alias, r)| { + infcx.enter_forall(bound_outlives, |bound_outlives| { + let (alias, r) = bound_outlives.no_ambiguous_aliases(); let u = infcx.universe(); infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty())); for bound_type_outlives in assumptions.type_outlives.iter() { let OutlivesPredicate(alias2, r2) = - infcx.instantiate_binder_with_infer(*bound_type_outlives); + infcx.instantiate_binder_with_infer(*bound_type_outlives).no_ambiguous_aliases(); let mut relation = HigherRankedAliasMatcher { infcx, @@ -1187,16 +1188,18 @@ impl<'a, Infcx: InferCtxtLike, I: Interner> TypeRelation T: Relate, { self.infcx.enter_forall(a, |a| { + let a = a.no_ambiguous_aliases(); let u = self.infcx.universe(); self.infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty())); - let b = self.infcx.instantiate_binder_with_infer(b); + let b = self.infcx.instantiate_binder_with_infer(b).no_ambiguous_aliases(); self.relate(a, b) })?; self.infcx.enter_forall(b, |b| { + let b = b.no_ambiguous_aliases(); let u = self.infcx.universe(); self.infcx.insert_placeholder_assumptions(u, Some(Assumptions::empty())); - let a = self.infcx.instantiate_binder_with_infer(a); + let a = self.infcx.instantiate_binder_with_infer(a).no_ambiguous_aliases(); self.relate(a, b) })?; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 51de99e92fcad..d85594eda3e85 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -213,7 +213,7 @@ impl Relate for ty::AliasTy { a: ty::AliasTy, b: ty::AliasTy, ) -> RelateResult> { - if a.kind.def_id() != b.kind.def_id() { + if a.kind != b.kind { Err(TypeError::ProjectionMismatched(ExpectedFound::new( a.kind.def_id(), b.kind.def_id(), @@ -236,7 +236,7 @@ impl Relate for ty::AliasTerm { a: ty::AliasTerm, b: ty::AliasTerm, ) -> RelateResult> { - if a.def_id() != b.def_id() { + if a.kind != b.kind { Err(TypeError::ProjectionMismatched(ExpectedFound::new(a.def_id(), b.def_id()))) } else { let args = match a.kind(relation.cx()) { @@ -255,6 +255,10 @@ impl Relate for ty::AliasTerm { | ty::AliasTermKind::ProjectionConst { .. } => { relate_args_invariantly(relation, a.args, b.args)? } + ty::AliasTermKind::AmbiguousTy { .. } => { + let nested = relation.tys(a.args.type_at(0), b.args.type_at(0))?; + relation.cx().mk_args(&[nested.into()]) + } }; Ok(a.with_args(relation.cx(), args)) } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index a643d22c17643..cf32b76caf283 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -5,7 +5,7 @@ use crate::data_structures::DelayedSet; use crate::relate::combine::combine_ty_args; pub use crate::relate::*; use crate::solve::{Goal, VisibleForLeakCheck}; -use crate::{self as ty, InferCtxtLike, Interner}; +use crate::{self as ty, InferCtxtLike, Interner, TypeFolder, TypeSuperFoldable, TypeVisitableExt}; pub trait RelateExt: InferCtxtLike { fn relate>( @@ -129,6 +129,17 @@ where cache: Default::default(), } } + + fn normalize_ambiguous_aliases>( + &mut self, + value: ty::UnnormalizedAmbiguous, + ) -> T { + let value = value.do_normalize(); + let mut replacer = ReplaceAmbiguousAliasWithInfer::new(self.infcx, self.param_env); + let value = value.fold_with(&mut replacer); + self.register_goals(replacer.goals()); + value + } } impl TypeRelation for SolverRelating<'_, Infcx, I> @@ -294,6 +305,19 @@ where return Ok(a); } + match self.structurally_relate_aliases { + StructurallyRelateAliases::Yes => { + assert_eq!(a.bound_vars(), b.bound_vars()); + a.rebind((a.skip_binder(), b.skip_binder())); + self.infcx.enter_forall(a.rebind((a.skip_binder(), b.skip_binder())), |val| { + let (a, b) = val.keep_ambiguous_aliases_for_structurally_relate(); + self.relate(a, b) + })?; + return Ok(a); + } + StructurallyRelateAliases::No => {} + } + match self.ambient_variance { // Checks whether `for<..> sub <: for<..> sup` holds. // @@ -312,13 +336,17 @@ where // [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html ty::Covariant => { self.infcx.enter_forall(b, |b| { + let b = self.normalize_ambiguous_aliases(b); let a = self.infcx.instantiate_binder_with_infer(a); + let a = self.normalize_ambiguous_aliases(a); self.relate(a, b) })?; } ty::Contravariant => { self.infcx.enter_forall(a, |a| { + let a = self.normalize_ambiguous_aliases(a); let b = self.infcx.instantiate_binder_with_infer(b); + let b = self.normalize_ambiguous_aliases(b); self.relate(a, b) })?; } @@ -335,13 +363,17 @@ where // Check if `exists<..> A == for<..> B` ty::Invariant => { self.infcx.enter_forall(b, |b| { + let b = self.normalize_ambiguous_aliases(b); let a = self.infcx.instantiate_binder_with_infer(a); + let a = self.normalize_ambiguous_aliases(a); self.relate(a, b) })?; // Check if `exists<..> B == for<..> A`. self.infcx.enter_forall(a, |a| { + let a = self.normalize_ambiguous_aliases(a); let b = self.infcx.instantiate_binder_with_infer(b); + let b = self.normalize_ambiguous_aliases(b); self.relate(a, b) })?; } @@ -374,12 +406,14 @@ where &mut self, obligations: impl IntoIterator>, ) { + std::assert_matches!(self.structurally_relate_aliases, StructurallyRelateAliases::No); self.goals.extend( obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)), ); } fn register_goals(&mut self, obligations: impl IntoIterator>) { + std::assert_matches!(self.structurally_relate_aliases, StructurallyRelateAliases::No); self.goals.extend(obligations); } @@ -407,3 +441,87 @@ where })]); } } + +// FIXME: this is a temporary solution for renomalizing ambiguous aliases +// inside solver relating. We may pursue actual normalization in the future. +pub struct ReplaceAmbiguousAliasWithInfer<'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + infcx: &'a Infcx, + param_env: I::ParamEnv, + goals: Vec>, +} + +impl<'a, Infcx, I> ReplaceAmbiguousAliasWithInfer<'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + pub fn new(infcx: &'a Infcx, param_env: I::ParamEnv) -> Self { + Self { infcx, param_env, goals: Vec::new() } + } + + pub fn goals(self) -> Vec> { + self.goals + } +} + +impl<'a, Infcx, I> TypeFolder for ReplaceAmbiguousAliasWithInfer<'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn cx(&self) -> I { + self.infcx.cx() + } + + fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { + // Ambiguous aliases in nested binders will be handled when they're instantiated. + t + } + + #[instrument(level = "trace", skip(self), ret)] + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + debug_assert!(!ty.has_escaping_bound_vars()); + if !ty.has_ambiguous_aliases() { + return ty; + } + + // With eager normalization, we should normalize the args of alias before + // normalizing the alias itself. + let ty = ty.super_fold_with(self); + let ty::Alias(ty::AliasTy { kind: ty::AliasTyKind::Ambiguous, args, .. }) = ty.kind() + else { + return ty; + }; + + let original_alias = args.type_at(0); + + let infer_ty = self.infcx.next_ty_infer(); + let normalizes_to = ty::PredicateKind::AliasRelate( + original_alias.into(), + infer_ty.into(), + ty::AliasRelationDirection::Equate, + ); + self.goals.push(Goal::new(self.cx(), self.param_env, normalizes_to)); + infer_ty + } + + #[instrument(level = "trace", skip(self), ret)] + fn fold_const(&mut self, ct: I::Const) -> I::Const { + debug_assert!(!ct.has_escaping_bound_vars()); + if !ct.has_ambiguous_aliases() { + return ct; + } + + // With eager normalization, we should normalize the args of alias before + // normalizing the alias itself. + let ct = ct.super_fold_with(self); + let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct }; + // FIXME: add an new `Ambiguous` kind to `UnevaluatedConst` as well. + // As a field or a new kind on `ConstKind`? + ct + } +} diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 6f3cea27cafdb..0550571375e6f 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -62,6 +62,15 @@ pub enum AliasTyKind { /// Currently only used if the type alias references opaque types. /// Can always be normalized away. Free { def_id: I::FreeTyAliasId }, + + /// A wrapper that indicates the alias needs to be re-normalized. + /// + /// It's specific to ambiguous aliases that contain escaping bound vars. + /// This is an optimization for binder renormalization and is only used in the + /// next solver. See `NormalizationFolder`. + /// + /// The original alias is stored in the first generic arg. + Ambiguous, } impl AliasTyKind { @@ -75,6 +84,7 @@ impl AliasTyKind { AliasTyKind::Inherent { .. } => "inherent associated type", AliasTyKind::Opaque { .. } => "opaque type", AliasTyKind::Free { .. } => "type alias", + AliasTyKind::Ambiguous { .. } => "ambiguous alias", } } @@ -84,6 +94,7 @@ impl AliasTyKind { AliasTyKind::Inherent { def_id } => def_id.into(), AliasTyKind::Opaque { def_id } => def_id.into(), AliasTyKind::Free { def_id } => def_id.into(), + AliasTyKind::Ambiguous => unreachable!("this method is expected to be removed"), } } } @@ -468,7 +479,7 @@ impl Eq for AliasTy {} impl AliasTy { pub fn new_from_args(interner: I, kind: AliasTyKind, args: I::GenericArgs) -> AliasTy { - interner.debug_assert_args_compatible(kind.def_id(), args); + interner.debug_assert_alias_ty_args_compatible(kind, args); AliasTy { kind, args, _use_alias_ty_new_instead: () } } diff --git a/compiler/rustc_type_ir/src/unnormalized.rs b/compiler/rustc_type_ir/src/unnormalized.rs index 0981a8a7e0e18..0949bc24817f3 100644 --- a/compiler/rustc_type_ir/src/unnormalized.rs +++ b/compiler/rustc_type_ir/src/unnormalized.rs @@ -7,7 +7,7 @@ use crate::inherent::*; use crate::upcast::Upcast; use crate::{ Binder, BoundConstness, ClauseKind, HostEffectPredicate, Interner, PredicatePolarity, - TraitPredicate, TraitRef, + TraitPredicate, TraitRef, TypeVisitable, TypeVisitableExt, }; /// A wrapper for values that need normalization. @@ -97,6 +97,10 @@ impl Unnormalized> { pub fn skip_binder(self) -> T { self.value.skip_binder() } + + pub fn bound_vars(&self) -> I::BoundVarKinds { + self.value.bound_vars() + } } impl Unnormalized { @@ -147,3 +151,41 @@ impl Unnormalized>> { Unnormalized::new(inner) } } + +/// Like `Unnormalized`, but for otherwise normalized values that contain +/// unnormalized `Ambiguous` aliases. +#[derive_where(Clone, Copy, PartialOrd, PartialEq, Debug; T)] +pub struct UnnormalizedAmbiguous { + value: T, + #[derive_where(skip(Debug))] + _tcx: PhantomData I>, +} + +impl UnnormalizedAmbiguous { + /// Should only be used in binder instantiation. + pub fn new(value: T) -> Self { + Self { value, _tcx: PhantomData } + } + + pub fn dummy(value: T) -> Self { + // TODO: assert no unnormalized alias without escaping bound vars + Self { value, _tcx: PhantomData } + } + + /// This should only be used when structurally relating types. + pub fn keep_ambiguous_aliases_for_structurally_relate(self) -> T { + self.value + } + + /// Only use this if it will then normalize away all ambiguous aliases. + pub fn do_normalize(self) -> T { + self.value + } +} + +impl> UnnormalizedAmbiguous { + pub fn no_ambiguous_aliases(self) -> T { + assert!(!self.value.has_ambiguous_aliases()); + self.value + } +} diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 492c37481298b..1b091eece4514 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -265,6 +265,10 @@ pub trait TypeVisitableExt: TypeVisitable { self.has_type_flags(TypeFlags::HAS_ALIAS) } + fn has_ambiguous_aliases(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_AMBIGUOUS_ALIAS) + } + fn has_opaque_types(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_OPAQUE) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d50e4dd80557a..8f20f2e5234a8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2346,6 +2346,7 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Placeholder(..) => panic!("Placeholder"), ty::CoroutineWitness(..) => panic!("CoroutineWitness"), ty::Infer(..) => panic!("Infer"), + ty::Alias(ty::AliasTy { kind: ty::Ambiguous, .. }) => panic!("Ambiguous alias"), ty::Error(_) => FatalError.raise(), } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 7a5150da6593a..07091d34ed310 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -904,7 +904,7 @@ impl TyCoercionStability { | ty::Error(_) | ty::Bound(..) | ty::Alias(ty::AliasTy { - kind: ty::Opaque { .. }, + kind: ty::Opaque { .. } | ty::Ambiguous, .. }) | ty::Placeholder(_) diff --git a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.stderr b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.stderr index c92854b92f9d3..22673cef64079 100644 --- a/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.stderr +++ b/tests/ui/coherence/coherence-overlap-unnormalizable-projection-1.stderr @@ -12,7 +12,7 @@ LL | impl Trait for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Box<_>` | = note: downstream crates may implement trait `WithAssoc<'a>` for type `std::boxed::Box<_>` - = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box< as WithAssoc<'a>>::Assoc>` + = note: downstream crates may implement trait `WhereBound` for type `std::boxed::Box<_>` error: aborting due to 1 previous error diff --git a/tests/ui/coherence/occurs-check/associated-type.next.stderr b/tests/ui/coherence/occurs-check/associated-type.next.stderr index 38fb75483f3b3..ef5a090de4891 100644 --- a/tests/ui/coherence/occurs-check/associated-type.next.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.next.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [Alias(AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: Projection { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. })], kind: AmbiguousTy, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [Alias(AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: Projection { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. })], kind: AmbiguousTy, .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/coherence/occurs-check/associated-type.old.stderr b/tests/ui/coherence/occurs-check/associated-type.old.stderr index 1dac3ecea2687..4e4ec2e9b17e1 100644 --- a/tests/ui/coherence/occurs-check/associated-type.old.stderr +++ b/tests/ui/coherence/occurs-check/associated-type.old.stderr @@ -1,5 +1,5 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: ProjectionTy { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [Alias(AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: Projection { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. })], kind: AmbiguousTy, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [Alias(AliasTy { args: [*const ?1t, '^0.Named(DefId(0:27 ~ associated_type[f554]::{impl#3}::'a#1))], kind: Projection { def_id: DefId(0:5 ~ associated_type[f554]::ToUnit::Unit) }, .. })], kind: AmbiguousTy, .. } error[E0119]: conflicting implementations of trait `Overlap fn(&'a (), ())>` for type `for<'a> fn(&'a (), ())` --> $DIR/associated-type.rs:32:1 | diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr index f609dcab752af..e14b7a110e436 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.next.stderr @@ -14,7 +14,7 @@ help: consider giving this pattern a type, where the value of const parameter `N LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = free(); | +++++++++++++ -error[E0271]: type mismatch resolving `10 == 2` +error[E0271]: type mismatch resolving `FREE::<10> == 2` --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:35:45 | LL | let (mut arr, mut arr_with_weird_len) = free(); @@ -36,11 +36,14 @@ help: consider giving this pattern a type, where the value of const parameter `N LL | let (mut arr, mut arr_with_weird_len): ([_; N], _) = proj(); | +++++++++++++ -error[E0271]: type mismatch resolving `10 == 2` +error[E0271]: type mismatch resolving `::PROJ::<10> == 2` --> $DIR/ambiguous-on-failed-eval-with-vars-fail.rs:52:45 | LL | let (mut arr, mut arr_with_weird_len) = proj(); - | ^^^^^^ types differ + | ^^^^^^ expected `2`, found `10` + | + = note: expected constant `2` + found constant `10` error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs index 72952940b1c12..12e92d5530032 100644 --- a/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs +++ b/tests/ui/const-generics/gca/ambiguous-on-failed-eval-with-vars-fail.rs @@ -33,7 +33,7 @@ fn test_free() { fn test_free_mismatch() { let (mut arr, mut arr_with_weird_len) = free(); - //[next]~^ ERROR type mismatch resolving `10 == 2` + //[next]~^ ERROR type mismatch resolving `FREE::<10> == 2` arr_with_weird_len = [(); 2]; arr = [(); 10]; } @@ -50,7 +50,7 @@ fn test_proj() { fn test_proj_mismatch() { let (mut arr, mut arr_with_weird_len) = proj(); - //[next]~^ ERROR type mismatch resolving `10 == 2` + //[next]~^ ERROR type mismatch resolving `::PROJ::<10> == 2` arr_with_weird_len = [(); 2]; arr = [(); 10]; } diff --git a/tests/ui/higher-ranked/structually-relate-aliases.stderr b/tests/ui/higher-ranked/structually-relate-aliases.stderr index 4649aac47cdbf..ec00873299f6e 100644 --- a/tests/ui/higher-ranked/structually-relate-aliases.stderr +++ b/tests/ui/higher-ranked/structually-relate-aliases.stderr @@ -1,4 +1,4 @@ - WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], kind: ProjectionTy { def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }, .. } + WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTerm { args: [Alias(AliasTy { args: [?1t, '^0.Named(DefId(0:15 ~ structually_relate_aliases[de75]::{impl#1}::'a))], kind: Projection { def_id: DefId(0:5 ~ structually_relate_aliases[de75]::ToUnit::Unit) }, .. })], kind: AmbiguousTy, .. } error[E0277]: the trait bound `for<'a> T: ToUnit<'a>` is not satisfied --> $DIR/structually-relate-aliases.rs:13:36 | diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr index 31d74d1c022a1..26e682dfb7a7c 100644 --- a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` - --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:50 +error[E0284]: type annotations needed: cannot normalize `<_ as Trait<'a>>::Assoc` + --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:12 | LL | let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::(); - | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc normalizes-to >::Assoc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot normalize `<_ as Trait<'a>>::Assoc` error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr index a76a10d20ee8b..bc89842d16a14 100644 --- a/tests/ui/traits/next-solver/async.fail.stderr +++ b/tests/ui/traits/next-solver/async.fail.stderr @@ -1,8 +1,8 @@ -error[E0271]: type mismatch resolving `() == i32` +error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` --> $DIR/async.rs:12:17 | LL | needs_async(async {}); - | ----------- ^^^^^^^^ types differ + | ----------- ^^^^^^^^ expected `i32`, found `()` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs index 34c0ed02eeb12..79985b6bb9962 100644 --- a/tests/ui/traits/next-solver/async.rs +++ b/tests/ui/traits/next-solver/async.rs @@ -10,7 +10,7 @@ fn needs_async(_: impl Future) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR type mismatch resolving `() == i32` + //[fail]~^ ERROR: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()` } #[cfg(pass)] diff --git a/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr b/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr index 462544b405218..cc11aa018161a 100644 --- a/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr +++ b/tests/ui/traits/next-solver/lazy-nested-obligations-2.next.stderr @@ -1,14 +1,20 @@ -error[E0271]: type mismatch resolving `fn(&str) == fn(&str) {f}` +error[E0271]: type mismatch resolving `::F == fn(&str) {f}` --> $DIR/lazy-nested-obligations-2.rs:20:21 | LL | let _: V = V(f); - | ^^^^ types differ + | ^^^^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a _) {f}` + found fn pointer `for<'a> fn(&'a _)` -error[E0271]: type mismatch resolving `fn(&str) == fn(&str) {f}` +error[E0271]: type mismatch resolving `::F == fn(&str) {f}` --> $DIR/lazy-nested-obligations-2.rs:27:22 | LL | let _: E3 = E3::Var(f); - | ^^^^^^^^^^ types differ + | ^^^^^^^^^^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a _) {f}` + found fn pointer `for<'a> fn(&'a _)` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/next-solver/more-object-bound.rs b/tests/ui/traits/next-solver/more-object-bound.rs index 1dad1903a649d..7a7615be71fcf 100644 --- a/tests/ui/traits/next-solver/more-object-bound.rs +++ b/tests/ui/traits/next-solver/more-object-bound.rs @@ -10,7 +10,7 @@ trait Trait: SuperTrait::B> {} fn transmute(x: A) -> B { foo::>(x) - //~^ ERROR type mismatch resolving `A == B` + //~^ ERROR: type mismatch resolving ` as SuperTrait>::A == B` } fn foo(x: T::A) -> B diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr index 7d279ed64282b..ccbf19ae4d96c 100644 --- a/tests/ui/traits/next-solver/more-object-bound.stderr +++ b/tests/ui/traits/next-solver/more-object-bound.stderr @@ -1,9 +1,17 @@ -error[E0271]: type mismatch resolving `A == B` +error[E0271]: type mismatch resolving ` as SuperTrait>::A == B` --> $DIR/more-object-bound.rs:12:17 | +LL | fn transmute(x: A) -> B { + | - - expected type parameter + | | + | found type parameter LL | foo::>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A` | + = note: expected type parameter `B` + found type parameter `A` + = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound + = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters = note: required because it appears within the type `dyn Trait` note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8