diff options
| author | Deadbeef <ent3rm4n@gmail.com> | 2023-12-19 04:28:56 +0000 |
|---|---|---|
| committer | Deadbeef <ent3rm4n@gmail.com> | 2023-12-22 08:20:57 +0000 |
| commit | df1a4c630dc8ea76f7dd01b3248689a2603b5da7 (patch) | |
| tree | 92ff9fdbf4c0cd01805742917c645b00433dab58 | |
| parent | 324ca878cec59b623fb6e4dbcfad1e94937d477a (diff) | |
| download | rust-df1a4c630dc8ea76f7dd01b3248689a2603b5da7.tar.gz rust-df1a4c630dc8ea76f7dd01b3248689a2603b5da7.zip | |
clean up `check_consts` checks
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/check_consts/check.rs | 187 |
1 files changed, 40 insertions, 147 deletions
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index bb17602d3ba..7a7a5ea8774 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -5,17 +5,15 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; +use rustc_infer::traits::ObligationCause; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::traits::BuiltinImplSource; -use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt}; -use rustc_middle::ty::{TraitRef, TypeVisitableExt}; +use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; use std::mem; @@ -752,143 +750,43 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { infcx.err_ctxt().report_fulfillment_errors(errors); } + let mut is_trait = false; // Attempting to call a trait method? - // FIXME(effects) do we need this? - if let Some(trait_id) = tcx.trait_of_item(callee) { + if tcx.trait_of_item(callee).is_some() { trace!("attempting to call a trait method"); - if !self.tcx.features().const_trait_impl { + // trait method calls are only permitted when `effects` is enabled. + // we don't error, since that is handled by typeck. We try to resolve + // the trait into the concrete method, and uses that for const stability + // checks. + // FIXME(effects) we might consider moving const stability checks to typeck as well. + if tcx.features().effects { + is_trait = true; + + if let Ok(Some(instance)) = + Instance::resolve(tcx, param_env, callee, fn_args) + && let InstanceDef::Item(def) = instance.def + { + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. This is only used for the const stability check below, since + // we want to look at the concrete impl's stability. + fn_args = instance.args; + callee = def; + } + } else { self.check_op(ops::FnCallNonConst { caller, callee, args: fn_args, span: *fn_span, call_source: *call_source, - feature: Some(sym::const_trait_impl), + feature: Some(if tcx.features().const_trait_impl { + sym::effects + } else { + sym::const_trait_impl + }), }); return; } - - let trait_ref = TraitRef::from_method(tcx, trait_id, fn_args); - let obligation = - Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref); - - let implsrc = { - let infcx = tcx.infer_ctxt().build(); - let mut selcx = SelectionContext::new(&infcx); - selcx.select(&obligation) - }; - - match implsrc { - Ok(Some(ImplSource::Param(_))) if tcx.features().effects => { - debug!( - "const_trait_impl: provided {:?} via where-clause in {:?}", - trait_ref, param_env - ); - return; - } - // Closure: Fn{Once|Mut} - Ok(Some(ImplSource::Builtin(BuiltinImplSource::Misc, _))) - if trait_ref.self_ty().is_closure() - && tcx.fn_trait_kind_from_def_id(trait_id).is_some() => - { - let ty::Closure(closure_def_id, fn_args) = *trait_ref.self_ty().kind() - else { - unreachable!() - }; - if !tcx.is_const_fn_raw(closure_def_id) { - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: None, - }); - - return; - } - } - Ok(Some(ImplSource::UserDefined(data))) => { - let callee_name = tcx.item_name(callee); - - if let hir::Constness::NotConst = tcx.constness(data.impl_def_id) { - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: None, - }); - return; - } - - if let Some(&did) = tcx - .associated_item_def_ids(data.impl_def_id) - .iter() - .find(|did| tcx.item_name(**did) == callee_name) - { - // using internal args is ok here, since this is only - // used for the `resolve` call below - fn_args = GenericArgs::identity_for_item(tcx, did); - callee = did; - } - } - _ if !tcx.is_const_fn_raw(callee) => { - // At this point, it is only legal when the caller is in a trait - // marked with #[const_trait], and the callee is in the same trait. - let mut nonconst_call_permission = false; - if let Some(callee_trait) = tcx.trait_of_item(callee) - && tcx.has_attr(callee_trait, sym::const_trait) - && Some(callee_trait) == tcx.trait_of_item(caller.to_def_id()) - // Can only call methods when it's `<Self as TheTrait>::f`. - && tcx.types.self_param == fn_args.type_at(0) - { - nonconst_call_permission = true; - } - - if !nonconst_call_permission { - let obligation = Obligation::new( - tcx, - ObligationCause::dummy_with_span(*fn_span), - param_env, - trait_ref, - ); - - // improve diagnostics by showing what failed. Our requirements are stricter this time - // as we are going to error again anyways. - let infcx = tcx.infer_ctxt().build(); - if let Err(e) = implsrc { - infcx.err_ctxt().report_selection_error( - obligation.clone(), - &obligation, - &e, - ); - } - - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: None, - }); - return; - } - } - _ => {} - } - - // Resolve a trait method call to its concrete implementation, which may be in a - // `const` trait impl. - let instance = Instance::resolve(tcx, param_env, callee, fn_args); - debug!("Resolving ({:?}) -> {:?}", callee, instance); - if let Ok(Some(func)) = instance { - if let InstanceDef::Item(def) = func.def { - callee = def; - } - } } // At this point, we are calling a function, `callee`, whose `DefId` is known... @@ -921,21 +819,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } - if !tcx.is_const_fn_raw(callee) { - if !tcx.is_const_default_method(callee) { - // To get to here we must have already found a const impl for the - // trait, but for it to still be non-const can be that the impl is - // using default method bodies. - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: None, - }); - return; - } + if !tcx.is_const_fn_raw(callee) && !is_trait { + self.check_op(ops::FnCallNonConst { + caller, + callee, + args: fn_args, + span: *fn_span, + call_source: *call_source, + feature: None, + }); + return; } // If the `const fn` we are trying to call is not const-stable, ensure that we have |
