diff --git a/go/types/expr.go b/go/types/expr.go index d21217c6..a971686a 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -1081,7 +1081,7 @@ func (check *checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { check.indexedElts(e.Elts, utyp.elem, -1) case *Map: - visited := make(map[interface{}]bool, len(e.Elts)) + visited := make(map[interface{}][]Type, len(e.Elts)) for _, e := range e.Elts { kv, _ := e.(*ast.KeyValueExpr) if kv == nil { @@ -1096,11 +1096,24 @@ func (check *checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { continue } if x.mode == constant { - if visited[x.val] { + duplicate := false + // if the key is of interface type, the type is also significant when checking for duplicates + if _, ok := utyp.key.Underlying().(*Interface); ok { + for _, vtyp := range visited[x.val] { + if Identical(vtyp, x.typ) { + duplicate = true + break + } + } + visited[x.val] = append(visited[x.val], x.typ) + } else { + _, duplicate = visited[x.val] + visited[x.val] = nil + } + if duplicate { check.errorf(x.pos(), "duplicate key %s in map literal", x.val) continue } - visited[x.val] = true } check.exprWithHint(x, kv.Value, utyp.elem) if !check.assignment(x, utyp.elem) { diff --git a/go/types/testdata/expr3.src b/go/types/testdata/expr3.src index 604a2575..8220364c 100644 --- a/go/types/testdata/expr3.src +++ b/go/types/testdata/expr3.src @@ -291,6 +291,9 @@ func slice_literals() { const index2 int = 2 +type N int +func (N) f() {} + func map_literals() { type M0 map[string]int type M1 map[bool]int @@ -302,6 +305,23 @@ func map_literals() { _ = M0{"foo": "bar" /* ERROR "cannot convert" */ } _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 } + _ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1} + _ = map[interface{}]int{int(2): 1, int16(2): 1} + _ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1} + + type S string + + _ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1} + _ = map[interface{}]int{"a": 1, S("a"): 1} + _ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1} + + type I interface { + f() + } + + _ = map[I]int{N(0): 1, N(2): 1} + _ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1} + // map keys must be resolved correctly key1 := "foo" _ = M0{key1: 1}