Skip to content

Commit 8fda40f

Browse files
committed
Introduce evaluate const err kind for impossible preds
1 parent 67cb628 commit 8fda40f

File tree

8 files changed

+64
-21
lines changed

8 files changed

+64
-21
lines changed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
761761
}
762762

763763
impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features {
764+
fn min_generic_const_args(self) -> bool {
765+
self.min_generic_const_args()
766+
}
767+
764768
fn generic_const_exprs(self) -> bool {
765769
self.generic_const_exprs()
766770
}

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,14 +143,26 @@ where
143143
) -> QueryResult<I> {
144144
match ct.kind() {
145145
ty::ConstKind::Unevaluated(uv) => {
146+
// `ConstEvaluatable` goals don't really need to exist under `mgca` as we can assume all
147+
// generic const args can be sucessfully evaluated as they have been checked at def site.
148+
//
149+
// The only reason we keep this around is so that wf checking of signatures is guaranteed
150+
// to wind up normalizing constants emitting errors if they are ill formed. The equivalent
151+
// check does not exist for types and results in diverging aliases not being normalized during
152+
// wfck sometimes.
153+
//
154+
// Regardless, the point being that the behaviour of this goal doesn't really matter so we just
155+
// always return `Ok` and evaluate for the CTFE side effect of emitting an error.
156+
if self.cx().features().min_generic_const_args() {
157+
let _ = self.evaluate_const(param_env, uv);
158+
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
159+
}
160+
146161
// We never return `NoSolution` here as `evaluate_const` emits an
147162
// error itself when failing to evaluate, so emitting an additional fulfillment
148163
// error in that case is unnecessary noise. This may change in the future once
149164
// evaluation failures are allowed to impact selection, e.g. generic const
150165
// expressions in impl headers or `where`-clauses.
151-
152-
// FIXME(generic_const_exprs): Implement handling for generic
153-
// const expressions here.
154166
if let Some(_normalized) = self.evaluate_const(param_env, uv) {
155167
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
156168
} else {

compiler/rustc_trait_selection/src/solve/delegate.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
8585
Ok(ct) => Some(ct),
8686
Err(EvaluateConstErr::EvaluationFailure(e)) => Some(ty::Const::new_error(self.tcx, e)),
8787
Err(
88-
EvaluateConstErr::InvalidConstParamTy(_) | EvaluateConstErr::HasGenericsOrInfers,
88+
EvaluateConstErr::ImpossibleClauses
89+
| EvaluateConstErr::InvalidConstParamTy(_)
90+
| EvaluateConstErr::HasGenericsOrInfers,
8991
) => None,
9092
}
9193
}

compiler/rustc_trait_selection/src/traits/const_evaluatable.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ pub fn is_const_evaluatable<'tcx>(
7676
"Missing value for constant, but no error reported?",
7777
)))
7878
}
79+
Err(EvaluateConstErr::ImpossibleClauses) => {
80+
unreachable!("under gce constants shouldnt be wf checked before evaluating")
81+
}
7982
Err(
8083
EvaluateConstErr::EvaluationFailure(e)
8184
| EvaluateConstErr::InvalidConstParamTy(e),
@@ -86,9 +89,16 @@ pub fn is_const_evaluatable<'tcx>(
8689
_ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"),
8790
}
8891
} else if tcx.features().min_generic_const_args() {
89-
// This is a sanity check to make sure that non-generics consts are checked to
90-
// be evaluatable in case they aren't cchecked elsewhere. This will NOT error
91-
// if the const uses generics, as desired.
92+
// `ConstEvaluatable` goals don't really need to exist under `mgca` as we can assume all
93+
// generic const args can be sucessfully evaluated as they have been checked at def site.
94+
//
95+
// The only reason we keep this around is so that wf checking of signatures is guaranteed
96+
// to wind up normalizing constants emitting errors if they are ill formed. The equivalent
97+
// check does not exist for types and results in diverging aliases not being normalized during
98+
// wfck sometimes.
99+
//
100+
// Regardless, the point being that the behaviour of this goal doesn't really matter so we just
101+
// always return `Ok` and evaluate for the CTFE side effect of emitting an error.
92102
crate::traits::evaluate_const(infcx, unexpanded_ct, param_env);
93103
Ok(())
94104
} else {
@@ -144,6 +154,12 @@ pub fn is_const_evaluatable<'tcx>(
144154

145155
Err(err)
146156
}
157+
Err(EvaluateConstErr::ImpossibleClauses) => {
158+
let e = tcx
159+
.dcx()
160+
.delayed_bug("constants with impossible preds shouldnt error on stable");
161+
return Err(NotConstEvaluatable::Error(e));
162+
}
147163
Err(
148164
EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e),
149165
) => Err(NotConstEvaluatable::Error(e)),

