Skip to content

Commit

Permalink
Fix attachment 'self' access
Browse files Browse the repository at this point in the history
  • Loading branch information
SupunS committed Jun 9, 2023
1 parent 9743293 commit ece3d8f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 7 deletions.
3 changes: 1 addition & 2 deletions runtime/sema/check_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,7 @@ func (checker *Checker) VisitIndexExpression(expression *ast.IndexExpression) Ty
// 1) is accessed via a reference, and
// 2) is container-typed,
// then the element type should also be a reference.
if _, accessedViaReference := parentType.(*ReferenceType); accessedViaReference &&
checker.isContainerType(elementType) {
if shouldReturnReference(parentType, elementType) {
elementType = checker.getReferenceType(elementType)
}

Expand Down
25 changes: 20 additions & 5 deletions runtime/sema/check_member_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,16 @@ func (checker *Checker) VisitMemberExpression(expression *ast.MemberExpression)
// 1) is accessed via a reference, and
// 2) is container-typed,
// then the member type should also be a reference.
if _, accessedViaReference := accessedType.(*ReferenceType); accessedViaReference &&
member.DeclarationKind == common.DeclarationKindField &&
checker.isContainerType(memberType) {

// Note: For attachments, `self` is always a reference.
// But we do not want to return a reference for `self.something`.
// Otherwise, things like `destroy self.something` would become invalid.
// Hence, special case `self`, and return a reference only if the member is not accessed via self.
// i.e: `accessedSelfMember == nil`

if accessedSelfMember == nil &&
shouldReturnReference(accessedType, memberType) &&
member.DeclarationKind == common.DeclarationKindField {
// Get a reference to the type
memberType = checker.getReferenceType(memberType)
}
Expand All @@ -120,14 +127,22 @@ func (checker *Checker) getReferenceType(typ Type) Type {
return NewReferenceType(checker.memoryGauge, typ, false)
}

func (checker *Checker) isContainerType(typ Type) bool {
func shouldReturnReference(parentType, memberType Type) bool {
if _, parentIsReference := parentType.(*ReferenceType); !parentIsReference {
return false
}

return isContainerType(memberType)
}

func isContainerType(typ Type) bool {
switch typ := typ.(type) {
case *CompositeType,
*DictionaryType,
ArrayType:
return true
case *OptionalType:
return checker.isContainerType(typ.Type)
return isContainerType(typ.Type)
default:
return false
}
Expand Down

0 comments on commit ece3d8f

Please sign in to comment.