in starlark/unpack.go [217:312]
func unpackOneArg(v Value, ptr interface{}) error {
// On failure, don't clobber *ptr.
switch ptr := ptr.(type) {
case Unpacker:
return ptr.Unpack(v)
case *Value:
*ptr = v
case *string:
s, ok := AsString(v)
if !ok {
return fmt.Errorf("got %s, want string", v.Type())
}
*ptr = s
case *bool:
b, ok := v.(Bool)
if !ok {
return fmt.Errorf("got %s, want bool", v.Type())
}
*ptr = bool(b)
case *int, *int8, *int16, *int32, *int64,
*uint, *uint8, *uint16, *uint32, *uint64, *uintptr:
return AsInt(v, ptr)
case *float64:
f, ok := v.(Float)
if !ok {
return fmt.Errorf("got %s, want float", v.Type())
}
*ptr = float64(f)
case **List:
list, ok := v.(*List)
if !ok {
return fmt.Errorf("got %s, want list", v.Type())
}
*ptr = list
case **Dict:
dict, ok := v.(*Dict)
if !ok {
return fmt.Errorf("got %s, want dict", v.Type())
}
*ptr = dict
case *Callable:
f, ok := v.(Callable)
if !ok {
return fmt.Errorf("got %s, want callable", v.Type())
}
*ptr = f
case *Iterable:
it, ok := v.(Iterable)
if !ok {
return fmt.Errorf("got %s, want iterable", v.Type())
}
*ptr = it
default:
// v must have type *V, where V is some subtype of starlark.Value.
ptrv := reflect.ValueOf(ptr)
if ptrv.Kind() != reflect.Ptr {
log.Panicf("internal error: not a pointer: %T", ptr)
}
paramVar := ptrv.Elem()
if !reflect.TypeOf(v).AssignableTo(paramVar.Type()) {
// The value is not assignable to the variable.
// Detect a possible bug in the Go program that called Unpack:
// If the variable *ptr is not a subtype of Value,
// no value of v can possibly work.
if !paramVar.Type().AssignableTo(reflect.TypeOf(new(Value)).Elem()) {
log.Panicf("pointer element type does not implement Value: %T", ptr)
}
// Report Starlark dynamic type error.
//
// We prefer the Starlark Value.Type name over
// its Go reflect.Type name, but calling the
// Value.Type method on the variable is not safe
// in general. If the variable is an interface,
// the call will fail. Even if the variable has
// a concrete type, it might not be safe to call
// Type() on a zero instance. Thus we must use
// recover.
// Default to Go reflect.Type name
paramType := paramVar.Type().String()
// Attempt to call Value.Type method.
func() {
defer func() { recover() }()
if typer, _ := paramVar.Interface().(interface{ Type() string }); typer != nil {
paramType = typer.Type()
}
}()
return fmt.Errorf("got %s, want %s", v.Type(), paramType)
}
paramVar.Set(reflect.ValueOf(v))
}
return nil
}