@@ -2816,19 +2816,18 @@ export class Compiler extends DiagnosticEmitter {
2816
2816
let numCases = cases . length ;
2817
2817
2818
2818
// Compile the condition (always executes)
2819
- let condExpr = this . compileExpression ( statement . condition , Type . u32 ,
2820
- Constraints . ConvImplicit
2821
- ) ;
2822
-
2819
+ let condExpr = this . compileExpression ( statement . condition , Type . auto ) ;
2820
+ let condType = this . currentType ;
2821
+
2823
2822
// Shortcut if there are no cases
2824
2823
if ( ! numCases ) return module . drop ( condExpr ) ;
2825
2824
2826
2825
// Assign the condition to a temporary local as we compare it multiple times
2827
2826
let outerFlow = this . currentFlow ;
2828
- let tempLocal = outerFlow . getTempLocal ( Type . u32 ) ;
2827
+ let tempLocal = outerFlow . getTempLocal ( condType ) ;
2829
2828
let tempLocalIndex = tempLocal . index ;
2830
2829
let breaks = new Array < ExpressionRef > ( 1 + numCases ) ;
2831
- breaks [ 0 ] = module . local_set ( tempLocalIndex , condExpr , false ) ; // u32
2830
+ breaks [ 0 ] = module . local_set ( tempLocalIndex , condExpr , condType . isManaged ) ;
2832
2831
2833
2832
// Make one br_if per labeled case and leave it to Binaryen to optimize the
2834
2833
// sequence of br_ifs to a br_table according to optimization levels
@@ -2841,14 +2840,24 @@ export class Compiler extends DiagnosticEmitter {
2841
2840
defaultIndex = i ;
2842
2841
continue ;
2843
2842
}
2844
- breaks [ breakIndex ++ ] = module . br ( `case${ i } |${ label } ` ,
2845
- module . binary ( BinaryOp . EqI32 ,
2846
- module . local_get ( tempLocalIndex , TypeRef . I32 ) ,
2847
- this . compileExpression ( assert ( case_ . label ) , Type . u32 ,
2848
- Constraints . ConvImplicit
2849
- )
2850
- )
2843
+
2844
+ // Compile the equality expression for this case
2845
+ const left = statement . condition ;
2846
+ const leftExpr = module . local_get ( tempLocalIndex , condType . toRef ( ) ) ;
2847
+ const leftType = condType ;
2848
+ const right = case_ . label ! ;
2849
+ const rightExpr = this . compileExpression ( assert ( case_ . label ) , condType , Constraints . ConvImplicit ) ;
2850
+ const rightType = this . currentType ;
2851
+ const equalityExpr = this . compileCommutativeCompareBinaryExpressionFromParts (
2852
+ Token . Equals_Equals ,
2853
+ left , leftExpr , leftType ,
2854
+ right , rightExpr , rightType ,
2855
+ condType ,
2856
+ statement
2851
2857
) ;
2858
+
2859
+ // Add it to the list of breaks
2860
+ breaks [ breakIndex ++ ] = module . br ( `case${ i } |${ label } ` , equalityExpr ) ;
2852
2861
}
2853
2862
2854
2863
// If there is a default case, break to it, otherwise break out of the switch
@@ -3800,32 +3809,53 @@ export class Compiler extends DiagnosticEmitter {
3800
3809
expression : BinaryExpression ,
3801
3810
contextualType : Type ,
3802
3811
) : ExpressionRef {
3803
- let module = this . module ;
3804
- let left = expression . left ;
3805
- let right = expression . right ;
3812
+
3813
+ const left = expression . left ;
3814
+ const leftExpr = this . compileExpression ( left , contextualType ) ;
3815
+ const leftType = this . currentType ;
3816
+
3817
+ const right = expression . right ;
3818
+ const rightExpr = this . compileExpression ( right , leftType ) ;
3819
+ const rightType = this . currentType ;
3820
+
3821
+ return this . compileCommutativeCompareBinaryExpressionFromParts (
3822
+ expression . operator ,
3823
+ left , leftExpr , leftType ,
3824
+ right , rightExpr , rightType ,
3825
+ contextualType ,
3826
+ expression
3827
+ ) ;
3828
+ }
3806
3829
3807
- let leftExpr : ExpressionRef ;
3808
- let leftType : Type ;
3809
- let rightExpr : ExpressionRef ;
3810
- let rightType : Type ;
3811
- let commonType : Type | null ;
3830
+ /**
3831
+ * compile `==` `===` `!=` `!==` BinaryExpression, from previously compiled left and right expressions.
3832
+ *
3833
+ * This is split from `compileCommutativeCompareBinaryExpression` so that the logic can be reused
3834
+ * for switch cases in `compileSwitchStatement`, where the left expression only should be compiled once.
3835
+ */
3836
+ private compileCommutativeCompareBinaryExpressionFromParts (
3837
+ operator : Token ,
3838
+ left : Expression ,
3839
+ leftExpr : ExpressionRef ,
3840
+ leftType : Type ,
3841
+ right : Expression ,
3842
+ rightExpr : ExpressionRef ,
3843
+ rightType : Type ,
3844
+ contextualType : Type ,
3845
+ reportNode : Node
3846
+ ) : ExpressionRef {
3812
3847
3813
- let operator = expression . operator ;
3848
+ let module = this . module ;
3814
3849
let operatorString = operatorTokenToString ( operator ) ;
3815
-
3816
- leftExpr = this . compileExpression ( left , contextualType ) ;
3817
- leftType = this . currentType ;
3818
-
3819
- rightExpr = this . compileExpression ( right , leftType ) ;
3820
- rightType = this . currentType ;
3821
3850
3822
3851
// check operator overload
3823
3852
const operatorKind = OperatorKind . fromBinaryToken ( operator ) ;
3824
3853
const leftOverload = leftType . lookupOverload ( operatorKind , this . program ) ;
3825
3854
const rightOverload = rightType . lookupOverload ( operatorKind , this . program ) ;
3826
3855
if ( leftOverload && rightOverload && leftOverload != rightOverload ) {
3827
3856
this . error (
3828
- DiagnosticCode . Ambiguous_operator_overload_0_conflicting_overloads_1_and_2 , expression . range ,
3857
+ DiagnosticCode . Ambiguous_operator_overload_0_conflicting_overloads_1_and_2 ,
3858
+ reportNode . range ,
3829
3859
operatorString ,
3830
3860
leftOverload . internalName ,
3831
3861
rightOverload . internalName
@@ -3838,23 +3868,23 @@ export class Compiler extends DiagnosticEmitter {
3838
3868
leftOverload ,
3839
3869
left , leftExpr , leftType ,
3840
3870
right , rightExpr , rightType ,
3841
- expression
3871
+ reportNode
3842
3872
) ;
3843
3873
}
3844
3874
if ( rightOverload ) {
3845
3875
return this . compileCommutativeBinaryOverload (
3846
3876
rightOverload ,
3847
3877
right , rightExpr , rightType ,
3848
3878
left , leftExpr , leftType ,
3849
- expression
3879
+ reportNode
3850
3880
) ;
3851
3881
}
3852
3882
const signednessIsRelevant = false ;
3853
- commonType = Type . commonType ( leftType , rightType , contextualType , signednessIsRelevant ) ;
3883
+ const commonType = Type . commonType ( leftType , rightType , contextualType , signednessIsRelevant ) ;
3854
3884
if ( ! commonType ) {
3855
3885
this . error (
3856
3886
DiagnosticCode . Operator_0_cannot_be_applied_to_types_1_and_2 ,
3857
- expression . range ,
3887
+ reportNode . range ,
3858
3888
operatorString ,
3859
3889
leftType . toString ( ) ,
3860
3890
rightType . toString ( )
@@ -3867,13 +3897,13 @@ export class Compiler extends DiagnosticEmitter {
3867
3897
if ( isConstExpressionNaN ( module , rightExpr ) || isConstExpressionNaN ( module , leftExpr ) ) {
3868
3898
this . warning (
3869
3899
DiagnosticCode . _NaN_does_not_compare_equal_to_any_other_value_including_itself_Use_isNaN_x_instead ,
3870
- expression . range
3900
+ reportNode . range
3871
3901
) ;
3872
3902
}
3873
3903
if ( isConstNegZero ( rightExpr ) || isConstNegZero ( leftExpr ) ) {
3874
3904
this . warning (
3875
3905
DiagnosticCode . Comparison_with_0_0_is_sign_insensitive_Use_Object_is_x_0_0_if_the_sign_matters ,
3876
- expression . range
3906
+ reportNode . range
3877
3907
) ;
3878
3908
}
3879
3909
}
@@ -3887,10 +3917,10 @@ export class Compiler extends DiagnosticEmitter {
3887
3917
switch ( operator ) {
3888
3918
case Token . Equals_Equals_Equals :
3889
3919
case Token . Equals_Equals :
3890
- return this . makeEq ( leftExpr , rightExpr , commonType , expression ) ;
3920
+ return this . makeEq ( leftExpr , rightExpr , commonType , reportNode ) ;
3891
3921
case Token . Exclamation_Equals_Equals :
3892
3922
case Token . Exclamation_Equals :
3893
- return this . makeNe ( leftExpr , rightExpr , commonType , expression ) ;
3923
+ return this . makeNe ( leftExpr , rightExpr , commonType , reportNode ) ;
3894
3924
default :
3895
3925
assert ( false ) ;
3896
3926
return module . unreachable ( ) ;
0 commit comments