diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index da5e9645eaa..04a4ed392fb 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -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) diff --git a/test/typeparam/issue50485.dir/a.go b/test/typeparam/issue50485.dir/a.go new file mode 100644 index 00000000000..3a7c71a711e --- /dev/null +++ b/test/typeparam/issue50485.dir/a.go @@ -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]() +} diff --git a/test/typeparam/issue50485.dir/main.go b/test/typeparam/issue50485.dir/main.go new file mode 100644 index 00000000000..88a765bfe9e --- /dev/null +++ b/test/typeparam/issue50485.dir/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "a" +) + +func main() { + _ = a.OrdOption(a.Given[int]()) +} diff --git a/test/typeparam/issue50485.go b/test/typeparam/issue50485.go new file mode 100644 index 00000000000..87b4ff46c1e --- /dev/null +++ b/test/typeparam/issue50485.go @@ -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