@@ -1104,22 +1104,54 @@ func (fc *funcContext) translateExprSlice(exprs []ast.Expr, desiredType types.Ty
11041104 return parts
11051105}
11061106
1107+ // packageAllowsKindTypeConversion determines if the current package should
1108+ // be checked for a special type of casts, `kindType` or `kindTypeExt` conversions.
1109+ func (fc * funcContext ) packageAllowsKindTypeConversion () bool {
1110+ switch fc .pkgCtx .Pkg .Path () {
1111+ case `internal/abi` , `internal/reflectlite` , `reflect` :
1112+ return true
1113+ }
1114+ return false
1115+ }
1116+
11071117func (fc * funcContext ) translateConversion (expr ast.Expr , desiredType types.Type ) * expression {
11081118 exprType := fc .typeOf (expr )
11091119 if types .Identical (exprType , desiredType ) {
11101120 return fc .translateExpr (expr )
11111121 }
11121122
1113- if fc .pkgCtx .Pkg .Path () == "reflect" || fc .pkgCtx .Pkg .Path () == "internal/reflectlite" {
1123+ // For some specific packages, e.g. reflect, the Go code performs casts between different sized memory footprints
1124+ // and leverages the fact that the pointer to the first field is the same as the pointer to the full struct in Go.
1125+ // These conversions are normally not allowed by GopherJS. However, in those specific packages, the original code
1126+ // does this kind of cast so often, that to avoid them would cause massive amounts of native overrides.
1127+ // To simplify the native overrides we will allow casts between specific types for specific packages by looking up
1128+ // the `kindType` that is assigned when creating them.
1129+ //
1130+ // Given the structure `type K struct{T; additional fields}` the untyped pointer to `K` is also the untyped pointer
1131+ // to the first field, i.e. `T`. An example of this is `abi.MapType` with `abi.Type` as its first field.
1132+ // These packages will hold onto `t *T` then cast to the kind type with `k = (*K)unsafe.Pointer(t)`.
1133+ // Normally this isn't allowed in JS because `K` is larger with additional fields, but when we created `t` in the
1134+ // native overrides, we assign `k` as the `t.kindType` then we translate those specific casts to get that `kindType`,
1135+ // thus greatly reducing the amount of overrides we have to add to those packages.
1136+ if fc .packageAllowsKindTypeConversion () {
11141137 if call , isCall := expr .(* ast.CallExpr ); isCall && types .Identical (fc .typeOf (call .Fun ), types .Typ [types .UnsafePointer ]) {
11151138 if ptr , isPtr := desiredType .(* types.Pointer ); isPtr {
11161139 if named , isNamed := ptr .Elem ().(* types.Named ); isNamed {
1117- switch named .Obj ().Name () {
1118- case "arrayType" , "chanType" , "funcType" , "interfaceType" , "mapType" , "ptrType" , "sliceType" , "structType" :
1119- return fc .formatExpr ("%e.kindType" , call .Args [0 ]) // unsafe conversion
1120- default :
1121- return fc .translateExpr (expr )
1140+ switch named .Obj ().Pkg ().Path () {
1141+ case `internal/abi` :
1142+ switch named .Obj ().Name () {
1143+ case `ArrayType` , `ChanType` , `FuncType` , `InterfaceType` , `MapType` , `PtrType` , `SliceType` , `StructType` :
1144+ return fc .formatExpr ("%e.kindType" , call .Args [0 ]) // unsafe conversion
1145+ }
1146+ case `reflect` :
1147+ switch named .Obj ().Name () {
1148+ // The following are extensions of the ABI equivalent type to add more methods.
1149+ // e.g. `type structType struct { abi.StructType }`.
1150+ case `interfaceType` , `mapType` , `ptrType` , `sliceType` , `structType` :
1151+ return fc .formatExpr ("toKindTypeExt(%e)" , call .Args [0 ]) // unsafe conversion
1152+ }
11221153 }
1154+ return fc .translateExpr (expr )
11231155 }
11241156 }
11251157 }
0 commit comments