From: Robert Griesemer Date: Wed, 18 Jan 2023 01:25:14 +0000 (-0800) Subject: go/types: factor out type parameter renaming (cleanup) X-Git-Tag: go1.21rc1~1901 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=7026a8a1a9aba58285b3cae215df04140245b6db;p=gostls13.git go/types: factor out type parameter renaming (cleanup) Follow-up on CL 461687 which missed the go/types change. (As an aside, we cannot yet generate this change because go/types uses a positioner and types2 just uses a syntax.Pos.) Change-Id: I28113a2efdc3ddd30cb9a80d2cb2c802ff035ec2 Reviewed-on: https://go-review.googlesource.com/c/go/+/461688 Reviewed-by: Robert Findley TryBot-Result: Gopher Robot Reviewed-by: Robert Griesemer Run-TryBot: Robert Griesemer --- diff --git a/src/go/types/infer.go b/src/go/types/infer.go index c1a1dd693b..d77f07447a 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -9,6 +9,7 @@ package types import ( "fmt" + "go/token" . "internal/types/errors" "strings" ) @@ -60,51 +61,8 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, } // len(targs) < n - const enableTparamRenaming = true - if enableTparamRenaming { - // For the purpose of type inference we must differentiate type parameters - // occurring in explicit type or value function arguments from the type - // parameters we are solving for via unification, because they may be the - // same in self-recursive calls. For example: - // - // func f[P *Q, Q any](p P, q Q) { - // f(p) - // } - // - // In this example, the fact that the P used in the instantation f[P] has - // the same pointer identity as the P we are trying to solve for via - // unification is coincidental: there is nothing special about recursive - // calls that should cause them to conflate the identity of type arguments - // with type parameters. To put it another way: any such self-recursive - // call is equivalent to a mutually recursive call, which does not run into - // any problems of type parameter identity. For example, the following code - // is equivalent to the code above. - // - // func f[P interface{*Q}, Q any](p P, q Q) { - // f2(p) - // } - // - // func f2[P interface{*Q}, Q any](p P, q Q) { - // f(p) - // } - // - // We turn the first example into the second example by renaming type - // parameters in the original signature to give them a new identity. - tparams2 := make([]*TypeParam, len(tparams)) - for i, tparam := range tparams { - tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil) - tparams2[i] = NewTypeParam(tname, nil) - tparams2[i].index = tparam.index // == i - } - - renameMap := makeRenameMap(tparams, tparams2) - for i, tparam := range tparams { - tparams2[i].bound = check.subst(posn.Pos(), tparam.bound, renameMap, nil, check.context()) - } - - tparams = tparams2 - params = check.subst(posn.Pos(), params, renameMap, nil, check.context()).(*Tuple) - } + // Rename type parameters to avoid conflicts in recursive instantiation scenarios. + tparams, params = check.renameTParams(posn.Pos(), tparams, params) // If we have more than 2 arguments, we may have arguments with named and unnamed types. // If that is the case, permutate params and args such that the arguments with named @@ -312,6 +270,53 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, return nil } +// renameTParams renames the type parameters in a function signature described by its +// type and ordinary parameters (tparams and params) such that each type parameter is +// given a new identity. renameTParams returns the new type and ordinary parameters. +func (check *Checker) renameTParams(pos token.Pos, tparams []*TypeParam, params *Tuple) ([]*TypeParam, *Tuple) { + // For the purpose of type inference we must differentiate type parameters + // occurring in explicit type or value function arguments from the type + // parameters we are solving for via unification, because they may be the + // same in self-recursive calls. For example: + // + // func f[P *Q, Q any](p P, q Q) { + // f(p) + // } + // + // In this example, the fact that the P used in the instantation f[P] has + // the same pointer identity as the P we are trying to solve for via + // unification is coincidental: there is nothing special about recursive + // calls that should cause them to conflate the identity of type arguments + // with type parameters. To put it another way: any such self-recursive + // call is equivalent to a mutually recursive call, which does not run into + // any problems of type parameter identity. For example, the following code + // is equivalent to the code above. + // + // func f[P interface{*Q}, Q any](p P, q Q) { + // f2(p) + // } + // + // func f2[P interface{*Q}, Q any](p P, q Q) { + // f(p) + // } + // + // We turn the first example into the second example by renaming type + // parameters in the original signature to give them a new identity. + tparams2 := make([]*TypeParam, len(tparams)) + for i, tparam := range tparams { + tname := NewTypeName(tparam.Obj().Pos(), tparam.Obj().Pkg(), tparam.Obj().Name(), nil) + tparams2[i] = NewTypeParam(tname, nil) + tparams2[i].index = tparam.index // == i + } + + renameMap := makeRenameMap(tparams, tparams2) + for i, tparam := range tparams { + tparams2[i].bound = check.subst(pos, tparam.bound, renameMap, nil, check.context()) + } + + return tparams2, check.subst(pos, params, renameMap, nil, check.context()).(*Tuple) +} + // typeParamsString produces a string containing all the type parameter names // in list suitable for human consumption. func typeParamsString(list []*TypeParam) string {