mirror of https://github.com/golang/go.git
go/types: cleaned up parameterized type code a bit; enabled more tests
Change-Id: I579239f30f26e8a483c6f5dc379124d8a9eb4576
This commit is contained in:
parent
2a76603101
commit
06ce58509d
|
|
@ -26,7 +26,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
|
|||
// conversion or type instantiation
|
||||
T := x.typ
|
||||
x.mode = invalid
|
||||
if named, _ := T.(*Named); named != nil && named.obj != nil && named.obj.IsParametrized() {
|
||||
if named, _ := T.(*Named); named != nil && named.obj != nil && named.obj.IsParameterized() {
|
||||
// type instantiation
|
||||
x.typ = check.instantiatedType(e)
|
||||
if x.typ != Typ[Invalid] {
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
|
|||
check.validType(obj.typ, nil)
|
||||
})
|
||||
|
||||
if obj.IsParametrized() {
|
||||
if obj.IsParameterized() {
|
||||
assert(obj.scope != nil)
|
||||
check.scope = obj.scope // push type parameter scope
|
||||
}
|
||||
|
|
@ -586,7 +586,7 @@ 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() {
|
||||
if obj.IsParameterized() {
|
||||
check.closeScope()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -228,8 +228,8 @@ func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
|
|||
return &TypeName{object{nil, pos, pkg, name, typ, 0, colorFor(typ), token.NoPos}, nil, nil}
|
||||
}
|
||||
|
||||
// IsParametrized reports whether obj is a parametrized type.
|
||||
func (obj *TypeName) IsParametrized() bool {
|
||||
// IsParameterized reports whether obj is a parametrized type.
|
||||
func (obj *TypeName) IsParameterized() bool {
|
||||
return len(obj.tparams) > 0
|
||||
}
|
||||
|
||||
|
|
@ -437,7 +437,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
|
|||
if _, ok := typ.(*Basic); ok {
|
||||
return
|
||||
}
|
||||
if tname.IsParametrized() {
|
||||
if tname.IsParameterized() {
|
||||
fmt.Fprint(buf, "(type ")
|
||||
for i, p := range tname.tparams {
|
||||
if i > 0 {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ package p
|
|||
|
||||
type List(type E) []E
|
||||
var _ List(List(List(int)))
|
||||
// var _ List(List(List(int))) = [](List(List(int))){}
|
||||
var _ List(List(List(int))) = [](List(List(int))){}
|
||||
|
||||
type (
|
||||
T1(type P1) struct {
|
||||
|
|
@ -27,10 +27,10 @@ func _() {
|
|||
x1.f1 = x2
|
||||
}
|
||||
|
||||
// type T3(type P) T1(T2(P, P))
|
||||
type T3(type P) T1(T2(P, P))
|
||||
|
||||
func _() {
|
||||
//var x1 T3(int)
|
||||
//var x2 T2
|
||||
//x1.f1.f2.f2 = 0
|
||||
var x1 T3(int)
|
||||
var x2 T2(int, int)
|
||||
x1.f1.f2.f2 = x2
|
||||
}
|
||||
|
|
@ -275,121 +275,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
|
|||
case *ast.CallExpr:
|
||||
typ := new(Parameterized)
|
||||
def.setUnderlying(typ)
|
||||
|
||||
// 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 || !named.obj.IsParametrized() {
|
||||
check.errorf(e.Pos(), "%s is not a parametrized type", t)
|
||||
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
|
||||
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))
|
||||
break
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
args, ok := check.exprOrTypeList(e.Args) // reports error if types and expressions are mixed
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// complete parameterized type
|
||||
typ.tname = tname
|
||||
typ.targs = make([]Type, len(args))
|
||||
for i, x := range args {
|
||||
typ.targs[i] = x.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
|
||||
*/
|
||||
check.parameterizedType(typ, e)
|
||||
|
||||
case *ast.ParenExpr:
|
||||
return check.definedType(e.X, def)
|
||||
|
|
@ -542,6 +428,64 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
|
|||
return -1
|
||||
}
|
||||
|
||||
// typeList provides the list of types corresponding to the incoming expression list.
|
||||
// If an error occured, the result is nil, but all list elements were type-checked.
|
||||
func (check *Checker) typeList(list []ast.Expr) []Type {
|
||||
res := make([]Type, len(list)) // res != nil even if len(list) == 0
|
||||
ok := true
|
||||
for i, x := range list {
|
||||
t := check.typ(x)
|
||||
if t == Typ[Invalid] {
|
||||
ok = false
|
||||
}
|
||||
res[i] = t
|
||||
}
|
||||
if ok {
|
||||
return res
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) {
|
||||
// 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] {
|
||||
return // 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// evaluate arguments
|
||||
args := check.typeList(e.Args)
|
||||
if args == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) If none of the arguments is parameterized than we can instantiate the type.
|
||||
// When instantiating, it will become a different type, at which point the outer type is
|
||||
// not correct anymore (it's not a Parameterized). If it's defined type, it may also have
|
||||
// methods and we don't deal with those either... :-(
|
||||
|
||||
// complete parameterized type
|
||||
typ.tname = tname
|
||||
typ.targs = args
|
||||
}
|
||||
|
||||
func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
|
||||
if list == nil {
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue