1
0
mirror of https://github.com/golang/go synced 2024-07-03 00:40:45 +00:00

cmd/compile/internal/types2: remove asTypeParam and simplify some code

Because we do not permit a stand-alone type parameter on the RHS of
a type declaration, the underlying type of a (Named) type cannot be
a type parameter. This allows us to simplify some code.

Specifically, when parsing union elements, we don't need to delay
a check for later, which allows further simplifications when computing
type sets.

Change-Id: I4047c609f87ebb194ea8c1bad630a70d255b20cf
Reviewed-on: https://go-review.googlesource.com/c/go/+/363438
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-11-11 16:02:35 -08:00
parent 3634594790
commit 9150c16bce
15 changed files with 34 additions and 60 deletions

View File

@ -706,8 +706,7 @@ func (r *importReader) tparamList() []*types2.TypeParam {
}
xs := make([]*types2.TypeParam, n)
for i := range xs {
typ := r.typ()
xs[i] = types2.AsTypeParam(typ)
xs[i] = r.typ().(*types2.TypeParam)
}
return xs
}

View File

@ -293,7 +293,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// the argument types must be of floating-point type
// (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type {
assert(asTypeParam(typ) == nil)
assert(!isTypeParam(typ))
if t, _ := under(typ).(*Basic); t != nil {
switch t.kind {
case Float32:
@ -436,7 +436,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
// the argument must be of complex type
// (applyTypeFunc never calls f with a type parameter)
f := func(typ Type) Type {
assert(asTypeParam(typ) == nil)
assert(!isTypeParam(typ))
if t, _ := under(typ).(*Basic); t != nil {
switch t.kind {
case Complex64:
@ -813,7 +813,7 @@ func hasVarSize(t Type) bool {
// 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 := asTypeParam(x); tp != nil {
if tp, _ := x.(*TypeParam); tp != nil {
// Test if t satisfies the requirements for the argument
// type and collect possible result types at the same time.
var terms []*Term

View File

@ -528,7 +528,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 := asTypeParam(x.typ); tpar != nil {
if tpar, _ := x.typ.(*TypeParam); tpar != nil {
// Type parameter bounds don't specify fields, so don't mention "field".
if tname := tpar.iface().obj; tname != nil {
why = check.sprintf("interface %s has no method %s", tname.name, sel)

View File

@ -19,12 +19,6 @@ func AsSignature(t Type) *Signature {
return u
}
// If t is a type parameter, AsTypeParam returns that type, otherwise it returns nil.
func AsTypeParam(t Type) *TypeParam {
u, _ := t.Underlying().(*TypeParam)
return u
}
// If typ is a type parameter, structuralType returns the single underlying
// type of all types in the corresponding type constraint if it exists, or
// nil otherwise. If the type set contains only unrestricted and restricted

View File

@ -48,7 +48,7 @@ func (check *Checker) conversion(x *operand, T Type) {
// If T's type set is empty, or if it doesn't
// have specific types, constant x cannot be
// converted.
ok = under(T).(*TypeParam).underIs(func(u Type) bool {
ok = T.(*TypeParam).underIs(func(u Type) bool {
// t is nil if there are no specific type terms
if u == nil {
cause = check.sprintf("%s does not contain specific types", T)
@ -194,8 +194,8 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool {
}
// optimization: if we don't have type parameters, we're done
Vp, _ := Vu.(*TypeParam)
Tp, _ := Tu.(*TypeParam)
Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam)
if Vp == nil && Tp == nil {
return false
}

View File

@ -616,10 +616,11 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
}
// Disallow a lone type parameter as the RHS of a type declaration (issue #45639).
// We can look directly at named.underlying because even if it is still a *Named
// type (underlying not fully resolved yet) it cannot become a type parameter due
// to this very restriction.
if tpar, _ := named.underlying.(*TypeParam); tpar != nil {
// We don't need this restriction anymore if we make the underlying type of a type
// parameter its constraint interface: if the RHS is a lone type parameter, we will
// use its underlying type (like we do for any RHS in a type declaration), and its
// underlying type is an interface and the type declaration is well defined.
if isTypeParam(rhs) {
check.error(tdecl.Type, "cannot use a type parameter as RHS in type declaration")
named.underlying = Typ[Invalid]
}
@ -671,7 +672,7 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
check.later(func() {
for i, bound := range bounds {
if _, ok := under(bound).(*TypeParam); ok {
if isTypeParam(bound) {
check.error(posers[i], "cannot use a type parameter as constraint")
}
}

View File

@ -160,11 +160,10 @@ var op2str2 = [...]string{
// If typ is a type parameter, underIs returns the result of typ.underIs(f).
// Otherwise, underIs returns the result of f(under(typ)).
func underIs(typ Type, f func(Type) bool) bool {
u := under(typ)
if tpar, _ := u.(*TypeParam); tpar != nil {
if tpar, _ := typ.(*TypeParam); tpar != nil {
return tpar.underIs(f)
}
return f(u)
return f(under(typ))
}
func (check *Checker) unary(x *operand, e *syntax.Operation) {

View File

@ -143,7 +143,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
// A type argument that is a type parameter with an empty type set satisfies any constraint.
// (The empty set is a subset of any set.)
if targ := asTypeParam(targ); targ != nil && targ.iface().typeSet().IsEmpty() {
if targ, _ := targ.(*TypeParam); targ != nil && targ.iface().typeSet().IsEmpty() {
return nil
}
@ -172,7 +172,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
// if iface is comparable, targ must be comparable
// TODO(gri) the error messages needs to be better, here
if iface.IsComparable() && !Comparable(targ) {
if tpar := asTypeParam(targ); tpar != nil && tpar.iface().typeSet().IsAll() {
if tpar, _ := targ.(*TypeParam); tpar != nil && tpar.iface().typeSet().IsAll() {
return errorf("%s has no constraints", targ)
}
return errorf("%s does not satisfy comparable", targ)
@ -184,7 +184,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
// 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 && asTypeParam(base) != nil {
if base, isPtr := deref(targ); isPtr && isTypeParam(base) {
return errorf("%s has no methods", targ)
}
if m, wrong := check.missingMethod(targ, iface, true); m != nil {
@ -212,7 +212,7 @@ func (check *Checker) satisfies(pos syntax.Pos, targ Type, tpar *TypeParam, smap
// If targ is itself a type parameter, each of its possible types must be in the set
// of iface types (i.e., the targ type set must be a subset of the iface type set).
// Type arguments with empty type sets were already excluded above.
if targ := asTypeParam(targ); targ != nil {
if targ, _ := targ.(*TypeParam); targ != nil {
targBound := targ.iface()
if !targBound.typeSet().subsetOf(iface.typeSet()) {
// TODO(gri) report which type is missing

View File

@ -134,12 +134,8 @@ func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
continue // we can't have a matching field or interface method
}
// 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)
// continue with underlying type
typ = named.under()
if asTypeParam(typ) != nil {
continue
}
}
tpar = nil

View File

@ -183,7 +183,7 @@ func operandString(x *operand, qf Qualifier) string {
}
buf.WriteString(intro)
WriteType(&buf, x.typ, qf)
if tpar := asTypeParam(x.typ); tpar != nil {
if tpar, _ := x.typ.(*TypeParam); tpar != nil {
buf.WriteString(" constrained by ")
WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here
}
@ -256,8 +256,8 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
Vu := under(V)
Tu := under(T)
Vp, _ := Vu.(*TypeParam)
Tp, _ := Tu.(*TypeParam)
Vp, _ := V.(*TypeParam)
Tp, _ := T.(*TypeParam)
// x is an untyped value representable by a value of type T.
if isUntyped(Vu) {

View File

@ -90,7 +90,7 @@ func IsInterface(t Type) bool {
// isTypeParam reports whether t is a type parameter.
func isTypeParam(t Type) bool {
_, ok := under(t).(*TypeParam)
_, ok := t.(*TypeParam)
return ok
}

View File

@ -88,9 +88,3 @@ func asNamed(t Type) *Named {
}
return e
}
// If t is a type parameter, asTypeParam returns that type, otherwise it returns nil.
func asTypeParam(t Type) *TypeParam {
u, _ := under(t).(*TypeParam)
return u
}

View File

@ -291,10 +291,6 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_
continue // ignore invalid unions
}
terms = tset.terms
case *TypeParam:
// Embedding stand-alone type parameters is not permitted.
// Union parsing reports a (delayed) error, so we can ignore this entry.
continue
default:
if u == Typ[Invalid] {
continue
@ -372,10 +368,6 @@ func computeUnionTypeSet(check *Checker, pos syntax.Pos, utyp *Union) *_TypeSet
switch u := under(t.typ).(type) {
case *Interface:
terms = computeInterfaceTypeSet(check, pos, u).terms
case *TypeParam:
// A stand-alone type parameters is not permitted as union term.
// Union parsing reports a (delayed) error, so we can ignore this entry.
continue
default:
if t.typ == Typ[Invalid] {
continue

View File

@ -356,7 +356,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
check.later(func() {
if !Comparable(typ.key) {
var why string
if asTypeParam(typ.key) != nil {
if isTypeParam(typ.key) {
why = " (missing comparable constraint)"
}
check.errorf(e.Key, "invalid map key type %s%s", typ.key, why)

View File

@ -115,15 +115,14 @@ func parseTilde(check *Checker, x syntax.Expr) (tilde bool, typ Type) {
}
typ = check.typ(x)
// Embedding stand-alone type parameters is not permitted (issue #47127).
// Do this check later because it requires computation of the underlying type (see also issue #46461).
// Note: If an underlying type cannot be a type parameter, the call to
// under() will not be needed and then we don't need to delay this
// check to later and could return Typ[Invalid] instead.
check.later(func() {
if _, ok := under(typ).(*TypeParam); ok {
check.error(x, "cannot embed a type parameter")
}
})
// We don't need this restriction anymore if we make the underlying type of a type
// parameter its constraint interface: if we embed a lone type parameter, we will
// simply use its underlying type (like we do for other named, embedded interfaces),
// and since the underlying type is an interface the embedding is well defined.
if isTypeParam(typ) {
check.error(x, "cannot embed a type parameter")
typ = Typ[Invalid]
}
return
}