slice, map, chan and func will not be set zero value, but pointer is zero value.
it will occur some package panic like net/http.Client
// code in src/net/http
func (c *Client) checkRedirect(req *Request, via []*Request) error {
fn := c.CheckRedirect
if fn == nil { // [error] in anko, this if is unexpected.
fn = defaultCheckRedirect
}
return fn(req, via)
}
func TestAnkoMakeHTTPClient(t *testing.T) {
e := env.NewEnv()
src := `
http = import("net/http")
// must 302
url = "http://example.com/302"
req, err = http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return false, err
}
client = new(http.Client)
resp, err = client.Do(req) // will return a nil pointer error
if err != nil {
return false, err
}
println(client.CheckRedirect == nil) // false
println(client.CheckRedirect) // invalid function
// ok
client.CheckRedirect = nil
resp, err = client.Do(req)
if err != nil {
return false, err
}
`
stmt, err := parser.ParseSrc(src)
require.NoError(t, err)
_, err = vm.Run(e, nil, stmt)
require.NoError(t, err)
}
file anko/vm/vm.go:
line 394:
func makeValue(t reflect.Type) (reflect.Value, error) {
switch t.Kind() {
case reflect.Chan:
return reflect.MakeChan(t, 0), nil
case reflect.Func:
return reflect.MakeFunc(t, nil), nil
case reflect.Map:
// note creating slice as work around to create map
// just doing MakeMap can give incorrect type for defined types
value := reflect.MakeSlice(reflect.SliceOf(t), 0, 1)
value = reflect.Append(value, reflect.MakeMap(reflect.MapOf(t.Key(), t.Elem())))
return value.Index(0), nil
case reflect.Ptr:
ptrV := reflect.New(t.Elem())
v, err := makeValue(t.Elem())
if err != nil {
return nilValue, err
}
ptrV.Elem().Set(v)
return ptrV, nil
case reflect.Slice:
return reflect.MakeSlice(t, 0, 0), nil
case reflect.Struct:
structV := reflect.New(t).Elem()
for i := 0; i < structV.NumField(); i++ {
// here Pointer will be zero value, but other type is not
if structV.Field(i).Kind() == reflect.Ptr {
continue
}
v, err := makeValue(structV.Field(i).Type())
if err != nil {
return nilValue, err
}
if structV.Field(i).CanSet() {
structV.Field(i).Set(v)
}
}
return structV, nil
// only this code is ok
// return reflect.New(t).Elem(), nil
}
return reflect.New(t).Elem(), nil
}
test code:
output:
file anko/vm/vm.go: