Skip to content

Commit 137b3da

Browse files
committed
Fixes jashkenas#2489: gets rid of __bind and instead use its inlined form, declaring the same parameters in the bound function as in the prototype's one
Ugliest code ever 💩
1 parent e26f982 commit 137b3da

File tree

3 files changed

+77
-55
lines changed

3 files changed

+77
-55
lines changed

lib/coffee-script/nodes.js

+39-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nodes.coffee

+16-9
Original file line numberDiff line numberDiff line change
@@ -985,9 +985,19 @@ exports.Class = class Class extends Base
985985
# Ensure that all functions bound to the instance are proxied in the
986986
# constructor.
987987
addBoundFunctions: (o) ->
988-
for bvar in @boundFuncs
989-
lhs = (new Value (new Literal "this"), [new Access bvar]).compile o
990-
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
988+
if @boundFuncs.length
989+
# Use a temporary Scope just to create some free variables.
990+
# TODO: This is ugly. This should be the @ctor's scope.
991+
scope = new Scope o.scope, @ctor.body
992+
for [name, func] in @boundFuncs
993+
varName = scope.freeVariable if IDENTIFIER.test(name.value) then name.value else 'bound'
994+
varDecl = new Assign new Literal(varName), new Value(new Literal("this"), [new Access name])
995+
lhs = new Value (new Literal "this"), [new Access name]
996+
body = new Block [new Return new Literal "#{varName}.apply(_this, arguments)"]
997+
rhs = new Code func.params, body, 'boundfunc'
998+
bound = new Assign lhs, rhs
999+
@ctor.body.unshift bound
1000+
@ctor.body.unshift varDecl
9911001
return
9921002

9931003
# Merge the properties from a top-level object as prototypal properties
@@ -1017,7 +1027,7 @@ exports.Class = class Class extends Base
10171027
else
10181028
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
10191029
if func instanceof Code and func.bound
1020-
@boundFuncs.push base
1030+
@boundFuncs.push [base, func]
10211031
func.bound = no
10221032
assign
10231033
compact exprs
@@ -1292,6 +1302,8 @@ exports.Code = class Code extends Base
12921302
delete o.isExistentialEquals
12931303
params = []
12941304
exprs = []
1305+
# Clean params references in case the params where used in other Code nodes.
1306+
delete param.reference for param in @params
12951307
@eachParamName (name) -> # this step must be performed before the others
12961308
unless o.scope.check name then o.scope.parameter name
12971309
for param in @params when param.splat
@@ -2115,11 +2127,6 @@ UTILITIES =
21152127
function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }
21162128
"""
21172129

2118-
# Create a function bound to the current value of "this".
2119-
bind: -> '''
2120-
function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
2121-
'''
2122-
21232130
# Discover if an item is in an array.
21242131
indexOf: -> """
21252132
[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }

test/classes.coffee

+22-18
Original file line numberDiff line numberDiff line change
@@ -730,30 +730,34 @@ test "#2359: extending native objects that use other typed constructors requires
730730
eq 'yes!', workingArray.method()
731731

732732

733-
test "#2782: non-alphanumeric-named bound functions", ->
734-
class A
735-
'b:c': =>
736-
'd'
733+
test "#2489: removing __bind", ->
737734

738-
eq (new A)['b:c'](), 'd'
735+
class Thing
736+
foo: (a, b, c) ->
737+
bar: (a, b, c) =>
739738

739+
thing = new Thing
740740

741-
test "#2781: overriding bound functions", ->
742-
class A
743-
a: ->
744-
@b()
745-
b: =>
746-
1
741+
eq thing.foo.length, 3
742+
eq thing.bar.length, 3
747743

748-
class B extends A
749-
b: =>
750-
2
751744

752-
b = (new A).b
753-
eq b(), 1
745+
test "#2773: overriding bound functions", ->
746+
class Foo
747+
method: => 'Foo'
748+
749+
class Bar extends Foo
750+
method: => 'Bar'
754751

755-
b = (new B).b
756-
eq b(), 2
752+
eq (new Bar).method(), 'Bar'
753+
754+
755+
test "#2782: non-alphanumeric-named bound functions", ->
756+
class A
757+
'b:c': =>
758+
'd'
759+
760+
eq (new A)['b:c'](), 'd'
757761

758762

759763
test "#2791: bound function with destructured argument", ->

0 commit comments

Comments
 (0)