Skip to content

Commit

Permalink
go/types, types2: factor out type parameter renaming (cleanup)
Browse files Browse the repository at this point in the history
Change-Id: I2d7e32ee2496d391f334ad9956e8d37c53f9be98
Reviewed-on: https://go-review.googlesource.com/c/go/+/461687
TryBot-Result: Gopher Robot <[email protected]>
Run-TryBot: Robert Griesemer <[email protected]>
Reviewed-by: Robert Griesemer <[email protected]>
Reviewed-by: Robert Findley <[email protected]>
Auto-Submit: Robert Griesemer <[email protected]>
  • Loading branch information
griesemer authored and gopherbot committed Jan 18, 2023
1 parent 7e740f9 commit 1c2c225
Showing 1 changed file with 49 additions and 45 deletions.
94 changes: 49 additions & 45 deletions src/cmd/compile/internal/types2/infer.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,51 +61,8 @@ func (check *Checker) infer(pos syntax.Pos, 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(pos, tparam.bound, renameMap, nil, check.context())
}

tparams = tparams2
params = check.subst(pos, params, renameMap, nil, check.context()).(*Tuple)
}
// Rename type parameters to avoid conflicts in recursive instantiation scenarios.
tparams, params = check.renameTParams(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
Expand Down Expand Up @@ -316,6 +273,53 @@ func (check *Checker) infer(pos syntax.Pos, 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 syntax.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 of the type parameter names
// in list suitable for human consumption.
func typeParamsString(list []*TypeParam) string {
Expand Down

0 comments on commit 1c2c225

Please sign in to comment.