From 1d542efe234792c515b3c60ec76f15d11f83aba1 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Wed, 26 Jun 2024 15:20:41 -0700 Subject: [PATCH] go/types, types2: adjust Checker.unpackRecv signature slightly Instead of returning the receiver type name (rname), return the receiver type base expression (base), with pointer indirections stripped. The type base may or may not not be a type name. This is needed for further rewrites of the signature type-checking code. Adjust call sites accordingly to preserve existing behavior. For #51343. Change-Id: Ib472ca25d43ec340762d0a8dd1ad038568c2b2bb Reviewed-on: https://go-review.googlesource.com/c/go/+/595335 Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer Reviewed-by: Tim King LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/resolver.go | 39 +++++++++++--------- src/cmd/compile/internal/types2/signature.go | 4 +- src/go/types/resolver.go | 39 +++++++++++--------- src/go/types/signature.go | 4 +- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index 4d9b4f92e1..c47672fa1e 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -445,11 +445,11 @@ func (check *Checker) collectObjects() { } else { // method // d.Recv != nil - ptr, recv, _ := check.unpackRecv(s.Recv.Type, false) + ptr, base, _ := check.unpackRecv(s.Recv.Type, false) // Methods with invalid receiver cannot be associated to a type, and // methods with blank _ names are never found; no need to collect any // of them. They will still be type-checked with all the other functions. - if recv != nil && name != "_" { + if recv, _ := base.(*syntax.Name); recv != nil && name != "_" { methods = append(methods, methodInfo{obj, ptr, recv}) } check.recordDef(s.Name, obj) @@ -506,37 +506,43 @@ func (check *Checker) collectObjects() { } } -// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether -// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its -// type parameters, if any. The type parameters are only unpacked if unpackParams is -// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we -// cannot easily work around). -func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, rname *syntax.Name, tparams []*syntax.Name) { -L: // unpack receiver type +// unpackRecv unpacks a receiver type expression and returns its components: ptr indicates +// whether rtyp is a pointer receiver, base is the receiver base type expression stripped +// of its type parameters (if any), and tparams are its type parameter names, if any. The +// type parameters are only unpacked if unpackParams is set. For instance, given the rtyp +// +// *T[A, _] +// +// ptr is true, base is T, and tparams is [A, _] (assuming unpackParams is set). +// Note that base may not be a *syntax.Name for erroneous programs. +func (check *Checker) unpackRecv(rtyp syntax.Expr, unpackParams bool) (ptr bool, base syntax.Expr, tparams []*syntax.Name) { + // unpack receiver type // This accepts invalid receivers such as ***T and does not // work for other invalid receivers, but we don't care. The // validity of receiver expressions is checked elsewhere. + base = rtyp +L: for { - switch t := rtyp.(type) { + switch t := base.(type) { case *syntax.ParenExpr: - rtyp = t.X + base = t.X // case *ast.StarExpr: // ptr = true - // rtyp = t.X + // base = t.X case *syntax.Operation: if t.Op != syntax.Mul || t.Y != nil { break } ptr = true - rtyp = t.X + base = t.X default: break L } } // unpack type parameters, if any - if ptyp, _ := rtyp.(*syntax.IndexExpr); ptyp != nil { - rtyp = ptyp.X + if ptyp, _ := base.(*syntax.IndexExpr); ptyp != nil { + base = ptyp.X if unpackParams { for _, arg := range syntax.UnpackListExpr(ptyp.Index) { var par *syntax.Name @@ -559,9 +565,6 @@ L: // unpack receiver type } } - // unpack receiver name - rname, _ = rtyp.(*syntax.Name) - return } diff --git a/src/cmd/compile/internal/types2/signature.go b/src/cmd/compile/internal/types2/signature.go index ed4ca1f08d..5dacd8fa1a 100644 --- a/src/cmd/compile/internal/types2/signature.go +++ b/src/cmd/compile/internal/types2/signature.go @@ -103,7 +103,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // collect generic receiver type parameters, if any // - a receiver type parameter is like any other type parameter, except that it is declared implicitly // - the receiver specification acts as local declaration for its type parameters, which may be blank - _, rname, rparams := check.unpackRecv(recvPar.Type, true) + _, base, rparams := check.unpackRecv(recvPar.Type, true) if len(rparams) > 0 { // The scope of the type parameter T in "func (r T[T]) f()" // starts after f, not at "r"; see #52038. @@ -131,7 +131,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *syntax.Field, tparams [] // determine receiver type to get its type parameters // and the respective type parameter bounds var recvTParams []*TypeParam - if rname != nil { + if rname := base.(*syntax.Name); rname != nil { // recv should be a Named type (otherwise an error is reported elsewhere) // Also: Don't report an error via genericType since it will be reported // again when we type-check the signature. diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go index 041c453667..5d6bf7aeda 100644 --- a/src/go/types/resolver.go +++ b/src/go/types/resolver.go @@ -437,11 +437,11 @@ func (check *Checker) collectObjects() { // when type checking the function type. Confirm that // we don't need to check tparams here. - ptr, recv, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false) + ptr, base, _ := check.unpackRecv(d.decl.Recv.List[0].Type, false) // (Methods with invalid receiver cannot be associated to a type, and // methods with blank _ names are never found; no need to collect any // of them. They will still be type-checked with all the other functions.) - if recv != nil && name != "_" { + if recv, _ := base.(*ast.Ident); recv != nil && name != "_" { methods = append(methods, methodInfo{obj, ptr, recv}) } check.recordDef(d.decl.Name, obj) @@ -496,33 +496,39 @@ func (check *Checker) collectObjects() { } } -// unpackRecv unpacks a receiver type and returns its components: ptr indicates whether -// rtyp is a pointer receiver, rname is the receiver type name, and tparams are its -// type parameters, if any. The type parameters are only unpacked if unpackParams is -// set. If rname is nil, the receiver is unusable (i.e., the source has a bug which we -// cannot easily work around). -func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, rname *ast.Ident, tparams []*ast.Ident) { -L: // unpack receiver type +// unpackRecv unpacks a receiver type expression and returns its components: ptr indicates +// whether rtyp is a pointer receiver, base is the receiver base type expression stripped +// of its type parameters (if any), and tparams are its type parameter names, if any. The +// type parameters are only unpacked if unpackParams is set. For instance, given the rtyp +// +// *T[A, _] +// +// ptr is true, base is T, and tparams is [A, _] (assuming unpackParams is set). +// Note that base may not be a *ast.Ident for erroneous programs. +func (check *Checker) unpackRecv(rtyp ast.Expr, unpackParams bool) (ptr bool, base ast.Expr, tparams []*ast.Ident) { + // unpack receiver type // This accepts invalid receivers such as ***T and does not // work for other invalid receivers, but we don't care. The // validity of receiver expressions is checked elsewhere. + base = rtyp +L: for { - switch t := rtyp.(type) { + switch t := base.(type) { case *ast.ParenExpr: - rtyp = t.X + base = t.X case *ast.StarExpr: ptr = true - rtyp = t.X + base = t.X default: break L } } // unpack type parameters, if any - switch rtyp.(type) { + switch base.(type) { case *ast.IndexExpr, *ast.IndexListExpr: - ix := typeparams.UnpackIndexExpr(rtyp) - rtyp = ix.X + ix := typeparams.UnpackIndexExpr(base) + base = ix.X if unpackParams { for _, arg := range ix.Indices { var par *ast.Ident @@ -544,9 +550,6 @@ L: // unpack receiver type } } - // unpack receiver name - rname, _ = rtyp.(*ast.Ident) - return } diff --git a/src/go/types/signature.go b/src/go/types/signature.go index 651a333e24..bcac0da012 100644 --- a/src/go/types/signature.go +++ b/src/go/types/signature.go @@ -114,7 +114,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // collect generic receiver type parameters, if any // - a receiver type parameter is like any other type parameter, except that it is declared implicitly // - the receiver specification acts as local declaration for its type parameters, which may be blank - _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true) + _, base, rparams := check.unpackRecv(recvPar.List[0].Type, true) if len(rparams) > 0 { // The scope of the type parameter T in "func (r T[T]) f()" // starts after f, not at "r"; see #52038. @@ -139,7 +139,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast // determine receiver type to get its type parameters // and the respective type parameter bounds var recvTParams []*TypeParam - if rname != nil { + if rname := base.(*ast.Ident); rname != nil { // recv should be a Named type (otherwise an error is reported elsewhere) // Also: Don't report an error via genericType since it will be reported // again when we type-check the signature. -- 2.48.1