improve compatibility with use strict (#5440)

This commit is contained in:
Alex Lam S.L
2022-05-14 05:15:54 +01:00
committed by GitHub
parent 8946c87011
commit e31bbe329a
6 changed files with 441 additions and 37 deletions

View File

@@ -827,6 +827,9 @@ var AST_Class = DEFNODE("Class", "extends name properties", {
extends: "[AST_Node?] the super class, or null if not specified",
properties: "[AST_ClassProperty*] array of class properties",
},
resolve: function(def_class) {
return def_class ? this : this.parent_scope.resolve();
},
walk: function(visitor) {
var node = this;
visitor.visit(node, function() {
@@ -851,9 +854,6 @@ var AST_DefClass = DEFNODE("DefClass", null, {
$propdoc: {
name: "[AST_SymbolDefClass] the name of this class",
},
resolve: function(def_class) {
return def_class ? this : this.parent_scope.resolve();
},
_validate: function() {
if (!(this.name instanceof AST_SymbolDefClass)) throw new Error("name must be AST_SymbolDefClass");
},
@@ -1837,7 +1837,7 @@ var AST_Label = DEFNODE("Label", "references", {
initialize: function() {
this.references = [];
this.thedef = this;
}
},
}, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
@@ -2039,16 +2039,21 @@ TreeWalker.prototype = {
return this.stack[this.stack.length - 2 - (n || 0)];
},
push: function(node) {
if (node instanceof AST_Lambda) {
var value;
if (node instanceof AST_Class) {
this.directives = Object.create(this.directives);
value = "use strict";
} else if (node instanceof AST_Directive) {
value = node.value;
} else if (node instanceof AST_Lambda) {
this.directives = Object.create(this.directives);
} else if (node instanceof AST_Directive && !this.directives[node.value]) {
this.directives[node.value] = node;
}
if (value && !this.directives[value]) this.directives[value] = node;
this.stack.push(node);
},
pop: function() {
var node = this.stack.pop();
if (node instanceof AST_Lambda) {
if (node instanceof AST_Class || node instanceof AST_Lambda) {
this.directives = Object.getPrototypeOf(this.directives);
}
},

View File

@@ -2552,8 +2552,7 @@ Compressor.prototype.compress = function(node) {
&& all(iife.args, function(arg) {
return !(arg instanceof AST_Spread);
})) {
var fn_strict = compressor.has_directive("use strict");
if (fn_strict && !member(fn_strict, fn.body)) fn_strict = false;
var fn_strict = fn.in_strict_mode() && !fn.parent_scope.resolve(true).in_strict_mode();
var has_await = is_async(fn) ? function(node) {
return node instanceof AST_Symbol && node.name == "await";
} : function(node) {
@@ -4120,6 +4119,25 @@ Compressor.prototype.compress = function(node) {
&& !(compressor && node.expression.has_side_effects(compressor));
}
// in_strict_mode()
// return true if scope executes in Strict Mode
(function(def) {
def(AST_Class, return_this);
def(AST_Scope, function() {
var body = this.body;
for (var i = 0; i < body.length; i++) {
var stat = body[i];
if (!(stat instanceof AST_Directive)) break;
if (stat.value == "use strict") return true;
}
var parent = this.parent_scope;
if (!parent) return false;
return parent.resolve(true).in_strict_mode();
});
})(function(node, func) {
node.DEFMETHOD("in_strict_mode", func);
});
// is_truthy()
// return true if `!!node === true`
(function(def) {
@@ -9882,6 +9900,10 @@ Compressor.prototype.compress = function(node) {
return safe;
}
function safe_from_strict_mode(fn, compressor) {
return fn.in_strict_mode() || !compressor.has_directive("use strict");
}
OPT(AST_Call, function(self, compressor) {
var exp = self.expression;
var terminated = trim_optional_chain(self, compressor);
@@ -10206,7 +10228,10 @@ Compressor.prototype.compress = function(node) {
}
return true;
}) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn, fn.rest));
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
var can_inline = can_drop
&& compressor.option("inline")
&& !self.is_expr_pure(compressor)
&& (exp === fn || safe_from_strict_mode(fn, compressor));
if (can_inline && stat instanceof AST_Return) {
var value = stat.value;
if (exp === fn
@@ -11813,8 +11838,9 @@ Compressor.prototype.compress = function(node) {
} else if (fixed.name && fixed.name.definition() !== def) {
single_use = false;
} else if (fixed.parent_scope !== self.scope || is_funarg(def)) {
single_use = fixed.is_constant_expression(self.scope);
if (single_use == "f") {
if (!safe_from_strict_mode(fixed, compressor)) {
single_use = false;
} else if ((single_use = fixed.is_constant_expression(self.scope)) == "f") {
var scope = self.scope;
do {
if (scope instanceof AST_LambdaDefinition || scope instanceof AST_LambdaExpression) {

View File

@@ -636,8 +636,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
next_token.add_directive = function(directive) {
S.directive_stack[S.directive_stack.length - 1].push(directive);
if (S.directives[directive]) S.directives[directive]++;
else S.directives[directive] = 1;
S.directives[directive] = (S.directives[directive] || 0) + 1;
}
next_token.push_directives_stack = function() {
@@ -1340,8 +1339,6 @@ function parse($TEXT, options) {
var loop = S.in_loop;
var labels = S.labels;
++S.in_function;
S.in_directives = true;
S.input.push_directives_stack();
S.in_loop = 0;
S.labels = [];
if (is("punc", "{")) {
@@ -1352,8 +1349,6 @@ function parse($TEXT, options) {
handle_regexp();
value = maybe_assign();
}
var is_strict = S.input.has_directive("use strict");
S.input.pop_directives_stack();
--S.in_function;
S.in_loop = loop;
S.labels = labels;
@@ -1367,7 +1362,7 @@ function parse($TEXT, options) {
value: value,
end: prev(),
});
if (is_strict) node.each_argname(strict_verify_symbol);
if (S.input.has_directive("use strict")) node.each_argname(strict_verify_symbol);
return node;
}
@@ -1412,7 +1407,7 @@ function parse($TEXT, options) {
name: name,
argnames: argnames,
rest: argnames.rest || null,
body: body
body: body,
});
if (is_strict) {
if (name) strict_verify_symbol(name);