Skip to content

Commit

Permalink
handle initialization using force-move assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Mar 30, 2021
1 parent c871c7d commit 3bbc8c8
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 6 deletions.
10 changes: 6 additions & 4 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,12 @@ func (interpreter *Interpreter) visitAssignment(

if transferOperation == ast.TransferOperationMoveForced {
target := getterSetter.get()
if _, ok := target.(NilValue); !ok {

// The value may be a NilValue or nil.
// The latter case exists when the force-move assignment is the initialization of a field
// in an initializer, in which case there is no prior value for the field.

if _, ok := target.(NilValue); !ok && target != nil {
getLocationRange := locationRangeGetter(interpreter.Location, position)
panic(ForceAssignmentToNonNilResourceError{
LocationRange: getLocationRange(),
Expand Down Expand Up @@ -2948,9 +2953,6 @@ func (interpreter *Interpreter) getMember(self Value, getLocationRange func() Lo
return interpreter.getTypeFunction(self)
}
}
if result == nil {
panic(errors.NewUnreachableError())
}
return result
}

Expand Down
6 changes: 6 additions & 0 deletions runtime/interpreter/interpreter_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@ func (interpreter *Interpreter) VisitMemberExpression(expression *ast.MemberExpr

getLocationRange := locationRangeGetter(interpreter.Location, expression)
resultValue := interpreter.getMember(result, getLocationRange, expression.Identifier.Identifier)
if resultValue == nil {
panic(errors.NewUnreachableError())
}

// If the member access is optional chaining, only wrap the result value
// in an optional, if it is not already an optional value
Expand Down Expand Up @@ -656,6 +659,9 @@ func (interpreter *Interpreter) visitPotentialStorageRemoval(expression ast.Expr

getterSetter := interpreter.indexExpressionGetterSetter(movingStorageIndexExpression)
value := getterSetter.get()
if value == nil {
panic(errors.NewUnreachableError())
}
getterSetter.set(NilValue{})
return value
}
Expand Down
6 changes: 6 additions & 0 deletions runtime/interpreter/interpreter_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,19 @@ func (interpreter *Interpreter) VisitSwapStatement(swap *ast.SwapStatement) ast.
// Evaluate the left expression
leftGetterSetter := interpreter.assignmentGetterSetter(swap.Left)
leftValue := leftGetterSetter.get()
if leftValue == nil {
panic(errors.NewUnreachableError())
}
if interpreter.movingStorageIndexExpression(swap.Left) != nil {
leftGetterSetter.set(NilValue{})
}

// Evaluate the right expression
rightGetterSetter := interpreter.assignmentGetterSetter(swap.Right)
rightValue := rightGetterSetter.get()
if rightValue == nil {
panic(errors.NewUnreachableError())
}
if interpreter.movingStorageIndexExpression(swap.Right) != nil {
rightGetterSetter.set(NilValue{})
}
Expand Down
12 changes: 10 additions & 2 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -6365,7 +6365,11 @@ func (v *StorageReferenceValue) GetMember(interpreter *Interpreter, getLocationR
})
}

return interpreter.getMember(*referencedValue, getLocationRange, name)
value := interpreter.getMember(*referencedValue, getLocationRange, name)
if value == nil {
panic(errors.NewUnreachableError())
}
return value
}

func (v *StorageReferenceValue) SetMember(interpreter *Interpreter, getLocationRange func() LocationRange, name string, value Value) {
Expand Down Expand Up @@ -6493,7 +6497,11 @@ func (v *EphemeralReferenceValue) GetMember(interpreter *Interpreter, getLocatio
})
}

return interpreter.getMember(*referencedValue, getLocationRange, name)
value := interpreter.getMember(*referencedValue, getLocationRange, name)
if value == nil {
panic(errors.NewUnreachableError())
}
return value
}

func (v *EphemeralReferenceValue) SetMember(interpreter *Interpreter, getLocationRange func() LocationRange, name string, value Value) {
Expand Down
29 changes: 29 additions & 0 deletions runtime/tests/interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7833,6 +7833,35 @@ func TestInterpretResourceAssignmentForceTransfer(t *testing.T) {

require.ErrorAs(t, err, &interpreter.ForceAssignmentToNonNilResourceError{})
})

t.Run("new to non-nil", func(t *testing.T) {

inter := parseCheckAndInterpret(t, `
resource X {}
resource Y {
var x: @X?
init() {
self.x <-! create X()
}
destroy() {
destroy self.x
}
}
fun test() {
let y <- create Y()
destroy y
}
`)

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

}

func TestInterpretForce(t *testing.T) {
Expand Down

0 comments on commit 3bbc8c8

Please sign in to comment.