Fix immediately invoked named classes (#4569)

Fixes #4436.
This commit is contained in:
Chris Connelly 2017-06-13 07:11:39 +01:00 committed by Geoffrey Booth
parent 5b7a7779fb
commit 76e70a6c81
3 changed files with 28 additions and 24 deletions

View File

@ -1769,28 +1769,27 @@
} }
compileNode(o) { compileNode(o) {
var assign, executableBody, parentName, result; var executableBody, node, parentName;
this.name = this.determineName(); this.name = this.determineName();
executableBody = this.walkBody(); executableBody = this.walkBody();
if (this.parent instanceof Value && !this.parent.hasProperties()) { if (this.parent instanceof Value && !this.parent.hasProperties()) {
parentName = this.parent.base.value; parentName = this.parent.base.value;
} }
this.hasNameClash = (this.name != null) && this.name === parentName; this.hasNameClash = (this.name != null) && this.name === parentName;
node = this;
if (executableBody || this.hasNameClash) { if (executableBody || this.hasNameClash) {
this.compileNode = this.compileClassDeclaration; node = new ExecutableClassBody(node, executableBody);
result = new ExecutableClassBody(this, executableBody).compileToFragments(o); } else if ((this.name == null) && o.level === LEVEL_TOP) {
this.compileNode = this.constructor.prototype.compileNode; node = new Parens(node);
} else {
result = this.compileClassDeclaration(o);
if ((this.name == null) && o.level === LEVEL_TOP) {
result = this.wrapInParentheses(result);
}
} }
if (this.variable) { if (this.variable) {
assign = new Assign(this.variable, new Literal(''), null, {moduleDeclaration: this.moduleDeclaration}); node = new Assign(this.variable, node, null, {moduleDeclaration: this.moduleDeclaration});
return [...assign.compileToFragments(o), ...result]; }
} else { this.compileNode = this.compileClassDeclaration;
return result; try {
return node.compileToFragments(o);
} finally {
delete this.compileNode;
} }
} }

View File

@ -1300,21 +1300,22 @@ exports.Class = class Class extends Base
parentName = @parent.base.value if @parent instanceof Value and not @parent.hasProperties() parentName = @parent.base.value if @parent instanceof Value and not @parent.hasProperties()
@hasNameClash = @name? and @name is parentName @hasNameClash = @name? and @name is parentName
if executableBody or @hasNameClash node = @
@compileNode = @compileClassDeclaration
result = new ExecutableClassBody(@, executableBody).compileToFragments o
@compileNode = @constructor::compileNode
else
result = @compileClassDeclaration o
if executableBody or @hasNameClash
node = new ExecutableClassBody node, executableBody
else if not @name? and o.level is LEVEL_TOP
# Anonymous classes are only valid in expressions # Anonymous classes are only valid in expressions
result = @wrapInParentheses result if not @name? and o.level is LEVEL_TOP node = new Parens node
if @variable if @variable
assign = new Assign @variable, new Literal(''), null, { @moduleDeclaration } node = new Assign @variable, node, null, { @moduleDeclaration }
[ assign.compileToFragments(o)..., result... ]
else @compileNode = @compileClassDeclaration
result try
return node.compileToFragments o
finally
delete @compileNode
compileClassDeclaration: (o) -> compileClassDeclaration: (o) ->
@ctor ?= @makeDefaultConstructor() if @externalCtor @ctor ?= @makeDefaultConstructor() if @externalCtor

View File

@ -734,6 +734,10 @@ test "#1392 calling `super` in methods defined on namespaced classes", ->
eq 5, (new C.a).m() eq 5, (new C.a).m()
test "#4436 immediately instantiated named class", ->
ok new class Foo
test "dynamic method names", -> test "dynamic method names", ->
class A class A
"#{name = 'm'}": -> 1 "#{name = 'm'}": -> 1