From 0c6e57809928a31df4e20b1c6ed56697e0e9f989 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 19 Dec 2023 04:28:56 +0000 Subject: [PATCH] clean up `check_consts` checks --- .../src/transform/check_consts/check.rs | 192 +++++------------- 1 file changed, 52 insertions(+), 140 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 bb17602d3ba01..534f405b50ea7 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -8,10 +8,8 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, 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::{GenericArgs, Instance, InstanceDef, TraitRef, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -752,142 +750,61 @@ 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) { trace!("attempting to call a trait method"); - if !self.tcx.features().const_trait_impl { - self.check_op(ops::FnCallNonConst { - caller, - callee, - args: fn_args, - span: *fn_span, - call_source: *call_source, - feature: Some(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))) => { + // 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; + 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) + }; + if let Ok(Some(ImplSource::UserDefined(data))) = implsrc { 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 `::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, - ); + // 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; + } } - - 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; - } + } else { + self.check_op(ops::FnCallNonConst { + caller, + callee, + args: fn_args, + span: *fn_span, + call_source: *call_source, + feature: Some(if tcx.features().const_trait_impl { + sym::effects + } else { + sym::const_trait_impl + }), + }); + return; } } @@ -921,21 +838,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