func unpackOneArg()

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
}