diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index db8f94e40354..c2fb4fa53880 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2542,6 +2542,19 @@ fn unsupported_str_binary_op_in_eval_rvalue() { ); } +#[test] +fn enum_variant_as_usize_in_const() { + check_number( + r#" +enum Foo { + Bar = 4, +} +const GOAL: usize = Foo::Bar as usize; + "#, + 4, + ); +} + #[test] fn const_loop() { check_fail( diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 3b82ed6f798e..7358c14af764 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -966,23 +966,62 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.lower_expr_to_place(id, place, current) } Expr::Cast { expr, type_ref: _ } => { - let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? else { - return Ok(None); - }; // Since we don't have THIR, this is the "zipped" version of [rustc's HIR lowering](https://github.com/rust-lang/rust/blob/e71f9529121ca8f687e4b725e3c9adc3f1ebab4d/compiler/rustc_mir_build/src/thir/cx/expr.rs#L165-L178) // and [THIR lowering as RValue](https://github.com/rust-lang/rust/blob/a4601859ae3875732797873612d424976d9e3dd0/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs#L193-L313) - let rvalue = if self.infer.coercion_casts.contains(expr) { - Rvalue::Use(it) + let (rvalue, current) = if self.infer.coercion_casts.contains(expr) { + let Some((it, current)) = self.lower_expr_to_some_operand(*expr, current)? + else { + return Ok(None); + }; + (Rvalue::Use(it), current) } else { let source_ty = self.infer.expr_ty(*expr); let target_ty = self.infer.expr_ty(expr_id); + let (it, source_ty, current) = + if let Some(VariantId::EnumVariantId(variant_id)) = + self.infer.variant_resolution_for_expr(*expr) + { + self.lower_variant_discriminant(current, variant_id)? + } else if let TyKind::Adt(adt, _) = source_ty.kind() + && adt.is_enum() + { + let Some((enum_place, current)) = + self.lower_expr_as_place(current, *expr, true)? + else { + return Ok(None); + }; + let discr_ty = Ty::new_int(self.interner(), rustc_type_ir::IntTy::I128); + let discr_place: Place<'db> = + self.temp(discr_ty, current, expr_id.into())?.into(); + + self.push_assignment( + current, + discr_place, + Rvalue::Discriminant(enum_place.store()), + expr_id.into(), + ); + ( + Operand { + kind: OperandKind::Copy(discr_place.store()), + span: Some(expr_id.into()), + }, + discr_ty, + current, + ) + } else { + let Some((it, current)) = + self.lower_expr_to_some_operand(*expr, current)? + else { + return Ok(None); + }; + (it, source_ty, current) + }; let cast_kind = if source_ty.as_reference().is_some() { CastKind::PointerCoercion(PointerCast::ArrayToPointer) } else { cast_kind(self.db, source_ty, target_ty)? }; - - Rvalue::Cast(cast_kind, it, target_ty.store()) + (Rvalue::Cast(cast_kind, it, target_ty.store()), current) }; self.push_assignment(current, place, rvalue, expr_id.into()); Ok(Some(current)) @@ -1519,6 +1558,17 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Ok(prev_block) } + fn lower_variant_discriminant( + &mut self, + current: BasicBlockId, + variant_id: EnumVariantId, + ) -> Result<'db, (Operand, Ty<'db>, BasicBlockId)> { + let discriminant = self.const_eval_discriminant(variant_id)?; + let discr_ty = Ty::new_int(self.interner(), rustc_type_ir::IntTy::I128); + let operand = Operand::from_bytes(Box::new(discriminant.to_le_bytes()), discr_ty); + Ok((operand, discr_ty, current)) + } + fn lower_call_and_args( &mut self, func: Operand,