cmd/compile: fix the names of methods created during type substitution

The names given to methods of types created during type substitution
were possible incorrect when the type parameters themselves were nested
types.

Fixes #50485

Change-Id: I7e0043ed22c26406a5f9d8d51d9e928770a678f6
Reviewed-on: https://go-review.googlesource.com/c/go/+/377494
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Dan Scales 2022-01-08 10:33:35 -08:00
parent 13c912d192
commit 1ee70da312
4 changed files with 277 additions and 2 deletions

View file

@ -976,7 +976,9 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
// function that helps implement a method of an instantiated type). For method nodes
// on shape types, we prepend "nofunc.", because method nodes for shape types will
// have no body, and we want to avoid a name conflict with the shape-based function
// that helps implement the same method for fully-instantiated types.
// that helps implement the same method for fully-instantiated types. Function names
// are also created at the end of (*Tsubster).typ1, so we append "nofunc" there as
// well, as needed.
func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, isMethodNode, hasBrackets bool) *types.Sym {
nm := makeInstName1(gf.Name, targs, hasBrackets)
if targs[0].HasShape() && isMethodNode {
@ -1273,7 +1275,25 @@ func (ts *Tsubster) typ1(t *types.Type) *types.Type {
for i, f := range t.Methods().Slice() {
t2 := ts.typ1(f.Type)
oldsym := f.Nname.Sym()
newsym := MakeFuncInstSym(oldsym, ts.Targs, true, true)
// Use the name of the substituted receiver to create the
// method name, since the receiver name may have many levels
// of nesting (brackets) with type names to be substituted.
recvType := t2.Recv().Type
var nm string
if recvType.IsPtr() {
recvType = recvType.Elem()
nm = "(*" + recvType.Sym().Name + ")." + f.Sym.Name
} else {
nm = recvType.Sym().Name + "." + f.Sym.Name
}
if recvType.RParams()[0].HasShape() {
// We add "nofunc" to methods of shape type to avoid
// conflict with the name of the shape-based helper
// function. See header comment of MakeFuncInstSym.
nm = "nofunc." + nm
}
newsym := oldsym.Pkg.Lookup(nm)
var nname *ir.Name
if newsym.Def != nil {
nname = newsym.Def.(*ir.Name)

View file

@ -0,0 +1,239 @@
package a
import "fmt"
type ImplicitOrd interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}
func LessGiven[T ImplicitOrd]() Ord[T] {
return LessFunc[T](func(a, b T) bool {
return a < b
})
}
type Eq[T any] interface {
Eqv(a T, b T) bool
}
type Ord[T any] interface {
Eq[T]
Less(a T, b T) bool
}
type LessFunc[T any] func(a, b T) bool
func (r LessFunc[T]) Eqv(a, b T) bool {
return r(a, b) == false && r(b, a) == false
}
func (r LessFunc[T]) Less(a, b T) bool {
return r(a, b)
}
type Option[T any] struct {
v *T
}
func (r Option[T]) IsDefined() bool {
return r.v != nil
}
func (r Option[T]) IsEmpty() bool {
return !r.IsDefined()
}
func (r Option[T]) Get() T {
return *r.v
}
func (r Option[T]) String() string {
if r.IsDefined() {
return fmt.Sprintf("Some(%v)", r.v)
} else {
return "None"
}
}
func (r Option[T]) OrElse(t T) T {
if r.IsDefined() {
return *r.v
}
return t
}
func (r Option[T]) Recover(f func() T) Option[T] {
if r.IsDefined() {
return r
}
t := f()
return Option[T]{&t}
}
type Func1[A1, R any] func(a1 A1) R
type Func2[A1, A2, R any] func(a1 A1, a2 A2) R
func (r Func2[A1, A2, R]) Curried() Func1[A1, Func1[A2, R]] {
return func(a1 A1) Func1[A2, R] {
return Func1[A2, R](func(a2 A2) R {
return r(a1, a2)
})
}
}
type HList interface {
sealed()
}
// Header is constrains interface type, enforce Head type of Cons is HT
type Header[HT any] interface {
HList
Head() HT
}
// Cons means H :: T
// zero value of Cons[H,T] is not allowed.
// so Cons defined as interface type
type Cons[H any, T HList] interface {
HList
Head() H
Tail() T
}
type Nil struct {
}
func (r Nil) Head() Nil {
return r
}
func (r Nil) Tail() Nil {
return r
}
func (r Nil) String() string {
return "Nil"
}
func (r Nil) sealed() {
}
type hlistImpl[H any, T HList] struct {
head H
tail T
}
func (r hlistImpl[H, T]) Head() H {
return r.head
}
func (r hlistImpl[H, T]) Tail() T {
return r.tail
}
func (r hlistImpl[H, T]) String() string {
return fmt.Sprintf("%v :: %v", r.head, r.tail)
}
func (r hlistImpl[H, T]) sealed() {
}
func hlist[H any, T HList](h H, t T) Cons[H, T] {
return hlistImpl[H, T]{h, t}
}
func Concat[H any, T HList](h H, t T) Cons[H, T] {
return hlist(h, t)
}
func Empty() Nil {
return Nil{}
}
func Some[T any](v T) Option[T] {
return Option[T]{}.Recover(func() T {
return v
})
}
func None[T any]() Option[T] {
return Option[T]{}
}
func Ap[T, U any](t Option[Func1[T, U]], a Option[T]) Option[U] {
return FlatMap(t, func(f Func1[T, U]) Option[U] {
return Map(a, f)
})
}
func Map[T, U any](opt Option[T], f func(v T) U) Option[U] {
return FlatMap(opt, func(v T) Option[U] {
return Some(f(v))
})
}
func FlatMap[T, U any](opt Option[T], fn func(v T) Option[U]) Option[U] {
if opt.IsDefined() {
return fn(opt.Get())
}
return None[U]()
}
type ApplicativeFunctor1[H Header[HT], HT, A, R any] struct {
h Option[H]
fn Option[Func1[A, R]]
}
func (r ApplicativeFunctor1[H, HT, A, R]) ApOption(a Option[A]) Option[R] {
return Ap(r.fn, a)
}
func (r ApplicativeFunctor1[H, HT, A, R]) Ap(a A) Option[R] {
return r.ApOption(Some(a))
}
func Applicative1[A, R any](fn Func1[A, R]) ApplicativeFunctor1[Nil, Nil, A, R] {
return ApplicativeFunctor1[Nil, Nil, A, R]{Some(Empty()), Some(fn)}
}
type ApplicativeFunctor2[H Header[HT], HT, A1, A2, R any] struct {
h Option[H]
fn Option[Func1[A1, Func1[A2, R]]]
}
func (r ApplicativeFunctor2[H, HT, A1, A2, R]) ApOption(a Option[A1]) ApplicativeFunctor1[Cons[A1, H], A1, A2, R] {
nh := FlatMap(r.h, func(hv H) Option[Cons[A1, H]] {
return Map(a, func(av A1) Cons[A1, H] {
return Concat(av, hv)
})
})
return ApplicativeFunctor1[Cons[A1, H], A1, A2, R]{nh, Ap(r.fn, a)}
}
func (r ApplicativeFunctor2[H, HT, A1, A2, R]) Ap(a A1) ApplicativeFunctor1[Cons[A1, H], A1, A2, R] {
return r.ApOption(Some(a))
}
func Applicative2[A1, A2, R any](fn Func2[A1, A2, R]) ApplicativeFunctor2[Nil, Nil, A1, A2, R] {
return ApplicativeFunctor2[Nil, Nil, A1, A2, R]{Some(Empty()), Some(fn.Curried())}
}
func OrdOption[T any](m Ord[T]) Ord[Option[T]] {
return LessFunc[Option[T]](func(t1 Option[T], t2 Option[T]) bool {
if !t1.IsDefined() && !t2.IsDefined() {
return false
}
return Applicative2(m.Less).ApOption(t1).ApOption(t2).OrElse(!t1.IsDefined())
})
}
func Given[T ImplicitOrd]() Ord[T] {
return LessGiven[T]()
}

View file

@ -0,0 +1,9 @@
package main
import (
"a"
)
func main() {
_ = a.OrdOption(a.Given[int]())
}

View file

@ -0,0 +1,7 @@
// compiledir -G=3
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ignored