mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Issue #897 ... fixed leaking direct-call-plucked comprehension variables, due to shared scope.
This commit is contained in:
parent
c0bbc609be
commit
2decb30d4e
6 changed files with 41 additions and 23 deletions
|
@ -56,7 +56,7 @@
|
|||
return compileScripts();
|
||||
};
|
||||
compileScripts = function() {
|
||||
var base, compile, _fn, _i, _len, _results;
|
||||
var base, compile, source, _fn, _i, _len, _results;
|
||||
_fn = function(source) {
|
||||
base = path.join(source);
|
||||
compile = function(source, topLevel) {
|
||||
|
|
29
lib/nodes.js
29
lib/nodes.js
|
@ -1204,9 +1204,12 @@
|
|||
return !!this.ctor;
|
||||
};
|
||||
Code.prototype.compileNode = function(o) {
|
||||
var code, exprs, i, idt, lit, p, param, ref, scope, sharedScope, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref, _ref2, _ref3, _ref4, _results;
|
||||
var code, exprs, i, idt, lit, p, param, ref, sharedScope, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref, _ref2, _ref3, _ref4, _results;
|
||||
sharedScope = del(o, 'sharedScope');
|
||||
o.scope = scope = sharedScope || new Scope(o.scope, this.body, this);
|
||||
o.scope = sharedScope || new Scope(o.scope, this.body, this);
|
||||
if (sharedScope) {
|
||||
o.scope.shared = true;
|
||||
}
|
||||
o.indent += TAB;
|
||||
delete o.bare;
|
||||
delete o.globals;
|
||||
|
@ -1259,7 +1262,7 @@
|
|||
if (!splats) {
|
||||
for (i = 0, _len4 = vars.length; i < _len4; i++) {
|
||||
v = vars[i];
|
||||
scope.parameter(vars[i] = v.compile(o));
|
||||
o.scope.parameter(vars[i] = v.compile(o));
|
||||
}
|
||||
}
|
||||
if (!(wasEmpty || this.noReturn)) {
|
||||
|
@ -1769,17 +1772,15 @@
|
|||
scope = o.scope;
|
||||
name = this.name && this.name.compile(o, LEVEL_LIST);
|
||||
index = this.index && this.index.compile(o, LEVEL_LIST);
|
||||
if (!hasCode) {
|
||||
if (name && !this.pattern) {
|
||||
scope.find(name, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (index) {
|
||||
scope.find(index, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (name && !this.pattern) {
|
||||
scope.find(name, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (index) {
|
||||
scope.find(index, {
|
||||
immediate: true
|
||||
});
|
||||
}
|
||||
if (this.returns && !hasPure) {
|
||||
rvar = scope.freeVariable('results');
|
||||
|
|
|
@ -48,6 +48,9 @@
|
|||
return false;
|
||||
};
|
||||
Scope.prototype.parameter = function(name) {
|
||||
if (this.shared && this.check(name, true)) {
|
||||
return;
|
||||
}
|
||||
return this.add(name, 'param');
|
||||
};
|
||||
Scope.prototype.check = function(name, immediate) {
|
||||
|
|
|
@ -982,9 +982,10 @@ exports.Code = class Code extends Base
|
|||
# arrow, generates a wrapper that saves the current value of `this` through
|
||||
# a closure.
|
||||
compileNode: (o) ->
|
||||
sharedScope = del o, 'sharedScope'
|
||||
o.scope = scope = sharedScope or new Scope o.scope, @body, this
|
||||
o.indent += TAB
|
||||
sharedScope = del o, 'sharedScope'
|
||||
o.scope = sharedScope or new Scope o.scope, @body, this
|
||||
o.scope.shared = yes if sharedScope
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
delete o.globals
|
||||
vars = []
|
||||
|
@ -1008,7 +1009,7 @@ exports.Code = class Code extends Base
|
|||
wasEmpty = @body.isEmpty()
|
||||
exprs.unshift splats if splats
|
||||
@body.expressions.unshift exprs... if exprs.length
|
||||
scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
@body.makeReturn() unless wasEmpty or @noReturn
|
||||
idt = o.indent
|
||||
code = 'function'
|
||||
|
@ -1425,9 +1426,8 @@ exports.For = class For extends Base
|
|||
scope = o.scope
|
||||
name = @name and @name.compile o, LEVEL_LIST
|
||||
index = @index and @index.compile o, LEVEL_LIST
|
||||
unless hasCode
|
||||
scope.find(name, immediate: yes) if name and not @pattern
|
||||
scope.find(index, immediate: yes) if index
|
||||
scope.find(name, immediate: yes) if name and not @pattern
|
||||
scope.find(index, immediate: yes) if index
|
||||
rvar = scope.freeVariable 'results' if @returns and not hasPure
|
||||
ivar = (if @range then name else index) or scope.freeVariable 'i'
|
||||
varPart = ''
|
||||
|
|
|
@ -44,6 +44,7 @@ exports.Scope = class Scope
|
|||
# Reserve a variable name as originating from a function parameter for this
|
||||
# scope. No `var` required for internal references.
|
||||
parameter: (name) ->
|
||||
return if @shared and @check name, yes
|
||||
@add name, 'param'
|
||||
|
||||
# Just check to see if a variable has already been declared, without reserving,
|
||||
|
|
|
@ -228,3 +228,16 @@ foo = ->
|
|||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
||||
# Issue #897: Ensure that plucked function variables aren't leaked.
|
||||
facets = {}
|
||||
list = ['one', 'two']
|
||||
|
||||
(->
|
||||
for entity in list
|
||||
facets[entity] = -> entity
|
||||
)()
|
||||
|
||||
eq typeof entity, 'undefined'
|
||||
eq facets['two'](), 'two'
|
||||
|
|
Loading…
Add table
Reference in a new issue