Skip to content

Commit

Permalink
update checker tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dsainati1 committed Oct 18, 2023
1 parent da02665 commit 8e04195
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 307 deletions.
114 changes: 63 additions & 51 deletions runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1026,9 +1026,14 @@ func (checker *Checker) convertReferenceType(t *ast.ReferenceType) Type {
var ty Type

if t.Authorization != nil {
access = checker.accessFromAstAccess(ast.EntitlementAccess{EntitlementSet: t.Authorization.(ast.EntitlementSet)})
switch mapAccess := access.(type) {
case *EntitlementMapAccess:
switch auth := t.Authorization.(type) {
case ast.EntitlementSet:
access = checker.accessFromAstAccess(ast.EntitlementAccess{EntitlementSet: auth})
case *ast.MappedAccess:
access = checker.accessFromAstAccess(auth)
}

if mapAccess, isMapAccess := access.(*EntitlementMapAccess); isMapAccess {
// mapped auth types are only allowed in the annotations of composite fields and accessor functions
if checker.entitlementMappingInScope == nil || !checker.entitlementMappingInScope.Equal(mapAccess.Type) {
checker.report(&InvalidMappedAuthorizationOutsideOfFieldError{
Expand Down Expand Up @@ -1256,19 +1261,21 @@ func (checker *Checker) functionType(
parameterList *ast.ParameterList,
returnTypeAnnotation *ast.TypeAnnotation,
) *FunctionType {

oldMappedAccess := checker.entitlementMappingInScope
if mapAccess, isMapAccess := access.(*EntitlementMapAccess); isMapAccess {
checker.entitlementMappingInScope = mapAccess.Type
} else {
checker.entitlementMappingInScope = nil
}
defer func() { checker.entitlementMappingInScope = oldMappedAccess }()

convertedParameters := checker.parameters(parameterList)

convertedReturnTypeAnnotation := VoidTypeAnnotation
if returnTypeAnnotation != nil {
// to allow entitlement mapping types to be used in the return annotation only of
// a mapped accessor function, we introduce a "variable" into the typing scope while
// checking the return
if mapAccess, isMapAccess := access.(*EntitlementMapAccess); isMapAccess {
checker.entitlementMappingInScope = mapAccess.Type
}
convertedReturnTypeAnnotation =
checker.ConvertTypeAnnotation(returnTypeAnnotation)
checker.entitlementMappingInScope = nil
}

return &FunctionType{
Expand Down Expand Up @@ -1932,6 +1939,31 @@ func (checker *Checker) accessFromAstAccess(access ast.Access) (result Access) {
case ast.PrimitiveAccess:
return PrimitiveAccess(access)

case *ast.MappedAccess:
semaAccess, hasAccess := checker.Elaboration.GetSemanticAccess(access)
if hasAccess {
return semaAccess
}
defer func() {
checker.Elaboration.SetSemanticAccess(access, result)
}()

switch nominalType := checker.convertNominalType(access.EntitlementMap).(type) {
case *EntitlementMapType:
result = NewEntitlementMapAccess(nominalType)
default:
if nominalType != InvalidType {
checker.report(
&InvalidEntitlementMappingTypeError{
Type: nominalType,
Pos: access.EntitlementMap.Identifier.Pos,
},
)
}
result = PrimitiveAccess(ast.AccessNotSpecified)
}
return

case ast.EntitlementAccess:
semaAccess, hasAccess := checker.Elaboration.GetSemanticAccess(access)
if hasAccess {
Expand All @@ -1942,62 +1974,42 @@ func (checker *Checker) accessFromAstAccess(access ast.Access) (result Access) {
}()

astEntitlements := access.EntitlementSet.Entitlements()
nominalType := checker.convertNominalType(astEntitlements[0])

switch nominalType := nominalType.(type) {
case *EntitlementType:
semanticEntitlements := make([]*EntitlementType, 0, len(astEntitlements))
semanticEntitlements = append(semanticEntitlements, nominalType)
semanticEntitlements := make([]*EntitlementType, 0, len(astEntitlements))

for _, entitlement := range astEntitlements[1:] {
nominalType := checker.convertNominalType(entitlement)
entitlementType, ok := nominalType.(*EntitlementType)
if !ok {
// don't duplicate errors when the type here is invalid, as this will have triggered an error before
if nominalType != InvalidType {
for _, entitlement := range astEntitlements {
nominalType := checker.convertNominalType(entitlement)
entitlementType, ok := nominalType.(*EntitlementType)
if !ok {
// don't duplicate errors when the type here is invalid, as this will have triggered an error before
if nominalType != InvalidType {
if _, isMap := nominalType.(*EntitlementMapType); isMap {
checker.report(
&MappingAccessMissingKeywordError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, entitlement),
},
)
} else {
checker.report(
&InvalidNonEntitlementAccessError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, entitlement),
},
)
}
result = PrimitiveAccess(ast.AccessNotSpecified)
return
}
semanticEntitlements = append(semanticEntitlements, entitlementType)
}
if access.EntitlementSet.Separator() == ast.Conjunction {
result = NewEntitlementSetAccess(semanticEntitlements, Conjunction)
return
}
result = NewEntitlementSetAccess(semanticEntitlements, Disjunction)
return
case *EntitlementMapType:
// 0-length entitlement lists are rejected by the parser
if len(astEntitlements) != 1 {
checker.report(
&InvalidMultipleMappedEntitlementError{
Pos: astEntitlements[1].Identifier.Pos,
},
)
result = PrimitiveAccess(ast.AccessNotSpecified)
return
}
result = NewEntitlementMapAccess(nominalType)
return
default:
// don't duplicate errors when the type here is invalid, as this will have triggered an error before
if nominalType != InvalidType {
checker.report(
&InvalidNonEntitlementAccessError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, astEntitlements[0]),
},
)
}
result = PrimitiveAccess(ast.AccessNotSpecified)
semanticEntitlements = append(semanticEntitlements, entitlementType)
}
if access.EntitlementSet.Separator() == ast.Conjunction {
result = NewEntitlementSetAccess(semanticEntitlements, Conjunction)
return
}
result = NewEntitlementSetAccess(semanticEntitlements, Disjunction)
return
}

panic(errors.NewUnreachableError())
}

Expand Down
39 changes: 28 additions & 11 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4173,27 +4173,28 @@ func (e *InvalidEntitlementAccessError) EndPosition(common.MemoryGauge) ast.Posi
return e.Pos
}

// InvalidMultipleMappedEntitlementError
type InvalidMultipleMappedEntitlementError struct {
Pos ast.Position
// InvalidEntitlementMappingTypeError
type InvalidEntitlementMappingTypeError struct {
Type Type
Pos ast.Position
}

var _ SemanticError = &InvalidMultipleMappedEntitlementError{}
var _ errors.UserError = &InvalidMultipleMappedEntitlementError{}
var _ SemanticError = &InvalidEntitlementMappingTypeError{}
var _ errors.UserError = &InvalidEntitlementMappingTypeError{}

func (*InvalidMultipleMappedEntitlementError) isSemanticError() {}
func (*InvalidEntitlementMappingTypeError) isSemanticError() {}

func (*InvalidMultipleMappedEntitlementError) IsUserError() {}
func (*InvalidEntitlementMappingTypeError) IsUserError() {}

func (e *InvalidMultipleMappedEntitlementError) Error() string {
return "entitlement mappings cannot be used as part of an entitlement set"
func (e *InvalidEntitlementMappingTypeError) Error() string {
return fmt.Sprintf("`%s` is not an entitlement map type", e.Type.QualifiedString())
}

func (e *InvalidMultipleMappedEntitlementError) StartPosition() ast.Position {
func (e *InvalidEntitlementMappingTypeError) StartPosition() ast.Position {
return e.Pos
}

func (e *InvalidMultipleMappedEntitlementError) EndPosition(common.MemoryGauge) ast.Position {
func (e *InvalidEntitlementMappingTypeError) EndPosition(common.MemoryGauge) ast.Position {
return e.Pos
}

Expand Down Expand Up @@ -4262,6 +4263,22 @@ func (e *InvalidNonEntitlementAccessError) Error() string {
return "only entitlements may be used in access modifiers"
}

// MappingAccessMissingKeywordError
type MappingAccessMissingKeywordError struct {
ast.Range
}

var _ SemanticError = &MappingAccessMissingKeywordError{}
var _ errors.UserError = &MappingAccessMissingKeywordError{}

func (*MappingAccessMissingKeywordError) isSemanticError() {}

func (*MappingAccessMissingKeywordError) IsUserError() {}

func (e *MappingAccessMissingKeywordError) Error() string {
return "entitlement mapping access modifiers require the `mapping` keyword preceding the name of the map"
}

// DirectEntitlementAnnotationError
type DirectEntitlementAnnotationError struct {
ast.Range
Expand Down
10 changes: 5 additions & 5 deletions runtime/tests/checker/attachments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3871,8 +3871,8 @@ func TestCheckAttachmentsExternalMutation(t *testing.T) {
Mutate -> Insert
}
access(M) attachment A for R {
access(Identity) let x: [String]
access(mapping M) attachment A for R {
access(mapping Identity) let x: [String]
init() {
self.x = ["x"]
}
Expand Down Expand Up @@ -3955,8 +3955,8 @@ func TestCheckAttachmentsExternalMutation(t *testing.T) {
xRef.append("y")
}
}
access(M) attachment A for R {
access(Identity) let x: [String]
access(mapping M) attachment A for R {
access(mapping Identity) let x: [String]
init() {
self.x = ["x"]
}
Expand Down Expand Up @@ -4524,7 +4524,7 @@ func TestCheckAttachmentForEachAttachment(t *testing.T) {
}
}
resource R {}
access(M) attachment A for R {
access(mapping M) attachment A for R {
access(F) fun foo() {}
}
access(all) fun foo(s: @R) {
Expand Down
Loading

0 comments on commit 8e04195

Please sign in to comment.