]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: factor out isInterface(x) && !isTypeParam(x) (cleanup)
authorRobert Griesemer <gri@golang.org>
Fri, 11 Mar 2022 05:50:54 +0000 (21:50 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 21 Mar 2022 19:10:06 +0000 (19:10 +0000)
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>
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/conversions.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/predicates.go
src/go/types/assignments.go
src/go/types/conversions.go
src/go/types/expr.go
src/go/types/predicates.go

index d88b03748fa02578caee8662e8d2dc50f4cb3f02..49f4e2d2ab590fceeb668f45e36de384fcb6414b 100644 (file)
@@ -44,7 +44,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
                                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)
index 08b3cbff29607d3814c50e1995fb2c1d0150dba3..a86645a547790c80be5452317d8daa708a12d56b 100644 (file)
@@ -105,7 +105,7 @@ func (check *Checker) conversion(x *operand, T Type) {
                //   (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
index 05cf1d0b33dce1f34ce06f51ea6b185cdd805ef6..e59f0b74aca9e4a22f28492ff2f48d23ad7b5593 100644 (file)
@@ -1101,7 +1101,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op
 
        // 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) {
@@ -1491,6 +1491,10 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                                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)
@@ -1505,9 +1509,8 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
                                }
                                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
@@ -1714,6 +1717,10 @@ Error:
 }
 
 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)
index ba259341f6ae125725b92ea9a7ca753a86de060e..6bce26137eb772d029f41aed15b5d1ff304141ff 100644 (file)
@@ -85,6 +85,11 @@ func IsInterface(t Type) bool {
        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)
index f5e22c2f675eef5c110d42fd3906e1fcf31ef460..101e868d82fa69bf244df1a453cb1b7426672461 100644 (file)
@@ -38,7 +38,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
                // 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
index c5a69cddf48502b4e909e6ade91777e4507a8885..65691cf4550acc061b995ddfa722091701f65a4c 100644 (file)
@@ -101,7 +101,7 @@ func (check *Checker) conversion(x *operand, T Type) {
                // - 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
index e24bd60dc391a300885920770552ddcfb784db0a..596bcef9c1401caf8defe7ad55123ccdb08e2e4c 100644 (file)
@@ -1081,7 +1081,7 @@ func (check *Checker) binary(x *operand, e ast.Expr, lhs, rhs ast.Expr, op token
 
        // 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) {
@@ -1468,6 +1468,10 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                                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)
@@ -1482,9 +1486,8 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
                                }
                                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
@@ -1657,6 +1660,10 @@ Error:
 }
 
 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)
index 0360f27ee60dc10d2e63c6717afd793eeccd01e8..51d056f35595183ca5771df30b1fb141426a8387 100644 (file)
@@ -87,6 +87,11 @@ func IsInterface(t Type) bool {
        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)