@@ -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
681690func (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
24692523func (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
30903177func (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
32373345func (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
32573410func (c * Compiler [_ , _ ]) emitTransferAndConvert (targetType sema.Type ) {
0 commit comments