From de712f2df818e95e712941ea1b7b38c68b0031f5 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 17 Jul 2019 15:28:08 -0700 Subject: [PATCH] go/types: implemented comparison of parameterized types; minor bug fixes Also: Added -h flag to test framework; setting -h causes a panic when an error is reported (for debugging). Change-Id: Ib45d4ef38769f2ecdd3ce53fa3aed9fd99ef6bc8 --- src/go/types/check.go | 1 - src/go/types/check_test.go | 2 +- src/go/types/errors.go | 4 ---- src/go/types/predicates.go | 17 ++++++++++++++++- src/go/types/testdata/tmp.go2 | 12 +++++++++--- src/go/types/testdata/typeinst.go2 | 4 ---- src/go/types/testdata/typeinst2.go2 | 2 +- src/go/types/type.go | 2 +- src/go/types/typexpr.go | 17 +++++++++++------ 9 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/go/types/check.go b/src/go/types/check.go index 62d2ade1a7..87c17d5886 100644 --- a/src/go/types/check.go +++ b/src/go/types/check.go @@ -18,7 +18,6 @@ import ( const ( debug = false // leave on during development trace = false // turn on for detailed type resolution traces - halt = false // panic on error ) // If Strict is set, the type-checker enforces additional diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go index b31b5031ec..090582bec2 100644 --- a/src/go/types/check_test.go +++ b/src/go/types/check_test.go @@ -100,7 +100,7 @@ var tests = [][]string{ {"testdata/issue6977.src"}, // Go 2 tests (type parameters and contracts) - // {"testdata/tmp.go2"}, // used for ad-hoc tests - file contents transient, excluded from tests + {"testdata/tmp.go2"}, // used for ad-hoc tests - file contents transient {"testdata/typeparams.go2"}, {"testdata/typeinst.go2"}, {"testdata/typeinst2.go2"}, diff --git a/src/go/types/errors.go b/src/go/types/errors.go index 9efd701fb6..91b077163c 100644 --- a/src/go/types/errors.go +++ b/src/go/types/errors.go @@ -90,10 +90,6 @@ func (check *Checker) err(pos token.Pos, msg string, soft bool) { if trace { check.trace(pos, "ERROR: %s", msg) } - - if halt { - panic(err) - } f := check.conf.Error if f == nil { diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go index 9ba0ddcfa4..28ce556f23 100644 --- a/src/go/types/predicates.go +++ b/src/go/types/predicates.go @@ -308,7 +308,22 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair, tparams } case *Parameterized: - panic("internal error: cannot compare uninstantiated parametrized types for identity") + // Two parameterized types are identical if the type name and the parameters are identical. + // TODO(gri) This ignores alias types for now. E.g., type A(type P) = P; A(int) == int does + // not work. + if y, ok := y.(*Parameterized); ok { + if x.tname != y.tname { + return false + } + assert(len(x.targs) == len(y.targs)) // since x, y have identical tname + for i, x := range x.targs { + y := y.targs[i] + if !identical(x, y, cmpTags, p, tparams) { + return false + } + } + return true + } case *TypeParam: if y, ok := y.(*TypeParam); ok { diff --git a/src/go/types/testdata/tmp.go2 b/src/go/types/testdata/tmp.go2 index 820a4f7e9a..a75d304ffb 100644 --- a/src/go/types/testdata/tmp.go2 +++ b/src/go/types/testdata/tmp.go2 @@ -4,8 +4,14 @@ package p -type List(type P) []P +type List(type E) []E -type T(type P) List(P) +func f(type P) (x P) List(P) { + return List(P){x} +} -var _ T(int) //= T(int)(List(int){1, 2, 3}) \ No newline at end of file +var ( + _ []int = f(0) + _ []float32 = f(float32)(10) + //_ []List(int) = f(List(int){}) +) diff --git a/src/go/types/testdata/typeinst.go2 b/src/go/types/testdata/typeinst.go2 index ad9dad05e1..949b9c55ab 100644 --- a/src/go/types/testdata/typeinst.go2 +++ b/src/go/types/testdata/typeinst.go2 @@ -59,7 +59,3 @@ var _ List(List(List(int))) type T3(type P) List(P) var _ T3(int) = T3(int)(List(int){1, 2, 3}) - - -// TODO -// type map maps to unique name found in scopes? diff --git a/src/go/types/testdata/typeinst2.go2 b/src/go/types/testdata/typeinst2.go2 index 01680d0b93..a82fa74d10 100644 --- a/src/go/types/testdata/typeinst2.go2 +++ b/src/go/types/testdata/typeinst2.go2 @@ -32,5 +32,5 @@ type T3(type P) T1(T2(P, P)) func _() { var x1 T3(int) var x2 T2(int, int) - x1.f1.f2.f2 = x2 + x1.f1.f2 = x2 } \ No newline at end of file diff --git a/src/go/types/type.go b/src/go/types/type.go index 096aa9f69b..43570a0a18 100644 --- a/src/go/types/type.go +++ b/src/go/types/type.go @@ -556,7 +556,7 @@ func (t *Interface) Underlying() Type { return t } func (m *Map) Underlying() Type { return m } func (c *Chan) Underlying() Type { return c } func (t *Named) Underlying() Type { return t.underlying } -func (p *Parameterized) Underlying() Type { return p } // TODO(gri) is this correct? +func (p *Parameterized) Underlying() Type { return p.tname.typ.Underlying() } func (c *Contract) Underlying() Type { return c } func (c *TypeParam) Underlying() Type { return c } diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 1912fd5bd5..29efd6f700 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -275,7 +275,11 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type { case *ast.CallExpr: typ := new(Parameterized) def.setUnderlying(typ) - check.parameterizedType(typ, e) + if check.parameterizedType(typ, e) { + return typ + } + // TODO(gri) If we have a cycle and we reach here, "leafs" of + // the cycle may refer to a not fully set up Parameterized typ. case *ast.ParenExpr: return check.definedType(e.X, def) @@ -447,18 +451,18 @@ func (check *Checker) typeList(list []ast.Expr) []Type { return nil } -func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) { +func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) bool { // 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 + return false // 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 + return false } // the number of supplied types must match the number of type parameters @@ -467,13 +471,13 @@ func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) { 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 + return false } // evaluate arguments args := check.typeList(e.Args) if args == nil { - return + return false } // TODO(gri) If none of the arguments is parameterized than we can instantiate the type. @@ -484,6 +488,7 @@ func (check *Checker) parameterizedType(typ *Parameterized, e *ast.CallExpr) { // complete parameterized type typ.tname = tname typ.targs = args + return true } func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {