Skip to content

Commit

Permalink
Merge pull request #3004 from onflow/bastian/2886-improve-type-inference
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored Jan 10, 2024
2 parents e46be51 + 4825f92 commit 30edca0
Show file tree
Hide file tree
Showing 10 changed files with 356 additions and 113 deletions.
42 changes: 33 additions & 9 deletions runtime/sema/check_invocation_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -578,29 +578,53 @@ func (checker *Checker) checkInvocationRequiredArgument(

var argumentType Type

if len(functionType.TypeParameters) == 0 {
// If the function doesn't use generic types, then the
// param types can be used to infer the types for arguments.
typeParameterCount := len(functionType.TypeParameters)

// If all type parameters have been bound to a type,
// then resolve the parameter type with the type arguments,
// and propose the parameter type as the expected type for the argument.
if typeParameters.Len() == typeParameterCount {

// Optimization: only resolve if there are type parameters.
// This avoids unnecessary work for non-generic functions.
if typeParameterCount > 0 {
parameterType = parameterType.Resolve(typeParameters)
// If the type parameter could not be resolved, use the invalid type.
if parameterType == nil {
parameterType = InvalidType
}

Check warning on line 595 in runtime/sema/check_invocation_expression.go

View check run for this annotation

Codecov / codecov/patch

runtime/sema/check_invocation_expression.go#L594-L595

Added lines #L594 - L595 were not covered by tests
}

argumentType = checker.VisitExpression(argument.Expression, parameterType)

} else {
// TODO: pass the expected type to support for parameters
// If there are still type parameters that have not been bound to a type,
// then check the argument without an expected type.
//
// We will then have to manually check that the argument type is compatible
// with the parameter type (see below).

argumentType = checker.VisitExpression(argument.Expression, nil)

// Try to unify the parameter type with the argument type.
// If unification fails, fall back to the parameter type for now.

argumentRange := ast.NewRangeFromPositioned(checker.memoryGauge, argument.Expression)

if parameterType.Unify(argumentType, typeParameters, checker.report, argumentRange) {
if parameterType.Unify(
argumentType,
typeParameters,
checker.report,
checker.memoryGauge,
argument.Expression,
) {
parameterType = parameterType.Resolve(typeParameters)
// If the type parameter could not be resolved, use the invalid type.
if parameterType == nil {
parameterType = InvalidType
}
}

// Check that the type of the argument matches the type of the parameter.

// TODO: remove this once type inferring support for parameters is added
checker.checkInvocationArgumentParameterTypeCompatibility(
argument.Expression,
argumentType,
Expand Down Expand Up @@ -695,7 +719,7 @@ func (checker *Checker) checkAndBindGenericTypeParameterTypeArguments(
// If the type parameter corresponding to the type argument has a type bound,
// then check that the argument is a subtype of the type bound.

err := typeParameter.checkTypeBound(ty, ast.NewRangeFromPositioned(checker.memoryGauge, rawTypeArgument))
err := typeParameter.checkTypeBound(ty, checker.memoryGauge, rawTypeArgument)
checker.report(err)

// Bind the type argument to the type parameter
Expand Down
3 changes: 2 additions & 1 deletion runtime/sema/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2475,7 +2475,8 @@ func (checker *Checker) convertInstantiationType(t *ast.InstantiationType) Type

err := typeParameter.checkTypeBound(
typeArgument,
ast.NewRangeFromPositioned(checker.memoryGauge, rawTypeArgument),
checker.memoryGauge,
rawTypeArgument,
)
checker.report(err)
}
Expand Down
8 changes: 7 additions & 1 deletion runtime/sema/simple_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,13 @@ func (t *SimpleType) RewriteWithIntersectionTypes() (Type, bool) {
return t, false
}

func (*SimpleType) Unify(_ Type, _ *TypeParameterTypeOrderedMap, _ func(err error), _ ast.Range) bool {
func (*SimpleType) Unify(
_ Type,
_ *TypeParameterTypeOrderedMap,
_ func(err error),
_ common.MemoryGauge,
_ ast.HasPosition,
) bool {
return false
}

Expand Down
Loading

0 comments on commit 30edca0

Please sign in to comment.