diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 7d5e4849ab..c91bf04b21 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -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 } diff --git a/src/go/types/call.go b/src/go/types/call.go index f436ae1d14..b312c58946 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -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 } diff --git a/src/go/types/decl.go b/src/go/types/decl.go index b470bb3c34..f3a59bacb8 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -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, diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 82af084b78..5dd89e9cec 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -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 } diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 2d94cff7a6..e5fa2524ec 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -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 diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index bd1de7341f..a6c9edc35e 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -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 } diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index f01ea780d5..c00a1d0ab9 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -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? diff --git a/src/go/types/type.go b/src/go/types/type.go index 754c027bd6..c0ab698353 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -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) } diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go index dcb7a45f87..fc87377cef 100644 --- a/src/go/types/typestring.go +++ b/src/go/types/typestring.go @@ -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 { diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 0aee471de3..325ee3b429 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -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