Skip to content

Commit

Permalink
Merge pull request #2850 from onflow/bastian/allow-native-generic-fun…
Browse files Browse the repository at this point in the history
…ctions
  • Loading branch information
turbolent authored Oct 12, 2023
2 parents 735a071 + 05e3c08 commit e69d6bb
Show file tree
Hide file tree
Showing 5 changed files with 336 additions and 6 deletions.
7 changes: 6 additions & 1 deletion runtime/sema/check_composite_declaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -1783,7 +1783,12 @@ func (checker *Checker) defaultMembersAndOrigins(

identifier := function.Identifier.Identifier

functionType := checker.functionType(function.ParameterList, function.ReturnTypeAnnotation)
functionType := checker.functionType(
function.IsNative(),
function.TypeParameterList,
function.ParameterList,
function.ReturnTypeAnnotation,
)

argumentLabels := function.ParameterList.EffectiveArgumentLabels()

Expand Down
15 changes: 13 additions & 2 deletions runtime/sema/check_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@ func (checker *Checker) visitFunctionDeclaration(

functionType := checker.Elaboration.FunctionDeclarationFunctionType(declaration)
if functionType == nil {
functionType = checker.functionType(declaration.ParameterList, declaration.ReturnTypeAnnotation)

functionType = checker.functionType(
declaration.IsNative(),
declaration.TypeParameterList,
declaration.ParameterList,
declaration.ReturnTypeAnnotation,
)

if options.declareFunction {
checker.declareFunctionDeclaration(declaration, functionType)
Expand Down Expand Up @@ -430,7 +436,12 @@ func (checker *Checker) declareBefore() {
func (checker *Checker) VisitFunctionExpression(expression *ast.FunctionExpression) Type {

// TODO: infer
functionType := checker.functionType(expression.ParameterList, expression.ReturnTypeAnnotation)
functionType := checker.functionType(
false,
nil,
expression.ParameterList,
expression.ReturnTypeAnnotation,
)

checker.Elaboration.SetFunctionExpressionFunctionType(expression, functionType)

Expand Down
90 changes: 89 additions & 1 deletion runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,12 @@ func (checker *Checker) checkTopLevelDeclarationValidity(
}

func (checker *Checker) declareGlobalFunctionDeclaration(declaration *ast.FunctionDeclaration) {
functionType := checker.functionType(declaration.ParameterList, declaration.ReturnTypeAnnotation)
functionType := checker.functionType(
declaration.IsNative(),
declaration.TypeParameterList,
declaration.ParameterList,
declaration.ReturnTypeAnnotation,
)
checker.Elaboration.SetFunctionDeclarationFunctionType(declaration, functionType)
checker.declareFunctionDeclaration(declaration, functionType)
}
Expand Down Expand Up @@ -1240,23 +1245,106 @@ func (checker *Checker) ConvertTypeAnnotation(typeAnnotation *ast.TypeAnnotation
}

func (checker *Checker) functionType(
isNative bool,
typeParameterList *ast.TypeParameterList,
parameterList *ast.ParameterList,
returnTypeAnnotation *ast.TypeAnnotation,
) *FunctionType {

// Convert type parameters (if any)

var convertedTypeParameters []*TypeParameter
if typeParameterList != nil {

// Only native functions may have type parameters at the moment
if !isNative && !typeParameterList.IsEmpty() {
checker.report(&InvalidTypeParameterizedNonNativeFunctionError{
Range: ast.NewRangeFromPositioned(
checker.memoryGauge,
typeParameterList,
),
})
}

checker.typeActivations.Enter()
defer checker.typeActivations.Leave(func(gauge common.MemoryGauge) ast.Position {
if returnTypeAnnotation != nil {
return returnTypeAnnotation.EndPosition(gauge)
} else {
return parameterList.EndPos
}
})

// All type parameters are converted at once,
// so type bounds may currently not refer to previous type parameters

convertedTypeParameters = checker.typeParameters(typeParameterList)

for typeParameterIndex, typeParameter := range typeParameterList.TypeParameters {
convertedTypeParameter := convertedTypeParameters[typeParameterIndex]

genericType := &GenericType{
TypeParameter: convertedTypeParameter,
}

_, err := checker.typeActivations.declareType(typeDeclaration{
identifier: typeParameter.Identifier,
ty: genericType,
declarationKind: common.DeclarationKindTypeParameter,
allowOuterScopeShadowing: false,
})
checker.report(err)

}
}

// Convert parameters

convertedParameters := checker.parameters(parameterList)

// Convert return type

convertedReturnTypeAnnotation := VoidTypeAnnotation
if returnTypeAnnotation != nil {
convertedReturnTypeAnnotation =
checker.ConvertTypeAnnotation(returnTypeAnnotation)
}

return &FunctionType{
TypeParameters: convertedTypeParameters,
Parameters: convertedParameters,
ReturnTypeAnnotation: convertedReturnTypeAnnotation,
}
}

func (checker *Checker) typeParameters(typeParameterList *ast.TypeParameterList) []*TypeParameter {

var typeParameters []*TypeParameter

typeParameterCount := len(typeParameterList.TypeParameters)
if typeParameterCount > 0 {
typeParameters = make([]*TypeParameter, typeParameterCount)

for i, typeParameter := range typeParameterList.TypeParameters {

typeBoundAnnotation := typeParameter.TypeBound
var convertedTypeBound Type
if typeBoundAnnotation != nil {
convertedTypeBoundAnnotation := checker.ConvertTypeAnnotation(typeBoundAnnotation)
checker.checkTypeAnnotation(convertedTypeBoundAnnotation, typeBoundAnnotation)
convertedTypeBound = convertedTypeBoundAnnotation.Type
}

typeParameters[i] = &TypeParameter{
Name: typeParameter.Identifier.Identifier,
TypeBound: convertedTypeBound,
}
}
}

return typeParameters
}

func (checker *Checker) parameters(parameterList *ast.ParameterList) []Parameter {

var parameters []Parameter
Expand Down
17 changes: 17 additions & 0 deletions runtime/sema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4194,3 +4194,20 @@ func (*AttachmentsNotEnabledError) IsUserError() {}
func (e *AttachmentsNotEnabledError) Error() string {
return "attachments are not enabled and cannot be used in this environment"
}

// InvalidTypeParameterizedNonNativeFunctionError

type InvalidTypeParameterizedNonNativeFunctionError struct {
ast.Range
}

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

func (*InvalidTypeParameterizedNonNativeFunctionError) isSemanticError() {}

func (*InvalidTypeParameterizedNonNativeFunctionError) IsUserError() {}

func (e *InvalidTypeParameterizedNonNativeFunctionError) Error() string {
return "invalid type parameters in non-native function"
}
Loading

0 comments on commit e69d6bb

Please sign in to comment.