loop_match: suggest extracting to a const item

if the expression cannot be evaluated in a straightforward way
This commit is contained in:
Folkert de Vries
2025-07-07 14:37:50 +02:00
parent 29a58723b0
commit 730d33dd64
5 changed files with 297 additions and 4 deletions

View File

@@ -86,10 +86,16 @@ mir_build_confused = missing patterns are not covered because `{$variable}` is i
mir_build_const_continue_bad_const = could not determine the target branch for this `#[const_continue]`
.label = this value is too generic
.note = the value must be a literal or a monomorphic const
mir_build_const_continue_missing_value = a `#[const_continue]` must break to a label with a value
mir_build_const_continue_not_const = could not determine the target branch for this `#[const_continue]`
.help = try extracting the expression into a `const` item
mir_build_const_continue_not_const_const_block = `const` blocks may use generics, and are not evaluated early enough
mir_build_const_continue_not_const_const_other = this value must be a literal or a monomorphic const
mir_build_const_continue_not_const_constant_parameter = constant parameters may use generics, and are not evaluated early enough
mir_build_const_continue_unknown_jump_target = the target of this `#[const_continue]` is not statically known
.label = this value must be a literal or a monomorphic const

View File

@@ -100,7 +100,9 @@ use tracing::{debug, instrument};
use super::matches::BuiltMatchTree;
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use crate::errors::{ConstContinueBadConst, ConstContinueUnknownJumpTarget};
use crate::errors::{
ConstContinueBadConst, ConstContinueNotMonomorphicConst, ConstContinueUnknownJumpTarget,
};
#[derive(Debug)]
pub(crate) struct Scopes<'tcx> {
@@ -867,7 +869,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
span_bug!(span, "break value must be a scope")
};
let constant = match &self.thir[value].kind {
let expr = &self.thir[value];
let constant = match &expr.kind {
ExprKind::Adt(box AdtExpr { variant_index, fields, base, .. }) => {
assert!(matches!(base, AdtExprBase::None));
assert!(fields.is_empty());
@@ -887,7 +890,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
),
}
}
_ => self.as_constant(&self.thir[value]),
ExprKind::Literal { .. }
| ExprKind::NonHirLiteral { .. }
| ExprKind::ZstLiteral { .. }
| ExprKind::NamedConst { .. } => self.as_constant(&self.thir[value]),
other => {
use crate::errors::ConstContinueNotMonomorphicConstReason as Reason;
let span = expr.span;
let reason = match other {
ExprKind::ConstParam { .. } => Reason::ConstantParameter { span },
ExprKind::ConstBlock { .. } => Reason::ConstBlock { span },
_ => Reason::Other { span },
};
self.tcx
.dcx()
.emit_err(ConstContinueNotMonomorphicConst { span: expr.span, reason });
return block.unit();
}
};
let break_index = self

View File

@@ -1213,6 +1213,38 @@ pub(crate) struct LoopMatchArmWithGuard {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(mir_build_const_continue_not_const)]
#[help]
pub(crate) struct ConstContinueNotMonomorphicConst {
#[primary_span]
pub span: Span,
#[subdiagnostic]
pub reason: ConstContinueNotMonomorphicConstReason,
}
#[derive(Subdiagnostic)]
pub(crate) enum ConstContinueNotMonomorphicConstReason {
#[label(mir_build_const_continue_not_const_constant_parameter)]
ConstantParameter {
#[primary_span]
span: Span,
},
#[label(mir_build_const_continue_not_const_const_block)]
ConstBlock {
#[primary_span]
span: Span,
},
#[label(mir_build_const_continue_not_const_const_other)]
Other {
#[primary_span]
span: Span,
},
}
#[derive(Diagnostic)]
#[diag(mir_build_const_continue_bad_const)]
pub(crate) struct ConstContinueBadConst {