From ac135a4bcfc8054d4a7f997a252890df478bfd61 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 2 Apr 2020 14:45:41 -0700 Subject: [PATCH] go/types: better error messages for type inference Change-Id: I8a5b07eca76b084901cce6f1bae4f8d107d10701 --- src/go/types/infer.go | 34 ++++++++++++++++++---------------- src/go/types/testdata/tmp.go2 | 13 ++++++------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/go/types/infer.go b/src/go/types/infer.go index a2aee940f4..1097e27d11 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -18,6 +18,17 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a u := check.unifier() u.x.init(tparams) + errorf := func(kind string, tpar, targ Type, arg *operand) { + // provide a better error message if we can + if tpar, _ := tpar.(*TypeParam); tpar != nil { + if inferred := u.x.at(tpar.index); inferred != nil { + check.errorf(arg.pos(), "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar) + return + } + } + check.errorf(arg.pos(), "%s %s of %s does not match %s", kind, targ, arg.expr, tpar) + } + // Terminology: generic parameter = function parameter with a type-parameterized type // 1st pass: Unify parameter and argument types for generic parameters with typed arguments @@ -34,17 +45,12 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a // simply ignoring (continue) invalid args return nil // error was reported earlier } - if isTyped(arg.typ) { - // If we permit bidirectional unification, and arg.typ is - // a generic function, we need to initialize u.y with the - // respectice type parameters of arg.typ. - if !u.unify(par.typ, arg.typ) { - // Calling subst for an error message can cause problems. - // TODO(gri) Determine best approach here. - // check.errorf(arg.pos(), "type %s for %s does not match %s = %s", - // arg.typ, arg.expr, par.typ, check.subst(pos, par.typ, tparams, targs), - // ) - check.errorf(arg.pos(), "type %s for %s does not match %s", arg.typ, arg.expr, par.typ) + if targ := arg.typ; isTyped(targ) { + // If we permit bidirectional unification, and targ is + // a generic function, we need to initialize u.y with + // the respectice type parameters of targ. + if !u.unify(par.typ, targ) { + errorf("type", par.typ, targ, arg) return nil } } else { @@ -83,11 +89,7 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a // infer an untyped nil type as type parameter type. Ignore untyped // nil by making sure all default argument types are typed. if isTyped(targ) && !u.unify(par.typ, targ) { - // TODO(gri) see TODO comment above - // check.errorf(arg.pos(), "default type %s for %s does not match %s = %s", - // Default(arg.typ), arg.expr, par.typ, check.subst(pos, par.typ, tparams, targs), - // ) - check.errorf(arg.pos(), "default type %s for %s does not match %s", Default(arg.typ), arg.expr, par.typ) + errorf("default type", par.typ, targ, arg) return nil } } diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index eebc2036f8..2aafee6efa 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -4,11 +4,10 @@ package p -func f(type _ interface{ m() })() - -type T struct{} -func (*T) m() - -func _() { - f(T)() +func f(type T comparable)(x, y T) bool { + return x == y } + +func _(){ + f(1, 2i /* ERROR does not match */) +} \ No newline at end of file