Skip to content

Commit

Permalink
forbid taking references of transaction roles
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent committed Jan 24, 2023
1 parent 8a95517 commit 2b6f834
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 10 deletions.
21 changes: 20 additions & 1 deletion runtime/sema/check_reference_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,16 @@ func (checker *Checker) VisitReferenceExpression(referenceExpression *ast.Refere

referencedExpression := referenceExpression.Expression

_, _ = checker.visitExpression(referencedExpression, targetType)
referencedType, _ := checker.visitExpression(referencedExpression, targetType)

if !IsValidReferencedType(referencedType) {
checker.report(
&InvalidReferenceTargetTypeError{
TargetType: targetType,
Range: ast.NewRangeFromPositioned(checker.memoryGauge, referenceExpression.Expression),
},
)
}

if referenceType == nil {
return InvalidType
Expand All @@ -81,3 +90,13 @@ func (checker *Checker) VisitReferenceExpression(referenceExpression *ast.Refere

return returnType
}

func IsValidReferencedType(referencedType Type) bool {
switch referencedType.(type) {
case *TransactionRoleType:
return false
// TODO: in Stable Cadence we may also want to disallow transactions
}

return true
}
16 changes: 8 additions & 8 deletions runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2233,16 +2233,16 @@ func (checker *Checker) VisitExpressionWithForceType(expr ast.Expression, expect
// visitExpressionWithForceType
//
// Parameters:
// expr - Expression to check
// expectedType - Contextually expected type of the expression
// forceType - Specifies whether to use the expected type as a hard requirement (forceType = true)
//
// or whether to use the expected type for type inferring only (forceType = false)
// - expr: Expression to check
// - expectedType: Contextually expected type of the expression
// - forceType:
// Specifies whether to use the expected type as a hard requirement (forceType = true)
// or whether to use the expected type for type inferring only (forceType = false)
//
// Return types:
// visibleType - The type that others should 'see' as the type of this expression. This could be
//
// used as the type of the expression to avoid the type errors being delegated up.
// - visibleType:
// The type that others should 'see' as the type of this expression.
// This could be used as the type of the expression to avoid the type errors being delegated up.
//
// actualType - The actual type of the expression.
func (checker *Checker) visitExpressionWithForceType(
Expand Down
22 changes: 21 additions & 1 deletion runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2615,6 +2615,27 @@ func (e *NonReferenceTypeReferenceError) SecondaryError() string {
)
}

// InvalidReferenceTargetTypeError is reported when a reference expression
// targets a type which may not be referenced.
type InvalidReferenceTargetTypeError struct {
TargetType Type
ast.Range
}

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

func (*InvalidReferenceTargetTypeError) isSemanticError() {}

func (*InvalidReferenceTargetTypeError) IsUserError() {}

func (e *InvalidReferenceTargetTypeError) Error() string {
return fmt.Sprintf(
"cannot create reference to `%s`",
e.TargetType.QualifiedString(),
)
}

// InvalidResourceCreationError

type InvalidResourceCreationError struct {
Expand Down Expand Up @@ -2903,7 +2924,6 @@ func (e *ReadOnlyTargetAssignmentError) Error() string {
}

// MissingPrepareForFieldError
//
type MissingPrepareForFieldError struct {
FirstFieldName string
FirstFieldPos ast.Position
Expand Down
25 changes: 25 additions & 0 deletions runtime/tests/checker/reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1279,3 +1279,28 @@ func TestCheckReferenceTypeImplicitConformance(t *testing.T) {
require.IsType(t, &sema.TypeMismatchError{}, errs[0])
})
}

func TestCheckInvalidReferenceTargetType(t *testing.T) {

t.Parallel()

t.Run("transaction role", func(t *testing.T) {

t.Parallel()

_, err := ParseAndCheck(t, `
transaction {
role role1 {}
execute {
&self.role1 as &AnyStruct
}
}
`)

errs := RequireCheckerErrors(t, err, 1)

assert.IsType(t, &sema.InvalidReferenceTargetTypeError{}, errs[0])
})
}

0 comments on commit 2b6f834

Please sign in to comment.