1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

[CS2] Compile all super calls to ES2015 super (#4424)

* Compile all super calls to ES2015 super

This breaks using `super` in non-methods, meaning several tests are
failing. Self-compilation still works.

* Use bound functions for IIFEs containing `super`

`super` can only be called directly in a method, or in an arrow
function.

* Fix handling of `class @A extends A`

This behaviour worked 'for free' when the parent reference was being
cached by the executable class body wrapper. There now needs to be
special handling in place to check if the parent name matches the class
name, and if so to cache the parent reference.

* Fix tests broken by compiling ES2015 `super`

* Disallow bare super

This removes syntax support for 'bare' super calls, e.g.:

    class B extends A
      constructor: -> super

`super` must now always be followed with arguments like a regular
function call. This also removes the capability of implicitly forwarding
arguments. The above can be equivalently be written as:

    class B extends A
      constructor: -> super arguments...

* Support super with accessors

`super` with following accessor(s) is now compiled to ES2015
equivalents. In particular, expressions such as `super.name`,
`super[name]`, and also `super.name.prop` are all now valid, and can be
used as expected as calls (i.e. `super.name()`) or in expressions (i.e.
`if super.name? ...`).

`super` without accessors is compiled to a constructor super call in a
constructor, and otherwise, as before, to a super call to the method of
the same name, i.e.

    speak: -> super()

...is equivalent to

    speak: -> super.speak()

A neat side-effect of the changes is that existential calls now work
properly with super, meaning `super?()` will only call if the super
property exists (and is a function). This is not valid for super in
constructors.

* Prevent calling `super` methods with `new`

This fixes a bug in the previous super handling whereby using the `new`
operator with a `super` call would silently drop the `new`. This is now
an explicit compiler error, as it is invalid JS at runtime.

* Clean up some old super handling code

This was mostly code for tracking the source classes and variables for
methods, which were needed to build the old lookups on `__super__`.

* Add TODO to improve bare super parse error

* Add some TODOs to improve some of the class tests
This commit is contained in:
Chris Connelly 2017-02-04 20:03:17 +00:00 committed by Geoffrey Booth
parent cbea7b5d1c
commit 396bd4f2f2
11 changed files with 710 additions and 1024 deletions

View file

@ -235,7 +235,14 @@
return new Value($1);
}), o('Range', function() {
return new Value($1);
}), o('This')
}), o('This'), o('Super')
],
Super: [
o('SUPER . Property', function() {
return new Super(LOC(3)(new Access($3)));
}), o('SUPER INDEX_START Expression INDEX_END', function() {
return new Super(LOC(3)(new Index($3)));
})
],
Accessor: [
o('. Property', function() {
@ -412,13 +419,8 @@
return new Call($1, $3, $2);
}), o('Invocation OptFuncExist Arguments', function() {
return new Call($1, $3, $2);
}), o('Super')
],
Super: [
o('SUPER', function() {
return new SuperCall;
}), o('SUPER Arguments', function() {
return new SuperCall($2);
}), o('SUPER OptFuncExist Arguments', function() {
return new SuperCall(LOC(1)(new Super), $3, $2);
})
],
OptFuncExist: [

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -309,6 +309,13 @@ grammar =
o 'Parenthetical', -> new Value $1
o 'Range', -> new Value $1
o 'This'
o 'Super'
]
# A `super`-based expression that can be used as a value.
Super: [
o 'SUPER . Property', -> new Super LOC(3) new Access $3
o 'SUPER INDEX_START Expression INDEX_END', -> new Super LOC(3) new Index $3
]
# The general group of accessors into an object, by property, by prototype
@ -429,12 +436,7 @@ grammar =
o 'Value OptFuncExist String', -> new TaggedTemplateCall $1, $3, $2
o 'Value OptFuncExist Arguments', -> new Call $1, $3, $2
o 'Invocation OptFuncExist Arguments', -> new Call $1, $3, $2
o 'Super'
]
Super: [
o 'SUPER', -> new SuperCall
o 'SUPER Arguments', -> new SuperCall $2
o 'SUPER OptFuncExist Arguments', -> new SuperCall LOC(1)(new Super), $3, $2
]
# An optional existence check on a function.

