Skip to content

Commit

Permalink
Merge pull request #3779 from onflow/bastian/v1.3-port-internal-fix-3
Browse files Browse the repository at this point in the history
[v1.3] Port internal fix
  • Loading branch information
turbolent authored Feb 18, 2025
2 parents 03b3b22 + 5592d40 commit deee80b
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 24 deletions.
13 changes: 13 additions & 0 deletions activations/activations.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,19 @@ func (a *Activation[T]) Set(name string, value T) {
a.entries[name] = value
}

func (a *Activation[T]) Clone() *Activation[T] {
clone := NewActivation[T](a.MemoryGauge, a.Parent)

if a.entries != nil {
clone.entries = make(map[string]T, len(a.entries))
for name, value := range a.entries { //nolint:maprange
clone.entries[name] = value
}
}

return clone
}

// Activations is a stack of activation records.
// Each entry represents a new activation record.
//
Expand Down
7 changes: 3 additions & 4 deletions interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,10 @@ func (interpreter *Interpreter) VisitFunctionDeclaration(declaration *ast.Functi
// return bar()
// }
//
// As variable declarations mutate the current activation in place,
// push a new activation, so that the mutations are not performed
// on the captured activation.
// As variable declarations mutate the current activation in place, capture a clone of the current activation,
// so that the mutations are not performed on the captured activation.

interpreter.activations.PushNewWithCurrent()
lexicalScope = lexicalScope.Clone()
}

// make the function itself available inside the function
Expand Down
7 changes: 3 additions & 4 deletions interpreter/interpreter_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -1334,11 +1334,10 @@ func (interpreter *Interpreter) VisitFunctionExpression(expression *ast.Function
// return bar()
// }
//
// As variable declarations mutate the current activation in place,
// push a new activation, so that the mutations are not performed
// on the captured activation.
// As variable declarations mutate the current activation in place, capture a clone of the current activation,
// so that the mutations are not performed on the captured activation.

interpreter.activations.PushNewWithCurrent()
lexicalScope = lexicalScope.Clone()

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

Expand Down
136 changes: 120 additions & 16 deletions interpreter/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6869,11 +6869,11 @@ func TestInterpretClosureScopingFunctionExpression(t *testing.T) {

inter := parseCheckAndInterpret(t, `
fun test(a: Int): Int {
let bar = fun(): Int {
return a
let bar = fun(b: Int): Int {
return a + b
}
let a = 2
return bar()
return bar(b: 10)
}
`)

Expand All @@ -6885,7 +6885,7 @@ func TestInterpretClosureScopingFunctionExpression(t *testing.T) {
AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(1),
interpreter.NewUnmeteredIntValueFromInt64(11),
actual,
)
}
Expand All @@ -6895,11 +6895,11 @@ func TestInterpretClosureScopingInnerFunction(t *testing.T) {

inter := parseCheckAndInterpret(t, `
fun test(a: Int): Int {
fun bar(): Int {
return a
fun bar(b: Int): Int {
return a + b
}
let a = 2
return bar()
return bar(b: 10)
}
`)

Expand All @@ -6911,22 +6911,126 @@ func TestInterpretClosureScopingInnerFunction(t *testing.T) {
AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(1),
interpreter.NewUnmeteredIntValueFromInt64(11),
value,
)
}

func TestInterpretClosureScopingFunctionExpressionParameterConfusion(t *testing.T) {
t.Parallel()

inter := parseCheckAndInterpret(t, `
fun foo(a: Int) {
fun() {}
}
fun test(): Int {
let a = 1
foo(a: 2)
return a
}
`)

actual, err := inter.Invoke("test")
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(1),
actual,
)
}

func TestInterpretClosureScopingInnerFunctionParameterConfusion(t *testing.T) {
t.Parallel()

inter := parseCheckAndInterpret(t, `
fun foo(a: Int) {
let f = fun() {}
}
fun test(): Int {
let a = 1
foo(a: 2)
return a
}
`)

actual, err := inter.Invoke("test")
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(1),
actual,
)
}

func TestInterpretClosureScopingFunctionExpressionInCall(t *testing.T) {
t.Parallel()

inter := parseCheckAndInterpret(t, `
fun foo() {
fun() {}
}
fun test(): Int {
let a = 1
foo()
return a
}
`)

actual, err := inter.Invoke("test")
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(1),
actual,
)
}

func TestInterpretClosureScopingInnerFunctionInCall(t *testing.T) {
t.Parallel()

inter := parseCheckAndInterpret(t, `
fun foo() {
let f = fun() {}
}
fun test(): Int {
let a = 1
foo()
return a
}
`)

actual, err := inter.Invoke("test")
require.NoError(t, err)

AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(1),
actual,
)
}

func TestInterpretAssignmentAfterClosureFunctionExpression(t *testing.T) {
t.Parallel()

inter := parseCheckAndInterpret(t, `
fun test(): Int {
var a = 1
let bar = fun(): Int {
return a
let bar = fun(b: Int): Int {
return a + b
}
a = 2
return bar()
return bar(b: 10)
}
`)

Expand All @@ -6936,7 +7040,7 @@ func TestInterpretAssignmentAfterClosureFunctionExpression(t *testing.T) {
AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(2),
interpreter.NewUnmeteredIntValueFromInt64(12),
value,
)
}
Expand All @@ -6947,11 +7051,11 @@ func TestInterpretAssignmentAfterClosureInnerFunction(t *testing.T) {
inter := parseCheckAndInterpret(t, `
fun test(): Int {
var a = 1
fun bar(): Int {
return a
fun bar(b: Int): Int {
return a + b
}
a = 2
return bar()
return bar(b: 10)
}
`)

Expand All @@ -6961,7 +7065,7 @@ func TestInterpretAssignmentAfterClosureInnerFunction(t *testing.T) {
AssertValuesEqual(
t,
inter,
interpreter.NewUnmeteredIntValueFromInt64(2),
interpreter.NewUnmeteredIntValueFromInt64(12),
value,
)
}
Expand Down

0 comments on commit deee80b

Please sign in to comment.