mirror of https://github.com/golang/go.git
go/types: significant steps towards complete parametrized type instantiation
testdata/typeinst2.go has some complex examples that pass now. But code elsewhere seems broken. go test has some issues at the moment. Committing anyway to not lose the snapshot. Change-Id: Id8f753a7b098405e2580a45ca1707ef6476c198e
This commit is contained in:
parent
a76283d6e4
commit
52934f1b1e
|
|
@ -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.typ(arg0)
|
||||
T := check.instantiatedType(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.typ(call.Args[0])
|
||||
T := check.instantiatedType(call.Args[0])
|
||||
if T == Typ[Invalid] {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,19 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
return statement
|
||||
|
||||
case typexpr:
|
||||
// conversion
|
||||
// conversion or type instantiation
|
||||
T := x.typ
|
||||
x.mode = invalid
|
||||
if named, _ := T.(*Named); named != nil && named.obj != nil && named.obj.IsParametrized() {
|
||||
// type instantiation
|
||||
x.typ = check.instantiatedType(e)
|
||||
if x.typ != Typ[Invalid] {
|
||||
x.mode = typexpr
|
||||
}
|
||||
return expression
|
||||
}
|
||||
|
||||
// conversion
|
||||
switch n := len(e.Args); n {
|
||||
case 0:
|
||||
check.errorf(e.Rparen, "missing argument in conversion to %s", T)
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ var tests = [][]string{
|
|||
// Go 2 tests (type parameters and contracts)
|
||||
{"testdata/typeparams.go2"},
|
||||
{"testdata/typeinst.go2"},
|
||||
{"testdata/typeinst2.go2"},
|
||||
{"testdata/contracts.go2"},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
|
|||
|
||||
// determine type, if any
|
||||
if typ != nil {
|
||||
t := check.typ(typ)
|
||||
t := check.instantiatedType(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.typ(typ)
|
||||
obj.typ = check.instantiatedType(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,
|
||||
|
|
@ -584,6 +584,8 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
|||
|
||||
}
|
||||
|
||||
// this must happen before addMethodDecls - cannot use defer
|
||||
// TODO(gri) consider refactoring this
|
||||
if obj.IsParametrized() {
|
||||
check.closeScope()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1044,7 +1044,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
}
|
||||
|
||||
case *ast.FuncLit:
|
||||
if sig, ok := check.typ(e.Type).(*Signature); ok {
|
||||
if sig, ok := check.instantiatedType(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.typ(atyp.Elt)}
|
||||
typ = &Array{len: -1, elem: check.instantiatedType(atyp.Elt)}
|
||||
base = typ
|
||||
break
|
||||
}
|
||||
}
|
||||
typ = check.typ(e.Type)
|
||||
typ = check.instantiatedType(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.typ(e.Type)
|
||||
T := check.instantiatedType(e.Type)
|
||||
if T == Typ[Invalid] {
|
||||
goto Error
|
||||
}
|
||||
|
|
@ -1515,7 +1515,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
|
|||
case *ast.ArrayType, *ast.StructType, *ast.FuncType,
|
||||
*ast.InterfaceType, *ast.MapType, *ast.ChanType, *ast.ContractType:
|
||||
x.mode = typexpr
|
||||
x.typ = check.typ(e)
|
||||
x.typ = check.typ(e) // TODO(gri) should this be check.instantiatedType?
|
||||
// Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
|
||||
// even though check.typ has already called it. This is fine as both
|
||||
// times the same expression and type are recorded. It is also not a
|
||||
|
|
|
|||
|
|
@ -257,6 +257,17 @@ func (obj *TypeName) IsAlias() bool {
|
|||
}
|
||||
}
|
||||
|
||||
// TypeParams returns the list if *TypeParam types for the type parameters of obj; or nil.
|
||||
func (obj *TypeName) TypeParams() (tparams []*TypeParam) {
|
||||
if n := len(obj.tparams); n > 0 {
|
||||
tparams = make([]*TypeParam, n)
|
||||
for i, tpar := range obj.tparams {
|
||||
tparams[i] = tpar.typ.(*TypeParam)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// A Variable represents a declared variable (including function parameters and results, and struct fields).
|
||||
type Var struct {
|
||||
object
|
||||
|
|
|
|||
|
|
@ -307,6 +307,9 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair, tparams
|
|||
return x.obj == y.obj
|
||||
}
|
||||
|
||||
case *Parameterized:
|
||||
panic("internal error: cannot compare uninstantiated parametrized types for identity")
|
||||
|
||||
case *TypeParam:
|
||||
if y, ok := y.(*TypeParam); ok {
|
||||
// TODO(gri) do we need to look at type names here?
|
||||
|
|
|
|||
|
|
@ -113,6 +113,15 @@ func (s *subster) typ(typ Type) (res Type) {
|
|||
return tname.typ
|
||||
}
|
||||
|
||||
case *Parameterized:
|
||||
// first, instantiate any arguments if necessary
|
||||
targs := make([]Type, len(t.targs))
|
||||
for i, a := range t.targs {
|
||||
targs[i] = s.typ(a) // TODO(gri) fix this
|
||||
}
|
||||
// then instantiate t
|
||||
return s.check.subst(t.tname.typ, targs)
|
||||
|
||||
case *TypeParam:
|
||||
// TODO(gri) do we need to check that we're using the correct targs list/index?
|
||||
if targ := s.targs[t.index]; targ != nil {
|
||||
|
|
@ -169,13 +178,13 @@ func (s *subster) varList(in []*Var) (out []*Var, copied bool) {
|
|||
|
||||
func typesString(targs []Type) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteByte('(')
|
||||
buf.WriteByte('<')
|
||||
for i, arg := range targs {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(TypeString(arg, nil))
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
buf.WriteByte('>')
|
||||
return buf.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
type List(type E) []E
|
||||
var _ List(List(List(int)))
|
||||
// var _ List(List(List(int))) = [](List(List(int))){}
|
||||
|
||||
type (
|
||||
T1(type P1) struct {
|
||||
f1 T2(P1, float32)
|
||||
}
|
||||
|
||||
T2(type P2, P3) struct {
|
||||
f2 P2
|
||||
f3 P3
|
||||
}
|
||||
)
|
||||
|
||||
func _() {
|
||||
var x1 T1(int)
|
||||
var x2 T2(int, float32)
|
||||
|
||||
x1.f1.f2 = 0
|
||||
x1.f1 = x2
|
||||
}
|
||||
|
||||
// type T3(type P) T1(T2(P, P))
|
||||
|
||||
func _() {
|
||||
//var x1 T3(int)
|
||||
//var x2 T2
|
||||
//x1.f1.f2.f2 = 0
|
||||
}
|
||||
|
|
@ -447,7 +447,7 @@ func (c *Chan) Dir() ChanDir { return c.dir }
|
|||
// Elem returns the element type of channel c.
|
||||
func (c *Chan) Elem() Type { return c.elem }
|
||||
|
||||
// A Named represents a named type.
|
||||
// A Named represents a named (defined) type.
|
||||
type Named struct {
|
||||
info typeInfo // for cycle detection
|
||||
obj *TypeName // corresponding declared object
|
||||
|
|
@ -497,6 +497,14 @@ 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.
|
||||
type Contract struct {
|
||||
TParams []*TypeName
|
||||
|
|
@ -537,30 +545,32 @@ func NewTypeParam(obj *TypeName, index int) *TypeParam {
|
|||
|
||||
// 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 (c *Contract) Underlying() Type { return c }
|
||||
func (c *TypeParam) Underlying() Type { return c }
|
||||
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 } // TODO(gri) is this correct?
|
||||
func (c *Contract) Underlying() Type { return c }
|
||||
func (c *TypeParam) Underlying() Type { return c }
|
||||
|
||||
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 (c *TypeParam) String() string { return TypeString(c, 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 (p *Parameterized) String() string { return TypeString(p, nil) }
|
||||
func (c *Contract) String() string { return TypeString(c, nil) }
|
||||
func (c *TypeParam) String() string { return TypeString(c, nil) }
|
||||
|
|
|
|||
|
|
@ -235,17 +235,30 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||
}
|
||||
|
||||
case *Named:
|
||||
s := "<Named w/o object>"
|
||||
if obj := t.obj; obj != nil {
|
||||
if obj.pkg != nil {
|
||||
writePackage(buf, obj.pkg, qf)
|
||||
writeTypeName(buf, t.obj, qf)
|
||||
if t.obj != nil && len(t.obj.tparams) > 0 {
|
||||
buf.WriteByte('(')
|
||||
for i, tpar := range t.obj.tparams {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
writeTypeName(buf, tpar, qf)
|
||||
}
|
||||
// TODO(gri): function-local named types should be displayed
|
||||
// differently from named types at package level to avoid
|
||||
// ambiguity.
|
||||
s = obj.name
|
||||
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(')')
|
||||
}
|
||||
buf.WriteString(s)
|
||||
|
||||
case *Contract:
|
||||
buf.WriteString("contract(")
|
||||
|
|
@ -273,6 +286,20 @@ func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
|
|||
}
|
||||
}
|
||||
|
||||
func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
|
||||
s := "<Named w/o object>"
|
||||
if obj != nil {
|
||||
if obj.pkg != nil {
|
||||
writePackage(buf, obj.pkg, qf)
|
||||
}
|
||||
// TODO(gri): function-local named types should be displayed
|
||||
// differently from named types at package level to avoid
|
||||
// ambiguity.
|
||||
s = obj.name
|
||||
}
|
||||
buf.WriteString(s)
|
||||
}
|
||||
|
||||
func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
|
||||
buf.WriteByte('(')
|
||||
if tup != nil {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,24 @@ 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.
|
||||
func (check *Checker) instantiatedType(e ast.Expr) Type {
|
||||
typ := check.typ(e)
|
||||
if ptyp, _ := typ.(*Parameterized); ptyp != nil {
|
||||
tname := ptyp.tname
|
||||
typ = check.subst(tname.typ, ptyp.targs)
|
||||
if typ == nil {
|
||||
return Typ[Invalid] // error was reported by check.instatiate
|
||||
}
|
||||
|
||||
if trace {
|
||||
check.trace(e.Pos(), "instantiated %s -> %s", tname, typ)
|
||||
}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
||||
// funcType type-checks a function or method type.
|
||||
func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, scope *Scope, tparams []*TypeName, ftyp *ast.FuncType) {
|
||||
// type parameters are in a scope enclosing the function scope
|
||||
|
|
@ -259,46 +277,33 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
}
|
||||
|
||||
case *ast.CallExpr:
|
||||
// Type instantiation requires a type name, handle everything
|
||||
// here so we don't need to introduce type parameters into
|
||||
// operands: parametrized types can only appear in type
|
||||
// instantiation expressions.
|
||||
typ := new(Parameterized)
|
||||
def.setUnderlying(typ)
|
||||
|
||||
// e.Fun must be a type name
|
||||
var tname *TypeName
|
||||
if ident, ok := e.Fun.(*ast.Ident); ok {
|
||||
obj := check.lookup(ident.Name)
|
||||
if obj == nil {
|
||||
if ident.Name == "_" {
|
||||
check.errorf(ident.Pos(), "cannot use _ as type")
|
||||
} else {
|
||||
check.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
|
||||
}
|
||||
break
|
||||
}
|
||||
check.recordUse(ident, obj)
|
||||
|
||||
tname, _ = obj.(*TypeName)
|
||||
if tname == nil {
|
||||
check.errorf(ident.Pos(), "%s is not a type", ident.Name)
|
||||
break
|
||||
}
|
||||
// TODO(gri) This code cannot handle type aliases at the moment.
|
||||
// Probably need to do the name lookup here.
|
||||
t := check.typ(e.Fun)
|
||||
if t == Typ[Invalid] {
|
||||
break // error already reported
|
||||
}
|
||||
|
||||
named, _ := t.(*Named)
|
||||
if named == nil || named.obj == nil {
|
||||
check.errorf(e.Pos(), "cannot instantiate type without a name")
|
||||
break
|
||||
}
|
||||
|
||||
tname := named.obj
|
||||
if !tname.IsParametrized() {
|
||||
check.errorf(e.Pos(), "%s is not a parametrized type", tname.name)
|
||||
break
|
||||
}
|
||||
|
||||
// typecheck tname (see check.ident for details)
|
||||
check.objDecl(tname, def)
|
||||
assert(tname.typ != nil)
|
||||
|
||||
// the number of supplied types must match the number of type parameters
|
||||
// TODO(gri) fold into code below - we want to eval args always
|
||||
if len(e.Args) != len(tname.tparams) {
|
||||
// TODO(gri) provide better error message
|
||||
check.errorf(e.Fun.Pos(), "got %d arguments but %d type parameters", len(e.Args), len(tname.tparams))
|
||||
check.errorf(e.Pos(), "got %d arguments but %d type parameters", len(e.Args), len(tname.tparams))
|
||||
break
|
||||
}
|
||||
|
||||
|
|
@ -309,23 +314,92 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
}
|
||||
|
||||
// arguments must be types
|
||||
// (If there was no error before, either all arguments are types
|
||||
// or all are values, thus it suffices to check the first one.)
|
||||
assert(len(args) > 0)
|
||||
if x := args[0]; x.mode != typexpr {
|
||||
check.errorf(x.pos(), "%s is not a type", x)
|
||||
break
|
||||
}
|
||||
|
||||
// instantiate typ
|
||||
typ := check.instantiate(tname.typ, tname.tparams, args)
|
||||
if typ == nil {
|
||||
break // error was reported by check.instatiate
|
||||
// complete parameterized type
|
||||
typ.tname = tname
|
||||
typ.targs = make([]Type, len(args))
|
||||
for i, x := range args {
|
||||
typ.targs[i] = x.typ
|
||||
}
|
||||
|
||||
if trace {
|
||||
check.trace(args[0].pos(), "instantiated %s -> %s", tname, typ)
|
||||
}
|
||||
return typ
|
||||
|
||||
/*
|
||||
// Type instantiation requires a type name, handle everything
|
||||
// here so we don't need to introduce type parameters into
|
||||
// operands: parametrized types can only appear in type
|
||||
// instantiation expressions.
|
||||
|
||||
// e.Fun must be a type name
|
||||
var tname *TypeName
|
||||
if ident, ok := e.Fun.(*ast.Ident); ok {
|
||||
obj := check.lookup(ident.Name)
|
||||
if obj == nil {
|
||||
if ident.Name == "_" {
|
||||
check.errorf(ident.Pos(), "cannot use _ as type")
|
||||
} else {
|
||||
check.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
|
||||
}
|
||||
break
|
||||
}
|
||||
check.recordUse(ident, obj)
|
||||
|
||||
tname, _ = obj.(*TypeName)
|
||||
if tname == nil {
|
||||
check.errorf(ident.Pos(), "%s is not a type", ident.Name)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !tname.IsParametrized() {
|
||||
check.errorf(e.Pos(), "%s is not a parametrized type", tname.name)
|
||||
break
|
||||
}
|
||||
|
||||
// typecheck tname (see check.ident for details)
|
||||
check.objDecl(tname, def)
|
||||
assert(tname.typ != nil)
|
||||
|
||||
// the number of supplied types must match the number of type parameters
|
||||
// TODO(gri) fold into code below - we want to eval args always
|
||||
if len(e.Args) != len(tname.tparams) {
|
||||
// TODO(gri) provide better error message
|
||||
check.errorf(e.Fun.Pos(), "got %d arguments but %d type parameters", len(e.Args), len(tname.tparams))
|
||||
break
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
args, ok := check.exprOrTypeList(e.Args) // reports error if types and expressions are mixed
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
// arguments must be types
|
||||
assert(len(args) > 0)
|
||||
if x := args[0]; x.mode != typexpr {
|
||||
check.errorf(x.pos(), "%s is not a type", x)
|
||||
break
|
||||
}
|
||||
|
||||
// instantiate typ
|
||||
typ := check.instantiate(tname.typ, tname.tparams, args)
|
||||
if typ == nil {
|
||||
break // error was reported by check.instatiate
|
||||
}
|
||||
|
||||
if trace {
|
||||
check.trace(args[0].pos(), "instantiated %s -> %s", tname, typ)
|
||||
}
|
||||
return typ
|
||||
*/
|
||||
|
||||
case *ast.ParenExpr:
|
||||
return check.definedType(e.X, def)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue