Skip to content

Commit 3748a84

Browse files
authored
Merge pull request onflow#4052 from onflow/raymond/attachments
[Compiler] Attachments #1/3
2 parents 196ea92 + 27e57fd commit 3748a84

15 files changed

+630
-55
lines changed

bbq/compiler/compiler.go

Lines changed: 172 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ func (c *Compiler[E, T]) Compile() *bbq.Program[E, T] {
575575
variableDeclarations := c.Program.VariableDeclarations()
576576
functionDeclarations := c.Program.FunctionDeclarations()
577577
interfaceDeclarations := c.Program.InterfaceDeclarations()
578+
attachmentDeclarations := c.Program.AttachmentDeclarations()
578579

579580
// Reserve globals for functions/types before visiting their implementations.
580581
c.reserveGlobals(
@@ -583,6 +584,7 @@ func (c *Compiler[E, T]) Compile() *bbq.Program[E, T] {
583584
functionDeclarations,
584585
compositeDeclarations,
585586
interfaceDeclarations,
587+
attachmentDeclarations,
586588
)
587589

588590
// Compile declarations
@@ -598,6 +600,9 @@ func (c *Compiler[E, T]) Compile() *bbq.Program[E, T] {
598600
for _, declaration := range interfaceDeclarations {
599601
c.compileDeclaration(declaration)
600602
}
603+
for _, declaration := range attachmentDeclarations {
604+
c.compileDeclaration(declaration)
605+
}
601606

602607
functions := c.exportFunctions()
603608
constants := c.exportConstants()
@@ -621,6 +626,7 @@ func (c *Compiler[_, _]) reserveGlobals(
621626
functionDecls []*ast.FunctionDeclaration,
622627
compositeDecls []*ast.CompositeDeclaration,
623628
interfaceDecls []*ast.InterfaceDeclaration,
629+
attachmentDecls []*ast.AttachmentDeclaration,
624630
) {
625631
// Reserve globals for the contract values before everything.
626632
// Contract values must be always start at the zero-th index.
@@ -641,6 +647,7 @@ func (c *Compiler[_, _]) reserveGlobals(
641647
functionDecls,
642648
compositeDecls,
643649
interfaceDecls,
650+
attachmentDecls,
644651
)
645652
}
646653

@@ -676,6 +683,8 @@ func (c *Compiler[_, _]) reserveVariableGlobals(
676683
members.Composites(),
677684
)
678685
}
686+
687+
// attachments will not have nested enum/composite declarations
679688
}
680689

681690
func (c *Compiler[_, _]) reserveFunctionGlobals(
@@ -684,6 +693,7 @@ func (c *Compiler[_, _]) reserveFunctionGlobals(
684693
functionDecls []*ast.FunctionDeclaration,
685694
compositeDecls []*ast.CompositeDeclaration,
686695
interfaceDecls []*ast.InterfaceDeclaration,
696+
attachmentDecls []*ast.AttachmentDeclaration,
687697
) {
688698
for _, declaration := range specialFunctionDecls {
689699
switch declaration.Kind {
@@ -765,6 +775,7 @@ func (c *Compiler[_, _]) reserveFunctionGlobals(
765775
members.Functions(),
766776
members.Composites(),
767777
members.Interfaces(),
778+
members.Attachments(),
768779
)
769780
}
770781

@@ -780,6 +791,26 @@ func (c *Compiler[_, _]) reserveFunctionGlobals(
780791
members.Functions(),
781792
members.Composites(),
782793
members.Interfaces(),
794+
members.Attachments(),
795+
)
796+
}
797+
798+
for _, declaration := range attachmentDecls {
799+
compositeType := c.DesugaredElaboration.CompositeDeclarationType(declaration)
800+
// Reserve a global for the constructor function.
801+
802+
constructorName := commons.TypeQualifier(compositeType)
803+
c.addGlobal(constructorName)
804+
805+
members := declaration.Members
806+
807+
c.reserveFunctionGlobals(
808+
compositeType,
809+
members.SpecialFunctions(),
810+
members.Functions(),
811+
members.Composites(),
812+
members.Interfaces(),
813+
members.Attachments(),
783814
)
784815
}
785816
}
@@ -2086,7 +2117,11 @@ func (c *Compiler[_, _]) emitVariableStore(name string) {
20862117
})
20872118
}
20882119

