@@ -9666,7 +9666,7 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_
96669666if c.ValueOrNil.Data != nil {
96679667c.ValueOrNil = p.visitExpr(c.ValueOrNil)
96689668p.warnAboutEqualityCheck("case", c.ValueOrNil, c.ValueOrNil.Loc)
9669- p.warnAboutTypeofAndString(s.Test, c.ValueOrNil)
9669+ p.warnAboutTypeofAndString(s.Test, c.ValueOrNil, onlyCheckOriginalOrder )
96709670}
96719671c.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+
1082410837if typeof, ok := a.Data.(*js_ast.EUnary); ok && typeof.Op == js_ast.UnOpTypeof {
1082510838if str, ok := b.Data.(*js_ast.EString); ok {
1082610839value := 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 {
1086410884if 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
1088010901op := 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 {
1088210903op = 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) {
1147811499if a, ok := left.Data.(*js_ast.EBinary); ok && a.Op == op {
1147911500if 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 {
1148511517return 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 {
1149211524return 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}
1216512197p.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
1217812200switch e.Op {
1217912201case js_ast.BinOpComma:
@@ -12200,11 +12222,13 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO
1220012222if !p.warnAboutEqualityCheck("==", e.Left, afterOpLoc) {
1220112223p.warnAboutEqualityCheck("==", e.Right, afterOpLoc)
1220212224}
12203- p.warnAboutTypeofAndString(e.Left, e.Right)
12225+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1220412226
1220512227if 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 {
1220812232e.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
1222112245if !p.warnAboutEqualityCheck("===", e.Left, afterOpLoc) {
1222212246p.warnAboutEqualityCheck("===", e.Right, afterOpLoc)
1222312247}
12224- p.warnAboutTypeofAndString(e.Left, e.Right)
12248+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1222512249
1222612250if 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
1224212266if !p.warnAboutEqualityCheck("!=", e.Left, afterOpLoc) {
1224312267p.warnAboutEqualityCheck("!=", e.Right, afterOpLoc)
1224412268}
12245- p.warnAboutTypeofAndString(e.Left, e.Right)
12269+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1224612270
1224712271if 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 {
1225012276e.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
1226312289if !p.warnAboutEqualityCheck("!==", e.Left, afterOpLoc) {
1226412290p.warnAboutEqualityCheck("!==", e.Right, afterOpLoc)
1226512291}
12266- p.warnAboutTypeofAndString(e.Left, e.Right)
12292+ p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders )
1226712293
1226812294if p.options.minifySyntax {
1226912295// "typeof x !== 'undefined'" => "typeof x != 'undefined'"
0 commit comments