Fixes #51581.
Change-Id: I3232428edd7dd86f2930af950fb5841f7394c4e5
Reviewed-on: https://go-review.googlesource.com/c/go/+/391834
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
                                x.mode = invalid
                                return
                        }
-               } else if T == nil || IsInterface(T) && !isTypeParam(T) {
+               } else if T == nil || isNonTypeParamInterface(T) {
                        target = Default(x.typ)
                }
                newType, val, code := check.implicitTypeAndValue(x, target)
 
                //   (See also the TODO below.)
                if x.typ == Typ[UntypedNil] {
                        // ok
-               } else if IsInterface(T) && !isTypeParam(T) || constArg && !isConstType(T) {
+               } else if isNonTypeParamInterface(T) || constArg && !isConstType(T) {
                        final = Default(x.typ)
                } else if x.mode == constant_ && isInteger(x.typ) && allString(T) {
                        final = x.typ
 
 
        // TODO(gri) make canMix more efficient - called for each binary operation
        canMix := func(x, y *operand) bool {
-               if IsInterface(x.typ) && !isTypeParam(x.typ) || IsInterface(y.typ) && !isTypeParam(y.typ) {
+               if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
                        return true
                }
                if allBoolean(x.typ) != allBoolean(y.typ) {
                                check.error(e, "illegal cycle in type declaration")
                                goto Error
                        }
+                       // If the map key type is an interface (but not a type parameter),
+                       // the type of a constant key must be considered when checking for
+                       // duplicates.
+                       keyIsInterface := isNonTypeParamInterface(utyp.key)
                        visited := make(map[interface{}][]Type, len(e.ElemList))
                        for _, e := range e.ElemList {
                                kv, _ := e.(*syntax.KeyValueExpr)
                                }
                                if x.mode == constant_ {
                                        duplicate := false
-                                       // if the key is of interface type, the type is also significant when checking for duplicates
                                        xkey := keyVal(x.val)
-                                       if IsInterface(utyp.key) {
+                                       if keyIsInterface {
                                                for _, vtyp := range visited[xkey] {
                                                        if Identical(vtyp, x.typ) {
                                                                duplicate = true
 }
 
 func keyVal(x constant.Value) interface{} {
+       // TODO(gri) This function must map 1, 1.0, and 1.0 + 0i to the same (integer) value.
+       //           Same for 1.1 and 1.1 + 0i.
+       //           Otherwise we won't get duplicate key errors for certain type parameter
+       //           key types. See issue #51610.
        switch x.Kind() {
        case constant.Bool:
                return constant.BoolVal(x)
 
        return ok
 }
 
+// isNonTypeParamInterface reports whether t is an interface type but not a type parameter.
+func isNonTypeParamInterface(t Type) bool {
+       return !isTypeParam(t) && IsInterface(t)
+}
+
 // isTypeParam reports whether t is a type parameter.
 func isTypeParam(t Type) bool {
        _, ok := t.(*TypeParam)
 
                // bool, rune, int, float64, complex128 or string respectively, depending
                // on whether the value is a boolean, rune, integer, floating-point,
                // complex, or string constant."
-               if T == nil || IsInterface(T) && !isTypeParam(T) {
+               if T == nil || isNonTypeParamInterface(T) {
                        if T == nil && x.typ == Typ[UntypedNil] {
                                check.errorf(x, _UntypedNil, "use of untyped nil in %s", context)
                                x.mode = invalid
 
                // - Keep untyped nil for untyped nil arguments.
                // - For constant integer to string conversions, keep the argument type.
                //   (See also the TODO below.)
-               if IsInterface(T) && !isTypeParam(T) || constArg && !isConstType(T) || x.isNil() {
+               if isNonTypeParamInterface(T) || constArg && !isConstType(T) || x.isNil() {
                        final = Default(x.typ) // default type of untyped nil is untyped nil
                } else if x.mode == constant_ && isInteger(x.typ) && allString(T) {
                        final = x.typ
 
 
        // TODO(gri) make canMix more efficient - called for each binary operation
        canMix := func(x, y *operand) bool {
-               if IsInterface(x.typ) && !isTypeParam(x.typ) || IsInterface(y.typ) && !isTypeParam(y.typ) {
+               if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) {
                        return true
                }
                if allBoolean(x.typ) != allBoolean(y.typ) {
                                check.error(e, _InvalidTypeCycle, "illegal cycle in type declaration")
                                goto Error
                        }
+                       // If the map key type is an interface (but not a type parameter),
+                       // the type of a constant key must be considered when checking for
+                       // duplicates.
+                       keyIsInterface := isNonTypeParamInterface(utyp.key)
                        visited := make(map[any][]Type, len(e.Elts))
                        for _, e := range e.Elts {
                                kv, _ := e.(*ast.KeyValueExpr)
                                }
                                if x.mode == constant_ {
                                        duplicate := false
-                                       // if the key is of interface type, the type is also significant when checking for duplicates
                                        xkey := keyVal(x.val)
-                                       if IsInterface(utyp.key) {
+                                       if keyIsInterface {
                                                for _, vtyp := range visited[xkey] {
                                                        if Identical(vtyp, x.typ) {
                                                                duplicate = true
 }
 
 func keyVal(x constant.Value) any {
+       // TODO(gri) This function must map 1, 1.0, and 1.0 + 0i to the same (integer) value.
+       //           Same for 1.1 and 1.1 + 0i.
+       //           Otherwise we won't get duplicate key errors for certain type parameter
+       //           key types. See issue #51610.
        switch x.Kind() {
        case constant.Bool:
                return constant.BoolVal(x)
 
        return ok
 }
 
+// isNonTypeParamInterface reports whether t is an interface type but not a type parameter.
+func isNonTypeParamInterface(t Type) bool {
+       return !isTypeParam(t) && IsInterface(t)
+}
+
 // isTypeParam reports whether t is a type parameter.
 func isTypeParam(t Type) bool {
        _, ok := t.(*TypeParam)