mirror of
https://github.com/golang/go
synced 2024-11-26 21:11:57 -07:00
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:
parent
13c912d192
commit
1ee70da312
@ -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)
|
||||
|
239
test/typeparam/issue50485.dir/a.go
Normal file
239
test/typeparam/issue50485.dir/a.go
Normal 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]()
|
||||
}
|
9
test/typeparam/issue50485.dir/main.go
Normal file
9
test/typeparam/issue50485.dir/main.go
Normal file
@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"a"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_ = a.OrdOption(a.Given[int]())
|
||||
}
|
7
test/typeparam/issue50485.go
Normal file
7
test/typeparam/issue50485.go
Normal 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
|
Loading…
Reference in New Issue
Block a user