@@ -14,11 +14,13 @@ use crate::{
14
14
NumericMode , SignOrIndeterminate , StructLiteral , UnaryMathOperation , VariableStorageKey ,
15
15
} ,
16
16
ast:: { FloatSize , IntegerBits , IntegerRigidity } ,
17
+ data_units:: BitUnits ,
17
18
ir:: { self , Break , IntegerSign , Literal , OverflowOperator , Value , ValueReference } ,
18
19
lower:: structure:: mono,
19
20
resolve:: PolyCatalog ,
20
21
} ;
21
22
use call:: { lower_expr_call, lower_expr_poly_call} ;
23
+ use num:: { BigInt , FromPrimitive } ;
22
24
use short_circuit:: lower_short_circuiting_binary_operation;
23
25
24
26
pub fn lower_expr (
@@ -559,6 +561,88 @@ pub fn lower_expr(
559
561
560
562
Ok ( ir:: Value :: Literal ( Literal :: Void ) )
561
563
}
564
+ ExprKind :: StaticAssert ( condition, message) => {
565
+ // TODO: How would this to make sense in generic functions?
566
+ // It would need access to polymorphs if used, so would only
567
+ // be able to do it when lowering (here).
568
+ // But if the condition doen't depend at all on polymorphs,
569
+ // then ideally we would evaluate it only once regardless
570
+ // of how many instances of the generic function are instatiated.
571
+ // (including zero)
572
+
573
+ let evaluated = evaluate_const_integer_expr ( builder, ir_module, & condition. expr , asg) ?;
574
+
575
+ if evaluated. is_zero ( ) {
576
+ return Err ( LowerErrorKind :: StaticAssertFailed ( message. clone ( ) ) . at ( expr. source ) ) ;
577
+ }
578
+
579
+ Ok ( ir:: Value :: Literal ( Literal :: Void ) )
580
+ }
581
+ }
582
+ }
583
+
584
+ #[ derive( Clone , Debug ) ]
585
+ pub struct EvaluatedConstInteger {
586
+ pub signed : bool ,
587
+ pub bits : BitUnits ,
588
+ pub value : BigInt ,
589
+ }
590
+
591
+ impl EvaluatedConstInteger {
592
+ pub fn is_zero ( & self ) -> bool {
593
+ self . value == BigInt :: ZERO
594
+ }
595
+ }
596
+
597
+ // NOTE: Should this be combined with the version that can happen at C parse-time?
598
+ pub fn evaluate_const_integer_expr (
599
+ builder : & mut Builder ,
600
+ ir_module : & ir:: Module ,
601
+ condition : & asg:: Expr ,
602
+ asg : & Asg ,
603
+ ) -> Result < EvaluatedConstInteger , LowerError > {
604
+ match & condition. kind {
605
+ ExprKind :: BooleanLiteral ( value) => Ok ( EvaluatedConstInteger {
606
+ signed : false ,
607
+ bits : BitUnits :: of ( 1 ) ,
608
+ value : BigInt :: from_u8 ( * value as u8 ) . unwrap ( ) ,
609
+ } ) ,
610
+ ExprKind :: IntegerLiteral ( _)
611
+ | ExprKind :: IntegerKnown ( _)
612
+ | ExprKind :: EnumMemberLiteral ( _) => todo ! ( ) ,
613
+ ExprKind :: ResolvedNamedExpression ( inner) => {
614
+ evaluate_const_integer_expr ( builder, ir_module, inner, asg)
615
+ }
616
+ ExprKind :: Variable ( _)
617
+ | ExprKind :: GlobalVariable ( _)
618
+ | ExprKind :: FloatingLiteral ( _, _)
619
+ | ExprKind :: String ( _)
620
+ | ExprKind :: NullTerminatedString ( _)
621
+ | ExprKind :: Null
622
+ | ExprKind :: Call ( _)
623
+ | ExprKind :: PolyCall ( _)
624
+ | ExprKind :: DeclareAssign ( _)
625
+ | ExprKind :: BasicBinaryOperation ( _) => todo ! ( ) ,
626
+ ExprKind :: ShortCircuitingBinaryOperation ( _) => todo ! ( ) ,
627
+ ExprKind :: IntegerCast ( _) => todo ! ( ) ,
628
+ ExprKind :: IntegerExtend ( _) => todo ! ( ) ,
629
+ ExprKind :: IntegerTruncate ( _) => todo ! ( ) ,
630
+ ExprKind :: FloatExtend ( _)
631
+ | ExprKind :: FloatToInteger ( _)
632
+ | ExprKind :: IntegerToFloat ( _)
633
+ | ExprKind :: Member ( _)
634
+ | ExprKind :: StructLiteral ( _)
635
+ | ExprKind :: UnaryMathOperation ( _) => todo ! ( ) ,
636
+ ExprKind :: Dereference ( _) | ExprKind :: AddressOf ( _) | ExprKind :: Conditional ( _) => todo ! ( ) ,
637
+ ExprKind :: While ( _) | ExprKind :: ArrayAccess ( _) | ExprKind :: Zeroed ( _) => todo ! ( ) ,
638
+ ExprKind :: SizeOf ( _)
639
+ | ExprKind :: InterpreterSyscall ( _, _)
640
+ | ExprKind :: Break
641
+ | ExprKind :: Continue
642
+ | ExprKind :: StaticAssert ( _, _) => Err ( LowerError :: other (
643
+ "Expected constant integer expression" ,
644
+ condition. source ,
645
+ ) ) ,
562
646
}
563
647
}
564
648
0 commit comments