@@ -2807,48 +2807,18 @@ export class Compiler extends DiagnosticEmitter {
2807
2807
2808
2808
// Compile the condition (always executes)
2809
2809
let condExpr = this . compileExpression ( statement . condition , Type . auto ) ;
2810
-
2811
- // Get the type set from compiling the condition expression
2812
- let currentType = this . currentType ;
2810
+ let condType = this . currentType ;
2813
2811
2814
- // Determine the binary operation to use for comparison
2815
- let binaryOp : BinaryOp ;
2816
- switch ( currentType . toRef ( ) ) {
2817
- case TypeRef . I32 : {
2818
- binaryOp = BinaryOp . EqI32 ;
2819
- break ;
2820
- }
2821
- case TypeRef . I64 : {
2822
- binaryOp = BinaryOp . EqI64 ;
2823
- break ;
2824
- }
2825
- case TypeRef . F32 : {
2826
- binaryOp = BinaryOp . EqF32 ;
2827
- break ;
2828
- }
2829
- case TypeRef . F64 : {
2830
- binaryOp = BinaryOp . EqF64 ;
2831
- break ;
2832
- }
2833
- default : {
2834
- this . error (
2835
- DiagnosticCode . Not_implemented_0 ,
2836
- statement . range , `Switch condition of type ${ currentType } `
2837
- ) ;
2838
- return module . unreachable ( ) ;
2839
- }
2840
- }
2841
-
2842
2812
// Shortcut if there are no cases
2843
2813
if ( ! numCases ) return module . drop ( condExpr ) ;
2844
2814
2845
2815
// Assign the condition to a temporary local as we compare it multiple times
2846
2816
let outerFlow = this . currentFlow ;
2847
- let tempLocal = outerFlow . getTempLocal ( currentType ) ;
2817
+ let tempLocal = outerFlow . getTempLocal ( condType ) ;
2848
2818
let tempLocalIndex = tempLocal . index ;
2849
2819
let breaks = new Array < ExpressionRef > ( 1 + numCases ) ;
2850
- breaks [ 0 ] = module . local_set ( tempLocalIndex , condExpr , currentType . isManaged ) ;
2851
-
2820
+ breaks [ 0 ] = module . local_set ( tempLocalIndex , condExpr , condType . isManaged ) ;
2821
+
2852
2822
// Make one br_if per labeled case and leave it to Binaryen to optimize the
2853
2823
// sequence of br_ifs to a br_table according to optimization levels
2854
2824
let breakIndex = 1 ;
@@ -2860,14 +2830,24 @@ export class Compiler extends DiagnosticEmitter {
2860
2830
defaultIndex = i ;
2861
2831
continue ;
2862
2832
}
2863
- breaks [ breakIndex ++ ] = module . br ( `case${ i } |${ label } ` ,
2864
- module . binary ( binaryOp ,
2865
- module . local_get ( tempLocalIndex , currentType . toRef ( ) ) ,
2866
- this . compileExpression ( assert ( case_ . label ) , currentType ,
2867
- Constraints . ConvImplicit
2868
- )
2869
- )
2833
+
2834
+ // Compile the equality expression for this case
2835
+ const left = statement . condition ;
2836
+ const leftExpr = module . local_get ( tempLocalIndex , condType . toRef ( ) ) ;
2837
+ const leftType = condType ;
2838
+ const right = case_ . label ! ;
2839
+ const rightExpr = this . compileExpression ( assert ( case_ . label ) , condType , Constraints . ConvImplicit ) ;
2840
+ const rightType = this . currentType ;
2841
+ const equalityExpr = this . compileCommutativeCompareBinaryExpressionFromParts (
2842
+ Token . Equals_Equals ,
2843
+ left , leftExpr , leftType ,
2844
+ right , rightExpr , rightType ,
2845
+ condType ,
2846
+ statement
2870
2847
) ;
2848
+
2849
+ // Add it to the list of breaks
2850
+ breaks [ breakIndex ++ ] = module . br ( `case${ i } |${ label } ` , equalityExpr ) ;
2871
2851
}
2872
2852
2873
2853
// If there is a default case, break to it, otherwise break out of the switch
@@ -3819,32 +3799,53 @@ export class Compiler extends DiagnosticEmitter {
3819
3799
expression : BinaryExpression ,
3820
3800
contextualType : Type ,
3821
3801
) : ExpressionRef {
3822
- let module = this . module ;
3823
- let left = expression . left ;
3824
- let right = expression . right ;
3802
+
3803
+ const left = expression . left ;
3804
+ const leftExpr = this . compileExpression ( left , contextualType ) ;
3805
+ const leftType = this . currentType ;
3806
+
3807
+ const right = expression . right ;
3808
+ const rightExpr = this . compileExpression ( right , leftType ) ;
3809
+ const rightType = this . currentType ;
3810
+
3811
+ return this . compileCommutativeCompareBinaryExpressionFromParts (
3812
+ expression . operator ,
3813
+ left , leftExpr , leftType ,
3814
+ right , rightExpr , rightType ,
3815
+ contextualType ,
3816
+ expression
3817
+ ) ;
3818
+ }
3825
3819
3826
- let leftExpr : ExpressionRef ;
3827
- let leftType : Type ;
3828
- let rightExpr : ExpressionRef ;
3829
- let rightType : Type ;
3830
- let commonType : Type | null ;
3820
+ /**
3821
+ * compile `==` `===` `!=` `!==` BinaryExpression, from previously compiled left and right expressions.
3822
+ *
3823
+ * This is split from `compileCommutativeCompareBinaryExpression` so that the logic can be reused
3824
+ * for switch cases in `compileSwitchStatement`, where the left expression only should be compiled once.
3825
+ */
3826
+ private compileCommutativeCompareBinaryExpressionFromParts (
3827
+ operator : Token ,
3828
+ left : Expression ,
3829
+ leftExpr : ExpressionRef ,
3830
+ leftType : Type ,
3831
+ right : Expression ,
3832
+ rightExpr : ExpressionRef ,
3833
+ rightType : Type ,
3834
+ contextualType : Type ,
3835
+ reportNode : Node
3836
+ ) : ExpressionRef {
3831
3837
3832
- let operator = expression . operator ;
3838
+ let module = this . module ;
3833
3839
let operatorString = operatorTokenToString ( operator ) ;
3834
-
3835
- leftExpr = this . compileExpression ( left , contextualType ) ;
3836
- leftType = this . currentType ;
3837
-
3838
- rightExpr = this . compileExpression ( right , leftType ) ;
3839
- rightType = this . currentType ;
3840
3840
3841
3841
// check operator overload
3842
3842
const operatorKind = OperatorKind . fromBinaryToken ( operator ) ;
3843
3843
const leftOverload = leftType . lookupOverload ( operatorKind , this . program ) ;
3844
3844
const rightOverload = rightType . lookupOverload ( operatorKind , this . program ) ;
3845
3845
if ( leftOverload && rightOverload && leftOverload != rightOverload ) {
3846
3846
this . error (
3847
- DiagnosticCode . Ambiguous_operator_overload_0_conflicting_overloads_1_and_2 , expression . range ,
3847
+ DiagnosticCode . Ambiguous_operator_overload_0_conflicting_overloads_1_and_2 ,
3848
+ reportNode . range ,
3848
3849
operatorString ,
3849
3850
leftOverload . internalName ,
3850
3851
rightOverload . internalName
@@ -3857,23 +3858,23 @@ export class Compiler extends DiagnosticEmitter {
3857
3858
leftOverload ,
3858
3859
left , leftExpr , leftType ,
3859
3860
right , rightExpr , rightType ,
3860
- expression
3861
+ reportNode
3861
3862
) ;
3862
3863
}
3863
3864
if ( rightOverload ) {
3864
3865
return this . compileCommutativeBinaryOverload (
3865
3866
rightOverload ,
3866
3867
right , rightExpr , rightType ,
3867
3868
left , leftExpr , leftType ,
3868
- expression
3869
+ reportNode
3869
3870
) ;
3870
3871
}
3871
3872
const signednessIsRelevant = false ;
3872
- commonType = Type . commonType ( leftType , rightType , contextualType , signednessIsRelevant ) ;
3873
+ const commonType = Type . commonType ( leftType , rightType , contextualType , signednessIsRelevant ) ;
3873
3874
if ( ! commonType ) {
3874
3875
this . error (
3875
3876
DiagnosticCode . Operator_0_cannot_be_applied_to_types_1_and_2 ,
3876
- expression . range ,
3877
+ reportNode . range ,
3877
3878
operatorString ,
3878
3879
leftType . toString ( ) ,
3879
3880
rightType . toString ( )
@@ -3886,13 +3887,13 @@ export class Compiler extends DiagnosticEmitter {
3886
3887
if ( isConstExpressionNaN ( module , rightExpr ) || isConstExpressionNaN ( module , leftExpr ) ) {
3887
3888
this . warning (
3888
3889
DiagnosticCode . _NaN_does_not_compare_equal_to_any_other_value_including_itself_Use_isNaN_x_instead ,
3889
- expression . range
3890
+ reportNode . range
3890
3891
) ;
3891
3892
}
3892
3893
if ( isConstNegZero ( rightExpr ) || isConstNegZero ( leftExpr ) ) {
3893
3894
this . warning (
3894
3895
DiagnosticCode . Comparison_with_0_0_is_sign_insensitive_Use_Object_is_x_0_0_if_the_sign_matters ,
3895
- expression . range
3896
+ reportNode . range
3896
3897
) ;
3897
3898
}
3898
3899
}
@@ -3906,10 +3907,10 @@ export class Compiler extends DiagnosticEmitter {
3906
3907
switch ( operator ) {
3907
3908
case Token . Equals_Equals_Equals :
3908
3909
case Token . Equals_Equals :
3909
- return this . makeEq ( leftExpr , rightExpr , commonType , expression ) ;
3910
+ return this . makeEq ( leftExpr , rightExpr , commonType , reportNode ) ;
3910
3911
case Token . Exclamation_Equals_Equals :
3911
3912
case Token . Exclamation_Equals :
3912
- return this . makeNe ( leftExpr , rightExpr , commonType , expression ) ;
3913
+ return this . makeNe ( leftExpr , rightExpr , commonType , reportNode ) ;
3913
3914
default :
3914
3915
assert ( false ) ;
3915
3916
return module . unreachable ( ) ;
0 commit comments