function assert(b) { if (!b) throw new Error("Bad assertion") } function shouldBeSyntaxError(str) { let failed = true; try { new Function(str); } catch(e) { if (e instanceof SyntaxError) failed = false; } if (failed) throw new Error("Did not throw syntax error: " + str); } function shouldNotBeSyntaxError(str) { let failed = false; try { new Function(str); } catch(e) { if (e instanceof SyntaxError && e.message.indexOf("new.target") !== -1) failed = true; } if (failed) throw new Error("Did throw a syntax error: " + str); } let operators = ["=", "+=", "-=", "*=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "%="]; for (let operator of operators) { let functionBody = `new.target ${operator} 20`; shouldBeSyntaxError(functionBody); functionBody = `foo = new.target ${operator} 20`; shouldBeSyntaxError(functionBody); functionBody = `foo ${operator} new.target ${operator} 20`; shouldBeSyntaxError(functionBody); functionBody = `new.target ${operator} foo *= 40`; shouldBeSyntaxError(functionBody); // Make sure our tests cases our sound and they should not be syntax errors if new.target is replaced by foo functionBody = `foo ${operator} 20`; shouldNotBeSyntaxError(functionBody); functionBody = `foo = foo ${operator} 20`; shouldNotBeSyntaxError(functionBody); functionBody = `foo ${operator} foo ${operator} 20`; shouldNotBeSyntaxError(functionBody); functionBody = `foo ${operator} foo *= 40`; shouldNotBeSyntaxError(functionBody); } let prePostFixOperators = ["++", "--"]; for (let operator of prePostFixOperators) { let functionBody = `${operator}new.target`; shouldBeSyntaxError(functionBody); functionBody = `foo = ${operator}new.target`; shouldBeSyntaxError(functionBody); functionBody = `${operator}foo`; shouldNotBeSyntaxError(functionBody); functionBody = `foo = ${operator}foo`; shouldNotBeSyntaxError(functionBody); } for (let operator of prePostFixOperators) { let functionBody = `new.target${operator}`; shouldBeSyntaxError(functionBody); functionBody = `foo = new.target${operator}`; shouldBeSyntaxError(functionBody); functionBody = `foo${operator}`; shouldNotBeSyntaxError(functionBody); functionBody = `foo = foo${operator}`; shouldNotBeSyntaxError(functionBody); } let otherUnaryOperators = ["!", "~", "+", "-", "typeof ", "void ", "delete "]; for (let operator of otherUnaryOperators) { function strict(body) { return `"use strict" ${body}`; } let functionBody = `${operator}new.target`; shouldNotBeSyntaxError(functionBody); shouldNotBeSyntaxError(strict(functionBody)); } shouldBeSyntaxError(`({foo: new.target} = {foo:20})`); // Scripts - 15.1.1 Static Semantics: Early Errors // https://tc39.github.io/ecma262/#sec-scripts-static-semantics-early-errors // // Modules - 15.2.1.1 Static Semantics: Early Errors // https://tc39.github.io/ecma262/#sec-module-semantics-static-semantics-early-errors // // new.target is not allowed in arrow functions in global scope. let sawSyntaxError; sawSyntaxError = false; try { eval(`() => new.target`); } catch(e) { sawSyntaxError = e instanceof SyntaxError; } assert(sawSyntaxError); sawSyntaxError = false; try { eval(`() => { new.target }`); } catch(e) { sawSyntaxError = e instanceof SyntaxError; } assert(sawSyntaxError); sawSyntaxError = false; try { eval(`async () => new.target`); } catch(e) { sawSyntaxError = e instanceof SyntaxError; } assert(sawSyntaxError); sawSyntaxError = false; try { eval(`async () => { new.target }`); } catch(e) { sawSyntaxError = e instanceof SyntaxError; } assert(sawSyntaxError); sawSyntaxError = false; try { eval(`async () => await new.target`); } catch(e) { sawSyntaxError = e instanceof SyntaxError; } assert(sawSyntaxError); sawSyntaxError = false; try { eval(`async () => { await new.target }`); } catch(e) { sawSyntaxError = e instanceof SyntaxError; } assert(sawSyntaxError); let sawError = false; try { new Function(`() => new.target`); new Function(`() => { new.target }`); new Function(`async () => new.target`); new Function(`async () => { new.target }`); new Function(`async () => await new.target`); new Function(`async () => { await new.target }`); function f() { () => new.target }; function f() { () => { new.target } }; function f() { async () => new.target }; function f() { async () => { new.target } }; function f() { async () => await new.target }; function f() { async () => { await new.target } }; (function() { eval(`() => new.target`) })(); (function() { eval(`() => { new.target }`) })(); (function() { eval(`async () => new.target`) })(); (function() { eval(`async () => { new.target }`) })(); (function() { eval(`async () => await new.target`) })(); (function() { eval(`async () => { await new.target }`) })(); } catch (e) { sawError = true; } assert(!sawError);