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:
Robert Griesemer 2019-11-26 21:38:34 -08:00
parent 703974d608
commit 8c7ab48154
10 changed files with 37 additions and 190 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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,

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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?

View File

@ -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) }

View File

@ -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 {

View File

@ -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