diff options
Diffstat (limited to 'compiler/rustc_trait_selection')
9 files changed, 70 insertions, 170 deletions
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 9b47c7299bb..911cc0b88c4 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -8,26 +8,16 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryRes use rustc_middle::traits::query::Fallible; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, ToPredicate}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; use std::fmt::Debug; pub use rustc_infer::infer::*; pub trait InferCtxtExt<'tcx> { - fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool; + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; - fn type_is_sized_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool; + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool; /// Check whether a `ty` implements given trait(trait_def_id). /// The inputs are: @@ -46,13 +36,9 @@ pub trait InferCtxtExt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> traits::EvaluationResult; } + impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { - fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); if !(param_env, ty).needs_infer() { @@ -65,17 +51,12 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // rightly refuses to work with inference variables, but // moves_by_default has a cache, which we want to use in other // cases. - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id) } - fn type_is_sized_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span) + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } #[instrument(level = "debug", skip(self, params), ret)] diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1870d3a2daf..dbf6775afc2 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -180,8 +180,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as // an additional sanity check. - let errors = - super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound(ObligationCause::dummy(), full_env, ty, trait_did); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f4cfe4ec0b0..572d20b5368 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -383,7 +383,10 @@ fn resolve_negative_obligation<'tcx>( }; let param_env = o.param_env; - if !super::fully_solve_obligation(&infcx, o).is_empty() { + let ocx = ObligationCtxt::new(&infcx); + ocx.register_obligation(o); + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index bfeda88a6d4..b27a3929078 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; -use rustc_span::def_id::{DefId, CRATE_DEF_ID}; +use rustc_span::def_id::DefId; use rustc_span::Span; use std::fmt::Debug; @@ -63,9 +63,7 @@ pub use self::util::{ elaborate_trait_ref, elaborate_trait_refs, }; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{ - get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices, -}; +pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; pub use self::util::{ supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type, SupertraitDefIds, Supertraits, @@ -131,29 +129,23 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, - span: Span, ) -> bool { let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty])); - pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const(), span) + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const()) } -#[instrument(level = "debug", skip(infcx, param_env, span, pred), ret)] +/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? +/// +/// Ping me on zulip if you want to use this method and need help with finding +/// an appropriate replacement. +#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, - span: Span, ) -> bool { let has_non_region_infer = pred.has_non_region_infer(); - let obligation = Obligation { - param_env, - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - cause: ObligationCause::misc(span, CRATE_DEF_ID), - recursion_depth: 0, - predicate: pred.to_predicate(infcx.tcx), - }; + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); let result = infcx.evaluate_obligation_no_overflow(&obligation); debug!(?result); @@ -166,14 +158,13 @@ fn pred_known_to_hold_modulo_regions<'tcx>( // this function's result remains infallible, we must confirm // that guess. While imperfect, I believe this is sound. - // FIXME(@lcnr): this function doesn't seem right. - // // The handling of regions in this area of the code is terrible, // see issue #29149. We should be able to improve on this with // NLL. - let errors = fully_solve_obligation(infcx, obligation); - - match &errors[..] { + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligation(obligation); + let errors = ocx.select_all_or_error(); + match errors.as_slice() { [] => true, errors => { debug!(?errors); @@ -389,43 +380,6 @@ where Ok(resolved_value) } -/// Process an obligation (and any nested obligations that come from it) to -/// completion, returning any errors -pub fn fully_solve_obligation<'tcx>( - infcx: &InferCtxt<'tcx>, - obligation: PredicateObligation<'tcx>, -) -> Vec<FulfillmentError<'tcx>> { - fully_solve_obligations(infcx, [obligation]) -} - -/// Process a set of obligations (and any nested obligations that come from them) -/// to completion -pub fn fully_solve_obligations<'tcx>( - infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, -) -> Vec<FulfillmentError<'tcx>> { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations); - ocx.select_all_or_error() -} - -/// Process a bound (and any nested obligations that come from it) to completion. -/// This is a convenience function for traits that have no generic arguments, such -/// as auto traits, and builtin traits like Copy or Sized. -pub fn fully_solve_bound<'tcx>( - infcx: &InferCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - bound: DefId, -) -> Vec<FulfillmentError<'tcx>> { - let tcx = infcx.tcx; - let trait_ref = tcx.mk_trait_ref(bound, [ty]); - let obligation = Obligation::new(tcx, cause, param_env, ty::Binder::dummy(trait_ref)); - - fully_solve_obligation(infcx, obligation) -} - /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 6cb64ad574f..bac02f2d383 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -1,7 +1,7 @@ use crate::infer::InferCtxt; use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use crate::traits::query::NoSolution; -use crate::traits::ObligationCause; +use crate::traits::{ObligationCause, ObligationCtxt}; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{self, ParamEnv, Ty}; use rustc_span::def_id::LocalDefId; @@ -71,22 +71,23 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> { if let Some(constraints) = constraints { debug!(?constraints); + if !constraints.member_constraints.is_empty() { + span_bug!(span, "{:#?}", constraints.member_constraints); + } + // Instantiation may have produced new inference variables and constraints on those // variables. Process these constraints. + let ocx = ObligationCtxt::new(self); let cause = ObligationCause::misc(span, body_id); - let errors = super::fully_solve_obligations( - self, - constraints.outlives.iter().map(|constraint| { - self.query_outlives_constraint_to_obligation( - *constraint, - cause.clone(), - param_env, - ) - }), - ); - if !constraints.member_constraints.is_empty() { - span_bug!(span, "{:#?}", constraints.member_constraints); + for &constraint in &constraints.outlives { + ocx.register_obligation(self.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + )); } + + let errors = ocx.select_all_or_error(); if !errors.is_empty() { self.tcx.sess.delay_span_bug( span, 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 6bf3ed0d0e2..8f1b05c1190 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 @@ -1,8 +1,8 @@ use crate::infer::canonical::query_response; use crate::infer::{InferCtxt, InferOk}; -use crate::traits; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; +use crate::traits::ObligationCtxt; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_span::source_map::DUMMY_SP; @@ -73,7 +73,9 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - let errors = traits::fully_solve_obligations(infcx, obligations); + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligations(obligations); + let errors = ocx.select_all_or_error(); if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, @@ -82,9 +84,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( } let region_obligations = infcx.take_registered_region_obligations(); - let region_constraint_data = infcx.take_and_reset_region_constraints(); - let region_constraints = query_response::make_query_region_constraints( infcx.tcx, region_obligations diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3d5dd18f4c1..eb354bc3f50 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -18,7 +18,7 @@ use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; use crate::traits::project::{normalize_with_depth, normalize_with_depth_to}; -use crate::traits::util::{self, closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::vtable::{ count_own_vtable_entries, prepare_vtable_segments, vtable_trait_first_method_offset, VtblSegment, @@ -253,15 +253,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - ensure_sufficient_stack(|| { - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - }) + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) } else { vec![] }; @@ -1118,14 +1116,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. - nested.push(predicate_for_trait_def( + let tail_unsize_obligation = obligation.with( tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [source_tail, target_tail], - )); + tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]), + ); + nested.push(tail_unsize_obligation); } // `(.., T)` -> `(.., U)` @@ -1147,17 +1142,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Construct the nested `T: Unsize<U>` predicate. - nested.push(ensure_sufficient_stack(|| { - predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - [a_last, b_last], - ) - })); + // Add a nested `T: Unsize<U>` predicate. + let last_unsize_obligation = obligation + .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last])); + nested.push(last_unsize_obligation); } _ => bug!("source: {source}, target: {target}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index bc1c72da1e1..d9b2b7dbe16 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -17,7 +17,7 @@ use super::project; use super::project::normalize_with_depth_to; use super::project::ProjectionTyObligation; use super::util; -use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use super::util::closure_trait_ref_and_return_type; use super::wf; use super::{ ErrorReporting, ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, @@ -2440,15 +2440,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { placeholder_ty, ) }); - let placeholder_obligation = predicate_for_trait_def( + + let obligation = Obligation::new( self.tcx(), - param_env, cause.clone(), - trait_def_id, - recursion_depth, - [normalized_ty], + param_env, + self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]), ); - obligations.push(placeholder_obligation); + obligations.push(obligation); obligations }) .collect() diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index ab4c36975a0..00c9a352258 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,11 +1,11 @@ use super::NormalizeExt; -use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext}; +use super::{ObligationCause, PredicateObligation, SelectionContext}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferOk; +use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{GenericArg, SubstsRef}; use rustc_span::Span; use smallvec::SmallVec; @@ -218,33 +218,6 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( (subject, impl_obligations) } -pub fn predicate_for_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize, -) -> PredicateObligation<'tcx> { - Obligation { - cause, - param_env, - recursion_depth, - predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx), - } -} - -pub fn predicate_for_trait_def<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>, -) -> PredicateObligation<'tcx> { - let trait_ref = tcx.mk_trait_ref(trait_def_id, params); - predicate_for_trait_ref(tcx, cause, param_env, trait_ref, recursion_depth) -} - /// Casts a trait reference into a reference to one of its super /// traits; returns `None` if `target_trait_def_id` is not a /// supertrait. |
