[dev.typeparams] cmd/compile: export OFUNCINST and OSELRECV2 nodes (for generic functions)

Added new test typeparam/factimp.go and changed a bunch of other tests
to test exporting more generic functions and types.

Change-Id: I573d75431cc92482f8f908695cfbc8e84dbb36d2
Reviewed-on: https://go-review.googlesource.com/c/go/+/321749
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-05-09 11:38:34 -07:00
parent 243076da64
commit ccbfbb1c33
11 changed files with 142 additions and 49 deletions

View file

@ -1920,6 +1920,26 @@ func (w *exportWriter) expr(n ir.Node) {
// if exporting, DCLCONST should just be removed as its usage
// has already been replaced with literals
case ir.OFUNCINST:
n := n.(*ir.InstExpr)
w.op(ir.OFUNCINST)
w.pos(n.Pos())
w.expr(n.X)
w.uint64(uint64(len(n.Targs)))
for _, targ := range n.Targs {
w.typ(targ.Type())
}
if go117ExportTypes {
w.typ(n.Type())
}
case ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
w.op(ir.OSELRECV2)
w.pos(n.Pos())
w.exprList(n.Lhs)
w.exprList(n.Rhs)
default:
base.Fatalf("cannot export %v (%d) node\n"+
"\t==> please file an issue and assign to gri@", n.Op(), int(n.Op()))

View file

@ -1582,6 +1582,26 @@ func (r *importReader) node() ir.Node {
case ir.OEND:
return nil
case ir.OFUNCINST:
pos := r.pos()
x := r.expr()
ntargs := r.uint64()
var targs []ir.Node
if ntargs > 0 {
targs = make([]ir.Node, ntargs)
for i := range targs {
targs[i] = ir.TypeNode(r.typ())
}
}
n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs)
if go117ExportTypes {
n.SetType(r.typ())
}
return n
case ir.OSELRECV2:
return ir.NewAssignListStmt(r.pos(), ir.OSELRECV2, r.exprList(), r.exprList())
default:
base.Fatalf("cannot import %v (%d) node\n"+
"\t==> please file an issue and assign to gri@", op, int(op))

View file

@ -10,9 +10,9 @@ import (
"fmt"
)
type _Gen[A any] func() (A, bool)
type Gen[A any] func() (A, bool)
func combine[T1, T2, T any](g1 _Gen[T1], g2 _Gen[T2], join func(T1, T2) T) _Gen[T] {
func Combine[T1, T2, T any](g1 Gen[T1], g2 Gen[T2], join func(T1, T2) T) Gen[T] {
return func() (T, bool) {
var t T
t1, ok := g1()
@ -27,38 +27,38 @@ func combine[T1, T2, T any](g1 _Gen[T1], g2 _Gen[T2], join func(T1, T2) T) _Gen[
}
}
type _Pair[A, B any] struct {
type Pair[A, B any] struct {
A A
B B
}
func _NewPair[A, B any](a A, b B) _Pair[A, B] {
return _Pair[A, B]{a, b}
func _NewPair[A, B any](a A, b B) Pair[A, B] {
return Pair[A, B]{a, b}
}
func _Combine2[A, B any](ga _Gen[A], gb _Gen[B]) _Gen[_Pair[A, B]] {
return combine(ga, gb, _NewPair[A, B])
func Combine2[A, B any](ga Gen[A], gb Gen[B]) Gen[Pair[A, B]] {
return Combine(ga, gb, _NewPair[A, B])
}
func main() {
var g1 _Gen[int] = func() (int, bool) { return 3, true }
var g2 _Gen[string] = func() (string, bool) { return "x", false }
var g3 _Gen[string] = func() (string, bool) { return "y", true }
var g1 Gen[int] = func() (int, bool) { return 3, true }
var g2 Gen[string] = func() (string, bool) { return "x", false }
var g3 Gen[string] = func() (string, bool) { return "y", true }
gc := combine(g1, g2, _NewPair[int, string])
gc := Combine(g1, g2, _NewPair[int, string])
if got, ok := gc(); ok {
panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok))
}
gc2 := _Combine2(g1, g2)
gc2 := Combine2(g1, g2)
if got, ok := gc2(); ok {
panic(fmt.Sprintf("got %v, %v, wanted -/false", got, ok))
}
gc3 := combine(g1, g3, _NewPair[int, string])
gc3 := Combine(g1, g3, _NewPair[int, string])
if got, ok := gc3(); !ok || got.A != 3 || got.B != "y" {
panic(fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok))
}
gc4 := _Combine2(g1, g3)
gc4 := Combine2(g1, g3)
if got, ok := gc4(); !ok || got.A != 3 || got.B != "y" {
panic (fmt.Sprintf("got %v, %v, wanted {3, y}, true", got, ok))
}

View file

@ -12,7 +12,7 @@ import "fmt"
// argument
type any interface{}
type _Function[a, b any] interface {
type Function[a, b any] interface {
Apply(x a) b
}
@ -29,8 +29,8 @@ func (this pos) Apply(x int) bool {
}
type compose[a, b, c any] struct {
f _Function[a, b]
g _Function[b, c]
f Function[a, b]
g Function[b, c]
}
func (this compose[a, b, c]) Apply(x a) c {
@ -47,52 +47,52 @@ func (this Int) Equal(that int) bool {
return int(this) == that
}
type _List[a any] interface {
Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any
type List[a any] interface {
Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any
}
type _Nil[a any] struct{
type Nil[a any] struct{
}
func (xs _Nil[a]) Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any {
func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any {
return casenil.Apply(xs)
}
type _Cons[a any] struct {
type Cons[a any] struct {
Head a
Tail _List[a]
Tail List[a]
}
func (xs _Cons[a]) Match(casenil _Function[_Nil[a], any], casecons _Function[_Cons[a], any]) any {
func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any {
return casecons.Apply(xs)
}
type mapNil[a, b any] struct{
}
func (m mapNil[a, b]) Apply(_ _Nil[a]) any {
return _Nil[b]{}
func (m mapNil[a, b]) Apply(_ Nil[a]) any {
return Nil[b]{}
}
type mapCons[a, b any] struct {
f _Function[a, b]
f Function[a, b]
}
func (m mapCons[a, b]) Apply(xs _Cons[a]) any {
return _Cons[b]{m.f.Apply(xs.Head), _Map[a, b](m.f, xs.Tail)}
func (m mapCons[a, b]) Apply(xs Cons[a]) any {
return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)}
}
func _Map[a, b any](f _Function[a, b], xs _List[a]) _List[b] {
return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(_List[b])
func Map[a, b any](f Function[a, b], xs List[a]) List[b] {
return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b])
}
func main() {
var xs _List[int] = _Cons[int]{3, _Cons[int]{6, _Nil[int]{}}}
var ys _List[int] = _Map[int, int](incr{-5}, xs)
var xz _List[bool] = _Map[int, bool](pos{}, ys)
cs1 := xz.(_Cons[bool])
cs2 := cs1.Tail.(_Cons[bool])
_, ok := cs2.Tail.(_Nil[bool])
var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}}
var ys List[int] = Map[int, int](incr{-5}, xs)
var xz List[bool] = Map[int, bool](pos{}, ys)
cs1 := xz.(Cons[bool])
cs2 := cs1.Tail.(Cons[bool])
_, ok := cs2.Tail.(Nil[bool])
if cs1.Head != false || cs2.Head != true || !ok {
panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true",
cs1.Head, cs2.Head, ok))

View file

@ -0,0 +1,12 @@
// 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 a
func Fact[T interface { type int, int64, float64 }](n T) T {
if n == T(1) {
return T(1)
}
return n * Fact(n - T(1))
}

View file

@ -0,0 +1,26 @@
// 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 main
import (
"a"
"fmt"
)
func main() {
const want = 120
if got := a.Fact(5); got != want {
panic(fmt.Sprintf("got %d, want %d", got, want))
}
if got := a.Fact[int64](5); got != want {
panic(fmt.Sprintf("got %d, want %d", got, want))
}
if got := a.Fact(5.0); got != want {
panic(fmt.Sprintf("got %f, want %f", got, want))
}
}

View file

@ -0,0 +1,7 @@
// rundir -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

View file

@ -11,7 +11,7 @@ import (
)
// Index returns the index of x in s, or -1 if not found.
func index[T comparable](s []T, x T) int {
func Index[T comparable](s []T, x T) int {
for i, v := range s {
// v and x are type T, which has the comparable
// constraint, so we can use == here.
@ -30,17 +30,17 @@ func main() {
want := 2
vec1 := []string{"ab", "cd", "ef"}
if got := index(vec1, "ef"); got != want {
if got := Index(vec1, "ef"); got != want {
panic(fmt.Sprintf("got %d, want %d", got, want))
}
vec2 := []byte{'c', '6', '@'}
if got := index(vec2, '@'); got != want {
if got := Index(vec2, '@'); got != want {
panic(fmt.Sprintf("got %d, want %d", got, want))
}
vec3 := []*obj{&obj{2}, &obj{42}, &obj{1}}
if got := index(vec3, vec3[2]); got != want {
if got := Index(vec3, vec3[2]); got != want {
panic(fmt.Sprintf("got %d, want %d", got, want))
}
}

View file

@ -1,3 +1,7 @@
// 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 a
type Ordered interface {

View file

@ -1,3 +1,7 @@
// 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 main
import (

View file

@ -8,29 +8,29 @@ package main
import "sync"
// A _Lockable is a value that may be safely simultaneously accessed
// A Lockable is a value that may be safely simultaneously accessed
// from multiple goroutines via the Get and Set methods.
type _Lockable[T any] struct {
type Lockable[T any] struct {
T
mu sync.Mutex
}
// Get returns the value stored in a _Lockable.
func (l *_Lockable[T]) get() T {
// Get returns the value stored in a Lockable.
func (l *Lockable[T]) get() T {
l.mu.Lock()
defer l.mu.Unlock()
return l.T
}
// set sets the value in a _Lockable.
func (l *_Lockable[T]) set(v T) {
// set sets the value in a Lockable.
func (l *Lockable[T]) set(v T) {
l.mu.Lock()
defer l.mu.Unlock()
l.T = v
}
func main() {
sl := _Lockable[string]{T: "a"}
sl := Lockable[string]{T: "a"}
if got := sl.get(); got != "a" {
panic(got)
}
@ -39,7 +39,7 @@ func main() {
panic(got)
}
il := _Lockable[int]{T: 1}
il := Lockable[int]{T: 1}
if got := il.get(); got != 1 {
panic(got)
}