diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index 4d9b4f92e1d..c47672fa1ea 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 ed4ca1f08df..5dacd8fa1a3 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 041c4536672..5d6bf7aedac 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 651a333e24f..bcac0da0128 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.