Skip to content

Commit

Permalink
set base during attachment iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
dsainati1 committed Oct 5, 2023
1 parent b89b670 commit c9089c8
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 5 deletions.
2 changes: 1 addition & 1 deletion runtime/interpreter/interpreter_statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ func (interpreter *Interpreter) VisitRemoveStatement(removeStatement *ast.Remove

if attachment.IsResourceKinded(interpreter) {
// this attachment is no longer attached to its base, but the `base` variable is still available in the destructor
attachment.setBaseValue(interpreter, base, attachmentBaseAuthorization(interpreter, attachment))
attachment.setBaseValue(interpreter, base)
attachment.Destroy(interpreter, locationRange)
}

Expand Down
10 changes: 6 additions & 4 deletions runtime/interpreter/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -16513,7 +16513,7 @@ func (v *CompositeValue) Destroy(interpreter *Interpreter, locationRange Locatio
// is a necessary pre-requisite for calling any members of the attachment. However, in
// the case of a destructor, this is called implicitly, and thus must have its `base`
// set manually
attachment.setBaseValue(interpreter, v, attachmentBaseAuthorization(interpreter, attachment))
attachment.setBaseValue(interpreter, v)
attachment.Destroy(interpreter, locationRange)
})

Expand Down Expand Up @@ -17276,7 +17276,7 @@ func (v *CompositeValue) Transfer(
if compositeValue, ok := value.(*CompositeValue); ok &&
compositeValue.Kind == common.CompositeKindAttachment {

compositeValue.setBaseValue(interpreter, v, attachmentBaseAuthorization(interpreter, compositeValue))
compositeValue.setBaseValue(interpreter, v)
}

value = value.Transfer(
Expand Down Expand Up @@ -17594,7 +17594,7 @@ func (v *CompositeValue) getBaseValue() *EphemeralReferenceValue {
return v.base
}

func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeValue, authorization Authorization) {
func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeValue) {
attachmentType, ok := interpreter.MustSemaTypeOfValue(v).(*sema.CompositeType)
if !ok {
panic(errors.NewUnreachableError())
Expand All @@ -17608,6 +17608,7 @@ func (v *CompositeValue) setBaseValue(interpreter *Interpreter, base *CompositeV
baseType = ty
}

authorization := attachmentBaseAuthorization(interpreter, v)
v.base = NewEphemeralReferenceValue(interpreter, authorization, base, baseType)
interpreter.trackReferencedResourceKindedValue(base.StorageID(), base)
}
Expand Down Expand Up @@ -17762,6 +17763,7 @@ func (v *CompositeValue) forEachAttachment(interpreter *Interpreter, _ LocationR
// attachments is added that takes a `fun (&Attachment): Void` callback, the `f` provided here
// should convert the provided attachment value into a reference before passing it to the user
// callback
attachment.setBaseValue(interpreter, v)
f(attachment)
}
}
Expand All @@ -17779,7 +17781,7 @@ func (v *CompositeValue) getTypeKey(
}
attachmentType := keyType.(*sema.CompositeType)
// dynamically set the attachment's base to this composite, but with authorization based on the requested access on that attachment
attachment.setBaseValue(interpreter, v, attachmentBaseAuthorization(interpreter, attachment))
attachment.setBaseValue(interpreter, v)

// Map the entitlements of the accessing reference through the attachment's entitlement map to get the authorization of this reference
attachmentReferenceAuth, err := attachmentReferenceAuthorization(interpreter, attachmentType, baseAccess)
Expand Down
34 changes: 34 additions & 0 deletions runtime/tests/interpreter/attachments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2237,6 +2237,40 @@ func TestInterpretMutationDuringForEachAttachment(t *testing.T) {

AssertValuesEqual(t, inter, interpreter.NewUnmeteredIntValueFromInt64(3), value)
})

t.Run("callback", func(t *testing.T) {

t.Parallel()

inter := parseCheckAndInterpret(t, `
access(all) resource R {
let foo: Int
init() {
self.foo = 9
}
}
access(all) attachment A for R {
access(all) fun touchBase(): Int {
var foo = base.foo
return foo
}
}
access(all) fun main(): Int {
var r <- attach A() to <- create R()
var id: Int = 0
r.forEachAttachment(fun(a: &AnyResourceAttachment) {
id = (a as! &A).touchBase()
});
destroy r
return id
}
`)

value, err := inter.Invoke("main")
require.NoError(t, err)

AssertValuesEqual(t, inter, interpreter.NewUnmeteredIntValueFromInt64(9), value)
})
}

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

0 comments on commit c9089c8

Please sign in to comment.