Skip to content

Commit 370d8c9

Browse files
authored
Merge pull request #1242 from nevkontakte/generics12
Complete type conversion support for type parameters
2 parents 3a9e2c9 + 267a750 commit 370d8c9

File tree

7 files changed

+358
-25
lines changed

7 files changed

+358
-25
lines changed

compiler/astutil/astutil.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ func IsTypeExpr(expr ast.Expr, info *types.Info) bool {
6060
}
6161
_, ok = info.Uses[ident].(*types.TypeName)
6262
return ok
63+
case *ast.IndexListExpr:
64+
ident, ok := e.X.(*ast.Ident)
65+
if !ok {
66+
return false
67+
}
68+
_, ok = info.Uses[ident].(*types.TypeName)
69+
return ok
6370
case *ast.ParenExpr:
6471
return IsTypeExpr(e.X, info)
6572
default:

compiler/natives/src/reflect/reflect.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1639,7 +1639,7 @@ func DeepEqual(a1, a2 interface{}) bool {
16391639
if i1 == i2 {
16401640
return true
16411641
}
1642-
if i1 == nil || i2 == nil || i1.Get("constructor") != i2.Get("constructor") {
1642+
if i1 == nil || i2 == nil {
16431643
return false
16441644
}
16451645
return deepValueEqualJs(ValueOf(a1), ValueOf(a2), nil)
@@ -1649,6 +1649,11 @@ func deepValueEqualJs(v1, v2 Value, visited [][2]unsafe.Pointer) bool {
16491649
if !v1.IsValid() || !v2.IsValid() {
16501650
return !v1.IsValid() && !v2.IsValid()
16511651
}
1652+
1653+
if v1.Kind() == Chan && v2.Kind() == Chan {
1654+
return v1.object() == v2.object()
1655+
}
1656+
16521657
if v1.Type() != v2.Type() {
16531658
return false
16541659
}

compiler/prelude/types.js

Lines changed: 138 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ var $idKey = x => {
5959
};
6060

6161
// Creates constructor functions for array pointer types. Returns a new function
62-
// instace each time to make sure each type is independent of the other.
62+
// instance each time to make sure each type is independent of the other.
6363
var $arrayPtrCtor = () => {
6464
return function (array) {
6565
this.$get = () => { return array; };
@@ -224,7 +224,10 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
224224
typ.keyFor = $idKey;
225225
typ.init = elem => {
226226
typ.elem = elem;
227-
typ.wrapped = (elem.kind === $kindArray);
227+
if (elem.kind === $kindArray) {
228+
typ.wrapped = true;
229+
typ.wrap = (v) => ((v === typ.nil) ? v : new typ(v));
230+
}
228231
typ.nil = new typ($throwNilPointerError, $throwNilPointerError);
229232
};
230233
break;
@@ -456,13 +459,26 @@ var $newType = (size, kind, string, named, pkg, exported, constructor) => {
456459
case $kindInterface:
457460
typ.convertFrom = (src) => $convertToInterface(src, typ);
458461
break;
459-
case $kindArray:
460462
case $kindSlice:
463+
typ.convertFrom = (src) => $convertToSlice(src, typ);
464+
break;
465+
case $kindPtr:
466+
typ.convertFrom = (src) => $convertToPointer(src, typ);
467+
break;
468+
case $kindArray:
469+
typ.convertFrom = (src) => $convertToArray(src, typ);
470+
break;
471+
case $kindStruct:
472+
typ.convertFrom = (src) => $convertToStruct(src, typ);
473+
break;
461474
case $kindMap:
475+
typ.convertFrom = (src) => $convertToMap(src, typ);
476+
break;
462477
case $kindChan:
463-
case $kindPtr:
478+
typ.convertFrom = (src) => $convertToChan(src, typ);
479+
break;
464480
case $kindFunc:
465-
case $kindStruct:
481+
typ.convertFrom = (src) => $convertToFunc(src, typ);
466482
break;
467483
default:
468484
$panic(new $String("invalid kind: " + kind));
@@ -1093,4 +1109,120 @@ const $convertToBool = (src, dstType) => {
10931109
*/
10941110
const $convertToInterface = (src, dstType) => {
10951111
return src;
1096-
};
1112+
};
1113+
1114+
/**
1115+
* Convert to a slice value.
1116+
*
1117+
* dstType.kind must be $kindSlice. For wrapped types, src value must be wrapped.
1118+
* The returned value is always a slice type.
1119+
*/
1120+
const $convertToSlice = (src, dstType) => {
1121+
const srcType = src.constructor;
1122+
if (srcType === dstType) {
1123+
return src;
1124+
}
1125+
1126+
switch (srcType.kind) {
1127+
case $kindString:
1128+
if (dstType.elem.kind === $kindInt32) { // Runes are int32.
1129+
return new dstType($stringToRunes(src.$val));
1130+
} else if (dstType.elem.kind === $kindUint8) { // Bytes are uint8.
1131+
return new dstType($stringToBytes(src.$val));
1132+
}
1133+
break;
1134+
case $kindSlice:
1135+
return $convertSliceType(src, dstType);
1136+
break;
1137+
}
1138+
throw new Error(`Unsupported conversion from ${srcType.string} to ${dstType.string}`);
1139+
};
1140+
1141+
/**
1142+
* Convert to a pointer value.
1143+
*
1144+
* dstType.kind must be $kindPtr. For wrapped types (specifically, pointers
1145+
* to an array), src value must be wrapped. The returned value is a bare JS
1146+
* array (typed or untyped), or a pointer object.
1147+
*/
1148+
const $convertToPointer = (src, dstType) => {
1149+
const srcType = src.constructor;
1150+
1151+
if (srcType === dstType) {
1152+
return src;
1153+
}
1154+
1155+
// []T → *[N]T
1156+
if (srcType.kind == $kindSlice && dstType.elem.kind == $kindArray) {
1157+
return $sliceToGoArray(src, dstType);
1158+
}
1159+
1160+
if (src === srcType.nil) {
1161+
return dstType.nil;
1162+
}
1163+
1164+
switch (dstType.elem.kind) {
1165+
case $kindArray:
1166+
// Pointers to arrays are a wrapped type, represented by a native JS array,
1167+
// which we return directly.
1168+
return src.$val;
1169+
case $kindStruct:
1170+
return $pointerOfStructConversion(src, dstType);
1171+
default:
1172+
return new dstType(src.$get, src.$set, src.$target);
1173+
}
1174+
};
1175+
1176+
/**
1177+
* Convert to struct types.
1178+
*
1179+
* dstType.kind must be $kindStruct. Src must be a wrapped struct value. Returned
1180+
* value will always be a bare JavaScript object representing the struct.
1181+
*/
1182+
const $convertToStruct = (src, dstType) => {
1183+
// Since structs are passed by value, the conversion result must be a copy
1184+
// of the original value, even if it is the same type.
1185+
return $clone(src.$val, dstType);
1186+
};
1187+
1188+
/**
1189+
* Convert to array types.
1190+
*
1191+
* dstType.kind must be $kindArray. Src must be a wrapped array value. Returned
1192+
* value will always be a bare JavaScript object representing the array.
1193+
*/
1194+
const $convertToArray = (src, dstType) => {
1195+
// Since arrays are passed by value, the conversion result must be a copy
1196+
// of the original value, even if it is the same type.
1197+
return $clone(src.$val, dstType);
1198+
};
1199+
1200+
/**
1201+
* Convert to map types.
1202+
*
1203+
* dstType.kind must be $kindMap. Src must be a wrapped map value. Returned
1204+
* value will always be a bare JavaScript object representing the map.
1205+
*/
1206+
const $convertToMap = (src, dstType) => {
1207+
return src.$val;
1208+
};
1209+
1210+
/**
1211+
* Convert to chan types.
1212+
*
1213+
* dstType.kind must be $kindChan. Src must be a wrapped chan value. Returned
1214+
* value will always be a bare $Chan object representing the channel.
1215+
*/
1216+
const $convertToChan = (src, dstType) => {
1217+
return src.$val;
1218+
};
1219+
1220+
/**
1221+
* Convert to function types.
1222+
*
1223+
* dstType.kind must be $kindFunc. Src must be a wrapped function value. Returned
1224+
* value will always be a bare JavaScript function.
1225+
*/
1226+
const $convertToFunc = (src, dstType) => {
1227+
return src.$val;
1228+
};

tests/gorepo/run.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ var knownFails = map[string]failReason{
157157
"typeparam/absdiff.go": {category: generics, desc: "missing operator support for generic types"},
158158
"typeparam/absdiff2.go": {category: generics, desc: "missing operator support for generic types"},
159159
"typeparam/absdiff3.go": {category: generics, desc: "missing operator support for generic types"},
160-
"typeparam/boundmethod.go": {category: generics, desc: "missing support for type conversion of a parameterized type"},
160+
"typeparam/boundmethod.go": {category: generics, desc: "missing support for method expressions with a type param"},
161161
"typeparam/chans.go": {category: generics, desc: "missing support for the comparable type constraint"},
162-
"typeparam/dictionaryCapture.go": {category: generics, desc: "missing support for conversion into a parameterized type"},
162+
"typeparam/dictionaryCapture.go": {category: generics, desc: "missing support for basic literals with type params"},
163163
"typeparam/double.go": {category: generics, desc: "make() doesn't support generic slice types"},
164164
"typeparam/equal.go": {category: generics, desc: "missing support for the comparable type constraint"},
165165
"typeparam/fact.go": {category: generics, desc: "missing support for the comparable type constraint"},
@@ -168,13 +168,11 @@ var knownFails = map[string]failReason{
168168
"typeparam/index2.go": {category: generics, desc: "missing index operator support for generic types"},
169169
"typeparam/issue47258.go": {category: generics, desc: "missing operator support for generic types"},
170170
"typeparam/issue47716.go": {category: generics, desc: "unsafe.Sizeof() doesn't work with generic types"},
171-
"typeparam/issue48137.go": {category: generics, desc: "unsupported conversion from func() main.Bar to main.Bar"},
172171
"typeparam/issue48276a.go": {category: generics, desc: "missing support for the comparable type constraint"},
173172
"typeparam/issue48453.go": {category: generics, desc: "make() doesn't support generic slice types"},
174173
"typeparam/issue49295.go": {category: generics, desc: "len() doesn't support generic pointer to array types"},
175174
"typeparam/issue50193.go": {category: generics, desc: "invalid print format for complex numbers"},
176-
"typeparam/issue50833.go": {category: generics, desc: "unsupported conversion from *main.S to main.PS"},
177-
"typeparam/issue51303.go": {category: generics, desc: "missing support for conversion into a parameterized type"},
175+
"typeparam/issue51303.go": {category: generics, desc: "missing support for range over type parameter"},
178176
"typeparam/issue51522a.go": {category: generics, desc: "missing support for the comparable type constraint"},
179177
"typeparam/issue51522b.go": {category: generics, desc: "missing support for the comparable type constraint"},
180178
"typeparam/list.go": {category: generics, desc: "missing operator support for generic types"},

tests/js_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,6 @@ func TestReflection(t *testing.T) {
732732
s := S{o}
733733

734734
v := reflect.ValueOf(&s).Elem()
735-
println(v.Field(0).Interface())
736735
if got := v.Field(0).Interface().(*js.Object).Get("answer").Int(); got != 42 {
737736
t.Errorf("Got: Accessing JS object property via reflect.Value.Interface() returned %v. Want: 42.", got)
738737
}

tests/misc_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,3 +959,31 @@ func TestFileSetSize(t *testing.T) {
959959
t.Errorf("Got: unsafe.Sizeof(token.FileSet{}) %v, Want: %v", n2, n1)
960960
}
961961
}
962+
963+
func TestChanEquality(t *testing.T) {
964+
type ch chan string
965+
966+
ch1 := make(chan string)
967+
ch2 := make(ch)
968+
ch3 := ch(ch1)
969+
970+
t.Run("equal", func(t *testing.T) {
971+
if ch1 != ch3 {
972+
t.Errorf("Got: ch1 != ch3. Want: channels created by the same call to make are equal.")
973+
}
974+
if runtime.Compiler != "gopherjs" {
975+
t.Skip("https://github.com/golang/go/issues/63886")
976+
}
977+
if !reflect.DeepEqual(ch1, ch3) {
978+
t.Errorf("Got: reflect.DeepEqual(ch1, ch3) == false. Want: channels created by the same call to make are equal.")
979+
}
980+
})
981+
t.Run("not equal", func(t *testing.T) {
982+
if ch1 == ch2 {
983+
t.Errorf("Got: ch1 == ch2. Want: channels created by different calls to make are not equal.")
984+
}
985+
if reflect.DeepEqual(ch1, ch2) {
986+
t.Errorf("Got: reflect.DeepEqual(ch1, ch2) == true. Want: channels created by different calls to make are not equal.")
987+
}
988+
})
989+
}

0 commit comments

Comments
 (0)