From 9918693037dce8aa4bb6f08741b6812923486c18 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:26:03 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- .../rustc_trait_selection/src/traits/auto_trait.rs | 14 +- .../rustc_trait_selection/src/traits/coherence.rs | 155 ++++--- .../src/traits/const_evaluatable.rs | 12 +- .../rustc_trait_selection/src/traits/engine.rs | 27 +- .../src/traits/error_reporting/ambiguity.rs | 4 +- .../src/traits/error_reporting/infer_ctxt_ext.rs | 7 +- .../src/traits/error_reporting/on_unimplemented.rs | 263 ++++++++--- .../src/traits/error_reporting/suggestions.rs | 492 +++++++++++++++------ .../traits/error_reporting/type_err_ctxt_ext.rs | 446 +++++++++++++++---- .../rustc_trait_selection/src/traits/fulfill.rs | 58 ++- compiler/rustc_trait_selection/src/traits/misc.rs | 10 +- compiler/rustc_trait_selection/src/traits/mod.rs | 8 +- .../src/traits/object_safety.rs | 19 +- .../src/traits/outlives_bounds.rs | 10 +- .../rustc_trait_selection/src/traits/project.rs | 281 ++++++++---- .../src/traits/query/dropck_outlives.rs | 8 +- .../src/traits/query/evaluate_obligation.rs | 4 +- .../src/traits/query/normalize.rs | 18 +- .../src/traits/query/type_op/ascribe_user_type.rs | 2 +- .../src/traits/query/type_op/custom.rs | 4 +- .../src/traits/query/type_op/eq.rs | 2 +- .../query/type_op/implied_outlives_bounds.rs | 25 +- .../src/traits/query/type_op/mod.rs | 8 +- .../src/traits/query/type_op/normalize.rs | 4 +- .../src/traits/query/type_op/outlives.rs | 2 +- .../src/traits/query/type_op/prove_predicate.rs | 2 +- .../src/traits/query/type_op/subtype.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 90 +++- .../src/traits/select/confirmation.rs | 135 +++--- .../rustc_trait_selection/src/traits/select/mod.rs | 165 ++++--- .../src/traits/specialize/mod.rs | 43 +- .../src/traits/structural_match.rs | 2 +- .../src/traits/structural_normalize.rs | 65 ++- compiler/rustc_trait_selection/src/traits/util.rs | 51 ++- compiler/rustc_trait_selection/src/traits/wf.rs | 28 +- 35 files changed, 1661 insertions(+), 805 deletions(-) (limited to 'compiler/rustc_trait_selection/src/traits') diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 8096d7969..13a09917c 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -5,11 +5,9 @@ use super::*; use crate::errors::UnableToConstructConstantValue; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ImplPolarity, Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; @@ -252,7 +250,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { fresh_preds.insert(self.clean_pred(infcx, predicate.as_predicate())); } - let mut select = SelectionContext::new(&infcx); + let mut select = SelectionContext::new(infcx); let mut already_visited = FxHashSet::default(); let mut predicates = VecDeque::new(); @@ -410,11 +408,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { iter::zip(new_args.regions(), old_args.regions()) { match (*new_region, *old_region) { - // If both predicates have an `ReLateBound` (a HRTB) in the + // If both predicates have an `ReBound` (a HRTB) in the // same spot, we do nothing. - (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {} + (ty::ReBound(_, _), ty::ReBound(_, _)) => {} - (ty::ReLateBound(_, _), _) | (_, ty::ReVar(_)) => { + (ty::ReBound(_, _), _) | (_, ty::ReVar(_)) => { // One of these is true: // The new predicate has a HRTB in a spot where the old // predicate does not (if they both had a HRTB, the previous @@ -440,7 +438,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // `user_computed_preds`. return false; } - (_, ty::ReLateBound(_, _)) | (ty::ReVar(_), _) => { + (_, ty::ReBound(_, _)) | (ty::ReVar(_), _) => { // This is the opposite situation as the previous arm. // One of these is true: // @@ -820,9 +818,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { // the `ParamEnv`. ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::ObjectSafe(..) - | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index dcf5fd869..533fe32f7 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -6,8 +6,8 @@ use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::InferOk; -use crate::solve::inspect; use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; +use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::engine::TraitEngineExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::select::{IntercrateAmbiguityCause, TreatInductiveCycleAs}; @@ -20,15 +20,15 @@ use crate::traits::{ }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, TraitEngine}; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::solve::{Certainty, Goal}; +use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE; @@ -53,7 +53,7 @@ pub enum Conflict { pub struct OverlapResult<'tcx> { pub impl_header: ty::ImplHeader<'tcx>, - pub intercrate_ambiguity_causes: FxIndexSet, + pub intercrate_ambiguity_causes: FxIndexSet>, /// `true` if the overlap might've been permitted before the shift /// to universes. @@ -100,7 +100,7 @@ pub fn overlapping_impls( let impl1_ref = tcx.impl_trait_ref(impl1_def_id); let impl2_ref = tcx.impl_trait_ref(impl2_def_id); let may_overlap = match (impl1_ref, impl2_ref) { - (Some(a), Some(b)) => drcx.args_refs_may_unify(a.skip_binder().args, b.skip_binder().args), + (Some(a), Some(b)) => drcx.args_may_unify(a.skip_binder().args, b.skip_binder().args), (None, None) => { let self_ty1 = tcx.type_of(impl1_def_id).skip_binder(); let self_ty2 = tcx.type_of(impl2_def_id).skip_binder(); @@ -245,7 +245,7 @@ fn overlap<'tcx>( let trait_ref = infcx.resolve_vars_if_possible(trait_ref); format!( "of `{}` for `{}`", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), trait_ref.self_ty() ) } @@ -273,7 +273,6 @@ fn overlap<'tcx>( causing the impls to overlap", infcx.resolve_vars_if_possible(failing_obligation.predicate) )); - lint }, ); } @@ -308,7 +307,13 @@ fn overlap<'tcx>( .iter() .any(|c| c.0.involves_placeholders()); - let impl_header = selcx.infcx.resolve_vars_if_possible(impl1_header); + let mut impl_header = infcx.resolve_vars_if_possible(impl1_header); + + // Deeply normalize the impl header for diagnostics, ignoring any errors if this fails. + if infcx.next_trait_solver() { + impl_header = deeply_normalize_for_diagnostics(&infcx, param_env, impl_header); + } + Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) } @@ -329,7 +334,7 @@ fn equate_impl_headers<'tcx>( impl1.self_ty, impl2.self_ty, ), - _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), + _ => bug!("equate_impl_headers given mismatched impl kinds"), }; result.map(|infer_ok| infer_ok.obligations).ok() @@ -360,15 +365,23 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let infcx = selcx.infcx; obligations.iter().find(|obligation| { - if infcx.next_trait_solver() { - infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) + let evaluation_result = if infcx.next_trait_solver() { + infcx.evaluate_obligation(obligation) } else { // We use `evaluate_root_obligation` to correctly track intercrate // ambiguity clauses. We cannot use this in the new solver. - selcx.evaluate_root_obligation(obligation).map_or( - false, // Overflow has occurred, and treat the obligation as possibly holding. - |result| !result.may_apply(), - ) + selcx.evaluate_root_obligation(obligation) + }; + + match evaluation_result { + Ok(result) => !result.may_apply(), + // If overflow occurs, we need to conservatively treat the goal as possibly holding, + // since there can be instantiations of this goal that don't overflow and result in + // success. This isn't much of a problem in the old solver, since we treat overflow + // fatally (this still can be encountered: ), + // but in the new solver, this is very important for correctness, since overflow + // *must* be treated as ambiguity for completeness. + Err(_overflow) => false, } }) } @@ -396,8 +409,11 @@ fn impl_intersection_has_negative_obligation( ) -> bool { debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id); + // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates + // do not need intercrate mode enabled. let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build(); - let universe = infcx.universe(); + let root_universe = infcx.universe(); + assert_eq!(root_universe, ty::UniverseIndex::ROOT); let impl1_header = fresh_impl_header(infcx, impl1_def_id); let param_env = @@ -407,13 +423,25 @@ fn impl_intersection_has_negative_obligation( // Equate the headers to find their intersection (the general type, with infer vars, // that may apply both impls). - let Some(_equate_obligations) = + let Some(equate_obligations) = equate_impl_headers(infcx, param_env, &impl1_header, &impl2_header) else { return false; }; - plug_infer_with_placeholders(infcx, universe, (impl1_header.impl_args, impl2_header.impl_args)); + // FIXME(with_negative_coherence): the infcx has constraints from equating + // the impl headers. We should use these constraints as assumptions, not as + // requirements, when proving the negated where clauses below. + drop(equate_obligations); + drop(infcx.take_registered_region_obligations()); + drop(infcx.take_and_reset_region_constraints()); + + plug_infer_with_placeholders( + infcx, + root_universe, + (impl1_header.impl_args, impl2_header.impl_args), + ); + let param_env = infcx.resolve_vars_if_possible(param_env); util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args)) .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env)) @@ -458,7 +486,7 @@ fn plug_infer_with_placeholders<'tcx>( ), ) else { - bug!() + bug!("we always expect to be able to plug an infer var with placeholder") }; assert_eq!(obligations, &[]); ControlFlow::Continue(()) @@ -481,7 +509,7 @@ fn plug_infer_with_placeholders<'tcx>( ), ) else { - bug!() + bug!("we always expect to be able to plug an infer var with placeholder") }; assert_eq!(obligations, &[]); ControlFlow::Continue(()) @@ -515,7 +543,7 @@ fn plug_infer_with_placeholders<'tcx>( ), ) else { - bug!() + bug!("we always expect to be able to plug an infer var with placeholder") }; assert_eq!(obligations, &[]); } @@ -540,15 +568,11 @@ fn try_prove_negated_where_clause<'tcx>( return false; }; - // FIXME(with_negative_coherence): the infcx has region contraints from equating - // the impl headers as requirements. Given that the only region constraints we - // get are involving inference regions in the root, it shouldn't matter, but - // still sus. - // - // We probably should just throw away the region obligations registered up until - // now, or ideally use them as assumptions when proving the region obligations - // that we get from proving the negative predicate below. - let ref infcx = root_infcx.fork(); + // N.B. We don't need to use intercrate mode here because we're trying to prove + // the *existence* of a negative goal, not the non-existence of a positive goal. + // Without this, we over-eagerly register coherence ambiguity candidates when + // impl candidates do exist. + let ref infcx = root_infcx.fork_with_intercrate(false); let ocx = ObligationCtxt::new(infcx); ocx.register_obligation(Obligation::new( @@ -830,7 +854,7 @@ where } fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - // Need to lazily normalize here in with `-Ztrait-solver=next-coherence`. + // Need to lazily normalize here in with `-Znext-solver=coherence`. let ty = match (self.lazily_normalize_ty)(ty) { Ok(ty) => ty, Err(err) => return ControlFlow::Break(OrphanCheckEarlyExit::NormalizationFailure(err)), @@ -967,8 +991,8 @@ where fn compute_intercrate_ambiguity_causes<'tcx>( infcx: &InferCtxt<'tcx>, obligations: &[PredicateObligation<'tcx>], -) -> FxIndexSet { - let mut causes: FxIndexSet = Default::default(); +) -> FxIndexSet> { + let mut causes: FxIndexSet> = Default::default(); for obligation in obligations { search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes); @@ -977,11 +1001,11 @@ fn compute_intercrate_ambiguity_causes<'tcx>( causes } -struct AmbiguityCausesVisitor<'a> { - causes: &'a mut FxIndexSet, +struct AmbiguityCausesVisitor<'a, 'tcx> { + causes: &'a mut FxIndexSet>, } -impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { +impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { type BreakTy = !; fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow { let infcx = goal.infcx(); @@ -998,26 +1022,53 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { let Goal { param_env, predicate } = goal.goal(); - // For bound predicates we simply call `infcx.replace_bound_vars_with_placeholders` + // For bound predicates we simply call `infcx.instantiate_binder_with_placeholders` // and then prove the resulting predicate as a nested goal. let trait_ref = match predicate.kind().no_bound_vars() { Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref, - Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) => { + Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj))) + if matches!( + infcx.tcx.def_kind(proj.projection_ty.def_id), + DefKind::AssocTy | DefKind::AssocConst + ) => + { proj.projection_ty.trait_ref(infcx.tcx) } _ => return ControlFlow::Continue(()), }; + // Add ambiguity causes for reservation impls. + for cand in goal.candidates() { + if let inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(def_id), + result: Ok(_), + } = cand.kind() + { + if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) { + let message = infcx + .tcx + .get_attr(def_id, sym::rustc_reservation_impl) + .and_then(|a| a.value_str()); + if let Some(message) = message { + self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { message }); + } + } + } + } + + // Add ambiguity causes for unknowable goals. let mut ambiguity_cause = None; for cand in goal.candidates() { // FIXME: boiiii, using string comparisions here sure is scuffed. - if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } = - cand.kind() + if let inspect::ProbeKind::MiscCandidate { + name: "coherence unknowable", + result: Ok(_), + } = cand.kind() { let lazily_normalize_ty = |ty: Ty<'tcx>| { let mut fulfill_cx = >::new(infcx); if matches!(ty.kind(), ty::Alias(..)) { - // FIXME(-Ztrait-solver=next-coherence): we currently don't + // FIXME(-Znext-solver=coherence): we currently don't // normalize opaque types here, resulting in diverging behavior // for TAITs. match infcx @@ -1038,25 +1089,23 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"), Ok(Err(conflict)) => { if !trait_ref.references_error() { + // Normalize the trait ref for diagnostics, ignoring any errors if this fails. + let trait_ref = + deeply_normalize_for_diagnostics(infcx, param_env, trait_ref); + let self_ty = trait_ref.self_ty(); - let (trait_desc, self_desc) = with_no_trimmed_paths!({ - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = self_ty - .has_concrete_skeleton() - .then(|| self_ty.to_string()); - (trait_desc, self_desc) - }); + let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); ambiguity_cause = Some(match conflict { Conflict::Upstream => { IntercrateAmbiguityCause::UpstreamCrateUpdate { - trait_desc, - self_desc, + trait_ref, + self_ty, } } Conflict::Downstream => { IntercrateAmbiguityCause::DownstreamCrate { - trait_desc, - self_desc, + trait_ref, + self_ty, } } }); @@ -1093,7 +1142,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { fn search_ambiguity_causes<'tcx>( infcx: &InferCtxt<'tcx>, goal: Goal<'tcx, ty::Predicate<'tcx>>, - causes: &mut FxIndexSet, + causes: &mut FxIndexSet>, ) { infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes }); } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 62ab1e104..aee513207 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -65,7 +65,7 @@ pub fn is_const_evaluatable<'tcx>( // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it // is evaluatable or not. For now we just ICE until this is implemented. - Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug( + Err(NotConstEvaluatable::Error(tcx.sess.span_delayed_bug( span, "evaluating `ConstKind::Expr` is not currently supported", ))) @@ -74,7 +74,7 @@ pub fn is_const_evaluatable<'tcx>( let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); match concrete { Err(ErrorHandled::TooGeneric(_)) => { - Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( + Err(NotConstEvaluatable::Error(infcx.tcx.sess.span_delayed_bug( span, "Missing value for constant, but no error reported?", ))) @@ -138,10 +138,10 @@ pub fn is_const_evaluatable<'tcx>( } else if uv.has_non_region_param() { NotConstEvaluatable::MentionsParam } else { - let guar = infcx - .tcx - .sess - .delay_span_bug(span, "Missing value for constant, but no error reported?"); + let guar = infcx.tcx.sess.span_delayed_bug( + span, + "Missing value for constant, but no error reported?", + ); NotConstEvaluatable::Error(guar) }; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index d9a1a9819..013a50f9f 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -25,7 +25,6 @@ use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::config::TraitSolver; pub trait TraitEngineExt<'tcx> { fn new(infcx: &InferCtxt<'tcx>) -> Box; @@ -33,18 +32,16 @@ pub trait TraitEngineExt<'tcx> { impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> { fn new(infcx: &InferCtxt<'tcx>) -> Box { - match (infcx.tcx.sess.opts.unstable_opts.trait_solver, infcx.next_trait_solver()) { - (TraitSolver::Classic, false) | (TraitSolver::NextCoherence, false) => { - Box::new(FulfillmentContext::new(infcx)) - } - (TraitSolver::Classic | TraitSolver::Next | TraitSolver::NextCoherence, true) => { - Box::new(NextFulfillmentCtxt::new(infcx)) - } - (TraitSolver::Next, false) => bug!( - "incompatible combination of -Ztrait-solver flag ({:?}) and InferCtxt::next_trait_solver ({:?})", - infcx.tcx.sess.opts.unstable_opts.trait_solver, - infcx.next_trait_solver() - ), + if infcx.next_trait_solver() { + Box::new(NextFulfillmentCtxt::new(infcx)) + } else { + let new_solver_globally = + infcx.tcx.sess.opts.unstable_opts.next_solver.map_or(false, |c| c.globally); + assert!( + !new_solver_globally, + "using old solver even though new solver is enabled globally" + ); + Box::new(FulfillmentContext::new(infcx)) } } } @@ -108,7 +105,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, value: T, ) -> T { - let infer_ok = self.infcx.at(&cause, param_env).normalize(value); + let infer_ok = self.infcx.at(cause, param_env).normalize(value); self.register_infer_ok_obligations(infer_ok) } @@ -204,7 +201,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { generic_param_scope: LocalDefId, outlives_env: &OutlivesEnvironment<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let errors = self.infcx.resolve_regions(&outlives_env); + let errors = self.infcx.resolve_regions(outlives_env); if errors.is_empty() { Ok(()) } else { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs index 5bc5a12a8..b246e476b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs @@ -1,5 +1,5 @@ use rustc_hir::def_id::DefId; -use rustc_infer::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation}; use rustc_middle::ty; @@ -53,7 +53,7 @@ pub fn recompute_applicable_impls<'tcx>( let param_env_predicate = infcx.instantiate_binder_with_fresh_vars( DUMMY_SP, - LateBoundRegionConversionTime::HigherRankedType, + BoundRegionConversionTime::HigherRankedType, poly_trait_predicate, ); let param_env_trait_ref = diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index b4835b011..0190d5ab4 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -61,8 +61,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { .params .iter() .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = - *arg.pat + if let hir::Pat { kind: hir::PatKind::Tuple(args, _), span, .. } = *arg.pat { Some(ArgKind::Tuple( Some(span), @@ -92,7 +91,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { .inputs .iter() .map(|arg| match arg.kind { - hir::TyKind::Tup(ref tys) => ArgKind::Tuple( + hir::TyKind::Tup(tys) => ArgKind::Tuple( Some(arg.span), vec![("_".to_owned(), "_".to_owned()); tys.len()], ), @@ -100,7 +99,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { }) .collect::>(), ), - Node::Ctor(ref variant_data) => { + Node::Ctor(variant_data) => { let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id)); (span, None, vec![ArgKind::empty(); variant_data.fields().len()]) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 5fbfedd3e..61e97dde5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -103,7 +103,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// to be the enclosing (async) block/function/closure fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { let hir = self.tcx.hir(); - let node = hir.find(hir_id)?; + let node = self.tcx.opt_hir_node(hir_id)?; match &node { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { self.describe_coroutine(*body_id).or_else(|| { @@ -184,18 +184,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { flags.push((sym::cause, Some("MainFunctionType".to_string()))); } - if let Some(kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id) - && let ty::Tuple(args) = trait_ref.args.type_at(1).kind() - { - let args = args - .iter() - .map(|ty| ty.to_string()) - .collect::>() - .join(", "); - flags.push((sym::Trait, Some(format!("{}({args})", kind.as_str())))); - } else { - flags.push((sym::Trait, Some(trait_ref.print_only_trait_path().to_string()))); - } + flags.push((sym::Trait, Some(trait_ref.print_trait_sugared().to_string()))); // Add all types without trimmed paths or visible paths, ensuring they end up with // their "canonical" def path. @@ -325,7 +314,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } #[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(Symbol); +pub struct OnUnimplementedFormatString { + symbol: Symbol, + span: Span, + is_diagnostic_namespace_variant: bool, +} #[derive(Debug)] pub struct OnUnimplementedDirective { @@ -354,7 +347,7 @@ pub struct OnUnimplementedNote { pub enum AppendConstMessage { #[default] Default, - Custom(Symbol), + Custom(Symbol, Span), } #[derive(LintDiagnostic)] @@ -376,6 +369,43 @@ impl MalformedOnUnimplementedAttrLint { #[help] pub struct MissingOptionsForOnUnimplementedAttr; +#[derive(LintDiagnostic)] +#[diag(trait_selection_ignored_diagnostic_option)] +pub struct IgnoredDiagnosticOption { + pub option_name: &'static str, + #[label] + pub span: Span, + #[label(trait_selection_other_label)] + pub prev_span: Span, +} + +impl IgnoredDiagnosticOption { + fn maybe_emit_warning<'tcx>( + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + new: Option, + old: Option, + option_name: &'static str, + ) { + if let (Some(new_item), Some(old_item)) = (new, old) { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), + new_item, + IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name }, + ); + } + } +} + +#[derive(LintDiagnostic)] +#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)] +#[help] +pub struct UnknownFormatParameterForOnUnimplementedAttr { + argument_name: Symbol, + trait_name: Symbol, +} + impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -388,8 +418,15 @@ impl<'tcx> OnUnimplementedDirective { let mut errored = None; let mut item_iter = items.iter(); - let parse_value = |value_str| { - OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some) + let parse_value = |value_str, value_span| { + OnUnimplementedFormatString::try_parse( + tcx, + item_def_id, + value_str, + value_span, + is_diagnostic_namespace_variant, + ) + .map(Some) }; let condition = if is_root { @@ -402,7 +439,7 @@ impl<'tcx> OnUnimplementedDirective { .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value - && let Err(guar) = parse_value(value) + && let Err(guar) = parse_value(value, cfg.span) { errored = Some(guar); } @@ -421,17 +458,17 @@ impl<'tcx> OnUnimplementedDirective { for item in item_iter { if item.has_name(sym::message) && message.is_none() { if let Some(message_) = item.value_str() { - message = parse_value(message_)?; + message = parse_value(message_, item.span())?; continue; } } else if item.has_name(sym::label) && label.is_none() { if let Some(label_) = item.value_str() { - label = parse_value(label_)?; + label = parse_value(label_, item.span())?; continue; } } else if item.has_name(sym::note) { if let Some(note_) = item.value_str() { - if let Some(note) = parse_value(note_)? { + if let Some(note) = parse_value(note_, item.span())? { notes.push(note); continue; } @@ -441,7 +478,7 @@ impl<'tcx> OnUnimplementedDirective { && !is_diagnostic_namespace_variant { if let Some(parent_label_) = item.value_str() { - parent_label = parse_value(parent_label_)?; + parent_label = parse_value(parent_label_, item.span())?; continue; } } else if item.has_name(sym::on) @@ -456,7 +493,7 @@ impl<'tcx> OnUnimplementedDirective { match Self::parse( tcx, item_def_id, - &items, + items, item.span(), false, is_diagnostic_namespace_variant, @@ -474,7 +511,7 @@ impl<'tcx> OnUnimplementedDirective { && !is_diagnostic_namespace_variant { if let Some(msg) = item.value_str() { - append_const_msg = Some(AppendConstMessage::Custom(msg)); + append_const_msg = Some(AppendConstMessage::Custom(msg, item.span())); continue; } else if item.is_word() { append_const_msg = Some(AppendConstMessage::Default); @@ -485,7 +522,7 @@ impl<'tcx> OnUnimplementedDirective { if is_diagnostic_namespace_variant { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), vec![item.span()], MalformedOnUnimplementedAttrLint::new(item.span()), ); @@ -523,6 +560,54 @@ impl<'tcx> OnUnimplementedDirective { subcommands.extend(directive.subcommands); let mut notes = aggr.notes; notes.extend(directive.notes); + IgnoredDiagnosticOption::maybe_emit_warning( + tcx, + item_def_id, + directive.message.as_ref().map(|f| f.span), + aggr.message.as_ref().map(|f| f.span), + "message", + ); + IgnoredDiagnosticOption::maybe_emit_warning( + tcx, + item_def_id, + directive.label.as_ref().map(|f| f.span), + aggr.label.as_ref().map(|f| f.span), + "label", + ); + IgnoredDiagnosticOption::maybe_emit_warning( + tcx, + item_def_id, + directive.condition.as_ref().map(|i| i.span), + aggr.condition.as_ref().map(|i| i.span), + "condition", + ); + IgnoredDiagnosticOption::maybe_emit_warning( + tcx, + item_def_id, + directive.parent_label.as_ref().map(|f| f.span), + aggr.parent_label.as_ref().map(|f| f.span), + "parent_label", + ); + IgnoredDiagnosticOption::maybe_emit_warning( + tcx, + item_def_id, + directive.append_const_msg.as_ref().and_then(|c| { + if let AppendConstMessage::Custom(_, s) = c { + Some(*s) + } else { + None + } + }), + aggr.append_const_msg.as_ref().and_then(|c| { + if let AppendConstMessage::Custom(_, s) = c { + Some(*s) + } else { + None + } + }), + "append_const_msg", + ); + Ok(Some(Self { condition: aggr.condition.or(directive.condition), subcommands, @@ -560,6 +645,7 @@ impl<'tcx> OnUnimplementedDirective { item_def_id, value, attr.span, + is_diagnostic_namespace_variant, )?), notes: Vec::new(), parent_label: None, @@ -576,7 +662,7 @@ impl<'tcx> OnUnimplementedDirective { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), report_span, MalformedOnUnimplementedAttrLint::new(report_span), ); @@ -587,14 +673,14 @@ impl<'tcx> OnUnimplementedDirective { AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, MalformedOnUnimplementedAttrLint::new(attr.span), ); } _ => tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, MissingOptionsForOnUnimplementedAttr, ), @@ -602,8 +688,9 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } else { - let reported = - tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); + let reported = tcx + .sess + .span_delayed_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str"); return Err(reported); }; debug!("of_item({:?}) = {:?}", item_def_id, result); @@ -636,7 +723,18 @@ impl<'tcx> OnUnimplementedDirective { let value = cfg.value.map(|v| { // `with_no_visible_paths` is also used when generating the options, // so we need to match it here. - ty::print::with_no_visible_paths!(OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)) + ty::print::with_no_visible_paths!( + OnUnimplementedFormatString { + symbol: v, + span: cfg.span, + is_diagnostic_namespace_variant: false + } + .format( + tcx, + trait_ref, + &options_map + ) + ) }); options.contains(&(cfg.name, value)) @@ -679,19 +777,19 @@ impl<'tcx> OnUnimplementedFormatString { tcx: TyCtxt<'tcx>, item_def_id: DefId, from: Symbol, - err_sp: Span, + value_span: Span, + is_diagnostic_namespace_variant: bool, ) -> Result { - let result = OnUnimplementedFormatString(from); - result.verify(tcx, item_def_id, err_sp)?; + let result = OnUnimplementedFormatString { + symbol: from, + span: value_span, + is_diagnostic_namespace_variant, + }; + result.verify(tcx, item_def_id)?; Ok(result) } - fn verify( - &self, - tcx: TyCtxt<'tcx>, - item_def_id: DefId, - span: Span, - ) -> Result<(), ErrorGuaranteed> { + fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> { let trait_def_id = if tcx.is_trait(item_def_id) { item_def_id } else { @@ -700,7 +798,7 @@ impl<'tcx> OnUnimplementedFormatString { }; let trait_name = tcx.item_name(trait_def_id); let generics = tcx.generics_of(item_def_id); - let s = self.0.as_str(); + let s = self.symbol.as_str(); let parser = Parser::new(s, None, None, false, ParseMode::Format); let mut result = Ok(()); for token in parser { @@ -710,24 +808,40 @@ impl<'tcx> OnUnimplementedFormatString { Position::ArgumentNamed(s) => { match Symbol::intern(s) { // `{ThisTraitsName}` is allowed - s if s == trait_name => (), - s if ALLOWED_FORMAT_SYMBOLS.contains(&s) => (), + s if s == trait_name && !self.is_diagnostic_namespace_variant => (), + s if ALLOWED_FORMAT_SYMBOLS.contains(&s) + && !self.is_diagnostic_namespace_variant => + { + () + } // So is `{A}` if A is a type parameter s if generics.params.iter().any(|param| param.name == s) => (), s => { - result = Err(struct_span_err!( - tcx.sess, - span, - E0230, - "there is no parameter `{}` on {}", - s, - if trait_def_id == item_def_id { - format!("trait `{trait_name}`") - } else { - "impl".to_string() - } - ) - .emit()); + if self.is_diagnostic_namespace_variant { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), + self.span, + UnknownFormatParameterForOnUnimplementedAttr { + argument_name: s, + trait_name, + }, + ); + } else { + result = Err(struct_span_err!( + tcx.sess, + self.span, + E0230, + "there is no parameter `{}` on {}", + s, + if trait_def_id == item_def_id { + format!("trait `{trait_name}`") + } else { + "impl".to_string() + } + ) + .emit()); + } } } } @@ -735,7 +849,7 @@ impl<'tcx> OnUnimplementedFormatString { Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { let reported = struct_span_err!( tcx.sess, - span, + self.span, E0231, "only named substitution parameters are allowed" ) @@ -774,37 +888,42 @@ impl<'tcx> OnUnimplementedFormatString { .collect::>(); let empty_string = String::new(); - let s = self.0.as_str(); + let s = self.symbol.as_str(); let parser = Parser::new(s, None, None, false, ParseMode::Format); let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string); parser .map(|p| match p { - Piece::String(s) => s, + Piece::String(s) => s.to_owned(), Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => { - let s = Symbol::intern(s); + Position::ArgumentNamed(arg) => { + let s = Symbol::intern(arg); match generic_map.get(&s) { - Some(val) => val, - None if s == name => &trait_str, + Some(val) => val.to_string(), + None if self.is_diagnostic_namespace_variant => { + format!("{{{arg}}}") + } + None if s == name => trait_str.clone(), None => { if let Some(val) = options.get(&s) { - val + val.clone() } else if s == sym::from_desugaring { // don't break messages using these two arguments incorrectly - &empty_string - } else if s == sym::ItemContext { - &item_context + String::new() + } else if s == sym::ItemContext + && !self.is_diagnostic_namespace_variant + { + item_context.clone() } else if s == sym::integral { - "{integral}" + String::from("{integral}") } else if s == sym::integer_ { - "{integer}" + String::from("{integer}") } else if s == sym::float { - "{float}" + String::from("{float}") } else { bug!( "broken on_unimplemented {:?} for {:?}: \ no argument matching {:?}", - self.0, + self.symbol, trait_ref, s ) @@ -812,7 +931,7 @@ impl<'tcx> OnUnimplementedFormatString { } } } - _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0), + _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol), }, }) .collect() diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6b09bc898..a1b896d22 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -17,7 +17,7 @@ use rustc_errors::{ ErrorGuaranteed, MultiSpan, Style, SuggestionStyle, }; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; @@ -26,7 +26,7 @@ use rustc_hir::{CoroutineKind, CoroutineSource, Node}; use rustc_hir::{Expr, HirId}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime}; +use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError::{self, Sorts}; @@ -36,7 +36,7 @@ use rustc_middle::ty::{ TypeSuperFoldable, TypeVisitableExt, TypeckResults, }; use rustc_span::def_id::LocalDefId; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP}; use rustc_target::spec::abi; use std::borrow::Cow; @@ -99,7 +99,7 @@ impl<'tcx, 'a> CoroutineData<'tcx, 'a> { .awaits .into_iter() .map(|id| hir.expect_expr(id)) - .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(&await_expr)))) + .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr)))) .map(|expr| expr.span) } } @@ -222,6 +222,15 @@ pub trait TypeErrCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>; + fn note_conflicting_fn_args( + &self, + err: &mut Diagnostic, + cause: &ObligationCauseCode<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ); + fn note_conflicting_closure_bounds( &self, cause: &ObligationCauseCode<'tcx>, @@ -501,7 +510,7 @@ pub fn suggest_restriction<'tcx>( impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_restricting_param_bound( &self, - mut err: &mut Diagnostic, + err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, associated_ty: Option<(&'static str, Ty<'tcx>)>, mut body_id: LocalDefId, @@ -521,7 +530,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. - while let Some(node) = self.tcx.hir().find_by_def_id(body_id) { + while let Some(node) = self.tcx.opt_hir_node_by_def_id(body_id) { match node { hir::Node::Item(hir::Item { ident, @@ -533,7 +542,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggest_restriction( self.tcx, body_id, - &generics, + generics, "`Self`", err, None, @@ -552,7 +561,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { assert!(param_ty); // Restricting `Self` for a single method. suggest_restriction( - self.tcx, body_id, &generics, "`Self`", err, None, projection, trait_pred, + self.tcx, body_id, generics, "`Self`", err, None, projection, trait_pred, None, ); return; @@ -575,7 +584,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggest_restriction( self.tcx, body_id, - &generics, + generics, "the associated type", err, Some(fn_sig), @@ -595,7 +604,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggest_restriction( self.tcx, body_id, - &generics, + generics, "the associated type", err, None, @@ -662,7 +671,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if suggest_constraining_type_param( self.tcx, generics, - &mut err, + err, ¶m_name, &constraint, Some(trait_pred.def_id()), @@ -690,7 +699,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if suggest_arbitrary_trait_bound( self.tcx, generics, - &mut err, + err, trait_pred, associated_ty, ) { @@ -723,7 +732,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let Some(typeck_results) = &self.typeck_results else { return false; }; - let hir::Node::Expr(expr) = self.tcx.hir().get(*arg_hir_id) else { + let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id) else { return false; }; let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) else { @@ -739,9 +748,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { real_trait_pred = parent_trait_pred; } - // We `erase_late_bound_regions` here because `make_subregion` does not handle - // `ReLateBound`, and we don't particularly care about the regions. - let real_ty = self.tcx.erase_late_bound_regions(real_trait_pred.self_ty()); + // 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()); if !self.can_eq(obligation.param_env, real_ty, arg_ty) { continue; } @@ -776,7 +785,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { kind: hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, expr), .. - })) = self.tcx.hir().find(*arg_hir_id) + })) = self.tcx.opt_hir_node(*arg_hir_id) { let derefs = "*".repeat(steps); err.span_suggestion_verbose( @@ -812,7 +821,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if self.predicate_may_hold(&obligation) && self.predicate_must_hold_modulo_regions(&sized_obligation) { - let call_node = self.tcx.hir().get(*call_hir_id); + let call_node = self.tcx.hir_node(*call_hir_id); let msg = "consider dereferencing here"; let is_receiver = matches!( call_node, @@ -871,7 +880,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let hir = self.tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?); match hir.find_parent(hir_id) { Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { get_name(err, &local.pat.kind) @@ -908,7 +917,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let self_ty = self.instantiate_binder_with_fresh_vars( DUMMY_SP, - LateBoundRegionConversionTime::FnCall, + BoundRegionConversionTime::FnCall, trait_pred.self_ty(), ); @@ -1034,10 +1043,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind else { return; }; - let hir::def::Res::Local(hir_id) = path.res else { + let Res::Local(hir_id) = path.res else { return; }; - let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(hir_id) else { + let Some(hir::Node::Pat(pat)) = self.tcx.opt_hir_node(hir_id) else { return; }; let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) = @@ -1097,7 +1106,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { else { return false; }; - let arg_node = self.tcx.hir().get(*arg_hir_id); + let arg_node = self.tcx.hir_node(*arg_hir_id); let Node::Expr(Expr { kind: hir::ExprKind::Path(_), .. }) = arg_node else { return false }; let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); @@ -1237,7 +1246,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let output = self.instantiate_binder_with_fresh_vars( DUMMY_SP, - LateBoundRegionConversionTime::FnCall, + BoundRegionConversionTime::FnCall, output, ); let inputs = inputs @@ -1246,7 +1255,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|ty| { self.instantiate_binder_with_fresh_vars( DUMMY_SP, - LateBoundRegionConversionTime::FnCall, + BoundRegionConversionTime::FnCall, inputs.rebind(*ty), ) }) @@ -1273,7 +1282,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = obligation.cause.code() { - &parent_code + parent_code } else if let ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() { @@ -1378,14 +1387,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.message = vec![(rustc_errors::DiagnosticMessage::from(msg), Style::NoStyle)]; } + let mut file = None; err.span_label( span, format!( "the trait `{}` is not implemented for `{}`", old_pred.print_modifiers_and_trait_path(), - old_pred.self_ty().skip_binder(), + self.tcx.short_ty_string(old_pred.self_ty().skip_binder(), &mut file), ), ); + if let Some(file) = file { + err.note(format!( + "the full type name has been written to '{}'", + file.display() + )); + } if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { err.span_suggestions( @@ -1618,8 +1634,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::def::Res::Local(hir_id) = path.res - && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) + && let Res::Local(hir_id) = path.res + && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(hir_id) && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id) && let None = local.ty && let Some(binding_expr) = local.init @@ -1634,9 +1650,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { let hir = self.tcx.hir(); - if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = - obligation.cause.code().peel_derives() - && let hir::Node::Expr(expr) = hir.get(*hir_id) + if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() + && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) { // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` // and if not maybe suggest doing something else? If we kept the expression around we @@ -1786,7 +1801,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let hir = self.tcx.hir(); - let node = hir.find_by_def_id(obligation.cause.body_id); + let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. })) = node && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind && sig.decl.output.span().overlaps(span) @@ -1821,9 +1836,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { - let hir = self.tcx.hir(); let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })) = - hir.find_by_def_id(obligation.cause.body_id) + self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id) else { return None; }; @@ -1867,7 +1881,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id)); let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); + visitor.visit_body(body); let mut sugg = vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())]; @@ -1915,14 +1929,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let hir = self.tcx.hir(); - let node = hir.find_by_def_id(obligation.cause.body_id); + let node = self.tcx.opt_hir_node_by_def_id(obligation.cause.body_id); if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = node { let body = hir.body(*body_id); // Point at all the `return`s in the function as they have failed trait bounds. let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); + visitor.visit_body(body); let typeck_results = self.typeck_results.as_ref().unwrap(); for expr in &visitor.returns { if let Some(returned_ty) = typeck_results.node_type_opt(expr.hir_id) { @@ -2006,6 +2020,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let signature_kind = format!("{argument_kind} signature"); err.note_expected_found(&signature_kind, expected_str, &signature_kind, found_str); + self.note_conflicting_fn_args(&mut err, cause, expected, found, param_env); self.note_conflicting_closure_bounds(cause, &mut err); if let Some(found_node) = found_node { @@ -2015,6 +2030,158 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err } + fn note_conflicting_fn_args( + &self, + err: &mut Diagnostic, + cause: &ObligationCauseCode<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) { + let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = cause else { + return; + }; + let ty::FnPtr(expected) = expected.kind() else { + return; + }; + let ty::FnPtr(found) = found.kind() else { + return; + }; + let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id) else { + return; + }; + let hir::ExprKind::Path(path) = arg.kind else { + return; + }; + let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(*expected).inputs(); + let found_inputs = self.tcx.instantiate_bound_regions_with_erased(*found).inputs(); + let both_tys = expected_inputs.iter().copied().zip(found_inputs.iter().copied()); + + let arg_expr = |infcx: &InferCtxt<'tcx>, name, expected: Ty<'tcx>, found: Ty<'tcx>| { + let (expected_ty, expected_refs) = get_deref_type_and_refs(expected); + let (found_ty, found_refs) = get_deref_type_and_refs(found); + + if infcx.can_eq(param_env, found_ty, expected_ty) { + if found_refs.len() == expected_refs.len() + && found_refs.iter().eq(expected_refs.iter()) + { + name + } else if found_refs.len() > expected_refs.len() { + let refs = &found_refs[..found_refs.len() - expected_refs.len()]; + if found_refs[..expected_refs.len()].iter().eq(expected_refs.iter()) { + format!( + "{}{name}", + refs.iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::>() + .join(""), + ) + } else { + // The refs have different mutability. + format!( + "{}*{name}", + refs.iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .collect::>() + .join(""), + ) + } + } else if expected_refs.len() > found_refs.len() { + format!( + "{}{name}", + (0..(expected_refs.len() - found_refs.len())) + .map(|_| "*") + .collect::>() + .join(""), + ) + } else { + format!( + "{}{name}", + found_refs + .iter() + .map(|mutbl| format!("&{}", mutbl.prefix_str())) + .chain(found_refs.iter().map(|_| "*".to_string())) + .collect::>() + .join(""), + ) + } + } else { + format!("/* {found} */") + } + }; + let args_have_same_underlying_type = both_tys.clone().all(|(expected, found)| { + let (expected_ty, _) = get_deref_type_and_refs(expected); + let (found_ty, _) = get_deref_type_and_refs(found); + self.can_eq(param_env, found_ty, expected_ty) + }); + let (closure_names, call_names): (Vec<_>, Vec<_>) = if args_have_same_underlying_type + && !expected_inputs.is_empty() + && expected_inputs.len() == found_inputs.len() + && let Some(typeck) = &self.typeck_results + && let Res::Def(res_kind, fn_def_id) = typeck.qpath_res(&path, *arg_hir_id) + && res_kind.is_fn_like() + { + let closure: Vec<_> = self + .tcx + .fn_arg_names(fn_def_id) + .iter() + .enumerate() + .map(|(i, ident)| { + if ident.name.is_empty() || ident.name == kw::SelfLower { + format!("arg{i}") + } else { + format!("{ident}") + } + }) + .collect(); + let args = closure + .iter() + .zip(both_tys) + .map(|(name, (expected, found))| { + arg_expr(self.infcx, name.to_owned(), expected, found) + }) + .collect(); + (closure, args) + } else { + let closure_args = expected_inputs + .iter() + .enumerate() + .map(|(i, _)| format!("arg{i}")) + .collect::>(); + let call_args = both_tys + .enumerate() + .map(|(i, (expected, found))| { + arg_expr(self.infcx, format!("arg{i}"), expected, found) + }) + .collect::>(); + (closure_args, call_args) + }; + let closure_names: Vec<_> = closure_names + .into_iter() + .zip(expected_inputs.iter()) + .map(|(name, ty)| { + format!( + "{name}{}", + if ty.has_infer_types() { + String::new() + } else if ty.references_error() { + ": /* type */".to_string() + } else { + format!(": {ty}") + } + ) + }) + .collect(); + err.multipart_suggestion( + "consider wrapping the function in a closure", + vec![ + (arg.span.shrink_to_lo(), format!("|{}| ", closure_names.join(", "))), + (arg.span.shrink_to_hi(), format!("({})", call_names.join(", "))), + ], + Applicability::MaybeIncorrect, + ); + } + // Add a note if there are two `Fn`-family bounds that have conflicting argument // requirements, which will always cause a closure to have a type error. fn note_conflicting_closure_bounds( @@ -2287,8 +2454,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // represent regions that are part of the suspended // coroutine frame. Bound regions are preserved by // `erase_regions` and so we must also call - // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(ty); + // `instantiate_bound_regions_with_erased`. + let ty_erased = self.tcx.instantiate_bound_regions_with_erased(ty); let ty_erased = self.tcx.erase_regions(ty_erased); let eq = ty_erased == target_ty_erased; debug!(?ty_erased, ?target_ty_erased, ?eq); @@ -2300,7 +2467,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // cycles. If we can't use resolved types because the coroutine comes from another crate, // we still provide a targeted error but without all the relevant spans. let coroutine_data = match &self.typeck_results { - Some(t) if t.hir_owner.to_def_id() == coroutine_did_root => CoroutineData(&t), + Some(t) if t.hir_owner.to_def_id() == coroutine_did_root => CoroutineData(t), _ if coroutine_did.is_local() => { CoroutineData(self.tcx.typeck(coroutine_did.expect_local())) } @@ -2344,7 +2511,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if interior_or_upvar_span.is_none() { interior_or_upvar_span = - coroutine_data.try_get_upvar_span(&self, coroutine_did, ty_matches); + coroutine_data.try_get_upvar_span(self, coroutine_did, ty_matches); } if interior_or_upvar_span.is_none() && !coroutine_did.is_local() { @@ -2415,7 +2582,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .tcx .parent(coroutine_did) .as_local() - .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) + .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) .map(|name| { format!("future returned by `{name}` is not {trait_name}") @@ -2426,11 +2593,28 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { CoroutineKind::Async(CoroutineSource::Closure) => { format!("future created by async closure is not {trait_name}") } + CoroutineKind::AsyncGen(CoroutineSource::Fn) => self + .tcx + .parent(coroutine_did) + .as_local() + .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) + .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .map(|name| { + format!("async iterator returned by `{name}` is not {trait_name}") + })?, + CoroutineKind::AsyncGen(CoroutineSource::Block) => { + format!("async iterator created by async gen block is not {trait_name}") + } + CoroutineKind::AsyncGen(CoroutineSource::Closure) => { + format!( + "async iterator created by async gen closure is not {trait_name}" + ) + } CoroutineKind::Gen(CoroutineSource::Fn) => self .tcx .parent(coroutine_did) .as_local() - .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) + .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) .map(|name| { format!("iterator returned by `{name}` is not {trait_name}") @@ -2517,7 +2701,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { CoroutineInteriorOrUpvar::Upvar(upvar_span) => { // `Some((ref_ty, is_mut))` if `target_ty` is `&T` or `&mut T` and fails to impl `Send` let non_send = match target_ty.kind() { - ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(&obligation) { + ty::Ref(_, ref_ty, mutability) => match self.evaluate_obligation(obligation) { Ok(eval) if !eval.may_apply() => Some((ref_ty, mutability.is_mut())), _ => None, }, @@ -2593,11 +2777,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::UnifyReceiver(..) - | ObligationCauseCode::OpaqueType | ObligationCauseCode::MiscObligation | ObligationCauseCode::WellFormed(..) | ObligationCauseCode::MatchImpl(..) - | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) @@ -2608,7 +2790,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::DropImpl - | ObligationCauseCode::ConstParam(_) => {} + | ObligationCauseCode::ConstParam(_) + | ObligationCauseCode::ReferenceOutlivesReferent(..) + | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::RustCall => { if let Some(pred) = predicate.to_opt_poly_trait_pred() && Some(pred.def_id()) == self.tcx.lang_items().sized_trait() @@ -2622,19 +2806,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } - ObligationCauseCode::ProjectionWf(data) => { - err.note(format!("required so that the projection `{data}` is well-formed")); - } - ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(format!( - "required so that reference `{ref_ty}` does not outlive its referent" - )); - } - ObligationCauseCode::ObjectTypeBound(object_ty, region) => { - err.note(format!( - "required so that the lifetime bound of `{region}` for `{object_ty}` is satisfied", - )); - } ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) => { // We hold the `DefId` of the item introducing the obligation, but displaying it @@ -2723,11 +2894,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .collect::>(); if !impls.is_empty() { let len = impls.len(); - let mut types = impls.iter() - .map(|t| with_no_trimmed_paths!(format!( - " {}", - tcx.type_of(*t).instantiate_identity(), - ))) + let mut types = impls + .iter() + .map(|t| { + with_no_trimmed_paths!(format!( + " {}", + tcx.type_of(*t).instantiate_identity(), + )) + }) .collect::>(); let post = if types.len() > 9 { types.truncate(8); @@ -2749,50 +2923,62 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::Coercion { source, target } => { - let (source, source_file) = - self.tcx.short_ty_string(self.resolve_vars_if_possible(source)); - let (target, target_file) = - self.tcx.short_ty_string(self.resolve_vars_if_possible(target)); + let mut file = None; + let source = + self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file); + let target = + self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); - if let Some(file) = source_file { - err.note(format!( - "the full name for the source type has been written to '{}'", - file.display(), - )); - } - if let Some(file) = target_file { + if let Some(file) = file { err.note(format!( - "the full name for the target type has been written to '{}'", + "the full name for the type has been written to '{}'", file.display(), )); } } - ObligationCauseCode::RepeatElementCopy { is_constable, elt_type, elt_span, elt_stmt_span } => { + ObligationCauseCode::RepeatElementCopy { + is_constable, + elt_type, + elt_span, + elt_stmt_span, + } => { err.note( "the `Copy` trait is required because this value will be copied for each element of the array", ); let value_kind = match is_constable { IsConstable::Fn => Some("the result of the function call"), IsConstable::Ctor => Some("the result of the constructor"), - _ => None + _ => None, }; let sm = tcx.sess.source_map(); - if let Some(value_kind) = value_kind && - let Ok(snip) = sm.span_to_snippet(elt_span) + if let Some(value_kind) = value_kind + && let Ok(snip) = sm.span_to_snippet(elt_span) { let help_msg = format!( "consider creating a new `const` item and initializing it with {value_kind} \ - to be used in the repeat position"); + to be used in the repeat position" + ); let indentation = sm.indentation_before(elt_stmt_span).unwrap_or_default(); - err.multipart_suggestion(help_msg, vec![ - (elt_stmt_span.shrink_to_lo(), format!("const ARRAY_REPEAT_VALUE: {elt_type} = {snip};\n{indentation}")), - (elt_span, "ARRAY_REPEAT_VALUE".to_string()) - ], Applicability::MachineApplicable); + err.multipart_suggestion( + help_msg, + vec![ + ( + elt_stmt_span.shrink_to_lo(), + format!( + "const ARRAY_REPEAT_VALUE: {elt_type} = {snip};\n{indentation}" + ), + ), + (elt_span, "ARRAY_REPEAT_VALUE".to_string()), + ], + Applicability::MachineApplicable, + ); } - if self.tcx.sess.is_nightly_build() && matches!(is_constable, IsConstable::Fn|IsConstable::Ctor) { + if self.tcx.sess.is_nightly_build() + && matches!(is_constable, IsConstable::Fn | IsConstable::Ctor) + { err.help( "create an inline `const` block, see RFC #2920 \ for more information", @@ -2801,7 +2987,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::VariableType(hir_id) => { let parent_node = self.tcx.hir().parent_id(hir_id); - match self.tcx.hir().find(parent_node) { + match self.tcx.opt_hir_node(parent_node) { Some(Node::Local(hir::Local { ty: Some(ty), .. })) => { err.span_suggestion_verbose( ty.span.shrink_to_lo(), @@ -2945,7 +3131,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "all values captured by value by a closure must have a statically known size", ); let hir::ExprKind::Closure(closure) = - self.tcx.hir().get_by_def_id(closure_def_id).expect_expr().kind + self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind else { bug!("expected closure in SizedClosureCapture obligation"); }; @@ -2957,16 +3143,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => { let what = match self.tcx.coroutine_kind(coroutine_def_id) { - None | Some(hir::CoroutineKind::Coroutine) | Some(hir::CoroutineKind::Gen(_)) => "yield", + None + | Some(hir::CoroutineKind::Coroutine) + | Some(hir::CoroutineKind::Gen(_)) => "yield", Some(hir::CoroutineKind::Async(..)) => "await", + Some(hir::CoroutineKind::AsyncGen(_)) => "yield`/`await", }; err.note(format!( "all values live across `{what}` must have a statically known size" )); } - ObligationCauseCode::ConstPatternStructural => { - err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); - } ObligationCauseCode::SharedStatic => { err.note("shared static variables must have a type that implements `Sync`"); } @@ -3000,9 +3186,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Don't print the tuple of capture types 'print: { if !is_upvar_tys_infer_tuple { - let msg = with_forced_trimmed_paths!(format!( - "required because it appears within the type `{ty}`", - )); + let mut file = None; + let ty_str = self.tcx.short_ty_string(ty, &mut file); + let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { Some(ident) => err.span_note(ident.span, msg), @@ -3099,8 +3285,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); - let (self_ty, file) = - self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty()); + let mut file = None; + let self_ty = + self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); let msg = format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3197,8 +3384,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { count, pluralize!(count) )); - let (self_ty, file) = - self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty()); + let mut file = None; + let self_ty = self + .tcx + .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3283,7 +3472,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err, predicate, param_env, - &parent_code, + parent_code, obligated_types, seen_requirements, ) @@ -3352,7 +3541,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let impls_future = self.type_implements_trait( future_trait, - [self.tcx.erase_late_bound_regions(self_ty)], + [self.tcx.instantiate_bound_regions_with_erased(self_ty)], obligation.param_env, ); if !impls_future.must_apply_modulo_regions() { @@ -3443,17 +3632,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { is_derivable_trait && // Ensure all fields impl the trait. adt.all_fields().all(|field| { - let field_ty = field.ty(self.tcx, args); + let field_ty = ty::GenericArg::from(field.ty(self.tcx, args)); let trait_args = match diagnostic_name { sym::PartialEq | sym::PartialOrd => { Some(field_ty) } _ => None, }; + // Also add host param, if present + let host = self.tcx.generics_of(trait_pred.def_id()).host_effect_index.map(|idx| trait_pred.skip_binder().trait_ref.args[idx]); let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { trait_ref: ty::TraitRef::new(self.tcx, trait_pred.def_id(), - [field_ty].into_iter().chain(trait_args), + [field_ty].into_iter().chain(trait_args).chain(host), ), ..*tr }); @@ -3474,6 +3665,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred.skip_binder().self_ty(), diagnostic_name, ), + // FIXME(effects, const_trait_impl) derive_const as suggestion? format!("#[derive({diagnostic_name})]\n"), Applicability::MaybeIncorrect, ); @@ -3513,13 +3705,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { call_hir_id: HirId, ) { let tcx = self.tcx; - let hir = tcx.hir(); - if let Some(Node::Expr(expr)) = hir.find(arg_hir_id) + if let Some(Node::Expr(expr)) = tcx.opt_hir_node(arg_hir_id) && let Some(typeck_results) = &self.typeck_results { if let hir::Expr { kind: hir::ExprKind::Block(block, _), .. } = expr { let inner_expr = expr.peel_blocks(); - let ty = typeck_results.expr_ty_adjusted_opt(inner_expr) + let ty = typeck_results + .expr_ty_adjusted_opt(inner_expr) .unwrap_or(Ty::new_misc_error(tcx)); let span = inner_expr.span; if Some(span) != err.span.primary_span() { @@ -3538,16 +3730,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { tcx.lang_items().fn_once_trait(), tcx.lang_items().fn_mut_trait(), tcx.lang_items().fn_trait(), - ].contains(&Some(pred.def_id())) + ] + .contains(&Some(pred.def_id())) { if let [stmt, ..] = block.stmts && let hir::StmtKind::Semi(value) = stmt.kind && let hir::ExprKind::Closure(hir::Closure { - body, - fn_decl_span, - .. + body, fn_decl_span, .. }) = value.kind - && let body = hir.body(*body) + && let body = tcx.hir().body(*body) && !matches!(body.value.kind, hir::ExprKind::Block(..)) { // Check if the failed predicate was an expectation of a closure type @@ -3568,9 +3759,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "you might have meant to create the closure instead of a block", format!( "|{}| ", - (0..pred.trait_ref.args.len() - 1).map(|_| "_") + (0..pred.trait_ref.args.len() - 1) + .map(|_| "_") .collect::>() - .join(", ")), + .join(", ") + ), Applicability::MaybeIncorrect, ); } @@ -3595,7 +3788,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let where_pred = self.instantiate_binder_with_placeholders(where_pred); let failed_pred = self.instantiate_binder_with_fresh_vars( expr.span, - LateBoundRegionConversionTime::FnCall, + BoundRegionConversionTime::FnCall, failed_pred, ); @@ -3627,21 +3820,21 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path - && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let hir::Path { res: Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id) && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id) - && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) + && let Some(hir::Node::Local(local)) = self.tcx.opt_hir_node(parent_hir_id) && let Some(binding_expr) = local.init { // If the expression we're calling on is a binding, we want to point at the // `let` when talking about the type. Otherwise we'll point at every part // of the method chain with the type. - self.point_at_chain(binding_expr, &typeck_results, type_diffs, param_env, err); + self.point_at_chain(binding_expr, typeck_results, type_diffs, param_env, err); } else { - self.point_at_chain(expr, &typeck_results, type_diffs, param_env, err); + self.point_at_chain(expr, typeck_results, type_diffs, param_env, err); } } - let call_node = hir.find(call_hir_id); + let call_node = tcx.opt_hir_node(call_hir_id); if let Some(Node::Expr(hir::Expr { kind: hir::ExprKind::MethodCall(path, rcvr, ..), .. })) = call_node @@ -3651,7 +3844,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - if let Some(Node::Expr(expr)) = hir.find(call_hir_id) { + if let Some(Node::Expr(expr)) = tcx.opt_hir_node(call_hir_id) { if let hir::ExprKind::Call(hir::Expr { span, .. }, _) | hir::ExprKind::MethodCall( hir::PathSegment { ident: Ident { span, .. }, .. }, @@ -3812,7 +4005,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { continue; }; let hir = tcx.hir(); - let node = hir.get_by_def_id(hir.get_parent_item(expr.hir_id).def_id); + let node = tcx.hir_node_by_def_id(hir.get_parent_item(expr.hir_id).def_id); let pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef::from_lang_item( @@ -3832,7 +4025,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { suggest_restriction( tcx, hir.body_owner_def_id(body_id), - &generics, + generics, &format!("type parameter `{ty}`"), err, node.fn_sig(), @@ -3887,8 +4080,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind - && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path - && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(*hir_id) + && let hir::Path { res: Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id) && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) { // We've reached the root of the method call chain... @@ -4267,7 +4460,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } return; }; - let Some(hir::Node::TraitItem(item)) = self.tcx.hir().find_by_def_id(fn_def_id) else { + let Some(hir::Node::TraitItem(item)) = self.tcx.opt_hir_node_by_def_id(fn_def_id) else { return; }; @@ -4342,17 +4535,6 @@ fn hint_missing_borrow<'tcx>( let args = fn_decl.inputs.iter(); - fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec) { - let mut refs = vec![]; - - while let ty::Ref(_, new_ty, mutbl) = ty.kind() { - ty = *new_ty; - refs.push(*mutbl); - } - - (ty, refs) - } - let mut to_borrow = Vec::new(); let mut remove_borrow = Vec::new(); @@ -4483,7 +4665,7 @@ pub trait NextTypeParamName { impl NextTypeParamName for &[hir::GenericParam<'_>] { fn next_type_param_name(&self, name: Option<&str>) -> String { // This is the list of possible parameter names that we might suggest. - let name = name.and_then(|n| n.chars().next()).map(|c| c.to_string().to_uppercase()); + let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string()); let name = name.as_deref(); let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"]; let used_names = self @@ -4512,7 +4694,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { fn visit_ty(&mut self, t: &'hir hir::Ty<'hir>) { if let hir::TyKind::Path(hir::QPath::Resolved( None, - hir::Path { res: hir::def::Res::Def(_, segment_did), .. }, + hir::Path { res: Res::Def(_, segment_did), .. }, )) = t.kind { if self.param_did == *segment_did { @@ -4530,6 +4712,7 @@ impl<'a, 'hir> hir::intravisit::Visitor<'hir> for ReplaceImplTraitVisitor<'a> { } pub(super) fn get_explanation_based_on_obligation<'tcx>( + tcx: TyCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, trait_predicate: &ty::PolyTraitPredicate<'tcx>, @@ -4550,13 +4733,13 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( pre_message, trait_predicate.print_modifiers_and_trait_path(), desc, - trait_ref.skip_binder().self_ty(), + tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None), ), None => format!( "{}the trait `{}` is not implemented for `{}`", pre_message, trait_predicate.print_modifiers_and_trait_path(), - trait_ref.skip_binder().self_ty(), + tcx.short_ty_string(trait_ref.skip_binder().self_ty(), &mut None), ), } } @@ -4599,9 +4782,15 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( return None; }; - let future = tcx.hir().get_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); - let Some(hir::GenericBound::LangItemTrait(_, _, _, generics)) = future.bounds.get(0) else { - // `async fn` should always lower to a lang item bound... but don't ICE. + let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); + let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { + // `async fn` should always lower to a single bound... but don't ICE. + return None; + }; + let Some(hir::PathSegment { args: Some(generics), .. }) = + trait_ref.trait_ref.path.segments.last() + else { + // desugaring to a single path segment for `Future<...>`. return None; }; let Some(hir::TypeBindingKind::Equality { term: hir::Term::Ty(future_output_ty) }) = @@ -4645,3 +4834,14 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( Some(sugg) } + +fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec) { + let mut refs = vec![]; + + while let ty::Ref(_, new_ty, mutbl) = ty.kind() { + ty = *new_ty; + refs.push(*mutbl); + } + + (ty, refs) +} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index ba2e3d1ae..9ee091bbd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -3,6 +3,7 @@ use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; use crate::traits::error_reporting::{ambiguity, ambiguity::Ambiguity::*}; @@ -36,11 +37,11 @@ use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, }; -use rustc_session::config::{DumpSolverProofTree, TraitSolver}; +use rustc_session::config::DumpSolverProofTree; use rustc_session::Limit; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::sym; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; +use rustc_span::{BytePos, ExpnKind, Span, Symbol, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::iter; @@ -98,8 +99,21 @@ pub trait TypeErrCtxtExt<'tcx> { error: &SelectionError<'tcx>, ); + fn emit_specialized_closure_kind_error( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Option; + fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool; + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) -> bool; + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -212,7 +226,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors") + self.tcx.sess.span_delayed_bug(DUMMY_SP, "expected fulfillment errors") } /// Reports that an overflow has occurred and halts compilation. We @@ -236,7 +250,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.emit(); self.tcx.sess.abort_if_errors(); - bug!(); + // FIXME: this should be something like `build_overflow_error_fatal`, which returns + // `DiagnosticBuilder<', !>`. Then we don't even need anything after that `emit()`. + unreachable!( + "did not expect compilation to continue after `abort_if_errors`, \ + since an error was definitely emitted!" + ); } fn build_overflow_error( @@ -356,14 +375,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) { let tcx = self.tcx; - if tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError { + if tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() + == DumpSolverProofTree::OnError + { dump_proof_tree(root_obligation, self.infcx); } let mut span = obligation.cause.span; // FIXME: statically guarantee this by tainting after the diagnostic is emitted self.set_tainted_by_errors( - tcx.sess.delay_span_bug(span, "`report_selection_error` did not emit an error"), + tcx.sess.span_delayed_bug(span, "`report_selection_error` did not emit an error"), ); let mut err = match *error { @@ -411,6 +432,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let trait_predicate = bound_predicate.rebind(trait_predicate); let trait_predicate = self.resolve_vars_if_possible(trait_predicate); + let trait_ref = trait_predicate.to_poly_trait_ref(); + + if let Some(_guar) = self.emit_specialized_closure_kind_error(&obligation, trait_ref) { + return; + } // FIXME(effects) let predicate_is_const = false; @@ -425,22 +451,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // reported on the binding definition (#56607). return; } - let trait_ref = trait_predicate.to_poly_trait_ref(); - let (post_message, pre_message, type_def, file_note) = self + let mut file = None; + let (post_message, pre_message, type_def) = self .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { - let (t, file) = self.tcx.short_ty_string(t); + let t = self.tcx.short_ty_string(t, &mut file); ( format!(" in `{t}`"), format!("within `{t}`, "), s.map(|s| (format!("within this `{t}`"), s)), - file.map(|file| format!( - "the full trait has been written to '{}'", - file.display(), - )) ) }) .unwrap_or_default(); + let file_note = file.map(|file| format!( + "the full trait has been written to '{}'", + file.display(), + )); let OnUnimplementedNote { message, @@ -499,6 +525,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg); + let mut suggested = false; + if is_try_conversion { + suggested = self.try_conversion_context(&obligation, trait_ref.skip_binder(), &mut err); + } + if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { err.span_label( ret_span, @@ -511,7 +542,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() { self.add_tuple_trait_message( - &obligation.cause.code().peel_derives(), + obligation.cause.code().peel_derives(), &mut err, ); } @@ -524,6 +555,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let explanation = get_explanation_based_on_obligation( + self.tcx, &obligation, trait_ref, &trait_predicate, @@ -569,7 +601,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { self.suggest_borrowing_for_object_cast( &mut err, - &root_obligation, + root_obligation, source, target, ); @@ -599,8 +631,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); self.suggest_dereferencing_index(&obligation, &mut err, trait_predicate); - let mut suggested = - self.suggest_dereferences(&obligation, &mut err, trait_predicate); + suggested |= self.suggest_dereferences(&obligation, &mut err, trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, trait_predicate); let impl_candidates = self.find_similar_impl_candidates(trait_predicate); suggested = if let &[cand] = &impl_candidates[..] { @@ -612,7 +643,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span.shrink_to_hi(), format!( "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", - cand.print_only_trait_path(), + cand.print_trait_sugared(), cand.self_ty(), ), format!(" as {}", cand.self_ty()), @@ -786,30 +817,22 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { report_object_safety_error(self.tcx, span, trait_def_id, violations) } - ty::PredicateKind::ClosureKind(closure_def_id, closure_args, kind) => { - let found_kind = self.closure_kind(closure_args).unwrap(); - self.report_closure_error(&obligation, closure_def_id, found_kind, kind) - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { let ty = self.resolve_vars_if_possible(ty); - match self.tcx.sess.opts.unstable_opts.trait_solver { - TraitSolver::Classic => { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "WF predicate not satisfied for {:?}", ty); - } - TraitSolver::Next | TraitSolver::NextCoherence => { - // FIXME: we'll need a better message which takes into account - // which bounds actually failed to hold. - self.tcx.sess.struct_span_err( - span, - format!("the type `{ty}` is not well-formed"), - ) - } + if self.next_trait_solver() { + // FIXME: we'll need a better message which takes into account + // which bounds actually failed to hold. + self.tcx.sess.struct_span_err( + span, + format!("the type `{ty}` is not well-formed"), + ) + } else { + // WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "WF predicate not satisfied for {:?}", ty); } } @@ -837,6 +860,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"), + ty::PredicateKind::NormalizesTo(..) => span_bug!( + span, + "NormalizesTo predicate should never be the predicate cause of a SelectionError" + ), + ty::PredicateKind::AliasRelate(..) => span_bug!( span, "AliasRelate predicate should never be the predicate cause of a SelectionError" @@ -927,18 +955,48 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.emit(); } + fn emit_specialized_closure_kind_error( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Option { + if let ty::Closure(closure_def_id, closure_args) = *trait_ref.self_ty().skip_binder().kind() + && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) + && let Some(found_kind) = self.closure_kind(closure_args) + && !found_kind.extends(expected_kind) + && let sig = closure_args.as_closure().sig() + && self.can_sub( + obligation.param_env, + trait_ref, + sig.map_bound(|sig| { + ty::TraitRef::new( + self.tcx, + trait_ref.def_id(), + [trait_ref.self_ty().skip_binder(), sig.inputs()[0]], + ) + }), + ) + { + let mut err = + self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + Some(err.emit()) + } else { + None + } + } + fn fn_arg_obligation(&self, obligation: &PredicateObligation<'tcx>) -> bool { - if let ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id, - .. - } = obligation.cause.code() - && let Some(Node::Expr(arg)) = self.tcx.hir().find(*arg_hir_id) + if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + && let Some(Node::Expr(arg)) = self.tcx.opt_hir_node(*arg_hir_id) && let arg = arg.peel_borrows() && let hir::ExprKind::Path(hir::QPath::Resolved( None, hir::Path { res: hir::def::Res::Local(hir_id), .. }, )) = arg.kind - && let Some(Node::Pat(pat)) = self.tcx.hir().find(*hir_id) + && let Some(Node::Pat(pat)) = self.tcx.opt_hir_node(*hir_id) && let Some(preds) = self.reported_trait_errors.borrow().get(&pat.span) && preds.contains(&obligation.predicate) { @@ -947,6 +1005,223 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { false } + /// When the `E` of the resulting `Result` in an expression `foo().bar().baz()?`, + /// identify thoe method chain sub-expressions that could or could not have been annotated + /// with `?`. + fn try_conversion_context( + &self, + obligation: &PredicateObligation<'tcx>, + trait_ref: ty::TraitRef<'tcx>, + err: &mut Diagnostic, + ) -> bool { + let span = obligation.cause.span; + struct V<'v> { + search_span: Span, + found: Option<&'v hir::Expr<'v>>, + } + impl<'v> Visitor<'v> for V<'v> { + fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { + if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind + { + if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) { + if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind { + self.found = Some(expr); + return; + } + } + } + hir::intravisit::walk_expr(self, ex); + } + } + let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); + let body_id = match self.tcx.opt_hir_node(hir_id) { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { + body_id + } + _ => return false, + }; + let mut v = V { search_span: span, found: None }; + v.visit_body(self.tcx.hir().body(*body_id)); + let Some(expr) = v.found else { + return false; + }; + let Some(typeck) = &self.typeck_results else { + return false; + }; + let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() + else { + return false; + }; + if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { + return false; + } + let self_ty = trait_ref.self_ty(); + let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type()); + + let mut prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + // We always look at the `E` type, because that's the only one affected by `?`. If the + // incorrect `Result` is because of the `T`, we'll get an E0308 on the whole + // expression, after the `?` has "unwrapped" the `T`. + let get_e_type = |prev_ty: Ty<'tcx>| -> Option> { + let ty::Adt(def, args) = prev_ty.kind() else { + return None; + }; + let Some(arg) = args.get(1) else { + return None; + }; + if !self.tcx.is_diagnostic_item(sym::Result, def.did()) { + return None; + } + arg.as_type() + }; + + let mut suggested = false; + let mut chain = vec![]; + + // The following logic is simlar to `point_at_chain`, but that's focused on associated types + let mut expr = expr; + while let hir::ExprKind::MethodCall(path_segment, rcvr_expr, args, span) = expr.kind { + // Point at every method call in the chain with the `Result` type. + // let foo = bar.iter().map(mapper)?; + // ------ ----------- + expr = rcvr_expr; + chain.push((span, prev_ty)); + + let next_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + + let is_diagnostic_item = |symbol: Symbol, ty: Ty<'tcx>| { + let ty::Adt(def, _) = ty.kind() else { + return false; + }; + self.tcx.is_diagnostic_item(symbol, def.did()) + }; + // For each method in the chain, see if this is `Result::map_err` or + // `Option::ok_or_else` and if it is, see if the closure passed to it has an incorrect + // trailing `;`. + if let Some(ty) = get_e_type(prev_ty) + && let Some(found_ty) = found_ty + // Ideally we would instead use `FnCtxt::lookup_method_for_diagnostic` for 100% + // accurate check, but we are in the wrong stage to do that and looking for + // `Result::map_err` by checking the Self type and the path segment is enough. + // sym::ok_or_else + && ( + ( // Result::map_err + path_segment.ident.name == sym::map_err + && is_diagnostic_item(sym::Result, next_ty) + ) || ( // Option::ok_or_else + path_segment.ident.name == sym::ok_or_else + && is_diagnostic_item(sym::Option, next_ty) + ) + ) + // Found `Result<_, ()>?` + && let ty::Tuple(tys) = found_ty.kind() + && tys.is_empty() + // The current method call returns `Result<_, ()>` + && self.can_eq(obligation.param_env, ty, found_ty) + // There's a single argument in the method call and it is a closure + && args.len() == 1 + && let Some(arg) = args.get(0) + && let hir::ExprKind::Closure(closure) = arg.kind + // The closure has a block for its body with no tail expression + && let body = self.tcx.hir().body(closure.body) + && let hir::ExprKind::Block(block, _) = body.value.kind + && let None = block.expr + // The last statement is of a type that can be converted to the return error type + && let [.., stmt] = block.stmts + && let hir::StmtKind::Semi(expr) = stmt.kind + && let expr_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr) + .unwrap_or(Ty::new_misc_error(self.tcx)), + ) + && self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, expr_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + suggested = true; + err.span_suggestion_short( + stmt.span.with_lo(expr.span.hi()), + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + + prev_ty = next_ty; + + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path + && let Some(hir::Node::Pat(binding)) = self.tcx.opt_hir_node(*hir_id) + && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id) + { + // We've reached the root of the method call chain... + if let hir::Node::Local(local) = parent + && let Some(binding_expr) = local.init + { + // ...and it is a binding. Get the binding creation and continue the chain. + expr = binding_expr; + } + if let hir::Node::Param(_param) = parent { + // ...and it is a an fn argument. + break; + } + } + } + // `expr` is now the "root" expression of the method call chain, which can be any + // expression kind, like a method call or a path. If this expression is `Result` as + // well, then we also point at it. + prev_ty = self.resolve_vars_if_possible( + typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), + ); + chain.push((expr.span, prev_ty)); + + let mut prev = None; + for (span, err_ty) in chain.into_iter().rev() { + let err_ty = get_e_type(err_ty); + let err_ty = match (err_ty, prev) { + (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => { + err_ty + } + (Some(err_ty), None) => err_ty, + _ => { + prev = err_ty; + continue; + } + }; + if self + .infcx + .type_implements_trait( + self.tcx.get_diagnostic_item(sym::From).unwrap(), + [self_ty, err_ty], + obligation.param_env, + ) + .must_apply_modulo_regions() + { + if !suggested { + err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); + } + } else { + err.span_label( + span, + format!( + "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", + ), + ); + } + prev = Some(err_ty); + } + suggested + } + fn report_const_param_not_wf( &self, ty: Ty<'tcx>, @@ -1291,7 +1566,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { #[instrument(skip(self), level = "debug")] fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) { - if self.tcx.sess.opts.unstable_opts.dump_solver_proof_tree == DumpSolverProofTree::OnError { + if self.tcx.sess.opts.unstable_opts.next_solver.map(|c| c.dump_tree).unwrap_or_default() + == DumpSolverProofTree::OnError + { dump_proof_tree(&error.root_obligation, self.infcx); } @@ -1377,7 +1654,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { let data = self.instantiate_binder_with_fresh_vars( obligation.cause.span, - infer::LateBoundRegionConversionTime::HigherRankedType, + infer::BoundRegionConversionTime::HigherRankedType, bound_predicate.rebind(data), ); let unnormalized_term = match data.term.unpack() { @@ -1397,7 +1674,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) .into(), }; - // FIXME(-Ztrait-solver=next): For diagnostic purposes, it would be nice + // 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, unnormalized_term); @@ -1413,7 +1690,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ExprItemObligation(..) | ObligationCauseCode::ExprBindingObligation(..) | ObligationCauseCode::Coercion { .. } - | ObligationCauseCode::OpaqueType ); // constrain inference variables a bit more to nested obligations from normalize so @@ -1653,6 +1929,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block", hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function", hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure", + hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Block) => "an async gen block", + hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Fn) => "an async gen function", + hir::CoroutineKind::AsyncGen(hir::CoroutineSource::Closure) => "an async gen closure", hir::CoroutineKind::Gen(hir::CoroutineSource::Block) => "a gen block", hir::CoroutineKind::Gen(hir::CoroutineSource::Fn) => "a gen function", hir::CoroutineKind::Gen(hir::CoroutineSource::Closure) => "a gen closure", @@ -1751,7 +2030,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }); err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (" implemented for `".to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1787,7 +2066,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => (" implemented for `", ""), }; err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_only_trait_path()), Style::NoStyle), + (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), ("is".to_string(), Style::Highlight), (desc.to_string(), Style::NoStyle), (cand.self_ty().to_string(), Style::Highlight), @@ -1820,7 +2099,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let end = if candidates.len() <= 9 { candidates.len() } else { 8 }; err.help(format!( "the following {other}types implement trait `{}`:{}{}", - trait_ref.print_only_trait_path(), + trait_ref.print_trait_sugared(), candidates[..end].join(""), if candidates.len() > 9 { format!("\nand {} others", candidates.len() - 8) @@ -1967,7 +2246,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { - self.get_parent_trait_ref(&parent_code) + self.get_parent_trait_ref(parent_code) } _ => None, } @@ -2182,7 +2461,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { let mut expr_finder = FindExprBySpan::new(span); - expr_finder.visit_expr(&self.tcx.hir().body(body_id).value); + expr_finder.visit_expr(self.tcx.hir().body(body_id).value); if let Some(hir::Expr { kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)), @@ -2228,7 +2507,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ident: trait_name, kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs), .. - })) = self.tcx.hir().find_by_def_id(local_def_id) + })) = self.tcx.opt_hir_node_by_def_id(local_def_id) && let Some(method_ref) = trait_item_refs .iter() .find(|item_ref| item_ref.ident == *assoc_item_name) @@ -2731,7 +3010,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { Some(format!("{cannot_do_this} in const contexts")) } // overridden post message - (true, Some(AppendConstMessage::Custom(custom_msg))) => { + (true, Some(AppendConstMessage::Custom(custom_msg, _))) => { Some(format!("{cannot_do_this}{custom_msg}")) } // fallback to generic message @@ -2752,7 +3031,8 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { use rustc_transmute::Answer; // Erase regions because layout code doesn't particularly care about regions. - let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref)); + let trait_ref = + self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); let src_and_dst = rustc_transmute::Types { dst: trait_ref.args.type_at(0), @@ -2933,7 +3213,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligation.param_env, ) { self.report_similar_impl_candidates_for_root_obligation( - &obligation, + obligation, *trait_predicate, body_def_id, err, @@ -3040,18 +3320,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Additional context information explaining why the closure only implements // a particular trait. if let Some(typeck_results) = &self.typeck_results { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id.expect_local()); match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { (ty::ClosureKind::FnOnce, Some((span, place))) => { err.fn_once_label = Some(ClosureFnOnceLabel { span: *span, - place: ty::place_to_string_for_capture(self.tcx, &place), + place: ty::place_to_string_for_capture(self.tcx, place), }) } (ty::ClosureKind::FnMut, Some((span, place))) => { err.fn_mut_label = Some(ClosureFnMutLabel { span: *span, - place: ty::place_to_string_for_capture(self.tcx, &place), + place: ty::place_to_string_for_capture(self.tcx, place), }) } _ => {} @@ -3115,7 +3395,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; if let Some(diag) = - self.tcx.sess.diagnostic().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle) + self.tcx.sess.dcx().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle) { diag.cancel(); } @@ -3163,7 +3443,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let mut not_tupled = false; let found = match found_trait_ref.skip_binder().args.type_at(1).kind() { - ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], + ty::Tuple(tys) => vec![ArgKind::empty(); tys.len()], _ => { not_tupled = true; vec![ArgKind::empty()] @@ -3172,7 +3452,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let expected_ty = expected_trait_ref.skip_binder().args.type_at(1); let expected = match expected_ty.kind() { - ty::Tuple(ref tys) => { + ty::Tuple(tys) => { tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() } _ => { @@ -3253,20 +3533,30 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => { - let ty::ConstKind::Unevaluated(uv) = ct.kind() else { + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => match ct.kind() { + ty::ConstKind::Unevaluated(uv) => { + let mut err = + self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); + let const_span = self.tcx.def_span(uv.def); + match self.tcx.sess.source_map().span_to_snippet(const_span) { + Ok(snippet) => err.help(format!( + "try adding a `where` bound using this expression: `where [(); {snippet}]:`" + )), + _ => err.help("consider adding a `where` bound using this expression"), + }; + Some(err) + } + ty::ConstKind::Expr(_) => { + let err = self + .tcx + .sess + .struct_span_err(span, format!("unconstrained generic constant `{ct}`")); + Some(err) + } + _ => { bug!("const evaluatable failed for non-unevaluated const `{ct:?}`"); - }; - let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); - let const_span = self.tcx.def_span(uv.def); - match self.tcx.sess.source_map().span_to_snippet(const_span) { - Ok(snippet) => err.help(format!( - "try adding a `where` bound using this expression: `where [(); {snippet}]:`" - )), - _ => err.help("consider adding a `where` bound using this expression"), - }; - Some(err) - } + } + }, _ => { span_bug!( span, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fb9cf51b5..045d7e444 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,5 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; +use crate::traits::error_reporting::TypeErrCtxtExt; use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; @@ -115,12 +116,13 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, + mut obligation: PredicateObligation<'tcx>, ) { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); // this helps to reduce duplicate errors, as well as making // debug output much nicer to read and so on. - let obligation = infcx.resolve_vars_if_possible(obligation); + debug_assert!(!obligation.param_env.has_non_region_infer()); + obligation.predicate = infcx.resolve_vars_if_possible(obligation.predicate); debug!(?obligation, "register_predicate_obligation"); @@ -350,7 +352,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) @@ -360,8 +361,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)])) } ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, + ty::PredicateKind::NormalizesTo(..) => { + bug!("NormalizesTo is only used by the new solver") + } ty::PredicateKind::AliasRelate(..) => { - bug!("AliasRelate is only used for new solver") + bug!("AliasRelate is only used by the new solver") } }, Some(pred) => match pred { @@ -411,17 +415,30 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } - ty::PredicateKind::ClosureKind(_, closure_args, kind) => { - match self.selcx.infcx.closure_kind(closure_args) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - ProcessResult::Changed(vec![]) - } else { - ProcessResult::Error(CodeSelectionError(Unimplemented)) - } - } - None => ProcessResult::Unchanged, - } + ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, + ty::PredicateKind::NormalizesTo(..) => { + bug!("NormalizesTo is only used by the new solver") + } + ty::PredicateKind::AliasRelate(..) => { + bug!("AliasRelate is only used by the new solver") + } + + // General case overflow check. Allow `process_trait_obligation` + // and `process_projection_obligation` to handle checking for + // the recursion limit themselves. Also don't check some + // predicate kinds that don't give further obligations. + _ if !self + .selcx + .tcx() + .recursion_limit() + .value_within_limit(obligation.recursion_depth) => + { + self.selcx.infcx.err_ctxt().report_overflow_error( + &obligation.predicate, + obligation.cause.span, + false, + |_| {}, + ); } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { @@ -454,7 +471,12 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)]; ProcessResult::Unchanged } - Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Ok(Ok(mut ok)) => { + for subobligation in &mut ok.obligations { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } + ProcessResult::Changed(mk_pending(ok.obligations)) + } Ok(Err(err)) => { let expected_found = ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b); @@ -625,10 +647,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } - ty::PredicateKind::Ambiguous => ProcessResult::Unchanged, - ty::PredicateKind::AliasRelate(..) => { - bug!("AliasRelate is only used for new solver") - } ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( DefineOpaqueTypes::No, diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index ab07b10c6..cf4fa2337 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -9,7 +9,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; -use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; use super::outlives_bounds::InferCtxtExt; @@ -173,7 +173,7 @@ pub fn all_fields_implement_trait<'tcx>( // 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() { - tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id))); + tcx.sess.span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id))); continue; } @@ -209,10 +209,10 @@ pub fn all_fields_implement_trait<'tcx>( pub fn check_tys_might_be_eq<'tcx>( tcx: TyCtxt<'tcx>, - canonical: Canonical<'tcx, (ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>, + canonical: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, ) -> Result<(), NoSolution> { - let (infcx, (param_env, ty_a, ty_b), _) = - tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical); + let (infcx, key, _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical); + let (param_env, (ty_a, ty_b)) = key.into_parts(); let ocx = ObligationCtxt::new(&infcx); let result = ocx.eq(&ObligationCause::dummy(), param_env, ty_a, ty_b); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index fff5510bb..8c5f1e907 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -215,7 +215,7 @@ fn do_normalize_predicates<'tcx>( // the normalized predicates. let errors = infcx.resolve_regions(&outlives_env); if !errors.is_empty() { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( span, format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"), ); @@ -315,7 +315,7 @@ pub fn normalize_param_env_or_error<'tcx>( // We do not normalize types here as there is no backwards compatibility requirement // for us to do so. // - // FIXME(-Ztrait-solver=next): remove this hack since we have deferred projection equality + // FIXME(-Znext-solver): remove this hack since we have deferred projection equality predicate.fold_with(&mut ConstNormalizer(tcx)) }), ) @@ -386,7 +386,7 @@ pub fn normalize_param_env_or_error<'tcx>( /// Normalize a type and process all resulting obligations, returning any errors. /// -/// FIXME(-Ztrait-solver=next): This should be replaced by `At::deeply_normalize` +/// FIXME(-Znext-solver): This should be replaced by `At::deeply_normalize` /// which has the same behavior with the new solver. Because using a separate /// fulfillment context worsens caching in the old solver, `At::deeply_normalize` /// is still lazy with the old solver as it otherwise negatively impacts perf. @@ -484,7 +484,7 @@ fn is_impossible_associated_item( t.super_visit_with(self) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { - if let ty::ReEarlyBound(param) = r.kind() + if let ty::ReEarlyParam(param) = r.kind() && let param_def_id = self.generics.region_param(¶m, self.tcx).def_id && self.tcx.parent(param_def_id) == self.trait_item_def_id { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 17c7f94ee..7ac37315f 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -84,7 +84,7 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { span, ) = violation { - lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation); + lint_object_unsafe_trait(tcx, *span, trait_def_id, violation); } } return true; @@ -192,9 +192,8 @@ fn lint_object_unsafe_trait( ); if node.is_some() { // Only provide the help if its a local trait, otherwise it's not - violation.solution(err); + violation.solution().add_to(err); } - err }, ); } @@ -329,7 +328,7 @@ fn super_predicates_have_non_lifetime_binders( tcx.super_predicates_of(trait_def_id) .predicates .iter() - .filter_map(|(pred, span)| pred.has_non_region_late_bound().then_some(*span)) + .filter_map(|(pred, span)| pred.has_non_region_bound_vars().then_some(*span)) .collect() } @@ -345,7 +344,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { // Search for a predicate like `Self : Sized` amongst the trait bounds. let predicates = tcx.predicates_of(def_id); let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() { + elaborate(tcx, predicates).any(|pred| match pred.kind().skip_binder() { ty::ClauseKind::Trait(ref trait_pred) => { trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0) } @@ -509,7 +508,7 @@ fn virtual_call_violations_for_method<'tcx>( Ok(layout) => Some(layout.abi), Err(err) => { // #78372 - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(method.def_id), format!("error: {err}\n while computing layout for type {ty:?}"), ); @@ -525,7 +524,7 @@ fn virtual_call_violations_for_method<'tcx>( match abi_of_ty(unit_receiver_ty) { Some(Abi::Scalar(..)) => (), abi => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(method.def_id), format!( "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}" @@ -543,7 +542,7 @@ fn virtual_call_violations_for_method<'tcx>( match abi_of_ty(trait_object_receiver) { Some(Abi::ScalarPair(..)) => (), abi => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( tcx.def_span(method.def_id), format!( "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}" @@ -595,9 +594,7 @@ fn virtual_call_violations_for_method<'tcx>( // would already have reported an error at the definition of the // auto trait. if pred_trait_ref.args.len() != 1 { - tcx.sess - .diagnostic() - .delay_span_bug(span, "auto traits cannot have generic parameters"); + tcx.sess.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters"); } return false; } diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 32bbd626d..7513f88cf 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { }; let mut constraints = QueryRegionConstraints::default(); - let Ok(InferOk { value, obligations }) = self + let Ok(InferOk { value: mut bounds, obligations }) = self .instantiate_nll_query_response_and_region_obligations( &ObligationCause::dummy(), param_env, @@ -85,6 +85,10 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { }; assert_eq!(&obligations, &[]); + // Because of #109628, we may have unexpected placeholders. Ignore them! + // FIXME(#109628): panic in this case once the issue is fixed. + bounds.retain(|bound| !bound.has_placeholders()); + if !constraints.is_empty() { let span = self.tcx.def_span(body_id); @@ -107,14 +111,14 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { let errors = ocx.select_all_or_error(); if !errors.is_empty() { - self.tcx.sess.delay_span_bug( + self.tcx.sess.span_delayed_bug( span, "implied_outlives_bounds failed to solve obligations from instantiation", ); } }; - value + bounds } fn implied_bounds_tys( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 471d10dbd..a1b0ada0e 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -18,7 +18,7 @@ use rustc_middle::traits::ImplSourceUserDefinedData; use crate::errors::InherentProjectionNormalizationOverflow; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; +use crate::infer::{BoundRegionConversionTime, InferCtxt, InferOk}; use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::select::ProjectionMatchesProjection; @@ -67,7 +67,7 @@ pub trait NormalizeExt<'tcx> { /// same goals in both a temporary and the shared context which negatively impacts /// performance as these don't share caching. /// - /// FIXME(-Ztrait-solver=next): This has the same behavior as `traits::fully_normalize` + /// FIXME(-Znext-solver): This has the same behavior as `traits::fully_normalize` /// in the new solver, but because of performance reasons, we currently reuse an /// existing fulfillment context in the old solver. Once we also eagerly prove goals with /// the old solver or have removed the old solver, remove `traits::fully_normalize` and @@ -191,7 +191,9 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { match (current, candidate) { (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => unreachable!(), + (_, ParamEnv(..)) => bug!( + "should never prefer non-param-env candidates over param-env candidates" + ), (_, _) => convert_to_ambiguous = (), } } @@ -584,7 +586,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx data, self.cause.clone(), self.depth, - &mut self.obligations, + self.obligations, ) } else { opt_normalize_projection_type( @@ -593,7 +595,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx data, self.cause.clone(), self.depth, - &mut self.obligations, + self.obligations, ) .ok() .flatten() @@ -632,7 +634,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx data, self.cause.clone(), self.depth, - &mut self.obligations, + self.obligations, ) .ok() .flatten() @@ -717,7 +719,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx data, self.cause.clone(), self.depth, - &mut self.obligations, + self.obligations, ) } @@ -732,7 +734,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx data, self.cause.clone(), self.depth, - &mut self.obligations, + self.obligations, ); PlaceholderReplacer::replace_placeholders( @@ -894,16 +896,16 @@ impl<'tcx> TypeFolder> for BoundVarReplacer<'_, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(debruijn, _) - if debruijn.as_usize() + 1 - > self.current_index.as_usize() + self.universe_indices.len() => + ty::ReBound(debruijn, _) + if debruijn.as_usize() + >= self.current_index.as_usize() + self.universe_indices.len() => { bug!( "Bound vars {r:#?} outside of `self.universe_indices`: {:#?}", self.universe_indices ); } - ty::ReLateBound(debruijn, br) if debruijn >= self.current_index => { + ty::ReBound(debruijn, br) if debruijn >= self.current_index => { let universe = self.universe_for(debruijn); let p = ty::PlaceholderRegion { universe, bound: br }; self.mapped_regions.insert(p, br); @@ -1001,7 +1003,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { &mut self, t: ty::Binder<'tcx, T>, ) -> ty::Binder<'tcx, T> { - if !t.has_placeholders() && !t.has_infer_regions() { + if !t.has_placeholders() && !t.has_infer() { return t; } self.current_index.shift_in(1); @@ -1034,7 +1036,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - ty::Region::new_late_bound(self.interner(), db, *replace_var) + ty::Region::new_bound(self.interner(), db, *replace_var) } None => r1, } @@ -1048,6 +1050,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.infcx.shallow_resolve(ty); match *ty.kind() { ty::Placeholder(p) => { let replace_var = self.mapped_types.get(&p); @@ -1063,16 +1066,23 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { ); Ty::new_bound(self.infcx.tcx, db, *replace_var) } - None => ty, + None => { + if ty.has_infer() { + ty.super_fold_with(self) + } else { + ty + } + } } } - _ if ty.has_placeholders() || ty.has_infer_regions() => ty.super_fold_with(self), + _ if ty.has_placeholders() || ty.has_infer() => ty.super_fold_with(self), _ => ty, } } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + let ct = self.infcx.shallow_resolve(ct); if let ty::ConstKind::Placeholder(p) = ct.kind() { let replace_var = self.mapped_consts.get(&p); match replace_var { @@ -1087,7 +1097,13 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { ); ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty()) } - None => ct, + None => { + if ct.has_infer() { + ct.super_fold_with(self) + } else { + ct + } + } } } else { ct.super_fold_with(self) @@ -1440,11 +1456,22 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. - let self_ty = alias_ty.self_ty(); + let mut self_ty = alias_ty.self_ty(); + if !selcx.infcx.next_trait_solver() { + self_ty = normalize_with_depth_to( + selcx, + param_env, + cause.clone(), + depth + 1, + self_ty, + obligations, + ); + } + match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) { Ok(mut ok) => obligations.append(&mut ok.obligations), Err(_) => { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( cause.span, format!( "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not" @@ -1798,11 +1825,18 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); let lang_items = selcx.tcx().lang_items(); - if [lang_items.coroutine_trait(), lang_items.future_trait(), lang_items.iterator_trait()].contains(&Some(trait_ref.def_id)) - || selcx.tcx().fn_trait_kind_from_def_id(trait_ref.def_id).is_some() + if [ + lang_items.coroutine_trait(), + lang_items.future_trait(), + lang_items.iterator_trait(), + lang_items.async_iterator_trait(), + lang_items.fn_trait(), + lang_items.fn_mut_trait(), + lang_items.fn_once_trait(), + ].contains(&Some(trait_ref.def_id)) { true - } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { + }else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { match self_ty.kind() { ty::Bool | ty::Char @@ -1949,7 +1983,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { // These traits have no associated types. - selcx.tcx().sess.delay_span_bug( + selcx.tcx().sess.span_delayed_bug( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); @@ -2017,6 +2051,8 @@ fn confirm_select_candidate<'cx, 'tcx>( confirm_future_candidate(selcx, obligation, data) } else if lang_items.iterator_trait() == Some(trait_def_id) { confirm_iterator_candidate(selcx, obligation, data) + } else if lang_items.async_iterator_trait() == Some(trait_def_id) { + confirm_async_iterator_candidate(selcx, obligation, data) } else if selcx.tcx().fn_trait_kind_from_def_id(trait_def_id).is_some() { if obligation.predicate.self_ty().is_closure() { confirm_closure_candidate(selcx, obligation, data) @@ -2046,12 +2082,13 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec>, ) -> Progress<'tcx> { - let ty::Coroutine(_, args, _) = - selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() - else { - unreachable!() + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let ty::Coroutine(_, args, _) = self_ty.kind() else { + unreachable!( + "expected coroutine self type for built-in coroutine candidate, found {self_ty}" + ) }; - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); let Normalized { value: coroutine_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2066,29 +2103,31 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None); - let predicate = super::util::coroutine_trait_ref_and_outputs( + let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs( tcx, coroutine_def_id, obligation.predicate.self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.def_id).name; - let ty = if name == sym::Return { - return_ty - } else if name == sym::Yield { - yield_ty - } else { - bug!() - }; + ); - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), - term: ty.into(), - } - }); + let name = tcx.associated_item(obligation.predicate.def_id).name; + let ty = if name == sym::Return { + return_ty + } else if name == sym::Yield { + yield_ty + } else { + span_bug!( + tcx.def_span(obligation.predicate.def_id), + "unexpected associated type: `Coroutine::{name}`" + ); + }; - confirm_param_env_candidate(selcx, obligation, predicate, false) + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: ty.into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(nested) .with_addl_obligations(obligations) } @@ -2098,12 +2137,13 @@ fn confirm_future_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec>, ) -> Progress<'tcx> { - let ty::Coroutine(_, args, _) = - selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() - else { - unreachable!() + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let ty::Coroutine(_, args, _) = self_ty.kind() else { + unreachable!( + "expected coroutine self type for built-in async future candidate, found {self_ty}" + ) }; - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); let Normalized { value: coroutine_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2117,22 +2157,21 @@ fn confirm_future_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); let fut_def_id = tcx.require_lang_item(LangItem::Future, None); - let predicate = super::util::future_trait_ref_and_outputs( + let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs( tcx, fut_def_id, obligation.predicate.self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, return_ty)| { - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); + ); - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), - term: return_ty.into(), - } - }); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output); + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: return_ty.into(), + }; - confirm_param_env_candidate(selcx, obligation, predicate, false) + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(nested) .with_addl_obligations(obligations) } @@ -2141,13 +2180,55 @@ fn confirm_iterator_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, nested: Vec>, +) -> Progress<'tcx> { + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let ty::Coroutine(_, args, _) = self_ty.kind() else { + unreachable!("expected coroutine self type for built-in gen candidate, found {self_ty}") + }; + let gen_sig = args.as_coroutine().sig(); + let Normalized { value: gen_sig, obligations } = normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + gen_sig, + ); + + debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate"); + + let tcx = selcx.tcx(); + let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None); + + let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs( + tcx, + iter_def_id, + obligation.predicate.self_ty(), + gen_sig, + ); + + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: yield_ty.into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) + .with_addl_obligations(nested) + .with_addl_obligations(obligations) +} + +fn confirm_async_iterator_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + nested: Vec>, ) -> Progress<'tcx> { let ty::Coroutine(_, args, _) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() else { unreachable!() }; - let gen_sig = args.as_coroutine().poly_sig(); + let gen_sig = args.as_coroutine().sig(); let Normalized { value: gen_sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2156,27 +2237,34 @@ fn confirm_iterator_candidate<'cx, 'tcx>( gen_sig, ); - debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate"); + debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None); - let predicate = super::util::iterator_trait_ref_and_outputs( + let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs( tcx, iter_def_id, obligation.predicate.self_ty(), gen_sig, - ) - .map_bound(|(trait_ref, yield_ty)| { - debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); + ); - ty::ProjectionPredicate { - projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), - term: yield_ty.into(), - } - }); + debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item); - confirm_param_env_candidate(selcx, obligation, predicate, false) + let ty::Adt(_poll_adt, args) = *yield_ty.kind() else { + bug!(); + }; + let ty::Adt(_option_adt, args) = *args.type_at(0).kind() else { + bug!(); + }; + let item_ty = args.type_at(0); + + let predicate = ty::ProjectionPredicate { + projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args), + term: item_ty.into(), + }; + + confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false) .with_addl_obligations(nested) .with_addl_obligations(obligations) } @@ -2239,8 +2327,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec>, ) -> Progress<'tcx> { + let tcx = selcx.tcx(); let fn_type = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); - let sig = fn_type.fn_sig(selcx.tcx()); + let sig = fn_type.fn_sig(tcx); let Normalized { value: sig, obligations } = normalize_with_depth( selcx, obligation.param_env, @@ -2249,9 +2338,24 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>( sig, ); - confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) - .with_addl_obligations(nested) - .with_addl_obligations(obligations) + let host_effect_param = match *fn_type.kind() { + ty::FnDef(def_id, args) => tcx + .generics_of(def_id) + .host_effect_index + .map_or(tcx.consts.true_, |idx| args.const_at(idx)), + ty::FnPtr(_) => tcx.consts.true_, + _ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"), + }; + + confirm_callable_candidate( + selcx, + obligation, + sig, + util::TupleArgumentsFlag::Yes, + host_effect_param, + ) + .with_addl_obligations(nested) + .with_addl_obligations(obligations) } fn confirm_closure_candidate<'cx, 'tcx>( @@ -2259,9 +2363,9 @@ fn confirm_closure_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, nested: Vec>, ) -> Progress<'tcx> { - let ty::Closure(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind() - else { - unreachable!() + let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()); + let ty::Closure(_, args) = self_ty.kind() else { + unreachable!("expected closure self type for closure candidate, found {self_ty}") }; let closure_sig = args.as_closure().sig(); let Normalized { value: closure_sig, obligations } = normalize_with_depth( @@ -2274,9 +2378,16 @@ fn confirm_closure_candidate<'cx, 'tcx>( debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); - confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) - .with_addl_obligations(nested) - .with_addl_obligations(obligations) + confirm_callable_candidate( + selcx, + obligation, + closure_sig, + util::TupleArgumentsFlag::No, + // FIXME(effects): This doesn't handle const closures correctly! + selcx.tcx().consts.true_, + ) + .with_addl_obligations(nested) + .with_addl_obligations(obligations) } fn confirm_callable_candidate<'cx, 'tcx>( @@ -2284,6 +2395,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, fn_sig: ty::PolyFnSig<'tcx>, flag: util::TupleArgumentsFlag, + fn_host_effect: ty::Const<'tcx>, ) -> Progress<'tcx> { let tcx = selcx.tcx(); @@ -2298,6 +2410,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( obligation.predicate.self_ty(), fn_sig, flag, + fn_host_effect, ) .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args), @@ -2319,7 +2432,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( let cache_entry = infcx.instantiate_binder_with_fresh_vars( cause.span, - LateBoundRegionConversionTime::HigherRankedType, + BoundRegionConversionTime::HigherRankedType, poly_cache_entry, ); 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 f8efa6a1f..ec80df1d6 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -48,9 +48,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // (T1..Tn) and closures have same properties as T1..Tn -- // check if *all* of them are trivial. ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)), - ty::Closure(_, ref args) => { - trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()) - } + ty::Closure(_, args) => trivial_dropck_outlives(tcx, args.as_closure().tupled_upvars_ty()), ty::Adt(def, _) => { if Some(def.did()) == tcx.lang_items().manually_drop() { @@ -239,7 +237,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // By the time this code runs, all type variables ought to // be fully resolved. - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( span, format!("upvar_tys for closure not found. Expected capture information for closure {ty}",), ); @@ -288,7 +286,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( if !args.is_valid() { // By the time this code runs, all type variables ought to // be fully resolved. - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( span, format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",), ); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 65f32b1c4..d812d537d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -72,7 +72,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { let mut fulfill_cx = crate::solve::FulfillmentCtxt::new(self); fulfill_cx.register_predicate_obligation(self, obligation.clone()); // True errors - // FIXME(-Ztrait-solver=next): Overflows are reported as ambig here, is that OK? + // FIXME(-Znext-solver): Overflows are reported as ambig here, is that OK? if !fulfill_cx.select_where_possible(self).is_empty() { Ok(EvaluationResult::EvaluatedToErr) } else if !fulfill_cx.select_all_or_error(self).is_empty() { @@ -108,7 +108,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { match self.evaluate_obligation(obligation) { Ok(result) => result, Err(OverflowError::Canonical) => { - let mut selcx = SelectionContext::new(&self); + let mut selcx = SelectionContext::new(self); selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| match r { OverflowError::Canonical => { span_bug!( diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2e31b560b..ed55533bc 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -150,7 +150,7 @@ impl<'tcx> TypeVisitor> for MaxEscapingBoundVarVisitor { #[inline] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { match *r { - ty::ReLateBound(debruijn, _) if debruijn > self.outer_index => { + ty::ReBound(debruijn, _) if debruijn > self.outer_index => { self.escaping = self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); } @@ -160,14 +160,12 @@ impl<'tcx> TypeVisitor> for MaxEscapingBoundVarVisitor { } fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow { - match ct.kind() { - ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => { - self.escaping = - self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize()); - ControlFlow::Continue(()) - } - _ => ct.super_visit_with(self), + if ct.outer_exclusive_binder() > self.outer_index { + self.escaping = self + .escaping + .max(ct.outer_exclusive_binder().as_usize() - self.outer_index.as_usize()); } + ControlFlow::Continue(()) } } @@ -287,14 +285,14 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> ty::Projection => tcx.normalize_projection_ty(c_data), ty::Weak => tcx.normalize_weak_ty(c_data), ty::Inherent => tcx.normalize_inherent_projection_ty(c_data), - _ => unreachable!(), + kind => unreachable!("did not expect {kind:?} due to match arm above"), }?; // We don't expect ambiguity. if !result.value.is_proven() { // Rustdoc normalizes possibly not well-formed types, so only // treat this as a bug if we're not in rustdoc. if !tcx.sess.opts.actually_rustdoc { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( DUMMY_SP, format!("unexpected ambiguity: {c_data:?} {result:?}"), ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 302b6016e..152ceeee8 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -26,7 +26,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { tcx.type_op_ascribe_user_type(canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { 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 c81bc5790..18bb56ba4 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 @@ -82,13 +82,13 @@ where let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); let value = op(&ocx).map_err(|_| { - infcx.tcx.sess.delay_span_bug(span, format!("error performing operation: {name}")) + infcx.tcx.sess.span_delayed_bug(span, format!("error performing operation: {name}")) })?; let errors = ocx.select_all_or_error(); if errors.is_empty() { Ok(value) } else { - Err(infcx.tcx.sess.delay_span_bug( + Err(infcx.tcx.sess.span_delayed_bug( DUMMY_SP, format!("errors selecting obligation during MIR typeck: {errors:?}"), )) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs index f65893088..57e649f3e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs @@ -23,7 +23,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { tcx.type_op_eq(canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e345fc39e..ba6ed2987 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -50,7 +50,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { tcx.implied_outlives_bounds(canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { @@ -123,20 +123,19 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( Some(pred) => pred, }; match pred { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound // if we ever support that + ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous - | ty::PredicateKind::AliasRelate(..) - => {} + | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::AliasRelate(..) => {} // We need to search through *all* WellFormed predicates ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { @@ -144,10 +143,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( } // We need to register region relationships - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate( - r_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), + ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( + ty::OutlivesPredicate(r_a, r_b), + )) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( ty_a, @@ -186,7 +184,9 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( push_outlives_components(tcx, ty_a, &mut components); implied_bounds.extend(implied_bounds_from_components(r_b, components)) } - ty::GenericArgKind::Const(_) => unreachable!(), + ty::GenericArgKind::Const(_) => { + unreachable!("consts do not participate in outlives bounds") + } } } @@ -208,6 +208,11 @@ fn implied_bounds_from_components<'tcx>( Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), + Component::Placeholder(_p) => { + // FIXME(non_lifetime_binders): Placeholders don't currently + // imply anything for outlives, though they could easily. + None + } Component::EscapingAlias(_) => // If the projection has escaping regions, don't // try to infer any implied bounds even for its diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 9d7933e23..272f1a54f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -89,7 +89,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable> + 't /// make sure to feed it predefined opaque types and the defining anchor /// and that would require duplicating all of the tcx queries. Instead, /// just perform these ops locally. - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result; @@ -149,7 +149,7 @@ where if infcx.next_trait_solver() { return Ok(scrape_region_constraints( infcx, - |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self), + |ocx| QueryTypeOp::perform_locally_with_next_solver(ocx, self), "query type op", span, )? @@ -159,7 +159,7 @@ where let mut region_constraints = QueryRegionConstraints::default(); let (output, error_info, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| { - infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}")) + infcx.tcx.sess.span_delayed_bug(span, format!("error performing {self:?}")) })?; // Typically, instantiating NLL query results does not @@ -188,7 +188,7 @@ where } } if !progress { - return Err(infcx.tcx.sess.delay_span_bug( + return Err(infcx.tcx.sess.span_delayed_bug( span, format!("ambiguity processing {obligations:?} from {self:?}"), )); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 9559f5002..3b33f6e61 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -25,11 +25,11 @@ where T::type_op_method(tcx, canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { - // FIXME(-Ztrait-solver=next): shouldn't be using old normalizer + // FIXME(-Znext-solver): shouldn't be using old normalizer Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value)) } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs index f2c1243f9..07587e374 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs @@ -42,7 +42,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { tcx.dropck_outlives(canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs index 789ef6472..e21ede47f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs @@ -40,7 +40,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { tcx.type_op_prove_predicate(canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs index 10976d5cd..ae11b0825 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs @@ -20,7 +20,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { tcx.type_op_subtype(canonicalized) } - fn perform_locally_in_new_solver( + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, ) -> Result { 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 f4b6d3bcf..38b1046ac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -115,6 +115,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_future_candidates(obligation, &mut candidates); } else if lang_items.iterator_trait() == Some(def_id) { self.assemble_iterator_candidates(obligation, &mut candidates); + } else if lang_items.async_iterator_trait() == Some(def_id) { + self.assemble_async_iterator_candidates(obligation, &mut candidates); } self.assemble_closure_candidates(obligation, &mut candidates); @@ -155,10 +157,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); - // FIXME(effects) proper constness needed? - candidates.vec.extend( - result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)), - ); + candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx))); } /// Given an obligation like ``, searches the obligations that the caller @@ -261,6 +260,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_async_iterator_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = obligation.self_ty().skip_binder(); + if let ty::Coroutine(did, args, _) = *self_ty.kind() { + // gen constructs get lowered to a special kind of coroutine that + // should directly `impl AsyncIterator`. + if self.tcx().coroutine_is_async_gen(did) { + debug!(?self_ty, ?obligation, "assemble_iterator_candidates",); + + // Can only confirm this candidate if we have constrained + // the `Yield` type to at least `Poll>`.. + let ty::Adt(_poll_def, args) = *args.as_coroutine().yield_ty().kind() else { + candidates.ambiguous = true; + return; + }; + let ty::Adt(_option_def, _) = *args.type_at(0).kind() else { + candidates.ambiguous = true; + return; + }; + + candidates.vec.push(AsyncIteratorCandidate); + } + } + } + /// Checks for the artificial impl that the compiler will create for an obligation like `X : /// FnMut<..>` where `X` is a closure type. /// @@ -291,8 +318,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } None => { - debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.vec.push(ClosureCandidate { is_const }); + if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); + } else { + candidates.ambiguous = true; + } } } } @@ -328,17 +358,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Provide an impl, but only for suitable `fn` pointers. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { - candidates.vec.push(FnPointerCandidate { is_const: false }); + candidates + .vec + .push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). - ty::FnDef(def_id, _) => { - if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible() - && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() + ty::FnDef(def_id, args) => { + let tcx = self.tcx(); + if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible() + && tcx.codegen_fn_attrs(def_id).target_features.is_empty() { - candidates - .vec - .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); + candidates.vec.push(FnPointerCandidate { + fn_host_effect: tcx + .generics_of(def_id) + .host_effect_index + .map_or(tcx.consts.true_, |idx| args.const_at(idx)), + }); } } _ => {} @@ -375,7 +411,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if !drcx.args_refs_may_unify(obligation_args, impl_trait_ref.skip_binder().args) { + if !drcx.args_may_unify(obligation_args, impl_trait_ref.skip_binder().args) { return; } if self.reject_fn_ptr_impls( @@ -555,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Alias(ty::Opaque, _) => { - if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) { + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) { // We do not generate an auto impl candidate for `impl Trait`s which already // reference our auto trait. // @@ -634,7 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = placeholder_trait_predicate.self_ty(); let principal_trait_ref = match self_ty.kind() { - ty::Dynamic(ref data, ..) => { + ty::Dynamic(data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { debug!( "assemble_candidates_from_object_ty: matched builtin bound, \ @@ -759,10 +795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - ( - &ty::Dynamic(ref a_data, a_region, ty::Dyn), - &ty::Dynamic(ref b_data, b_region, ty::Dyn), - ) => { + (&ty::Dynamic(a_data, a_region, ty::Dyn), &ty::Dynamic(b_data, b_region, ty::Dyn)) => { // Upcast coercions permit several things: // // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` @@ -923,9 +956,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // If the predicate is `~const Destruct` in a non-const environment, we don't actually need // to check anything. We'll short-circuit checking any obligations in confirmation, too. - // FIXME(effects) - if true { - candidates.vec.push(ConstDestructCandidate(None)); + let Some(host_effect_index) = + self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index + else { + candidates.vec.push(BuiltinCandidate { has_nested: false }); + return; + }; + // If the obligation has `host = true`, then the obligation is non-const and it's always + // trivially implemented. + if obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index) + == self.tcx().consts.true_ + { + candidates.vec.push(BuiltinCandidate { has_nested: false }); return; } @@ -1051,7 +1093,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // The regions of a type don't affect the size of the type let tcx = self.tcx(); - let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty()); + let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty()); // We should erase regions from both the param-env and type, since both // may have infer regions. Specifically, after canonicalizing and instantiating, // early bound regions turn into region vars in both the new and old solver. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4bfa341e3..ce3fc2185 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -9,7 +9,7 @@ use rustc_ast::Mutability; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::{ @@ -71,7 +71,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, data) } - ProjectionCandidate(idx, _) => { + ProjectionCandidate(idx) => { let obligations = self.confirm_projection_candidate(obligation, idx)?; ImplSource::Param(obligations) } @@ -98,8 +98,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) } - FnPointerCandidate { is_const } => { - let data = self.confirm_fn_pointer_candidate(obligation, is_const)?; + AsyncIteratorCandidate => { + let vtable_iterator = self.confirm_async_iterator_candidate(obligation)?; + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) + } + + FnPointerCandidate { fn_host_effect } => { + let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?; ImplSource::Builtin(BuiltinImplSource::Misc, data) } @@ -327,8 +332,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // care about other regions. Erasing late-bound regions is equivalent // to instantiating the binder with placeholders then erasing those // placeholder regions. - let predicate = - self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate)); + let predicate = self + .tcx() + .erase_regions(self.tcx().instantiate_bound_regions_with_erased(obligation.predicate)); let Some(assume) = rustc_transmute::Assume::from_const( self.infcx.tcx, @@ -393,7 +399,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, obligation.param_env, trait_def_id, - &trait_ref.args, + trait_ref.args, obligation.predicate, ); @@ -454,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth, param_env, impl_def_id, - &args.value, + args.value, parent_trait_pred, ); @@ -552,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let defs: &ty::Generics = tcx.generics_of(assoc_type); if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( obligation.cause.span, "GATs in trait object shouldn't have been considered", ); @@ -592,7 +598,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - ty::Region::new_late_bound( + ty::Region::new_bound( tcx, ty::INNERMOST, ty::BoundRegion { @@ -647,8 +653,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_fn_pointer_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, - // FIXME(effects) - _is_const: bool, + fn_host_effect: ty::Const<'tcx>, ) -> Result>, SelectionError<'tcx>> { debug!(?obligation, "confirm_fn_pointer_candidate"); @@ -669,6 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self_ty, sig, util::TupleArgumentsFlag::Yes, + fn_host_effect, ) .map_bound(|(trait_ref, _)| trait_ref); @@ -707,7 +713,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth, obligation.param_env, trait_def_id, - &args, + args, obligation.predicate, ); @@ -730,7 +736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate"); - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); // NOTE: The self-type is a coroutine type and hence is // in fact unparameterized (or at least does not reference any @@ -741,15 +747,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .no_bound_vars() .expect("unboxed closure type should not capture bound vars from the predicate"); - let trait_ref = super::util::coroutine_trait_ref_and_outputs( + let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), self_ty, coroutine_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "coroutine candidate obligations"); Ok(nested) @@ -769,17 +774,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate"); - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); - let trait_ref = super::util::future_trait_ref_and_outputs( + let (trait_ref, _) = super::util::future_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "future candidate obligations"); Ok(nested) @@ -799,17 +803,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate"); - let gen_sig = args.as_coroutine().poly_sig(); + let gen_sig = args.as_coroutine().sig(); - let trait_ref = super::util::iterator_trait_ref_and_outputs( + let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(), gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; + debug!(?trait_ref, ?nested, "iterator candidate obligations"); + + Ok(nested) + } + + fn confirm_async_iterator_candidate( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + // Okay to skip binder because the args on coroutine types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let ty::Coroutine(coroutine_def_id, args, _) = *self_ty.kind() else { + bug!("closure candidate for non-closure {:?}", obligation); + }; + + debug!(?obligation, ?coroutine_def_id, ?args, "confirm_async_iterator_candidate"); + + let gen_sig = args.as_coroutine().sig(); + + let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(), + gen_sig, + ); + + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "iterator candidate obligations"); Ok(nested) @@ -820,11 +852,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result>, SelectionError<'tcx>> { - let kind = self - .tcx() - .fn_trait_kind_from_def_id(obligation.predicate.def_id()) - .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); - // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope // type/region parameters. @@ -833,16 +860,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("closure candidate for non-closure {:?}", obligation); }; - let trait_ref = self.closure_trait_ref_unnormalized(obligation, args); - let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let trait_ref = + self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_); + let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); - nested.push(obligation.with( - self.tcx(), - ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, args, kind)), - )); - Ok(nested) } @@ -920,8 +943,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let a_ty = self.infcx.shallow_resolve(predicate.self_ty()); let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1)); - let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { bug!() }; - let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { bug!() }; + let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { + bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`") + }; + let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { + bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`") + }; let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty); let unnormalized_upcast_principal = @@ -985,7 +1012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). - (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b)) + (&ty::Dynamic(data_a, r_a, dyn_a), &ty::Dynamic(data_b, r_b, dyn_b)) if dyn_a == dyn_b => { // See `assemble_candidates_for_unsizing` for more info. @@ -1030,7 +1057,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { + (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); @@ -1184,11 +1211,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, impl_def_id: Option, ) -> Result>, SelectionError<'tcx>> { - // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` - // FIXME(effects) - if true { - return Ok(vec![]); - } + let Some(host_effect_index) = + self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index + else { + bug!() + }; + let host_effect_param: ty::GenericArg<'tcx> = + obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index).into(); let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None); @@ -1277,7 +1306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| { let ty = bty.instantiate(tcx, args); - debug_assert!(!ty.has_late_bound_regions()); + debug_assert!(!ty.has_bound_regions()); ty })) } @@ -1285,7 +1314,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable ty::Alias(ty::Projection | ty::Inherent, ..) => { - // FIXME(effects) this needs constness let predicate = normalize_with_depth_to( self, obligation.param_env, @@ -1296,7 +1324,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx(), LangItem::Destruct, cause.span, - [nested_ty], + [nested_ty.into(), host_effect_param], ), polarity: ty::ImplPolarity::Positive, }), @@ -1316,13 +1344,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // since it's either not `const Drop` (and we raise an error during selection), // or it's an ADT (and we need to check for a custom impl during selection) _ => { - // FIXME(effects) this needs constness let predicate = self_ty.rebind(ty::TraitPredicate { trait_ref: ty::TraitRef::from_lang_item( self.tcx(), LangItem::Destruct, cause.span, - [nested_ty], + [nested_ty.into(), host_effect_param], ), polarity: ty::ImplPolarity::Positive, }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 08208cc60..23f7bdd15 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,8 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::TraitObligation; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::DepNodeIndex; @@ -46,6 +46,7 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; +use rustc_span::Symbol; use std::cell::{Cell, RefCell}; use std::cmp; @@ -59,13 +60,13 @@ mod candidate_assembly; mod confirmation; #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum IntercrateAmbiguityCause { - DownstreamCrate { trait_desc: String, self_desc: Option }, - UpstreamCrateUpdate { trait_desc: String, self_desc: Option }, - ReservationImpl { message: String }, +pub enum IntercrateAmbiguityCause<'tcx> { + DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option> }, + UpstreamCrateUpdate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option> }, + ReservationImpl { message: Symbol }, } -impl IntercrateAmbiguityCause { +impl<'tcx> IntercrateAmbiguityCause<'tcx> { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) { @@ -73,28 +74,32 @@ impl IntercrateAmbiguityCause { } pub fn intercrate_ambiguity_hint(&self) -> String { - match self { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => { - let self_desc = if let Some(ty) = self_desc { - format!(" for type `{ty}`") - } else { - String::new() - }; - format!("downstream crates may implement trait `{trait_desc}`{self_desc}") + with_no_trimmed_paths!(match self { + IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { + format!( + "downstream crates may implement trait `{trait_desc}`{self_desc}", + trait_desc = trait_ref.print_trait_sugared(), + self_desc = if let Some(self_ty) = self_ty { + format!(" for type `{self_ty}`") + } else { + String::new() + } + ) } - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => { - let self_desc = if let Some(ty) = self_desc { - format!(" for type `{ty}`") - } else { - String::new() - }; + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } => { format!( "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ - in future versions" + in future versions", + trait_desc = trait_ref.print_trait_sugared(), + self_desc = if let Some(self_ty) = self_ty { + format!(" for type `{self_ty}`") + } else { + String::new() + } ) } - IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(), - } + IntercrateAmbiguityCause::ReservationImpl { message } => message.to_string(), + }) } } @@ -114,7 +119,7 @@ pub struct SelectionContext<'cx, 'tcx> { /// We don't do his until we detect a coherence error because it can /// lead to false overflow results (#47139) and because always /// computing it may negatively impact performance. - intercrate_ambiguity_causes: Option>, + intercrate_ambiguity_causes: Option>>, /// The mode that trait queries run in, which informs our error handling /// policy. In essence, canonicalized queries need their errors propagated @@ -217,8 +222,8 @@ pub enum TreatInductiveCycleAs { impl From for EvaluationResult { fn from(treat: TreatInductiveCycleAs) -> EvaluationResult { match treat { - TreatInductiveCycleAs::Ambig => EvaluatedToUnknown, - TreatInductiveCycleAs::Recur => EvaluatedToRecur, + TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent, + TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent, } } } @@ -270,7 +275,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Gets the intercrate ambiguity causes collected since tracking /// was enabled and disables tracking at the same time. If /// tracking is not enabled, just returns an empty vector. - pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet { + pub fn take_intercrate_ambiguity_causes( + &mut self, + ) -> FxIndexSet> { assert!(self.is_intercrate()); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -367,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug_assert!(!self.infcx.next_trait_solver()); // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. - self.check_recursion_limit(&stack.obligation, &stack.obligation)?; + self.check_recursion_limit(stack.obligation, stack.obligation)?; // Check the cache. Note that we freshen the trait-ref // separately rather than using `stack.fresh_trait_ref` -- @@ -416,7 +423,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut no_candidates_apply = true; for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, &c)?.may_apply() { + if self.evaluate_candidate(stack, c)?.may_apply() { no_candidates_apply = false; break; } @@ -428,19 +435,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); if !trait_ref.references_error() { let self_ty = trait_ref.self_ty(); - let (trait_desc, self_desc) = with_no_trimmed_paths!({ - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = - self_ty.has_concrete_skeleton().then(|| self_ty.to_string()); - (trait_desc, self_desc) - }); + let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { - trait_desc, - self_desc, - } + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } }; debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); @@ -799,7 +798,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // A global type with no free lifetimes or generic parameters // outlives anything. if pred.0.has_free_regions() - || pred.0.has_late_bound_regions() + || pred.0.has_bound_regions() || pred.0.has_non_region_infer() || pred.0.has_non_region_infer() { @@ -885,19 +884,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::ClosureKind(_, closure_args, kind) => { - match self.infcx.closure_kind(closure_args) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - None => Ok(EvaluatedToAmbig), - } - } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, @@ -1004,8 +990,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + ty::PredicateKind::NormalizesTo(..) => { + bug!("NormalizesTo is only used by the new solver") + } ty::PredicateKind::AliasRelate(..) => { - bug!("AliasRelate is only used for new solver") + bug!("AliasRelate is only used by the new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { @@ -1237,15 +1226,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if unbound_input_types && stack.iter().skip(1).any(|prev| { stack.obligation.param_env == prev.obligation.param_env - && self.match_fresh_trait_refs( - stack.fresh_trait_pred, - prev.fresh_trait_pred, - prev.obligation.param_env, - ) + && self.match_fresh_trait_refs(stack.fresh_trait_pred, prev.fresh_trait_pred) }) { debug!("evaluate_stack --> unbound argument, recursive --> giving up",); - return Ok(EvaluatedToUnknown); + return Ok(EvaluatedToAmbigStackDependent); } match self.candidate_from_obligation(stack) { @@ -1464,20 +1449,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ImplCandidate(def_id) = candidate { if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) { if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes { - let value = tcx + let message = tcx .get_attr(def_id, sym::rustc_reservation_impl) .and_then(|a| a.value_str()); - if let Some(value) = value { + if let Some(message) = message { debug!( "filter_reservation_impls: \ reservation impl ambiguity on {:?}", def_id ); - intercrate_ambiguity_clauses.insert( - IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }, - ); + intercrate_ambiguity_clauses + .insert(IntercrateAmbiguityCause::ReservationImpl { message }); } } return Ok(None); @@ -1751,7 +1733,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested_obligations = Vec::new(); let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - LateBoundRegionConversionTime::HigherRankedType, + BoundRegionConversionTime::HigherRankedType, env_predicate, ); let infer_projection = if potentially_unnormalized_candidates { @@ -1841,7 +1823,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. let is_global = - |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_late_bound_vars(); + |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // `DiscriminantKindCandidate`, `ConstDestructCandidate` @@ -1879,7 +1861,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } // Drop otherwise equivalent non-const fn pointer candidates - (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes, + (FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => { + DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_) + } ( ParamCandidate(ref other_cand), @@ -1889,6 +1873,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1896,7 +1881,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | BuiltinCandidate { .. } | TraitAliasCandidate | ObjectCandidate(_) - | ProjectionCandidate(..), + | ProjectionCandidate(_), ) => { // We have a where clause so don't go around looking // for impls. Arbitrarily give param candidates priority @@ -1906,7 +1891,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // here (see issue #50825). DropVictim::drop_if(!is_global(other_cand)) } - (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => { + (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } @@ -1918,6 +1903,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1933,26 +1919,27 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ) } - (ProjectionCandidate(i, _), ProjectionCandidate(j, _)) + (ProjectionCandidate(i), ProjectionCandidate(j)) | (ObjectCandidate(i), ObjectCandidate(j)) => { // Arbitrarily pick the lower numbered candidate for backwards // compatibility reasons. Don't let this affect inference. DropVictim::drop_if(i < j && !has_non_region_infer) } - (ObjectCandidate(_), ProjectionCandidate(..)) - | (ProjectionCandidate(..), ObjectCandidate(_)) => { + (ObjectCandidate(_), ProjectionCandidate(_)) + | (ProjectionCandidate(_), ObjectCandidate(_)) => { bug!("Have both object and projection candidate") } // Arbitrarily give projection and object candidates priority. ( - ObjectCandidate(_) | ProjectionCandidate(..), + ObjectCandidate(_) | ProjectionCandidate(_), ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1968,13 +1955,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { .. } | TraitAliasCandidate, - ObjectCandidate(_) | ProjectionCandidate(..), + ObjectCandidate(_) | ProjectionCandidate(_), ) => DropVictim::No, (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => { @@ -2075,6 +2063,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -2086,6 +2075,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -2218,7 +2208,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - ty::CoroutineWitness(def_id, ref args) => { + ty::CoroutineWitness(def_id, args) => { let hidden_types = bind_coroutine_hidden_types_above( self.infcx, def_id, @@ -2307,23 +2297,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), - ty::Tuple(ref tys) => { + ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet t.rebind(tys.iter().collect()) } - ty::Closure(_, ref args) => { + ty::Closure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); t.rebind(vec![ty]) } - ty::Coroutine(_, ref args, _) => { + ty::Coroutine(_, args, _) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) } - ty::CoroutineWitness(def_id, ref args) => { + ty::CoroutineWitness(def_id, args) => { bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars()) } @@ -2436,7 +2426,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the placeholder trait ref may fail due the Generalizer relation // raising a CyclicalTy error due to a sub_root_var relation // for a variable being generalized... - let guar = self.infcx.tcx.sess.delay_span_bug( + let guar = self.infcx.tcx.sess.span_delayed_bug( obligation.cause.span, format!( "Impl {impl_def_id:?} was matchable against {obligation:?} but now is not" @@ -2638,9 +2628,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &self, previous: ty::PolyTraitPredicate<'tcx>, current: ty::PolyTraitPredicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, ) -> bool { - let mut matcher = MatchAgainstFreshVars::new(self.tcx(), param_env); + let mut matcher = MatchAgainstFreshVars::new(self.tcx()); matcher.relate(previous, current).is_ok() } @@ -2668,6 +2657,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, args: GenericArgsRef<'tcx>, + fn_host_effect: ty::Const<'tcx>, ) -> ty::PolyTraitRef<'tcx> { let closure_sig = args.as_closure().sig(); @@ -2688,6 +2678,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { self_ty, closure_sig, util::TupleArgumentsFlag::No, + fn_host_effect, ) .map_bound(|(trait_ref, _)| trait_ref) } @@ -3103,7 +3094,7 @@ fn bind_coroutine_hidden_types_above<'tcx>( kind: ty::BrAnon, }; counter += 1; - ty::Region::new_late_bound(tcx, current_depth, br) + ty::Region::new_bound(tcx, current_depth, br) } r => bug!("unexpected region: {r:?}"), }) diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index efab29743..71a88f5f0 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -37,7 +37,7 @@ pub struct OverlapError<'tcx> { pub with_impl: DefId, pub trait_ref: ty::TraitRef<'tcx>, pub self_ty: Option>, - pub intercrate_ambiguity_causes: FxIndexSet, + pub intercrate_ambiguity_causes: FxIndexSet>, pub involves_placeholder: bool, } @@ -107,7 +107,7 @@ pub fn translate_args_with_cause<'tcx>( param_env, source_impl, source_args, target_node ); let source_trait_ref = - infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, &source_args); + infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, source_args); // translate the Self and Param parts of the substitution, since those // vary across impls @@ -197,25 +197,22 @@ fn fulfill_implication<'tcx>( param_env, source_trait_ref, target_impl ); - let source_trait_ref = match traits::fully_normalize( - &infcx, - ObligationCause::dummy(), - param_env, - source_trait_ref, - ) { - Ok(source_trait_ref) => source_trait_ref, - Err(_errors) => { - infcx.tcx.sess.delay_span_bug( - infcx.tcx.def_span(source_impl), - format!("failed to fully normalize {source_trait_ref}"), - ); - source_trait_ref - } - }; + let source_trait_ref = + match traits::fully_normalize(infcx, ObligationCause::dummy(), param_env, source_trait_ref) + { + Ok(source_trait_ref) => source_trait_ref, + Err(_errors) => { + infcx.tcx.sess.span_delayed_bug( + infcx.tcx.def_span(source_impl), + format!("failed to fully normalize {source_trait_ref}"), + ); + source_trait_ref + } + }; let source_trait = ImplSubject::Trait(source_trait_ref); - let selcx = &mut SelectionContext::new(&infcx); + let selcx = &mut SelectionContext::new(infcx); let target_args = infcx.fresh_args_for_item(DUMMY_SP, target_impl); let (target_trait, obligations) = util::impl_subject_and_oblig(selcx, param_env, target_impl, target_args, error_cause); @@ -415,7 +412,7 @@ fn report_conflicting_impls<'tcx>( let msg = DelayDm(|| { format!( "conflicting implementations of trait `{}`{}{}", - overlap.trait_ref.print_only_trait_path(), + overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), match used_to_be_allowed { Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)", @@ -434,7 +431,10 @@ fn report_conflicting_impls<'tcx>( decorate(tcx, &overlap, impl_span, &mut err); Some(err.emit()) } else { - Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check")) + Some( + tcx.sess + .span_delayed_bug(impl_span, "impl should have failed the orphan check"), + ) }; sg.has_errored = reported; } @@ -445,12 +445,11 @@ fn report_conflicting_impls<'tcx>( }; tcx.struct_span_lint_hir( lint, - tcx.hir().local_def_id_to_hir_id(impl_def_id), + tcx.local_def_id_to_hir_id(impl_def_id), impl_span, msg, |err| { decorate(tcx, &overlap, impl_span, err); - err }, ); } diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 5960415a8..f8e47cacc 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -135,7 +135,7 @@ impl<'tcx> TypeVisitor> for Search<'tcx> { bug!("unexpected type during structural-match checking: {:?}", ty); } ty::Error(_) => { - self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check"); + self.tcx.sess.span_delayed_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. return ControlFlow::Continue(()); diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 9d6be7689..e0f9fdc38 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -3,7 +3,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_infer::traits::{FulfillmentError, TraitEngine}; use rustc_middle::ty::{self, Ty}; -use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation}; +use crate::traits::{NormalizeExt, Obligation}; pub trait StructurallyNormalizeExt<'tcx> { fn structurally_normalize( @@ -16,46 +16,43 @@ pub trait StructurallyNormalizeExt<'tcx> { impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { fn structurally_normalize( &self, - mut ty: Ty<'tcx>, + ty: Ty<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, ) -> Result, Vec>> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - // FIXME(-Ztrait-solver=next): correctly handle - // overflow here. - for _ in 0..256 { - let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, projection_ty) = *ty.kind() - else { - break; - }; - - let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: self.cause.span, - }); - let obligation = Obligation::new( - self.infcx.tcx, - self.cause.clone(), - self.param_env, - ty::Binder::dummy(ty::ProjectionPredicate { - projection_ty, - term: new_infer_ty.into(), - }), - ); - if self.infcx.predicate_may_hold(&obligation) { - fulfill_cx.register_predicate_obligation(self.infcx, obligation); - let errors = fulfill_cx.select_where_possible(self.infcx); - if !errors.is_empty() { - return Err(errors); - } - ty = self.infcx.resolve_vars_if_possible(new_infer_ty); - } else { - break; - } + // FIXME(-Znext-solver): Should we resolve opaques here? + let ty::Alias(ty::Projection | ty::Inherent | ty::Weak, _) = *ty.kind() else { + return Ok(ty); + }; + + let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: self.cause.span, + }); + + // We simply emit an `alias-eq` goal here, since that will take care of + // normalizing the LHS of the projection until it is a rigid projection + // (or a not-yet-defined opaque in scope). + let obligation = Obligation::new( + self.infcx.tcx, + self.cause.clone(), + self.param_env, + ty::PredicateKind::AliasRelate( + ty.into(), + new_infer_ty.into(), + ty::AliasRelationDirection::Equate, + ), + ); + + fulfill_cx.register_predicate_obligation(self.infcx, obligation); + let errors = fulfill_cx.select_where_possible(self.infcx); + if !errors.is_empty() { + return Err(errors); } - Ok(ty) + Ok(self.infcx.resolve_vars_if_possible(new_infer_ty)) } else { Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx)) } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index bbde0c827..19eae93df 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -220,9 +220,8 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates); let impl_obligations = super::predicates_for_generics(cause, param_env, predicates); - let impl_obligations = impl_obligations - .chain(normalization_obligations1.into_iter()) - .chain(normalization_obligations2.into_iter()); + let impl_obligations = + impl_obligations.chain(normalization_obligations1).chain(normalization_obligations2); (subject, impl_obligations) } @@ -265,13 +264,26 @@ pub fn closure_trait_ref_and_return_type<'tcx>( self_ty: Ty<'tcx>, sig: ty::PolyFnSig<'tcx>, tuple_arguments: TupleArgumentsFlag, + fn_host_effect: ty::Const<'tcx>, ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { assert!(!self_ty.has_escaping_bound_vars()); let arguments_tuple = match tuple_arguments { TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()), }; - let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]); + let trait_ref = if tcx.generics_of(fn_trait_def_id).host_effect_index.is_some() { + ty::TraitRef::new( + tcx, + fn_trait_def_id, + [ + ty::GenericArg::from(self_ty), + ty::GenericArg::from(arguments_tuple), + ty::GenericArg::from(fn_host_effect), + ], + ) + } else { + ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]) + }; sig.map_bound(|sig| (trait_ref, sig.output())) } @@ -279,33 +291,44 @@ pub fn coroutine_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); - let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]); - sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) + let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.resume_ty]); + (trait_ref, sig.yield_ty, sig.return_ty) } pub fn future_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, fn_trait_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]); - sig.map_bound(|sig| (trait_ref, sig.return_ty)) + (trait_ref, sig.return_ty) } pub fn iterator_trait_ref_and_outputs<'tcx>( tcx: TyCtxt<'tcx>, iterator_def_id: DefId, self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef::new(tcx, iterator_def_id, [self_ty]); - sig.map_bound(|sig| (trait_ref, sig.yield_ty)) + (trait_ref, sig.yield_ty) +} + +pub fn async_iterator_trait_ref_and_outputs<'tcx>( + tcx: TyCtxt<'tcx>, + async_iterator_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::GenSig<'tcx>, +) -> (ty::TraitRef<'tcx>, Ty<'tcx>) { + assert!(!self_ty.has_escaping_bound_vars()); + let trait_ref = ty::TraitRef::new(tcx, async_iterator_def_id, [self_ty]); + (trait_ref, sig.yield_ty) } pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fe5b625e4..0f8d9c6bf 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // Note that we handle the len is implicitly checked while walking `arg`. } - ty::Tuple(ref tys) => { + ty::Tuple(tys) => { if let Some((_last, rest)) = tys.split_last() { for &elem in rest { self.require_sized(elem, traits::TupleElem); @@ -761,18 +761,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; if !defer_to_coercion { - let cause = self.cause(traits::WellFormed(None)); - let component_traits = data.auto_traits().chain(data.principal_def_id()); - let tcx = self.tcx(); - self.out.extend(component_traits.map(|did| { - traits::Obligation::with_depth( - tcx, - cause.clone(), + if let Some(principal) = data.principal_def_id() { + self.out.push(traits::Obligation::with_depth( + self.tcx(), + self.cause(traits::WellFormed(None)), depth, param_env, - ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did)), - ) - })); + ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), + )); + } } } @@ -913,20 +910,15 @@ pub fn object_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, existential_predicates: &'tcx ty::List>, ) -> Vec> { - // Since we don't actually *know* the self type for an object, - // this "open(err)" serves as a kind of dummy standin -- basically - // a placeholder type. - let open_ty = Ty::new_fresh(tcx, 0); - let predicates = existential_predicates.iter().filter_map(|predicate| { if let ty::ExistentialPredicate::Projection(_) = predicate.skip_binder() { None } else { - Some(predicate.with_self_ty(tcx, open_ty)) + Some(predicate.with_self_ty(tcx, tcx.types.trait_object_dummy_self)) } }); - required_region_bounds(tcx, open_ty, predicates) + required_region_bounds(tcx, tcx.types.trait_object_dummy_self, predicates) } /// Given a set of predicates that apply to an object type, returns -- cgit v1.2.3