From 2e6bf0923b113b754c9bda72b78eac354bec61f7 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Thu, 2 Jul 2020 23:56:17 +0200 Subject: [PATCH] const_eval_resolve --- src/librustc_codegen_ssa/mir/constant.rs | 2 +- src/librustc_infer/infer/mod.rs | 4 +- src/librustc_middle/mir/interpret/queries.rs | 4 +- src/librustc_middle/query/mod.rs | 9 ++++ src/librustc_middle/ty/instance.rs | 11 ++++ src/librustc_middle/ty/mod.rs | 4 +- src/librustc_middle/ty/print/pretty.rs | 4 +- src/librustc_middle/ty/query/keys.rs | 11 ++++ src/librustc_middle/ty/sty.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 2 +- .../traits/fulfill.rs | 2 +- .../traits/select/mod.rs | 2 +- src/librustc_trait_selection/traits/wf.rs | 6 +-- src/librustc_ty/instance.rs | 52 +++++++++++++++---- src/librustc_typeck/check/wfcheck.rs | 7 ++- src/tools/clippy/clippy_lints/src/consts.rs | 2 +- 16 files changed, 96 insertions(+), 28 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 007be7a62ae..4943e279c7e 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -28,7 +28,7 @@ pub fn eval_mir_constant( ty::ConstKind::Unevaluated(def, substs, promoted) => self .cx .tcx() - .const_eval_resolve(ty::ParamEnv::reveal_all(), def.did, substs, promoted, None) + .const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None) .map_err(|err| { if promoted.is_none() { self.cx diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 27da514a17f..85c568cbd65 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -1536,7 +1536,7 @@ pub fn create_next_universe(&self) -> ty::UniverseIndex { pub fn const_eval_resolve( &self, param_env: ty::ParamEnv<'tcx>, - def_id: DefId, + def: ty::WithOptParam, substs: SubstsRef<'tcx>, promoted: Option, span: Option, @@ -1547,7 +1547,7 @@ pub fn const_eval_resolve( let (param_env, substs) = canonical.value; // The return value is the evaluated value which doesn't contain any reference to inference // variables, thus we don't need to substitute back the original values. - self.tcx.const_eval_resolve(param_env, def_id, substs, promoted, span) + self.tcx.const_eval_resolve(param_env, def, substs, promoted, span) } /// If `typ` is a type variable of some kind, resolve it one level diff --git a/src/librustc_middle/mir/interpret/queries.rs b/src/librustc_middle/mir/interpret/queries.rs index a7953f0f900..bbaead535f6 100644 --- a/src/librustc_middle/mir/interpret/queries.rs +++ b/src/librustc_middle/mir/interpret/queries.rs @@ -34,12 +34,12 @@ pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { pub fn const_eval_resolve( self, param_env: ty::ParamEnv<'tcx>, - def_id: DefId, + def: ty::WithOptParam, substs: SubstsRef<'tcx>, promoted: Option, span: Option, ) -> ConstEvalResult<'tcx> { - match ty::Instance::resolve(self, param_env, def_id, substs) { + match ty::Instance::resolve_const_arg(self, param_env, def, substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted }; self.const_eval_global_id(param_env, cid, span) diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index d53b8d33262..50625af0adf 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1463,5 +1463,14 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { ) -> Result>, ErrorReported> { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } } + + query resolve_instance_of_const_arg( + key: ty::ParamEnvAnd<'tcx, (ty::WithOptParam, SubstsRef<'tcx>)> + ) -> Result>, ErrorReported> { + desc { + "resolving instance of the potential const argument `{}`", + ty::Instance::new(key.value.0.did, key.value.1), + } + } } } diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index d628d6783d5..fef1f9a51e6 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -336,6 +336,17 @@ pub fn resolve( tcx.resolve_instance(tcx.erase_regions(¶m_env.and((def_id, substs)))) } + // This should be kept up to date with `resolve`. + pub fn resolve_const_arg( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + def: ty::WithOptParam, + substs: SubstsRef<'tcx>, + ) -> Result>, ErrorReported> { + let substs = tcx.erase_regions(&substs); + tcx.resolve_instance_of_const_arg(tcx.erase_regions(¶m_env.and((def, substs)))) + } + pub fn resolve_for_fn_ptr( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 539dfa6e892..bc55c1b2fe8 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1100,7 +1100,7 @@ pub enum PredicateKind<'tcx> { Subtype(PolySubtypePredicate<'tcx>), /// Constant initializer must evaluate successfully. - ConstEvaluatable(DefId, SubstsRef<'tcx>), + ConstEvaluatable(ty::WithOptParam, SubstsRef<'tcx>), /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), @@ -1571,7 +1571,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas pub type PlaceholderConst = Placeholder; -#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, Debug, TypeFoldable, Lift, RustcEncodable, RustcDecodable)] #[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(Hash, HashStable)] pub struct WithOptParam { diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 1cba593879a..b50d2852c1c 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2027,9 +2027,9 @@ pub fn print_only_trait_path(self) -> ty::Binder { + &ty::PredicateKind::ConstEvaluatable(def, substs) => { p!(write("the constant `"), - print_value_path(def_id, substs), + print_value_path(def.did, substs), write("` can be evaluated")) } ty::PredicateKind::ConstEquate(c1, c2) => { diff --git a/src/librustc_middle/ty/query/keys.rs b/src/librustc_middle/ty/query/keys.rs index 4acf766f033..5fc99173761 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/src/librustc_middle/ty/query/keys.rs @@ -171,6 +171,17 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span { } } +impl<'tcx> Key for (ty::WithOptParam, SubstsRef<'tcx>) { + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + self.0.did.default_span(tcx) + } +} + impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { type CacheSelector = DefaultCacheSelector; diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 1e7171ea06c..3d16a9f92c9 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2373,7 +2373,7 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> let (param_env, substs) = param_env_and_substs.into_parts(); // try to resolve e.g. associated constants to their definition on an impl, and then // evaluate the const. - match tcx.const_eval_resolve(param_env, def.did, substs, promoted, None) { + match tcx.const_eval_resolve(param_env, def, substs, promoted, None) { // NOTE(eddyb) `val` contains no lifetimes/types/consts, // and we use the original type, so nothing from `substs` // (which may be identity substs, see above), diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 7a649649a42..a927df02cdc 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -623,7 +623,7 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) match substituted_constant.val { ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output), ty::ConstKind::Unevaluated(def, substs, promoted) => { - match self.tcx.const_eval_resolve(param_env, def.did, substs, promoted, None) { + match self.tcx.const_eval_resolve(param_env, def, substs, promoted, None) { Ok(val) => collect_const_value(self.tcx, val, self.output), Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {} Err(ErrorHandled::TooGeneric) => span_bug!( diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 702dcc2f9e1..c6c76028f85 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -527,7 +527,7 @@ fn process_obligation( if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { match self.selcx.infcx().const_eval_resolve( obligation.param_env, - def.did, + def, substs, promoted, Some(obligation.cause.span), diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 77c50973b91..5dc5fb797ff 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -511,7 +511,7 @@ fn evaluate_predicate_recursively<'o>( self.infcx .const_eval_resolve( obligation.param_env, - def.did, + def, substs, promoted, Some(obligation.cause.span), diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 30ba49ed2d8..b8446fa0012 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -116,8 +116,8 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(data.skip_binder().a.into()); // (*) wf.compute(data.skip_binder().b.into()); // (*) } - &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { - let obligations = wf.nominal_obligations(def_id, substs); + &ty::PredicateKind::ConstEvaluatable(def, substs) => { + let obligations = wf.nominal_obligations(def.did, substs); wf.out.extend(obligations); for arg in substs.iter() { @@ -365,7 +365,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) { let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def.did, substs) + let predicate = ty::PredicateKind::ConstEvaluatable(def, substs) .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new( diff --git a/src/librustc_ty/instance.rs b/src/librustc_ty/instance.rs index 9f5ab7f8e4a..d5c84881758 100644 --- a/src/librustc_ty/instance.rs +++ b/src/librustc_ty/instance.rs @@ -14,15 +14,48 @@ fn resolve_instance<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>, ) -> Result>, ErrorReported> { - let (param_env, (def_id, substs)) = key.into_parts(); + let (param_env, (did, substs)) = key.into_parts(); + if let param_did @ Some(_) = did.as_local().and_then(|did| tcx.opt_const_param_of(did)) { + tcx.resolve_instance_of_const_arg( + param_env.and((ty::WithOptParam { did, param_did }, substs)), + ) + } else { + inner_resolve_instance(tcx, param_env.and((ty::WithOptParam::dummy(did), substs))) + } +} + +fn resolve_instance_of_const_arg<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::WithOptParam, SubstsRef<'tcx>)>, +) -> Result>, ErrorReported> { + let (param_env, (def, substs)) = key.into_parts(); + if def.param_did.is_none() { + if let Some(did) = def.did.as_local() { + if let param_did @ Some(_) = tcx.opt_const_param_of(did) { + return tcx.resolve_instance_of_const_arg( + param_env.and((ty::WithOptParam { param_did, ..def }, substs)), + ); + } + } + tcx.resolve_instance(param_env.and((def.did, substs))) + } else { + inner_resolve_instance(tcx, param_env.and((def, substs))) + } +} + +fn inner_resolve_instance<'tcx>( + tcx: TyCtxt<'tcx>, + key: ty::ParamEnvAnd<'tcx, (ty::WithOptParam, SubstsRef<'tcx>)>, +) -> Result>, ErrorReported> { + let (param_env, (def, substs)) = key.into_parts(); - debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { + debug!("resolve(def={:?}, substs={:?})", def.did, substs); + let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) { debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); - let item = tcx.associated_item(def_id); + let item = tcx.associated_item(def.did); resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) } else { - let ty = tcx.type_of(def_id); + let ty = tcx.type_of(def.ty_def_id()); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); let def = match item_type.kind { @@ -33,7 +66,7 @@ fn resolve_instance<'tcx>( } => { debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) + ty::InstanceDef::Intrinsic(def.did) } ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => { let ty = substs.type_at(0); @@ -53,12 +86,12 @@ fn resolve_instance<'tcx>( } _ => { debug!(" => free item"); - ty::InstanceDef::Item(def_id) + ty::InstanceDef::Item(def.did) } }; Ok(Some(Instance { def, substs })) }; - debug!("resolve(def_id={:?}, substs={:?}) = {:?}", def_id, substs, result); + debug!("resolve(def.did={:?}, substs={:?}) = {:?}", def.did, substs, result); result } @@ -244,5 +277,6 @@ fn resolve_associated_item<'tcx>( } pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { resolve_instance, ..*providers }; + *providers = + ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers }; } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 19c556942af..f64dce5132d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -423,8 +423,11 @@ fn check_type_defn<'tcx, F>( fcx.register_predicate(traits::Obligation::new( cause, fcx.param_env, - ty::PredicateKind::ConstEvaluatable(discr_def_id.to_def_id(), discr_substs) - .to_predicate(fcx.tcx), + ty::PredicateKind::ConstEvaluatable( + ty::WithOptParam::dummy(discr_def_id.to_def_id()), + discr_substs, + ) + .to_predicate(fcx.tcx), )); } } diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs index 2f963dfcf8b..6ba4201b2c2 100644 --- a/src/tools/clippy/clippy_lints/src/consts.rs +++ b/src/tools/clippy/clippy_lints/src/consts.rs @@ -332,7 +332,7 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option