Skip to content

Commit 4cc6a91

Browse files
committed
cmd/compile/internal/types2: implement generic conversions
Fixes #47150. Change-Id: I7531ca5917d4e52ca0b9211d6f2114495b19ba09 Reviewed-on: https://go-review.googlesource.com/c/go/+/356010 Trust: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 2be5b84 commit 4cc6a91

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

src/cmd/compile/internal/types2/conversions.go

+33
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,39 @@ func (x *operand) convertibleTo(check *Checker, T Type) bool {
8989
return true
9090
}
9191

92+
// TODO(gri) consider passing under(x.typ), under(T) into convertibleToImpl (optimization)
93+
Vp, _ := under(x.typ).(*TypeParam)
94+
Tp, _ := under(T).(*TypeParam)
95+
96+
// generic cases
97+
// (generic operands cannot be constants, so we can ignore x.val)
98+
switch {
99+
case Vp != nil && Tp != nil:
100+
x := *x // don't modify outer x
101+
return Vp.underIs(func(V Type) bool {
102+
x.typ = V
103+
return Tp.underIs(func(T Type) bool {
104+
return x.convertibleToImpl(check, T)
105+
})
106+
})
107+
case Vp != nil:
108+
x := *x // don't modify outer x
109+
return Vp.underIs(func(V Type) bool {
110+
x.typ = V
111+
return x.convertibleToImpl(check, T)
112+
})
113+
case Tp != nil:
114+
return Tp.underIs(func(T Type) bool {
115+
return x.convertibleToImpl(check, T)
116+
})
117+
}
118+
119+
// non-generic case
120+
return x.convertibleToImpl(check, T)
121+
}
122+
123+
// convertibleToImpl should only be called by convertibleTo
124+
func (x *operand) convertibleToImpl(check *Checker, T Type) bool {
92125
// "x's type and T have identical underlying types if tags are ignored"
93126
V := x.typ
94127
Vu := under(V)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package conversions
6+
7+
import "unsafe"
8+
9+
// "x is assignable to T"
10+
// - tested via assignability tests
11+
12+
// "x's type and T have identical underlying types if tags are ignored"
13+
14+
func _[X ~int, T ~int](x X) T { return T(x) }
15+
func _[X struct{f int "foo"}, T struct{f int "bar"}](x X) T { return T(x) }
16+
17+
type Foo struct{f int "foo"}
18+
type Bar struct{f int "bar"}
19+
type Far struct{f float64 }
20+
21+
func _[X Foo, T Bar](x X) T { return T(x) }
22+
func _[X Foo|Bar, T Bar](x X) T { return T(x) }
23+
func _[X Foo, T Foo|Bar](x X) T { return T(x) }
24+
func _[X Foo, T Far](x X) T { return T(x /* ERROR cannot convert */ ) }
25+
26+
// "x's type and T are unnamed pointer types and their pointer base types
27+
// have identical underlying types if tags are ignored"
28+
29+
func _[X ~*Foo, T ~*Bar](x X) T { return T(x) }
30+
func _[X ~*Foo|~*Bar, T ~*Bar](x X) T { return T(x) }
31+
func _[X ~*Foo, T ~*Foo|~*Bar](x X) T { return T(x) }
32+
func _[X ~*Foo, T ~*Far](x X) T { return T(x /* ERROR cannot convert */ ) }
33+
34+
// "x's type and T are both integer or floating point types"
35+
36+
func _[X Integer, T Integer](x X) T { return T(x) }
37+
func _[X Unsigned, T Integer](x X) T { return T(x) }
38+
func _[X Float, T Integer](x X) T { return T(x) }
39+
40+
func _[X Integer, T Unsigned](x X) T { return T(x) }
41+
func _[X Unsigned, T Unsigned](x X) T { return T(x) }
42+
func _[X Float, T Unsigned](x X) T { return T(x) }
43+
44+
func _[X Integer, T Float](x X) T { return T(x) }
45+
func _[X Unsigned, T Float](x X) T { return T(x) }
46+
func _[X Float, T Float](x X) T { return T(x) }
47+
48+
func _[X, T Integer|Unsigned|Float](x X) T { return T(x) }
49+
func _[X, T Integer|~string](x X) T { return T(x /* ERROR cannot convert */ ) }
50+
51+
// "x's type and T are both complex types"
52+
53+
func _[X, T Complex](x X) T { return T(x) }
54+
func _[X, T Float|Complex](x X) T { return T(x /* ERROR cannot convert */ ) }
55+
56+
// "x is an integer or a slice of bytes or runes and T is a string type"
57+
58+
type myInt int
59+
type myString string
60+
61+
func _[T ~string](x int) T { return T(x) }
62+
func _[T ~string](x myInt) T { return T(x) }
63+
func _[X Integer](x X) string { return string(x) }
64+
func _[X Integer](x X) myString { return myString(x) }
65+
func _[X Integer](x X) *string { return (*string)(x /* ERROR cannot convert */ ) }
66+
67+
func _[T ~string](x []byte) T { return T(x) }
68+
func _[T ~string](x []rune) T { return T(x) }
69+
func _[X ~[]byte, T ~string](x X) T { return T(x) }
70+
func _[X ~[]rune, T ~string](x X) T { return T(x) }
71+
func _[X Integer|~[]byte|~[]rune, T ~string](x X) T { return T(x) }
72+
func _[X Integer|~[]byte|~[]rune, T ~*string](x X) T { return T(x /* ERROR cannot convert */ ) }
73+
74+
// "x is a string and T is a slice of bytes or runes"
75+
76+
func _[T ~[]byte](x string) T { return T(x) }
77+
func _[T ~[]rune](x string) T { return T(x) }
78+
func _[T ~[]rune](x *string) T { return T(x /* ERROR cannot convert */ ) }
79+
80+
func _[X ~string, T ~[]byte](x X) T { return T(x) }
81+
func _[X ~string, T ~[]rune](x X) T { return T(x) }
82+
func _[X ~string, T ~[]byte|~[]rune](x X) T { return T(x) }
83+
func _[X ~*string, T ~[]byte|~[]rune](x X) T { return T(x /* ERROR cannot convert */ ) }
84+
85+
// package unsafe:
86+
// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
87+
88+
type myUintptr uintptr
89+
90+
func _[X ~uintptr](x X) unsafe.Pointer { return unsafe.Pointer(x) }
91+
func _[T unsafe.Pointer](x myUintptr) T { return T(x) }
92+
func _[T unsafe.Pointer](x int64) T { return T(x /* ERROR cannot convert */ ) }
93+
94+
// "and vice versa"
95+
96+
func _[T ~uintptr](x unsafe.Pointer) T { return T(x) }
97+
func _[X unsafe.Pointer](x X) uintptr { return uintptr(x) }
98+
func _[X unsafe.Pointer](x X) myUintptr { return myUintptr(x) }
99+
func _[X unsafe.Pointer](x X) int64 { return int64(x /* ERROR cannot convert */ ) }
100+
101+
// "x is a slice, T is a pointer-to-array type,
102+
// and the slice and array types have identical element types."
103+
104+
func _[X ~[]E, T ~*[10]E, E any](x X) T { return T(x) }
105+
func _[X ~[]E, T ~[10]E, E any](x X) T { return T(x /* ERROR cannot convert */ ) }
106+
107+
// ----------------------------------------------------------------------------
108+
// The following declarations can be replaced by the exported types of the
109+
// constraints package once all builders support importing interfaces with
110+
// type constraints.
111+
112+
type Signed interface {
113+
~int | ~int8 | ~int16 | ~int32 | ~int64
114+
}
115+
116+
type Unsigned interface {
117+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
118+
}
119+
120+
type Integer interface {
121+
Signed | Unsigned
122+
}
123+
124+
type Float interface {
125+
~float32 | ~float64
126+
}
127+
128+
type Complex interface {
129+
~complex64 | ~complex128
130+
}

0 commit comments

Comments
 (0)