@@ -2807,48 +2807,18 @@ export class Compiler extends DiagnosticEmitter {
28072807
28082808 // Compile the condition (always executes)
28092809 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 ;
28132811
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-
28422812 // Shortcut if there are no cases
28432813 if ( ! numCases ) return module . drop ( condExpr ) ;
28442814
28452815 // Assign the condition to a temporary local as we compare it multiple times
28462816 let outerFlow = this . currentFlow ;
2847- let tempLocal = outerFlow . getTempLocal ( currentType ) ;
2817+ let tempLocal = outerFlow . getTempLocal ( condType ) ;
28482818 let tempLocalIndex = tempLocal . index ;
28492819 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+
28522822 // Make one br_if per labeled case and leave it to Binaryen to optimize the
28532823 // sequence of br_ifs to a br_table according to optimization levels
28542824 let breakIndex = 1 ;
@@ -2860,14 +2830,24 @@ export class Compiler extends DiagnosticEmitter {
28602830 defaultIndex = i ;
28612831 continue ;
28622832 }
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
28702847 ) ;
2848+
2849+ // Add it to the list of breaks
2850+ breaks [ breakIndex ++ ] = module . br ( `case${ i } |${ label } ` , equalityExpr ) ;
28712851 }
28722852
28732853 // If there is a default case, break to it, otherwise break out of the switch
@@ -3819,32 +3799,53 @@ export class Compiler extends DiagnosticEmitter {
38193799 expression : BinaryExpression ,
38203800 contextualType : Type ,
38213801 ) : 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+ }
38253819
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 {
38313837
3832- let operator = expression . operator ;
3838+ let module = this . module ;
38333839 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 ;
38403840
38413841 // check operator overload
38423842 const operatorKind = OperatorKind . fromBinaryToken ( operator ) ;
38433843 const leftOverload = leftType . lookupOverload ( operatorKind , this . program ) ;
38443844 const rightOverload = rightType . lookupOverload ( operatorKind , this . program ) ;
38453845 if ( leftOverload && rightOverload && leftOverload != rightOverload ) {
38463846 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 ,
38483849 operatorString ,
38493850 leftOverload . internalName ,
38503851 rightOverload . internalName
@@ -3857,23 +3858,23 @@ export class Compiler extends DiagnosticEmitter {
38573858 leftOverload ,
38583859 left , leftExpr , leftType ,
38593860 right , rightExpr , rightType ,
3860- expression
3861+ reportNode
38613862 ) ;
38623863 }
38633864 if ( rightOverload ) {
38643865 return this . compileCommutativeBinaryOverload (
38653866 rightOverload ,
38663867 right , rightExpr , rightType ,
38673868 left , leftExpr , leftType ,
3868- expression
3869+ reportNode
38693870 ) ;
38703871 }
38713872 const signednessIsRelevant = false ;
3872- commonType = Type . commonType ( leftType , rightType , contextualType , signednessIsRelevant ) ;
3873+ const commonType = Type . commonType ( leftType , rightType , contextualType , signednessIsRelevant ) ;
38733874 if ( ! commonType ) {
38743875 this . error (
38753876 DiagnosticCode . Operator_0_cannot_be_applied_to_types_1_and_2 ,
3876- expression . range ,
3877+ reportNode . range ,
38773878 operatorString ,
38783879 leftType . toString ( ) ,
38793880 rightType . toString ( )
@@ -3886,13 +3887,13 @@ export class Compiler extends DiagnosticEmitter {
38863887 if ( isConstExpressionNaN ( module , rightExpr ) || isConstExpressionNaN ( module , leftExpr ) ) {
38873888 this . warning (
38883889 DiagnosticCode . _NaN_does_not_compare_equal_to_any_other_value_including_itself_Use_isNaN_x_instead ,
3889- expression . range
3890+ reportNode . range
38903891 ) ;
38913892 }
38923893 if ( isConstNegZero ( rightExpr ) || isConstNegZero ( leftExpr ) ) {
38933894 this . warning (
38943895 DiagnosticCode . Comparison_with_0_0_is_sign_insensitive_Use_Object_is_x_0_0_if_the_sign_matters ,
3895- expression . range
3896+ reportNode . range
38963897 ) ;
38973898 }
38983899 }
@@ -3906,10 +3907,10 @@ export class Compiler extends DiagnosticEmitter {
39063907 switch ( operator ) {
39073908 case Token . Equals_Equals_Equals :
39083909 case Token . Equals_Equals :
3909- return this . makeEq ( leftExpr , rightExpr , commonType , expression ) ;
3910+ return this . makeEq ( leftExpr , rightExpr , commonType , reportNode ) ;
39103911 case Token . Exclamation_Equals_Equals :
39113912 case Token . Exclamation_Equals :
3912- return this . makeNe ( leftExpr , rightExpr , commonType , expression ) ;
3913+ return this . makeNe ( leftExpr , rightExpr , commonType , reportNode ) ;
39133914 default :
39143915 assert ( false ) ;
39153916 return module . unreachable ( ) ;
0 commit comments