about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2023-12-19 04:28:56 +0000
committerDeadbeef <ent3rm4n@gmail.com>2023-12-22 08:20:57 +0000
commitdf1a4c630dc8ea76f7dd01b3248689a2603b5da7 (patch)
tree92ff9fdbf4c0cd01805742917c645b00433dab58
parent324ca878cec59b623fb6e4dbcfad1e94937d477a (diff)
downloadrust-df1a4c630dc8ea76f7dd01b3248689a2603b5da7.tar.gz
rust-df1a4c630dc8ea76f7dd01b3248689a2603b5da7.zip
clean up `check_consts` checks
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs187
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