diff --git a/src/go/types/call.go b/src/go/types/call.go index da7dae8165..b53b0cea43 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -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] { diff --git a/src/go/types/decl.go b/src/go/types/decl.go index 039ded089d..70f36d826e 100644 --- a/src/go/types/decl.go +++ b/src/go/types/decl.go @@ -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() } diff --git a/src/go/types/object.go b/src/go/types/object.go index a123df8d90..f0db9fbaad 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -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 { diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 index 2753b7d7aa..01680d0b93 100644 --- a/src/go/types/testdata/typeinst2.go2 +++ b/src/go/types/testdata/typeinst2.go2 @@ -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 } \ No newline at end of file diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 5823e3c674..1912fd5bd5 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -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