Skip to content

Commit ddd6e6f

Browse files
committed
static pattern matching when lowering #[const_continue]
1 parent f943ea1 commit ddd6e6f

File tree

5 files changed

+182
-235
lines changed

5 files changed

+182
-235
lines changed

compiler/rustc_mir_build/src/builder/expr/into.rs

Lines changed: 35 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! See docs in build/expr/mod.rs
22
3-
use rustc_abi::VariantIdx;
43
use rustc_ast::{AsmMacro, InlineAsmOptions};
54
use rustc_data_structures::fx::FxHashMap;
65
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -9,17 +8,14 @@ use rustc_hir::lang_items::LangItem;
98
use rustc_middle::mir::*;
109
use rustc_middle::span_bug;
1110
use rustc_middle::thir::*;
12-
use rustc_middle::ty::util::Discr;
1311
use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty};
14-
use rustc_pattern_analysis::constructor::Constructor;
15-
use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt};
1612
use rustc_span::DUMMY_SP;
1713
use rustc_span::source_map::Spanned;
1814
use rustc_trait_selection::infer::InferCtxtExt;
1915
use tracing::{debug, instrument};
2016

2117
use crate::builder::expr::category::{Category, RvalueFunc};
22-
use crate::builder::matches::DeclareLetBindings;
18+
use crate::builder::matches::{DeclareLetBindings, HasMatchGuard};
2319
use crate::builder::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
2420

