From 03db2c24136939416903b284a19905d97ceea40d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 26 Aug 2021 11:56:52 -0700 Subject: cmd/compile/internal/types2: implement TypeList.String (debugging support) Change-Id: Iaa203def3dac94a7d5ff6120e89315c3d7977ee1 Reviewed-on: https://go-review.googlesource.com/c/go/+/345471 Trust: Robert Griesemer Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/types2/instantiate.go | 2 +- src/cmd/compile/internal/types2/subst.go | 6 ------ src/cmd/compile/internal/types2/typelists.go | 13 +++++++++++++ 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'src/cmd/compile/internal/types2') diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index f9cde24dfc..4113d248b8 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -75,7 +75,7 @@ func Instantiate(env *Environment, typ Type, targs []Type, validate bool) (Type, func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posList []syntax.Pos) (res Type) { assert(check != nil) if check.conf.Trace { - check.trace(pos, "-- instantiating %s with %s", typ, typeListString(targs)) + check.trace(pos, "-- instantiating %s with %s", typ, NewTypeList(targs)) check.indent++ defer func() { check.indent-- diff --git a/src/cmd/compile/internal/types2/subst.go b/src/cmd/compile/internal/types2/subst.go index ff8dd13b6d..7c33e7ade4 100644 --- a/src/cmd/compile/internal/types2/subst.go +++ b/src/cmd/compile/internal/types2/subst.go @@ -281,12 +281,6 @@ func instantiatedHash(typ *Named, targs []Type) string { return string(res[:i]) } -func typeListString(list []Type) string { - var buf bytes.Buffer - writeTypeList(&buf, list, nil, nil) - return buf.String() -} - // typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid]. // A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_)) // where an array/slice element is accessed before it is set up. diff --git a/src/cmd/compile/internal/types2/typelists.go b/src/cmd/compile/internal/types2/typelists.go index 3258a5e9f8..c3befb077f 100644 --- a/src/cmd/compile/internal/types2/typelists.go +++ b/src/cmd/compile/internal/types2/typelists.go @@ -4,6 +4,8 @@ package types2 +import "bytes" + // TParamList holds a list of type parameters. type TParamList struct{ tparams []*TypeParam } @@ -52,6 +54,17 @@ func (l *TypeList) list() []Type { return l.types } +func (l *TypeList) String() string { + if l == nil || len(l.types) == 0 { + return "[]" + } + var buf bytes.Buffer + buf.WriteByte('[') + writeTypeList(&buf, l.types, nil, nil) + buf.WriteByte(']') + return buf.String() +} + // ---------------------------------------------------------------------------- // Implementation -- cgit v1.2.3-54-g00ecf From af80af22b507ae23ae04372f30b98f7720c85f8a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 26 Aug 2021 12:27:06 -0700 Subject: cmd/compile/internal/types2: do not declare new methods on instantiated types Report an error if an alias is used to declare a method on an instantiated type. Also, when resolving the receiver type, don't use asNamed to avoid premature expansion of the type. Fixes #47968. Change-Id: Ie5acc4cfb1944deaaeeaee98707f31e256f8ef5e Reviewed-on: https://go-review.googlesource.com/c/go/+/345472 Trust: Robert Griesemer Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/types2/signature.go | 8 +++++++- .../types2/testdata/fixedbugs/issue47968.go2 | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 (limited to 'src/cmd/compile/internal/types2') diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index d28e7b8944..ddad1f0311 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -132,7 +132,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // Also: Don't report an error via genericType since it will be reported // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead? - if recv := asNamed(check.genericType(rname, false)); recv != nil { + if recv, _ := check.genericType(rname, false).(*Named); recv != nil { recvTParams = recv.TParams().list() } } @@ -211,6 +211,12 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] switch T := rtyp.(type) { case *Named: T.expand(nil) + // The receiver type may be an instantiated type referred to + // by an alias (which cannot have receiver parameters for now). + if T.TArgs() != nil && sig.RParams() == nil { + check.errorf(recv.pos, "cannot define methods on instantiated type %s", recv.typ) + break + } // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 new file mode 100644 index 0000000000..bbbe6805f2 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 @@ -0,0 +1,21 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +type T[P any] struct{} + +func (T[P]) m1() + +type A1 = T + +func (A1[P]) m2() {} + +type A2 = T[int] + +func (A2 /* ERROR cannot define methods on instantiated type T\[int\] */) m3() {} +func (_ /* ERROR cannot define methods on instantiated type T\[int\] */ A2) m4() {} + +func (T[int]) m5() {} // int is the type parameter name, not an instantiation +func (T[* /* ERROR must be an identifier */ int]) m6() {} // syntax error -- cgit v1.2.3-54-g00ecf From 2c60a99f723e779a39664b5f12cb41878fd4a700 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 26 Aug 2021 14:52:32 -0700 Subject: cmd/compile/internal/syntax: make valid type parameter list in presence of errors Make sure the parser fills in names and types for type parameter lists, even in the case of errors. While at it, adjust some of the test functions to accept generic code and report all syntax errors. Added offending source as test for types2. Fixes #47996. Change-Id: I449bcf5e2cb80fa2a24cdd3945f484bfca218a06 Reviewed-on: https://go-review.googlesource.com/c/go/+/345476 Trust: Robert Griesemer Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/syntax/dumper_test.go | 6 +----- src/cmd/compile/internal/syntax/parser.go | 5 +---- src/cmd/compile/internal/syntax/printer_test.go | 6 +----- src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 | 8 ++++++++ 4 files changed, 11 insertions(+), 14 deletions(-) create mode 100644 src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 (limited to 'src/cmd/compile/internal/types2') diff --git a/src/cmd/compile/internal/syntax/dumper_test.go b/src/cmd/compile/internal/syntax/dumper_test.go index 22680dce78..033283a352 100644 --- a/src/cmd/compile/internal/syntax/dumper_test.go +++ b/src/cmd/compile/internal/syntax/dumper_test.go @@ -13,11 +13,7 @@ func TestDump(t *testing.T) { t.Skip("skipping test in short mode") } - // provide a no-op error handler so parsing doesn't stop after first error - ast, err := ParseFile(*src_, func(error) {}, nil, CheckBranches) - if err != nil { - t.Error(err) - } + ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, CheckBranches|AllowGenerics) if ast != nil { Fdump(testOut(), ast) diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index fd97279f9d..3d1ca9d6d4 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -1924,7 +1924,7 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []* } // distribute parameter types (len(list) > 0) - if named == 0 { + if named == 0 && !requireNames { // all unnamed => found names are named types for _, par := range list { if typ := par.Name; typ != nil { @@ -1932,9 +1932,6 @@ func (p *parser) paramList(name *Name, close token, requireNames bool) (list []* par.Name = nil } } - if requireNames { - p.syntaxErrorAt(list[0].Type.Pos(), "type parameters must be named") - } } else if named != len(list) { // some named => all must have names and types var pos Pos // left-most error position (or unknown) diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go index ec4b1de573..638e6d4a9d 100644 --- a/src/cmd/compile/internal/syntax/printer_test.go +++ b/src/cmd/compile/internal/syntax/printer_test.go @@ -18,11 +18,7 @@ func TestPrint(t *testing.T) { t.Skip("skipping test in short mode") } - // provide a no-op error handler so parsing doesn't stop after first error - ast, err := ParseFile(*src_, func(error) {}, nil, 0) - if err != nil { - t.Error(err) - } + ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, AllowGenerics) if ast != nil { Fprint(testOut(), ast, LineForm) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 new file mode 100644 index 0000000000..56e90942ab --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 @@ -0,0 +1,8 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +// don't crash +func T /* ERROR missing */ [P /* ERROR named */ ] m /* ERROR m */ () /* ERROR \) */ { /* ERROR { */ } /* ERROR } */ -- cgit v1.2.3-54-g00ecf