From 552f09f89562ee3bba9f5572a45fcee4c5b941a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 18 Apr 2024 13:41:42 -0700 Subject: [PATCH] use new entitlement set in SupportedEntitlements this also improves the inferrence of entitlements in the entitlement migration --- migrations/entitlements/migration.go | 2 +- migrations/entitlements/migration_test.go | 2 +- runtime/interpreter/interpreter.go | 18 +-- runtime/interpreter/interpreter_expression.go | 2 +- runtime/interpreter/value.go | 4 +- runtime/sema/access.go | 2 +- runtime/sema/check_composite_declaration.go | 31 +++- runtime/sema/check_function.go | 2 +- runtime/sema/check_member_expression.go | 9 +- runtime/sema/errors.go | 4 + runtime/sema/type.go | 137 +++++++++++------- runtime/sema/type_tags.go | 8 +- ..._v0.42_to_v1_contract_upgrade_validator.go | 11 +- 13 files changed, 131 insertions(+), 101 deletions(-) diff --git a/migrations/entitlements/migration.go b/migrations/entitlements/migration.go index 3b73fecc23..3f4b58fd55 100644 --- a/migrations/entitlements/migration.go +++ b/migrations/entitlements/migration.go @@ -123,7 +123,7 @@ func ConvertToEntitledType( default: supportedEntitlements := entitlementSupportingType.SupportedEntitlements() - newAccess := sema.NewAccessFromEntitlementSet(supportedEntitlements, sema.Conjunction) + newAccess := supportedEntitlements.Access() auth = interpreter.ConvertSemaAccessToStaticAuthorization(inter, newAccess) returnNew = true } diff --git a/migrations/entitlements/migration_test.go b/migrations/entitlements/migration_test.go index 21846b1a4e..ea79ea671f 100644 --- a/migrations/entitlements/migration_test.go +++ b/migrations/entitlements/migration_test.go @@ -474,7 +474,7 @@ func TestConvertToEntitledType(t *testing.T) { }, { Input: sema.NewReferenceType(nil, sema.UnauthorizedAccess, compositeResourceWithEOrF), - Output: sema.NewReferenceType(nil, eAndFAccess, compositeResourceWithEOrF), + Output: sema.NewReferenceType(nil, eOrFAccess, compositeResourceWithEOrF), Name: "composite E or F", }, { diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 16b438c834..39511f6b3b 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -817,14 +817,8 @@ func (interpreter *Interpreter) resultValue(returnValue Value, returnType sema.T auth := UnauthorizedAccess // reference is authorized to the entire resource, since it is only accessible in a function where a resource value is owned if entitlementSupportingType, ok := ty.(sema.EntitlementSupportingType); ok { - supportedEntitlements := entitlementSupportingType.SupportedEntitlements() - if supportedEntitlements != nil && supportedEntitlements.Len() > 0 { - access := sema.EntitlementSetAccess{ - SetKind: sema.Conjunction, - Entitlements: supportedEntitlements, - } - auth = ConvertSemaAccessToStaticAuthorization(interpreter, access) - } + access := entitlementSupportingType.SupportedEntitlements().Access() + auth = ConvertSemaAccessToStaticAuthorization(interpreter, access) } return auth } @@ -1038,7 +1032,7 @@ func (interpreter *Interpreter) evaluateDefaultDestroyEvent( panic(errors.NewUnreachableError()) } supportedEntitlements := entitlementSupportingType.SupportedEntitlements() - access := sema.NewAccessFromEntitlementSet(supportedEntitlements, sema.Conjunction) + access := supportedEntitlements.Access() base, self = attachmentBaseAndSelfValues( declarationInterpreter, access, @@ -1393,10 +1387,8 @@ func (declarationInterpreter *Interpreter) declareNonEnumCompositeValue( // Self's type in the constructor is fully entitled, since // the constructor can only be called when in possession of the base resource - auth := ConvertSemaAccessToStaticAuthorization( - interpreter, - sema.NewAccessFromEntitlementSet(attachmentType.SupportedEntitlements(), sema.Conjunction), - ) + access := attachmentType.SupportedEntitlements().Access() + auth := ConvertSemaAccessToStaticAuthorization(interpreter, access) self = NewEphemeralReferenceValue(interpreter, auth, value, attachmentType, locationRange) diff --git a/runtime/interpreter/interpreter_expression.go b/runtime/interpreter/interpreter_expression.go index 81b31b4a00..41efd18cd5 100644 --- a/runtime/interpreter/interpreter_expression.go +++ b/runtime/interpreter/interpreter_expression.go @@ -1562,7 +1562,7 @@ func (interpreter *Interpreter) VisitAttachExpression(attachExpression *ast.Atta // within the constructor, the attachment's base and self references should be fully entitled, // as the constructor of the attachment is only callable by the owner of the base baseType := interpreter.MustSemaTypeOfValue(base).(sema.EntitlementSupportingType) - baseAccess := sema.NewAccessFromEntitlementSet(baseType.SupportedEntitlements(), sema.Conjunction) + baseAccess := baseType.SupportedEntitlements().Access() auth := ConvertSemaAccessToStaticAuthorization(interpreter, baseAccess) attachmentType := interpreter.Program.Elaboration.AttachTypes(attachExpression) diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index 40ba2719c7..ec3dd005e0 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -18370,10 +18370,10 @@ func (v *CompositeValue) GetTypeKey( locationRange LocationRange, ty sema.Type, ) Value { - var access sema.Access = sema.UnauthorizedAccess + access := sema.UnauthorizedAccess attachmentTyp, isAttachmentType := ty.(*sema.CompositeType) if isAttachmentType { - access = sema.NewAccessFromEntitlementSet(attachmentTyp.SupportedEntitlements(), sema.Conjunction) + access = attachmentTyp.SupportedEntitlements().Access() } return v.getTypeKey(interpreter, locationRange, ty, access) } diff --git a/runtime/sema/access.go b/runtime/sema/access.go index 0d17df61c1..c3ef376f53 100644 --- a/runtime/sema/access.go +++ b/runtime/sema/access.go @@ -74,7 +74,7 @@ func NewEntitlementSetAccess( } } -func NewAccessFromEntitlementSet( +func NewAccessFromEntitlementOrderedSet( set *EntitlementOrderedSet, setKind EntitlementSetKind, ) Access { diff --git a/runtime/sema/check_composite_declaration.go b/runtime/sema/check_composite_declaration.go index d18536496d..c64ac8487d 100644 --- a/runtime/sema/check_composite_declaration.go +++ b/runtime/sema/check_composite_declaration.go @@ -107,20 +107,35 @@ func (checker *Checker) checkAttachmentMembersAccess(attachmentType *CompositeTy var supportedBaseEntitlements *EntitlementOrderedSet baseType := attachmentType.GetBaseType() if base, ok := attachmentType.GetBaseType().(EntitlementSupportingType); ok { - supportedBaseEntitlements = base.SupportedEntitlements() + // TODO: + access := base.SupportedEntitlements().Access() + if access, ok := access.(EntitlementSetAccess); ok { + supportedBaseEntitlements = access.Entitlements + } } if supportedBaseEntitlements == nil { supportedBaseEntitlements = &orderedmap.OrderedMap[*EntitlementType, struct{}]{} } - attachmentType.EffectiveInterfaceConformanceSet().ForEach(func(intf *InterfaceType) { - intf.Members.Foreach(func(_ string, member *Member) { - checker.checkAttachmentMemberAccess(attachmentType, member, baseType, supportedBaseEntitlements) + attachmentType.EffectiveInterfaceConformanceSet(). + ForEach(func(interfaceType *InterfaceType) { + interfaceType.Members.Foreach(func(_ string, member *Member) { + checker.checkAttachmentMemberAccess( + attachmentType, + member, + baseType, + supportedBaseEntitlements, + ) + }) }) - }) attachmentType.Members.Foreach(func(_ string, member *Member) { - checker.checkAttachmentMemberAccess(attachmentType, member, baseType, supportedBaseEntitlements) + checker.checkAttachmentMemberAccess( + attachmentType, + member, + baseType, + supportedBaseEntitlements, + ) }) } @@ -2081,7 +2096,7 @@ func (checker *Checker) checkDefaultDestroyEventParam( // make `self` and `base` available when checking default arguments so the fields of the composite are available // as this event is emitted when the resource is destroyed, these values should be fully entitled - fullyEntitledAccess := NewAccessFromEntitlementSet(containerType.SupportedEntitlements(), Conjunction) + fullyEntitledAccess := containerType.SupportedEntitlements().Access() checker.declareSelfValue( fullyEntitledAccess, @@ -2224,7 +2239,7 @@ func (checker *Checker) checkSpecialFunction( defer checker.leaveValueScope(specialFunction.EndPosition, checkResourceLoss) // initializers and destructors are considered fully entitled to their container type - fnAccess := NewAccessFromEntitlementSet(containerType.SupportedEntitlements(), Conjunction) + fnAccess := containerType.SupportedEntitlements().Access() checker.declareSelfValue(fnAccess, containerType, containerDocString) diff --git a/runtime/sema/check_function.go b/runtime/sema/check_function.go index f94e1ef929..2de49767b6 100644 --- a/runtime/sema/check_function.go +++ b/runtime/sema/check_function.go @@ -423,7 +423,7 @@ func (checker *Checker) visitWithPostConditions(postConditions *ast.Conditions, // here the `result` value in the `post` block will have type `auth(E, X, Y) &R` if entitlementSupportingType, ok := innerType.(EntitlementSupportingType); ok { supportedEntitlements := entitlementSupportingType.SupportedEntitlements() - auth = NewAccessFromEntitlementSet(supportedEntitlements, Conjunction) + auth = supportedEntitlements.Access() } resultType = &ReferenceType{ diff --git a/runtime/sema/check_member_expression.go b/runtime/sema/check_member_expression.go index 8dbbe11580..3f04c0b29f 100644 --- a/runtime/sema/check_member_expression.go +++ b/runtime/sema/check_member_expression.go @@ -521,12 +521,9 @@ func allSupportedEntitlements(typ Type, isInnerType bool) Access { return allSupportedEntitlements(typ.ReturnTypeAnnotation.Type, true) } case EntitlementSupportingType: - supportedEntitlements := typ.SupportedEntitlements() - if supportedEntitlements != nil && supportedEntitlements.Len() > 0 { - return EntitlementSetAccess{ - SetKind: Conjunction, - Entitlements: supportedEntitlements, - } + access := typ.SupportedEntitlements().Access() + if access != UnauthorizedAccess { + return access } } diff --git a/runtime/sema/errors.go b/runtime/sema/errors.go index 6a4153be1b..68a95eb2d7 100644 --- a/runtime/sema/errors.go +++ b/runtime/sema/errors.go @@ -3071,6 +3071,7 @@ func (e *InvalidAccessError) SecondaryError() string { fmt.Fprint(&sb, "reference needs all of entitlements ") missingEntitlements.ForeachWithIndex(enumerateEntitlements(missingLen, "and")) } + case Disjunction: // when both `required` is a disjunction, we know `possessed` has none of the entitlements in it: // suggest adding one of those entitlements @@ -3079,6 +3080,9 @@ func (e *InvalidAccessError) SecondaryError() string { requiredLen := requiredEntitlementsSet.Len() // singleton-1 sets are always conjunctions requiredEntitlementsSet.ForeachWithIndex(enumerateEntitlements(requiredLen, "or")) + + default: + panic(errors.NewUnreachableError()) } return sb.String() diff --git a/runtime/sema/type.go b/runtime/sema/type.go index 08fd27de9a..4627d6a2f8 100644 --- a/runtime/sema/type.go +++ b/runtime/sema/type.go @@ -30,7 +30,6 @@ import ( "github.com/onflow/cadence/fixedpoint" "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" - "github.com/onflow/cadence/runtime/common/orderedmap" "github.com/onflow/cadence/runtime/errors" ) @@ -253,7 +252,7 @@ type NominalType interface { // entitlement supporting types type EntitlementSupportingType interface { Type - SupportedEntitlements() *EntitlementOrderedSet + SupportedEntitlements() *EntitlementSet } // ContainedType is a type which might have a container type @@ -797,7 +796,7 @@ func (t *OptionalType) Resolve(typeArguments *TypeParameterTypeOrderedMap) Type } } -func (t *OptionalType) SupportedEntitlements() *EntitlementOrderedSet { +func (t *OptionalType) SupportedEntitlements() *EntitlementSet { if entitlementSupportingType, ok := t.Type.(EntitlementSupportingType); ok { return entitlementSupportingType.SupportedEntitlements() } @@ -3125,15 +3124,15 @@ func (t *VariableSizedType) Resolve(typeArguments *TypeParameterTypeOrderedMap) } } -func (t *VariableSizedType) SupportedEntitlements() *EntitlementOrderedSet { +func (t *VariableSizedType) SupportedEntitlements() *EntitlementSet { return arrayDictionaryEntitlements } -var arrayDictionaryEntitlements = func() *EntitlementOrderedSet { - set := orderedmap.New[EntitlementOrderedSet](3) - set.Set(MutateType, struct{}{}) - set.Set(InsertType, struct{}{}) - set.Set(RemoveType, struct{}{}) +var arrayDictionaryEntitlements = func() *EntitlementSet { + set := &EntitlementSet{} + set.Add(MutateType) + set.Add(InsertType) + set.Add(RemoveType) return set }() @@ -3321,7 +3320,7 @@ func (t *ConstantSizedType) Resolve(typeArguments *TypeParameterTypeOrderedMap) } } -func (t *ConstantSizedType) SupportedEntitlements() *EntitlementOrderedSet { +func (t *ConstantSizedType) SupportedEntitlements() *EntitlementSet { return arrayDictionaryEntitlements } @@ -4770,7 +4769,7 @@ type CompositeType struct { // Only applicable for native composite types ImportableBuiltin bool supportedEntitlementsOnce sync.Once - supportedEntitlements *EntitlementOrderedSet + supportedEntitlements *EntitlementSet } var _ Type = &CompositeType{} @@ -4957,27 +4956,69 @@ func (t *CompositeType) MemberMap() *StringMemberOrderedMap { return t.Members } -func (t *CompositeType) SupportedEntitlements() *EntitlementOrderedSet { - t.supportedEntitlementsOnce.Do(func() { - set := orderedmap.New[EntitlementOrderedSet](t.Members.Len()) - t.Members.Foreach(func(_ string, member *Member) { - switch access := member.Access.(type) { - case *EntitlementMapAccess: - set.SetAll(access.Domain().Entitlements) - case EntitlementSetAccess: - set.SetAll(access.Entitlements) +// TODO: improve naming +func newCompositeOrInterfaceSupportedEntitlementSet( + members *StringMemberOrderedMap, + effectiveInterfaceConformanceSet *InterfaceSet, +) *EntitlementSet { + set := &EntitlementSet{} + + // First pass: Handle maps and conjunctions + members.Foreach(func(_ string, member *Member) { + switch access := member.Access.(type) { + case *EntitlementMapAccess: + // Domain is a conjunction, add all entitlements + domain := access.Domain() + if domain.SetKind != Conjunction { + panic(errors.NewUnreachableError()) } - }) - t.EffectiveInterfaceConformanceSet().ForEach(func(it *InterfaceType) { - set.SetAll(it.SupportedEntitlements()) - }) + domain.Entitlements. + Foreach(func(entitlementType *EntitlementType, _ struct{}) { + set.Add(entitlementType) + }) + + case EntitlementSetAccess: + // Disjunctions are handled in a second pass + if access.SetKind == Conjunction { + access.Entitlements.Foreach(func(entitlementType *EntitlementType, _ struct{}) { + set.Add(entitlementType) + }) + } + } + }) + + // Second pass: Handle disjunctions + for pair := members.Oldest(); pair != nil; pair = pair.Next() { + member := pair.Value + + if access, ok := member.Access.(EntitlementSetAccess); ok && + access.SetKind == Disjunction { + + set.AddDisjunction(access.Entitlements) + } + } + + effectiveInterfaceConformanceSet.ForEach(func(it *InterfaceType) { + set.Merge(it.SupportedEntitlements()) + }) + + return set +} + +func (t *CompositeType) SupportedEntitlements() *EntitlementSet { + t.supportedEntitlementsOnce.Do(func() { + + set := newCompositeOrInterfaceSupportedEntitlementSet( + t.Members, + t.EffectiveInterfaceConformanceSet(), + ) // attachments support at least the entitlements supported by their base, // and we must ensure there is no recursive case if entitlementSupportingBase, isEntitlementSupportingBase := t.GetBaseType().(EntitlementSupportingType); isEntitlementSupportingBase && entitlementSupportingBase != t { - set.SetAll(entitlementSupportingBase.SupportedEntitlements()) + set.Merge(entitlementSupportingBase.SupportedEntitlements()) } t.supportedEntitlements = set @@ -5155,7 +5196,7 @@ func (t *CompositeType) TypeIndexingElementType(indexingType Type, _ func() ast. case *CompositeType: // when accessed on an owned value, the produced attachment reference is entitled to all the // entitlements it supports - access = NewAccessFromEntitlementSet(attachment.SupportedEntitlements(), Conjunction) + access = attachment.SupportedEntitlements().Access() } return &OptionalType{ @@ -5658,7 +5699,7 @@ type InterfaceType struct { effectiveInterfaceConformances []Conformance effectiveInterfaceConformanceSet *InterfaceSet supportedEntitlementsOnce sync.Once - supportedEntitlements *EntitlementOrderedSet + supportedEntitlements *EntitlementSet DefaultDestroyEvent *CompositeType } @@ -5767,27 +5808,12 @@ func (t *InterfaceType) MemberMap() *StringMemberOrderedMap { return t.Members } -func (t *InterfaceType) SupportedEntitlements() *EntitlementOrderedSet { +func (t *InterfaceType) SupportedEntitlements() *EntitlementSet { t.supportedEntitlementsOnce.Do(func() { - set := orderedmap.New[EntitlementOrderedSet](t.Members.Len()) - t.Members.Foreach(func(_ string, member *Member) { - switch access := member.Access.(type) { - case *EntitlementMapAccess: - access.Domain().Entitlements.Foreach(func(entitlement *EntitlementType, _ struct{}) { - set.Set(entitlement, struct{}{}) - }) - case EntitlementSetAccess: - access.Entitlements.Foreach(func(entitlement *EntitlementType, _ struct{}) { - set.Set(entitlement, struct{}{}) - }) - } - }) - - t.EffectiveInterfaceConformanceSet().ForEach(func(it *InterfaceType) { - set.SetAll(it.SupportedEntitlements()) - }) - - t.supportedEntitlements = set + t.supportedEntitlements = newCompositeOrInterfaceSupportedEntitlementSet( + t.Members, + t.EffectiveInterfaceConformanceSet(), + ) }) return t.supportedEntitlements } @@ -6535,7 +6561,7 @@ func (t *DictionaryType) Resolve(typeArguments *TypeParameterTypeOrderedMap) Typ } } -func (t *DictionaryType) SupportedEntitlements() *EntitlementOrderedSet { +func (t *DictionaryType) SupportedEntitlements() *EntitlementSet { return arrayDictionaryEntitlements } @@ -8146,7 +8172,7 @@ type IntersectionType struct { memberResolvers map[string]MemberResolver memberResolversOnce sync.Once supportedEntitlementsOnce sync.Once - supportedEntitlements *EntitlementOrderedSet + supportedEntitlements *EntitlementSet // Deprecated LegacyType Type } @@ -8401,13 +8427,14 @@ func (t *IntersectionType) initializeMemberResolvers() { }) } -func (t *IntersectionType) SupportedEntitlements() *EntitlementOrderedSet { +func (t *IntersectionType) SupportedEntitlements() *EntitlementSet { t.supportedEntitlementsOnce.Do(func() { // an intersection type supports all the entitlements of its interfaces - set := orderedmap.New[EntitlementOrderedSet](t.EffectiveIntersectionSet().Len()) - t.EffectiveIntersectionSet().ForEach(func(it *InterfaceType) { - set.SetAll(it.SupportedEntitlements()) - }) + set := &EntitlementSet{} + t.EffectiveIntersectionSet(). + ForEach(func(interfaceType *InterfaceType) { + set.Merge(interfaceType.SupportedEntitlements()) + }) t.supportedEntitlements = set }) @@ -8450,7 +8477,7 @@ func (t *IntersectionType) TypeIndexingElementType(indexingType Type, _ func() a case *CompositeType: // when accessed on an owned value, the produced attachment reference is entitled to all the // entitlements it supports - access = NewAccessFromEntitlementSet(attachment.SupportedEntitlements(), Conjunction) + access = attachment.SupportedEntitlements().Access() } return &OptionalType{ diff --git a/runtime/sema/type_tags.go b/runtime/sema/type_tags.go index d54de169c5..1cd45718fa 100644 --- a/runtime/sema/type_tags.go +++ b/runtime/sema/type_tags.go @@ -736,7 +736,7 @@ func leastCommonAccess(accessA, accessB Access) Access { // e.g. the least common supertype of (E, F) and (E, G) is just E intersection := orderedmap.KeySetIntersection(setAccessA.Entitlements, setAccessB.Entitlements) if intersection.Len() != 0 { - return NewAccessFromEntitlementSet(intersection, Conjunction) + return NewAccessFromEntitlementOrderedSet(intersection, Conjunction) } // if the intersection is completely empty (i.e. the two sets are totally disjoint) // the least common supertype is the union of one element arbitrarily chosen from each conjunction. @@ -749,7 +749,7 @@ func leastCommonAccess(accessA, accessB Access) Access { // e.g. the least common supertype of E and F is `(E | F)` // and the least common supertype of `(A, B)` and `(C, D)` is `(A | B | C | D)` union := orderedmap.KeySetUnion(setAccessA.Entitlements, setAccessB.Entitlements) - return NewAccessFromEntitlementSet(union, Disjunction) + return NewAccessFromEntitlementOrderedSet(union, Disjunction) case Disjunction: // least common supertype of a non-disjoint conjunction and a disjunction is @@ -769,7 +769,7 @@ func leastCommonAccess(accessA, accessB Access) Access { // which luckily here is just the union of the elements of the disjunction and the conjunction. // E.g. our computed supertype of `(E, F)` and `(G | H)` is `(E | F | G | H)` union := orderedmap.KeySetUnion(setAccessA.Entitlements, setAccessB.Entitlements) - return NewAccessFromEntitlementSet(union, Disjunction) + return NewAccessFromEntitlementOrderedSet(union, Disjunction) } case Disjunction: @@ -781,7 +781,7 @@ func leastCommonAccess(accessA, accessB Access) Access { // least common access of two disjunctions is their union // e.g. the least common supertype of (E | F) and (E | G) is (E | F | G) union := orderedmap.KeySetUnion(setAccessA.Entitlements, setAccessB.Entitlements) - return NewAccessFromEntitlementSet(union, Disjunction) + return NewAccessFromEntitlementOrderedSet(union, Disjunction) } } diff --git a/runtime/stdlib/cadence_v0.42_to_v1_contract_upgrade_validator.go b/runtime/stdlib/cadence_v0.42_to_v1_contract_upgrade_validator.go index 2b35d7a2cd..47cf58a5d0 100644 --- a/runtime/stdlib/cadence_v0.42_to_v1_contract_upgrade_validator.go +++ b/runtime/stdlib/cadence_v0.42_to_v1_contract_upgrade_validator.go @@ -23,7 +23,6 @@ import ( "github.com/onflow/cadence/runtime/ast" "github.com/onflow/cadence/runtime/common" - "github.com/onflow/cadence/runtime/common/orderedmap" "github.com/onflow/cadence/runtime/errors" "github.com/onflow/cadence/runtime/interpreter" "github.com/onflow/cadence/runtime/sema" @@ -267,7 +266,7 @@ func (validator *CadenceV042ToV1ContractUpdateValidator) expectedAuthorizationOf } supportedEntitlements := compositeType.SupportedEntitlements() - return sema.NewAccessFromEntitlementSet(supportedEntitlements, sema.Conjunction) + return supportedEntitlements.Access() } func (validator *CadenceV042ToV1ContractUpdateValidator) expectedAuthorizationOfIntersection( @@ -279,13 +278,9 @@ func (validator *CadenceV042ToV1ContractUpdateValidator) expectedAuthorizationOf // been a restricted type with no legacy type interfaces := validator.getIntersectedInterfaces(intersectionTypes) - supportedEntitlements := orderedmap.New[sema.EntitlementOrderedSet](0) + intersectionType := sema.NewIntersectionType(nil, nil, interfaces) - for _, interfaceType := range interfaces { - supportedEntitlements.SetAll(interfaceType.SupportedEntitlements()) - } - - return sema.NewAccessFromEntitlementSet(supportedEntitlements, sema.Conjunction) + return intersectionType.SupportedEntitlements().Access() } func (validator *CadenceV042ToV1ContractUpdateValidator) checkEntitlementsUpgrade(