mirror of https://github.com/golang/go.git
go/types: more steps towards type-checking instantiated types
Change-Id: Iab2dab932faad704fc7141f7afe04eb80597ec57
This commit is contained in:
parent
e6f3c8a0b4
commit
fac6c330ac
|
|
@ -66,32 +66,17 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
}
|
||||
|
||||
// evaluate arguments
|
||||
args := check.exprOrTypeList(e.Args)
|
||||
args, _ := check.exprOrTypeList(e.Args)
|
||||
|
||||
// instantiate function if needed
|
||||
if n := len(args); len(sig.tparams) > 0 && n > 0 && args[0].mode == typexpr {
|
||||
// if the first argument is a type, assume we have explicit type arguments
|
||||
if len(sig.tparams) != n {
|
||||
check.errorf(args[n-1].pos(), "got %d type arguments but want %d", n, len(sig.tparams))
|
||||
x.mode = invalid
|
||||
x.expr = e
|
||||
return expression
|
||||
}
|
||||
// collect types
|
||||
targs := make([]Type, n)
|
||||
for i, a := range args {
|
||||
if a.mode != typexpr {
|
||||
// error was reported earlier
|
||||
x.mode = invalid
|
||||
x.expr = e
|
||||
return expression
|
||||
}
|
||||
targs[i] = a.typ
|
||||
}
|
||||
// result is type-instantiated function value
|
||||
x.mode = value
|
||||
x.typ = check.instantiate(sig, sig.tparams, args)
|
||||
if x.typ == nil {
|
||||
x.mode = invalid
|
||||
}
|
||||
x.expr = e
|
||||
x.typ = subst(sig, targs)
|
||||
return expression
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +112,9 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
|
||||
// exprOrTypeList returns a list of operands and reports an error if the
|
||||
// list contains a mix of values and types (ignoring invalid operands).
|
||||
func (check *Checker) exprOrTypeList(elist []ast.Expr) (xlist []*operand) {
|
||||
func (check *Checker) exprOrTypeList(elist []ast.Expr) (xlist []*operand, ok bool) {
|
||||
ok = true
|
||||
|
||||
switch len(elist) {
|
||||
case 0:
|
||||
// nothing to do
|
||||
|
|
@ -166,12 +153,32 @@ func (check *Checker) exprOrTypeList(elist []ast.Expr) (xlist []*operand) {
|
|||
}
|
||||
if 0 < ntypes && ntypes < len(xlist) {
|
||||
check.errorf(xlist[0].pos(), "mix of value and type expressions")
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (check *Checker) instantiate(typ Type, tparams []*TypeName, args []*operand) Type {
|
||||
n := len(args)
|
||||
if n != len(tparams) {
|
||||
check.errorf(args[n-1].pos(), "got %d type arguments but want %d", n, len(tparams))
|
||||
return nil
|
||||
}
|
||||
// collect types
|
||||
targs := make([]Type, n)
|
||||
for i, a := range args {
|
||||
if a.mode != typexpr {
|
||||
// error was reported earlier
|
||||
return nil
|
||||
}
|
||||
targs[i] = a.typ
|
||||
}
|
||||
// result is instantiated typ
|
||||
return subst(typ, targs)
|
||||
}
|
||||
|
||||
func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) {
|
||||
switch len(elist) {
|
||||
case 0:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import (
|
|||
|
||||
// debugging/development support
|
||||
const (
|
||||
debug = false // leave on during development
|
||||
debug = true // leave on during development
|
||||
trace = false // turn on for detailed type resolution traces
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ func (s *subster) typ(typ Type) (res Type) {
|
|||
results := s.tuple(t.results)
|
||||
if recv != t.recv || params != t.params || results != t.results {
|
||||
copy := *t
|
||||
copy.tparams = nil // TODO(gri) is this correct?
|
||||
copy.tparams = nil // TODO(gri) is this correct? (another indication that perhaps tparams belong to the function decl)
|
||||
copy.recv = recv
|
||||
copy.params = params
|
||||
copy.results = results
|
||||
|
|
|
|||
|
|
@ -17,17 +17,27 @@ type T2(type P) struct {
|
|||
|
||||
type List(type P) []P
|
||||
|
||||
type A1(type P) P
|
||||
type A1(type P) = P
|
||||
|
||||
type A2(type P) struct {
|
||||
type A2(type P) = struct {
|
||||
f P
|
||||
g myInt // myInt should still be in scope chain
|
||||
}
|
||||
|
||||
// Parametrized type instantiations
|
||||
|
||||
type _ T1 /* ERROR not a type */ (int) // TODO fix this
|
||||
var x int
|
||||
type _ x /* ERROR not a type */ (int)
|
||||
|
||||
type _ int /* ERROR not a parametrized type */ ()
|
||||
type _ myInt /* ERROR not a parametrized type */ ()
|
||||
|
||||
// TODO(gri) better error messages
|
||||
type _ T1 /* ERROR got 0 arguments but 1 type parameters */ ()
|
||||
type _ T1(x /* ERROR not a type */ )
|
||||
type _ T1 /* ERROR got 2 arguments but 1 type parameters */ (int, float32)
|
||||
|
||||
// var _ A1(int) = x
|
||||
|
||||
|
||||
// TODO
|
||||
|
|
|
|||
|
|
@ -258,9 +258,65 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
check.errorf(x.pos(), "%s is not a type", &x)
|
||||
}
|
||||
|
||||
// case *ast.CallExpr:
|
||||
// check.typ(e.Fun)
|
||||
// panic("type instantiation not yet implemented")
|
||||
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
|
||||
// instatiation 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
|
||||
}
|
||||
|
||||
// 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
|
||||
if typ := check.instantiate(tname.typ, tname.tparams, args); typ != nil {
|
||||
// TODO(gri) this is probably not correct
|
||||
def.setUnderlying(typ)
|
||||
return typ
|
||||
}
|
||||
|
||||
case *ast.ParenExpr:
|
||||
return check.definedType(e.X, def)
|
||||
|
|
|
|||
Loading…
Reference in New Issue