compiler/rustc_trait_selection/src/traits/fulfill.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
687687
}
688688
e @ Err(
689689
EvaluateConstErr::EvaluationFailure(_)
690-
| EvaluateConstErr::InvalidConstParamTy(_),
690+
| EvaluateConstErr::InvalidConstParamTy(_)
691+
| EvaluateConstErr::ImpossibleClauses,
691692
) => e,
692693
}
693694
} else {
@@ -715,6 +716,10 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
715716
}
716717
}
717718
}
719+
(Err(EvaluateConstErr::ImpossibleClauses), _)
720+
| (_, Err(EvaluateConstErr::ImpossibleClauses)) => unreachable!(
721+
"under gce constants shouldnt be wf checked before evaluating"
722+
),
718723
(Err(EvaluateConstErr::InvalidConstParamTy(e)), _)
719724
| (_, Err(EvaluateConstErr::InvalidConstParamTy(e))) => {
720725
ProcessResult::Error(FulfillmentErrorCode::Select(

compiler/rustc_trait_selection/src/traits/mod.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ pub enum EvaluateConstErr {
493493
/// CTFE failed to evaluate the constant in some unrecoverable way (e.g. encountered a `panic!`).
494494
/// This is also used when the constant was already tainted by error.
495495
EvaluationFailure(ErrorGuaranteed),
496+
/// The constant requires impossible clauses to hold in order for it to be evaluated. This does not
497+
/// necessarily imply that type checking should error as there may be similar impossible clauses in
498+
/// the type checking environment that can be used to prove this constant wf.
499+
ImpossibleClauses,
496500
}
497501

498502
// FIXME(BoxyUwU): Private this once we `generic_const_exprs` isn't doing its own normalization routine
@@ -514,7 +518,7 @@ pub fn evaluate_const<'tcx>(
514518
Err(EvaluateConstErr::EvaluationFailure(e) | EvaluateConstErr::InvalidConstParamTy(e)) => {
515519
ty::Const::new_error(infcx.tcx, e)
516520
}
517-
Err(EvaluateConstErr::HasGenericsOrInfers) => ct,
521+
Err(EvaluateConstErr::ImpossibleClauses | EvaluateConstErr::HasGenericsOrInfers) => ct,
518522
}
519523
}
520524

@@ -671,7 +675,7 @@ pub fn try_evaluate_const<'tcx>(
671675
// If we are dealing with a fully monomorphic constant then we should ensure that
672676
// it is well formed as otherwise CTFE will ICE. For the same reasons as with
673677
// deferring evaluation of generic/uninferred constants, we do not have to worry
674-
// about `generic_const_expr`
678+
// about `generic_const_exprs`
675679
//
676680
// This check is done in an empty environment which is a little weird, however, mir
677681
// bodies with impossible predicates (in an empty environment) are sometimes built as
@@ -681,17 +685,9 @@ pub fn try_evaluate_const<'tcx>(
681685
uv.def,
682686
tcx.erase_regions(uv.args),
683687
)) {
684-
// We treat these consts as rigid instead of an error or delaying a bug as we may
685-
// be checking a constant with a trivialy-false where clause that is satisfied from
686-
// a trivially-false clause in the environment.
687-
//
688-
// Delaying a bug would ICE the compiler as we may be in an environment where the
689-
// impossible pred actually holds.
690-
//
691-
// Emitting an error would be wrong as we may be normalizing inside of a probe where
692-
// an inference variable was inferred to a concrete value resulting in an impossible
693-
// predicate.
694-
return Ok(ct);
688+
// We can't delay a bug here as that could ICE the compiler if we are in an environment
689+
// where the impossible pred actually holds due to it also existing in this env.
690+
return Err(EvaluateConstErr::ImpossibleClauses);
695691
}
696692

697693
let typing_env = infcx

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
932932
Err(_) => Ok(EvaluatedToErr),
933933
}
934934
}
935+
(Err(EvaluateConstErr::ImpossibleClauses), _)
936+
| (_, Err(EvaluateConstErr::ImpossibleClauses)) => {
937+
unreachable!(
938+
"under gce constants shouldnt be wf checked before evaluating"
939+
)
940+
}
935941
(Err(EvaluateConstErr::InvalidConstParamTy(..)), _)
936942
| (_, Err(EvaluateConstErr::InvalidConstParamTy(..))) => Ok(EvaluatedToErr),
937943
(Err(EvaluateConstErr::EvaluationFailure(..)), _)

compiler/rustc_type_ir/src/inherent.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,8 @@ pub trait ParamEnv<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
570570
}
571571

572572
pub trait Features<I: Interner>: Copy {
573+
fn min_generic_const_args(self) -> bool;
574+
573575
fn generic_const_exprs(self) -> bool;
574576

575577
fn coroutine_clone(self) -> bool;

0 commit comments

Comments
 (0)