diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index db8588f49c371..ffd36865c729e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -16,6 +16,7 @@ use rustc_hir::{ CoroutineDesugaring, CoroutineKind, CoroutineSource, LangItem, PatField, find_attr, }; use rustc_index::bit_set::DenseBitSet; +use rustc_infer::traits::TraitErrors; use rustc_middle::bug; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::{ @@ -1462,7 +1463,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { let cause = ObligationCause::misc(expr.span, self.mir_def_id()); ocx.register_bound(cause, self.infcx.param_env, ty, clone_trait); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() + if let TraitErrors::HasErrors(errors) = errors && errors.iter().all(|error| { match error.obligation.predicate.as_clause().and_then(|c| c.as_trait_clause()) { Some(clause) => match clause.self_ty().skip_binder().kind() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index e9c1c1d57b936..7ba109d804259 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1534,9 +1534,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { ) && !has_sugg { let skip_for_simple_clone = - has_deref && !has_overloaded_deref && errors.is_empty(); + has_deref && !has_overloaded_deref && errors.no_errors(); if !skip_for_simple_clone { - let msg = match &errors[..] { + let msg = match errors.as_slice() { [] => "you can `clone` the value and consume it, but \ this might not be your desired behavior" .to_string(), @@ -1553,7 +1553,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { the following trait bounds could be satisfied: \ {}", listify( - &errors, + errors.as_slice(), |e: &FulfillmentError<'tcx>| format!( "`{}`", e.obligation.predicate @@ -1569,7 +1569,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { Applicability::MaybeIncorrect, ); - suggested_cloning = errors.is_empty(); + suggested_cloning = errors.no_errors(); for error in errors { if let FulfillmentErrorCode::Select( diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 99cd7104692e1..9fac00016eac2 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -716,7 +716,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { return CloneSuggestion::NotEmitted; }; - if !errors.is_empty() { + if errors.has_errors() { return CloneSuggestion::NotEmitted; } let sugg = vec![ diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 56dc3ed8c8600..acaf7adceca2a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1616,7 +1616,8 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { match self .infcx .type_implements_trait_shallow(clone_trait, ty.peel_refs(), self.infcx.param_env) - .as_deref() + .as_ref() + .map(|it| it.as_slice()) { Some([]) => { // FIXME: This error message isn't useful, since we're just diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 1eaf6839f3dd7..a2669ced50c30 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1181,7 +1181,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { ) })); - if ocx.evaluate_obligations_error_on_ambiguity().is_empty() && count > 0 { + if ocx.evaluate_obligations_error_on_ambiguity().no_errors() && count > 0 { diag.span_suggestion_verbose( tcx.hir_body(*body).value.peel_blocks().span.shrink_to_lo(), msg!("dereference the return value"), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 8229be10960f9..6f1f977823c8e 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_index::bit_set::DenseBitSet; use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; +use rustc_infer::traits::TraitErrors; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location}; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::relate::Relate; @@ -660,12 +661,12 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> { span, ) { Ok(_) => ocx.evaluate_obligations_error_on_ambiguity(), - Err(e) => e, + Err(e) => TraitErrors::HasErrors(e), }; // Could have no errors if a type lowering error, say, caused the query // to fail. - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { typeck.infcx.err_ctxt().report_fulfillment_errors(errors); } }); diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index a1239cab05598..40ff5fa58de69 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -143,7 +143,7 @@ pub fn validate_trivial_unsize<'tcx>( ) else { return false; }; - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { return false; } infcx.leak_check(universe, None).is_ok() diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index e0388f3cc7464..bf37bc941dd12 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -416,7 +416,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { })); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if errors.is_empty() { + if errors.no_errors() { Some(ConstConditionsHold::Yes) } else { tcx.dcx() diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index d6578def58692..fa54d1ed4e562 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -118,7 +118,7 @@ impl Qualif for HasMutInterior { ); ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - !errors.is_empty() + !errors.no_errors() } fn is_structural_in_adt_value<'tcx>(_cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool { @@ -195,7 +195,7 @@ impl Qualif for NeedsNonConstDrop { }, ), )); - !ocx.evaluate_obligations_error_on_ambiguity().is_empty() + !ocx.evaluate_obligations_error_on_ambiguity().no_errors() } fn is_structural_in_adt_value<'tcx>(cx: &ConstCx<'_, 'tcx>, adt: AdtDef<'tcx>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 1b23432c8c57a..ce8560fd2acd9 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -43,7 +43,7 @@ pub(crate) fn type_implements_dyn_trait<'tcx, M: Machine<'tcx>>( }); Obligation::new(ecx.tcx.tcx, ObligationCause::dummy(), param_env, pred) })); - let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().is_empty(); + let type_impls_trait = ocx.evaluate_obligations_error_on_ambiguity().no_errors(); // Since `assumed_wf_tys=[]` the choice of LocalDefId is irrelevant, so using the "default" let regions_are_valid = ocx.resolve_regions(CRATE_DEF_ID, param_env, []).is_empty(); diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index ad958c1f282e7..66c537b4b18b0 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -43,5 +43,5 @@ pub fn relate_types<'tcx>( Ok(()) => {} Err(_) => return false, }; - ocx.evaluate_obligations_error_on_ambiguity().is_empty() + ocx.evaluate_obligations_error_on_ambiguity().no_errors() } diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 4075efbd240bc..20c3ac6036678 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -186,7 +186,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { ty, ); let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { // We shouldn't have errors here in the old solver, except for // evaluate/fulfill mismatches, but that's not a reason for an ICE. debug!(?errors, "encountered errors while fulfilling"); diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 2d56f2f1542ab..972c6715ee345 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -312,7 +312,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>( // obligation cause code, and perhaps some custom logic in `report_region_errors`. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if !errors.no_errors() { let mut guar = None; let mut root_predicates = FxHashSet::default(); for error in errors { diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index be821e2044a5b..f7d6af3c65dda 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -10,7 +10,7 @@ use rustc_hir::attrs::ReprAttr::ReprPacked; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::{LangItem, Node, find_attr, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc}; +use rustc_infer::traits::{Obligation, ObligationCauseCode, TraitErrors, WellFormedLoc}; use rustc_lint_defs::builtin::UNSUPPORTED_CALLING_CONVENTIONS; use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; @@ -409,7 +409,7 @@ fn check_opaque_meets_bounds<'tcx>( // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let guar = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } @@ -2292,7 +2292,7 @@ pub(super) fn check_coroutine_obligations( let errors = ocx.evaluate_obligations_error_on_ambiguity(); debug!(?errors); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } @@ -2336,5 +2336,9 @@ pub(super) fn check_potentially_region_dependent_goals<'tcx>( let errors = ocx.evaluate_obligations_error_on_ambiguity(); debug!(?errors); - if errors.is_empty() { Ok(()) } else { Err(infcx.err_ctxt().report_fulfillment_errors(errors)) } + if let TraitErrors::HasErrors(errors) = errors { + Err(infcx.err_ctxt().report_fulfillment_errors(errors)) + } else { + Ok(()) + } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_eii.rs b/compiler/rustc_hir_analysis/src/check/compare_eii.rs index 57824a91a680f..a723a2119c3ec 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_eii.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_eii.rs @@ -13,7 +13,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, FnSig, HirId, ItemKind, find_attr}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; +use rustc_infer::traits::{ObligationCause, ObligationCauseCode, TraitErrors}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; @@ -138,7 +138,7 @@ pub(crate) fn compare_eii_function_types<'tcx>( // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -207,7 +207,7 @@ pub(crate) fn compare_eii_statics<'tcx>( // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } 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 7cfe32b78b577..a2e1107be547f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisit}; use rustc_infer::infer::{self, BoundRegionConversionTime, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::util; +use rustc_infer::traits::{TraitErrors, util}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, BottomUpFolder, GenericArgs, GenericParamDefKind, Generics, RegionExt, Ty, TyCtxt, @@ -382,7 +382,7 @@ fn compare_method_clause_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -691,7 +691,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // Check that all obligations are satisfied by the implementation's // RPITs. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { if let Err(guar) = try_report_async_mismatch(tcx, infcx, &errors, trait_m, impl_m, impl_sig) { return Err(guar); @@ -1277,7 +1277,7 @@ fn check_region_late_boundedness<'tcx>( }; let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { return None; } @@ -2294,7 +2294,7 @@ fn compare_const_clause_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } @@ -2429,7 +2429,7 @@ fn compare_type_clause_entailment<'tcx>( // Check that all obligations are satisfied by the implementation's // version. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -2560,7 +2560,7 @@ pub(super) fn check_type_bounds<'tcx>( // version. ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } 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 6b5313e4254fa..0b40d80231d0e 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 @@ -179,7 +179,7 @@ pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>( param_env, Unnormalized::new_wip(trait_m_sig.inputs_and_output), )); - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (selection)"); return; } diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index a18fdcfa6f5fe..c34147756f153 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -3,6 +3,7 @@ use std::ops::Not; use rustc_hir as hir; use rustc_hir::{Node, find_attr}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::traits::TraitErrors; use rustc_middle::span_bug; use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized}; use rustc_session::config::EntryFnType; @@ -133,7 +134,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) -> Result<(), ErrorGuar let norm_return_ty = ocx.normalize(&cause, param_env, Unnormalized::new_wip(return_ty)); ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 6986ee1aa837f..aabb41cecfb93 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -83,7 +83,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::DenseBitSet; use rustc_infer::infer::{self, TyCtxtInferExt as _}; -use rustc_infer::traits::ObligationCause; +use rustc_infer::traits::{ObligationCause, TraitErrors}; use rustc_middle::middle::stability::EvalResult; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -694,7 +694,7 @@ pub fn check_function_signature<'tcx>( match ocx.eq(&cause, param_env, expected_sig, actual_sig) { Ok(()) => { let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 35628e54769b4..4f63408abdb33 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -15,7 +15,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{AmbigArg, ItemKind, find_attr}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::traits::PredicateObligations; +use rustc_infer::traits::{PredicateObligations, TraitErrors}; use rustc_lint_defs::builtin::SHADOWING_SUPERTRAIT_ITEMS; use rustc_macros::Diagnostic; use rustc_middle::mir::interpret::ErrorHandled; @@ -178,7 +178,7 @@ where f(&mut wfcx)?; let errors = wfcx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } @@ -1888,7 +1888,7 @@ fn receiver_is_valid<'tcx>( if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(wfcx.infcx); ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; - if ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if ocx.evaluate_obligations_error_on_ambiguity().no_errors() { Ok(()) } else { Err(NoSolution) @@ -1927,7 +1927,7 @@ fn receiver_is_valid<'tcx>( if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(wfcx.infcx); ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?; - if ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if ocx.evaluate_obligations_error_on_ambiguity().no_errors() { Ok(()) } else { Err(NoSolution) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index ecc7b170818d2..805993984ad81 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -4,13 +4,14 @@ use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::ItemKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::{self, InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt}; -use rustc_infer::traits::Obligation; +use rustc_infer::traits::{Obligation, TraitErrors}; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::relate::solver_relating::RelateExt; @@ -424,7 +425,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]), )); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { if is_from_coerce_pointee_derive(tcx, span) { return Err(tcx.dcx().emit_err(diagnostics::CoerceFieldValidity { span, @@ -543,7 +544,7 @@ fn assert_field_type_is_reborrow<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, span: Span, -) -> Result<(), Vec>> { +) -> Result<(), ThinVec>> { if ty.ref_mutability() == Some(ty::Mutability::Mut) { // Mutable references are Reborrow but not really. return Ok(()); @@ -555,7 +556,7 @@ fn assert_field_type_is_reborrow<'tcx>( ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { Err(errors) } else { Ok(()) } + if let TraitErrors::HasErrors(errors) = errors { Err(errors) } else { Ok(()) } } pub(crate) fn coerce_shared_info<'tcx>( @@ -709,7 +710,7 @@ pub(crate) fn coerce_shared_info<'tcx>( ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); } // Finally, resolve all regions. @@ -774,7 +775,7 @@ fn assert_field_type_is_copy<'tcx>( ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { Err(infcx.err_ctxt().report_fulfillment_errors(errors)) } else { Ok(()) @@ -996,7 +997,7 @@ pub(crate) fn coerce_unsized_info<'tcx>( ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { if is_from_coerce_pointee_derive(tcx, span) { return Err(tcx.dcx().emit_err(diagnostics::CoerceFieldValidity { span, diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1cf5da0522c2c..34a7c3b7c01de 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -332,7 +332,7 @@ fn orphan_check<'tcx>( let ty = ocx.normalize(&cause, ty::ParamEnv::empty(), Unnormalized::new_wip(user_ty)); let ty = infcx.resolve_vars_if_possible(ty); let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { return Ok(user_ty); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index bf17952313479..6394760baa766 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -20,6 +20,7 @@ use std::{assert_matches, debug_assert_matches, iter}; use rustc_abi::{ExternAbi, Size}; use rustc_ast::Recovered; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, Diagnostic, E0228, ErrorGuaranteed, Level, StashKey, }; @@ -400,7 +401,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { _span: Span, self_ty: Ty<'tcx>, candidates: Vec, - ) -> (Vec, Vec>) { + ) -> (Vec, ThinVec>) { assert!(!self_ty.has_infer()); // We don't just call the normal normalization routine here as we can't provide the @@ -443,7 +444,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { }) .collect(); - (candidates, vec![]) + (candidates, thin_vec![]) } fn lower_assoc_item_path( @@ -1369,7 +1370,7 @@ pub fn suggest_impl_trait<'tcx>( )), ); // FIXME(compiler-errors): We may benefit from resolving regions here. - if ocx.try_evaluate_obligations().is_empty() + if ocx.try_evaluate_obligations().no_errors() && let item_ty = infcx.resolve_vars_if_possible(item_ty) && let Some(item_ty) = item_ty.make_suggestable(infcx.tcx, false, None) && let Some(sugg) = formatter( diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 460ef9d56dee5..3ba2c0b5acbd0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; +use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ @@ -884,7 +885,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { name: Ident, self_ty: Ty<'tcx>, candidates: Vec, - fulfillment_errors: Vec>, + fulfillment_errors: ThinVec>, span: Span, assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { 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 aea2226815ce4..e4f8599226f76 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -25,6 +25,7 @@ use rustc_abi::FIRST_VARIANT; use rustc_ast::LitKind; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::sso::SsoHashSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, StashKey, @@ -179,7 +180,7 @@ pub trait HirTyLowerer<'tcx> { span: Span, self_ty: Ty<'tcx>, candidates: Vec, - ) -> (Vec, Vec>); + ) -> (Vec, ThinVec>); /// Lower a path to an associated item (of a trait) to a projection. /// diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index b8cb4c7f0e7c7..5a0801e1baaa3 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -68,8 +68,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::ObligationCause; use rustc_infer::traits::specialization_graph::Node; +use rustc_infer::traits::{ObligationCause, TraitErrors}; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode, @@ -184,7 +184,7 @@ fn get_impl_args( ); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(errors); return Err(guar); } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 986e127ac6b8b..f0f61edaa8c94 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -181,7 +181,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(InferOk { value, obligations }) if self.next_trait_solver() => { let ocx = ObligationCtxt::new(self); ocx.register_obligations(obligations); - if ocx.try_evaluate_obligations().is_empty() { + if ocx.try_evaluate_obligations().no_errors() { Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { Err(TypeError::Mismatch) @@ -1002,7 +1002,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ocx = ObligationCtxt::new(&self.infcx); ocx.register_obligation(obligation); let errs = ocx.evaluate_obligations_error_on_ambiguity(); - if errs.is_empty() { + if errs.no_errors() { Ok(InferOk { value: ( vec![Adjustment { @@ -1181,7 +1181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; }; ocx.register_obligations(ok.obligations); - ocx.try_evaluate_obligations().is_empty() + ocx.try_evaluate_obligations().no_errors() }) } @@ -1354,7 +1354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = if self.next_trait_solver() { let ocx = ObligationCtxt::new(self); let value = ocx.lub(cause, self.param_env, prev_ty, new_ty)?; - if ocx.try_evaluate_obligations().is_empty() { + if ocx.try_evaluate_obligations().no_errors() { Ok(InferOk { value, obligations: ocx.into_pending_obligations() }) } else { Err(TypeError::Mismatch) @@ -1950,7 +1950,7 @@ impl<'tcx> CoerceMany<'tcx> { )) }), ); - ocx.try_evaluate_obligations().is_empty() + ocx.try_evaluate_obligations().no_errors() }) }; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6f9b6a4f14ce9..bf25513a9a60c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -10,6 +10,7 @@ use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ @@ -1041,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn point_at_return_for_opaque_ty_error( &self, - errors: &mut Vec>, + errors: &mut ThinVec>, hir_id: HirId, span: Span, return_expr_ty: Ty<'tcx>, @@ -1869,7 +1870,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?; - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { return Err(TypeError::Mismatch); } Ok(self.resolve_vars_if_possible(adt_ty)) @@ -3615,14 +3616,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Bail if we have ambiguity errors, which we can't report in a useful way. let ambiguity_errors = ocx.evaluate_obligations_error_on_ambiguity(); - if true_errors.is_empty() && !ambiguity_errors.is_empty() { + if true_errors.no_errors() && ambiguity_errors.has_errors() { return Err(NoSolution); } // There should be at least one error reported. If not, we // will still delay a span bug in `report_fulfillment_errors`. Ok::<_, NoSolution>(( - self.err_ctxt().report_fulfillment_errors(true_errors), + self.err_ctxt().report_fulfillment_errors(true_errors.into_thin_vec()), impl_trait_ref.args.type_at(1), element_ty, )) @@ -3630,7 +3631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .ok() } - fn point_at_index(&self, errors: &mut Vec>, span: Span) { + fn point_at_index(&self, errors: &mut ThinVec>, span: Span) { let mut seen_preds = FxHashSet::default(); // We re-sort here so that the outer most root obligations comes first, as we have the // subsequent weird logic to identify *every* relevant obligation for proper deduplication diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 0e34a6120b609..db312e65b2679 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -370,7 +370,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // If we have no errors with `fallback = ()`, but *do* have errors with `fallback = !`, // then this code will be broken by the never type fallback change. let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit); - if unit_errors.is_empty() + if unit_errors.no_errors() && let mut never_errors = remaining_errors_if_fallback_to(self.tcx.types.never) && let [never_error, ..] = never_errors.as_mut_slice() { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 1886888c476a0..2fc4db504d39a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -3,6 +3,7 @@ use std::slice; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, }; @@ -21,6 +22,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; +use rustc_infer::traits::TraitErrors; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, DerefAdjustKind, @@ -719,9 +721,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(crate) fn report_ambiguity_errors(&self) { - let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self); + let errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self); - if !errors.is_empty() { + if let TraitErrors::HasErrors(mut errors) = errors { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); self.err_ctxt().report_fulfillment_errors(errors); } @@ -730,10 +732,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Select as many obligations as we can at present. pub(crate) fn select_obligations_where_possible( &self, - mutate_fulfillment_errors: impl Fn(&mut Vec>), + mutate_fulfillment_errors: impl Fn(&mut ThinVec>), ) { - let mut result = self.fulfillment_cx.borrow_mut().try_evaluate_obligations(self); - if !result.is_empty() { + let result = self.fulfillment_cx.borrow_mut().try_evaluate_obligations(self); + if let TraitErrors::HasErrors(mut result) = result { mutate_fulfillment_errors(&mut result); self.adjust_fulfillment_errors_for_expr_obligation(&mut result); self.err_ctxt().report_fulfillment_errors(result); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 0cb0562a368ff..83a755d0cf5aa 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -4,6 +4,7 @@ use std::{fmt, iter}; use itertools::Itertools; use rustc_ast as ast; use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize}; use rustc_hir as hir; @@ -269,7 +270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { return Err(TypeError::Mismatch); } @@ -653,7 +654,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let type_errors = ocx.try_evaluate_obligations(); - if type_errors.is_empty() { + if type_errors.no_errors() { new_tupled_type } else { let guar = struct_span_code_err!( @@ -1544,7 +1545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// have been created with different [`ObligationCause`][traits::ObligationCause]s. pub(super) fn adjust_fulfillment_errors_for_expr_obligation( &self, - errors: &mut Vec>, + errors: &mut ThinVec>, ) { // Store a mapping from `(Span, Predicate) -> ObligationCause`, so that // other errors that have the same span and predicate can also get fixed, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 287e3857087e7..f062ef288b0f7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -9,6 +9,7 @@ use std::cell::{Cell, RefCell}; use std::ops::Deref; pub(crate) use inspect_obligations::UseSubtyping; +use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; use rustc_errors::DiagCtxtHandle; use rustc_hir::attrs::{DivergingBlockBehavior, DivergingFallbackBehavior}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -17,7 +18,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ HirTyLowerer, InherentAssocCandidate, RegionInferReason, }; use rustc_infer::infer::{self, RegionVariableOrigin}; -use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; +use rustc_infer::traits::{DynCompatibilityViolation, Obligation, TraitErrors}; use rustc_middle::ty::{ self, CantBeErased, Const, Flags, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized, }; @@ -312,10 +313,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { span: Span, self_ty: Ty<'tcx>, candidates: Vec, - ) -> (Vec, Vec>) { + ) -> (Vec, ThinVec>) { let tcx = self.tcx(); let infcx = &self.infcx; - let mut fulfillment_errors = vec![]; + let mut fulfillment_errors = thin_vec![]; let mut filter_iat_candidate = |self_ty, impl_| { let ocx = ObligationCtxt::new_with_diagnostics(self); @@ -344,8 +345,8 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { ); ocx.register_obligations(impl_obligations); - let mut errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + let errors = ocx.try_evaluate_obligations(); + if let TraitErrors::HasErrors(mut errors) = errors { fulfillment_errors.append(&mut errors); return false; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b28eb8ad940d9..0e63e0d7fa575 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2095,7 +2095,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let manually_impl = "consider manually implementing `Clone` to avoid the \ implicit type parameter bounds"; - match &errors[..] { + match errors.as_slice() { [] => {} [error] => { let msg = "`Clone` is not implemented because a trait bound is not \ @@ -2126,6 +2126,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => { let unsatisfied_bounds: Vec<_> = errors + .as_slice() .iter() .filter_map(|error| match error.obligation.cause.code() { traits::ObligationCauseCode::ImplDerived(data) => { @@ -2160,12 +2161,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unsatisfied_bounds_spans.push_span_label(span, label); } diag.span_help(unsatisfied_bounds_spans, msg); - if errors.iter().all(|error| match error.obligation.cause.code() { - traits::ObligationCauseCode::ImplDerived(data) => { - self.tcx.is_automatically_derived(data.impl_or_alias_def_id) - && data.impl_or_alias_def_id.is_local() + if errors.as_slice().iter().all(|error| { + match error.obligation.cause.code() { + traits::ObligationCauseCode::ImplDerived(data) => { + self.tcx + .is_automatically_derived(data.impl_or_alias_def_id) + && data.impl_or_alias_def_id.is_local() + } + _ => false, } - _ => false, }) { diag.help(manually_impl); suggest_derive = false; @@ -2173,8 +2177,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { diag.help(format!( "{msg}: {}", - listify(&errors, |e| format!("`{}`", e.obligation.predicate)) - .unwrap(), + listify(errors.as_slice(), |e| format!( + "`{}`", + e.obligation.predicate + )) + .unwrap(), )); } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index eab4e1990455c..4f003bd18bdcb 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -2003,7 +2003,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.next_trait_solver() { ocx.register_obligations(instantiate_self_ty_obligations.iter().cloned()); let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { unreachable!("unexpected autoderef error {errors:?}"); } } @@ -2331,7 +2331,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }; let ocx = ObligationCtxt::new(self); let self_ty = ocx.register_infer_ok_obligations(ok); - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { debug!("failed to prove instantiate self_ty obligations"); return false; } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 9605b956f53a4..99833a5f81cb9 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -2,6 +2,7 @@ use rustc_ast::{self as ast, AssignOp, BinOp}; use rustc_data_structures::packed::Pu128; +use rustc_data_structures::thin_vec::{ThinVec, thin_vec}; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; use rustc_hir::def_id::DefId; @@ -272,7 +273,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op: Op, expected: Expectation<'tcx>, lhs_ty: Ty<'tcx>, - result: Result, Vec>>, + result: Result, ThinVec>>, rhs_ty: Ty<'tcx>, ) -> Ty<'tcx> { match result { @@ -335,7 +336,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, lhs_ty: Ty<'tcx>, rhs_ty: Ty<'tcx>, - errors: Vec>, + errors: ThinVec>, ) -> Ty<'tcx> { let (_, trait_def_id) = lang_item_for_binop(self.tcx, op); @@ -1074,10 +1075,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (opname, trait_did): (Symbol, Option), span: Span, expected: Expectation<'tcx>, - ) -> Result, Vec>> { + ) -> Result, ThinVec>> { let Some(trait_did) = trait_did else { // Bail if the operator trait is not defined. - return Err(vec![]); + return Err(thin_vec![]); }; debug!( @@ -1155,7 +1156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); ocx.register_obligation(obligation); - Err(ocx.evaluate_obligations_error_on_ambiguity()) + Err(ocx.evaluate_obligations_error_on_ambiguity().into_thin_vec()) } } } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 733cf757a17cb..1bb4e7e8f618c 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -28,7 +28,9 @@ use crate::infer::{ TypeOutlivesConstraint, }; use crate::traits::query::NoSolution; -use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine}; +use crate::traits::{ + ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine, TraitErrors, +}; impl<'tcx> InferCtxt<'tcx> { /// This method is meant to be invoked as the final step of a canonical query @@ -129,10 +131,17 @@ impl<'tcx> InferCtxt<'tcx> { // Select everything, returning errors. let errors = fulfill_cx.evaluate_obligations_error_on_ambiguity(self); - // True error! - if errors.iter().any(|e| e.is_true_error()) { - return Err(NoSolution); - } + let certainty = match errors { + TraitErrors::HasErrors(errors) => { + if errors.iter().any(|e| e.is_true_error()) { + // True error! + return Err(NoSolution); + } else { + Certainty::Ambiguous + } + } + TraitErrors::NoErrors => Certainty::Proven, + }; let region_obligations = self.take_registered_region_obligations(); let region_assumptions = self.take_registered_region_assumptions(); @@ -146,8 +155,6 @@ impl<'tcx> InferCtxt<'tcx> { }); debug!(?region_constraints); - let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; - let opaque_types = self .inner .borrow_mut() diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 6adec25be32f0..5ee2d8992b773 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -2,6 +2,7 @@ use std::fmt::Debug; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Ty, TyVid, Upcast}; +use thin_vec::{ThinVec, thin_vec}; use super::{ObligationCause, PredicateObligation, PredicateObligations}; use crate::infer::InferCtxt; @@ -33,6 +34,90 @@ impl<'tcx> ScrubbedTraitError<'tcx> { } } +#[derive(Debug, Clone)] +#[must_use] +pub enum TraitErrors { + HasErrors(ThinVec), + NoErrors, +} + +impl TraitErrors { + #[inline] + pub fn from_iter(iter: impl ExactSizeIterator) -> TraitErrors { + if iter.len() == 0 { TraitErrors::NoErrors } else { TraitErrors::HasErrors(iter.collect()) } + } + + #[inline] + pub fn has_errors(&self) -> bool { + matches!(self, TraitErrors::HasErrors(_)) + } + + #[inline] + pub fn no_errors(&self) -> bool { + matches!(self, TraitErrors::NoErrors) + } + + #[inline] + pub fn as_slice(&self) -> &[E] { + match self { + TraitErrors::HasErrors(errors) => errors.as_slice(), + TraitErrors::NoErrors => &[], + } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [E] { + match self { + TraitErrors::HasErrors(errors) => errors.as_mut_slice(), + TraitErrors::NoErrors => &mut [], + } + } + + #[inline] + pub fn into_thin_vec(self) -> ThinVec { + match self { + TraitErrors::HasErrors(errors) => errors, + TraitErrors::NoErrors => ThinVec::new(), + } + } + + #[cold] + pub fn push(&mut self, err: E) { + match self { + TraitErrors::HasErrors(errors) => errors.push(err), + TraitErrors::NoErrors => *self = TraitErrors::HasErrors(thin_vec![err]), + } + } + + #[inline] + pub fn len(&self) -> usize { + match self { + TraitErrors::HasErrors(errors) => errors.len(), + TraitErrors::NoErrors => 0, + } + } +} + +impl IntoIterator for TraitErrors { + type Item = E; + type IntoIter = thin_vec::IntoIter; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.into_thin_vec().into_iter() + } +} + +impl<'a, E> IntoIterator for &'a TraitErrors { + type Item = &'a E; + type IntoIter = std::slice::Iter<'a, E>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.as_slice().iter() + } +} + pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { /// Requires that `ty` must implement the trait with `def_id` in /// the given environment. This trait must not have any type @@ -82,9 +167,9 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { /// /// Returns a list of errors from obligations that evaluated to Err. #[must_use] - fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> Vec; + fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors; - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec; + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors; /// Evaluate all pending obligations, return error if they can't be evaluated. /// @@ -95,9 +180,12 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { /// /// Returns a list of errors from obligations that evaluated to Ambiguous or Err. #[must_use] - fn evaluate_obligations_error_on_ambiguity(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { + fn evaluate_obligations_error_on_ambiguity( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> TraitErrors { let errors = self.try_evaluate_obligations(infcx); - if !errors.is_empty() { + if errors.has_errors() { return errors; } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 219d7efa391e3..86aae77adcf8e 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; use thin_vec::ThinVec; -pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine}; +pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine, TraitErrors}; pub(crate) use self::project::UndoLog; pub use self::project::{ MismatchedProjectionTypes, Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry, diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index a7c5943c250b8..25fc52540d4f9 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -187,5 +187,5 @@ fn suggest_question_mark<'tcx>( into_iterator_did, ); - ocx.evaluate_obligations_error_on_ambiguity().is_empty() + ocx.evaluate_obligations_error_on_ambiguity().no_errors() } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 61578ee2892d5..d9dfe5fa7de0c 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { cx.param_env, Unnormalized::new_wip(assoc_pred), ); - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { // Can't normalize for some reason...? continue; } @@ -172,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { // If that predicate doesn't hold modulo regions (but passed during type-check), // then we must've taken advantage of the hack in `project_and_unify_types` where // we replace opaques with inference vars. Emit a warning! - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { // If it's a trait bound and an opaque that doesn't satisfy it, // then we can emit a suggestion to add the bound. let add_bound = match (proj_term.kind(), assoc_pred.kind().skip_binder()) { diff --git a/compiler/rustc_mir_transform/src/coroutine/layout.rs b/compiler/rustc_mir_transform/src/coroutine/layout.rs index ad0a3207cfbb0..58678e46e559b 100644 --- a/compiler/rustc_mir_transform/src/coroutine/layout.rs +++ b/compiler/rustc_mir_transform/src/coroutine/layout.rs @@ -29,6 +29,7 @@ use rustc_errors::pluralize; use rustc_hir::{self as hir, find_attr}; use rustc_index::bit_set::{BitMatrix, DenseBitSet}; use rustc_index::{Idx, IndexVec}; +use rustc_infer::traits::TraitErrors; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, Ty, TyCtxt, TypingMode}; @@ -515,7 +516,7 @@ fn check_field_tys_sized<'tcx>( let errors = ocx.evaluate_obligations_error_on_ambiguity(); debug!(?errors); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { infcx.err_ctxt().report_fulfillment_errors(errors); } } diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 4413d5064bd14..b4eb90f4507c9 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -622,7 +622,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { param_env, pred, )); - ocx.evaluate_obligations_error_on_ambiguity().is_empty() + ocx.evaluate_obligations_error_on_ambiguity().no_errors() } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a55d38251c843..fab7d35cbcec0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -47,7 +47,7 @@ use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; -use rustc_trait_selection::traits::ObligationCtxt; +use rustc_trait_selection::traits::{ObligationCtxt, TraitErrors}; use crate::diagnostics; @@ -1446,7 +1446,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // proc macro is not WF. let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { return; } @@ -1513,7 +1513,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { infcx.err_ctxt().report_fulfillment_errors(errors); self.abort.set(true); } diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index d81eabc032f32..2fc94c70d28e8 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, Unnormalized}; use rustc_span::Span; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt; -use rustc_trait_selection::traits; +use rustc_trait_selection::traits::{self, TraitErrors}; pub fn test_layout(tcx: TyCtxt<'_>) { if !tcx.features().rustc_attrs() { @@ -50,7 +50,7 @@ pub fn ensure_wf<'tcx>( ); ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { infcx.err_ctxt().report_fulfillment_errors(errors); false } else { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 77c631d86bf59..1210a3ef57e32 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.probe(|_| { let ocx = ObligationCtxt::new(self); let normalized_fn_sig = ocx.normalize(&ObligationCause::dummy(), param_env, fn_sig); - if ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if ocx.evaluate_obligations_error_on_ambiguity().no_errors() { let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig); if !normalized_fn_sig.has_infer() { return normalized_fn_sig; 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 95c42b34499b6..3ef350613ee16 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -95,7 +95,7 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( ocx.register_obligations(obligations); } - ocx.try_evaluate_obligations().is_empty() + ocx.try_evaluate_obligations().no_errors() }) }; @@ -128,7 +128,7 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( return false; } - ocx.try_evaluate_obligations().is_empty() + ocx.try_evaluate_obligations().no_errors() }) }; 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 32e7a9535a830..95054de6d0734 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 @@ -18,8 +18,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem, Node, expr_needs_parens, find_attr}; use rustc_infer::infer::{InferOk, TypeTrace}; -use rustc_infer::traits::ImplSource; use rustc_infer::traits::solve::Goal; +use rustc_infer::traits::{ImplSource, TraitErrors}; use rustc_middle::traits::SignatureMismatchData; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -2161,7 +2161,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }), ); - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { return false; } @@ -2177,7 +2177,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { { terrs.push(terr); } - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { return false; } } @@ -2347,7 +2347,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) .is_err() { - return Vec::new(); + return TraitErrors::NoErrors; } ocx.register_obligations( self.tcx @@ -2370,10 +2370,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if !self.tcx.clauses_of(def_id).clauses.is_empty() { self.probe(|_| evaluate_obligations()) } else { - Vec::new() + TraitErrors::NoErrors }; - if failing_obligations.is_empty() { + if failing_obligations.no_errors() { (" implemented for `", "") } else { for error in failing_obligations { @@ -3842,7 +3842,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let ocx = ObligationCtxt::new(self); ocx.register_obligation(obligation); - if ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if ocx.evaluate_obligations_error_on_ambiguity().no_errors() { return Ok(( self.tcx .fn_trait_kind_from_def_id(trait_def_id) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index b072c6d3565eb..bc4d33b346efa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -23,6 +23,7 @@ use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_span::{DesugaringKind, ErrorGuaranteed, ExpnKind, Span}; +use thin_vec::ThinVec; use tracing::{info, instrument}; pub use self::overflow::*; @@ -140,7 +141,7 @@ pub enum DefIdOrName { impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub fn report_fulfillment_errors( &self, - mut errors: Vec>, + mut errors: ThinVec>, ) -> ErrorGuaranteed { #[derive(Debug)] struct ErrorDescriptor<'tcx> { 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 8c72f0d90bb58..3ce0c99e6669a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5445,7 +5445,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { param_env, projection, )); - if ocx.try_evaluate_obligations().is_empty() + if ocx.try_evaluate_obligations().no_errors() && let ty = self.resolve_vars_if_possible(ty) && !ty.is_ty_var() { @@ -5778,7 +5778,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pred, )); }); - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { // encountered errors. return; } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f55468d6324af..a633f5de16c6f 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; pub use rustc_infer::infer::*; +use rustc_infer::traits::TraitErrors; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{ @@ -25,7 +26,7 @@ impl<'tcx> InferCtxt<'tcx> { let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else { return false; }; - ocx.try_evaluate_obligations().is_empty() + ocx.try_evaluate_obligations().no_errors() }) } @@ -115,7 +116,7 @@ impl<'tcx> InferCtxt<'tcx> { trait_def_id: DefId, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Option>> { + ) -> Option>> { self.probe(|_snapshot| { let ocx = ObligationCtxt::new_with_diagnostics(self); ocx.register_obligation(Obligation::new( diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 342609d9d3bd5..b221824c14575 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -4,7 +4,7 @@ use std::mem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::{ - FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, + FromSolverError, PredicateObligation, PredicateObligations, TraitEngine, TraitErrors, }; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_next_trait_solver::solve::fast_path::compute_goal_fast_path; @@ -182,31 +182,20 @@ where } } - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { - #[allow(clippy::iter_skip_zero)] - self.obligations - .pending - .drain(..) - .map(|(obligation, _)| NextSolverError::Ambiguity(obligation)) - .chain( - self.obligations - .overflowed - .drain(..) - .map(|obligation| NextSolverError::Overflow(obligation)), - ) - .map(|e| E::from_solver_error(infcx, e)) - // Skip doesn't implement TrustedLen, so we use it to - // avoid Vec::from_iter specialization that seems - // to optimize poorly in combination with ThinVec::drain - // on this particular sequence. - // See https://github.com/rust-lang/rust/pull/160073 - .skip(0) - .collect() + #[inline] + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors { + if self.obligations.pending.is_empty() && self.obligations.overflowed.is_empty() { + // Typically in more than 99.9% of cases this condition is true, therefore we outline + // the other case. + TraitErrors::NoErrors + } else { + TraitErrors::HasErrors(collect_remaining_errors_impl(self, infcx)) + } } - fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { + fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); - let mut errors = Vec::new(); + let mut errors = TraitErrors::NoErrors; loop { let mut any_changed = false; for (mut obligation, stalled_on) in mem::take(&mut self.obligations.pending) { @@ -373,6 +362,29 @@ where } } +#[cold] +#[inline(never)] +fn collect_remaining_errors_impl<'tcx, E>( + cx: &mut FulfillmentCtxt<'tcx, E>, + infcx: &InferCtxt<'tcx>, +) -> ThinVec +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ + cx.obligations + .pending + .drain(..) + .map(|(obligation, _)| NextSolverError::Ambiguity(obligation)) + .chain( + cx.obligations + .overflowed + .drain(..) + .map(|obligation| NextSolverError::Overflow(obligation)), + ) + .map(|e| E::from_solver_error(infcx, e)) + .collect() +} + pub enum NextSolverError<'tcx> { TrueError(PredicateObligation<'tcx>), Ambiguity(PredicateObligation<'tcx>), diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index a1a7fdc6f6b82..4e718ed896add 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::infer::at::At; use rustc_infer::traits::solve::Goal; use rustc_infer::traits::{ - FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, + FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, TraitErrors, }; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{ @@ -11,6 +11,7 @@ use rustc_middle::ty::{ }; use rustc_next_trait_solver::normalize::{NormalizationFolder, NormalizationWasAmbiguous}; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; +use thin_vec::ThinVec; use super::{FulfillmentCtxt, NextSolverError}; use crate::solve::{Certainty, SolverDelegate}; @@ -170,7 +171,7 @@ impl<'me, 'tcx> TypeFolder> for ReplaceAliasWithInfer<'me, 'tcx> { pub fn deeply_normalize<'tcx, T, E>( at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>, -) -> Result> +) -> Result> where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, @@ -189,7 +190,7 @@ pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>( at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>, universes: Vec>, -) -> Result> +) -> Result> where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, @@ -216,7 +217,7 @@ pub fn deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals<'tc at: At<'_, 'tcx>, value: Unnormalized<'tcx, T>, universes: Vec>, -) -> Result<(T, Vec>>), Vec> +) -> Result<(T, Vec>>), ThinVec> where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, @@ -229,7 +230,7 @@ where } let errors = fulfill_cx.try_evaluate_obligations(at.infcx); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(errors); } @@ -240,7 +241,7 @@ where .collect(); let errors = fulfill_cx.collect_remaining_errors(at.infcx); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(errors); } @@ -269,7 +270,7 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { let infcx = self.at.infcx; - let result: Result<_, Vec>> = infcx.commit_if_ok(|_| { + let result: Result<_, ThinVec>> = infcx.commit_if_ok(|_| { deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( self.at, Unnormalized::new_wip(ty), @@ -284,7 +285,7 @@ impl<'tcx> TypeFolder> for DeeplyNormalizeForDiagnosticsFolder<'_, fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let infcx = self.at.infcx; - let result: Result<_, Vec>> = infcx.commit_if_ok(|_| { + let result: Result<_, ThinVec>> = infcx.commit_if_ok(|_| { deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals( self.at, Unnormalized::new_wip(ct), diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 13c4a9169d339..455a9359aea1c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -168,7 +168,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let ocx = ObligationCtxt::new(&infcx); ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if !errors.no_errors() { panic!("Unable to fulfill trait {trait_did:?} for '{ty:?}': {errors:?}"); } @@ -245,7 +245,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let ocx = ObligationCtxt::new(&infcx); ocx.register_bound(ObligationCause::dummy(), orig_env, fresh_ty, trait_did); let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { return AutoTraitResult::NegativeImpl; } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 70c381d8afc50..78ccf04d456a3 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -11,7 +11,7 @@ use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::find_attr; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::PredicateObligations; +use rustc_infer::traits::{PredicateObligations, TraitErrors}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::traits::query::NoSolution; @@ -425,7 +425,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let ocx = ObligationCtxt::new(infcx); ocx.register_obligations(obligations.iter().cloned()); let hard_errors = ocx.try_evaluate_obligations(); - if !hard_errors.is_empty() { + if let TraitErrors::HasErrors(hard_errors) = hard_errors { assert!( hard_errors.iter().all(|e| e.is_true_error()), "should not have detected ambiguity during first pass" @@ -691,7 +691,7 @@ fn try_prove_negated_where_clause<'tcx>( param_env, negative_predicate, )); - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { return false; } @@ -811,7 +811,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { Unnormalized::new_wip(ty), ) .map_err(|_| ())?; - if !ocx.try_evaluate_obligations().is_empty() { + if !ocx.try_evaluate_obligations().no_errors() { return Err(()); } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index ab2965a345360..74413d430b1cd 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -174,7 +174,7 @@ fn satisfied_from_param_env<'tcx>( if self.infcx.probe(|_| { let ocx = ObligationCtxt::new(self.infcx); ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok() - && ocx.evaluate_obligations_error_on_ambiguity().is_empty() + && ocx.evaluate_obligations_error_on_ambiguity().no_errors() }) { self.single_match = match self.single_match { None => Some(Ok(c)), @@ -215,7 +215,7 @@ fn satisfied_from_param_env<'tcx>( if let Some(Ok(c)) = single_match { let ocx = ObligationCtxt::new(infcx); assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok()); - assert!(ocx.evaluate_obligations_error_on_ambiguity().is_empty()); + assert!(ocx.evaluate_obligations_error_on_ambiguity().no_errors()); return true; } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 1990ebd913eca..da3e6f350f4b9 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -9,13 +9,14 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; -use rustc_infer::traits::PredicateObligations; +use rustc_infer::traits::{PredicateObligations, TraitErrors}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Unnormalized, Upcast, Variance}; +use thin_vec::ThinVec; use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine}; use crate::error_reporting::InferCtxtErrorExt; @@ -211,7 +212,7 @@ where /// /// Returns a list of errors from obligations that evaluated to Err. #[must_use] - pub fn try_evaluate_obligations(&self) -> Vec { + pub fn try_evaluate_obligations(&self) -> TraitErrors { self.engine.borrow_mut().try_evaluate_obligations(self.infcx) } @@ -224,7 +225,7 @@ where /// /// Returns a list of errors from obligations that evaluated to Ambiguous or Err. #[must_use] - pub fn evaluate_obligations_error_on_ambiguity(&self) -> Vec { + pub fn evaluate_obligations_error_on_ambiguity(&self) -> TraitErrors { self.engine.borrow_mut().evaluate_obligations_error_on_ambiguity(self.infcx) } @@ -310,10 +311,10 @@ where &self, param_env: ty::ParamEnv<'tcx>, def_id: LocalDefId, - ) -> Result>, Vec> { + ) -> Result>, ThinVec> { let tcx = self.infcx.tcx; let mut implied_bounds = FxIndexSet::default(); - let mut errors = Vec::new(); + let mut errors = ThinVec::new(); for &(ty, span) in tcx.assumed_wf_types(def_id) { // FIXME(@lcnr): rustc currently does not check wf for types // pre-normalization, meaning that implied bounds are sometimes @@ -347,7 +348,7 @@ where cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: Unnormalized<'tcx, T>, - ) -> Result> { + ) -> Result> { self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) } @@ -356,7 +357,7 @@ where cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: Unnormalized<'tcx, Ty<'tcx>>, - ) -> Result, Vec> { + ) -> Result, ThinVec> { self.infcx .at(cause, param_env) .structurally_normalize_ty(value, &mut **self.engine.borrow_mut()) @@ -367,7 +368,7 @@ where cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: Unnormalized<'tcx, ty::Const<'tcx>>, - ) -> Result, Vec> { + ) -> Result, ThinVec> { self.infcx .at(cause, param_env) .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) @@ -378,7 +379,7 @@ where cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, value: Unnormalized<'tcx, ty::Term<'tcx>>, - ) -> Result, Vec> { + ) -> Result, ThinVec> { self.infcx .at(cause, param_env) .structurally_normalize_term(value, &mut **self.engine.borrow_mut()) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 8179b0f6f01a1..532faa47f6bb6 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::traits::{ FromSolverError, PolyTraitObligation, PredicateObligations, ProjectionCacheKey, SelectionError, - TraitEngine, + TraitEngine, TraitErrors, }; use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -104,7 +104,7 @@ where } /// Attempts to select obligations using `selcx`. - fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec { + fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> TraitErrors { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); let infcx = selcx.infcx; @@ -116,11 +116,9 @@ where // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. - let errors: Vec = outcome - .errors - .into_iter() - .map(|err| E::from_solver_error(infcx, OldSolverError(err))) - .collect(); + let errors = TraitErrors::from_iter( + outcome.errors.into_iter().map(|err| E::from_solver_error(infcx, OldSolverError(err))), + ); debug!( "select({} predicates remaining, {} errors) done", @@ -154,15 +152,16 @@ where .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { - self.predicates - .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) - .into_iter() - .map(|err| E::from_solver_error(infcx, OldSolverError(err))) - .collect() + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors { + TraitErrors::from_iter( + self.predicates + .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) + .into_iter() + .map(|err| E::from_solver_error(infcx, OldSolverError(err))), + ) } - fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> Vec { + fn try_evaluate_obligations(&mut self, infcx: &InferCtxt<'tcx>) -> TraitErrors { let selcx = SelectionContext::new(infcx); self.select(selcx) } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 46616c84578cc..c5c4288ea64b2 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -4,9 +4,11 @@ use hir::LangItem; use rustc_ast::Mutability; use rustc_hir as hir; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::traits::TraitErrors; use rustc_middle::bug; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::{Span, sym}; +use thin_vec::ThinVec; use crate::regions::InferCtxtRegionExt; use crate::traits::{self, FulfillmentError, Obligation, ObligationCause}; @@ -27,7 +29,7 @@ pub enum ConstParamTyImplementationError<'tcx> { } pub enum InfringingFieldsReason<'tcx> { - Fulfill(Vec>), + Fulfill(ThinVec>), Regions(Vec>), } @@ -171,7 +173,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( ty::ClauseKind::UnstableFeature(sym::unsized_const_params), )); - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired); } } @@ -184,7 +186,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( ); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors))); continue; } @@ -256,7 +258,7 @@ pub fn all_fields_implement_trait<'tcx>( // such as when we project to a missing type or we have a mismatch // between expected and found const-generic types. Don't report an // additional copy error here, since it's not typically useful. - if !normalization_errors.is_empty() || ty.references_error() { + if !normalization_errors.no_errors() || ty.references_error() { tcx.dcx().span_delayed_bug( field_span, format!( @@ -274,7 +276,7 @@ pub fn all_fields_implement_trait<'tcx>( trait_def_id, ); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { infringing.push((field, ty, InfringingFieldsReason::Fulfill(errors))); } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 76607a0107ecb..734c1a703022c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -235,11 +235,11 @@ fn pred_known_to_hold_modulo_regions<'tcx>( ocx.register_obligation(obligation); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - match errors.as_slice() { + match errors { // Only known to hold if we did no inference. - [] => infcx.resolve_vars_if_possible(goal) == goal, + TraitErrors::NoErrors => infcx.resolve_vars_if_possible(goal) == goal, - errors => { + TraitErrors::HasErrors(errors) => { debug!(?errors); false } @@ -324,7 +324,7 @@ fn do_normalize_clauses<'tcx>( }; let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { let reported = infcx.err_ctxt().report_fulfillment_errors(errors); return Err(reported); } @@ -806,7 +806,7 @@ pub fn impossible_clauses<'tcx>(tcx: TyCtxt<'tcx>, clauses: Vec // with no infer vars. There may also be ways to encounter ambiguity due // to post-mono overflow. let true_errors = ocx.try_evaluate_obligations(); - if !true_errors.is_empty() { + if !true_errors.no_errors() { return true; } @@ -921,7 +921,7 @@ fn is_impossible_associated_item( let ocx = ObligationCtxt::new(&infcx); ocx.register_obligations(predicates_for_trait); - !ocx.try_evaluate_obligations().is_empty() + !ocx.try_evaluate_obligations().no_errors() } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index dfdf99cc904c6..74908ea577d0d 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -5,7 +5,7 @@ use rustc_errors::msg; use rustc_infer::infer::at::At; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ - FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, + FromSolverError, Normalized, Obligation, PredicateObligations, TraitEngine, TraitErrors, }; use rustc_macros::extension; use rustc_middle::span_bug; @@ -14,6 +14,7 @@ use rustc_middle::ty::{ self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingMode, Unnormalized, }; +use thin_vec::ThinVec; use tracing::{debug, instrument}; use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project}; @@ -58,7 +59,7 @@ impl<'tcx> At<'_, 'tcx> { self, value: Unnormalized<'tcx, T>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, - ) -> Result> + ) -> Result> where T: TypeFoldable>, E: FromSolverError<'tcx, NextSolverError<'tcx>>, @@ -79,14 +80,15 @@ impl<'tcx> At<'_, 'tcx> { .into_value_registering_obligations(self.infcx, &mut *fulfill_cx); let errors = fulfill_cx.evaluate_obligations_error_on_ambiguity(self.infcx); let value = self.infcx.resolve_vars_if_possible(value); - if errors.is_empty() { - Ok(value) - } else { - // Drop pending obligations, since deep normalization may happen - // in a loop and we don't want to trigger the assertion on the next - // iteration due to pending ambiguous obligations we've left over. - let _ = fulfill_cx.collect_remaining_errors(self.infcx); - Err(errors) + match errors { + TraitErrors::NoErrors => Ok(value), + TraitErrors::HasErrors(errors) => { + // Drop pending obligations, since deep normalization may happen + // in a loop and we don't want to trigger the assertion on the next + // iteration due to pending ambiguous obligations we've left over. + let _ = fulfill_cx.collect_remaining_errors(self.infcx); + Err(errors) + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index a9ed6126ea752..140e4d2a47b61 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -1,8 +1,10 @@ use rustc_data_structures::fx::FxHashSet; +use rustc_infer::traits::TraitErrors; use rustc_infer::traits::query::type_op::DropckOutlives; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt, Unnormalized}; use rustc_span::Span; +use thin_vec::ThinVec; use tracing::{debug, instrument}; use crate::solve::NextSolverError; @@ -104,7 +106,7 @@ pub fn compute_dropck_outlives_with_errors<'tcx, E>( ocx: &ObligationCtxt<'_, 'tcx, E>, goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, span: Span, -) -> Result, Vec> +) -> Result, ThinVec> where E: FromSolverError<'tcx, NextSolverError<'tcx>>, { @@ -200,7 +202,7 @@ where // obligations, and we may have pending obligations from the // branch above (from other types). let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(errors); } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 812e087a0cf69..25385d15e36f4 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -128,7 +128,7 @@ where ) })?; let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if errors.is_empty() { + if errors.no_errors() { Ok(value) } else if let Err(guar) = infcx.tcx.check_potentially_region_dependent_goals(root_def_id) { Err(guar) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 6abdaf404f103..b5fa71735f4e9 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -166,7 +166,7 @@ fn fulfill_implication<'tcx>( let ocx = ObligationCtxt::new(infcx); let source_trait_ref = ocx.normalize(cause, param_env, Unnormalized::new_wip(source_trait_ref)); - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { infcx.dcx().span_delayed_bug( infcx.tcx.def_span(source_impl), format!("failed to fully normalize {source_trait_ref}"), @@ -197,7 +197,7 @@ fn fulfill_implication<'tcx>( ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if !errors.no_errors() { // no dice! debug!( "fulfill_implication: for impls on {:?} and {:?}, \ @@ -294,7 +294,7 @@ pub(super) fn specializes( let ocx = ObligationCtxt::new(&infcx); let specializing_impl_trait_ref = ocx.normalize(cause, param_env, specializing_impl_trait_ref); - if !ocx.evaluate_obligations_error_on_ambiguity().is_empty() { + if !ocx.evaluate_obligations_error_on_ambiguity().no_errors() { infcx.dcx().span_delayed_bug( infcx.tcx.def_span(specializing_impl_def_id), format!("failed to fully normalize {specializing_impl_trait_ref}"), @@ -328,7 +328,7 @@ pub(super) fn specializes( ocx.register_obligations(obligations); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if !errors.no_errors() { // no dice! debug!( "fulfill_implication: for impls on {:?} and {:?}, \ @@ -364,7 +364,7 @@ pub(super) fn specializes( })); let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if !errors.no_errors() { // no dice! debug!( "fulfill_implication: for impls on {:?} and {:?}, \ diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index c73974d661365..2556c2baffada 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -1,7 +1,8 @@ use rustc_infer::infer::at::At; -use rustc_infer::traits::TraitEngine; +use rustc_infer::traits::{TraitEngine, TraitErrors}; use rustc_macros::extension; use rustc_middle::ty::{self, Ty, Unnormalized}; +use thin_vec::ThinVec; use crate::traits::{NormalizeExt, Obligation}; @@ -11,7 +12,7 @@ impl<'tcx> At<'_, 'tcx> { &self, ty: Unnormalized<'tcx, Ty<'tcx>>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, - ) -> Result, Vec> { + ) -> Result, ThinVec> { self.structurally_normalize_term(ty.map(Into::into), fulfill_cx) .map(|term| term.expect_type()) } @@ -20,7 +21,7 @@ impl<'tcx> At<'_, 'tcx> { &self, ct: Unnormalized<'tcx, ty::Const<'tcx>>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, - ) -> Result, Vec> { + ) -> Result, ThinVec> { if self.infcx.tcx.features().generic_const_exprs() { return Ok(super::evaluate_const(&self.infcx, ct.skip_normalization(), self.param_env)); } @@ -33,7 +34,7 @@ impl<'tcx> At<'_, 'tcx> { &self, term: Unnormalized<'tcx, ty::Term<'tcx>>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, - ) -> Result, Vec> { + ) -> Result, ThinVec> { assert!( !term.as_ref().skip_normalization().is_infer(), "should have resolved vars before calling" @@ -64,7 +65,7 @@ impl<'tcx> At<'_, 'tcx> { fulfill_cx.register_predicate_obligation(self.infcx, obligation); let errors = fulfill_cx.try_evaluate_obligations(self.infcx); - if !errors.is_empty() { + if let TraitErrors::HasErrors(errors) = errors { return Err(errors); } diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 9d3284e609260..e03b67f8e4d39 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -60,7 +60,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( // contains unbound type parameters. It could be a slight // optimization to stop iterating early. let errors = ocx.evaluate_obligations_error_on_ambiguity(); - if !errors.is_empty() { + if !errors.no_errors() { // `rustc_monomorphize::collector` assumes there are no type errors. // Cycle errors are the only post-monomorphization errors possible; emit them now so // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 96d5f4fb398e0..3710d41dba0d9 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -71,7 +71,7 @@ fn normalize_canonicalized_projection<'tcx>( // In that case, we may only realize a cycle error when calling // `normalize_erasing_regions` in mono. let errors = ocx.try_evaluate_obligations(); - if !errors.is_empty() { + if !errors.no_errors() { // Rustdoc may attempt to normalize type alias types which are not // well-formed. Rustdoc also normalizes types that are just not // well-formed, since we don't do as much HIR analysis (checking diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 80d9c53b108f5..a3b9d49b30900 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -28,7 +28,7 @@ fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { // // 2. We are sometimes doing future-incompatibility lints for // now, so we do not want unconditional errors here. - ocx.evaluate_obligations_error_on_ambiguity().is_empty() + ocx.evaluate_obligations_error_on_ambiguity().no_errors() } pub(crate) fn provide(providers: &mut Providers) { diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 9af3d72bcffa9..f4a3e01bbe0d4 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { // This is to prevent emitting warnings for e.g. holding a `::Output` across await // points, where `Fut` is a type parameter. - let is_send = send_errors.iter().all(|err| { + let is_send = send_errors.as_slice().iter().all(|err| { err.obligation .predicate .as_trait_clause() diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index b53215355e5b4..ca2cd7338d5a2 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -6,8 +6,8 @@ use crate::msrvs::{self, Msrv}; use hir::LangItem; use rustc_const_eval::check_consts::ConstCx; -use rustc_hir::def_id::DefId; use rustc_hir::attrs::RustcVersion; +use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, HirId, StableSince}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; @@ -492,7 +492,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> let ocx = ObligationCtxt::new(&infcx); ocx.register_obligations(impl_src.nested_obligations()); - ocx.evaluate_obligations_error_on_ambiguity().is_empty() + ocx.evaluate_obligations_error_on_ambiguity().no_errors() } !ty.needs_drop(tcx, ConstCx::new(tcx, body).typing_env)