2521
impl<'a, 'tcx> Builder<'a, 'tcx> {
@@ -251,28 +247,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
251247
ExprKind::LoopMatch { state, region_scope, ref arms } => {
252248
// FIXME add diagram
253249

254-
let dropless_arena = rustc_arena::DroplessArena::default();
255-
let typeck_results = this.tcx.typeck(this.def_id);
256-
257-
// the PatCtxt is normally used in pattern exhaustiveness checking, but reused here
258-
// because it performs normalization and const evaluation.
259-
let cx = RustcPatCtxt {
260-
tcx: this.tcx,
261-
typeck_results,
262-
module: this.tcx.parent_module(this.hir_id).to_def_id(),
263-
// FIXME(#132279): We're in a body, should handle opaques.
264-
typing_env: rustc_middle::ty::TypingEnv::non_body_analysis(
265-
this.tcx,
266-
this.def_id,
267-
),
268-
dropless_arena: &dropless_arena,
269-
match_lint_level: this.hir_id,
270-
whole_match_span: Some(rustc_span::Span::default()),
271-
scrut_span: rustc_span::Span::default(),
272-
refutable: true,
273-
known_valid_scrutinee: true,
274-
};
275-
276250
let loop_block = this.cfg.start_new_block();
277251

278252
// Start the loop.
@@ -290,131 +264,52 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
290264
);
291265
this.diverge_from(loop_block);
292266

293-
let state_place = unpack!(body_block = this.as_place(body_block, state));
294-
let state_ty = this.thir.exprs[state].ty;
295-
296-
// the type of the value that is switched on by the `SwitchInt`
297-
let discr_ty = match state_ty {
298-
ty if ty.is_enum() => ty.discriminant_ty(this.tcx),
299-
ty if ty.is_integral() => ty,
300-
other => todo!("{other:?}"),
301-
};
302-
303-
let rvalue = match state_ty {
304-
ty if ty.is_enum() => Rvalue::Discriminant(state_place),
305-
ty if ty.is_integral() => Rvalue::Use(Operand::Copy(state_place)),
306-
_ => todo!(),
307-
};
267+
let scrutinee_place_builder =
268+
unpack!(body_block = this.as_place_builder(body_block, state));
269+
let scrutinee_span = this.thir.exprs[state].span;
270+
let match_start_span = scrutinee_span; // span.shrink_to_lo().to(scrutinee_span); FIXME
271+
let patterns = arms
272+
.iter()
273+
.map(|&arm_id| {
274+
// FIXME nice error for guards (which are not allowed)
275+
let arm = &this.thir[arm_id];
276+
assert!(arm.guard.is_none());
277+
(&*arm.pattern, HasMatchGuard::No)
278+
})
279+
.collect();
280+
281+
let built_tree = this.lower_match_tree(
282+
body_block,
283+
scrutinee_span,
284+
&scrutinee_place_builder,
285+
match_start_span,
286+
patterns,
287+
false,
288+
);
308289

309-
// block and arm of the wildcard pattern (if any)
310-
let mut otherwise = None;
290+
let state_place = scrutinee_place_builder.to_place(this);
311291

312292
unpack!(
313293
body_block = this.in_scope(
314294
(region_scope, source_info),
315295
LintLevel::Inherited,
316296
move |this| {
317-
let mut arm_blocks = Vec::with_capacity(arms.len());
318-
for &arm in arms {
319-
let pat = &this.thir[arm].pattern;
320-
321-
this.loop_match_patterns(
322-
arm,
323-
&cx.lower_pat(pat),
324-
None,
325-
&mut arm_blocks,
326-
&mut otherwise,
327-
);
328-
}
329-
330-
// handle patterns like `None | None` or two different arms that
331-
// have the same pattern.
332-
//
333-
// NOTE: why this works is a bit subtle: we always want to pick the
334-
// first arm for a pattern, and because this is a stable sort that
335-
// works out.
336-
arm_blocks.sort_by_key(|(_, discr, _, _)| discr.val);
337-
arm_blocks.dedup_by_key(|(_, discr, _, _)| discr.val);
338-
339-
// if we're matching on an enum, the discriminant order in the `SwitchInt`
340-
// targets should match the order yielded by `AdtDef::discriminants`.
341-
if state_ty.is_enum() {
342-
arm_blocks.sort_by_key(|(variant_idx, ..)| *variant_idx);
343-
}
344-
345-
let targets = SwitchTargets::new(
346-
arm_blocks
347-
.iter()
348-
.map(|&(_, discr, block, _arm)| (discr.val, block)),
349-
if let Some((block, _)) = otherwise {
350-
block
351-
} else {
352-
let unreachable_block = this.cfg.start_new_block();
353-
this.cfg.terminate(
354-
unreachable_block,
355-
source_info,
356-
TerminatorKind::Unreachable,
357-
);
358-
unreachable_block
359-
},
360-
);
361-
362297
this.in_breakable_scope(None, state_place, expr_span, |this| {
363298
Some(this.in_const_continuable_scope(
364-
targets.clone(),
299+
arms.clone(),
300+
built_tree.clone(),
365301
state_place,
366302
expr_span,
367303
|this| {
368-
let discr = this.temp(discr_ty, source_info.span);
369-
this.cfg.push_assign(
370-
body_block,
371-
source_info,
372-
discr,
373-
rvalue,
374-
);
375-
let discr = Operand::Copy(discr);
376-
this.cfg.terminate(
377-
body_block,
378-
source_info,
379-
TerminatorKind::SwitchInt { discr, targets },
380-
);
381-
382-
let it = arm_blocks
383-
.into_iter()
384-
.map(|(_, _, block, arm)| (block, arm))
385-
.chain(otherwise);
386-
387-
for (mut block, arm_id) in it {
388-
if this.cfg.block_data(block).terminator.is_some() {
389-
continue; // this can occur with or-patterns
390-
}
391-
392-
let arm = &this.thir[arm_id];
393-
let arm_source_info = this.source_info(arm.span);
394-
let arm_scope = (arm.scope, arm_source_info);
395-
396-
let empty_place = this.get_unit_temp();
397-
unpack!(
398-
block = {
399-
this.in_scope(
400-
arm_scope,
401-
arm.lint_level,
402-
|this| {
403-
this.expr_into_dest(
404-
empty_place,
405-
block,
406-
arm.body,
407-
)
408-
},
409-
)
410-
}
411-
);
412-
this.cfg.terminate(
413-
block,
414-
source_info,
415-
TerminatorKind::Unreachable,
416-
);
417-
}
304+
this.lower_match_arms(
305+
destination,
306+
scrutinee_place_builder,
307+
scrutinee_span,
308+
arms,
309+
built_tree,
310+
// FIXME this should be the span of just the match
311+
this.source_info(expr_span),
312+
)
418313
},
419314
))
420315
})
@@ -893,55 +788,4 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
893788
_ => false,
894789
}
895790
}
896-
897-
fn loop_match_patterns(
898-
&mut self,
899-
arm_id: ArmId,
900-
pat: &DeconstructedPat<'_, 'tcx>,
901-
current_block: Option<BasicBlock>,
902-
result: &mut Vec<(VariantIdx, Discr<'tcx>, BasicBlock, ArmId)>,
903-
otherwise: &mut Option<(BasicBlock, ArmId)>,
904-
) {
905-
match pat.ctor() {
906-
Constructor::Variant(variant_index) => {
907-
let PatKind::Variant { adt_def, .. } = pat.data().kind else { unreachable!() };
908-
909-
let discr = adt_def.discriminant_for_variant(self.tcx, *variant_index);
910-
911-
let block = current_block.unwrap_or_else(|| self.cfg.start_new_block());
912-
result.push((*variant_index, discr, block, arm_id));
913-
}
914-
Constructor::IntRange(int_range) => {
915-
assert!(int_range.is_singleton());
916-
917-
let bits = pat.ty().primitive_size(self.tcx).bits();
918-
919-
let value = if pat.ty().is_signed() {
920-
int_range.lo.as_finite_int(bits).unwrap()
921-
} else {
922-
int_range.lo.as_finite_uint().unwrap()
923-
};
924-
925-
let discr = Discr { val: value, ty: **pat.ty() };
926-
927-
let block = current_block.unwrap_or_else(|| self.cfg.start_new_block());
928-
result.push((VariantIdx::ZERO, discr, block, arm_id));
929-
}
930-
Constructor::Wildcard => {
931-
// the first wildcard wins
932-
if otherwise.is_none() {
933-
let block = current_block.unwrap_or_else(|| self.cfg.start_new_block());
934-
*otherwise = Some((block, arm_id))
935-
}
936-
}
937-
Constructor::Or => {
938-
let block = current_block.unwrap_or_else(|| self.cfg.start_new_block());
939-
940-
for indexed in pat.iter_fields() {
941-
self.loop_match_patterns(arm_id, &indexed.pat, Some(block), result, otherwise);
942-
}
943-
}
944-
other => todo!("{:?}", other),
945-
}
946-
}
947791
}

0 commit comments

Comments
 (0)