]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: remove tparamIsIface flag and corresponding dead code
authorRobert Findley <rfindley@google.com>
Thu, 18 Nov 2021 00:14:58 +0000 (19:14 -0500)
committerRobert Findley <rfindley@google.com>
Thu, 18 Nov 2021 02:14:25 +0000 (02:14 +0000)
This is a port of CL 363654 from types2 to go/types.

Change-Id: I64041615ccc7f11f2e4ae395b063ec5141ccf2cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/364896
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/builtins.go
src/go/types/decl.go
src/go/types/expr.go
src/go/types/index.go
src/go/types/predicates.go
src/go/types/sizes.go
src/go/types/struct.go
src/go/types/type.go
src/go/types/typeparam.go

index 5abfe8d35b9f8ee634f916aac415b4262f2d96a1..b547cddeb1a5c98a7cdc8812e75d5bf785549ab8 100644 (file)
@@ -180,28 +180,10 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
                        }
 
                case *Interface:
-                       if tparamIsIface && isTypeParam(x.typ) {
-                               if t.typeSet().underIs(func(t Type) bool {
-                                       switch t := arrayPtrDeref(t).(type) {
-                                       case *Basic:
-                                               if isString(t) && id == _Len {
-                                                       return true
-                                               }
-                                       case *Array, *Slice, *Chan:
-                                               return true
-                                       case *Map:
-                                               if id == _Len {
-                                                       return true
-                                               }
-                                       }
-                                       return false
-                               }) {
-                                       mode = value
-                               }
+                       if !isTypeParam(x.typ) {
+                               break
                        }
-               case *TypeParam:
-                       assert(!tparamIsIface)
-                       if t.underIs(func(t Type) bool {
+                       if t.typeSet().underIs(func(t Type) bool {
                                switch t := arrayPtrDeref(t).(type) {
                                case *Basic:
                                        if isString(t) && id == _Len {
@@ -829,9 +811,6 @@ func hasVarSize(t Type) bool {
                }
        case *Interface:
                return isTypeParam(t)
-       case *TypeParam:
-               assert(!tparamIsIface)
-               return true
        case *Named, *Union:
                unreachable()
        }
index 600467620cce46d070794728c5c3c2028bcd5df3..c85087018cdf305448cda07d4977eb3c8e2f6726 100644 (file)
@@ -725,6 +725,10 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
        check.later(func() {
                for i, bound := range bounds {
                        if isTypeParam(bound) {
+                               // We may be able to allow this since it is now well-defined what
+                               // the underlying type and thus type set of a type parameter is.
+                               // But we may need some additional form of cycle detection within
+                               // type parameter lists.
                                check.error(posns[i], _MisplacedTypeParam, "cannot use a type parameter as constraint")
                        }
                }
index 0a3fa72c970db5866184d1c2bd06a780a6e5537b..e93a2bc7c8b84a349fa9a3af36c7f8cd6f21b034 100644 (file)
@@ -599,7 +599,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
        newType, val, code := check.implicitTypeAndValue(x, target)
        if code != 0 {
                t := target
-               if !tparamIsIface || !isTypeParam(target) {
+               if !isTypeParam(target) {
                        t = safeUnderlying(target)
                }
                check.invalidConversion(code, x, t)
@@ -680,23 +680,8 @@ func (check *Checker) implicitTypeAndValue(x *operand, target Type) (Type, const
                default:
                        return nil, nil, _InvalidUntypedConversion
                }
-       case *TypeParam:
-               assert(!tparamIsIface)
-               if !u.underIs(func(u Type) bool {
-                       if u == nil {
-                               return false
-                       }
-                       t, _, _ := check.implicitTypeAndValue(x, u)
-                       return t != nil
-               }) {
-                       return nil, nil, _InvalidUntypedConversion
-               }
-               // keep nil untyped (was bug #39755)
-               if x.isNil() {
-                       return Typ[UntypedNil], nil, 0
-               }
        case *Interface:
-               if tparamIsIface && isTypeParam(target) {
+               if isTypeParam(target) {
                        if !u.typeSet().underIs(func(u Type) bool {
                                if u == nil {
                                        return false
index 2ff33814e57970688090e25b3b3e162668c8db54..54398ad19bd8cee1ba5c1a631f40ea5d39d7731c 100644 (file)
@@ -101,97 +101,14 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
                return false
 
        case *Interface:
-               // Note: The body of this 'if' statement is the same as the body
-               //       of the case for type parameters below. If we keep both
-               //       these branches we should factor out the code.
-               if tparamIsIface && isTypeParam(x.typ) {
-                       // TODO(gri) report detailed failure cause for better error messages
-                       var key, elem Type // key != nil: we must have all maps
-                       mode := variable   // non-maps result mode
-                       // TODO(gri) factor out closure and use it for non-typeparam cases as well
-                       if typ.typeSet().underIs(func(u Type) bool {
-                               l := int64(-1) // valid if >= 0
-                               var k, e Type  // k is only set for maps
-                               switch t := u.(type) {
-                               case *Basic:
-                                       if isString(t) {
-                                               e = universeByte
-                                               mode = value
-                                       }
-                               case *Array:
-                                       l = t.len
-                                       e = t.elem
-                                       if x.mode != variable {
-                                               mode = value
-                                       }
-                               case *Pointer:
-                                       if t, _ := under(t.base).(*Array); t != nil {
-                                               l = t.len
-                                               e = t.elem
-                                       }
-                               case *Slice:
-                                       e = t.elem
-                               case *Map:
-                                       k = t.key
-                                       e = t.elem
-                               }
-                               if e == nil {
-                                       return false
-                               }
-                               if elem == nil {
-                                       // first type
-                                       length = l
-                                       key, elem = k, e
-                                       return true
-                               }
-                               // all map keys must be identical (incl. all nil)
-                               // (that is, we cannot mix maps with other types)
-                               if !Identical(key, k) {
-                                       return false
-                               }
-                               // all element types must be identical
-                               if !Identical(elem, e) {
-                                       return false
-                               }
-                               // track the minimal length for arrays, if any
-                               if l >= 0 && l < length {
-                                       length = l
-                               }
-                               return true
-                       }) {
-                               // For maps, the index expression must be assignable to the map key type.
-                               if key != nil {
-                                       index := check.singleIndex(e)
-                                       if index == nil {
-                                               x.mode = invalid
-                                               return false
-                                       }
-                                       var k operand
-                                       check.expr(&k, index)
-                                       check.assignment(&k, key, "map index")
-                                       // ok to continue even if indexing failed - map element type is known
-                                       x.mode = mapindex
-                                       x.typ = elem
-                                       x.expr = e
-                                       return false
-                               }
-
-                               // no maps
-                               valid = true
-                               x.mode = mode
-                               x.typ = elem
-                       }
+               if !isTypeParam(x.typ) {
+                       break
                }
-       case *TypeParam:
-               // Note: The body of this case is the same as the body of the 'if'
-               //       statement in the interface case above. If we keep both
-               //       these branches we should factor out the code.
                // TODO(gri) report detailed failure cause for better error messages
-               assert(!tparamIsIface)
                var key, elem Type // key != nil: we must have all maps
                mode := variable   // non-maps result mode
                // TODO(gri) factor out closure and use it for non-typeparam cases as well
-               if typ.underIs(func(u Type) bool {
+               if typ.typeSet().underIs(func(u Type) bool {
                        l := int64(-1) // valid if >= 0
                        var k, e Type  // k is only set for maps
                        switch t := u.(type) {
index 5204eb0c29a7a4b637e3671d59aa886ef1c26cc8..229a616eaccf5e1493a591db870513d177456673 100644 (file)
@@ -133,13 +133,7 @@ func comparable(T Type, seen map[Type]bool) bool {
        case *Array:
                return comparable(t.elem, seen)
        case *Interface:
-               if tparamIsIface && isTypeParam(T) {
-                       return t.IsComparable()
-               }
-               return true
-       case *TypeParam:
-               assert(!tparamIsIface)
-               return t.iface().IsComparable()
+               return !isTypeParam(T) || t.IsComparable()
        }
        return false
 }
@@ -152,15 +146,7 @@ func hasNil(t Type) bool {
        case *Slice, *Pointer, *Signature, *Map, *Chan:
                return true
        case *Interface:
-               if tparamIsIface && isTypeParam(t) {
-                       return u.typeSet().underIs(func(u Type) bool {
-                               return u != nil && hasNil(u)
-                       })
-               }
-               return true
-       case *TypeParam:
-               assert(!tparamIsIface)
-               return u.underIs(func(u Type) bool {
+               return !isTypeParam(t) || u.typeSet().underIs(func(u Type) bool {
                        return u != nil && hasNil(u)
                })
        }
index a92152506235b58f57087941efb5230c61ba979c..dd4b78969f6844d8674f10201149331ac4c13ecb 100644 (file)
@@ -67,7 +67,9 @@ func (s *StdSizes) Alignof(T Type) int64 {
        case *Slice, *Interface:
                // Multiword data structures are effectively structs
                // in which each element has size WordSize.
-               assert(!tparamIsIface || !isTypeParam(T))
+               // Type parameters lead to variable sizes/alignments;
+               // StdSizes.Alignof won't be called for them.
+               assert(!isTypeParam(T))
                return s.WordSize
        case *Basic:
                // Strings are like slices and interfaces.
@@ -152,6 +154,9 @@ func (s *StdSizes) Sizeof(T Type) int64 {
                offsets := s.Offsetsof(t.fields)
                return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
        case *Interface:
+               // Type parameters lead to variable sizes/alignments;
+               // StdSizes.Sizeof won't be called for them.
+               assert(!isTypeParam(T))
                return s.WordSize * 2
        case *TypeParam, *Union:
                unreachable()
index 53204dc381248703e7bb422b62165f0eb440a14e..d6c56341f05e12fa0f09ddaed742f8d833b39afb 100644 (file)
@@ -155,14 +155,11 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
                                        }
                                case *Pointer:
                                        check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer")
-                               case *TypeParam:
-                                       assert(!tparamIsIface)
-                                       // This error code here is inconsistent with other error codes for
-                                       // invalid embedding, because this restriction may be relaxed in the
-                                       // future, and so it did not warrant a new error code.
-                                       check.error(embeddedPos, _MisplacedTypeParam, "embedded field type cannot be a (pointer to a) type parameter")
                                case *Interface:
-                                       if tparamIsIface && isTypeParam(t) {
+                                       if isTypeParam(t) {
+                                               // The error code here is inconsistent with other error codes for
+                                               // invalid embedding, because this restriction may be relaxed in the
+                                               // future, and so it did not warrant a new error code.
                                                check.error(embeddedPos, _MisplacedTypeParam, "embedded field type cannot be a (pointer to a) type parameter")
                                                break
                                        }
index 1d672135b8b69818b3c084b34637c719a3d259be..97de5e49d1ed08cbc02be381ea6841394684ee39 100644 (file)
@@ -25,9 +25,7 @@ func under(t Type) Type {
        case *Named:
                return t.under()
        case *TypeParam:
-               if tparamIsIface {
-                       return t.iface()
-               }
+               return t.iface()
        }
        return t
 }
index f000d8f10881f33f2084a2da5ebf961435b87754..7cce1f7e357d55d18d958b0234bb2f92c7c379df 100644 (file)
@@ -9,12 +9,6 @@ import (
        "sync/atomic"
 )
 
-// If set, the underlying type of a type parameter is
-// is the underlying type of its type constraint, i.e.,
-// an interface. With that, a type parameter satisfies
-// isInterface.
-const tparamIsIface = true
-
 // Note: This is a uint32 rather than a uint64 because the
 // respective 64 bit atomic instructions are not available
 // on all platforms.
@@ -79,10 +73,7 @@ func (t *TypeParam) SetConstraint(bound Type) {
 }
 
 func (t *TypeParam) Underlying() Type {
-       if tparamIsIface {
-               return t.iface()
-       }
-       return t
+       return t.iface()
 }
 
 func (t *TypeParam) String() string { return TypeString(t, nil) }
@@ -105,15 +96,11 @@ func (t *TypeParam) iface() *Interface {
                        return &emptyInterface
                }
        case *Interface:
-               if tparamIsIface && isTypeParam(bound) {
+               if isTypeParam(bound) {
                        // error is reported in Checker.collectTypeParams
                        return &emptyInterface
                }
                ityp = u
-       case *TypeParam:
-               assert(!tparamIsIface)
-               // error is reported in Checker.collectTypeParams
-               return &emptyInterface
        }
 
        // If we don't have an interface, wrap constraint into an implicit interface.