go.tools/go/types: check map key type when it is fully known
Fixes golang/go#6667. R=adonovan CC=golang-dev https://golang.org/cl/17360043
This commit is contained in:
parent
1e05a58b11
commit
65aaa0093c
|
@ -38,6 +38,7 @@ type checker struct {
|
|||
conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls)
|
||||
untyped map[ast.Expr]exprInfo // map of expressions without final type
|
||||
lhsVarsList [][]*Var // type switch lhs variable sets, for 'declared but not used' errors
|
||||
delayed []func() // delayed checks that require fully setup types
|
||||
|
||||
firstErr error // first error encountered
|
||||
Info // collected type info
|
||||
|
@ -66,6 +67,10 @@ func newChecker(conf *Config, fset *token.FileSet, pkg *Package) *checker {
|
|||
}
|
||||
}
|
||||
|
||||
func (check *checker) delay(f func()) {
|
||||
check.delayed = append(check.delayed, f)
|
||||
}
|
||||
|
||||
func (check *checker) recordTypeAndValue(x ast.Expr, typ Type, val exact.Value) {
|
||||
assert(x != nil && typ != nil)
|
||||
if m := check.Types; m != nil {
|
||||
|
@ -196,6 +201,12 @@ func (conf *Config) check(pkgPath string, fset *token.FileSet, files []*ast.File
|
|||
|
||||
check.resolveFiles(files[:i])
|
||||
|
||||
// perform delayed checks
|
||||
for _, f := range check.delayed {
|
||||
f()
|
||||
}
|
||||
check.delayed = nil // not needed anymore
|
||||
|
||||
// remaining untyped expressions must indeed be untyped
|
||||
if debug {
|
||||
for x, info := range check.untyped {
|
||||
|
|
|
@ -79,7 +79,9 @@ func isInterface(typ Type) bool {
|
|||
func isComparable(typ Type) bool {
|
||||
switch t := typ.Underlying().(type) {
|
||||
case *Basic:
|
||||
return t.kind != Invalid && t.kind != UntypedNil
|
||||
// assume invalid types to be comparable
|
||||
// to avoid follow-up errors
|
||||
return t.kind != UntypedNil
|
||||
case *Pointer, *Interface, *Chan:
|
||||
return true
|
||||
case *Struct:
|
||||
|
|
|
@ -108,4 +108,12 @@ func _() {
|
|||
// channels
|
||||
c0 chan c0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// test cases for issue 6667
|
||||
|
||||
type A [10]map[A /* ERROR invalid map key */ ]bool
|
||||
|
||||
type S struct {
|
||||
m map[S /* ERROR invalid map key */ ]bool
|
||||
}
|
||||
|
|
|
@ -314,11 +314,14 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
|
|||
// spec: "The comparison operators == and != must be fully defined
|
||||
// for operands of the key type; thus the key type must not be a
|
||||
// function, map, or slice."
|
||||
// TODO(gri) if the key type is not fully defined yet, this test will be incorrect
|
||||
if !isComparable(typ.key) {
|
||||
check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
|
||||
// ok to continue
|
||||
}
|
||||
//
|
||||
// Delay this check because it requires fully setup types;
|
||||
// it is safe to continue in any case (was issue 6667).
|
||||
check.delay(func() {
|
||||
if !isComparable(typ.key) {
|
||||
check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
|
||||
}
|
||||
})
|
||||
|
||||
return typ
|
||||
|
||||
|
|
Loading…
Reference in New Issue