]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix the names of methods created during type substitution
authorDan Scales <danscales@google.com>
Sat, 8 Jan 2022 18:33:35 +0000 (10:33 -0800)
committerDan Scales <danscales@google.com>
Tue, 11 Jan 2022 22:50:23 +0000 (22:50 +0000)
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>

src/cmd/compile/internal/typecheck/subr.go
test/typeparam/issue50485.dir/a.go [new file with mode: 0644]
test/typeparam/issue50485.dir/main.go [new file with mode: 0644]
test/typeparam/issue50485.go [new file with mode: 0644]

index da5e9645eaa897ee343494f9086eb36c92a33dd1..04a4ed392fb4410d945d5b6d6bf6bda95a038b0e 100644 (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)
diff --git a/test/typeparam/issue50485.dir/a.go b/test/typeparam/issue50485.dir/a.go
new file mode 100644 (file)
index 0000000..3a7c71a
--- /dev/null
@@ -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 (file)
index 0000000..88a765b
--- /dev/null
@@ -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 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -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