From 4d1fc2257baf4a8fc7e688f09b60618d9f050b21 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Sep 2022 19:34:51 +0200 Subject: [PATCH 1/3] stop using fresh inference vars --- compiler/rustc_middle/src/traits/select.rs | 9 +- compiler/rustc_middle/src/ty/_match.rs | 29 +-- compiler/rustc_middle/src/ty/erase_regions.rs | 18 ++ .../src/traits/auto_trait.rs | 61 +++--- .../src/traits/select/candidate_assembly.rs | 26 +-- .../src/traits/select/mod.rs | 176 ++++++++++-------- 6 files changed, 166 insertions(+), 153 deletions(-) diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 6bcdfd6394a94..82847eca55d5a 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -5,10 +5,9 @@ use self::EvaluationResult::*; use super::{SelectionError, SelectionResult}; -use rustc_errors::ErrorGuaranteed; - +use crate::traits::Canonical; use crate::ty; - +use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_query_system::cache::Cache; @@ -16,14 +15,14 @@ pub type SelectionCache<'tcx> = Cache< // This cache does not use `ParamEnvAnd` in its keys because `ParamEnv::and` can replace // caller bounds with an empty list if the `TraitPredicate` looks global, which may happen // after erasing lifetimes from the predicate. - (ty::ParamEnv<'tcx>, ty::TraitPredicate<'tcx>), + (ty::ParamEnv<'tcx>, Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>), SelectionResult<'tcx, SelectionCandidate<'tcx>>, >; pub type EvaluationCache<'tcx> = Cache< // See above: this cache does not use `ParamEnvAnd` in its keys due to sometimes incorrectly // caching with the wrong `ParamEnv`. - (ty::ParamEnv<'tcx>, ty::PolyTraitPredicate<'tcx>), + (ty::ParamEnv<'tcx>, Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>), EvaluationResult, >; diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index e6aab30a150de..1bae323c897c1 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -1,17 +1,15 @@ use crate::ty::error::TypeError; use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::{self, InferConst, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; -/// A type "A" *matches* "B" if the fresh types in B could be -/// substituted with values so as to make it equal to A. Matching is -/// intended to be used only on freshened types, and it basically -/// indicates if the non-freshened versions of A and B could have been -/// unified. +/// A type "A" *matches* "B" if the inference variables in B could be +/// substituted with values so as to make it equal to A. +/// Matching basically indicates whether A would contain B. /// /// It is only an approximation. If it yields false, unification would /// definitely fail, but a true result doesn't mean unification would /// succeed. This is because we don't track the "side-constraints" on -/// type variables, nor do we track if the same freshened type appears +/// type variables, nor do we track if the same inference variable appears /// more than once. To some extent these approximations could be /// fixed, given effort. /// @@ -69,16 +67,9 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { } match (a.kind(), b.kind()) { - ( - _, - &ty::Infer(ty::FreshTy(_)) - | &ty::Infer(ty::FreshIntTy(_)) - | &ty::Infer(ty::FreshFloatTy(_)), - ) => Ok(a), - - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(relate::expected_found(self, a, b))) - } + (_, &ty::Infer(_)) => Ok(a), + + (&ty::Infer(_), _) => Err(TypeError::Sorts(relate::expected_found(self, a, b))), (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()), @@ -97,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { } match (a.kind(), b.kind()) { - (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => { + (_, ty::ConstKind::Infer(_)) => { return Ok(a); } - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { + (ty::ConstKind::Infer(_), _) => { return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b))); } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 3226950e79e13..ed21f341a5445 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -30,6 +30,24 @@ impl<'tcx> TyCtxt<'tcx> { debug!("erase_regions = {:?}", value1); value1 } + + pub fn erase_regions_keep_static(self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + if value.has_free_regions() { + self.fold_regions(value, |r, _| match r.kind() { + ty::ReLateBound(_, _) | ty::ReStatic => r, + ty::ReEarlyBound(_) + | ty::ReFree(_) + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased => self.lifetimes.re_erased, + }) + } else { + value + } + } } struct RegionEraserVisitor<'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6ed4f1b8c4988..a130d7871864a 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -7,6 +7,7 @@ use crate::errors::UnableToConstructConstantValue; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; +use rustc_middle::infer::canonical::{Canonical, OriginalQueryValues}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitable; @@ -160,7 +161,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' // // We fix the first assumption by manually clearing out all of the InferCtxt's caches - // in between calls to SelectionContext.select. This allows us to keep all of the + // in between calls to `selcx.select`. This allows us to keep all of the // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift // them between calls. // @@ -233,7 +234,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { impl<'tcx> AutoTraitFinder<'tcx> { /// The core logic responsible for computing the bounds for our synthesized impl. /// - /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like + /// To calculate the bounds, we call `selcx.select` in a loop. Like /// `FulfillmentContext`, we recursively select the nested obligations of predicates we /// encounter. However, whenever we encounter an `UnimplementedError` involving a type /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular @@ -277,7 +278,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, user_env: ty::ParamEnv<'tcx>, - fresh_preds: &mut FxHashSet>, + deduplicated_preds: &mut FxHashSet>>, only_projections: bool, ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> { let tcx = infcx.tcx; @@ -286,10 +287,13 @@ impl<'tcx> AutoTraitFinder<'tcx> { // that are already in the `ParamEnv` (modulo regions): we already // know that they must hold. for predicate in param_env.caller_bounds() { - fresh_preds.insert(self.clean_pred(infcx, predicate)); + deduplicated_preds.insert( + infcx + .canonicalize_query_keep_static(predicate, &mut OriginalQueryValues::default()), + ); } - let mut select = SelectionContext::new(&infcx); + let mut selcx = SelectionContext::new(&infcx); let mut already_visited = FxHashSet::default(); let mut predicates = VecDeque::new(); @@ -320,7 +324,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // get rid of any inference variables. let obligation = infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred)); - let result = select.select(&obligation); + let result = selcx.select(&obligation); match result { Ok(Some(ref impl_source)) => { @@ -348,9 +352,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty, obligations, &mut user_computed_preds, - fresh_preds, + deduplicated_preds, &mut predicates, - &mut select, + &mut selcx, only_projections, ) { return None; @@ -403,7 +407,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } /// This method is designed to work around the following issue: - /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`, + /// When we compute auto trait bounds, we repeatedly call `selcx.select`, /// progressively building a `ParamEnv` based on the results we get. /// However, our usage of `SelectionContext` differs from its normal use within the compiler, /// in that we capture and re-reprocess predicates from `Unimplemented` errors. @@ -624,19 +628,22 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty: Ty<'_>, nested: impl Iterator>>, computed_preds: &mut FxHashSet>, - fresh_preds: &mut FxHashSet>, + deduplicated_preds: &mut FxHashSet>>, predicates: &mut VecDeque>, - select: &mut SelectionContext<'_, 'tcx>, + selcx: &mut SelectionContext<'_, 'tcx>, only_projections: bool, ) -> bool { let dummy_cause = ObligationCause::dummy(); for obligation in nested { let is_new_pred = - fresh_preds.insert(self.clean_pred(select.infcx(), obligation.predicate)); + deduplicated_preds.insert(selcx.infcx().canonicalize_query_keep_static( + obligation.predicate, + &mut OriginalQueryValues::default(), + )); // Resolve any inference variables that we can, to help selection succeed - let predicate = select.infcx().resolve_vars_if_possible(obligation.predicate); + let predicate = selcx.infcx().resolve_vars_if_possible(obligation.predicate); // We only add a predicate as a user-displayable bound if // it involves a generic parameter, and doesn't contain @@ -744,7 +751,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // and turn them into an explicit negative impl for our type. debug!("Projecting and unifying projection predicate {:?}", predicate); - match project::poly_project_and_unify_type(select, &obligation.with(p)) { + match project::poly_project_and_unify_type(selcx, &obligation.with(p)) { ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { debug!( "evaluate_nested_obligations: Unable to unify predicate \ @@ -767,9 +774,9 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty, v.into_iter(), computed_preds, - fresh_preds, + deduplicated_preds, predicates, - select, + selcx, only_projections, ) { return false; @@ -792,7 +799,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } ty::PredicateKind::RegionOutlives(binder) => { let binder = bound_predicate.rebind(binder); - select.infcx().region_outlives_predicate(&dummy_cause, binder) + selcx.infcx().region_outlives_predicate(&dummy_cause, binder) } ty::PredicateKind::TypeOutlives(binder) => { let binder = bound_predicate.rebind(binder); @@ -801,14 +808,14 @@ impl<'tcx> AutoTraitFinder<'tcx> { binder.map_bound_ref(|pred| pred.0).no_bound_vars(), ) { (None, Some(t_a)) => { - select.infcx().register_region_obligation_with_cause( + selcx.infcx().register_region_obligation_with_cause( t_a, - select.infcx().tcx.lifetimes.re_static, + selcx.infcx().tcx.lifetimes.re_static, &dummy_cause, ); } (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - select.infcx().register_region_obligation_with_cause( + selcx.infcx().register_region_obligation_with_cause( t_a, r_b, &dummy_cause, @@ -820,13 +827,13 @@ impl<'tcx> AutoTraitFinder<'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { let evaluate = |c: ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { - match select.infcx().const_eval_resolve( + match selcx.infcx().const_eval_resolve( obligation.param_env, unevaluated, Some(obligation.cause.span), ) { Ok(Some(valtree)) => { - Ok(ty::Const::from_value(select.tcx(), valtree, c.ty())) + Ok(ty::Const::from_value(selcx.tcx(), valtree, c.ty())) } Ok(None) => { let tcx = self.tcx; @@ -847,7 +854,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { match (evaluate(c1), evaluate(c2)) { (Ok(c1), Ok(c2)) => { - match select + match selcx .infcx() .at(&obligation.cause, obligation.param_env) .eq(c1, c2) @@ -874,14 +881,6 @@ impl<'tcx> AutoTraitFinder<'tcx> { } true } - - pub fn clean_pred( - &self, - infcx: &InferCtxt<'_, 'tcx>, - p: ty::Predicate<'tcx>, - ) -> ty::Predicate<'tcx> { - infcx.freshen(p) - } } // Replaces all ReVars in a type with ty::Region's, using the provided map 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 451427a69807d..13777fcaf2863 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -5,6 +5,11 @@ //! candidates. See the [rustc dev guide] for more details. //! //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly +use crate::traits; +use crate::traits::coherence::Conflict; +use crate::traits::query::evaluate_obligation::InferCtxtExt; +use crate::traits::{util, SelectionResult}; +use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented}; use hir::LangItem; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -15,12 +20,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; use rustc_target::spec::abi::Abi; -use crate::traits; -use crate::traits::coherence::Conflict; -use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{util, SelectionResult}; -use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented}; - use super::BuiltinImplConditions; use super::IntercrateAmbiguityCause; use super::OverflowError; @@ -41,13 +40,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // separately rather than using `stack.fresh_trait_ref` -- // this is because we want the unbound variables to be // replaced with fresh types starting from index 0. - let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate); - debug!(?cache_fresh_trait_pred); + let cache_entry = + self.canonicalize_for_cache(stack.obligation.param_env, stack.obligation.predicate); debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); - if let Some(c) = - self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) - { + if let Some(c) = self.check_candidate_cache(cache_entry) { debug!("CACHE HIT"); return c; } @@ -62,12 +59,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); debug!("CACHE MISS"); - self.insert_candidate_cache( - stack.obligation.param_env, - cache_fresh_trait_pred, - dep_node, - candidate.clone(), - ); + self.insert_candidate_cache(cache_entry, dep_node, candidate.clone()); candidate } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5e32a27cdb1da..505a5a2a71226 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -18,8 +18,10 @@ use super::{ ObligationCause, ObligationCauseCode, Overflow, PredicateObligation, Selection, SelectionError, SelectionResult, TraitObligation, TraitQueryMode, }; +use rustc_middle::infer::canonical::{Canonical, OriginalQueryValues}; -use crate::infer::{InferCtxt, InferOk, TypeFreshener}; +use crate::infer::{InferCtxt, InferOk}; +use crate::rustc_middle::ty::relate::TypeRelation; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; @@ -36,7 +38,6 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable}; @@ -96,13 +97,6 @@ impl IntercrateAmbiguityCause { pub struct SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, - /// Freshener used specifically for entries on the obligation - /// stack. This ensures that all entries on the stack at one time - /// will have the same set of placeholder entries, which is - /// important for checking for trait bounds that recursively - /// require themselves. - freshener: TypeFreshener<'cx, 'tcx>, - /// During coherence we have to assume that other crates may add /// additional impls which we currently don't know about. /// @@ -140,9 +134,9 @@ pub struct SelectionContext<'cx, 'tcx> { struct TraitObligationStack<'prev, 'tcx> { obligation: &'prev TraitObligation<'tcx>, - /// The trait predicate from `obligation` but "freshened" with the - /// selection-context's freshener. Used to check for recursion. - fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + /// The trait predicate from `obligation` but with non-`'static` + /// regions erased. Used to check for recursion. + predicate_no_lt: ty::PolyTraitPredicate<'tcx>, /// Starts out equal to `depth` -- if, during evaluation, we /// encounter a cycle, then we will set this flag to the minimum @@ -218,7 +212,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { SelectionContext { infcx, - freshener: infcx.freshener_keep_static(), intercrate: false, intercrate_ambiguity_causes: None, query_mode: TraitQueryMode::Standard, @@ -266,6 +259,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.intercrate } + #[instrument(level = "debug", skip(self), ret)] + fn canonicalize_for_cache( + &self, + param_env: ty::ParamEnv<'tcx>, + predicate: ty::PolyTraitPredicate<'tcx>, + ) -> (ty::ParamEnv<'tcx>, Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>) { + // FIXME: once canonicalization also replaces parameters, + // we probably also want to canonicalize the `param_env` here. + let predicate = self.infcx.resolve_vars_if_possible(predicate); + let predicate = self.tcx().erase_regions_keep_static(predicate); + let canonicalized_predicate = self + .infcx + .canonicalize_query_keep_static(predicate, &mut OriginalQueryValues::default()); + (param_env, canonicalized_predicate) + } + /////////////////////////////////////////////////////////////////////////// // Selection // @@ -763,24 +772,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } let stack = self.push_stack(previous_stack, &obligation); - let mut fresh_trait_pred = stack.fresh_trait_pred; - let mut param_env = obligation.param_env; + let (mut param_env, mut canonicalized_predicate) = + self.canonicalize_for_cache(obligation.param_env, stack.predicate_no_lt); - fresh_trait_pred = fresh_trait_pred.map_bound(|mut pred| { + canonicalized_predicate.value = canonicalized_predicate.value.map_bound(|mut pred| { pred.remap_constness(&mut param_env); pred }); - debug!(?fresh_trait_pred); + debug!(?canonicalized_predicate); // If a trait predicate is in the (local or global) evaluation cache, // then we know it holds without cycles. - if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { + if let Some(result) = self.check_evaluation_cache(param_env, canonicalized_predicate) { debug!("CACHE HIT"); return Ok(result); } - if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) { + if let Some(result) = stack.cache().get_provisional(canonicalized_predicate) { debug!("PROVISIONAL CACHE HIT"); stack.update_reached_depth(result.reached_depth); return Ok(result.result); @@ -805,17 +814,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let reached_depth = stack.reached_depth.get(); if reached_depth >= stack.depth { debug!("CACHE MISS"); - self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); + self.insert_evaluation_cache(param_env, canonicalized_predicate, dep_node, result); stack.cache().on_completion(stack.dfn); } else { debug!("PROVISIONAL"); debug!( "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", - fresh_trait_pred, stack.depth, reached_depth, + canonicalized_predicate, stack.depth, reached_depth, ); - stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result); + stack.cache().insert_provisional( + stack.dfn, + reached_depth, + canonicalized_predicate, + result, + ); } Ok(result) @@ -849,7 +863,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .skip(1) // Skip top-most frame. .find(|prev| { stack.obligation.param_env == prev.obligation.param_env - && stack.fresh_trait_pred == prev.fresh_trait_pred + && stack.predicate_no_lt == prev.predicate_no_lt }) .map(|stack| stack.depth) { @@ -912,7 +926,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // terms of `Fn` etc, but we could probably make this more // precise still. let unbound_input_types = - stack.fresh_trait_pred.skip_binder().trait_ref.substs.types().any(|ty| ty.is_fresh()); + stack.predicate_no_lt.skip_binder().trait_ref.substs.types().any(|ty| ty.is_ty_infer()); if stack.obligation.polarity() != ty::ImplPolarity::Negative { // This check was an imperfect workaround for a bug in the old @@ -949,17 +963,14 @@ 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, - ) + && ty::_match::Match::new(self.tcx(), prev.obligation.param_env) + .relate(stack.predicate_no_lt, prev.predicate_no_lt) + .is_ok() }) { debug!("evaluate_stack --> unbound argument, recursive --> giving up",); return Ok(EvaluatedToUnknown); } - match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig), @@ -1031,7 +1042,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // not just the lifetime choice for this particular (non-erased) // predicate. // See issue #80691 - if stack.fresh_trait_pred.has_erased_regions() { + if stack.predicate_no_lt.has_erased_regions() { + debug!(?stack.predicate_no_lt, "downgrade to modulo regions"); result = result.max(EvaluatedToOkModuloRegions); } @@ -1041,7 +1053,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_evaluation_cache( &self, param_env: ty::ParamEnv<'tcx>, - trait_pred: ty::PolyTraitPredicate<'tcx>, + trait_pred: Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>, ) -> Option { // Neither the global nor local cache is aware of intercrate // mode, so don't do any caching. In particular, we might @@ -1063,7 +1075,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn insert_evaluation_cache( &mut self, param_env: ty::ParamEnv<'tcx>, - trait_pred: ty::PolyTraitPredicate<'tcx>, + canonicalized_predicate: Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>, dep_node: DepNodeIndex, result: EvaluationResult, ) { @@ -1082,19 +1094,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if self.can_use_global_caches(param_env) { - if !trait_pred.needs_infer() { - debug!(?trait_pred, ?result, "insert_evaluation_cache global"); - // This may overwrite the cache with the same value - // FIXME: Due to #50507 this overwrites the different values - // This should be changed to use HashMapExt::insert_same - // when that is fixed - self.tcx().evaluation_cache.insert((param_env, trait_pred), dep_node, result); - return; - } + debug!(?canonicalized_predicate, ?result, "insert_evaluation_cache: global"); + self.tcx().evaluation_cache.insert( + (param_env, canonicalized_predicate), + dep_node, + result, + ); + } else { + debug!(?canonicalized_predicate, ?result, "insert_evaluation_cache: local"); + self.infcx.evaluation_cache.insert( + (param_env, canonicalized_predicate), + dep_node, + result, + ); } - - debug!(?trait_pred, ?result, "insert_evaluation_cache"); - self.infcx.evaluation_cache.insert((param_env, trait_pred), dep_node, result); } /// For various reasons, it's possible for a subobligation @@ -1289,8 +1302,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn check_candidate_cache( &mut self, - mut param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + (mut param_env, cache_canonical_pred): ( + ty::ParamEnv<'tcx>, + Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>, + ), ) -> Option>> { // Neither the global nor local cache is aware of intercrate // mode, so don't do any caching. In particular, we might @@ -1300,8 +1315,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return None; } let tcx = self.tcx(); - let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(&mut param_env); + let mut pred = cache_canonical_pred; + pred.value = pred.value.map_bound(|mut p| { + p.remap_constness(&mut param_env); + p + }); if self.can_use_global_caches(param_env) { if let Some(res) = tcx.selection_cache.get(&(param_env, pred), tcx) { @@ -1344,18 +1362,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - #[instrument(skip(self, param_env, cache_fresh_trait_pred, dep_node), level = "debug")] + #[instrument(level = "debug", skip(self, param_env, cache_canonical_pred, dep_node))] fn insert_candidate_cache( &mut self, - mut param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + (mut param_env, cache_canonical_pred): ( + ty::ParamEnv<'tcx>, + Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>, + ), dep_node: DepNodeIndex, candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, ) { let tcx = self.tcx(); - let mut pred = cache_fresh_trait_pred.skip_binder(); - pred.remap_constness(&mut param_env); + let mut pred = cache_canonical_pred; + pred.value = pred.value.map_bound(|mut p| { + p.remap_constness(&mut param_env); + p + }); if !self.can_cache_candidate(&candidate) { debug!(?pred, ?candidate, "insert_candidate_cache - candidate is not cacheable"); @@ -1794,7 +1817,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // about which one should actually apply. !needs_infer } - Some(_) => true, + Some( + ty::ImplOverlapKind::Permitted { marker: false } + | ty::ImplOverlapKind::Issue33140, + ) => true, None => false, } } else { @@ -2270,29 +2296,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Miscellany - - fn match_fresh_trait_refs( - &self, - previous: ty::PolyTraitPredicate<'tcx>, - current: ty::PolyTraitPredicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - let mut matcher = ty::_match::Match::new(self.tcx(), param_env); - matcher.relate(previous, current).is_ok() - } - fn push_stack<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &'o TraitObligation<'tcx>, ) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_pred = obligation.predicate.fold_with(&mut self.freshener); + let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate); + let predicate_no_lt = self.tcx().erase_regions_keep_static(predicate); let dfn = previous_stack.cache.next_dfn(); let depth = previous_stack.depth() + 1; TraitObligationStack { obligation, - fresh_trait_pred, + predicate_no_lt, reached_depth: Cell::new(depth), previous: previous_stack, dfn, @@ -2431,7 +2447,7 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { debug!(reached_depth, "update_reached_depth"); let mut p = self; while reached_depth < p.depth { - debug!(?p.fresh_trait_pred, "update_reached_depth: marking as cycle participant"); + debug!(?p.predicate_no_lt, "update_reached_depth: marking as cycle participant"); p.reached_depth.set(p.reached_depth.get().min(reached_depth)); p = p.previous.head.unwrap(); } @@ -2510,7 +2526,7 @@ struct ProvisionalEvaluationCache<'tcx> { /// - then we determine that `E` is in error -- we will then clear /// all cache values whose DFN is >= 4 -- in this case, that /// means the cached value for `F`. - map: RefCell, ProvisionalEvaluation>>, + map: RefCell>, ProvisionalEvaluation>>, /// The stack of args that we assume to be true because a `WF(arg)` predicate /// is on the stack above (and because of wellformedness is coinductive). @@ -2549,31 +2565,26 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// `fresh_trait_ref`. If there is a hit, then you must consider /// it an access to the stack slots at depth /// `reached_depth` (from the returned value). + #[instrument(level = "debug", skip(self), ret)] fn get_provisional( &self, - fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + canonicalized_predicate: Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>, ) -> Option { - debug!( - ?fresh_trait_pred, - "get_provisional = {:#?}", - self.map.borrow().get(&fresh_trait_pred), - ); - Some(*self.map.borrow().get(&fresh_trait_pred)?) + self.map.borrow().get(&canonicalized_predicate).copied() } /// Insert a provisional result into the cache. The result came /// from the node with the given DFN. It accessed a minimum depth /// of `reached_depth` to compute. It evaluated `fresh_trait_pred` /// and resulted in `result`. + #[instrument(level = "debug", skip(self, reached_depth))] fn insert_provisional( &self, from_dfn: usize, reached_depth: usize, - fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, + canonicalized_predicate: Canonical<'tcx, ty::PolyTraitPredicate<'tcx>>, result: EvaluationResult, ) { - debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional"); - let mut map = self.map.borrow_mut(); // Subtle: when we complete working on the DFN `from_dfn`, anything @@ -2596,7 +2607,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { } } - map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result }); + map.insert( + canonicalized_predicate, + ProvisionalEvaluation { from_dfn, reached_depth, result }, + ); } /// Invoked when the node with dfn `dfn` does not get a successful From 3a762b948f76042d30c0b2f84570d3ca4f1ac538 Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Sep 2022 20:21:23 +0200 Subject: [PATCH 2/3] remove fresh inference variables from the compiler --- .../src/const_eval/valtrees.rs | 4 - .../src/infer/canonical/canonicalizer.rs | 11 +- compiler/rustc_infer/src/infer/combine.rs | 25 +- .../src/infer/error_reporting/mod.rs | 2 +- .../infer/error_reporting/need_type_info.rs | 7 +- compiler/rustc_infer/src/infer/freshen.rs | 254 ------------------ compiler/rustc_infer/src/infer/fudge.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 31 +-- .../rustc_infer/src/infer/nll_relate/mod.rs | 10 +- compiler/rustc_infer/src/infer/resolve.rs | 18 +- compiler/rustc_middle/src/ty/consts/kind.rs | 12 +- compiler/rustc_middle/src/ty/context.rs | 26 +- compiler/rustc_middle/src/ty/diagnostics.rs | 18 +- compiler/rustc_middle/src/ty/error.rs | 3 - compiler/rustc_middle/src/ty/flags.rs | 21 +- compiler/rustc_middle/src/ty/mod.rs | 4 +- compiler/rustc_middle/src/ty/print/pretty.rs | 20 +- .../rustc_middle/src/ty/structural_impls.rs | 6 +- compiler/rustc_middle/src/ty/sty.rs | 21 +- compiler/rustc_middle/src/ty/util.rs | 4 +- compiler/rustc_symbol_mangling/src/v0.rs | 4 +- .../src/traits/error_reporting/suggestions.rs | 26 +- .../src/traits/query/dropck_outlives.rs | 4 +- .../src/traits/select/mod.rs | 10 +- .../rustc_trait_selection/src/traits/wf.rs | 16 +- compiler/rustc_type_ir/src/lib.rs | 18 -- .../rustc_typeck/src/check/method/suggest.rs | 12 +- 27 files changed, 102 insertions(+), 487 deletions(-) delete mode 100644 compiler/rustc_infer/src/infer/freshen.rs diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index a964fe8465eec..c6e84b1ca92f5 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -140,8 +140,6 @@ pub(crate) fn const_to_valtree_inner<'tcx>( ty::Never | ty::Error(_) | ty::Foreign(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) @@ -305,8 +303,6 @@ pub fn valtree_to_const_value<'tcx>( ty::Never | ty::Error(_) | ty::Foreign(..) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9488d0a6cbb68..8b82d96ade66d 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -13,7 +13,7 @@ use crate::infer::InferCtxt; use rustc_middle::ty::flags::FlagComputation; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}; +use rustc_middle::ty::{self, BoundVar, List, Ty, TyCtxt, TypeFlags}; use std::sync::atomic::Ordering; use rustc_data_structures::fx::FxHashMap; @@ -416,10 +416,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { t, ), - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("encountered a fresh type during canonicalization") - } - ty::Placeholder(placeholder) => self.canonicalize_ty_var( CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) }, t, @@ -468,7 +464,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { + ty::ConstKind::Infer(vid) => { debug!("canonical: const var found with vid {:?}", vid); match self.infcx.probe_const_var(vid) { Ok(c) => { @@ -490,9 +486,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } } } - ty::ConstKind::Infer(InferConst::Fresh(_)) => { - bug!("encountered a fresh const during canonicalization") - } ty::ConstKind::Bound(debruijn, _) => { if debruijn >= self.binder_index { bug!("escaping bound type during canonicalization") diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 9488f1f6bfc48..275e2df576d7a 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -37,7 +37,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::{Span, DUMMY_SP}; @@ -143,25 +143,16 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { let a_is_expected = relation.a_is_expected(); match (a.kind(), b.kind()) { - ( - ty::ConstKind::Infer(InferConst::Var(a_vid)), - ty::ConstKind::Infer(InferConst::Var(b_vid)), - ) => { + (ty::ConstKind::Infer(a_vid), ty::ConstKind::Infer(b_vid)) => { self.inner.borrow_mut().const_unification_table().union(a_vid, b_vid); return Ok(a); } - // All other cases of inference with other variables are errors. - (ty::ConstKind::Infer(InferConst::Var(_)), ty::ConstKind::Infer(_)) - | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(InferConst::Var(_))) => { - bug!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var)") - } - - (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { + (ty::ConstKind::Infer(vid), _) => { return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected); } - (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { + (_, ty::ConstKind::Infer(vid)) => { return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected); } (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { @@ -712,7 +703,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { + ty::ConstKind::Infer(vid) => { let mut inner = self.infcx.inner.borrow_mut(); let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); @@ -729,7 +720,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { origin: var_value.origin, val: ConstVariableValue::Unknown { universe: self.for_universe }, }); - Ok(self.tcx().mk_const_var(new_var_id, c.ty())) + Ok(self.tcx().mk_const_infer(new_var_id, c.ty())) } } } @@ -909,7 +900,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { debug_assert_eq!(c, _c); match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { + ty::ConstKind::Infer(vid) => { // Check if the current unification would end up // unifying `target_vid` with a const which contains // an inference variable which is unioned with `target_vid`. @@ -942,7 +933,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { }, }, ); - Ok(self.tcx().mk_const_var(new_var_id, c.ty())) + Ok(self.tcx().mk_const_infer(new_var_id, c.ty())) } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 82099d9e3f345..d02f2cf9548ff 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -574,7 +574,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { match *cause.code() { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { let ty = self.resolve_vars_if_possible(root_ty); - if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_))) + if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_))) { // don't show type `_` if span.desugaring_kind() == Some(DesugaringKind::ForLoop) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index baa97d72a4baa..de1a20e567fd8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -16,7 +16,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; -use rustc_middle::ty::{self, DefIdTree, InferConst}; +use rustc_middle::ty::{self, DefIdTree}; use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults}; use rustc_span::symbol::{kw, Ident}; @@ -269,7 +269,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } GenericArgKind::Const(ct) => { - if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() { + if let ty::ConstKind::Infer(vid) = ct.kind() { let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = @@ -821,9 +821,8 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => { - use ty::InferConst::*; match (inner_ct.kind(), target_ct.kind()) { - (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => self + (ty::ConstKind::Infer(a_vid), ty::ConstKind::Infer(b_vid)) => self .infcx .inner .borrow_mut() diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs deleted file mode 100644 index fee15afc7b3aa..0000000000000 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ /dev/null @@ -1,254 +0,0 @@ -//! Freshening is the process of replacing unknown variables with fresh types. The idea is that -//! the type, after freshening, contains no inference variables but instead contains either a -//! value for each variable or fresh "arbitrary" types wherever a variable would have been. -//! -//! Freshening is used primarily to get a good type for inserting into a cache. The result -//! summarizes what the type inferencer knows "so far". The primary place it is used right now is -//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type -//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in -//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending -//! on what type that type variable is ultimately assigned, the match may or may not succeed. -//! -//! To handle closures, freshened types also have to contain the signature and kind of any -//! closure in the local inference context, as otherwise the cache key might be invalidated. -//! The way this is done is somewhat hacky - the closure signature is appended to the substs, -//! as well as the closure kind "encoded" as a type. Also, special handling is needed when -//! the closure signature contains a reference to the original closure. -//! -//! Note that you should be careful not to allow the output of freshening to leak to the user in -//! error messages or in any other form. Freshening is only really useful as an internal detail. -//! -//! Because of the manipulation required to handle closures, doing arbitrary operations on -//! freshened types is not recommended. However, in addition to doing equality/hash -//! comparisons (for caching), it is possible to do a `ty::_match` operation between -//! 2 freshened types - this works even with the closure encoding. -//! -//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with -//! 'erased. The reason behind this is that, in general, we do not take region relationships into -//! account when making type-overloaded decisions. This is important because of the design of the -//! region inferencer, which is not based on unification but rather on accumulating and then -//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type -//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type -//! inferencer knows "so far". -use super::InferCtxt; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::infer::unify_key::ToType; -use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable}; -use std::collections::hash_map::Entry; - -pub struct TypeFreshener<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - ty_freshen_count: u32, - const_freshen_count: u32, - ty_freshen_map: FxHashMap>, - const_freshen_map: FxHashMap, ty::Const<'tcx>>, - keep_static: bool, -} - -impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>, keep_static: bool) -> TypeFreshener<'a, 'tcx> { - TypeFreshener { - infcx, - ty_freshen_count: 0, - const_freshen_count: 0, - ty_freshen_map: Default::default(), - const_freshen_map: Default::default(), - keep_static, - } - } - - fn freshen_ty( - &mut self, - opt_ty: Option>, - key: ty::InferTy, - freshener: F, - ) -> Ty<'tcx> - where - F: FnOnce(u32) -> ty::InferTy, - { - if let Some(ty) = opt_ty { - return ty.fold_with(self); - } - - match self.ty_freshen_map.entry(key) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let index = self.ty_freshen_count; - self.ty_freshen_count += 1; - let t = self.infcx.tcx.mk_ty_infer(freshener(index)); - entry.insert(t); - t - } - } - } - - fn freshen_const( - &mut self, - opt_ct: Option>, - key: ty::InferConst<'tcx>, - freshener: F, - ty: Ty<'tcx>, - ) -> ty::Const<'tcx> - where - F: FnOnce(u32) -> ty::InferConst<'tcx>, - { - if let Some(ct) = opt_ct { - return ct.fold_with(self); - } - - match self.const_freshen_map.entry(key) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let index = self.const_freshen_count; - self.const_freshen_count += 1; - let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty); - entry.insert(ct); - ct - } - } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(..) => { - // leave bound regions alone - r - } - - ty::ReEarlyBound(..) - | ty::ReFree(_) - | ty::ReVar(_) - | ty::RePlaceholder(..) - | ty::ReErased => { - // replace all free regions with 'erased - self.tcx().lifetimes.re_erased - } - ty::ReStatic => { - if self.keep_static { - r - } else { - self.tcx().lifetimes.re_erased - } - } - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !t.has_erasable_regions() { - return t; - } - - let tcx = self.infcx.tcx; - - match *t.kind() { - ty::Infer(ty::TyVar(v)) => { - let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); - self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy) - } - - ty::Infer(ty::IntVar(v)) => self.freshen_ty( - self.infcx - .inner - .borrow_mut() - .int_unification_table() - .probe_value(v) - .map(|v| v.to_type(tcx)), - ty::IntVar(v), - ty::FreshIntTy, - ), - - ty::Infer(ty::FloatVar(v)) => self.freshen_ty( - self.infcx - .inner - .borrow_mut() - .float_unification_table() - .probe_value(v) - .map(|v| v.to_type(tcx)), - ty::FloatVar(v), - ty::FreshFloatTy, - ), - - ty::Infer(ty::FreshTy(ct) | ty::FreshIntTy(ct) | ty::FreshFloatTy(ct)) => { - if ct >= self.ty_freshen_count { - bug!( - "Encountered a freshend type with id {} \ - but our counter is only at {}", - ct, - self.ty_freshen_count - ); - } - t - } - - ty::Generator(..) - | ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Adt(..) - | ty::Str - | ty::Error(_) - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Never - | ty::Tuple(..) - | ty::Projection(..) - | ty::Foreign(..) - | ty::Param(..) - | ty::Closure(..) - | ty::GeneratorWitness(..) - | ty::Opaque(..) => t.super_fold_with(self), - - ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t), - } - } - - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match ct.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(v)) => { - let opt_ct = self - .infcx - .inner - .borrow_mut() - .const_unification_table() - .probe_value(v) - .val - .known(); - self.freshen_const(opt_ct, ty::InferConst::Var(v), ty::InferConst::Fresh, ct.ty()) - } - ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { - if i >= self.const_freshen_count { - bug!( - "Encountered a freshend const with id {} \ - but our counter is only at {}", - i, - self.const_freshen_count, - ); - } - ct - } - - ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - bug!("unexpected const {:?}", ct) - } - - ty::ConstKind::Param(_) - | ty::ConstKind::Value(_) - | ty::ConstKind::Unevaluated(..) - | ty::ConstKind::Error(_) => ct.super_fold_with(self), - } - } -} diff --git a/compiler/rustc_infer/src/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs index 2f0eadce631e2..edbbd81ba02bd 100644 --- a/compiler/rustc_infer/src/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -229,7 +229,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + if let ty::ConstKind::Infer(vid) = ct.kind() { if self.const_vars.0.contains(&vid) { // This variable was created during the fudging. // Recreate it with a fresh variable here. diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 55cf9b7a2ea18..60fb3e9cd7c56 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,4 +1,3 @@ -pub use self::freshen::TypeFreshener; pub use self::lexical_region_resolve::RegionResolutionError; pub use self::LateBoundRegionConversionTime::*; pub use self::RegionVariableOrigin::*; @@ -30,7 +29,7 @@ use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; use rustc_middle::ty::visit::TypeVisitable; pub use rustc_middle::ty::IntVarValue; -use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -54,7 +53,6 @@ mod combine; mod equate; pub mod error_reporting; pub mod free_regions; -mod freshen; mod fudge; mod glb; mod higher_ranked; @@ -730,10 +728,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.in_snapshot.get() } - pub fn freshen>(&self, t: T) -> T { - t.fold_with(&mut self.freshener()) - } - /// Returns the origin of the type variable identified by `vid`, or `None` /// if this is not a type variable. /// @@ -747,15 +741,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } - pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { - freshen::TypeFreshener::new(self, false) - } - - /// Like `freshener`, but does not replace `'static` regions. - pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { - freshen::TypeFreshener::new(self, true) - } - pub fn unsolved_variables(&self) -> Vec> { let mut inner = self.inner.borrow_mut(); let mut vars: Vec> = inner @@ -1112,7 +1097,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> { - self.tcx.mk_const_var(self.next_const_var_id(origin), ty) + self.tcx.mk_const_infer(self.next_const_var_id(origin), ty) } pub fn next_const_var_in_universe( @@ -1126,7 +1111,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .borrow_mut() .const_unification_table() .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); - self.tcx.mk_const_var(vid, ty) + self.tcx.mk_const_infer(vid, ty) } pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { @@ -1242,7 +1227,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, }); - self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into() + self.tcx.mk_const_infer(const_var_id, self.tcx.type_of(param.def_id)).into() } } } @@ -1857,7 +1842,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> { /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). fn maybe_from_const(ct: ty::Const<'tcx>) -> Option { match ct.kind() { - ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), + ty::ConstKind::Infer(v) => Some(TyOrConstInferVar::Const(v)), _ => None, } } @@ -1876,8 +1861,8 @@ impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { match ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FreshIntTy(_)) => self.tcx.types.i32, - ty::Infer(ty::FloatVar(_) | ty::FreshFloatTy(_)) => self.tcx.types.f64, + ty::Infer(ty::IntVar(_)) => self.tcx.types.i32, + ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64, _ => ty.super_fold_with(self), } } @@ -1935,7 +1920,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() { + if let ty::ConstKind::Infer(vid) = ct.kind() { self.infcx .inner .borrow_mut() diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index bb6f6ae60e26a..7e544fc916b5f 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -29,7 +29,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; use std::fmt::Debug; use std::ops::ControlFlow; @@ -668,7 +668,7 @@ where } match b.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + ty::ConstKind::Infer(_) if D::forbid_inference_vars() => { // Forbid inference variables in the RHS. self.infcx.tcx.sess.delay_span_bug( self.delegate.span(), @@ -1047,10 +1047,10 @@ where _: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { match a.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + ty::ConstKind::Infer(_) if D::forbid_inference_vars() => { bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); } - ty::ConstKind::Infer(InferConst::Var(vid)) => { + ty::ConstKind::Infer(vid) => { let mut inner = self.infcx.inner.borrow_mut(); let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); @@ -1061,7 +1061,7 @@ where origin: var_value.origin, val: ConstVariableValue::Unknown { universe: self.universe }, }); - Ok(self.tcx().mk_const_var(new_var_id, a.ty())) + Ok(self.tcx().mk_const_infer(new_var_id, a.ty())) } } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 3d99f0958f7f9..c72570fad1ffb 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -3,7 +3,7 @@ use super::{FixupError, FixupResult, InferCtxt, Span}; use rustc_middle::mir; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; -use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable}; +use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable, TypeVisitable}; use std::ops::ControlFlow; @@ -193,12 +193,11 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { } else { let t = self.infcx.shallow_resolve(t); match *t.kind() { - ty::Infer(ty::TyVar(vid)) => Err(FixupError::UnresolvedTy(vid)), - ty::Infer(ty::IntVar(vid)) => Err(FixupError::UnresolvedIntTy(vid)), - ty::Infer(ty::FloatVar(vid)) => Err(FixupError::UnresolvedFloatTy(vid)), - ty::Infer(_) => { - bug!("Unexpected type in full type resolver: {:?}", t); - } + ty::Infer(infer_ty) => match infer_ty { + ty::TyVar(vid) => Err(FixupError::UnresolvedTy(vid)), + ty::IntVar(vid) => Err(FixupError::UnresolvedIntTy(vid)), + ty::FloatVar(vid) => Err(FixupError::UnresolvedFloatTy(vid)), + }, _ => t.try_super_fold_with(self), } } @@ -223,12 +222,9 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { } else { let c = self.infcx.shallow_resolve(c); match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { + ty::ConstKind::Infer(vid) => { return Err(FixupError::UnresolvedConst(vid)); } - ty::ConstKind::Infer(InferConst::Fresh(_)) => { - bug!("Unexpected const in full const resolver: {:?}", c); - } _ => {} } c.try_super_fold_with(self) diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index c444ec23563ce..84a41db2287fb 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -51,7 +51,7 @@ pub enum ConstKind<'tcx> { Param(ty::ParamConst), /// Infer the value of the const. - Infer(InferConst<'tcx>), + Infer(ty::ConstVid<'tcx>), /// Bound const variable, used only when preparing a trait query. Bound(ty::DebruijnIndex, ty::BoundVar), @@ -106,16 +106,6 @@ impl<'tcx> ConstKind<'tcx> { } } -/// An inference variable for a const, for use in const generics. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] -#[derive(HashStable)] -pub enum InferConst<'tcx> { - /// Infer the value of the const. - Var(ty::ConstVid<'tcx>), - /// A fresh const variable. See `infer::freshen` for more details. - Fresh(u32), -} - enum EvalMode { Typeck, Mir, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 2b5b4017a5a11..276e1665186ee 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -18,10 +18,9 @@ use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, - FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, - ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, - RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, - Visibility, + FloatVar, FloatVid, GenericParamDefKind, InferTy, IntTy, IntVar, IntVid, List, ParamConst, + ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, RegionKind, + ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility, }; use crate::ty::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef, UserSubsts}; use rustc_ast as ast; @@ -972,7 +971,15 @@ impl<'tcx> CommonTypes<'tcx> { str_: mk(Str), self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })), - trait_object_dummy_self: mk(Infer(ty::FreshTy(0))), + // Using a placeholder type feels weird here, but placeholders cannot + // be directly created by astconv so it mostly works out ok. + // + // This is definitely not ideal and we should switch this to a more + // sensible type. + trait_object_dummy_self: mk(Placeholder(ty::PlaceholderType { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundVar::from_usize(0), + })), } } } @@ -2584,8 +2591,8 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(InferConst::Var(v)), ty }) + pub fn mk_const_infer(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(v), ty }) } #[inline] @@ -2603,11 +2610,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(Infer(it)) } - #[inline] - pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> { - self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(ic), ty }) - } - #[inline] pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> { self.mk_ty(Param(ParamTy { index, name })) diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 855917fb82869..ed00e0ac7c4db 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use crate::ty::{ - visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferConst, InferTy, + visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, }; @@ -31,12 +31,7 @@ impl<'tcx> Ty<'tcx> { | Int(_) | Uint(_) | Float(_) - | Infer( - InferTy::IntVar(_) - | InferTy::FloatVar(_) - | InferTy::FreshIntTy(_) - | InferTy::FreshFloatTy(_) - ) + | Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) ) } @@ -50,12 +45,7 @@ impl<'tcx> Ty<'tcx> { | Int(_) | Uint(_) | Float(_) - | Infer( - InferTy::IntVar(_) - | InferTy::FloatVar(_) - | InferTy::FreshIntTy(_) - | InferTy::FreshFloatTy(_), - ) => true, + | Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => true, Ref(_, x, _) | Array(x, _) | Slice(x) => x.peel_refs().is_simple_ty(), Tuple(tys) if tys.is_empty() => true, _ => false, @@ -497,7 +487,7 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow { match c.kind() { - ConstKind::Infer(InferConst::Var(_)) if self.infer_suggestable => {} + ConstKind::Infer(_) if self.infer_suggestable => {} ConstKind::Infer(..) | ConstKind::Bound(..) diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 01e1e97b21a0b..4c5095ebe5755 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -322,9 +322,6 @@ impl<'tcx> Ty<'tcx> { ty::Infer(ty::FloatVar(_)) => "floating-point number".into(), ty::Placeholder(..) => "placeholder type".into(), ty::Bound(..) => "bound type".into(), - ty::Infer(ty::FreshTy(_)) => "fresh type".into(), - ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(), - ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(), ty::Projection(_) => "associated type".into(), ty::Param(p) => format!("type parameter `{}`", p).into(), ty::Opaque(..) => "opaque type".into(), diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index a6d0678e99d6d..78dd1a5d4af69 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -1,5 +1,5 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, InferConst, Ty, TypeFlags}; +use crate::ty::{self, Ty, TypeFlags}; use std::slice; #[derive(Debug)] @@ -144,17 +144,9 @@ impl FlagComputation { self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - &ty::Infer(infer) => { + &ty::Infer(_) => { + self.add_flags(TypeFlags::HAS_TY_INFER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - match infer { - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { - self.add_flags(TypeFlags::HAS_TY_FRESH) - } - - ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => { - self.add_flags(TypeFlags::HAS_TY_INFER) - } - } } &ty::Adt(_, substs) => { @@ -290,12 +282,9 @@ impl FlagComputation { self.add_ty(c.ty()); match c.kind() { ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated), - ty::ConstKind::Infer(infer) => { + ty::ConstKind::Infer(_) => { + self.add_flags(TypeFlags::HAS_CT_INFER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); - match infer { - InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), - InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER), - } } ty::ConstKind::Bound(debruijn, _) => { self.add_bound_var(debruijn); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 63dd213a0854f..536e4bd2441df 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -72,9 +72,7 @@ pub use self::closure::{ RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath, CAPTURE_STRUCT_LOCAL, }; -pub use self::consts::{ - Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, UnevaluatedConst, ValTree, -}; +pub use self::consts::{Const, ConstInt, ConstKind, ConstS, ScalarInt, UnevaluatedConst, ValTree}; pub use self::context::{ tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b76e899980800..686f8d07a1a57 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1079,9 +1079,8 @@ pub trait PrettyPrinter<'tcx>: // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`, // in order to place the projections inside the `<...>`. if !resugared { - // Use a type that can't appear in defaults of type parameters. - let dummy_cx = cx.tcx().mk_ty_infer(ty::FreshTy(0)); - let principal = principal.with_self_ty(cx.tcx(), dummy_cx); + let principal = + principal.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); let args = cx .tcx() @@ -1220,12 +1219,11 @@ pub trait PrettyPrinter<'tcx>: } } } - ty::ConstKind::Infer(infer_ct) => { - match infer_ct { - ty::InferConst::Var(ct_vid) - if let Some(name) = self.const_infer_name(ct_vid) => - p!(write("{}", name)), - _ => print_underscore!(), + ty::ConstKind::Infer(ct_vid) => { + if let Some(name) = self.const_infer_name(ct_vid) { + p!(write("{}", name)) + } else { + print_underscore!() } } ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), @@ -2505,9 +2503,7 @@ define_print_and_forward_display! { } ty::ExistentialTraitRef<'tcx> { - // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx().mk_ty_infer(ty::FreshTy(0)); - let trait_ref = self.with_self_ty(cx.tcx(), dummy_self); + let trait_ref = self.with_self_ty(cx.tcx(), cx.tcx().types.trait_object_dummy_self); p!(print(trait_ref.print_only_trait_path())) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 3b42f4b51fc49..ebd48e437acbd 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,7 @@ use crate::mir::{Field, ProjectionKind}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{self, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; use rustc_hir::def::Namespace; use rustc_index::vec::{Idx, IndexVec}; @@ -817,13 +817,13 @@ impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::ConstVid<'tcx> { fn try_fold_with>(self, _folder: &mut F) -> Result { Ok(self) } } -impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> { +impl<'tcx> TypeVisitable<'tcx> for ty::ConstVid<'tcx> { fn visit_with>(&self, _visitor: &mut V) -> ControlFlow { ControlFlow::CONTINUE } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e773b3032aab8..03983e6198263 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1818,16 +1818,6 @@ impl<'tcx> Ty<'tcx> { matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_)) } - #[inline] - pub fn is_fresh_ty(self) -> bool { - matches!(self.kind(), Infer(FreshTy(_))) - } - - #[inline] - pub fn is_fresh(self) -> bool { - matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_))) - } - #[inline] pub fn is_char(self) -> bool { matches!(self.kind(), Char) @@ -2017,9 +2007,7 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8, - ty::Bound(..) - | ty::Placeholder(_) - | ty::Infer(FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Bound(..) | ty::Placeholder(_) => { bug!("`discriminant_ty` applied to unexpected type: {:?}", self) } } @@ -2072,8 +2060,7 @@ impl<'tcx> Ty<'tcx> { ty::Infer(ty::TyVar(_)) | ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + | ty::Placeholder(..) => { bug!("`ptr_metadata_ty` applied to unexpected type: {:?} (tail = {:?})", self, tail) } } @@ -2149,9 +2136,7 @@ impl<'tcx> Ty<'tcx> { ty::Infer(ty::TyVar(_)) => false, - ty::Bound(..) - | ty::Placeholder(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Bound(..) | ty::Placeholder(..) => { bug!("`is_trivially_sized` applied to unexpected type: {:?}", self) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index d93aab04e9921..a396c4c9706a3 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1133,9 +1133,7 @@ pub fn needs_drop_components<'tcx>( target_layout: &TargetDataLayout, ) -> Result; 2]>, AlwaysRequiresDrop> { match ty.kind() { - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 18e7e74741af8..492b950a12224 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -539,8 +539,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { match predicate.as_ref().skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => { // Use a type that can't appear in defaults of type parameters. - let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); - let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self); + let trait_ref = + trait_ref.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self); cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?; } ty::ExistentialPredicate::Projection(projection) => { 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 d90b77fc55682..6d89c6d997c5f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1403,22 +1403,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { |(last_ty, mut same, only_never_return): (std::option::Option>, bool, bool), (_, ty)| { let ty = self.resolve_vars_if_possible(ty); - same &= - !matches!(ty.kind(), ty::Error(_)) - && last_ty.map_or(true, |last_ty| { - // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes - // *after* in the dependency graph. - match (ty.kind(), last_ty.kind()) { - (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) - | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) - | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) - | ( - Infer(InferTy::FreshFloatTy(_)), - Infer(InferTy::FreshFloatTy(_)), - ) => true, - _ => ty == last_ty, - } - }); + same &= !matches!(ty.kind(), ty::Error(_)) + && last_ty.map_or(true, |last_ty| { + // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes + // *after* in the dependency graph. + match (ty.kind(), last_ty.kind()) { + (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) + | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) => true, + _ => ty == last_ty, + } + }); (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never)) }, ); 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 aad3c37f84e5a..aa6c1bbc6fda7 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -20,9 +20,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // None of these types have a destructor and hence they do not // require anything in particular to outlive the dtor's // execution. - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool + ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 505a5a2a71226..d149e990e6285 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1904,9 +1904,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, ty::Infer(ty::TyVar(_)) => Ambiguous, - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Placeholder(..) | ty::Bound(..) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } } @@ -2013,9 +2011,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ambiguous } - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + ty::Placeholder(..) | ty::Bound(..) => { bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); } } @@ -2055,7 +2051,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(..) | ty::Projection(..) | ty::Bound(..) - | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + | ty::Infer(ty::TyVar(_)) => { bug!("asked to assemble constituent types of unexpected type: {:?}", t); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9722b48a68ab6..ca1755743f9e9 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -820,17 +820,16 @@ pub fn object_region_bounds<'tcx>( // 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 = tcx.mk_ty_infer(ty::FreshTy(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, predicates) } /// Given a set of predicates that apply to an object type, returns @@ -850,13 +849,10 @@ pub fn object_region_bounds<'tcx>( /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. #[instrument(skip(tcx, predicates), level = "debug", ret)] -pub(crate) fn required_region_bounds<'tcx>( +fn required_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, - erased_self_ty: Ty<'tcx>, predicates: impl Iterator>, ) -> Vec> { - assert!(!erased_self_ty.has_escaping_bound_vars()); - traits::elaborate_predicates(tcx, predicates) .filter_map(|obligation| { debug!(?obligation); @@ -872,7 +868,7 @@ pub(crate) fn required_region_bounds<'tcx>( | ty::PredicateKind::ConstEvaluatable(..) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::TypeWellFormedFromEnv(..) => None, - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t, r)) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> // erased_self_ty : 'a` (we interpret a @@ -882,8 +878,8 @@ pub(crate) fn required_region_bounds<'tcx>( // it's kind of a moot point since you could never // construct such an object, but this seems // correct even if that code changes). - if t == &erased_self_ty && !r.has_escaping_bound_vars() { - Some(*r) + if t == tcx.types.trait_object_dummy_self && !r.has_escaping_bound_vars() { + Some(r) } else { None } diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index da30344ef7ec0..e6e3d382ca037 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -537,17 +537,6 @@ pub enum InferTy { /// We don't know until it's used what type it's supposed to be, so /// we create a fresh type variable. FloatVar(FloatVid), - - /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement - /// for an unbound type variable. This is convenient for caching etc. See - /// `rustc_infer::infer::freshen` for more details. - /// - /// Compare with [`TyVar`][Self::TyVar]. - FreshTy(u32), - /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar]. - FreshIntTy(u32), - /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar]. - FreshFloatTy(u32), } /// Raw `TyVid` are used as the unification key for `sub_relations`; @@ -678,7 +667,6 @@ impl HashStable for InferTy { TyVar(v) => v.as_u32().hash_stable(ctx, hasher), IntVar(v) => v.index.hash_stable(ctx, hasher), FloatVar(v) => v.index.hash_stable(ctx, hasher), - FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher), } } } @@ -717,9 +705,6 @@ impl fmt::Debug for InferTy { TyVar(ref v) => v.fmt(f), IntVar(ref v) => v.fmt(f), FloatVar(ref v) => v.fmt(f), - FreshTy(v) => write!(f, "FreshTy({:?})", v), - FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v), - FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v), } } } @@ -742,9 +727,6 @@ impl fmt::Display for InferTy { TyVar(_) => write!(f, "_"), IntVar(_) => write!(f, "{}", "{integer}"), FloatVar(_) => write!(f, "{}", "{float}"), - FreshTy(v) => write!(f, "FreshTy({})", v), - FreshIntTy(v) => write!(f, "FreshIntTy({})", v), - FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v), } } } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 2d459b2cc0e32..a6fc4a1419af2 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -262,11 +262,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if actual.is_enum() { "variant or associated item" } else { - match (item_name.as_str().chars().next(), actual.is_fresh_ty()) { - (Some(name), false) if name.is_lowercase() => "function or associated item", - (Some(_), false) => "associated item", - (Some(_), true) | (None, false) => "variant or associated item", - (None, true) => "variant", + match item_name.as_str().chars().next() { + Some(name) if name.is_lowercase() => "function or associated item", + Some(_) => "associated item", + None => "variant or associated item", } }; @@ -991,8 +990,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(span, &msg); } - if actual.is_numeric() && actual.is_fresh() || restrict_type_params { - } else { + if !restrict_type_params { self.suggest_traits_to_import( &mut err, span, From ccb9f3b70f2b07e701d7216702a46165dedc2b4f Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 23 Sep 2022 20:26:07 +0200 Subject: [PATCH 3/3] update 33140 test --- ...ssue-33140-traitobject-crate-non-static.rs | 11 ++++++++++ ...-33140-traitobject-crate-non-static.stderr | 22 +++++++++++++++++++ .../object/issue-33140-traitobject-crate.rs | 6 ++--- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.rs create mode 100644 src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.stderr diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.rs b/src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.rs new file mode 100644 index 0000000000000..0cf37901486ec --- /dev/null +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.rs @@ -0,0 +1,11 @@ +#![allow(order_dependent_trait_objects)] +trait Trait {} + +impl Trait for dyn Send + Sync {} +impl Trait for dyn Sync + Send {} +fn assert_trait() {} + +fn main() { + assert_trait::(); + //~^ ERROR type annotations needed: cannot satisfy `dyn Send + Sync: Trait` +} diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.stderr b/src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.stderr new file mode 100644 index 0000000000000..28c5191378502 --- /dev/null +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate-non-static.stderr @@ -0,0 +1,22 @@ +error[E0283]: type annotations needed: cannot satisfy `dyn Send + Sync: Trait` + --> $DIR/issue-33140-traitobject-crate-non-static.rs:9:5 + | +LL | assert_trait::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: multiple `impl`s satisfying `dyn Send + Sync: Trait` found + --> $DIR/issue-33140-traitobject-crate-non-static.rs:4:1 + | +LL | impl Trait for dyn Send + Sync {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Trait for dyn Sync + Send {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `assert_trait` + --> $DIR/issue-33140-traitobject-crate-non-static.rs:6:20 + | +LL | fn assert_trait() {} + | ^^^^^ required by this bound in `assert_trait` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/traits/object/issue-33140-traitobject-crate.rs b/src/test/ui/traits/object/issue-33140-traitobject-crate.rs index 8abd92da362d3..5e94dd1026b5e 100644 --- a/src/test/ui/traits/object/issue-33140-traitobject-crate.rs +++ b/src/test/ui/traits/object/issue-33140-traitobject-crate.rs @@ -102,7 +102,7 @@ unsafe impl Trait for dyn (::std::string::ToString) + Send + Sync { } fn assert_trait() {} fn main() { - assert_trait::(); - assert_trait::(); - assert_trait::(); + assert_trait::(); + assert_trait::(); + assert_trait::(); }