aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorRobert Griesemer <gri@google.com>2026-01-22 16:16:17 -0800
committerRobert Griesemer <gri@google.com>2026-02-19 12:22:13 -0800
commit06dc5db75d4c2548c0187f34ce79389678be7ca0 (patch)
tree67ed553c81ea149812d0d2482ec4d2dafe216fcf /src/cmd
parenta8032d4c781f14fa0bd561d96e719492aee08c23 (diff)
downloadgo-06dc5db75d4c2548c0187f34ce79389678be7ca0.tar.xz
cmd/compile, go/*: move method type parameter checks from parsers to type checkers
The parsers (cmd/compile/internal/syntax and go/parser) always accepted type parameters on methods for parser robustness but reported an error. With this change, the parsers accept the type parameters on methods, and then the type checkers (cmd/compile/internal/types2 and go/types) complain about them. Add test case for method type parameters when running the parsers only. Adjust some existing test cases as needed. This change is a necessary first step towards implementing generic methods but does not enable them. For #77273. Change-Id: I291fcf0aef0c917c74b32131c88b9e4ed71c5060 Reviewed-on: https://go-review.googlesource.com/c/go/+/738441 Reviewed-by: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Griesemer <gri@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/compile/internal/syntax/parser.go8
-rw-r--r--src/cmd/compile/internal/syntax/testdata/smoketest.go30
-rw-r--r--src/cmd/compile/internal/types2/resolver.go5
-rw-r--r--src/cmd/compile/internal/types2/signature.go1
4 files changed, 39 insertions, 5 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index 8278685943..aade7b9fd3 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -797,9 +797,9 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
f.pos = p.pos()
f.Pragma = p.takePragma()
- var context string
+ hasRecv := false
if p.got(_Lparen) {
- context = "method"
+ hasRecv = true
rcvr := p.paramList(nil, nil, _Rparen, false, false)
switch len(rcvr) {
case 0:
@@ -814,13 +814,13 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
if p.tok == _Name {
f.Name = p.name()
- f.TParamList, f.Type = p.funcType(context)
+ f.TParamList, f.Type = p.funcType("")
} else {
f.Name = NewName(p.pos(), "_")
f.Type = new(FuncType)
f.Type.pos = p.pos()
msg := "expected name or ("
- if context != "" {
+ if hasRecv {
msg = "expected name"
}
p.syntaxError(msg)
diff --git a/src/cmd/compile/internal/syntax/testdata/smoketest.go b/src/cmd/compile/internal/syntax/testdata/smoketest.go
index 6b3593ac7a..e7c9f7283f 100644
--- a/src/cmd/compile/internal/syntax/testdata/smoketest.go
+++ b/src/cmd/compile/internal/syntax/testdata/smoketest.go
@@ -71,3 +71,33 @@ type _ interface {
T[P]
T[P1, P2]
}
+
+// generic method
+type List[E any] []E
+
+func (l List[E]) Map[F any](m func(E) F) (r List[F]) {
+ for _, x := range l {
+ r = append(r, m(x))
+ }
+ return
+}
+
+func _() {
+ l := List[string]{"foo", "foobar", "42"}
+ r := l.Map(func(s string) int { return len(s)})
+ _ = r
+}
+
+func _[E, F any](l List[E]) List[F] {
+ var f func(List[E], func(E) F) List[F] = List[E].Map // method expression & type inference
+ return f(l, func(E) F { var f F; return f })
+}
+
+// disallowed type parameters
+
+type _ func /* ERROR function type must have no type parameters */ [P any](P)
+type _ interface {
+ m /* ERROR interface method must have no type parameters */ [P any](P)
+}
+
+var _ = func /* ERROR function type must have no type parameters */ [P any](P) {}
diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go
index f075f5447f..0911ae9c90 100644
--- a/src/cmd/compile/internal/types2/resolver.go
+++ b/src/cmd/compile/internal/types2/resolver.go
@@ -452,6 +452,11 @@ func (check *Checker) collectObjects() {
if recv, _ := base.(*syntax.Name); recv != nil && name != "_" {
methods = append(methods, methodInfo{obj, ptr, recv})
}
+ // methods cannot have type parameters for now
+ if len(s.TParamList) != 0 {
+ check.softErrorf(s.TParamList[0], InvalidMethodTypeParams, "method %s must have no type parameters", name)
+ hasTParamError = true
+ }
check.recordDef(s.Name, obj)
}
_ = len(s.TParamList) != 0 && !hasTParamError && check.verifyVersionf(s.TParamList[0], go1_18, "type parameter")
diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go
index d569ba8013..9d739909fd 100644
--- a/src/cmd/compile/internal/types2/signature.go
+++ b/src/cmd/compile/internal/types2/signature.go
@@ -155,7 +155,6 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams []
// collect and declare function type parameters
if tparams != nil {
- // The parser will complain about invalid type parameters for methods.
check.collectTypeParams(&sig.tparams, tparams)
}