Fix: use CallTyped for methods as well

This commit is contained in:
Anton Medvedev
2023-01-21 12:20:17 +01:00
parent 312e6558c8
commit 9f69ffc06d
3 changed files with 33 additions and 21 deletions
+15 -18
View File
@@ -511,44 +511,41 @@ func (v *visitor) checkFunc(fn reflect.Type, method bool, node *ast.CallNode, na
return v.error(node, "func %v returns more then two values", name)
}
numIn := fn.NumIn()
// If func is method on an env, first argument should be a receiver,
// and actual arguments less than numIn by one.
// and actual arguments less than fnNumIn by one.
fnNumIn := fn.NumIn()
if method {
numIn--
fnNumIn--
}
// Skip first argument in case of the receiver.
fnInOffset := 0
if method {
fnInOffset = 1
}
if fn.IsVariadic() {
if len(arguments) < numIn-1 {
if len(arguments) < fnNumIn-1 {
return v.error(node, "not enough arguments to call %v", name)
}
} else {
if len(arguments) > numIn {
if len(arguments) > fnNumIn {
return v.error(node, "too many arguments to call %v", name)
}
if len(arguments) < numIn {
if len(arguments) < fnNumIn {
return v.error(node, "not enough arguments to call %v", name)
}
}
offset := 0
// Skip first argument in case of the receiver.
if method {
offset = 1
}
for i, arg := range arguments {
t, _ := v.visit(arg)
var in reflect.Type
if fn.IsVariadic() && i >= numIn-1 {
if fn.IsVariadic() && i >= fnNumIn-1 {
// For variadic arguments fn(xs ...int), go replaces type of xs (int) with ([]int).
// As we compare arguments one by one, we need underling type.
in = fn.In(fn.NumIn() - 1).Elem()
} else {
in = fn.In(i + offset)
in = fn.In(i + fnInOffset)
}
if isIntegerOrArithmeticOperation(arg) {
@@ -583,11 +580,11 @@ func (v *visitor) checkFunc(fn reflect.Type, method bool, node *ast.CallNode, na
continue funcTypes
}
}
if typed.NumIn() != fn.NumIn() {
if typed.NumIn() != fnNumIn {
continue
}
for j := 0; j < typed.NumIn(); j++ {
if typed.In(j) != fn.In(j) {
if typed.In(j) != fn.In(j+fnInOffset) {
continue funcTypes
}
}
+14 -3
View File
@@ -714,11 +714,22 @@ func TestCheck_CallFastTyped(t *testing.T) {
tree, err := parser.Parse("fn([1, 2], 'bar')")
require.NoError(t, err)
config := conf.New(env)
_, err = checker.Check(tree, config)
_, err = checker.Check(tree, conf.New(env))
require.NoError(t, err)
require.False(t, tree.Node.(*ast.CallNode).Fast)
require.Equal(t, 22, tree.Node.(*ast.CallNode).Typed)
}
func TestCheck_CallFastTyped_Method(t *testing.T) {
env := mock.Env{}
tree, err := parser.Parse("FuncTyped('bar')")
require.NoError(t, err)
_, err = checker.Check(tree, conf.New(env))
require.NoError(t, err)
require.False(t, tree.Node.(*ast.CallNode).Fast)
require.Equal(t, 42, tree.Node.(*ast.CallNode).Typed)
}
+4
View File
@@ -43,6 +43,10 @@ func (p Env) Func() int {
return 0
}
func (p Env) FuncTyped(_ string) int {
return 2023
}
type Embed struct {
EmbedEmbed
EmbedString string