2089-
func (c *Compiler[_, _]) VisitInvocationExpression(expression *ast.InvocationExpression) (_ struct{}) {
2120+
func (c *Compiler[_, _]) visitInvocationExpressionWithImplicitArgument(
2121+
expression *ast.InvocationExpression,
2122+
implicitArgIndex uint16,
2123+
implicitArgType sema.Type,
2124+
) (_ struct{}) {
20902125
// TODO: copy
20912126

20922127
invocationTypes := c.DesugaredElaboration.InvocationExpressionTypes(expression)
@@ -2130,10 +2165,29 @@ func (c *Compiler[_, _]) VisitInvocationExpression(expression *ast.InvocationExp
21302165
c.compileArguments(expression.Arguments, invocationTypes)
21312166

21322167
typeArgs := c.loadTypeArguments(invocationTypes)
2168+
if implicitArgType != nil {
2169+
// Add the implicit argument to the end of the argument list, if it exists.
2170+
// Used in attachments, the attachment constructor/init expects an implicit argument:
2171+
// a reference to the base value used to set base.
2172+
// This hides the base argument away from the user.
2173+
typeArgs = append(typeArgs, c.getOrAddType(implicitArgType))
2174+
argumentCount += 1
2175+
if argumentCount >= math.MaxUint16 {
2176+
panic(errors.NewDefaultUserError("invalid number of arguments"))
2177+
}
2178+
// Load implicit argument from locals
2179+
c.emitGetLocal(implicitArgIndex)
2180+
}
2181+
21332182
c.emit(opcode.InstructionInvoke{
21342183
TypeArgs: typeArgs,
21352184
ArgCount: uint16(argumentCount),
21362185
})
2186+
return
2187+
}
2188+
2189+
func (c *Compiler[_, _]) VisitInvocationExpression(expression *ast.InvocationExpression) (_ struct{}) {
2190+
c.visitInvocationExpressionWithImplicitArgument(expression, 0, nil)
21372191

21382192
return
21392193
}
@@ -2468,9 +2522,16 @@ func (c *Compiler[_, _]) compileMemberAccess(expression *ast.MemberExpression) {
24682522

24692523
func (c *Compiler[_, _]) VisitIndexExpression(expression *ast.IndexExpression) (_ struct{}) {
24702524
c.compileExpression(expression.TargetExpression)
2471-
c.compileExpression(expression.IndexingExpression)
24722525

2473-
c.compileIndexAccess(expression)
2526+
if attachmentType, ok := c.DesugaredElaboration.AttachmentAccessTypes(expression); ok {
2527+
c.emit(opcode.InstructionGetTypeIndex{
2528+
Type: c.getOrAddType(attachmentType),
2529+
})
2530+
} else {
2531+
c.compileExpression(expression.IndexingExpression)
2532+
2533+
c.compileIndexAccess(expression)
2534+
}
24742535

24752536
return
24762537
}
@@ -2892,6 +2953,31 @@ func (c *Compiler[_, _]) compileInitializer(declaration *ast.SpecialFunctionDecl
28922953
},
28932954
)
28942955

2956+
// stores the return value of the constructor
2957+
var returnLocalIndex uint16
2958+
// `self` in attachments is a reference.
2959+
if kind == common.CompositeKindAttachment {
2960+
// Store the new composite as the return value.
2961+
returnLocalIndex = c.currentFunction.generateLocalIndex()
2962+
c.emitSetLocal(returnLocalIndex)
2963+
c.emitGetLocal(returnLocalIndex)
2964+
baseTyp := enclosingType.(sema.EntitlementSupportingType)
2965+
baseAccess := baseTyp.SupportedEntitlements().Access()
2966+
refType := &sema.ReferenceType{
2967+
Type: baseTyp,
2968+
Authorization: baseAccess,
2969+
}
2970+
// Set `self` to be a reference.
2971+
c.emit(opcode.InstructionNewRef{
2972+
Type: c.getOrAddType(refType),
2973+
IsImplicit: false,
2974+
})
2975+
2976+
// TODO: expose base, a reference to the attachment's base value
2977+
} else {
2978+
returnLocalIndex = self.index
2979+
}
2980+
28952981
if kind == common.CompositeKindContract {
28962982
// During contract init, update the global variable with the newly initialized contract value.
28972983
// So accessing the contract through the global variable while initializing itself, would work.
@@ -2923,7 +3009,7 @@ func (c *Compiler[_, _]) compileInitializer(declaration *ast.SpecialFunctionDecl
29233009
)
29243010

29253011
// Constructor should return the created the struct. i.e: return `self`
2926-
c.emitGetLocal(self.index)
3012+
c.emitGetLocal(returnLocalIndex)
29273013

29283014
// No need to transfer, since the type is same as the constructed value, for initializers.
29293015
c.emit(opcode.InstructionReturnValue{})
@@ -3025,9 +3111,7 @@ func (c *Compiler[_, _]) VisitCompositeDeclaration(declaration *ast.CompositeDec
30253111
}
30263112

30273113
c.compositeTypeStack.push(compositeType)
3028-
defer func() {
3029-
c.compositeTypeStack.pop()
3030-
}()
3114+
defer c.compositeTypeStack.pop()
30313115

30323116
// Compile members
30333117
hasInit := false
@@ -3085,14 +3169,15 @@ func (c *Compiler[_, _]) compileCompositeMembers(
30853169
for _, nestedType := range members.Interfaces() {
30863170
c.compileDeclaration(nestedType)
30873171
}
3172+
for _, nestedAttachments := range members.Attachments() {
3173+
c.compileDeclaration(nestedAttachments)
3174+
}
30883175
}
30893176

30903177
func (c *Compiler[_, _]) VisitInterfaceDeclaration(declaration *ast.InterfaceDeclaration) (_ struct{}) {
30913178
interfaceType := c.DesugaredElaboration.InterfaceDeclarationType(declaration)
30923179
c.compositeTypeStack.push(interfaceType)
3093-
defer func() {
3094-
c.compositeTypeStack.pop()
3095-
}()
3180+
defer c.compositeTypeStack.pop()
30963181

30973182
// Visit members.
30983183
c.compileCompositeMembers(interfaceType, declaration.Members)
@@ -3229,9 +3314,32 @@ func (c *Compiler[_, _]) compileEnumCaseDeclaration(
32293314
return
32303315
}
32313316

3232-
func (c *Compiler[_, _]) VisitAttachmentDeclaration(_ *ast.AttachmentDeclaration) (_ struct{}) {
3233-
// TODO
3234-
panic(errors.NewUnreachableError())
3317+
func (c *Compiler[_, _]) VisitAttachmentDeclaration(declaration *ast.AttachmentDeclaration) (_ struct{}) {
3318+
// Similar to VisitCompositeDeclaration
3319+
// Not combined because need to access fields not accessible in CompositeLikeDeclaration
3320+
compositeType := c.DesugaredElaboration.CompositeDeclarationType(declaration)
3321+
3322+
c.compositeTypeStack.push(compositeType)
3323+
defer c.compositeTypeStack.pop()
3324+
3325+
// Compile members
3326+
hasInit := false
3327+
for _, specialFunc := range declaration.Members.SpecialFunctions() {
3328+
if specialFunc.Kind == common.DeclarationKindInitializer {
3329+
hasInit = true
3330+
}
3331+
c.compileDeclaration(specialFunc)
3332+
}
3333+
3334+
// If the initializer is not declared, generate an empty initializer
3335+
if !hasInit {
3336+
c.generateEmptyInit()
3337+
}
3338+
3339+
// Visit members.
3340+
c.compileCompositeMembers(compositeType, declaration.Members)
3341+
3342+
return
32353343
}
32363344

32373345
func (c *Compiler[_, _]) VisitEntitlementDeclaration(_ *ast.EntitlementDeclaration) (_ struct{}) {
@@ -3244,14 +3352,59 @@ func (c *Compiler[_, _]) VisitEntitlementMappingDeclaration(_ *ast.EntitlementMa
32443352
panic(errors.NewUnreachableError())
32453353
}
32463354

3247-
func (c *Compiler[_, _]) VisitRemoveStatement(_ *ast.RemoveStatement) (_ struct{}) {
3248-
// TODO
3249-
panic(errors.NewUnreachableError())
3355+
func (c *Compiler[_, _]) VisitRemoveStatement(statement *ast.RemoveStatement) (_ struct{}) {
3356+
// load base onto stack
3357+
c.compileExpression(statement.Value)
3358+
// remove attachment from base
3359+
nominalType := c.DesugaredElaboration.AttachmentRemoveTypes(statement)
3360+
c.emit(opcode.InstructionRemoveTypeIndex{
3361+
Type: c.getOrAddType(nominalType),
3362+
})
3363+
return
32503364
}
32513365

3252-
func (c *Compiler[_, _]) VisitAttachExpression(_ *ast.AttachExpression) (_ struct{}) {
3253-
// TODO
3254-
panic(errors.NewUnreachableError())
3366+
func (c *Compiler[_, _]) VisitAttachExpression(expression *ast.AttachExpression) (_ struct{}) {
3367+
types := c.DesugaredElaboration.AttachTypes(expression)
3368+
baseType := types.BaseType
3369+
attachmentType := types.AttachType
3370+
3371+
// base on stack
3372+
c.compileExpression(expression.Base)
3373+
// store base locally
3374+
baseLocalIndex := c.currentFunction.generateLocalIndex()
3375+
c.emitSetLocal(baseLocalIndex)
3376+
// get base back on stack
3377+
c.emitGetLocal(baseLocalIndex)
3378+
baseTyp := baseType.(sema.EntitlementSupportingType)
3379+
baseAccess := baseTyp.SupportedEntitlements().Access()
3380+
refType := &sema.ReferenceType{
3381+
Type: baseTyp,
3382+
Authorization: baseAccess,
3383+
}
3384+
// create reference to base to pass as implicit arg
3385+
c.emit(opcode.InstructionNewRef{
3386+
Type: c.getOrAddType(refType),
3387+
IsImplicit: false,
3388+
})
3389+
refLocalIndex := c.currentFunction.generateLocalIndex()
3390+
c.emitSetLocal(refLocalIndex)
3391+
3392+
// create the attachment
3393+
c.visitInvocationExpressionWithImplicitArgument(expression.Attachment, refLocalIndex, baseType)
3394+
// attachment on stack
3395+
3396+
// base back on stack
3397+
c.emitGetLocal(baseLocalIndex)
3398+
// TODO: do attachment.setbaseValue(...)
3399+
// base should now be transferred
3400+
c.emitTransfer()
3401+
3402+
// add attachment value as a member of transferred base
3403+
// returns the result
3404+
c.emit(opcode.InstructionSetTypeIndex{
3405+
Type: c.getOrAddType(attachmentType),
3406+
})
3407+
return
32553408
}
32563409

32573410
func (c *Compiler[_, _]) emitTransferAndConvert(targetType sema.Type) {

0 commit comments

Comments
 (0)