mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] cmd/compile/internal/types2: remove Type.Under method in favor of function
This removes the need for the aType embedded type and brings the types2.Type API in sync with the go/types.Type API. For reasons not fully understood yet, introducing the new under function causes a very long initialization cycle error, which doesn't exist in go/types. For now, circumvent the problem through a helper function variable. This CL also eliminates superflous (former) Under() method calls inside optype calls (optype takes care of this). Plus some minor misc. cleanups and comment adjustments. Change-Id: I86e13ccf6f0b34d7496240ace61a1c84856b6033 Reviewed-on: https://go-review.googlesource.com/c/go/+/293470 Reviewed-by: Robert Findley <rfindley@google.com> Trust: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
653386a89a
commit
099374b55e
17 changed files with 111 additions and 148 deletions
|
|
@ -125,5 +125,4 @@ var predeclared = []types2.Type{
|
||||||
type anyType struct{}
|
type anyType struct{}
|
||||||
|
|
||||||
func (t anyType) Underlying() types2.Type { return t }
|
func (t anyType) Underlying() types2.Type { return t }
|
||||||
func (t anyType) Under() types2.Type { return t }
|
|
||||||
func (t anyType) String() string { return "any" }
|
func (t anyType) String() string { return "any" }
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
mode := invalid
|
mode := invalid
|
||||||
var typ Type
|
var typ Type
|
||||||
var val constant.Value
|
var val constant.Value
|
||||||
switch typ = implicitArrayDeref(optype(x.typ.Under())); t := typ.(type) {
|
switch typ = implicitArrayDeref(optype(x.typ)); t := typ.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(t) && id == _Len {
|
if isString(t) && id == _Len {
|
||||||
if x.mode == constant_ {
|
if x.mode == constant_ {
|
||||||
|
|
@ -178,7 +178,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
|
|
||||||
case *Sum:
|
case *Sum:
|
||||||
if t.is(func(t Type) bool {
|
if t.is(func(t Type) bool {
|
||||||
switch t := t.Under().(type) {
|
switch t := under(t).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(t) && id == _Len {
|
if isString(t) && id == _Len {
|
||||||
return true
|
return true
|
||||||
|
|
@ -330,7 +330,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var src Type
|
var src Type
|
||||||
switch t := optype(y.typ.Under()).(type) {
|
switch t := optype(y.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(y.typ) {
|
if isString(y.typ) {
|
||||||
src = universeByte
|
src = universeByte
|
||||||
|
|
@ -453,7 +453,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
var valid func(t Type) bool
|
var valid func(t Type) bool
|
||||||
valid = func(t Type) bool {
|
valid = func(t Type) bool {
|
||||||
var m int
|
var m int
|
||||||
switch t := optype(t.Under()).(type) {
|
switch t := optype(t).(type) {
|
||||||
case *Slice:
|
case *Slice:
|
||||||
m = 2
|
m = 2
|
||||||
case *Map, *Chan:
|
case *Map, *Chan:
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,8 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
|
|
||||||
// "x's type and T have identical underlying types if tags are ignored"
|
// "x's type and T have identical underlying types if tags are ignored"
|
||||||
V := x.typ
|
V := x.typ
|
||||||
Vu := V.Under()
|
Vu := under(V)
|
||||||
Tu := T.Under()
|
Tu := under(T)
|
||||||
if check.identicalIgnoreTags(Vu, Tu) {
|
if check.identicalIgnoreTags(Vu, Tu) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +100,7 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
|
||||||
// have identical underlying types if tags are ignored"
|
// have identical underlying types if tags are ignored"
|
||||||
if V, ok := V.(*Pointer); ok {
|
if V, ok := V.(*Pointer); ok {
|
||||||
if T, ok := T.(*Pointer); ok {
|
if T, ok := T.(*Pointer); ok {
|
||||||
if check.identicalIgnoreTags(V.base.Under(), T.base.Under()) {
|
if check.identicalIgnoreTags(under(V.base), under(T.base)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +146,7 @@ func isUintptr(typ Type) bool {
|
||||||
|
|
||||||
func isUnsafePointer(typ Type) bool {
|
func isUnsafePointer(typ Type) bool {
|
||||||
// TODO(gri): Is this asBasic(typ) instead of typ.(*Basic) correct?
|
// TODO(gri): Is this asBasic(typ) instead of typ.(*Basic) correct?
|
||||||
// (The former calls typ.Under(), while the latter doesn't.)
|
// (The former calls under(), while the latter doesn't.)
|
||||||
// The spec does not say so, but gc claims it is. See also
|
// The spec does not say so, but gc claims it is. See also
|
||||||
// issue 6326.
|
// issue 6326.
|
||||||
t := asBasic(typ)
|
t := asBasic(typ)
|
||||||
|
|
|
||||||
|
|
@ -445,7 +445,7 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited boo
|
||||||
if !isConstType(t) {
|
if !isConstType(t) {
|
||||||
// don't report an error if the type is an invalid C (defined) type
|
// don't report an error if the type is an invalid C (defined) type
|
||||||
// (issue #22090)
|
// (issue #22090)
|
||||||
if t.Under() != Typ[Invalid] {
|
if under(t) != Typ[Invalid] {
|
||||||
check.errorf(typ, "invalid constant type %s", t)
|
check.errorf(typ, "invalid constant type %s", t)
|
||||||
}
|
}
|
||||||
obj.typ = Typ[Invalid]
|
obj.typ = Typ[Invalid]
|
||||||
|
|
@ -545,13 +545,13 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
|
||||||
check.initVars(lhs, []syntax.Expr{init}, nopos)
|
check.initVars(lhs, []syntax.Expr{init}, nopos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Under returns the expanded underlying type of n0; possibly by following
|
// under returns the expanded underlying type of n0; possibly by following
|
||||||
// forward chains of named types. If an underlying type is found, resolve
|
// forward chains of named types. If an underlying type is found, resolve
|
||||||
// the chain by setting the underlying type for each defined type in the
|
// the chain by setting the underlying type for each defined type in the
|
||||||
// chain before returning it. If no underlying type is found or a cycle
|
// chain before returning it. If no underlying type is found or a cycle
|
||||||
// is detected, the result is Typ[Invalid]. If a cycle is detected and
|
// is detected, the result is Typ[Invalid]. If a cycle is detected and
|
||||||
// n0.check != nil, the cycle is reported.
|
// n0.check != nil, the cycle is reported.
|
||||||
func (n0 *Named) Under() Type {
|
func (n0 *Named) under() Type {
|
||||||
u := n0.underlying
|
u := n0.underlying
|
||||||
if u == nil {
|
if u == nil {
|
||||||
return Typ[Invalid]
|
return Typ[Invalid]
|
||||||
|
|
@ -584,6 +584,8 @@ func (n0 *Named) Under() Type {
|
||||||
|
|
||||||
if i, ok := seen[n]; ok {
|
if i, ok := seen[n]; ok {
|
||||||
// cycle
|
// cycle
|
||||||
|
// TODO(gri) revert this to a method on Checker. Having a possibly
|
||||||
|
// nil Checker on Named and TypeParam is too subtle.
|
||||||
if n0.check != nil {
|
if n0.check != nil {
|
||||||
n0.check.cycleError(path[i:])
|
n0.check.cycleError(path[i:])
|
||||||
}
|
}
|
||||||
|
|
@ -667,7 +669,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
|
||||||
// any forward chain.
|
// any forward chain.
|
||||||
// TODO(gri) Investigate if we can just use named.origin here
|
// TODO(gri) Investigate if we can just use named.origin here
|
||||||
// and rely on lazy computation of the underlying type.
|
// and rely on lazy computation of the underlying type.
|
||||||
named.underlying = named.Under()
|
named.underlying = under(named)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -716,7 +718,7 @@ func (check *Checker) collectTypeParams(list []*syntax.Field) (tparams []*TypeNa
|
||||||
// we may not have a complete interface yet:
|
// we may not have a complete interface yet:
|
||||||
// type C(type T C) interface {}
|
// type C(type T C) interface {}
|
||||||
// (issue #39724).
|
// (issue #39724).
|
||||||
if _, ok := bound.Under().(*Interface); ok {
|
if _, ok := under(bound).(*Interface); ok {
|
||||||
// set the type bounds
|
// set the type bounds
|
||||||
for i < j {
|
for i < j {
|
||||||
tparams[i].typ.(*TypeParam).bound = bound
|
tparams[i].typ.(*TypeParam).bound = bound
|
||||||
|
|
|
||||||
|
|
@ -656,7 +656,7 @@ func (check *Checker) convertUntypedInternal(x *operand, target Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// typed target
|
// typed target
|
||||||
switch t := optype(target.Under()).(type) {
|
switch t := optype(target).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if x.mode == constant_ {
|
if x.mode == constant_ {
|
||||||
check.representable(x, t)
|
check.representable(x, t)
|
||||||
|
|
@ -1258,7 +1258,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
case hint != nil:
|
case hint != nil:
|
||||||
// no composite literal type present - use hint (element type of enclosing type)
|
// no composite literal type present - use hint (element type of enclosing type)
|
||||||
typ = hint
|
typ = hint
|
||||||
base, _ = deref(typ.Under()) // *T implies &T{}
|
base, _ = deref(under(typ)) // *T implies &T{}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO(gri) provide better error messages depending on context
|
// TODO(gri) provide better error messages depending on context
|
||||||
|
|
@ -1266,7 +1266,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
|
|
||||||
switch utyp := optype(base.Under()).(type) {
|
switch utyp := optype(base).(type) {
|
||||||
case *Struct:
|
case *Struct:
|
||||||
if len(e.ElemList) == 0 {
|
if len(e.ElemList) == 0 {
|
||||||
break
|
break
|
||||||
|
|
@ -1475,7 +1475,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
// ordinary index expression
|
// ordinary index expression
|
||||||
valid := false
|
valid := false
|
||||||
length := int64(-1) // valid if >= 0
|
length := int64(-1) // valid if >= 0
|
||||||
switch typ := optype(x.typ.Under()).(type) {
|
switch typ := optype(x.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
valid = true
|
valid = true
|
||||||
|
|
@ -1528,7 +1528,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
nmaps := 0 // number of map types in sum type
|
nmaps := 0 // number of map types in sum type
|
||||||
if typ.is(func(t Type) bool {
|
if typ.is(func(t Type) bool {
|
||||||
var e Type
|
var e Type
|
||||||
switch t := t.Under().(type) {
|
switch t := under(t).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(t) {
|
if isString(t) {
|
||||||
e = universeByte
|
e = universeByte
|
||||||
|
|
@ -1637,7 +1637,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
|
|
||||||
valid := false
|
valid := false
|
||||||
length := int64(-1) // valid if >= 0
|
length := int64(-1) // valid if >= 0
|
||||||
switch typ := optype(x.typ.Under()).(type) {
|
switch typ := optype(x.typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
if e.Full {
|
if e.Full {
|
||||||
|
|
@ -1738,7 +1738,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
xtyp, _ := x.typ.Under().(*Interface)
|
xtyp, _ := under(x.typ).(*Interface)
|
||||||
if xtyp == nil {
|
if xtyp == nil {
|
||||||
check.errorf(x, "%s is not an interface type", x)
|
check.errorf(x, "%s is not an interface type", x)
|
||||||
goto Error
|
goto Error
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type) (types []Type, i
|
||||||
// Unify type parameters with their structural constraints, if any.
|
// Unify type parameters with their structural constraints, if any.
|
||||||
for _, tpar := range tparams {
|
for _, tpar := range tparams {
|
||||||
typ := tpar.typ.(*TypeParam)
|
typ := tpar.typ.(*TypeParam)
|
||||||
sbound := check.structuralType(typ.bound.Under())
|
sbound := check.structuralType(typ.bound)
|
||||||
if sbound != nil {
|
if sbound != nil {
|
||||||
if !u.unify(typ, sbound) {
|
if !u.unify(typ, sbound) {
|
||||||
check.errorf(tpar.pos, "%s does not match %s", tpar, sbound)
|
check.errorf(tpar.pos, "%s does not match %s", tpar, sbound)
|
||||||
|
|
@ -344,7 +344,7 @@ func (check *Checker) inferB(tparams []*TypeName, targs []Type) (types []Type, i
|
||||||
|
|
||||||
// structuralType returns the structural type of a constraint, if any.
|
// structuralType returns the structural type of a constraint, if any.
|
||||||
func (check *Checker) structuralType(constraint Type) Type {
|
func (check *Checker) structuralType(constraint Type) Type {
|
||||||
if iface, _ := constraint.(*Interface); iface != nil {
|
if iface, _ := under(constraint).(*Interface); iface != nil {
|
||||||
check.completeInterface(nopos, iface)
|
check.completeInterface(nopos, iface)
|
||||||
types := unpack(iface.allTypes)
|
types := unpack(iface.allTypes)
|
||||||
if len(types) == 1 {
|
if len(types) == 1 {
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ func (check *Checker) rawLookupFieldOrMethod(T Type, addressable bool, pkg *Pack
|
||||||
|
|
||||||
// continue with underlying type, but only if it's not a type parameter
|
// 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(gri) is this what we want to do for type parameters? (spec question)
|
||||||
typ = named.Under()
|
typ = under(named)
|
||||||
if asTypeParam(typ) != nil {
|
if asTypeParam(typ) != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -461,7 +461,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
||||||
if tname.IsAlias() {
|
if tname.IsAlias() {
|
||||||
buf.WriteString(" =")
|
buf.WriteString(" =")
|
||||||
} else {
|
} else {
|
||||||
typ = typ.Under()
|
typ = under(typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,8 +257,8 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
Vu := optype(V.Under())
|
Vu := optype(V)
|
||||||
Tu := optype(T.Under())
|
Tu := optype(T)
|
||||||
|
|
||||||
// x is an untyped value representable by a value of type T
|
// x is an untyped value representable by a value of type T
|
||||||
// TODO(gri) This is borrowing from checker.convertUntyped and
|
// TODO(gri) This is borrowing from checker.convertUntyped and
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ func isGeneric(typ Type) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func is(typ Type, what BasicInfo) bool {
|
func is(typ Type, what BasicInfo) bool {
|
||||||
switch t := optype(typ.Under()).(type) {
|
switch t := optype(typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
return t.info&what != 0
|
return t.info&what != 0
|
||||||
case *Sum:
|
case *Sum:
|
||||||
|
|
@ -73,7 +73,7 @@ func isOrdered(typ Type) bool { return is(typ, IsOrdered) }
|
||||||
|
|
||||||
func isConstType(typ Type) bool {
|
func isConstType(typ Type) bool {
|
||||||
// Type parameters are never const types.
|
// Type parameters are never const types.
|
||||||
t, _ := typ.Under().(*Basic)
|
t, _ := under(typ).(*Basic)
|
||||||
return t != nil && t.info&IsConstType != 0
|
return t != nil && t.info&IsConstType != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ func comparable(T Type, seen map[Type]bool) bool {
|
||||||
return t.Bound().IsComparable()
|
return t.Bound().IsComparable()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t := optype(T.Under()).(type) {
|
switch t := optype(T).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
// assume invalid types to be comparable
|
// assume invalid types to be comparable
|
||||||
// to avoid follow-up errors
|
// to avoid follow-up errors
|
||||||
|
|
@ -137,7 +137,7 @@ func comparable(T Type, seen map[Type]bool) bool {
|
||||||
|
|
||||||
// hasNil reports whether a type includes the nil value.
|
// hasNil reports whether a type includes the nil value.
|
||||||
func hasNil(typ Type) bool {
|
func hasNil(typ Type) bool {
|
||||||
switch t := optype(typ.Under()).(type) {
|
switch t := optype(typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
return t.kind == UnsafePointer
|
return t.kind == UnsafePointer
|
||||||
case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
|
case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ type StdSizes struct {
|
||||||
func (s *StdSizes) Alignof(T Type) int64 {
|
func (s *StdSizes) Alignof(T Type) int64 {
|
||||||
// For arrays and structs, alignment is defined in terms
|
// For arrays and structs, alignment is defined in terms
|
||||||
// of alignment of the elements and fields, respectively.
|
// of alignment of the elements and fields, respectively.
|
||||||
switch t := optype(T.Under()).(type) {
|
switch t := optype(T).(type) {
|
||||||
case *Array:
|
case *Array:
|
||||||
// spec: "For a variable x of array type: unsafe.Alignof(x)
|
// spec: "For a variable x of array type: unsafe.Alignof(x)
|
||||||
// is the same as unsafe.Alignof(x[0]), but at least 1."
|
// is the same as unsafe.Alignof(x[0]), but at least 1."
|
||||||
|
|
@ -118,7 +118,7 @@ var basicSizes = [...]byte{
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StdSizes) Sizeof(T Type) int64 {
|
func (s *StdSizes) Sizeof(T Type) int64 {
|
||||||
switch t := optype(T.Under()).(type) {
|
switch t := optype(T).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
assert(isTyped(T))
|
assert(isTyped(T))
|
||||||
k := t.kind
|
k := t.kind
|
||||||
|
|
|
||||||
|
|
@ -680,7 +680,7 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
|
||||||
if x.mode == invalid {
|
if x.mode == invalid {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
xtyp, _ := x.typ.Under().(*Interface)
|
xtyp, _ := under(x.typ).(*Interface)
|
||||||
if xtyp == nil {
|
if xtyp == nil {
|
||||||
check.errorf(&x, "%s is not an interface type", &x)
|
check.errorf(&x, "%s is not an interface type", &x)
|
||||||
return
|
return
|
||||||
|
|
@ -769,7 +769,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||||
// determine key/value types
|
// determine key/value types
|
||||||
var key, val Type
|
var key, val Type
|
||||||
if x.mode != invalid {
|
if x.mode != invalid {
|
||||||
typ := optype(x.typ.Under())
|
typ := optype(x.typ)
|
||||||
if _, ok := typ.(*Chan); ok && sValue != nil {
|
if _, ok := typ.(*Chan); ok && sValue != nil {
|
||||||
// TODO(gri) this also needs to happen for channels in generic variables
|
// TODO(gri) this also needs to happen for channels in generic variables
|
||||||
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
|
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
|
||||||
|
|
@ -906,7 +906,7 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
|
||||||
var key, val Type
|
var key, val Type
|
||||||
var msg string
|
var msg string
|
||||||
typ.is(func(t Type) bool {
|
typ.is(func(t Type) bool {
|
||||||
k, v, m := rangeKeyVal(t.Under(), wantKey, wantVal)
|
k, v, m := rangeKeyVal(under(t), wantKey, wantVal)
|
||||||
if k == nil || m != "" {
|
if k == nil || m != "" {
|
||||||
key, val, msg = k, v, m
|
key, val, msg = k, v, m
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
|
||||||
check.indent--
|
check.indent--
|
||||||
var under Type
|
var under Type
|
||||||
if res != nil {
|
if res != nil {
|
||||||
// Calling Under() here may lead to endless instantiations.
|
// Calling under() here may lead to endless instantiations.
|
||||||
// Test case: type T[P any] T[P]
|
// Test case: type T[P any] T[P]
|
||||||
// TODO(gri) investigate if that's a bug or to be expected.
|
// TODO(gri) investigate if that's a bug or to be expected.
|
||||||
under = res.Underlying()
|
under = res.Underlying()
|
||||||
|
|
@ -186,7 +186,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for _, t := range unpack(targBound.allTypes) {
|
for _, t := range unpack(targBound.allTypes) {
|
||||||
if !iface.isSatisfiedBy(t.Under()) {
|
if !iface.isSatisfiedBy(t) {
|
||||||
// TODO(gri) match this error message with the one below (or vice versa)
|
// TODO(gri) match this error message with the one below (or vice versa)
|
||||||
check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
|
check.softErrorf(pos, "%s does not satisfy %s (%s type constraint %s not found in %s)", targ, tpar.bound, targ, t, iface.allTypes)
|
||||||
break
|
break
|
||||||
|
|
@ -197,7 +197,7 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, poslis
|
||||||
|
|
||||||
// Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
|
// Otherwise, targ's type or underlying type must also be one of the interface types listed, if any.
|
||||||
if !iface.isSatisfiedBy(targ) {
|
if !iface.isSatisfiedBy(targ) {
|
||||||
check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, targ.Under(), iface.allTypes)
|
check.softErrorf(pos, "%s does not satisfy %s (%s not found in %s)", targ, tpar.bound, under(targ), iface.allTypes)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,24 +18,10 @@ type Type interface {
|
||||||
// client packages (here for backward-compatibility).
|
// client packages (here for backward-compatibility).
|
||||||
Underlying() Type
|
Underlying() Type
|
||||||
|
|
||||||
// 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
|
|
||||||
// to be fully set up.
|
|
||||||
Under() Type
|
|
||||||
|
|
||||||
// String returns a string representation of a type.
|
// String returns a string representation of a type.
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// aType implements default type behavior
|
|
||||||
type aType struct{}
|
|
||||||
|
|
||||||
// These methods must be implemented by each type.
|
|
||||||
func (aType) Underlying() Type { panic("unreachable") }
|
|
||||||
func (aType) Under() Type { panic("unreachable") }
|
|
||||||
func (aType) String() string { panic("unreachable") }
|
|
||||||
|
|
||||||
// BasicKind describes the kind of basic type.
|
// BasicKind describes the kind of basic type.
|
||||||
type BasicKind int
|
type BasicKind int
|
||||||
|
|
||||||
|
|
@ -99,7 +85,6 @@ type Basic struct {
|
||||||
kind BasicKind
|
kind BasicKind
|
||||||
info BasicInfo
|
info BasicInfo
|
||||||
name string
|
name string
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kind returns the kind of basic type b.
|
// Kind returns the kind of basic type b.
|
||||||
|
|
@ -115,7 +100,6 @@ func (b *Basic) Name() string { return b.name }
|
||||||
type Array struct {
|
type Array struct {
|
||||||
len int64
|
len int64
|
||||||
elem Type
|
elem Type
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewArray returns a new array type for the given element type and length.
|
// NewArray returns a new array type for the given element type and length.
|
||||||
|
|
@ -132,7 +116,6 @@ func (a *Array) Elem() Type { return a.elem }
|
||||||
// A Slice represents a slice type.
|
// A Slice represents a slice type.
|
||||||
type Slice struct {
|
type Slice struct {
|
||||||
elem Type
|
elem Type
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSlice returns a new slice type for the given element type.
|
// NewSlice returns a new slice type for the given element type.
|
||||||
|
|
@ -145,7 +128,6 @@ func (s *Slice) Elem() Type { return s.elem }
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
fields []*Var
|
fields []*Var
|
||||||
tags []string // field tags; nil if there are no tags
|
tags []string // field tags; nil if there are no tags
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStruct returns a new struct with the given fields and corresponding field tags.
|
// NewStruct returns a new struct with the given fields and corresponding field tags.
|
||||||
|
|
@ -182,7 +164,6 @@ func (s *Struct) Tag(i int) string {
|
||||||
// A Pointer represents a pointer type.
|
// A Pointer represents a pointer type.
|
||||||
type Pointer struct {
|
type Pointer struct {
|
||||||
base Type // element type
|
base Type // element type
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPointer returns a new pointer type for the given element (base) type.
|
// NewPointer returns a new pointer type for the given element (base) type.
|
||||||
|
|
@ -196,17 +177,15 @@ func (p *Pointer) Elem() Type { return p.base }
|
||||||
// assignments; they are not first class types of Go.
|
// assignments; they are not first class types of Go.
|
||||||
type Tuple struct {
|
type Tuple struct {
|
||||||
vars []*Var
|
vars []*Var
|
||||||
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.
|
// NewTuple returns a new tuple for the given variables.
|
||||||
func NewTuple(x ...*Var) *Tuple {
|
func NewTuple(x ...*Var) *Tuple {
|
||||||
if len(x) > 0 {
|
if len(x) > 0 {
|
||||||
return &Tuple{vars: x}
|
return &Tuple{vars: x}
|
||||||
}
|
}
|
||||||
|
// TODO(gri) Don't represent empty tuples with a (*Tuple)(nil) pointer;
|
||||||
|
// it's too subtle and causes problems.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,7 +214,6 @@ type Signature struct {
|
||||||
params *Tuple // (incoming) parameters from left to right; or nil
|
params *Tuple // (incoming) parameters from left to right; or nil
|
||||||
results *Tuple // (outgoing) results from left to right; or nil
|
results *Tuple // (outgoing) results from left to right; or nil
|
||||||
variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only)
|
variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only)
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSignature returns a new function type for the given receiver, parameters,
|
// NewSignature returns a new function type for the given receiver, parameters,
|
||||||
|
|
@ -284,7 +262,6 @@ func (s *Signature) Variadic() bool { return s.variadic }
|
||||||
// first class types of Go.
|
// first class types of Go.
|
||||||
type Sum struct {
|
type Sum struct {
|
||||||
types []Type // types are unique
|
types []Type // types are unique
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSum returns a new Sum type consisting of the provided
|
// NewSum returns a new Sum type consisting of the provided
|
||||||
|
|
@ -336,8 +313,6 @@ type Interface struct {
|
||||||
allTypes Type // intersection of all embedded and locally declared types (TODO(gri) need better field name)
|
allTypes Type // intersection of all embedded and locally declared types (TODO(gri) need better field name)
|
||||||
|
|
||||||
obj Object // type declaration defining this interface; or nil (for better error messages)
|
obj Object // type declaration defining this interface; or nil (for better error messages)
|
||||||
|
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unpack unpacks a type into a list of types.
|
// unpack unpacks a type into a list of types.
|
||||||
|
|
@ -468,10 +443,7 @@ func (t *Interface) Empty() bool {
|
||||||
return len(t.allMethods) == 0 && t.allTypes == nil
|
return len(t.allMethods) == 0 && t.allTypes == nil
|
||||||
}
|
}
|
||||||
return !t.iterate(func(t *Interface) bool {
|
return !t.iterate(func(t *Interface) bool {
|
||||||
if len(t.methods) > 0 || t.types != nil {
|
return len(t.methods) > 0 || t.types != nil
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -483,10 +455,7 @@ func (t *Interface) HasTypeList() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.iterate(func(t *Interface) bool {
|
return t.iterate(func(t *Interface) bool {
|
||||||
if t.types != nil {
|
return t.types != nil
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -560,7 +529,7 @@ func (t *Interface) isSatisfiedBy(typ Type) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
types := unpack(t.allTypes)
|
types := unpack(t.allTypes)
|
||||||
return includes(types, typ) || includes(types, typ.Under())
|
return includes(types, typ) || includes(types, under(typ))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete computes the interface's method set. It must be called by users of
|
// Complete computes the interface's method set. It must be called by users of
|
||||||
|
|
@ -598,7 +567,7 @@ func (t *Interface) Complete() *Interface {
|
||||||
allTypes := t.types
|
allTypes := t.types
|
||||||
|
|
||||||
for _, typ := range t.embeddeds {
|
for _, typ := range t.embeddeds {
|
||||||
utyp := typ.Under()
|
utyp := under(typ)
|
||||||
etyp := asInterface(utyp)
|
etyp := asInterface(utyp)
|
||||||
if etyp == nil {
|
if etyp == nil {
|
||||||
if utyp != Typ[Invalid] {
|
if utyp != Typ[Invalid] {
|
||||||
|
|
@ -633,7 +602,6 @@ func (t *Interface) Complete() *Interface {
|
||||||
// A Map represents a map type.
|
// A Map represents a map type.
|
||||||
type Map struct {
|
type Map struct {
|
||||||
key, elem Type
|
key, elem Type
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMap returns a new map for the given key and element types.
|
// NewMap returns a new map for the given key and element types.
|
||||||
|
|
@ -651,7 +619,6 @@ func (m *Map) Elem() Type { return m.elem }
|
||||||
type Chan struct {
|
type Chan struct {
|
||||||
dir ChanDir
|
dir ChanDir
|
||||||
elem Type
|
elem Type
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A ChanDir value indicates a channel direction.
|
// A ChanDir value indicates a channel direction.
|
||||||
|
|
@ -677,7 +644,7 @@ func (c *Chan) Elem() Type { return c.elem }
|
||||||
|
|
||||||
// A Named represents a named (defined) type.
|
// A Named represents a named (defined) type.
|
||||||
type Named struct {
|
type Named struct {
|
||||||
check *Checker // for Named.Under implementation
|
check *Checker // for Named.under implementation
|
||||||
info typeInfo // for cycle detection
|
info typeInfo // for cycle detection
|
||||||
obj *TypeName // corresponding declared object
|
obj *TypeName // corresponding declared object
|
||||||
orig Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
|
orig Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
|
||||||
|
|
@ -685,7 +652,6 @@ type Named struct {
|
||||||
tparams []*TypeName // type parameters, or nil
|
tparams []*TypeName // type parameters, or nil
|
||||||
targs []Type // type arguments (after instantiation), or nil
|
targs []Type // type arguments (after instantiation), or nil
|
||||||
methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
|
methods []*Func // methods declared for this type (not the method set of this type); signatures are type-checked lazily
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
|
// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
|
||||||
|
|
@ -757,7 +723,6 @@ type TypeParam struct {
|
||||||
obj *TypeName // corresponding type name
|
obj *TypeName // corresponding type name
|
||||||
index int // parameter index
|
index int // parameter index
|
||||||
bound Type // *Named or *Interface; underlying type is always *Interface
|
bound Type // *Named or *Interface; underlying type is always *Interface
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TypeParam) Obj() *TypeName {
|
func (t *TypeParam) Obj() *TypeName {
|
||||||
|
|
@ -788,7 +753,7 @@ func (t *TypeParam) Bound() *Interface {
|
||||||
|
|
||||||
// optype returns a type's operational type. Except for
|
// optype returns a type's operational type. Except for
|
||||||
// type parameters, the operational type is the same
|
// type parameters, the operational type is the same
|
||||||
// as the underlying type (as returned by Under). For
|
// as the underlying type (as returned by under). For
|
||||||
// Type parameters, the operational type is determined
|
// Type parameters, the operational type is determined
|
||||||
// by the corresponding type bound's type list. The
|
// by the corresponding type bound's type list. The
|
||||||
// result may be the bottom or top type, but it is never
|
// result may be the bottom or top type, but it is never
|
||||||
|
|
@ -802,12 +767,12 @@ func optype(typ Type) Type {
|
||||||
// (type T interface { type T }).
|
// (type T interface { type T }).
|
||||||
// See also issue #39680.
|
// See also issue #39680.
|
||||||
if u := t.Bound().allTypes; u != nil && u != typ {
|
if u := t.Bound().allTypes; u != nil && u != typ {
|
||||||
// u != typ and u is a type parameter => u.Under() != typ, so this is ok
|
// u != typ and u is a type parameter => under(u) != typ, so this is ok
|
||||||
return u.Under()
|
return under(u)
|
||||||
}
|
}
|
||||||
return theTop
|
return theTop
|
||||||
}
|
}
|
||||||
return typ.Under()
|
return under(typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// An instance represents an instantiated generic type syntactically
|
// An instance represents an instantiated generic type syntactically
|
||||||
|
|
@ -821,7 +786,6 @@ type instance struct {
|
||||||
targs []Type // type arguments
|
targs []Type // type arguments
|
||||||
poslist []syntax.Pos // position of each targ; for error reporting only
|
poslist []syntax.Pos // position of each targ; for error reporting only
|
||||||
value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set
|
value Type // base(targs...) after instantiation or Typ[Invalid]; nil if not yet set
|
||||||
aType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// expand returns the instantiated (= expanded) type of t.
|
// expand returns the instantiated (= expanded) type of t.
|
||||||
|
|
@ -863,9 +827,7 @@ func init() { expandf = expand }
|
||||||
// It is the underlying type of a type parameter that
|
// It is the underlying type of a type parameter that
|
||||||
// cannot be satisfied by any type, usually because
|
// cannot be satisfied by any type, usually because
|
||||||
// the intersection of type constraints left nothing).
|
// the intersection of type constraints left nothing).
|
||||||
type bottom struct {
|
type bottom struct{}
|
||||||
aType
|
|
||||||
}
|
|
||||||
|
|
||||||
// theBottom is the singleton bottom type.
|
// theBottom is the singleton bottom type.
|
||||||
var theBottom = &bottom{}
|
var theBottom = &bottom{}
|
||||||
|
|
@ -875,9 +837,7 @@ var theBottom = &bottom{}
|
||||||
// can be satisfied by any type (ignoring methods),
|
// can be satisfied by any type (ignoring methods),
|
||||||
// usually because the type constraint has no type
|
// usually because the type constraint has no type
|
||||||
// list.
|
// list.
|
||||||
type top struct {
|
type top struct{}
|
||||||
aType
|
|
||||||
}
|
|
||||||
|
|
||||||
// theTop is the singleton top type.
|
// theTop is the singleton top type.
|
||||||
var theTop = &top{}
|
var theTop = &top{}
|
||||||
|
|
@ -900,25 +860,6 @@ func (t *instance) Underlying() Type { return t }
|
||||||
func (t *bottom) Underlying() Type { return t }
|
func (t *bottom) Underlying() Type { return t }
|
||||||
func (t *top) Underlying() Type { return t }
|
func (t *top) Underlying() Type { return t }
|
||||||
|
|
||||||
// Type-specific implementations of Under.
|
|
||||||
func (t *Basic) Under() Type { return t }
|
|
||||||
func (t *Array) Under() Type { return t }
|
|
||||||
func (t *Slice) Under() Type { return t }
|
|
||||||
func (t *Struct) Under() Type { return t }
|
|
||||||
func (t *Pointer) Under() Type { return t }
|
|
||||||
func (t *Tuple) Under() Type { return t }
|
|
||||||
func (t *Signature) Under() Type { return t }
|
|
||||||
func (t *Sum) Under() Type { return t } // TODO(gri) is this correct?
|
|
||||||
func (t *Interface) Under() Type { return t }
|
|
||||||
func (t *Map) Under() Type { return t }
|
|
||||||
func (t *Chan) Under() Type { return t }
|
|
||||||
|
|
||||||
// see decl.go for implementation of Named.Under
|
|
||||||
func (t *TypeParam) Under() Type { return t }
|
|
||||||
func (t *instance) Under() Type { return t.expand().Under() }
|
|
||||||
func (t *bottom) Under() Type { return t }
|
|
||||||
func (t *top) Under() Type { return t }
|
|
||||||
|
|
||||||
// Type-specific implementations of String.
|
// Type-specific implementations of String.
|
||||||
func (t *Basic) String() string { return TypeString(t, nil) }
|
func (t *Basic) String() string { return TypeString(t, nil) }
|
||||||
func (t *Array) String() string { return TypeString(t, nil) }
|
func (t *Array) String() string { return TypeString(t, nil) }
|
||||||
|
|
@ -937,6 +878,27 @@ func (t *instance) String() string { return TypeString(t, nil) }
|
||||||
func (t *bottom) String() string { return TypeString(t, nil) }
|
func (t *bottom) String() string { return TypeString(t, nil) }
|
||||||
func (t *top) String() string { return TypeString(t, nil) }
|
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
|
||||||
|
// to be fully set up.
|
||||||
|
//
|
||||||
|
// under is set to underf to avoid an initialization cycle.
|
||||||
|
// TODO(gri) this doesn't happen in go/types - investigate
|
||||||
|
var under func(Type) Type
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
under = underf
|
||||||
|
}
|
||||||
|
|
||||||
|
func underf(t Type) Type {
|
||||||
|
// TODO(gri) is this correct for *Sum?
|
||||||
|
if n := asNamed(t); n != nil {
|
||||||
|
return n.under()
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// Converters
|
// Converters
|
||||||
//
|
//
|
||||||
// A converter must only be called when a type is
|
// A converter must only be called when a type is
|
||||||
|
|
@ -1007,6 +969,6 @@ func asNamed(t Type) *Named {
|
||||||
}
|
}
|
||||||
|
|
||||||
func asTypeParam(t Type) *TypeParam {
|
func asTypeParam(t Type) *TypeParam {
|
||||||
u, _ := t.Under().(*TypeParam)
|
u, _ := under(t).(*TypeParam)
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ func (check *Checker) varType(e syntax.Expr) Type {
|
||||||
// ordinaryType reports an error if typ is an interface type containing
|
// ordinaryType reports an error if typ is an interface type containing
|
||||||
// type lists or is (or embeds) the predeclared type comparable.
|
// type lists or is (or embeds) the predeclared type comparable.
|
||||||
func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
|
func (check *Checker) ordinaryType(pos syntax.Pos, typ Type) {
|
||||||
// We don't want to call Under() (via Interface) or complete interfaces while we
|
// We don't want to call under() (via Interface) or complete interfaces while we
|
||||||
// are in the middle of type-checking parameter declarations that might belong to
|
// are in the middle of type-checking parameter declarations that might belong to
|
||||||
// interface methods. Delay this check to the end of type-checking.
|
// interface methods. Delay this check to the end of type-checking.
|
||||||
check.atEnd(func() {
|
check.atEnd(func() {
|
||||||
|
|
@ -393,7 +393,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
|
||||||
err = ""
|
err = ""
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch u := optype(T.Under()).(type) {
|
switch u := optype(T).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
// unsafe.Pointer is treated like a regular pointer
|
// unsafe.Pointer is treated like a regular pointer
|
||||||
if u.kind == UnsafePointer {
|
if u.kind == UnsafePointer {
|
||||||
|
|
@ -442,7 +442,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
|
||||||
check.indent--
|
check.indent--
|
||||||
var under Type
|
var under Type
|
||||||
if T != nil {
|
if T != nil {
|
||||||
// Calling Under() here may lead to endless instantiations.
|
// Calling under() here may lead to endless instantiations.
|
||||||
// Test case: type T[P any] *T[P]
|
// Test case: type T[P any] *T[P]
|
||||||
// TODO(gri) investigate if that's a bug or to be expected
|
// TODO(gri) investigate if that's a bug or to be expected
|
||||||
// (see also analogous comment in Checker.instantiate).
|
// (see also analogous comment in Checker.instantiate).
|
||||||
|
|
@ -967,7 +967,7 @@ func (check *Checker) completeInterface(pos syntax.Pos, ityp *Interface) {
|
||||||
posList := check.posMap[ityp]
|
posList := check.posMap[ityp]
|
||||||
for i, typ := range ityp.embeddeds {
|
for i, typ := range ityp.embeddeds {
|
||||||
pos := posList[i] // embedding position
|
pos := posList[i] // embedding position
|
||||||
utyp := typ.Under()
|
utyp := under(typ)
|
||||||
etyp := asInterface(utyp)
|
etyp := asInterface(utyp)
|
||||||
if etyp == nil {
|
if etyp == nil {
|
||||||
if utyp != Typ[Invalid] {
|
if utyp != Typ[Invalid] {
|
||||||
|
|
@ -1159,12 +1159,12 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
|
||||||
// Because we have a name, typ must be of the form T or *T, where T is the name
|
// Because we have a name, typ must be of the form T or *T, where T is the name
|
||||||
// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
|
// of a (named or alias) type, and t (= deref(typ)) must be the type of T.
|
||||||
// We must delay this check to the end because we don't want to instantiate
|
// We must delay this check to the end because we don't want to instantiate
|
||||||
// (via t.Under()) a possibly incomplete type.
|
// (via under(t)) a possibly incomplete type.
|
||||||
embeddedTyp := typ // for closure below
|
embeddedTyp := typ // for closure below
|
||||||
embeddedPos := pos
|
embeddedPos := pos
|
||||||
check.atEnd(func() {
|
check.atEnd(func() {
|
||||||
t, isPtr := deref(embeddedTyp)
|
t, isPtr := deref(embeddedTyp)
|
||||||
switch t := optype(t.Under()).(type) {
|
switch t := optype(t).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if t == Typ[Invalid] {
|
if t == Typ[Invalid] {
|
||||||
// error was reported before
|
// error was reported before
|
||||||
|
|
|
||||||
|
|
@ -215,9 +215,9 @@ func (u *unifier) nify(x, y Type, p *ifacePair) bool {
|
||||||
// want *Named types.)
|
// want *Named types.)
|
||||||
switch {
|
switch {
|
||||||
case !isNamed(x) && y != nil && asNamed(y) != nil:
|
case !isNamed(x) && y != nil && asNamed(y) != nil:
|
||||||
return u.nify(x, y.Under(), p)
|
return u.nify(x, under(y), p)
|
||||||
case x != nil && asNamed(x) != nil && !isNamed(y):
|
case x != nil && asNamed(x) != nil && !isNamed(y):
|
||||||
return u.nify(x.Under(), y, p)
|
return u.nify(under(x), y, p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,39 +34,39 @@ var (
|
||||||
// Use Universe.Lookup("byte").Type() to obtain the specific
|
// Use Universe.Lookup("byte").Type() to obtain the specific
|
||||||
// alias basic type named "byte" (and analogous for "rune").
|
// alias basic type named "byte" (and analogous for "rune").
|
||||||
var Typ = [...]*Basic{
|
var Typ = [...]*Basic{
|
||||||
Invalid: {Invalid, 0, "invalid type", aType{}},
|
Invalid: {Invalid, 0, "invalid type"},
|
||||||
|
|
||||||
Bool: {Bool, IsBoolean, "bool", aType{}},
|
Bool: {Bool, IsBoolean, "bool"},
|
||||||
Int: {Int, IsInteger, "int", aType{}},
|
Int: {Int, IsInteger, "int"},
|
||||||
Int8: {Int8, IsInteger, "int8", aType{}},
|
Int8: {Int8, IsInteger, "int8"},
|
||||||
Int16: {Int16, IsInteger, "int16", aType{}},
|
Int16: {Int16, IsInteger, "int16"},
|
||||||
Int32: {Int32, IsInteger, "int32", aType{}},
|
Int32: {Int32, IsInteger, "int32"},
|
||||||
Int64: {Int64, IsInteger, "int64", aType{}},
|
Int64: {Int64, IsInteger, "int64"},
|
||||||
Uint: {Uint, IsInteger | IsUnsigned, "uint", aType{}},
|
Uint: {Uint, IsInteger | IsUnsigned, "uint"},
|
||||||
Uint8: {Uint8, IsInteger | IsUnsigned, "uint8", aType{}},
|
Uint8: {Uint8, IsInteger | IsUnsigned, "uint8"},
|
||||||
Uint16: {Uint16, IsInteger | IsUnsigned, "uint16", aType{}},
|
Uint16: {Uint16, IsInteger | IsUnsigned, "uint16"},
|
||||||
Uint32: {Uint32, IsInteger | IsUnsigned, "uint32", aType{}},
|
Uint32: {Uint32, IsInteger | IsUnsigned, "uint32"},
|
||||||
Uint64: {Uint64, IsInteger | IsUnsigned, "uint64", aType{}},
|
Uint64: {Uint64, IsInteger | IsUnsigned, "uint64"},
|
||||||
Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr", aType{}},
|
Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr"},
|
||||||
Float32: {Float32, IsFloat, "float32", aType{}},
|
Float32: {Float32, IsFloat, "float32"},
|
||||||
Float64: {Float64, IsFloat, "float64", aType{}},
|
Float64: {Float64, IsFloat, "float64"},
|
||||||
Complex64: {Complex64, IsComplex, "complex64", aType{}},
|
Complex64: {Complex64, IsComplex, "complex64"},
|
||||||
Complex128: {Complex128, IsComplex, "complex128", aType{}},
|
Complex128: {Complex128, IsComplex, "complex128"},
|
||||||
String: {String, IsString, "string", aType{}},
|
String: {String, IsString, "string"},
|
||||||
UnsafePointer: {UnsafePointer, 0, "Pointer", aType{}},
|
UnsafePointer: {UnsafePointer, 0, "Pointer"},
|
||||||
|
|
||||||
UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool", aType{}},
|
UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
|
||||||
UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int", aType{}},
|
UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int"},
|
||||||
UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune", aType{}},
|
UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
|
||||||
UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float", aType{}},
|
UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
|
||||||
UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex", aType{}},
|
UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
|
||||||
UntypedString: {UntypedString, IsString | IsUntyped, "untyped string", aType{}},
|
UntypedString: {UntypedString, IsString | IsUntyped, "untyped string"},
|
||||||
UntypedNil: {UntypedNil, IsUntyped, "untyped nil", aType{}},
|
UntypedNil: {UntypedNil, IsUntyped, "untyped nil"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var aliases = [...]*Basic{
|
var aliases = [...]*Basic{
|
||||||
{Byte, IsInteger | IsUnsigned, "byte", aType{}},
|
{Byte, IsInteger | IsUnsigned, "byte"},
|
||||||
{Rune, IsInteger, "rune", aType{}},
|
{Rune, IsInteger, "rune"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func defPredeclaredTypes() {
|
func defPredeclaredTypes() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue