Skip to content

Commit

Permalink
Merge pull request #2656 from onflow/supun/master-port-internal-128
Browse files Browse the repository at this point in the history
Add support for max parameter count (internal #128)
  • Loading branch information
SupunS authored Jul 12, 2023
2 parents 9f9c5fd + 46cc113 commit a393e87
Show file tree
Hide file tree
Showing 20 changed files with 401 additions and 150 deletions.
4 changes: 2 additions & 2 deletions runtime/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2361,7 +2361,7 @@ func TestGetAuthAccount(t *testing.T) {

errs := checker.RequireCheckerErrors(t, err, 1)

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

t.Run("too many args", func(t *testing.T) {
Expand All @@ -2388,7 +2388,7 @@ func TestGetAuthAccount(t *testing.T) {
)
errs := checker.RequireCheckerErrors(t, err, 1)

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

t.Run("transaction", func(t *testing.T) {
Expand Down
14 changes: 8 additions & 6 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,12 +423,15 @@ func (interpreter *Interpreter) InvokeExternally(

if argumentCount != parameterCount {

// if the function has defined optional parameters,
// then the provided arguments must be equal to or greater than
// the number of required parameters.
if functionType.RequiredArgumentCount == nil ||
argumentCount < *functionType.RequiredArgumentCount {
if argumentCount < functionType.Arity.MinCount(parameterCount) {
return nil, ArgumentCountError{
ParameterCount: parameterCount,
ArgumentCount: argumentCount,
}
}

maxCount := functionType.Arity.MaxCount(parameterCount)
if maxCount != nil && argumentCount > *maxCount {
return nil, ArgumentCountError{
ParameterCount: parameterCount,
ArgumentCount: argumentCount,
Expand Down Expand Up @@ -1065,7 +1068,6 @@ func (interpreter *Interpreter) declareNonEnumCompositeValue(
ReturnTypeAnnotation: sema.TypeAnnotation{
Type: compositeType,
},
RequiredArgumentCount: nil,
}

var initializerFunction FunctionValue
Expand Down
2 changes: 1 addition & 1 deletion runtime/sema/authaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ package sema
var AuthAccountTypeLinkAccountFunctionTypePathParameterTypeAnnotation = AuthAccountTypeLinkAccountFunctionType.Parameters[0].TypeAnnotation

func init() {
AuthAccountContractsTypeAddFunctionType.RequiredArgumentCount = RequiredArgumentCount(2)
AuthAccountContractsTypeAddFunctionType.Arity = &Arity{Min: 2}
AuthAccountTypeGetCapabilityFunctionTypeParameterT.Optional = true
PublicAccountTypeGetCapabilityFunctionTypeParameterT.Optional = true
}
31 changes: 18 additions & 13 deletions runtime/sema/check_invocation_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func (checker *Checker) checkInvocation(
returnType Type,
) {
parameterCount := len(functionType.Parameters)
requiredArgumentCount := functionType.RequiredArgumentCount
arity := functionType.Arity
typeParameterCount := len(functionType.TypeParameters)

// Check the type arguments and bind them to type parameters
Expand Down Expand Up @@ -421,7 +421,7 @@ func (checker *Checker) checkInvocation(
checker.checkInvocationArgumentCount(
argumentCount,
parameterCount,
requiredArgumentCount,
arity,
invocationExpression,
)

Expand Down Expand Up @@ -592,23 +592,28 @@ func (checker *Checker) checkInvocationRequiredArgument(
func (checker *Checker) checkInvocationArgumentCount(
argumentCount int,
parameterCount int,
requiredArgumentCount *int,
arity *Arity,
pos ast.HasPosition,
) {

if argumentCount == parameterCount {
minCount := arity.MinCount(parameterCount)
if argumentCount < minCount {
checker.report(
&InsufficientArgumentsError{
MinCount: minCount,
ActualCount: argumentCount,
Range: ast.NewRangeFromPositioned(checker.memoryGauge, pos),
},
)
return
}

// TODO: improve
if requiredArgumentCount == nil ||
argumentCount < *requiredArgumentCount {

maxCount := arity.MaxCount(parameterCount)
if maxCount != nil && argumentCount > *maxCount {
checker.report(
&ArgumentCountError{
ParameterCount: parameterCount,
ArgumentCount: argumentCount,
Range: ast.NewRangeFromPositioned(checker.memoryGauge, pos),
&ExcessiveArgumentsError{
MaxCount: *maxCount,
ActualCount: argumentCount,
Range: ast.NewRangeFromPositioned(checker.memoryGauge, pos),
},
)
}
Expand Down
58 changes: 43 additions & 15 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,31 +411,59 @@ func (e *NotCallableError) Error() string {
)
}

// ArgumentCountError
// InsufficientArgumentsError

type ArgumentCountError struct {
ParameterCount int
ArgumentCount int
type InsufficientArgumentsError struct {
MinCount int
ActualCount int
ast.Range
}

var _ SemanticError = &ArgumentCountError{}
var _ errors.UserError = &ArgumentCountError{}
var _ errors.SecondaryError = &ArgumentCountError{}
var _ SemanticError = &InsufficientArgumentsError{}
var _ errors.UserError = &InsufficientArgumentsError{}
var _ errors.SecondaryError = &InsufficientArgumentsError{}

func (*ArgumentCountError) isSemanticError() {}
func (*InsufficientArgumentsError) isSemanticError() {}

func (*ArgumentCountError) IsUserError() {}
func (*InsufficientArgumentsError) IsUserError() {}

func (e *ArgumentCountError) Error() string {
return "incorrect number of arguments"
func (e *InsufficientArgumentsError) Error() string {
return "too few arguments"
}

func (e *ArgumentCountError) SecondaryError() string {
func (e *InsufficientArgumentsError) SecondaryError() string {
return fmt.Sprintf(
"expected %d, got %d",
e.ParameterCount,
e.ArgumentCount,
"expected at least %d, got %d",
e.MinCount,
e.ActualCount,
)
}

// ExcessiveArgumentsError

type ExcessiveArgumentsError struct {
MaxCount int
ActualCount int
ast.Range
}

var _ SemanticError = &ExcessiveArgumentsError{}
var _ errors.UserError = &ExcessiveArgumentsError{}
var _ errors.SecondaryError = &ExcessiveArgumentsError{}

func (*ExcessiveArgumentsError) isSemanticError() {}

func (*ExcessiveArgumentsError) IsUserError() {}

func (e *ExcessiveArgumentsError) Error() string {
return "too many arguments"
}

func (e *ExcessiveArgumentsError) SecondaryError() string {
return fmt.Sprintf(
"expected up to %d, got %d",
e.MaxCount,
e.ActualCount,
)
}

Expand Down
48 changes: 36 additions & 12 deletions runtime/sema/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -2655,10 +2655,38 @@ func formatFunctionType(
return builder.String()
}

// Arity

type Arity struct {
Min int
Max int
}

func (arity *Arity) MinCount(parameterCount int) int {
minCount := parameterCount
if arity != nil {
minCount = arity.Min
}

return minCount
}

func (arity *Arity) MaxCount(parameterCount int) *int {
maxCount := parameterCount
if arity != nil {
if arity.Max < parameterCount {
return nil
}
maxCount = arity.Max
}

return &maxCount
}

// FunctionType
type FunctionType struct {
ReturnTypeAnnotation TypeAnnotation
RequiredArgumentCount *int
Arity *Arity
ArgumentExpressionsCheck ArgumentExpressionsCheck
Members *StringMemberOrderedMap
TypeParameters []*TypeParameter
Expand All @@ -2670,10 +2698,6 @@ type FunctionType struct {

var _ Type = &FunctionType{}

func RequiredArgumentCount(count int) *int {
return &count
}

func (*FunctionType) IsType() {}

func (t *FunctionType) Tag() TypeTag {
Expand Down Expand Up @@ -2994,10 +3018,10 @@ func (t *FunctionType) RewriteWithRestrictedTypes() (Type, bool) {
}

return &FunctionType{
TypeParameters: rewrittenTypeParameters,
Parameters: rewrittenParameters,
ReturnTypeAnnotation: NewTypeAnnotation(rewrittenReturnType),
RequiredArgumentCount: t.RequiredArgumentCount,
TypeParameters: rewrittenTypeParameters,
Parameters: rewrittenParameters,
ReturnTypeAnnotation: NewTypeAnnotation(rewrittenReturnType),
Arity: t.Arity,
}, true
} else {
return t, false
Expand Down Expand Up @@ -3106,9 +3130,9 @@ func (t *FunctionType) Resolve(typeArguments *TypeParameterTypeOrderedMap) Type
}

return &FunctionType{
Parameters: newParameters,
ReturnTypeAnnotation: NewTypeAnnotation(newReturnType),
RequiredArgumentCount: t.RequiredArgumentCount,
Parameters: newParameters,
ReturnTypeAnnotation: NewTypeAnnotation(newReturnType),
Arity: t.Arity,
}

}
Expand Down
3 changes: 2 additions & 1 deletion runtime/stdlib/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ var assertFunctionType = &sema.FunctionType{
ReturnTypeAnnotation: sema.NewTypeAnnotation(
sema.VoidType,
),
RequiredArgumentCount: sema.RequiredArgumentCount(1),
// `message` parameter is optional
Arity: &sema.Arity{Min: 1, Max: 2},
}

var AssertFunction = NewStandardLibraryFunction(
Expand Down
Loading

0 comments on commit a393e87

Please sign in to comment.