Skip to content

[CS2] Remove support for bound instance methods #4530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 4 additions & 27 deletions lib/coffeescript/nodes.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 3 additions & 16 deletions src/nodes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -1279,11 +1279,9 @@ exports.Class = class Class extends Base
result

compileClassDeclaration: (o) ->
@ctor ?= @makeDefaultConstructor() if @externalCtor or @boundMethods.length
@ctor ?= @makeDefaultConstructor() if @externalCtor
@ctor?.noReturn = true

@proxyBoundMethods o if @boundMethods.length

o.indent += TAB

result = []
Expand Down Expand Up @@ -1319,7 +1317,6 @@ exports.Class = class Class extends Base

walkBody: ->
@ctor = null
@boundMethods = []
executableBody = null

initializer = []
Expand Down Expand Up @@ -1363,11 +1360,8 @@ exports.Class = class Class extends Base
if method.ctor
method.error 'Cannot define more than one constructor in a class' if @ctor
@ctor = method
else if method.bound and method.isStatic
else if method.isStatic and method.bound
method.context = @name
else if method.bound
@boundMethods.push method.name
method.bound = false

if initializer.length isnt expressions.length
@body.expressions = (expression.hoist() for expression in initializer)
Expand Down Expand Up @@ -1405,7 +1399,7 @@ exports.Class = class Class extends 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
method.error 'Methods cannot be bound functions' if method.bound

method

Expand All @@ -1424,13 +1418,6 @@ exports.Class = class Class extends Base

ctor

proxyBoundMethods: (o) ->
@ctor.thisAssignments = for name in @boundMethods by -1
name = new Value(new ThisLiteral, [ name ]).compile o
new Literal "#{name} = #{name}.bind(this)"

null

exports.ExecutableClassBody = class ExecutableClassBody extends Base
children: [ 'class', 'body' ]

Expand Down
5 changes: 2 additions & 3 deletions test/assignment.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,8 @@ test "Assignment to variables similar to helper functions", ->
extend = 3
hasProp = 4
value: 5
method: (bind, bind1) => [bind, bind1, extend, hasProp, @value]
{method} = new B
arrayEq [1, 2, 3, 4, 5], method 1, 2
method: (bind, bind1) -> [bind, bind1, extend, hasProp, @value]
arrayEq [1, 2, 3, 4, 5], new B().method 1, 2

modulo = -1 %% 3
eq 2, modulo
Expand Down
104 changes: 4 additions & 100 deletions test/classes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -136,42 +136,20 @@ test "classes with JS-keyword properties", ->
ok instance.name() is 'class'


test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
test "Classes with methods that are pre-bound statically, to the class", ->

class Dog
constructor: (name) ->
@name = name

bark: =>
"#{@name} woofs!"

@static = =>
new this('Dog')

spark = new Dog('Spark')
fido = new Dog('Fido')
fido.bark = spark.bark

ok fido.bark() is 'Spark woofs!'

obj = func: Dog.static

ok obj.func().name is 'Dog'


test "a bound function in a bound function", ->

class Mini
num: 10
generate: =>
for i in [1..3]
=>
@num

m = new Mini
eq (func() for func in m.generate()).join(' '), '10 10 10'


test "contructor called with varargs", ->

class Connection
Expand Down Expand Up @@ -476,21 +454,6 @@ test "#1182: execution order needs to be considered as well", ->
@B: makeFn 2
constructor: makeFn 3

test "#1182: external constructors with bound functions", ->
fn = ->
{one: 1}
this
class B
class A
constructor: fn
method: => this instanceof A
ok (new A).method.call(new B)

test "#1372: bound class methods with reserved names", ->
class C
delete: =>
ok C::delete

test "#1380: `super` with reserved names", ->
class C
do: -> super()
Expand Down Expand Up @@ -559,7 +522,7 @@ test "#1842: Regression with bound functions within bound class methods", ->
@unbound: ->
eq this, Store

instance: =>
instance: ->
ok this instanceof Store

Store.bound()
Expand Down Expand Up @@ -722,57 +685,6 @@ test "extending native objects works with and without defining a constructor", -
ok overrideArray instanceof OverrideArray
eq 'yes!', overrideArray.method()


test "#2782: non-alphanumeric-named bound functions", ->
class A
'b:c': =>
'd'

eq (new A)['b:c'](), 'd'


test "#2781: overriding bound functions", ->
class A
a: ->
@b()
b: =>
1

class B extends A
b: =>
2

b = (new A).b
eq b(), 1

b = (new B).b
eq b(), 2


test "#2791: bound function with destructured argument", ->
class Foo
method: ({a}) => 'Bar'

eq (new Foo).method({a: 'Bar'}), 'Bar'


test "#2796: ditto, ditto, ditto", ->
answer = null

outsideMethod = (func) ->
func.call message: 'wrong!'

class Base
constructor: ->
@message = 'right!'
outsideMethod @echo

echo: =>
answer = @message

new Base
eq answer, 'right!'

test "#3063: Class bodies cannot contain pure statements", ->
throws -> CoffeeScript.compile """
class extends S
Expand Down Expand Up @@ -984,9 +896,6 @@ test "`this` access after `super` in extended classes", ->
eq result.super, this
eq result.param, @param
eq result.method, @method
ok result.method isnt Test::method

method: =>

nonce = {}
new Test nonce, {}
Expand All @@ -1006,8 +915,6 @@ test "`@`-params and bound methods with multiple `super` paths (blocks)", ->
super 'not param'
eq @name, 'not param'
eq @param, nonce
ok @method isnt Test::method
method: =>
new Test true, nonce
new Test false, nonce

Expand All @@ -1026,16 +933,13 @@ test "`@`-params and bound methods with multiple `super` paths (expressions)", -
eq (super 'param'), @;
eq @name, 'param';
eq @param, nonce;
ok @method isnt Test::method
)
else
result = (
eq (super 'not param'), @;
eq @name, 'not param';
eq @param, nonce;
ok @method isnt Test::method
)
method: =>
new Test true, nonce
new Test false, nonce

Expand Down Expand Up @@ -1237,15 +1141,15 @@ test "super in a bound function", ->
make: -> "Making a #{@drink}"

class B extends A
make: (@flavor) =>
make: (@flavor) ->
super() + " with #{@flavor}"

b = new B('Machiato')
eq b.make('vanilla'), "Making a Machiato with vanilla"

# super in a bound function in a bound function
class C extends A
make: (@flavor) =>
make: (@flavor) ->
func = () =>
super() + " with #{@flavor}"
func()
Expand Down
10 changes: 0 additions & 10 deletions test/scope.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,6 @@ test "#1183: super + closures", ->
ret
eq (new B).foo(), 10

test "#2331: bound super regression", ->
class A
@value = 'A'
method: -> @constructor.value

class B extends A
method: => super()

eq (new B).method(), 'A'

test "#3259: leak with @-params within destructured parameters", ->
fn = ({@foo}, [@bar], [{@baz}]) ->
foo = bar = baz = false
Expand Down