Skip to content

Commit add4b32

Browse files
committed
instead of pushing an additional activation, capture a clone of the current activation
pushing an additional activation would also have to get popped at the end of the function call to ensure the activation stack stays balanced
1 parent 03b3b22 commit add4b32

File tree

4 files changed

+83
-18
lines changed

4 files changed

+83
-18
lines changed

activations/activations.go

+13
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,19 @@ func (a *Activation[T]) Set(name string, value T) {
107107
a.entries[name] = value
108108
}
109109

110+
func (a *Activation[T]) Clone() *Activation[T] {
111+
clone := NewActivation[T](a.MemoryGauge, a.Parent)
112+
113+
if a.entries != nil {
114+
clone.entries = make(map[string]T, len(a.entries))
115+
for name, value := range a.entries { //nolint:maprange
116+
clone.entries[name] = value
117+
}
118+
}
119+
120+
return clone
121+
}
122+
110123
// Activations is a stack of activation records.
111124
// Each entry represents a new activation record.
112125
//

interpreter/interpreter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ func (interpreter *Interpreter) VisitFunctionDeclaration(declaration *ast.Functi
742742
// push a new activation, so that the mutations are not performed
743743
// on the captured activation.
744744

745-
interpreter.activations.PushNewWithCurrent()
745+
lexicalScope = lexicalScope.Clone()
746746
}
747747

748748
// make the function itself available inside the function

interpreter/interpreter_expression.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1338,7 +1338,7 @@ func (interpreter *Interpreter) VisitFunctionExpression(expression *ast.Function
13381338
// push a new activation, so that the mutations are not performed
13391339
// on the captured activation.
13401340

1341-
interpreter.activations.PushNewWithCurrent()
1341+
lexicalScope = lexicalScope.Clone()
13421342

13431343
functionType := interpreter.Program.Elaboration.FunctionExpressionFunctionType(expression)
13441344

interpreter/misc_test.go

+68-16
Original file line numberDiff line numberDiff line change
@@ -6869,11 +6869,11 @@ func TestInterpretClosureScopingFunctionExpression(t *testing.T) {
68696869

68706870
inter := parseCheckAndInterpret(t, `
68716871
fun test(a: Int): Int {
6872-
let bar = fun(): Int {
6873-
return a
6872+
let bar = fun(b: Int): Int {
6873+
return a + b
68746874
}
68756875
let a = 2
6876-
return bar()
6876+
return bar(b: 10)
68776877
}
68786878
`)
68796879

@@ -6885,7 +6885,7 @@ func TestInterpretClosureScopingFunctionExpression(t *testing.T) {
68856885
AssertValuesEqual(
68866886
t,
68876887
inter,
6888-
interpreter.NewUnmeteredIntValueFromInt64(1),
6888+
interpreter.NewUnmeteredIntValueFromInt64(11),
68896889
actual,
68906890
)
68916891
}
@@ -6895,11 +6895,11 @@ func TestInterpretClosureScopingInnerFunction(t *testing.T) {
68956895

68966896
inter := parseCheckAndInterpret(t, `
68976897
fun test(a: Int): Int {
6898-
fun bar(): Int {
6899-
return a
6898+
fun bar(b: Int): Int {
6899+
return a + b
69006900
}
69016901
let a = 2
6902-
return bar()
6902+
return bar(b: 10)
69036903
}
69046904
`)
69056905

@@ -6911,22 +6911,74 @@ func TestInterpretClosureScopingInnerFunction(t *testing.T) {
69116911
AssertValuesEqual(
69126912
t,
69136913
inter,
6914-
interpreter.NewUnmeteredIntValueFromInt64(1),
6914+
interpreter.NewUnmeteredIntValueFromInt64(11),
69156915
value,
69166916
)
69176917
}
69186918

6919+
func TestInterpretClosureScopingFunctionExpressionInCall(t *testing.T) {
6920+
t.Parallel()
6921+
6922+
inter := parseCheckAndInterpret(t, `
6923+
fun foo(a: Int) {
6924+
fun() {}
6925+
}
6926+
6927+
fun test(): Int {
6928+
let a = 1
6929+
foo(a: 2)
6930+
return a
6931+
}
6932+
`)
6933+
6934+
actual, err := inter.Invoke("test")
6935+
require.NoError(t, err)
6936+
6937+
AssertValuesEqual(
6938+
t,
6939+
inter,
6940+
interpreter.NewUnmeteredIntValueFromInt64(1),
6941+
actual,
6942+
)
6943+
}
6944+
6945+
func TestInterpretClosureScopingInnerFunctionInCall(t *testing.T) {
6946+
t.Parallel()
6947+
6948+
inter := parseCheckAndInterpret(t, `
6949+
fun foo(a: Int) {
6950+
let f = fun() {}
6951+
}
6952+
6953+
fun test(): Int {
6954+
let a = 1
6955+
foo(a: 2)
6956+
return a
6957+
}
6958+
`)
6959+
6960+
actual, err := inter.Invoke("test")
6961+
require.NoError(t, err)
6962+
6963+
AssertValuesEqual(
6964+
t,
6965+
inter,
6966+
interpreter.NewUnmeteredIntValueFromInt64(1),
6967+
actual,
6968+
)
6969+
}
6970+
69196971
func TestInterpretAssignmentAfterClosureFunctionExpression(t *testing.T) {
69206972
t.Parallel()
69216973

69226974
inter := parseCheckAndInterpret(t, `
69236975
fun test(): Int {
69246976
var a = 1
6925-
let bar = fun(): Int {
6926-
return a
6977+
let bar = fun(b: Int): Int {
6978+
return a + b
69276979
}
69286980
a = 2
6929-
return bar()
6981+
return bar(b: 10)
69306982
}
69316983
`)
69326984

@@ -6936,7 +6988,7 @@ func TestInterpretAssignmentAfterClosureFunctionExpression(t *testing.T) {
69366988
AssertValuesEqual(
69376989
t,
69386990
inter,
6939-
interpreter.NewUnmeteredIntValueFromInt64(2),
6991+
interpreter.NewUnmeteredIntValueFromInt64(12),
69406992
value,
69416993
)
69426994
}
@@ -6947,11 +6999,11 @@ func TestInterpretAssignmentAfterClosureInnerFunction(t *testing.T) {
69476999
inter := parseCheckAndInterpret(t, `
69487000
fun test(): Int {
69497001
var a = 1
6950-
fun bar(): Int {
6951-
return a
7002+
fun bar(b: Int): Int {
7003+
return a + b
69527004
}
69537005
a = 2
6954-
return bar()
7006+
return bar(b: 10)
69557007
}
69567008
`)
69577009

@@ -6961,7 +7013,7 @@ func TestInterpretAssignmentAfterClosureInnerFunction(t *testing.T) {
69617013
AssertValuesEqual(
69627014
t,
69637015
inter,
6964-
interpreter.NewUnmeteredIntValueFromInt64(2),
7016+
interpreter.NewUnmeteredIntValueFromInt64(12),
69657017
value,
69667018
)
69677019
}

0 commit comments

Comments
 (0)