about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src/traits/mod.rs
diff options
context:
space:
mode:
authorBoxy <rust@boxyuwu.dev>2025-05-01 14:57:25 +0100
committerBoxy <rust@boxyuwu.dev>2025-05-21 20:20:19 +0100
commitb4079c62bd6b8ca5321ac8b75e336d772985dfeb (patch)
tree11b3847de1c29a93da46eae9a4be633fc42dbc51 /compiler/rustc_trait_selection/src/traits/mod.rs
parent996a185ba74755cb39a4fe24151ea65e671d4c0d (diff)
downloadrust-b4079c62bd6b8ca5321ac8b75e336d772985dfeb.tar.gz
rust-b4079c62bd6b8ca5321ac8b75e336d772985dfeb.zip
Don't evaluate constants depending on infers or params
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/mod.rs')
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs106
1 files changed, 64 insertions, 42 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index e00be6425bc..c174de44558 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -545,7 +545,7 @@ pub fn try_evaluate_const<'tcx>(
             // Postpone evaluation of constants that depend on generic parameters or
             // inference variables.
             //
-            // We use `TypingMode::PostAnalysis`  here which is not *technically* correct
+            // We use `TypingMode::PostAnalysis` here which is not *technically* correct
             // to be revealing opaque types here as borrowcheck has not run yet. However,
             // CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
             // typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
@@ -555,68 +555,90 @@ pub fn try_evaluate_const<'tcx>(
             // instead of having this logic here
             let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst
                 && let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def)
-                && uv.has_non_region_infer()
             {
-                // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
-                // inference variables and generic parameters to show up in `ty::Const` even though the anon const
-                // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
-                match tcx.thir_abstract_const(uv.def) {
-                    Ok(Some(ct)) => {
-                        let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
-                        if let Err(e) = ct.error_reported() {
-                            return Err(EvaluateConstErr::EvaluationFailure(e));
-                        } else if ct.has_non_region_infer() || ct.has_non_region_param() {
-                            // If the anon const *does* actually use generic parameters or inference variables from
-                            // the generic arguments provided for it, then we should *not* attempt to evaluate it.
-                            return Err(EvaluateConstErr::HasGenericsOrInfers);
-                        } else {
-                            let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args);
-                            let typing_env = infcx
-                                .typing_env(tcx.erase_regions(param_env))
-                                .with_post_analysis_normalized(tcx);
+                // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
+                // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
+                // about if you have to consider gce whatsoever.
+
+                if uv.has_non_region_infer() || uv.has_non_region_param() {
+                    // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
+                    // inference variables and generic parameters to show up in `ty::Const` even though the anon const
+                    // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
+                    match tcx.thir_abstract_const(uv.def) {
+                        Ok(Some(ct)) => {
+                            let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
+                            if let Err(e) = ct.error_reported() {
+                                return Err(EvaluateConstErr::EvaluationFailure(e));
+                            } else if ct.has_non_region_infer() || ct.has_non_region_param() {
+                                // If the anon const *does* actually use generic parameters or inference variables from
+                                // the generic arguments provided for it, then we should *not* attempt to evaluate it.
+                                return Err(EvaluateConstErr::HasGenericsOrInfers);
+                            } else {
+                                let args =
+                                    replace_param_and_infer_args_with_placeholder(tcx, uv.args);
+                                let typing_env = infcx
+                                    .typing_env(tcx.erase_regions(param_env))
+                                    .with_post_analysis_normalized(tcx);
+                                (args, typing_env)
+                            }
+                        }
+                        Err(_) | Ok(None) => {
+                            let args = GenericArgs::identity_for_item(tcx, uv.def);
+                            let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
                             (args, typing_env)
                         }
                     }
-                    Err(_) | Ok(None) => {
-                        let args = GenericArgs::identity_for_item(tcx, uv.def);
-                        let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
-                        (args, typing_env)
-                    }
+                } else {
+                    let typing_env = infcx
+                        .typing_env(tcx.erase_regions(param_env))
+                        .with_post_analysis_normalized(tcx);
+                    (uv.args, typing_env)
                 }
             } else if tcx.def_kind(uv.def) == DefKind::AnonConst
                 && let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def)
-                && uv.has_non_region_infer()
             {
-                // FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
-                //
-                // Diagnostics will sometimes replace the identity args of anon consts in
-                // array repeat expr counts with inference variables so we have to handle this
-                // even though it is not something we should ever actually encounter.
-                //
-                // Array repeat expr counts are allowed to syntactically use generic parameters
-                // but must not actually depend on them in order to evalaute successfully. This means
-                // that it is actually fine to evalaute them in their own environment rather than with
-                // the actually provided generic arguments.
-                tcx.dcx().delayed_bug(
-                    "Encountered anon const with inference variable args but no error reported",
-                );
+                if uv.has_non_region_infer() {
+                    // Diagnostics will sometimes replace the identity args of anon consts in
+                    // array repeat expr counts with inference variables so we have to handle this
+                    // even though it is not something we should ever actually encounter.
+                    //
+                    // Array repeat expr counts are allowed to syntactically use generic parameters
+                    // but must not actually depend on them in order to evalaute successfully. This means
+                    // that it is actually fine to evalaute them in their own environment rather than with
+                    // the actually provided generic arguments.
+                    tcx.dcx().delayed_bug(
+                        "Encountered anon const with inference variable args but no error reported",
+                    );
+                }
 
+                // The generic args of repeat expr counts under `min_const_generics` are not supposed to
+                // affect evaluation of the constant as this would make it a "truly" generic const arg.
+                // To prevent this we discard all the generic arguments and evalaute with identity args
+                // and in its own environment instead of the current environment we are normalizing in.
                 let args = GenericArgs::identity_for_item(tcx, uv.def);
                 let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
 
                 (args, typing_env)
             } else {
-                // FIXME: This codepath is reachable under `associated_const_equality` and in the
-                // future will be reachable by `min_generic_const_args`. We should handle inference
-                // variables and generic parameters properly instead of doing nothing.
+                // We are only dealing with "truly" generic/uninferred constants here:
+                // - GCEConsts have been handled separately
+                // - Repeat expr count back compat consts have also been handled separately
+                // So we are free to simply defer evaluation here.
+                //
+                // FIXME: This assumes that `args` are normalized which is not necessarily true
+                if uv.args.has_non_region_param() || uv.args.has_non_region_infer() {
+                    return Err(EvaluateConstErr::HasGenericsOrInfers);
+                }
+
                 let typing_env = infcx
                     .typing_env(tcx.erase_regions(param_env))
                     .with_post_analysis_normalized(tcx);
                 (uv.args, typing_env)
             };
-            let uv = ty::UnevaluatedConst::new(uv.def, args);
 
+            let uv = ty::UnevaluatedConst::new(uv.def, args);
             let erased_uv = tcx.erase_regions(uv);
+
             use rustc_middle::mir::interpret::ErrorHandled;
             match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
                 Ok(Ok(val)) => Ok(ty::Const::new_value(