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:
Robert Griesemer 2013-10-25 14:32:14 -07:00
parent 1e05a58b11
commit 65aaa0093c
4 changed files with 31 additions and 7 deletions

View File

@ -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 {

View File

@ -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:

View File

@ -109,3 +109,11 @@ func _() {
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
}

View File

@ -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
//
// 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)
// ok to continue
}
})
return typ