// x.typ is typed
// A generic (non-instantiated) function value cannot be assigned to a variable.
- if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
+ if sig := toSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
check.errorf(x, "cannot use generic function %s without instantiation in %s", x, context)
}
// of S and the respective parameter passing rules apply."
S := x.typ
var T Type
- if s := asSlice(S); s != nil {
+ if s, _ := singleUnder(S).(*Slice); s != nil {
T = s.elem
} else {
check.errorf(x, invalidArg+"%s is not a slice", x)
}
// the argument types must be of floating-point type
- f := func(x Type) Type {
- if t := asBasic(x); t != nil {
+ // (applyTypeFunc never calls f with a type parameter)
+ f := func(typ Type) Type {
+ assert(asTypeParam(typ) == nil)
+ if t := toBasic(typ); t != nil {
switch t.kind {
case Float32:
return Typ[Complex64]
}
// the argument must be of complex type
- f := func(x Type) Type {
- if t := asBasic(x); t != nil {
+ // (applyTypeFunc never calls f with a type parameter)
+ f := func(typ Type) Type {
+ assert(asTypeParam(typ) == nil)
+ if t := toBasic(typ); t != nil {
switch t.kind {
case Complex64:
return Typ[Float32]
return
}
- typ := asPointer(x.typ)
+ typ := toPointer(x.typ)
if typ == nil {
check.errorf(x, invalidArg+"%s is not a pointer", x)
return
}
case *TypeParam:
return true
- case *Named, *Union, *top:
+ case *Named, *Union:
unreachable()
}
return false
return nil
}
- // TODO(gri) Would it be ok to return just the one type
- // if len(rtypes) == 1? What about top-level
- // uses of real() where the result is used to
- // define type and initialize a variable?
-
- // Construct a suitable new type parameter for the sum type. The
- // type param is placed in the current package so export/import
+ // Construct a suitable new type parameter for the result type.
+ // The type parameter is placed in the current package so export/import
// works as expected.
tpar := NewTypeName(nopos, check.pkg, "<type parameter>", nil)
ptyp := check.newTypeParam(tpar, NewInterfaceType(nil, []Type{NewUnion(terms)})) // assigns type to tpar as a side-effect
// otherwise it returns typ.
func arrayPtrDeref(typ Type) Type {
if p, ok := typ.(*Pointer); ok {
- if a := asArray(p.base); a != nil {
+ if a := toArray(p.base); a != nil {
return a
}
}
case 1:
check.expr(x, call.ArgList[0])
if x.mode != invalid {
- if t := asInterface(T); t != nil {
+ if t := toInterface(T); t != nil {
if !t.IsMethodSet() {
- check.errorf(call, "cannot use interface %s in conversion (contains type list or is comparable)", T)
+ check.errorf(call, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
break
}
}
// signature may be generic
cgocall := x.mode == cgofunc
- sig := asSignature(x.typ)
+ // a type parameter may be "called" if all types have the same signature
+ sig, _ := singleUnder(x.typ).(*Signature)
if sig == nil {
check.errorf(x, invalidOp+"cannot call non-function %s", x)
x.mode = invalid
switch {
case constArg && isConstType(T):
// constant conversion (T cannot be a type parameter)
- switch t := asBasic(T); {
+ switch t := toBasic(T); {
case representableConst(x.val, check, t, &x.val):
ok = true
case isInteger(x.typ) && isString(t):
// "V a slice, T is a pointer-to-array type,
// and the slice and array types have identical element types."
- if s := asSlice(V); s != nil {
- if p := asPointer(T); p != nil {
- if a := asArray(p.Elem()); a != nil {
+ if s := toSlice(V); s != nil {
+ if p := toPointer(T); p != nil {
+ if a := toArray(p.Elem()); a != nil {
if Identical(s.Elem(), a.Elem()) {
if check == nil || check.allowVersion(check.pkg, 1, 17) {
return true
return false
}
+// Helper predicates for convertibleToImpl. The types provided to convertibleToImpl
+// may be type parameters but they won't have specific type terms. Thus it is ok to
+// use the toT convenience converters in the predicates below.
+
func isUintptr(typ Type) bool {
- t := asBasic(typ)
+ t := toBasic(typ)
return t != nil && t.kind == Uintptr
}
func isUnsafePointer(typ Type) bool {
- // TODO(gri): Is this asBasic(typ) instead of typ.(*Basic) correct?
+ // TODO(gri): Is this toBasic(typ) instead of typ.(*Basic) correct?
// (The former calls under(), while the latter doesn't.)
// The spec does not say so, but gc claims it is. See also
// issue 6326.
- t := asBasic(typ)
+ t := toBasic(typ)
return t != nil && t.kind == UnsafePointer
}
func isPointer(typ Type) bool {
- return asPointer(typ) != nil
+ return toPointer(typ) != nil
}
func isBytesOrRunes(typ Type) bool {
- if s := asSlice(typ); s != nil {
- t := asBasic(s.elem)
+ if s := toSlice(typ); s != nil {
+ t := toBasic(s.elem)
return t != nil && (t.kind == Byte || t.kind == Rune)
}
return false
// Typed constants must be representable in
// their type after each constant operation.
+ // x.typ cannot be a type parameter (type
+ // parameters cannot be constant types).
if isTyped(x.typ) {
- check.representable(x, asBasic(x.typ))
+ check.representable(x, toBasic(x.typ))
return
}
// If the new type is not final and still untyped, just
// update the recorded type.
if !final && isUntyped(typ) {
- old.typ = asBasic(typ)
+ old.typ = toBasic(typ)
check.untyped[x] = old
return
}
duplicate := false
// if the key is of interface type, the type is also significant when checking for duplicates
xkey := keyVal(x.val)
- if asInterface(utyp.key) != nil {
+ if toInterface(utyp.key) != nil {
for _, vtyp := range visited[xkey] {
if Identical(vtyp, x.typ) {
duplicate = true
return false
case value:
- if sig := asSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
+ if sig := toSignature(x.typ); sig != nil && sig.TypeParams().Len() > 0 {
// function instantiation
return true
}
x.typ = typ.elem
case *Pointer:
- if typ := asArray(typ.base); typ != nil {
+ if typ := toArray(typ.base); typ != nil {
valid = true
length = typ.len
x.mode = variable
x.typ = &Slice{elem: u.elem}
case *Pointer:
- if u := asArray(u.base); u != nil {
+ if u := toArray(u.base); u != nil {
valid = true
length = u.len
x.typ = &Slice{elem: u.elem}
}()
switch t := typ.(type) {
- case nil, *top, *Basic: // TODO(gri) should nil be handled here?
+ case nil, *Basic: // TODO(gri) should nil be handled here?
break
case *Array:
defer delete(w.seen, typ)
switch t := typ.(type) {
- case *Basic, *top:
+ case *Basic:
// nothing to do
case *Array:
return
}
- if ityp := asInterface(V); ityp != nil {
+ if ityp := toInterface(V); ityp != nil {
// TODO(gri) the methods are sorted - could do this more efficiently
for _, m := range T.typeSet().methods {
_, f := ityp.typeSet().LookupMethod(m.pkg, m.name)
// no static check is required if T is an interface
// spec: "If T is an interface type, x.(T) asserts that the
// dynamic type of x implements the interface T."
- if asInterface(T) != nil && !forceStrict {
+ if toInterface(T) != nil && !forceStrict {
return
}
return check.missingMethod(T, V, false)
// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
// (named or unnamed) struct and returns its base. Otherwise it returns typ.
func derefStructPtr(typ Type) Type {
- if p := asPointer(typ); p != nil {
- if asStruct(p.base) != nil {
+ if p := toPointer(typ); p != nil {
+ if toStruct(p.base) != nil {
return p.base
}
}
// are not fully set up.
func isTyped(typ Type) bool {
// isTyped is called with types that are not fully
- // set up. Must not call asBasic()!
+ // set up. Must not call toBasic()!
t, _ := typ.(*Basic)
return t == nil || t.info&IsUntyped == 0
}
func isConstType(typ Type) bool {
// Type parameters are never const types.
- t, _ := under(typ).(*Basic)
+ t := toBasic(typ)
return t != nil && t.info&IsConstType != 0
}
// IsInterface reports whether typ is an interface type.
func IsInterface(typ Type) bool {
- return asInterface(typ) != nil
+ return toInterface(typ) != nil
}
// Comparable reports whether values of type T are comparable.
case *TypeParam:
// nothing to do (x and y being equal is caught in the very beginning of this function)
- case *top:
- // Either both types are theTop in which case the initial x == y check
- // will have caught them. Otherwise they are not identical.
-
case nil:
// avoid a crash in case of nil type
{Named{}, 68, 128},
{TypeParam{}, 28, 48},
{term{}, 12, 24},
- {top{}, 0, 0},
// Objects
{PkgName{}, 64, 104},
func (conf *Config) offsetof(typ Type, index []int) int64 {
var o int64
for _, i := range index {
- s := asStruct(typ)
+ s := toStruct(typ)
o += conf.offsetsof(s)[i]
typ = s.fields[i].typ
}
// Call typOrNil if it's possible that typ is nil.
panic("nil typ")
- case *Basic, *top:
+ case *Basic:
// nothing to do
case *Array:
go f()
}
+type F1 func()
+type F2 func()
+func _[T interface{ func()|F1|F2 }](f T) {
+ f()
+ go f()
+}
+
// We must compare against the underlying type of type list entries
// when checking if a constraint is satisfied by a type. The under-
// lying type of each type list entry must be computed after the
type Type interface {
// Underlying returns the underlying type of a type
// w/o following forwarding chains. Only used by
- // client packages (here for backward-compatibility).
+ // client packages.
Underlying() Type
// String returns a string representation of a type.
String() string
}
-// top represents the top of the type lattice.
-// It is the underlying type of a type parameter that
-// can be satisfied by any type (ignoring methods),
-// because its type constraint contains no restrictions
-// besides methods.
-type top struct{}
-
-// theTop is the singleton top type.
-var theTop = &top{}
-
-func (t *top) Underlying() Type { return t }
-func (t *top) String() string { return TypeString(t, nil) }
-
// under returns the true expanded underlying type.
// If it doesn't exist, the result is Typ[Invalid].
// under must only be called when a type is known
return t
}
-// optype returns a type's operational type. Except for
-// type parameters, the operational type is the same
-// as the underlying type (as returned by under). For
-// Type parameters, the operational type is the structural
-// type, if any; otherwise it's the top type.
-// The result is never the incoming type parameter.
-func optype(typ Type) Type {
- if t := asTypeParam(typ); t != nil {
- // TODO(gri) review accuracy of this comment
- // If the optype is typ, return the top type as we have
- // no information. It also prevents infinite recursion
- // via the asTypeParam converter function. This can happen
- // for a type parameter list of the form:
- // (type T interface { type T }).
- // See also issue #39680.
- if u := t.structuralType(); u != nil {
- assert(u != typ) // "naked" type parameters cannot be embedded
- return under(u) // optype should always return an underlying type
- }
- return theTop
- }
- return under(typ)
-}
+// Convenience converters
-// Converters
-//
-// A converter must only be called when a type is
-// known to be fully set up. A converter returns
-// a type's operational type (see comment for optype)
-// or nil if the type argument is not of the
-// respective type.
-
-func asBasic(t Type) *Basic {
- op, _ := optype(t).(*Basic)
- return op
+func toBasic(t Type) *Basic {
+ u, _ := under(t).(*Basic)
+ return u
}
-func asArray(t Type) *Array {
- op, _ := optype(t).(*Array)
- return op
+func toArray(t Type) *Array {
+ u, _ := under(t).(*Array)
+ return u
}
-func asSlice(t Type) *Slice {
- op, _ := optype(t).(*Slice)
- return op
+func toSlice(t Type) *Slice {
+ u, _ := under(t).(*Slice)
+ return u
}
-func asStruct(t Type) *Struct {
- op, _ := optype(t).(*Struct)
- return op
+func toStruct(t Type) *Struct {
+ u, _ := under(t).(*Struct)
+ return u
}
-func asPointer(t Type) *Pointer {
- op, _ := optype(t).(*Pointer)
- return op
+func toPointer(t Type) *Pointer {
+ u, _ := under(t).(*Pointer)
+ return u
}
-func asSignature(t Type) *Signature {
- op, _ := optype(t).(*Signature)
- return op
+func toSignature(t Type) *Signature {
+ u, _ := under(t).(*Signature)
+ return u
}
-// If the argument to asInterface, asNamed, or asTypeParam is of the respective type
-// (possibly after expanding an instance type), these methods return that type.
-// Otherwise the result is nil.
-
-// asInterface does not need to look at optype (type sets don't contain interfaces)
-func asInterface(t Type) *Interface {
+func toInterface(t Type) *Interface {
u, _ := under(t).(*Interface)
return u
}
+// If the argument to asNamed, or asTypeParam is of the respective type
+// (possibly after expanding resolving a *Named type), these methods return that type.
+// Otherwise the result is nil.
+
func asNamed(t Type) *Named {
e, _ := t.(*Named)
if e != nil {
// Exported for the compiler.
-func AsPointer(t Type) *Pointer { return asPointer(t) }
+func AsPointer(t Type) *Pointer { return toPointer(t) }
func AsNamed(t Type) *Named { return asNamed(t) }
-func AsSignature(t Type) *Signature { return asSignature(t) }
-func AsInterface(t Type) *Interface { return asInterface(t) }
+func AsSignature(t Type) *Signature { return toSignature(t) }
+func AsInterface(t Type) *Interface { return toInterface(t) }
func AsTypeParam(t Type) *TypeParam { return asTypeParam(t) }
}
w.string(t.obj.name + subscript(t.id))
- case *top:
- w.error("⊤")
-
default:
// For externally defined implementations of Type.
// Note: In this case cycles won't be caught.
} else {
// special case:
// append(s, "foo"...) leads to signature func([]byte, string...)
- if t := asBasic(typ); t == nil || t.kind != String {
+ if t := toBasic(typ); t == nil || t.kind != String {
w.error("expected string type")
continue
}
func (check *Checker) varType(e syntax.Expr) Type {
typ := check.definedType(e, nil)
- // We don't want to call under() (via asInterface) or complete interfaces while we
+ // We don't want to call under() (via toInterface) or complete interfaces while we
// are in the middle of type-checking parameter declarations that might belong to
// interface methods. Delay this check to the end of type-checking.
check.later(func() {
- if t := asInterface(typ); t != nil {
+ if t := toInterface(typ); t != nil {
pos := syntax.StartPos(e)
tset := computeInterfaceTypeSet(check, pos, t) // TODO(gri) is this the correct position?
if !tset.IsMethodSet() {