Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/lower/pattern_matching.rs')
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs81
1 files changed, 67 insertions, 14 deletions
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 86c3ce9eec..97aa3b0f21 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,5 +1,7 @@
//! MIR lowering for patterns
+use hir_def::resolver::HasResolver;
+
use crate::utils::pattern_matching_dereference_count;
use super::*;
@@ -72,7 +74,7 @@ impl MirLowerCtx<'_> {
*pat,
binding_mode,
)?;
- self.set_goto(next, then_target);
+ self.set_goto(next, then_target, pattern.into());
match next_else {
Some(t) => {
current = t;
@@ -85,13 +87,13 @@ impl MirLowerCtx<'_> {
}
if !finished {
let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
- self.set_goto(current, ce);
+ self.set_goto(current, ce, pattern.into());
}
(then_target, current_else)
}
Pat::Record { args, .. } => {
let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else {
- not_supported!("unresolved variant");
+ not_supported!("unresolved variant for record");
};
self.pattern_matching_variant(
cond_ty,
@@ -106,11 +108,8 @@ impl MirLowerCtx<'_> {
}
Pat::Range { .. } => not_supported!("range pattern"),
Pat::Slice { .. } => not_supported!("slice pattern"),
- Pat::Path(_) => {
- let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else {
- not_supported!("unresolved variant");
- };
- self.pattern_matching_variant(
+ Pat::Path(p) => match self.infer.variant_resolution_for_pat(pattern) {
+ Some(variant) => self.pattern_matching_variant(
cond_ty,
binding_mode,
cond_place,
@@ -119,8 +118,60 @@ impl MirLowerCtx<'_> {
pattern.into(),
current_else,
AdtPatternShape::Unit,
- )?
- }
+ )?,
+ None => {
+ let unresolved_name = || MirLowerError::unresolved_path(self.db, p);
+ let resolver = self.owner.resolver(self.db.upcast());
+ let pr = resolver
+ .resolve_path_in_value_ns(self.db.upcast(), p)
+ .ok_or_else(unresolved_name)?;
+ match pr {
+ ResolveValueResult::ValueNs(v) => match v {
+ ValueNs::ConstId(c) => {
+ let tmp: Place = self.temp(cond_ty.clone())?.into();
+ let span = pattern.into();
+ self.lower_const(
+ c,
+ current,
+ tmp.clone(),
+ Substitution::empty(Interner),
+ span,
+ cond_ty.clone(),
+ )?;
+ let tmp2: Place = self.temp(TyBuilder::bool())?.into();
+ self.push_assignment(
+ current,
+ tmp2.clone(),
+ Rvalue::CheckedBinaryOp(
+ BinOp::Eq,
+ Operand::Copy(tmp),
+ Operand::Copy(cond_place),
+ ),
+ span,
+ );
+ let next = self.new_basic_block();
+ let else_target =
+ current_else.unwrap_or_else(|| self.new_basic_block());
+ self.set_terminator(
+ current,
+ TerminatorKind::SwitchInt {
+ discr: Operand::Copy(tmp2),
+ targets: SwitchTargets::static_if(1, next, else_target),
+ },
+ span,
+ );
+ (next, Some(else_target))
+ }
+ _ => not_supported!(
+ "path in pattern position that is not const or variant"
+ ),
+ },
+ ResolveValueResult::Partial(_, _) => {
+ not_supported!("assoc const in patterns")
+ }
+ }
+ }
+ },
Pat::Lit(l) => match &self.body.exprs[*l] {
Expr::Literal(l) => {
let c = self.lower_literal_to_operand(cond_ty, l)?;
@@ -218,10 +269,11 @@ impl MirLowerCtx<'_> {
let discr = Operand::Copy(discr);
self.set_terminator(
current,
- Terminator::SwitchInt {
+ TerminatorKind::SwitchInt {
discr,
targets: SwitchTargets::static_if(1, then_target, else_target),
},
+ pattern.into(),
);
Ok((then_target, Some(else_target)))
}
@@ -244,8 +296,7 @@ impl MirLowerCtx<'_> {
};
Ok(match variant {
VariantId::EnumVariantId(v) => {
- let e = self.db.const_eval_discriminant(v)? as u128;
- let next = self.new_basic_block();
+ let e = self.const_eval_discriminant(v)? as u128;
let tmp = self.discr_temp_place();
self.push_assignment(
current,
@@ -253,13 +304,15 @@ impl MirLowerCtx<'_> {
Rvalue::Discriminant(cond_place.clone()),
span,
);
+ let next = self.new_basic_block();
let else_target = current_else.unwrap_or_else(|| self.new_basic_block());
self.set_terminator(
current,
- Terminator::SwitchInt {
+ TerminatorKind::SwitchInt {
discr: Operand::Copy(tmp),
targets: SwitchTargets::static_if(e, next, else_target),
},
+ span,
);
let enum_data = self.db.enum_data(v.parent);
self.pattern_matching_variant_fields(