Skip to content

Commit

Permalink
[dev.typeparams] cmd/compile/internal/types2: replace Named, TypePara…
Browse files Browse the repository at this point in the history
…m methods with functions

This removes two more converter methods in favor of functions.
This further reduces the API surface of types2.Type and matches
the approach taken in go/types.

Change-Id: I3cdd54c5e0d1e7664a69f3697fc081a66315b969
Reviewed-on: https://go-review.googlesource.com/c/go/+/293292
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
griesemer committed Feb 18, 2021
1 parent 5e4da86 commit 653386a
Show file tree
Hide file tree
Showing 13 changed files with 43 additions and 62 deletions.
4 changes: 0 additions & 4 deletions src/cmd/compile/internal/importer/support.go
Expand Up @@ -127,7 +127,3 @@ type anyType struct{}
func (t anyType) Underlying() types2.Type { return t }
func (t anyType) Under() types2.Type { return t }
func (t anyType) String() string { return "any" }

// types2.aType is not exported for now so we need to implemented these here.
func (anyType) Named() *types2.Named { return nil }
func (anyType) TypeParam() *types2.TypeParam { return nil }
6 changes: 3 additions & 3 deletions src/cmd/compile/internal/types2/builtins.go
Expand Up @@ -577,7 +577,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (

case _Alignof:
// unsafe.Alignof(x T) uintptr
if x.typ.TypeParam() != nil {
if asTypeParam(x.typ) != nil {
check.invalidOpf(call, "unsafe.Alignof undefined for %s", x)
return
}
Expand Down Expand Up @@ -638,7 +638,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (

case _Sizeof:
// unsafe.Sizeof(x T) uintptr
if x.typ.TypeParam() != nil {
if asTypeParam(x.typ) != nil {
check.invalidOpf(call, "unsafe.Sizeof undefined for %s", x)
return
}
Expand Down Expand Up @@ -705,7 +705,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// applyTypeFunc returns nil.
// If x is not a type parameter, the result is f(x).
func (check *Checker) applyTypeFunc(f func(Type) Type, x Type) Type {
if tp := x.TypeParam(); tp != nil {
if tp := asTypeParam(x); tp != nil {
// Test if t satisfies the requirements for the argument
// type and collect possible result types at the same time.
var rtypes []Type
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/types2/call.go
Expand Up @@ -563,7 +563,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) {
check.errorf(e.Sel, "cannot call pointer method %s on %s", sel, x.typ)
default:
var why string
if tpar := x.typ.TypeParam(); tpar != nil {
if tpar := asTypeParam(x.typ); tpar != nil {
// Type parameter bounds don't specify fields, so don't mention "field".
switch obj := tpar.Bound().obj.(type) {
case nil:
Expand Down
6 changes: 3 additions & 3 deletions src/cmd/compile/internal/types2/decl.go
Expand Up @@ -559,7 +559,7 @@ func (n0 *Named) Under() Type {

// If the underlying type of a defined type is not a defined
// type, then that is the desired underlying type.
n := u.Named()
n := asNamed(u)
if n == nil {
return u // common case
}
Expand All @@ -573,7 +573,7 @@ func (n0 *Named) Under() Type {
u = Typ[Invalid]
break
}
n1 := u.Named()
n1 := asNamed(u)
if n1 == nil {
break // end of chain
}
Expand Down Expand Up @@ -760,7 +760,7 @@ func (check *Checker) collectMethods(obj *TypeName) {

// spec: "If the base type is a struct type, the non-blank method
// and field names must be distinct."
base := obj.typ.Named() // shouldn't fail but be conservative
base := asNamed(obj.typ) // shouldn't fail but be conservative
if base != nil {
if t, _ := base.underlying.(*Struct); t != nil {
for _, fld := range t.fields {
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/types2/expr.go
Expand Up @@ -615,7 +615,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
// TODO(gri) We should not need this because we have the code
// for Sum types in convertUntypedInternal. But at least one
// test fails. Investigate.
if t := target.TypeParam(); t != nil {
if t := asTypeParam(target); t != nil {
types := t.Bound().allTypes
if types == nil {
goto Error
Expand Down
8 changes: 4 additions & 4 deletions src/cmd/compile/internal/types2/lookup.go
Expand Up @@ -54,7 +54,7 @@ func (check *Checker) lookupFieldOrMethod(T Type, addressable bool, pkg *Package
// Thus, if we have a named pointer type, proceed with the underlying
// pointer type but discard the result if it is a method since we would
// not have found it for T (see also issue 8590).
if t := T.Named(); t != nil {
if t := asNamed(T); t != nil {
if p, _ := t.underlying.(*Pointer); p != nil {
obj, index, indirect = check.rawLookupFieldOrMethod(p, false, pkg, name)
if _, ok := obj.(*Func); ok {
Expand Down Expand Up @@ -112,7 +112,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack

// If we have a named type, we may have associated methods.
// Look for those first.
if named := typ.Named(); named != nil {
if named := asNamed(typ); named != nil {
if seen[named] {
// We have seen this type before, at a more shallow depth
// (note that multiples of this type at the current depth
Expand Down Expand Up @@ -142,7 +142,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
// continue with underlying type, but only if it's not a type parameter
// TODO(gri) is this what we want to do for type parameters? (spec question)
typ = named.Under()
if typ.TypeParam() != nil {
if asTypeParam(typ) != nil {
continue
}
}
Expand Down Expand Up @@ -352,7 +352,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,

// A concrete type implements T if it implements all methods of T.
Vd, _ := deref(V)
Vn := Vd.Named()
Vn := asNamed(Vd)
for _, m := range T.allMethods {
// TODO(gri) should this be calling lookupFieldOrMethod instead (and why not)?
obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name)
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/types2/operand.go
Expand Up @@ -180,7 +180,7 @@ func operandString(x *operand, qf Qualifier) string {
switch {
case isGeneric(x.typ):
intro = " of generic type "
case x.typ.TypeParam() != nil:
case asTypeParam(x.typ) != nil:
intro = " of type parameter type "
default:
intro = " of type "
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/types2/predicates.go
Expand Up @@ -104,7 +104,7 @@ func comparable(T Type, seen map[Type]bool) bool {
// interface{ comparable; type []byte }
//
// is not comparable because []byte is not comparable.
if t := T.TypeParam(); t != nil && optype(t) == theTop {
if t := asTypeParam(T); t != nil && optype(t) == theTop {
return t.Bound().IsComparable()
}

Expand Down
4 changes: 2 additions & 2 deletions src/cmd/compile/internal/types2/subst.go
Expand Up @@ -146,7 +146,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
// If the type argument is a pointer to a type parameter, the type argument's
// method set is empty.
// TODO(gri) is this what we want? (spec question)
if base, isPtr := deref(targ); isPtr && base.TypeParam() != nil {
if base, isPtr := deref(targ); isPtr && asTypeParam(base) != nil {
check.errorf(pos, "%s has no methods", targ)
break
}
Expand Down Expand Up @@ -179,7 +179,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis

// If targ is itself a type parameter, each of its possible types, but at least one, must be in the
// list of iface types (i.e., the targ type list must be a non-empty subset of the iface types).
if targ := targ.TypeParam(); targ != nil {
if targ := asTypeParam(targ); targ != nil {
targBound := targ.Bound()
if targBound.allTypes == nil {
check.softErrorf(pos, "%s does not satisfy %s (%s has no type constraints)", targ, tpar.bound, targ)
Expand Down
51 changes: 18 additions & 33 deletions src/cmd/compile/internal/types2/type.go
Expand Up @@ -26,13 +26,6 @@ type Type interface {

// String returns a string representation of a type.
String() string

// If the receiver for Named and TypeParam is of
// the respective type (possibly after unpacking
// an instance type), these methods return that
// type. Otherwise the result is nil.
Named() *Named
TypeParam() *TypeParam
}

// aType implements default type behavior
Expand All @@ -43,9 +36,6 @@ func (aType) Underlying() Type { panic("unreachable") }
func (aType) Under() Type { panic("unreachable") }
func (aType) String() string { panic("unreachable") }

func (aType) Named() *Named { return nil }
func (aType) TypeParam() *TypeParam { return nil }

// BasicKind describes the kind of basic type.
type BasicKind int

Expand Down Expand Up @@ -209,6 +199,9 @@ type Tuple struct {
aType
}

// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
// it's too subtle and causes problems. Use a singleton instead.

// NewTuple returns a new tuple for the given variables.
func NewTuple(x ...*Var) *Tuple {
if len(x) > 0 {
Expand All @@ -217,16 +210,6 @@ func NewTuple(x ...*Var) *Tuple {
return nil
}

// We cannot rely on the embedded X() *X methods because (*Tuple)(nil)
// is a valid *Tuple value but (*Tuple)(nil).X() would panic without
// these implementations. At the moment we only need X = Basic, Named,
// but add all because missing one leads to very confusing bugs.
// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
// it's too subtle and causes problems.

func (*Tuple) Named() *Named { return nil }
func (*Tuple) TypeParam() *TypeParam { return nil }

// Len returns the number variables of tuple t.
func (t *Tuple) Len() int {
if t != nil {
Expand Down Expand Up @@ -730,9 +713,6 @@ func (check *Checker) NewNamed(obj *TypeName, underlying Type, methods []*Func)
// Obj returns the type name for the named type t.
func (t *Named) Obj() *TypeName { return t.obj }

// func (t *Named) Named() *Named // declared below
func (t *Named) TypeParam() *TypeParam { return t.Under().TypeParam() }

// TODO(gri) Come up with a better representation and API to distinguish
// between parameterized instantiated and non-instantiated types.

Expand Down Expand Up @@ -814,7 +794,7 @@ func (t *TypeParam) Bound() *Interface {
// result may be the bottom or top type, but it is never
// the incoming type parameter.
func optype(typ Type) Type {
if t := typ.TypeParam(); t != nil {
if t := asTypeParam(typ); t != nil {
// If the optype is typ, return the top type as we have
// no information. It also prevents infinite recursion
// via the TypeParam converter methods. This can happen
Expand All @@ -830,9 +810,6 @@ func optype(typ Type) Type {
return typ.Under()
}

// func (t *TypeParam) Named() *Named // Named does not unpack type parameters
// func (t *TypeParam) TypeParam() *TypeParam // declared below

// An instance represents an instantiated generic type syntactically
// (without expanding the instantiation). Type instances appear only
// during type-checking and are replaced by their fully instantiated
Expand All @@ -847,9 +824,6 @@ type instance struct {
aType
}

func (t *instance) Named() *Named { return t.expand().Named() }
func (t *instance) TypeParam() *TypeParam { return t.expand().TypeParam() }

// expand returns the instantiated (= expanded) type of t.
// The result is either an instantiated *Named type, or
// Typ[Invalid] if there was an error.
Expand Down Expand Up @@ -908,9 +882,6 @@ type top struct {
// theTop is the singleton top type.
var theTop = &top{}

func (t *Named) Named() *Named { return t }
func (t *TypeParam) TypeParam() *TypeParam { return t }

// Type-specific implementations of Underlying.
func (t *Basic) Underlying() Type { return t }
func (t *Array) Underlying() Type { return t }
Expand Down Expand Up @@ -1025,3 +996,17 @@ func asChan(t Type) *Chan {
op, _ := optype(t).(*Chan)
return op
}

// If the argument to asNamed and asTypeParam is of the respective types
// (possibly after expanding an instance type), these methods return that type.
// Otherwise the result is nil.

func asNamed(t Type) *Named {
e, _ := expand(t).(*Named)
return e
}

func asTypeParam(t Type) *TypeParam {
u, _ := t.Under().(*TypeParam)
return u
}
10 changes: 5 additions & 5 deletions src/cmd/compile/internal/types2/typexpr.go
Expand Up @@ -302,7 +302,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// Also: Don't report an error via genericType since it will be reported
// again when we type-check the signature.
// TODO(gri) maybe the receiver should be marked as invalid instead?
if recv := check.genericType(rname, false).Named(); recv != nil {
if recv := asNamed(check.genericType(rname, false)); recv != nil {
recvTParams = recv.tparams
}
}
Expand Down Expand Up @@ -382,7 +382,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// (ignore invalid types - error was reported before)
if t := rtyp; t != Typ[Invalid] {
var err string
if T := t.Named(); T != nil {
if T := asNamed(t); T != nil {
// spec: "The type denoted by T is called the receiver base type; it must not
// be a pointer or interface type and it must be declared in the same package
// as the method."
Expand Down Expand Up @@ -575,7 +575,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
check.atEnd(func() {
if !Comparable(typ.key) {
var why string
if typ.key.TypeParam() != nil {
if asTypeParam(typ.key) != nil {
why = " (missing comparable constraint)"
}
check.errorf(e.Key, "invalid map key type %s%s", typ.key, why)
Expand Down Expand Up @@ -644,7 +644,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, targs []syntax.Expr, def *
if b == Typ[Invalid] {
return b // error already reported
}
base := b.Named()
base := asNamed(b)
if base == nil {
unreachable() // should have been caught by genericType
}
Expand Down Expand Up @@ -1045,7 +1045,7 @@ func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName
func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

func sortName(t Type) string {
if named := t.Named(); named != nil {
if named := asNamed(t); named != nil {
return named.obj.Id()
}
return ""
Expand Down
6 changes: 3 additions & 3 deletions src/cmd/compile/internal/types2/unify.go
Expand Up @@ -211,12 +211,12 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
// match a type name against an unnamed type literal, consider
// the underlying type of the named type.
// (Subtle: We use isNamed to include any type with a name (incl.
// basic types and type parameters. We use Named() because we only
// basic types and type parameters. We use asNamed because we only
// want *Named types.)
switch {
case !isNamed(x) && y != nil && y.Named() != nil:
case !isNamed(x) && y != nil && asNamed(y) != nil:
return u.nify(x, y.Under(), p)
case x != nil && x.Named() != nil && !isNamed(y):
case x != nil && asNamed(x) != nil && !isNamed(y):
return u.nify(x.Under(), y, p)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/types2/universe.go
Expand Up @@ -255,7 +255,7 @@ func def(obj Object) {
return // nothing to do
}
// fix Obj link for named types
if typ := obj.Type().Named(); typ != nil {
if typ := asNamed(obj.Type()); typ != nil {
typ.obj = obj.(*TypeName)
}
// exported identifiers go into package unsafe
Expand Down

0 comments on commit 653386a

Please sign in to comment.