@@ -9666,7 +9666,7 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_
96669666 if c.ValueOrNil.Data != nil {
96679667 c.ValueOrNil = p.visitExpr(c.ValueOrNil)
96689668 p.warnAboutEqualityCheck("case", c.ValueOrNil, c.ValueOrNil.Loc)
9669- p.warnAboutTypeofAndString(s.Test, c.ValueOrNil)
9669+ p.warnAboutTypeofAndString(s.Test, c.ValueOrNil, onlyCheckOriginalOrder )
96709670 }
96719671 c.Body = p.visitStmts(c.Body, stmtsNormal)
96729672
@@ -10820,7 +10820,20 @@ func (p *parser) checkForUnrepresentableIdentifier(loc logger.Loc, name string)
1082010820 }
1082110821}
1082210822
10823- func (p *parser) warnAboutTypeofAndString(a js_ast.Expr, b js_ast.Expr) {
10823+ type typeofStringOrder uint8
10824+
10825+ const (
10826+ onlyCheckOriginalOrder typeofStringOrder = iota
10827+ checkBothOrders
10828+ )
10829+
10830+ func (p *parser) warnAboutTypeofAndString(a js_ast.Expr, b js_ast.Expr, order typeofStringOrder) {
10831+ if order == checkBothOrders {
10832+ if _, ok := a.Data.(*js_ast.EString); ok {
10833+ a, b = b, a
10834+ }
10835+ }
10836+
1082410837 if typeof, ok := a.Data.(*js_ast.EUnary); ok && typeof.Op == js_ast.UnOpTypeof {
1082510838 if str, ok := b.Data.(*js_ast.EString); ok {
1082610839 value := helpers.UTF16ToString(str.Value)
@@ -10856,15 +10869,22 @@ func canChangeStrictToLoose(a js_ast.Expr, b js_ast.Expr) bool {
1085610869}
1085710870
1085810871func (p *parser) maybeSimplifyEqualityComparison(loc logger.Loc, e *js_ast.EBinary) (js_ast.Expr, bool) {
10872+ value, primitive := e.Left, e.Right
10873+
10874+ // Detect when the primitive comes first and flip the order of our checks
10875+ if isPrimitiveLiteral(value.Data) {
10876+ value, primitive = primitive, value
10877+ }
10878+
1085910879 // "!x === true" => "!x"
1086010880 // "!x === false" => "!!x"
1086110881 // "!x !== true" => "!!x"
1086210882 // "!x !== false" => "!x"
10863- if boolean, ok := e.Right. Data.(*js_ast.EBoolean); ok && js_ast.KnownPrimitiveType(e.Left ) == js_ast.PrimitiveBoolean {
10883+ if boolean, ok := primitive. Data.(*js_ast.EBoolean); ok && js_ast.KnownPrimitiveType(value ) == js_ast.PrimitiveBoolean {
1086410884 if boolean.Value == (e.Op == js_ast.BinOpLooseNe || e.Op == js_ast.BinOpStrictNe) {
10865- return js_ast.Not(e.Left ), true
10885+ return js_ast.Not(value ), true
1086610886 } else {
10867- return e.Left , true
10887+ return value , true
1086810888 }
1086910889 }
1087010890
@@ -10875,17 +10895,18 @@ func (p *parser) maybeSimplifyEqualityComparison(loc logger.Loc, e *js_ast.EBina
1087510895 // return something random. The only case of this happening was Internet
1087610896 // Explorer returning "unknown" for some objects, which messes with this
1087710897 // optimization. So we don't do this when targeting Internet Explorer.
10878- if typeof, ok := e.Left.Data.(*js_ast.EUnary); ok && typeof.Op == js_ast.UnOpTypeof {
10879- if str, ok := e.Right.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "undefined") {
10898+ if typeof, ok := value.Data.(*js_ast.EUnary); ok && typeof.Op == js_ast.UnOpTypeof {
10899+ if str, ok := primitive.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "undefined") {
10900+ flip := value == e.Right
1088010901 op := js_ast.BinOpLt
10881- if e.Op == js_ast.BinOpLooseEq || e.Op == js_ast.BinOpStrictEq {
10902+ if ( e.Op == js_ast.BinOpLooseEq || e.Op == js_ast.BinOpStrictEq) != flip {
1088210903 op = js_ast.BinOpGt
1088310904 }
10884- return js_ast.Expr{Loc: loc, Data: &js_ast.EBinary{
10885- Op: op,
10886- Left: e.Left,
10887- Right: js_ast.Expr{Loc: e.Right.Loc, Data: &js_ast.EString{Value: []uint16{'u'}}},
10888- }}, true
10905+ primitive. Data = &js_ast.EString{Value: []uint16{'u'}}
10906+ if flip {
10907+ value, primitive = primitive, value
10908+ }
10909+ return js_ast.Expr{Loc: loc, Data: &js_ast.EBinary{Op: op, Left: value, Right: primitive }}, true
1088910910 }
1089010911 }
1089110912 }
@@ -11477,18 +11498,29 @@ func stringToEquivalentNumberValue(value []uint16) (float64, bool) {
1147711498func isBinaryNullAndUndefined(left js_ast.Expr, right js_ast.Expr, op js_ast.OpCode) (js_ast.Expr, js_ast.Expr, bool) {
1147811499 if a, ok := left.Data.(*js_ast.EBinary); ok && a.Op == op {
1147911500 if b, ok := right.Data.(*js_ast.EBinary); ok && b.Op == op {
11480- if idA, ok := a.Left.Data.(*js_ast.EIdentifier); ok {
11481- if idB, ok := b.Left.Data.(*js_ast.EIdentifier); ok && idA.Ref == idB.Ref {
11501+ idA, eqA := a.Left, a.Right
11502+ idB, eqB := b.Left, b.Right
11503+
11504+ // Detect when the identifier comes second and flip the order of our checks
11505+ if _, ok := eqA.Data.(*js_ast.EIdentifier); ok {
11506+ idA, eqA = eqA, idA
11507+ }
11508+ if _, ok := eqB.Data.(*js_ast.EIdentifier); ok {
11509+ idB, eqB = eqB, idB
11510+ }
11511+
11512+ if idA, ok := idA.Data.(*js_ast.EIdentifier); ok {
11513+ if idB, ok := idB.Data.(*js_ast.EIdentifier); ok && idA.Ref == idB.Ref {
1148211514 // "a === null || a === void 0"
11483- if _, ok := a.Right .Data.(*js_ast.ENull); ok {
11484- if _, ok := b.Right .Data.(*js_ast.EUndefined); ok {
11515+ if _, ok := eqA .Data.(*js_ast.ENull); ok {
11516+ if _, ok := eqB .Data.(*js_ast.EUndefined); ok {
1148511517 return a.Left, a.Right, true
1148611518 }
1148711519 }
1148811520
1148911521 // "a === void 0 || a === null"
11490- if _, ok := a.Right .Data.(*js_ast.EUndefined); ok {
11491- if _, ok := b.Right .Data.(*js_ast.ENull); ok {
11522+ if _, ok := eqA .Data.(*js_ast.EUndefined); ok {
11523+ if _, ok := eqB .Data.(*js_ast.ENull); ok {
1149211524 return b.Left, b.Right, true
1149311525 }
1149411526 }
@@ -12164,16 +12196,6 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1216412196 }
1216512197 p.fnOnlyDataVisit.silenceWarningAboutThisBeingUndefined = oldSilenceWarningAboutThisBeingUndefined
1216612198
12167- // Always put constants on the right for equality comparisons to help
12168- // reduce the number of cases we have to check during pattern matching. We
12169- // can only reorder expressions that do not have any side effects.
12170- switch e.Op {
12171- case js_ast.BinOpLooseEq, js_ast.BinOpLooseNe, js_ast.BinOpStrictEq, js_ast.BinOpStrictNe:
12172- if isPrimitiveLiteral(e.Left.Data) && !isPrimitiveLiteral(e.Right.Data) {
12173- e.Left, e.Right = e.Right, e.Left
12174- }
12175- }
12176-
1217712199 // Post-process the binary expression
1217812200 switch e.Op {
1217912201 case js_ast.BinOpComma:
@@ -12200,11 +12222,13 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1220012222 if !p.warnAboutEqualityCheck("==", e.Left, afterOpLoc) {
1220112223 p.warnAboutEqualityCheck("==", e.Right, afterOpLoc)
1220212224 }
12203- p.warnAboutTypeofAndString(e.Left, e.Right)
12225+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1220412226
1220512227 if p.options.minifySyntax {
1220612228 // "x == void 0" => "x == null"
12207- if _, ok := e.Right.Data.(*js_ast.EUndefined); ok {
12229+ if _, ok := e.Left.Data.(*js_ast.EUndefined); ok {
12230+ e.Left.Data = js_ast.ENullShared
12231+ } else if _, ok := e.Right.Data.(*js_ast.EUndefined); ok {
1220812232 e.Right.Data = js_ast.ENullShared
1220912233 }
1221012234
@@ -12221,7 +12245,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1222112245 if !p.warnAboutEqualityCheck("===", e.Left, afterOpLoc) {
1222212246 p.warnAboutEqualityCheck("===", e.Right, afterOpLoc)
1222312247 }
12224- p.warnAboutTypeofAndString(e.Left, e.Right)
12248+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1222512249
1222612250 if p.options.minifySyntax {
1222712251 // "typeof x === 'undefined'" => "typeof x == 'undefined'"
@@ -12242,11 +12266,13 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1224212266 if !p.warnAboutEqualityCheck("!=", e.Left, afterOpLoc) {
1224312267 p.warnAboutEqualityCheck("!=", e.Right, afterOpLoc)
1224412268 }
12245- p.warnAboutTypeofAndString(e.Left, e.Right)
12269+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1224612270
1224712271 if p.options.minifySyntax {
1224812272 // "x != void 0" => "x != null"
12249- if _, ok := e.Right.Data.(*js_ast.EUndefined); ok {
12273+ if _, ok := e.Left.Data.(*js_ast.EUndefined); ok {
12274+ e.Left.Data = js_ast.ENullShared
12275+ } else if _, ok := e.Right.Data.(*js_ast.EUndefined); ok {
1225012276 e.Right.Data = js_ast.ENullShared
1225112277 }
1225212278
@@ -12263,7 +12289,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1226312289 if !p.warnAboutEqualityCheck("!==", e.Left, afterOpLoc) {
1226412290 p.warnAboutEqualityCheck("!==", e.Right, afterOpLoc)
1226512291 }
12266- p.warnAboutTypeofAndString(e.Left, e.Right)
12292+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1226712293
1226812294 if p.options.minifySyntax {
1226912295 // "typeof x !== 'undefined'" => "typeof x != 'undefined'"
0 commit comments