aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Findley <rfindley@google.com>2021-11-15 23:39:22 -0500
committerRobert Findley <rfindley@google.com>2021-11-16 15:35:52 +0000
commit7c50ef6c8c4c827db45a3327cb950913cf9d489b (patch)
treeb570a3df02a34195eec03464cb795543ea6da78c /src
parentf041c7e3028545ba39c60d6e20ab9b74c01bbf33 (diff)
downloadgo-7c50ef6c8c4c827db45a3327cb950913cf9d489b.tar.xz
go/types: remove asTypeParam and simplify some code
This is a port of CL 363438 from types2 to go/types. Change-Id: I87c76d31b398b9ce406f96b0030ee458619b3dbe Reviewed-on: https://go-review.googlesource.com/c/go/+/364235 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>
Diffstat (limited to 'src')
-rw-r--r--src/go/types/builtins.go6
-rw-r--r--src/go/types/call.go2
-rw-r--r--src/go/types/conversions.go6
-rw-r--r--src/go/types/decl.go11
-rw-r--r--src/go/types/expr.go5
-rw-r--r--src/go/types/instantiate.go8
-rw-r--r--src/go/types/lookup.go8
-rw-r--r--src/go/types/operand.go6
-rw-r--r--src/go/types/predicates.go2
-rw-r--r--src/go/types/type.go6
-rw-r--r--src/go/types/typeset.go8
-rw-r--r--src/go/types/typexpr.go2
-rw-r--r--src/go/types/union.go17
13 files changed, 33 insertions, 54 deletions
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index c1932232aa..5418d66aeb 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -298,7 +298,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// 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:
@@ -441,7 +441,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// 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:
@@ -822,7 +822,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
diff --git a/src/go/types/call.go b/src/go/types/call.go
index dfd7142094..7cb6027f3b 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -531,7 +531,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
check.errorf(e.Sel, _InvalidMethodExpr, "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)
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index 18d24e404c..eadc923f5e 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -47,7 +47,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)
@@ -186,8 +186,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
}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index e12961416e..2108cf6b05 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -669,10 +669,11 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, 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, _MisplacedTypeParam, "cannot use a type parameter as RHS in type declaration")
named.underlying = Typ[Invalid]
}
@@ -723,7 +724,7 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list *ast.FieldList
check.later(func() {
for i, bound := range bounds {
- if _, ok := under(bound).(*TypeParam); ok {
+ if isTypeParam(bound) {
check.error(posns[i], _MisplacedTypeParam, "cannot use a type parameter as constraint")
}
}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 6eeb431b73..660c92de3b 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -147,11 +147,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))
}
// The unary expression e may be nil. It's passed in for better error messages only.
diff --git a/src/go/types/instantiate.go b/src/go/types/instantiate.go
index 13d6e3114d..c9ce6f6ae1 100644
--- a/src/go/types/instantiate.go
+++ b/src/go/types/instantiate.go
@@ -157,7 +157,7 @@ func (check *Checker) satisfies(pos token.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
}
@@ -186,7 +186,7 @@ func (check *Checker) satisfies(pos token.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)
@@ -198,7 +198,7 @@ func (check *Checker) satisfies(pos token.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 {
@@ -227,7 +227,7 @@ func (check *Checker) satisfies(pos token.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
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
index aae6fa206d..98af6bfcd7 100644
--- a/src/go/types/lookup.go
+++ b/src/go/types/lookup.go
@@ -134,14 +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)
- // TODO(#45639) the error message produced as a result of skipping an
- // underlying type parameter should be improved.
+ // continue with underlying type
typ = named.under()
- if asTypeParam(typ) != nil {
- continue
- }
}
tpar = nil
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
index 8b76e939b6..6f902e9749 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -166,7 +166,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
}
@@ -241,8 +241,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) {
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 2d9b9c4c07..d0697b1ad7 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -92,7 +92,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
}
diff --git a/src/go/types/type.go b/src/go/types/type.go
index e26d8189d1..555eb9e8b9 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -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
-}
diff --git a/src/go/types/typeset.go b/src/go/types/typeset.go
index 1e6b9dd390..d0464aeaa0 100644
--- a/src/go/types/typeset.go
+++ b/src/go/types/typeset.go
@@ -289,10 +289,6 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T
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
@@ -370,10 +366,6 @@ func computeUnionTypeSet(check *Checker, pos token.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
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index 5828c2e7c3..89264ee9eb 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -337,7 +337,7 @@ func (check *Checker) typInternal(e0 ast.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, _IncomparableMapKey, "incomparable map key type %s%s", typ.key, why)
diff --git a/src/go/types/union.go b/src/go/types/union.go
index bb08174728..2a65ca4d8e 100644
--- a/src/go/types/union.go
+++ b/src/go/types/union.go
@@ -118,15 +118,14 @@ func parseTilde(check *Checker, x ast.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, _MisplacedTypeParam, "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, _MisplacedTypeParam, "cannot embed a type parameter")
+ typ = Typ[Invalid]
+ }
return
}