mirror of https://github.com/golang/go.git
go/types: remove Parameterized type and related code
The need for the Parameterized type was eliminated by the prior commit. Change-Id: I8a2a2ae19ec5fef9292885fc7d23f8950d917e2f
This commit is contained in:
parent
703974d608
commit
8c7ab48154
|
|
@ -424,7 +424,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
// make(T, n, m)
|
||||
// (no argument evaluated yet)
|
||||
arg0 := call.Args[0]
|
||||
T := check.instantiatedType(arg0)
|
||||
T := check.typ(arg0)
|
||||
if T == Typ[Invalid] {
|
||||
return
|
||||
}
|
||||
|
|
@ -465,7 +465,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
case _New:
|
||||
// new(T)
|
||||
// (no argument evaluated yet)
|
||||
T := check.instantiatedType(call.Args[0])
|
||||
T := check.typ(call.Args[0])
|
||||
if T == Typ[Invalid] {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
// TODO(gri) This seems a bit subtle. Can we do better?
|
||||
if named, _ := T.(*Named); named != nil && named.obj != nil && named.obj.IsParameterized() && named.targs == nil {
|
||||
// type instantiation
|
||||
x.typ = check.instantiatedType(e)
|
||||
x.typ = check.typ(e)
|
||||
if x.typ != Typ[Invalid] {
|
||||
x.mode = typexpr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
|
|||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
t := check.instantiatedType(typ)
|
||||
t := check.typ(typ)
|
||||
if !isConstType(t) {
|
||||
// don't report an error if the type is an invalid C (defined) type
|
||||
// (issue #22090)
|
||||
|
|
@ -419,7 +419,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
|
|||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
obj.typ = check.instantiatedType(typ)
|
||||
obj.typ = check.typ(typ)
|
||||
// We cannot spread the type to all lhs variables if there
|
||||
// are more than one since that would mark them as checked
|
||||
// (see Checker.objDecl) and the assignment of init exprs,
|
||||
|
|
|
|||
|
|
@ -1044,7 +1044,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
}
|
||||
|
||||
case *ast.FuncLit:
|
||||
if sig, ok := check.instantiatedType(e.Type).(*Signature); ok {
|
||||
if sig, ok := check.typ(e.Type).(*Signature); ok {
|
||||
// Anonymous functions are considered part of the
|
||||
// init expression/func declaration which contains
|
||||
// them: use existing package-level declaration info.
|
||||
|
|
@ -1077,12 +1077,12 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
// We have an "open" [...]T array type.
|
||||
// Create a new ArrayType with unknown length (-1)
|
||||
// and finish setting it up after analyzing the literal.
|
||||
typ = &Array{len: -1, elem: check.instantiatedType(atyp.Elt)}
|
||||
typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
|
||||
base = typ
|
||||
break
|
||||
}
|
||||
}
|
||||
typ = check.instantiatedType(e.Type)
|
||||
typ = check.typ(e.Type)
|
||||
base = typ
|
||||
|
||||
case hint != nil:
|
||||
|
|
@ -1459,7 +1459,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
check.invalidAST(e.Pos(), "use of .(type) outside type switch")
|
||||
goto Error
|
||||
}
|
||||
T := check.instantiatedType(e.Type)
|
||||
T := check.typ(e.Type)
|
||||
if T == Typ[Invalid] {
|
||||
goto Error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,9 +159,6 @@ func isParameterized(typ Type, seen map[Type]bool) (res bool) {
|
|||
case *Chan:
|
||||
return isParameterized(t.elem, seen)
|
||||
|
||||
case *Parameterized:
|
||||
return isParameterizedList(t.targs, seen)
|
||||
|
||||
case *TypeParam:
|
||||
return true
|
||||
|
||||
|
|
|
|||
|
|
@ -360,12 +360,8 @@ func deref(typ Type) (Type, bool) {
|
|||
// and parameterized types.
|
||||
func derefUnpack(typ Type) (Type, bool) {
|
||||
typ, ptr := deref(typ)
|
||||
// TODO(gri) do we need to iterate/recurse here for unpacking?
|
||||
switch t := typ.(type) {
|
||||
case *Parameterized:
|
||||
typ = t.tname.typ
|
||||
case *TypeParam:
|
||||
typ = t.Interface()
|
||||
if tpar, _ := typ.(*TypeParam); tpar != nil {
|
||||
typ = tpar.Interface()
|
||||
}
|
||||
return typ, ptr
|
||||
}
|
||||
|
|
|
|||
|
|
@ -287,24 +287,6 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair, tparams
|
|||
return x.obj == y.obj
|
||||
}
|
||||
|
||||
case *Parameterized:
|
||||
// Two parameterized types are identical if the type name and the parameters are identical.
|
||||
// TODO(gri) This ignores alias types for now. E.g., type A(type P) = P; A(int) == int does
|
||||
// not work.
|
||||
if y, ok := y.(*Parameterized); ok {
|
||||
if x.tname != y.tname {
|
||||
return false
|
||||
}
|
||||
assert(len(x.targs) == len(y.targs)) // since x, y have identical tname
|
||||
for i, x := range x.targs {
|
||||
y := y.targs[i]
|
||||
if !check.identical0(x, y, cmpTags, p, tparams) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
case *TypeParam:
|
||||
if y, ok := y.(*TypeParam); ok {
|
||||
// TODO(gri) do we need to look at type names here?
|
||||
|
|
|
|||
|
|
@ -512,14 +512,6 @@ func (t *Named) AddMethod(m *Func) {
|
|||
}
|
||||
}
|
||||
|
||||
// A Parameterized represents a type name instantiated with type arguments;
|
||||
// e.g., myType(P, int) where P might be a (yet to be instantiated) type parameter.
|
||||
// A Parameterized is similar to an *ast.CallExpr, but for types.
|
||||
type Parameterized struct {
|
||||
tname *TypeName // instantiated type
|
||||
targs []Type // len(targs) == len(tname.tparams)
|
||||
}
|
||||
|
||||
// A Contract represents a contract.
|
||||
// TODO(gri) Do we need the ability to represent unnamed type parameter literals?
|
||||
// For instance, when creating (result) type parameters out of whole cloth
|
||||
|
|
@ -580,32 +572,30 @@ func (t *TypeParam) Interface() *Interface {
|
|||
|
||||
// Implementations for Type methods.
|
||||
|
||||
func (b *Basic) Underlying() Type { return b }
|
||||
func (a *Array) Underlying() Type { return a }
|
||||
func (s *Slice) Underlying() Type { return s }
|
||||
func (s *Struct) Underlying() Type { return s }
|
||||
func (p *Pointer) Underlying() Type { return p }
|
||||
func (t *Tuple) Underlying() Type { return t }
|
||||
func (s *Signature) Underlying() Type { return s }
|
||||
func (t *Interface) Underlying() Type { return t }
|
||||
func (m *Map) Underlying() Type { return m }
|
||||
func (c *Chan) Underlying() Type { return c }
|
||||
func (t *Named) Underlying() Type { return t.underlying }
|
||||
func (p *Parameterized) Underlying() Type { return p.tname.typ.Underlying() }
|
||||
func (c *Contract) Underlying() Type { return c }
|
||||
func (t *TypeParam) Underlying() Type { return t } // TODO(gri) should this return t.Interface() instead?
|
||||
func (b *Basic) Underlying() Type { return b }
|
||||
func (a *Array) Underlying() Type { return a }
|
||||
func (s *Slice) Underlying() Type { return s }
|
||||
func (s *Struct) Underlying() Type { return s }
|
||||
func (p *Pointer) Underlying() Type { return p }
|
||||
func (t *Tuple) Underlying() Type { return t }
|
||||
func (s *Signature) Underlying() Type { return s }
|
||||
func (t *Interface) Underlying() Type { return t }
|
||||
func (m *Map) Underlying() Type { return m }
|
||||
func (c *Chan) Underlying() Type { return c }
|
||||
func (t *Named) Underlying() Type { return t.underlying }
|
||||
func (c *Contract) Underlying() Type { return c }
|
||||
func (t *TypeParam) Underlying() Type { return t } // TODO(gri) should this return t.Interface() instead?
|
||||
|
||||
func (b *Basic) String() string { return TypeString(b, nil) }
|
||||
func (a *Array) String() string { return TypeString(a, nil) }
|
||||
func (s *Slice) String() string { return TypeString(s, nil) }
|
||||
func (s *Struct) String() string { return TypeString(s, nil) }
|
||||
func (p *Pointer) String() string { return TypeString(p, nil) }
|
||||
func (t *Tuple) String() string { return TypeString(t, nil) }
|
||||
func (s *Signature) String() string { return TypeString(s, nil) }
|
||||
func (t *Interface) String() string { return TypeString(t, nil) }
|
||||
func (m *Map) String() string { return TypeString(m, nil) }
|
||||
func (c *Chan) String() string { return TypeString(c, nil) }
|
||||
func (t *Named) String() string { return TypeString(t, nil) }
|
||||
func (p *Parameterized) String() string { return TypeString(p, nil) }
|
||||
func (c *Contract) String() string { return TypeString(c, nil) }
|
||||
func (t *TypeParam) String() string { return TypeString(t, nil) }
|
||||
func (b *Basic) String() string { return TypeString(b, nil) }
|
||||
func (a *Array) String() string { return TypeString(a, nil) }
|
||||
func (s *Slice) String() string { return TypeString(s, nil) }
|
||||
func (s *Struct) String() string { return TypeString(s, nil) }
|
||||
func (p *Pointer) String() string { return TypeString(p, nil) }
|
||||
func (t *Tuple) String() string { return TypeString(t, nil) }
|
||||
func (s *Signature) String() string { return TypeString(s, nil) }
|
||||
func (t *Interface) String() string { return TypeString(t, nil) }
|
||||
func (m *Map) String() string { return TypeString(m, nil) }
|
||||
func (c *Chan) String() string { return TypeString(c, nil) }
|
||||
func (t *Named) String() string { return TypeString(t, nil) }
|
||||
func (c *Contract) String() string { return TypeString(c, nil) }
|
||||
func (t *TypeParam) String() string { return TypeString(t, nil) }
|
||||
|
|
|
|||
|
|
@ -248,19 +248,6 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||
// buf.WriteByte(')')
|
||||
// }
|
||||
|
||||
case *Parameterized:
|
||||
writeTypeName(buf, t.tname, qf)
|
||||
if len(t.targs) > 0 {
|
||||
buf.WriteByte('(')
|
||||
for i, targ := range t.targs {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
writeType(buf, targ, qf, visited)
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
|
||||
case *Contract:
|
||||
buf.WriteString("contract(")
|
||||
for i, p := range t.TParams {
|
||||
|
|
|
|||
|
|
@ -142,24 +142,6 @@ func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) {
|
|||
return
|
||||
}
|
||||
|
||||
// instantiatedType is like typ but it ensures that a Parametrized type is
|
||||
// fully instantiated if all type parameters are known.
|
||||
// (When we type-check a parameterized function body, parameterized types
|
||||
// whose type parameters are incoming parameters cannot be instantiated.)
|
||||
func (check *Checker) instantiatedType(e ast.Expr) Type {
|
||||
typ := check.typ(e)
|
||||
// A parameterized type where all type arguments are known
|
||||
// (i.e., not type parameters themselves) can be instantiated.
|
||||
if ptyp, _ := typ.(*Parameterized); ptyp != nil && !IsParameterized(ptyp) {
|
||||
typ = check.instantiate2(e.Pos(), ptyp.tname.typ.(*Named), ptyp.targs)
|
||||
// TODO(gri) can this ever be nil? comment.
|
||||
if typ == nil {
|
||||
return Typ[Invalid] // error was reported by check.instatiate
|
||||
}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// funcType type-checks a function or method type.
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
|
||||
scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
|
||||
|
|
@ -190,11 +172,6 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
// (ignore invalid types - error was reported before)
|
||||
if t, _ := deref(recv.typ); t != Typ[Invalid] {
|
||||
var err string
|
||||
// TODO(gri) Unpacking a parameterized receiver here is a bit of a party trick
|
||||
// and probably not very robust. Rethink this code.
|
||||
if p, _ := t.(*Parameterized); p != nil {
|
||||
t = p.tname.typ
|
||||
}
|
||||
if T, _ := t.(*Named); 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
|
||||
|
|
@ -515,88 +492,6 @@ func (check *Checker) typeList(list []ast.Expr) []Type {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) bool {
|
||||
t := check.typ(e.Fun)
|
||||
if t == Typ[Invalid] {
|
||||
return false // error already reported
|
||||
}
|
||||
|
||||
named, _ := t.(*Named)
|
||||
if named == nil || named.obj == nil || !named.obj.IsParameterized() {
|
||||
check.errorf(e.Pos(), "%s is not a parametrized type", t)
|
||||
return false
|
||||
}
|
||||
|
||||
// the number of supplied types must match the number of type parameters
|
||||
// TODO(gri) fold into code below - we want to eval args always
|
||||
tname := named.obj
|
||||
if len(e.Args) != len(tname.tparams) {
|
||||
// TODO(gri) provide better error message
|
||||
check.errorf(e.Pos(), "got %d arguments but %d type parameters", len(e.Args), len(tname.tparams))
|
||||
return false
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
args := check.typeList(e.Args)
|
||||
if args == nil {
|
||||
return false
|
||||
}
|
||||
assert(len(args) == len(tname.tparams))
|
||||
|
||||
// substitute type bound parameters with arguments
|
||||
// and check if each argument satisfies its bound
|
||||
for i, tpar := range tname.tparams {
|
||||
pos := e.Args[i].Pos()
|
||||
pos = e.Pos() // TODO(gri) remove in favor of more accurate pos on prev. line?
|
||||
bound := tpar.typ.(*TypeParam).bound // interface or contract or nil
|
||||
switch b := bound.(type) {
|
||||
case nil:
|
||||
// nothing to do (no bound)
|
||||
case *Interface:
|
||||
iface := check.subst(e.Pos(), b, tname.tparams, args).(*Interface)
|
||||
check.satisfyBound(pos, tpar, args[i], iface)
|
||||
case *Contract:
|
||||
panic("unimplemented")
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO(gri) quick hack - clean this up
|
||||
// Also, it looks like contract should be part of the parameterized type,
|
||||
// not its individual type parameters, at least as long as we only permit
|
||||
// one contract. If we permit multiple contracts C1, C2 as in
|
||||
//
|
||||
// type _(type A, B C1, B C2, ...)
|
||||
//
|
||||
// the current approach may be the right one. The current approach also
|
||||
// lends itself more easily to a design where we just use interfaces
|
||||
// rather than contracts.
|
||||
/*
|
||||
assert(len(tname.tparams) > 0)
|
||||
bound := tname.tparams[0].typ.(*TypeParam).bound // TODO(gri) This is incorrect (index 0) in general. FIX THIS.
|
||||
switch b := bound.(type) {
|
||||
case nil:
|
||||
// nothing to do (no bound)
|
||||
case *Interface:
|
||||
panic("unimplemented")
|
||||
case *Contract:
|
||||
if !check.satisfyContract(b, args) {
|
||||
// TODO(gri) need to put in some work for really good error messages here
|
||||
check.errorf(e.Pos(), "contract for %s is not satisfied", tname)
|
||||
}
|
||||
default:
|
||||
unreachable()
|
||||
}
|
||||
*/
|
||||
|
||||
// complete parameterized type
|
||||
typ.tname = tname
|
||||
typ.targs = args
|
||||
return true
|
||||
}
|
||||
|
||||
func (check *Checker) satisfyBound(pos token.Pos, tname *TypeName, arg Type, bound *Interface) bool {
|
||||
// use interface type of type parameter, if any
|
||||
// targ must implement iface
|
||||
|
|
|
|||
Loading…
Reference in New Issue