From 0ffe62a473ce9403780ea862761f1922ffa4b83f Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 18 Jul 2019 16:54:05 -0700 Subject: [PATCH] go/types: more fixes around parameterized types Change-Id: I81e6e70a2833e7dbb17f5155386ed3c7a75dc2ac --- src/go/types/call.go | 2 +- src/go/types/check.go | 2 +- src/go/types/infer.go | 39 +++++++++++++++++++---------- src/go/types/testdata/tmp.go2 | 11 ++++---- src/go/types/testdata/typeinst2.go2 | 15 ++++++++++- src/go/types/typexpr.go | 10 ++++---- 6 files changed, 52 insertions(+), 27 deletions(-) diff --git a/src/go/types/call.go b/src/go/types/call.go index b53b0cea43..44b0ddd3f2 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -112,7 +112,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind { // if type inference failed, a parametrized result must be invalidated // (operands cannot have a parametrized type) - if x.mode == value && len(sig.tparams) > 0 && isParametrized(x.typ) { + if x.mode == value && len(sig.tparams) > 0 && isParameterized(x.typ) { x.mode = invalid } diff --git a/src/go/types/check.go b/src/go/types/check.go index 87c17d5886..badb54aca1 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -16,7 +16,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 ) diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 2fa0b3979b..d06dc6f891 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -21,7 +21,7 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a var indices []int for i := 0; i < params.Len(); i++ { par := params.At(i).typ - if isParametrized(par) { + if isParameterized(par) { indices = append(indices, i) } } @@ -71,50 +71,53 @@ func (check *Checker) infer(pos token.Pos, tparams []*TypeName, params *Tuple, a return targs } -// isParametrized reports whether typ contains any type parameters. +// isParameterized reports whether typ contains any type parameters. // TODO(gri) do we need to handle cycles here? -func isParametrized(typ Type) bool { +func isParameterized(typ Type) bool { switch t := typ.(type) { case nil, *Basic, *Named: // TODO(gri) should nil be handled here? break case *Array: - return isParametrized(t.elem) + return isParameterized(t.elem) case *Slice: - return isParametrized(t.elem) + return isParameterized(t.elem) case *Struct: for _, fld := range t.fields { - if isParametrized(fld.typ) { + if isParameterized(fld.typ) { return true } } case *Pointer: - return isParametrized(t.base) + return isParameterized(t.base) case *Tuple: n := t.Len() for i := 0; i < n; i++ { - if isParametrized(t.At(i).typ) { + if isParameterized(t.At(i).typ) { return true } } case *Signature: - assert(t.tparams == nil) // TODO(gri) is this correct? - assert(t.recv == nil || !isParametrized(t.recv.typ)) // interface method receiver may not be nil - return isParametrized(t.params) || isParametrized(t.results) + assert(t.tparams == nil) // TODO(gri) is this correct? + assert(t.recv == nil || !isParameterized(t.recv.typ)) // interface method receiver may not be nil + return isParameterized(t.params) || isParameterized(t.results) case *Interface: panic("unimplemented") case *Map: - return isParametrized(t.key) || isParametrized(t.elem) + return isParameterized(t.key) || isParameterized(t.elem) case *Chan: - return isParametrized(t.elem) + return isParameterized(t.elem) + + case *Parameterized: + return isParameterizedList(t.targs) case *TypeParam: return true @@ -125,3 +128,13 @@ func isParametrized(typ Type) bool { return false } + +// isParameterizedList reports whether any type in list is parameterized. +func isParameterizedList(list []Type) bool { + for _, t := range list { + if isParameterized(t) { + return true + } + } + return false +} diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index 308c438b4e..7c694dd9b0 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -11,10 +11,9 @@ func f(type P) (x P) List(P) { } var ( - //_ []int = f(0) - //_ []float32 = f(float32)(10) - // TODO(gri) fix next line - // [](List(int)) = f(List(int){}) - // _ List(List(int)) = [](List(int)){} - // _ = [](List(int)){} + _ []int = f(0) + _ []float32 = f(float32)(10) + _ [](List(int)) = f(List(int){}) + _ List(List(int)) = [](List(int)){} + _ = [](List(int)){} ) diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 index a82fa74d10..15a83a1251 100644 --- a/src/go/types/testdata/typeinst2.go2 +++ b/src/go/types/testdata/typeinst2.go2 @@ -33,4 +33,17 @@ func _() { var x1 T3(int) var x2 T2(int, int) x1.f1.f2 = x2 -} \ No newline at end of file +} + +func f(type P) (x P) List(P) { + return List(P){x} +} + +var ( + _ []int = f(0) + _ []float32 = f(float32)(10) + _ List(complex128) = f(1i) + _ [](List(int)) = f(List(int){}) + _ List(List(int)) = [](List(int)){} + _ = [](List(int)){} +) \ No newline at end of file diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 29efd6f700..320390fd2d 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -276,6 +276,11 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type { typ := new(Parameterized) def.setUnderlying(typ) if check.parameterizedType(typ, e) { + if isParameterizedList(typ.targs) { + return typ + } + typ := check.inst(typ.tname, typ.targs) + def.setUnderlying(typ) // TODO(gri) do we need this? return typ } // TODO(gri) If we have a cycle and we reach here, "leafs" of @@ -480,11 +485,6 @@ func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) boo return false } - // 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