diff --git a/src/go/types/call.go b/src/go/types/call.go index 03554c675c..b36ada7949 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -161,6 +161,7 @@ func (check *Checker) exprOrTypeList(elist []ast.Expr) (xlist []*operand, ok boo } func (check *Checker) instantiate(typ Type, tparams []*TypeName, args []*operand) Type { + assert(typ != nil) n := len(args) if n != len(tparams) { check.errorf(args[n-1].pos(), "got %d type arguments but want %d", n, len(tparams)) @@ -176,7 +177,7 @@ func (check *Checker) instantiate(typ Type, tparams []*TypeName, args []*operand targs[i] = a.typ } // result is instantiated typ - return subst(typ, targs) + return check.subst(typ, targs) } func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*operand, commaOk bool) { @@ -301,8 +302,8 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper if targs == nil { return } - rsig = subst(sig, targs).(*Signature) - params = subst(params, targs).(*Tuple) + rsig = check.subst(sig, targs).(*Signature) + params = check.subst(params, targs).(*Tuple) // TODO(gri) Optimization: We don't need to check arguments // from which we inferred parameter types. } diff --git a/src/go/types/check.go b/src/go/types/check.go index 493b73986f..e15acbefcd 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -8,6 +8,7 @@ package types import ( "errors" + "fmt" "go/ast" "go/constant" "go/token" @@ -257,21 +258,34 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { defer check.handleBailout(&err) + print := func(msg string) { + if trace { + fmt.Println(msg) + } + } + + print("== initFiles ==") check.initFiles(files) + print("== collectObjects ==") check.collectObjects() + print("== packagetObjects ==") check.packageObjects() + print("== processDelayed ==") check.processDelayed(0) // incl. all functions check.processFinals() + print("== initOrder ==") check.initOrder() if !check.conf.DisableUnusedImportCheck { + print("== unusedImports ==") check.unusedImports() } + print("== recordUntyped ==") check.recordUntyped() check.pkg.complete = true diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 1c2ae54472..51d07f620a 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -39,7 +39,7 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a } par := params.At(i) if !check.identical0(par.typ, arg.typ, true, nil, targs) { - check.errorf(arg.pos(), "type %s for %s does not match %s = %s", arg.typ, arg.expr, par.typ, subst(par.typ, targs)) + check.errorf(arg.pos(), "type %s for %s does not match %s = %s", arg.typ, arg.expr, par.typ, check.subst(par.typ, targs)) return nil } } @@ -52,7 +52,7 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a } par := params.At(i) if !check.identical0(par.typ, Default(arg.typ), true, nil, targs) { - check.errorf(arg.pos(), "default type %s for %s does not match %s = %s", Default(arg.typ), arg.expr, par.typ, subst(par.typ, targs)) + check.errorf(arg.pos(), "default type %s for %s does not match %s = %s", Default(arg.typ), arg.expr, par.typ, check.subst(par.typ, targs)) return nil } } diff --git a/src/go/types/object.go b/src/go/types/object.go index be8558410c..04a4cfb85b 100644 --- a/src/go/types/object.go +++ b/src/go/types/object.go @@ -426,6 +426,16 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { if _, ok := typ.(*Basic); ok { return } + if tname.IsParametrized() { + fmt.Fprint(buf, "(type ") + for i, p := range tname.tparams { + if i > 0 { + fmt.Fprint(buf, ", ") + } + fmt.Fprintf(buf, "%s", p.name) + } + fmt.Fprint(buf, ")") + } if tname.IsAlias() { buf.WriteString(" =") } else { diff --git a/src/go/types/subst.go b/src/go/types/subst.go index 8c245753b0..76ef5f3828 100644 --- a/src/go/types/subst.go +++ b/src/go/types/subst.go @@ -8,15 +8,20 @@ package types -func subst(typ Type, targs []Type) Type { +import ( + "bytes" +) + +func (check *Checker) subst(typ Type, targs []Type) Type { if len(targs) == 0 { return typ } - s := subster{targs, make(map[Type]Type)} + s := subster{check, targs, make(map[Type]Type)} return s.typ(typ) } type subster struct { + check *Checker targs []Type cache map[Type]Type } @@ -90,8 +95,17 @@ func (s *subster) typ(typ Type) (res Type) { } case *Named: - // TODO(gri) is this correct? - // nothing to do + underlying := s.typ(t.underlying) + if underlying != t.underlying { + // create a new named type - for now use printed type in name + // TODO(gri) use type map to map types to indices + if len(t.methods) > 0 { + panic("cannot handle instantiation of types with methods yet") + } + // TODO(gri) what is the correct position to use here? + obj := NewTypeName(t.obj.pos, s.check.pkg, t.obj.name+typesString(s.targs), nil) + return NewNamed(obj, underlying, nil) // TODO(gri) provide correct method list + } case *TypeParam: if targ := s.targs[t.index]; targ != nil { @@ -145,3 +159,16 @@ func (s *subster) varList(in []*Var) (out []*Var, copied bool) { } return } + +func typesString(targs []Type) string { + var buf bytes.Buffer + buf.WriteByte('(') + for i, arg := range targs { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(TypeString(arg, nil)) + } + buf.WriteByte(')') + return buf.String() +} diff --git a/src/go/types/testdata/typeinst.go2 b/src/go/types/testdata/typeinst.go2 index 5aa4c44061..6e1336d5e3 100644 --- a/src/go/types/testdata/typeinst.go2 +++ b/src/go/types/testdata/typeinst.go2 @@ -20,6 +20,11 @@ type List(type P) []P type A1(type P) = P type A2(type P) = struct { + f P + g int +} + +type A3(type P) = struct { f P g myInt // myInt should still be in scope chain } @@ -37,8 +42,14 @@ 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 +var _ A1(int) = x +var _ A1(float32) = x // ERROR cannot use x .* as float32 +var _ T2(*int) = A2(*int){} +var _ T2(*int) = A2 /* ERROR cannot use */ (int){} + +// TODO(gri) cannot handle this yet due because instantiated types are not yet canonicalized +//var _ T2(int) = T2(int){} // TODO // think about instantiated types (they are defined types unless alias) diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index a9e6c8ef6c..9006ec4a98 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -262,7 +262,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type { // 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. + // instantiation expressions. // e.Fun must be a type name var tname *TypeName @@ -290,6 +290,10 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type { 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) { @@ -312,12 +316,16 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type { } // 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 + 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)