mirror of https://github.com/golang/go.git
[dev.go2go] go/types: fix assertion failure, better error message for inference failure
Fixes #39976. Change-Id: Idc304a615193847337438e7024e43140472e7bae Reviewed-on: https://go-review.googlesource.com/c/go/+/240718 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
6cf6bf162c
commit
d014fca6d4
|
|
@ -136,6 +136,7 @@ var tests = [][]string{
|
|||
{"fixedbugs/issue39768.go2"},
|
||||
{"fixedbugs/issue39938.go2"},
|
||||
{"fixedbugs/issue39948.go2"},
|
||||
{"fixedbugs/issue39976.go2"},
|
||||
}
|
||||
|
||||
var fset = token.NewFileSet()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type policy(type K, V) interface{}
|
||||
type LRU(type K, V) struct{}
|
||||
|
||||
func NewCache(type K, V)(p policy(K, V))
|
||||
|
||||
func _() {
|
||||
var lru LRU(int, string)
|
||||
NewCache(int, string)(&lru)
|
||||
NewCache(& /* ERROR does not match policy\(K, V\) \(cannot infer K and V\) */ lru)
|
||||
}
|
||||
|
|
@ -7,7 +7,10 @@
|
|||
|
||||
package types
|
||||
|
||||
import "go/token"
|
||||
import (
|
||||
"go/token"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// infer returns the list of actual type arguments for the given list of type parameters tparams
|
||||
// by inferring them from the actual arguments args for the parameters params. If infer fails to
|
||||
|
|
@ -20,7 +23,23 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
|
|||
|
||||
errorf := func(kind string, tpar, targ Type, arg *operand) {
|
||||
// provide a better error message if we can
|
||||
targs, _ := u.x.types()
|
||||
targs, failed := u.x.types()
|
||||
if failed == 0 {
|
||||
// The first type parameter couldn't be inferred.
|
||||
// If none of them could be inferred, don't try
|
||||
// to provide the inferred type in the error msg.
|
||||
allFailed := true
|
||||
for _, targ := range targs {
|
||||
if targ != nil {
|
||||
allFailed = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allFailed {
|
||||
check.errorf(arg.pos(), "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeNamesString(tparams))
|
||||
return
|
||||
}
|
||||
}
|
||||
smap := makeSubstMap(tparams, targs)
|
||||
inferred := check.subst(arg.pos(), tpar, smap)
|
||||
if inferred != tpar {
|
||||
|
|
@ -108,6 +127,33 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a
|
|||
return targs
|
||||
}
|
||||
|
||||
// typeNamesString produces a string containing all the
|
||||
// type names in list suitable for human consumption.
|
||||
func typeNamesString(list []*TypeName) string {
|
||||
// common cases
|
||||
n := len(list)
|
||||
switch n {
|
||||
case 0:
|
||||
return ""
|
||||
case 1:
|
||||
return list[0].name
|
||||
case 2:
|
||||
return list[0].name + " and " + list[1].name
|
||||
}
|
||||
|
||||
// general case (n > 2)
|
||||
var b strings.Builder
|
||||
for i, tname := range list[:n-1] {
|
||||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
b.WriteString(tname.name)
|
||||
}
|
||||
b.WriteString(", and ")
|
||||
b.WriteString(list[n-1].name)
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// IsParameterized reports whether typ contains any type parameters.
|
||||
// TODO(gri) This is not strictly correct. We only want the free
|
||||
// type parameters for a given type. (At the moment, the only way
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ type substMap struct {
|
|||
proj map[*TypeParam]Type
|
||||
}
|
||||
|
||||
// makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
|
||||
// If targs[i] is nil, tpars[i] is not substituted.
|
||||
func makeSubstMap(tpars []*TypeName, targs []Type) *substMap {
|
||||
assert(len(tpars) == len(targs))
|
||||
proj := make(map[*TypeParam]Type, len(tpars))
|
||||
|
|
@ -29,10 +31,9 @@ func makeSubstMap(tpars []*TypeName, targs []Type) *substMap {
|
|||
// We must expand type arguments otherwise *Instance
|
||||
// types end up as components in composite types.
|
||||
// TODO(gri) explain why this causes problems, if it does
|
||||
targ := expand(targs[i])
|
||||
targ := expand(targs[i]) // possibly nil
|
||||
targs[i] = targ
|
||||
assert(targ != nil)
|
||||
proj[tpar.typ.(*TypeParam)] = targs[i]
|
||||
proj[tpar.typ.(*TypeParam)] = targ
|
||||
}
|
||||
return &substMap{targs, proj}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue