Skip to content

Commit

Permalink
Merge branch 'master' into tarak/2712-revertibleRandom-modulo
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Jan 9, 2024
2 parents 74ce6e8 + ddc2ad9 commit f0eb54f
Show file tree
Hide file tree
Showing 6 changed files with 400 additions and 133 deletions.
26 changes: 25 additions & 1 deletion runtime/sema/check_composite_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -1960,6 +1960,16 @@ func (checker *Checker) enumMembersAndOrigins(
func (checker *Checker) checkDefaultDestroyParamExpressionKind(
arg ast.Expression,
) {

rejectReferenceTypedSubExpressions := func(typ Type) {
if _, isReferenceType := UnwrapOptionalType(typ).(*ReferenceType); isReferenceType {
checker.report(&DefaultDestroyInvalidArgumentError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, arg),
Kind: ReferenceTypedMemberAccess,
})
}
}

switch arg := arg.(type) {
case *ast.StringExpression,
*ast.BoolExpression,
Expand All @@ -1983,25 +1993,37 @@ func (checker *Checker) checkDefaultDestroyParamExpressionKind(
}
checker.report(&DefaultDestroyInvalidArgumentError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, arg),
Kind: InvalidIdentifier,
})

case *ast.MemberExpression:

memberExpressionInfo, ok := checker.Elaboration.MemberExpressionMemberAccessInfo(arg)
if !ok {
panic(errors.NewUnreachableError())
}

rejectReferenceTypedSubExpressions(memberExpressionInfo.ResultingType)

checker.checkDefaultDestroyParamExpressionKind(arg.Expression)

case *ast.IndexExpression:

checker.checkDefaultDestroyParamExpressionKind(arg.TargetExpression)
checker.checkDefaultDestroyParamExpressionKind(arg.IndexingExpression)

indexExprType := checker.Elaboration.IndexExpressionTypes(arg)

// indexing expressions on arrays can fail, and must be disallowed, but
// indexing expressions on dicts, or composites (for attachments) will return `nil` and thus never fail
targetExprType := checker.Elaboration.IndexExpressionTypes(arg).IndexedType
targetExprType := indexExprType.IndexedType
// `nil` indicates that the index is a type-index (i.e. for an attachment access)
if targetExprType == nil {
return
}

rejectReferenceTypedSubExpressions(indexExprType.ResultType)

switch targetExprType := targetExprType.(type) {
case *DictionaryType:
return
Expand All @@ -2013,12 +2035,14 @@ func (checker *Checker) checkDefaultDestroyParamExpressionKind(

checker.report(&DefaultDestroyInvalidArgumentError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, arg),
Kind: NonDictionaryIndexExpression,
})

default:

checker.report(&DefaultDestroyInvalidArgumentError{
Range: ast.NewRangeFromPositioned(checker.memoryGauge, arg),
Kind: InvalidExpression,
})

}
Expand Down
99 changes: 70 additions & 29 deletions runtime/sema/check_pragma.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,88 @@ package sema

import "github.com/onflow/cadence/runtime/ast"

// VisitPragmaDeclaration checks that the pragma declaration is valid.
// It is valid if the root expression is an identifier or invocation.
// Invocations must
func (checker *Checker) VisitPragmaDeclaration(declaration *ast.PragmaDeclaration) (_ struct{}) {

switch expression := declaration.Expression.(type) {
case *ast.InvocationExpression:
// Type arguments are not supported for pragmas
if len(expression.TypeArguments) > 0 {
checker.report(&InvalidPragmaError{
Message: "type arguments are not supported",
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
expression.TypeArguments[0],
),
})
}

// Ensure arguments are string expressions
for _, arg := range expression.Arguments {
_, ok := arg.Expression.(*ast.StringExpression)
if !ok {
checker.report(&InvalidPragmaError{
Message: "invalid non-string argument",
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
arg.Expression,
),
})
}
}

case *ast.IdentifierExpression:
// NO-OP
// valid, NO-OP

case *ast.InvocationExpression:
checker.checkPragmaInvocationExpression(expression)

default:
checker.report(&InvalidPragmaError{
Message: "pragma must be identifier or invocation expression",
Message: "expression must be literal, identifier, or invocation",
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
declaration,
expression,
),
})
}

return
}

func (checker *Checker) checkPragmaInvocationExpression(expression *ast.InvocationExpression) {
// Invoked expression must be an identifier
if _, ok := expression.InvokedExpression.(*ast.IdentifierExpression); !ok {
checker.report(&InvalidPragmaError{
Message: "invoked expression must be an identifier",
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
expression.InvokedExpression,
),
})
}

// Type arguments are not supported for pragmas
if len(expression.TypeArguments) > 0 {
checker.report(&InvalidPragmaError{
Message: "type arguments are not supported",
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
expression.TypeArguments[0],
),
})
}

// Ensure arguments are valid
for _, arg := range expression.Arguments {
checker.checkPragmaArgumentExpression(arg.Expression)
}
}

func (checker *Checker) checkPragmaArgumentExpression(expression ast.Expression) {
switch expression := expression.(type) {
case *ast.InvocationExpression:
checker.checkPragmaInvocationExpression(expression)
return

case *ast.StringExpression,
*ast.IntegerExpression,
*ast.FixedPointExpression,
*ast.ArrayExpression,
*ast.DictionaryExpression,
*ast.NilExpression,
*ast.BoolExpression,
*ast.PathExpression:

return

case *ast.UnaryExpression:
if expression.Operation == ast.OperationMinus {
return
}
}

checker.report(&InvalidPragmaError{
Message: "expression in invocation must be literal or invocation",
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
expression,
),
})
}
28 changes: 26 additions & 2 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4643,10 +4643,20 @@ func (e *DefaultDestroyEventInNonResourceError) Error() string {
)
}

type DefaultDestroyInvalidArgumentKind int

const (
NonDictionaryIndexExpression DefaultDestroyInvalidArgumentKind = iota
ReferenceTypedMemberAccess
InvalidIdentifier
InvalidExpression
)

// DefaultDestroyInvalidArgumentError

type DefaultDestroyInvalidArgumentError struct {
ast.Range
Kind DefaultDestroyInvalidArgumentKind
}

var _ SemanticError = &DefaultDestroyInvalidArgumentError{}
Expand All @@ -4657,10 +4667,24 @@ func (*DefaultDestroyInvalidArgumentError) isSemanticError() {}
func (*DefaultDestroyInvalidArgumentError) IsUserError() {}

func (e *DefaultDestroyInvalidArgumentError) Error() string {
return "default destroy event arguments must be literals, member access expressions on `self` or `base`, indexed access expressions on dictionaries, or attachment accesses"
return "Invalid default destroy event argument"
}

func (e *DefaultDestroyInvalidArgumentError) SecondaryError() string {
switch e.Kind {
case NonDictionaryIndexExpression:
return "Indexed accesses may only be performed on dictionaries"
case ReferenceTypedMemberAccess:
return "Member accesses in arguments may not contain reference types"
case InvalidIdentifier:
return "Identifiers other than `self` or `base` may not appear in arguments"
case InvalidExpression:
return "Arguments must be literals, member access expressions on `self` or `base`, indexed access expressions on dictionaries, or attachment accesses"
}
return ""
}

// DefaultDestroyInvalidArgumentError
// DefaultDestroyInvalidParameterError

type DefaultDestroyInvalidParameterError struct {
ParamType Type
Expand Down
Loading

0 comments on commit f0eb54f

Please sign in to comment.