View file

@ -81,7 +81,9 @@ exports.Base = class Base
o.sharedScope = yes
func = new Code [], Block.wrap [this]
args = []
if (argumentsNode = @contains isLiteralArguments) or @contains isLiteralThis
if @contains ((node) -> node instanceof SuperCall)
func.bound = yes
else if (argumentsNode = @contains isLiteralArguments) or @contains isLiteralThis
args = [new ThisLiteral]
if argumentsNode
meth = 'apply'
@ -516,7 +518,7 @@ exports.Literal = class Literal extends Base
[@makeCode @value]
toString: ->
" #{if @isStatement() then super else @constructor.name}: #{@value}"
" #{if @isStatement() then super() else @constructor.name}: #{@value}"
exports.NumberLiteral = class NumberLiteral extends Literal
@ -610,14 +612,14 @@ exports.YieldReturn = class YieldReturn extends Return
compileNode: (o) ->
unless o.scope.parent?
@error 'yield can only occur inside functions'
super
super o
exports.AwaitReturn = class AwaitReturn extends Return
compileNode: (o) ->
unless o.scope.parent?
@error 'await can only occur inside functions'
super
super o
#### Value
@ -780,9 +782,10 @@ exports.Call = class Call extends Base
# Soaked chained invocations unfold into if/else ternary structures.
unfoldSoak: (o) ->
if @soak
if this instanceof SuperCall
left = new Literal @superReference o
if @variable instanceof Super
left = new Literal @variable.compile o
rite = new Value left
@variable.error "Unsupported reference to 'super'" unless @variable.accessor?
else
return ifn if ifn = unfoldSoak o, this, 'variable'
[left, rite] = new Value(@variable).cacheReference o
@ -818,20 +821,11 @@ exports.Call = class Call extends Base
compiledArgs.push (arg.compileToFragments o, LEVEL_LIST)...
fragments = []
if this instanceof SuperCall
preface = @superReference o
if preface is 'super'
preface += '('
else
preface += ".call(#{@superThis(o)}"
if compiledArgs.length then preface += ", "
fragments.push @makeCode preface
else
if @isNew then fragments.push @makeCode 'new '
fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
fragments.push @makeCode "("
fragments.push compiledArgs...
fragments.push @makeCode ")"
if @isNew
@variable.error "Unsupported reference to 'super'" if @variable instanceof Super
fragments.push @makeCode 'new '
fragments.push @variable.compileToFragments(o, LEVEL_ACCESS)...
fragments.push @makeCode('('), compiledArgs..., @makeCode(')')
fragments
#### Super
@ -842,20 +836,15 @@ exports.Call = class Call extends Base
# expressions are evaluated without altering the return value of the `SuperCall`
# expression.
exports.SuperCall = class SuperCall extends Call
children: ['expressions']
constructor: (args) ->
super null, args ? [new Splat new IdentifierLiteral 'arguments']
# Allow to recognize a bare `super` call without parentheses and arguments.
@isBare = args?
children: Call::children.concat ['expressions']
isStatement: (o) ->
@expressions?.length and o.level is LEVEL_TOP
compileNode: (o) ->
return super unless @expressions?.length
return super o unless @expressions?.length
superCall = new Literal fragmentsToText super
superCall = new Literal fragmentsToText super o
replacement = new Block @expressions.slice()
if o.level > LEVEL_TOP
@ -866,33 +855,26 @@ exports.SuperCall = class SuperCall extends Call
replacement.unshift superCall
replacement.compileToFragments o, if o.level is LEVEL_TOP then o.level else LEVEL_LIST
# Grab the reference to the superclass's implementation of the current
# method.
superReference: (o) ->
exports.Super = class Super extends Base
children: ['accessor']
constructor: (@accessor) ->
super()
compileNode: (o) ->
method = o.scope.namedMethod()
if method?.ctor
'super'
else if method?.klass
{klass, name, variable} = method
if klass.shouldCache()
bref = new IdentifierLiteral o.scope.parent.freeVariable 'base'
base = new Value new Parens new Assign bref, klass
variable.base = base
variable.properties.splice 0, klass.properties.length
@error 'cannot use super outside of an instance method' unless method?.isMethod
@inCtor = !!method.ctor
unless @inCtor or @accessor?
{name, variable} = method
if name.shouldCache() or (name instanceof Index and name.index.isAssignable())
nref = new IdentifierLiteral o.scope.parent.freeVariable 'name'
name.index = new Assign nref, name.index
accesses = [new Access new PropertyName '__super__']
accesses.push new Access new PropertyName 'constructor' if method.isStatic
accesses.push if nref? then new Index nref else name
(new Value bref ? klass, accesses).compile o
else
@error 'cannot call super outside of an instance method.'
@accessor = if nref? then new Index nref else name
# The appropriate `this` value for a `super` call.
superThis : (o) ->
method = o.scope.method
(method and not method.klass and method.context) or "this"
(new Value (new Literal 'super'), if @accessor then [ @accessor ] else []).compileToFragments o
#### RegexWithInterpolations
@ -1195,7 +1177,11 @@ exports.Class = class Class extends Base
@name = @determineName()
executableBody = @walkBody()
if executableBody
# Special handling to allow `class expr.A extends A` declarations
parentName = @parent.base.value if @parent instanceof Value and not @parent.hasProperties()
@hasNameClash = @name? and @name == parentName
if executableBody or @hasNameClash
@compileNode = @compileClassDeclaration
result = new ExecutableClassBody(@, executableBody).compileToFragments o
@compileNode = @constructor::compileNode
@ -1302,8 +1288,7 @@ exports.Class = class Class extends Base
@boundMethods.push method.name
method.bound = false
# TODO Once `super` has been changed over to ES, the check for @parent can be removed
if @parent or initializer.length != expressions.length
if initializer.length != expressions.length
@body.expressions = (expression.hoist() for expression in initializer)
new Block expressions
@ -1328,18 +1313,16 @@ exports.Class = class Class extends Base
# Returns a configured class initializer method
addInitializerMethod: (assign) ->
variable = assign.variable
method = assign.value
{ variable, value: method } = assign
method.isMethod = yes
method.isStatic = variable.looksStatic @name
method.klass = new IdentifierLiteral @name
method.variable = variable
if method.isStatic
method.name = variable.properties[0]
else
methodName = variable.base
method.name = new (if methodName.shouldCache() then Index else Access) methodName
method.name.updateLocationDataIfMissing methodName.locationData
method.ctor = (if @parent then 'derived' else 'base') if methodName.value is 'constructor'
method.error 'Cannot define a constructor as a bound function' if method.bound and method.ctor
@ -1349,7 +1332,8 @@ exports.Class = class Class extends Base
ctor = @addInitializerMethod new Assign (new Value new PropertyName 'constructor'), new Code
@body.unshift ctor
ctor.body.push new SuperCall if @parent
if @parent
ctor.body.push new SuperCall new Super, [new Splat new IdentifierLiteral 'arguments']
if @externalCtor
applyCtor = new Value @externalCtor, [ new Access new PropertyName 'apply' ]
@ -1394,19 +1378,17 @@ exports.ExecutableClassBody = class ExecutableClassBody extends Base
o.classScope = wrapper.makeScope o.scope
if @class.hasNameClash
parent = new IdentifierLiteral o.classScope.freeVariable 'superClass'
wrapper.params.push new Param parent
args.push @class.parent
@class.parent = parent
if @externalCtor
externalCtor = new IdentifierLiteral o.classScope.freeVariable 'ctor', reserve: no
@class.externalCtor = externalCtor
@externalCtor.variable.base = externalCtor
if @class.parent
parent = new IdentifierLiteral o.classScope.freeVariable 'superClass', reserve: no
params.push new Param parent
args.push @class.parent
@class.parent = parent
@body.unshift new Literal "#{@name}.__super__ = #{parent.value}.prototype"
if @name != @class.name
@body.expressions.unshift new Assign (new IdentifierLiteral @name), @class
else
@ -1442,8 +1424,6 @@ exports.ExecutableClassBody = class ExecutableClassBody extends Base
child.expressions[i] = @addProperties node.base.properties
else if node instanceof Assign and node.variable.looksStatic @name
node.value.isStatic = yes
else if node instanceof Code and node.isMethod
node.klass = new IdentifierLiteral @name
child.expressions = flatten child.expressions
cont
@ -1670,15 +1650,10 @@ exports.Assign = class Assign extends Base
return @compileSpecialMath o if @context in ['**=', '//=', '%%=']
if @value instanceof Code
if @value.isStatic
@value.klass = @variable.base
@value.name = @variable.properties[0]
@value.variable = @variable
@value.name = @variable.properties[0]
else if @variable.properties?.length >= 2
[properties..., prototype, name] = @variable.properties
if prototype.name?.value is 'prototype'
@value.klass = new Value @variable.base, properties
@value.name = name
@value.variable = @variable
@value.name = name if prototype.name?.value is 'prototype'
unless @context
varBase = @variable.unwrapAll()
unless varBase.isAssignable()
@ -1904,8 +1879,8 @@ exports.Code = class Code extends Base
# function body.
compileNode: (o) ->
if @ctor
@variable.error 'Class constructor may not be async' if @isAsync
@variable.error 'Class constructor may not be a generator' if @isGenerator
@name.error 'Class constructor may not be async' if @isAsync
@name.error 'Class constructor may not be a generator' if @isGenerator
if @bound
@context = o.scope.method.context if o.scope.method?.bound
@ -2263,7 +2238,7 @@ exports.While = class While extends Base
makeReturn: (res) ->
if res
super
super res
else
@returns = not @jumps loop: yes
this
@ -2985,7 +2960,6 @@ UTILITIES =
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
}
"
@ -3052,9 +3026,7 @@ isLiteralArguments = (node) ->
node instanceof IdentifierLiteral and node.value is 'arguments'
isLiteralThis = (node) ->
node instanceof ThisLiteral or
(node instanceof Code and node.bound) or
node instanceof SuperCall
node instanceof ThisLiteral or (node instanceof Code and node.bound)
shouldCacheOrIsAssignable = (node) -> node.shouldCache() or node.isAssignable?()

