From fc98b381f635576d1af867063c6d5bd441c52249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 17 Feb 2021 17:51:58 -0800 Subject: [PATCH] cache members of composite types and interface types --- runtime/sema/check_composite_declaration.go | 2 +- runtime/sema/type.go | 112 ++++++++++++-------- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/runtime/sema/check_composite_declaration.go b/runtime/sema/check_composite_declaration.go index 1183c5be75..8ceb599a31 100644 --- a/runtime/sema/check_composite_declaration.go +++ b/runtime/sema/check_composite_declaration.go @@ -584,7 +584,7 @@ func (checker *Checker) declareCompositeMembersAndValue( continue } - nestedCompositeType.AddImplicitTypeRequirementConformance(typeRequirement) + nestedCompositeType.addImplicitTypeRequirementConformance(typeRequirement) } }) diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 27ac6b4527..91eb8453dc 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -4760,6 +4760,8 @@ type CompositeType struct { ExplicitInterfaceConformances []*InterfaceType ImplicitTypeRequirementConformances []*CompositeType Members *StringMemberOrderedMap + memberResolversOnce sync.Once + memberResolvers map[string]MemberResolver Fields []string // TODO: add support for overloaded initializers ConstructorParameters []*Parameter @@ -4785,7 +4787,7 @@ func (t *CompositeType) initializeExplicitInterfaceConformanceSet() { }) } -func (t *CompositeType) AddImplicitTypeRequirementConformance(typeRequirement *CompositeType) { +func (t *CompositeType) addImplicitTypeRequirementConformance(typeRequirement *CompositeType) { t.ImplicitTypeRequirementConformances = append(t.ImplicitTypeRequirementConformances, typeRequirement) } @@ -4831,35 +4833,8 @@ func (t *CompositeType) Equal(other Type) bool { } func (t *CompositeType) GetMembers() map[string]MemberResolver { - // TODO: optimize - members := make(map[string]MemberResolver, t.Members.Len()) - t.Members.Foreach(func(name string, loopMember *Member) { - // NOTE: don't capture loop variable - member := loopMember - members[name] = MemberResolver{ - Kind: member.DeclarationKind, - Resolve: func(_ string, _ ast.Range, _ func(error)) *Member { - return member - }, - } - }) - - // Check conformances. - // If this composite type results from a normal composite declaration, - // it must have members declared for all interfaces it conforms to. - // However, if this composite type is a type requirement, - // it acts like an interface and does not have to declare members. - - t.ExplicitInterfaceConformanceSet(). - ForEach(func(conformance *InterfaceType) { - for name, resolver := range conformance.GetMembers() { - if _, ok := members[name]; !ok { - members[name] = resolver - } - } - }) - - return withBuiltinMembers(t, members) + t.initializeMemberResolvers() + return t.memberResolvers } func (t *CompositeType) IsResourceType() bool { @@ -4982,6 +4957,40 @@ func (t *CompositeType) NestedTypes() *StringTypeOrderedMap { return t.nestedTypes } +func (t *CompositeType) initializeMemberResolvers() { + t.memberResolversOnce.Do(func() { + members := make(map[string]MemberResolver, t.Members.Len()) + + t.Members.Foreach(func(name string, loopMember *Member) { + // NOTE: don't capture loop variable + member := loopMember + members[name] = MemberResolver{ + Kind: member.DeclarationKind, + Resolve: func(_ string, _ ast.Range, _ func(error)) *Member { + return member + }, + } + }) + + // Check conformances. + // If this composite type results from a normal composite declaration, + // it must have members declared for all interfaces it conforms to. + // However, if this composite type is a type requirement, + // it acts like an interface and does not have to declare members. + + t.ExplicitInterfaceConformanceSet(). + ForEach(func(conformance *InterfaceType) { + for name, resolver := range conformance.GetMembers() { + if _, ok := members[name]; !ok { + members[name] = resolver + } + } + }) + + t.memberResolvers = withBuiltinMembers(t, members) + }) +} + // AuthAccountType represents the authorized access to an account. // Access to an AuthAccount means having full access to its storage, public keys, and code. // Only signed transactions can get the AuthAccount for an account. @@ -5820,11 +5829,13 @@ func (m *Member) testType(test func(Type) bool, results map[*Member]bool) (resul // InterfaceType type InterfaceType struct { - Location common.Location - Identifier string - CompositeKind common.CompositeKind - Members *StringMemberOrderedMap - Fields []string + Location common.Location + Identifier string + CompositeKind common.CompositeKind + Members *StringMemberOrderedMap + memberResolversOnce sync.Once + memberResolvers map[string]MemberResolver + Fields []string // TODO: add support for overloaded initializers InitializerParameters []*Parameter ContainerType Type @@ -5872,19 +5883,26 @@ func (t *InterfaceType) Equal(other Type) bool { } func (t *InterfaceType) GetMembers() map[string]MemberResolver { - // TODO: optimize - members := make(map[string]MemberResolver, t.Members.Len()) - t.Members.Foreach(func(name string, loopMember *Member) { - // NOTE: don't capture loop variable - member := loopMember - members[name] = MemberResolver{ - Kind: member.DeclarationKind, - Resolve: func(_ string, _ ast.Range, _ func(error)) *Member { - return member - }, - } + t.initializeMemberResolvers() + return t.memberResolvers +} + +func (t *InterfaceType) initializeMemberResolvers() { + t.memberResolversOnce.Do(func() { + members := make(map[string]MemberResolver, t.Members.Len()) + t.Members.Foreach(func(name string, loopMember *Member) { + // NOTE: don't capture loop variable + member := loopMember + members[name] = MemberResolver{ + Kind: member.DeclarationKind, + Resolve: func(_ string, _ ast.Range, _ func(error)) *Member { + return member + }, + } + }) + + t.memberResolvers = withBuiltinMembers(t, members) }) - return withBuiltinMembers(t, members) } func (t *InterfaceType) IsResourceType() bool {