Issue #897 ... fixed leaking direct-call-plucked comprehension variables, due to shared scope.

This commit is contained in:
Jeremy Ashkenas 2010-12-05 21:18:30 -05:00
parent c0bbc609be
commit 2decb30d4e
6 changed files with 41 additions and 23 deletions

View File

@ -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) {

View File

@ -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');

View File

@ -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) {

View File

@ -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 = ''

View File

@ -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,

View File

@ -227,4 +227,17 @@ foo = ->
for j in [0..7]
-> i + j
eq foo()[3][4](), 7
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'