View file

@ -40,13 +40,6 @@ test "classes with a four-level inheritance chain", ->
ok result is 'zero/one/two/three/four'
ok Base.static('word') is 'static/word'
FirstChild::func = (string) ->
super('one/').length + string
result = (new ThirdChild).func 'four'
ok result is '9two/three/four'
ok (new ThirdChild).array.join(' ') is '1 2 3'
@ -69,56 +62,46 @@ test "constructors with inheritance and super", ->
ok (new SubClass).prop is 'top-super-sub'
test "basic classes, again, but in the manual prototype style", ->
test "'super' with accessors", ->
class Base
m: -> 4
n: -> 5
o: -> 6
Base = ->
Base::func = (string) ->
'zero/' + string
Base::['func-func'] = (string) ->
"dynamic-#{string}"
name = 'o'
class A extends Base
m: -> super()
n: -> super.n()
"#{name}": -> super()
p: -> super[name]()
FirstChild = ->
SecondChild = ->
ThirdChild = ->
@array = [1, 2, 3]
this
ThirdChild extends SecondChild extends FirstChild extends Base
FirstChild::func = (string) ->
super('one/') + string
SecondChild::func = (string) ->
super('two/') + string
ThirdChild::func = (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
a = new A
eq 4, a.m()
eq 5, a.n()
eq 6, a.o()
eq 6, a.p()
test "super with plain ol' prototypes", ->
test "soaked 'super' invocation", ->
class Base
method: -> 2
TopClass = ->
TopClass::func = (arg) ->
'top-' + arg
class A extends Base
method: -> super?()
noMethod: -> super?()
SuperClass = ->
SuperClass extends TopClass
SuperClass::func = (arg) ->
super 'super-' + arg
a = new A
eq 2, a.method()
eq undefined, a.noMethod()
SubClass = ->
SubClass extends SuperClass
SubClass::func = ->
super 'sub'
eq (new SubClass).func(), 'top-super-sub'
name = 'noMethod'
class B extends Base
"#{'method'}": -> super?()
"#{'noMethod'}": -> super?() ? super['method']()
b = new B
eq 2, b.method()
eq 2, b.noMethod()
test "'@' referring to the current instance, and not being coerced into a call", ->
@ -136,7 +119,7 @@ test "super() calls in constructors of classes that are defined as object proper
constructor: (name) -> @name = name
class Hive.Bee extends Hive
constructor: (name) -> super
constructor: (name) -> super name
maya = new Hive.Bee 'Maya'
ok maya.name is 'Maya'
@ -210,7 +193,7 @@ test "calling super and passing along all arguments", ->
method: (args...) -> @args = args
class Child extends Parent
method: -> super
method: -> super arguments...
c = new Child
c.method 1, 2, 3, 4
@ -421,7 +404,7 @@ test "`class extends this`", ->
B = null
makeClass = ->
B = class extends this
func: -> super + ' B'
func: -> super() + ' B'
makeClass.call A
@ -483,7 +466,7 @@ test "#1313: misplaced __extends", ->
class A
class B extends A
prop: nonce
constructor: -> super
constructor: -> super()
eq nonce, B::prop
test "#1182: execution order needs to be considered as well", ->
@ -510,11 +493,11 @@ test "#1372: bound class methods with reserved names", ->
test "#1380: `super` with reserved names", ->
class C
do: -> super
do: -> super()
ok C::do
class B
0: -> super
0: -> super()
ok B::[0]
test "#1464: bound class methods should keep context", ->
@ -550,7 +533,7 @@ test "#1598: super works for static methods too", ->
class Child extends Parent
@method: ->
'pass? ' + super
'pass? ' + super()
eq Child.method(), 'pass? yes'
@ -732,7 +715,7 @@ test "extending native objects works with and without defining a constructor", -
ok 'yes!', myArray.method()
class OverrideArray extends Array
constructor: -> super
constructor: -> super()
method: -> 'yes!'
overrideArray = new OverrideArray
@ -802,7 +785,7 @@ test "#2949: super in static method with reserved name", ->
@static: -> 'baz'
class Bar extends Foo
@static: -> super
@static: -> super()
eq Bar.static(), 'baz'
@ -812,8 +795,8 @@ test "#3232: super in static methods (not object-assigned)", ->
@qux = -> true
class Bar extends Foo
@baz = -> super
Bar.qux = -> super
@baz = -> super()
Bar.qux = -> super()
ok Bar.baz()
ok Bar.qux()
@ -825,24 +808,17 @@ test "#1392 calling `super` in methods defined on namespaced classes", ->
namespace =
A: ->
B: ->
namespace.A extends Base
class namespace.A extends Base
m: -> super()
namespace.A::m = -> super
eq 5, (new namespace.A).m()
namespace.B::m = namespace.A::m
namespace.A::m = null
eq 5, (new namespace.B).m()
count = 0
getNamespace = -> count++; namespace
getNamespace().A::n = -> super
eq 4, (new namespace.A).n()
eq 1, count
class C
@a: (->)
@a extends Base
@a::m = -> super
@a: class extends Base
m: -> super()
eq 5, (new C.a).m()
@ -852,7 +828,7 @@ test "dynamic method names", ->
eq 1, new A().m()
class B extends A
"#{name = 'm'}": -> super
"#{name = 'm'}": -> super()
eq 1, new B().m()
getName = -> 'm'
@ -867,18 +843,18 @@ test "dynamic method names and super", ->
m: -> 5
m2: -> 4.5
n: -> 4
A = ->
A extends Base
name = -> count++; 'n'
count = 0
m = 'm'
A::[m] = -> super
class A extends Base
"#{m}": -> super()
"#{name()}": -> super()
m = 'n'
eq 5, (new A).m()
name = -> count++; 'n'
count = 0
A::[name()] = -> super
eq 4, (new A).n()
eq 1, count
@ -886,9 +862,9 @@ test "dynamic method names and super", ->
m2 = 'm2'
count = 0
class B extends Base
@[name()] = -> super
@::[m] = -> super
"#{m2}": -> super
@[name()] = -> super()
"#{m}": -> super()
"#{m2}": -> super()
b = new B
m = m2 = 'n'
eq 6, B.m()
@ -897,7 +873,7 @@ test "dynamic method names and super", ->
eq 1, count
class C extends B
m: -> super
m: -> super()
eq 5, (new C).m()
# ES2015+ class interoperability
@ -1066,11 +1042,16 @@ test "`@`-params and bound methods with multiple `super` paths (expressions)", -
test "constructor super in arrow functions", ->
class Test extends (class)
constructor: (@param) ->
do => super
do => super()
eq @param, nonce
new Test nonce = {}
# TODO Some of these tests use CoffeeScript.compile and CoffeeScript.run when they could use
# regular test mechanics.
# TODO Some of these tests might be better placed in `test/error_messages.coffee`.
# TODO Some of these tests are duplicates.
# Ensure that we always throw if we experience more than one super()
# call in a constructor. This ends up being a runtime error.
# Should be caught at compile time.
@ -1230,24 +1211,6 @@ test "super and external constructors", ->
throws -> CoffeeScript.compile throwsC, bare: yes
test "super in external prototype", ->
class A
constructor: (@drink) ->
make: -> "Making a #{@drink}"
class B extends A
B::make = (@flavor) -> super() + " with #{@flavor}"
b = new B('Machiato')
eq b.make('caramel'), "Making a Machiato with caramel"
# Fails, bound
# TODO: Could this throw a compile error?
class C extends A
C::make = (@flavor) => super() + " with #{@flavor}"
c = new C('Machiato')
ok c.make('caramel') isnt "Making a Machiato with caramel"
test "bound functions without super", ->
# Bound function with @
# Throw on compile, since bound
@ -1275,7 +1238,7 @@ test "super in a bound function", ->
class B extends A
make: (@flavor) =>
super + " with #{@flavor}"
super() + " with #{@flavor}"
b = new B('Machiato')
eq b.make('vanilla'), "Making a Machiato with vanilla"
@ -1284,7 +1247,7 @@ test "super in a bound function", ->
class C extends A
make: (@flavor) =>
func = () =>
super + " with #{@flavor}"
super() + " with #{@flavor}"
func()
c = new C('Machiato')
@ -1312,13 +1275,13 @@ test "super in a try/catch", ->
class B extends A
constructor: ->
try
super
super()
"""
throwsC = """
ctor = ->
try
super
super()
class C extends A
constructor: ctor
@ -1702,7 +1665,7 @@ test "CS6 Class extends a CS1 compiled class with super()", ->
constructor: (@shots) ->
super('caramel')
make: () ->
super + " and #{@shots} shots of espresso"
super() + " and #{@shots} shots of espresso"
eq B.className(), 'ExtendedCS1'
b = new B('three')

View file

@ -1284,10 +1284,10 @@ test "constructor functions can't be generators", ->
'''
test "non-derived constructors can't call super", ->
assertErrorFormat 'class then constructor: -> super', '''
assertErrorFormat 'class then constructor: -> super()', '''
[stdin]:1:28: error: 'super' is only allowed in derived class constructors
class then constructor: -> super
^^^^^
class then constructor: -> super()
^^^^^^^
'''
test "derived constructors can't reference `this` before calling super", ->
@ -1305,10 +1305,10 @@ test "derived constructors can't use @params without calling super", ->
'''
test "'super' is not allowed in constructor parameter defaults", ->
assertErrorFormat 'class extends A then constructor: (a = super) ->', '''
assertErrorFormat 'class extends A then constructor: (a = super()) ->', '''
[stdin]:1:40: error: 'super' is not allowed in constructor parameter defaults
class extends A then constructor: (a = super) ->
^^^^^
class extends A then constructor: (a = super()) ->
^^^^^^^
'''
test "can't use pattern matches for loop indices", ->
@ -1317,3 +1317,25 @@ test "can't use pattern matches for loop indices", ->
a for b, {c} in d
^^^
'''
test "bare 'super' is no longer allowed", ->
# TODO Improve this error message (it should at least be 'unexpected super')
assertErrorFormat 'class extends A then constructor: -> super', '''
[stdin]:1:35: error: unexpected ->
class extends A then constructor: -> super
^^
'''
test "soaked 'super' in constructor", ->
assertErrorFormat 'class extends A then constructor: -> super?()', '''
[stdin]:1:38: error: Unsupported reference to 'super'
class extends A then constructor: -> super?()
^^^^^
'''
test "new with 'super'", ->
assertErrorFormat 'class extends A then foo: -> new super()', '''
[stdin]:1:34: error: Unsupported reference to 'super'
class extends A then foo: -> new super()
^^^^^
'''

View file

@ -337,8 +337,8 @@ test "generator methods in classes", ->
arrayEq [2], Array.from new Base().method()
class Child extends Base
@static: -> super
method: -> super
@static: -> super()
method: -> super()
arrayEq [1], Array.from Child.static()
arrayEq [2], Array.from new Child().method()

View file

@ -465,7 +465,7 @@ test "export class that extends", ->
baz: ->
console.log 'hello, world!'"""
output = toJS input
ok /export (class foo|var foo = \(function)/.test(output) and \
ok /export var foo = class foo/.test(output) and \
not /var foo(;|,)/.test output
test "export default class that extends", ->
@ -473,7 +473,7 @@ test "export default class that extends", ->
export default class foo extends bar
baz: ->
console.log 'hello, world!'"""
ok /export default (class foo|foo = \(function)/.test toJS input
ok /export default foo = class foo/.test toJS input
test "export default named member, within an object", ->
input = "export { foo as default, bar }"

View file

@ -110,9 +110,9 @@ test "division vs regex after a callable token", ->
p: (regex) -> if regex then r regex else 4
class B extends A
p: ->
eq 2, super / b/g
eq 2, super/b/g
eq 2, super/ b/g
eq 2, super() / b/g
eq 2, super()/b/g
eq 2, super()/ b/g
eq true, super /b/g
new B().p()

View file

@ -72,7 +72,7 @@ test "#1183: super + fat arrows", ->
class B extends A
constructor : ->
super
super()
foo : (cb) ->
dolater =>
dolater =>
@ -87,9 +87,9 @@ test "#1183: super + wrap", ->
m : -> 10
class B extends A
constructor : -> super
B::m = -> r = try super()
constructor : -> super()
m: -> r = try super()
m: -> r = super()
eq (new B).m(), 10
@ -113,7 +113,7 @@ test "#2331: bound super regression", ->
method: -> @constructor.value
class B extends A
method: => super
method: => super()
eq (new B).method(), 'A'