mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
Fix ScanToGo's error message when ptr points to an interface.
When the destination to scan into is an interface, its zero value is simply a nil interface, losing the information of the original type and resulting in error messages like "need nil, got $actual-type". ScanToGo now handles this case specifically, and uses the string representation of the interface type in the error message. Before: ~> ns [] Exception: wrong type of argument 0: wrong type: need nil, got list ~> var x~ = x Exception: wrong type: need nil, got string After: ~> ns [] Exception: wrong type of argument 0: wrong type: need !!hashmap.Map, got list ~> var x~ = x Exception: wrong type: need !!eval.Callable, got string This is still not ideal, since the "need" type is not given as an Elvish "kind", but it's much less confusing than than old "need nil" messages. This fixes #715.
This commit is contained in:
parent
82dda13def
commit
ab88de7c15
|
@ -94,7 +94,13 @@ func ScanToGo(src interface{}, ptr interface{}) error {
|
|||
}
|
||||
dstType := ptrType.Elem()
|
||||
if !TypeOf(src).AssignableTo(dstType) {
|
||||
return wrongType{Kind(reflect.Zero(dstType).Interface()), Kind(src)}
|
||||
var dstKind string
|
||||
if dstType.Kind() == reflect.Interface {
|
||||
dstKind = "!!" + dstType.String()
|
||||
} else {
|
||||
dstKind = Kind(reflect.Zero(dstType).Interface())
|
||||
}
|
||||
return wrongType{dstKind, Kind(src)}
|
||||
}
|
||||
ValueOf(ptr).Elem().Set(ValueOf(src))
|
||||
return nil
|
||||
|
|
|
@ -12,17 +12,17 @@ type someType struct {
|
|||
foo string
|
||||
}
|
||||
|
||||
// A wrapper around ScanToGo, to make it easier to test. Instead of supplying a
|
||||
// pointer to the destination, an initial value to the destination is supplied
|
||||
// and the result is returned.
|
||||
func scanToGo2(src interface{}, dstInit interface{}) (interface{}, error) {
|
||||
ptr := reflect.New(TypeOf(dstInit))
|
||||
err := ScanToGo(src, ptr.Interface())
|
||||
return ptr.Elem().Interface(), err
|
||||
}
|
||||
func TestScanToGo_ConcreteTypeDst(t *testing.T) {
|
||||
// A wrapper around ScanToGo, to make it easier to test. Instead of
|
||||
// supplying a pointer to the destination, an initial value to the
|
||||
// destination is supplied and the result is returned.
|
||||
scanToGo := func(src interface{}, dstInit interface{}) (interface{}, error) {
|
||||
ptr := reflect.New(TypeOf(dstInit))
|
||||
err := ScanToGo(src, ptr.Interface())
|
||||
return ptr.Elem().Interface(), err
|
||||
}
|
||||
|
||||
func TestScanToGo(t *testing.T) {
|
||||
Test(t, Fn("ScanToGo", scanToGo2), Table{
|
||||
Test(t, Fn("ScanToGo", scanToGo), Table{
|
||||
// int
|
||||
Args("12", 0).Rets(12),
|
||||
Args("0x12", 0).Rets(0x12),
|
||||
|
@ -40,8 +40,6 @@ func TestScanToGo(t *testing.T) {
|
|||
Args(someType{}, 0.0).Rets(Any, errMustBeNumber),
|
||||
Args("x", 0.0).Rets(Any, cannotParseAs{"number", "x"}),
|
||||
|
||||
// Num is tested below
|
||||
|
||||
// rune
|
||||
Args("x", ' ').Rets('x'),
|
||||
Args(someType{}, ' ').Rets(Any, errMustBeString),
|
||||
|
@ -56,14 +54,14 @@ func TestScanToGo(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func scanToGoNum(src interface{}) (Num, error) {
|
||||
var n Num
|
||||
err := ScanToGo(src, &n)
|
||||
return n, err
|
||||
}
|
||||
func TestScanToGo_NumDst(t *testing.T) {
|
||||
scanToGo := func(src interface{}) (Num, error) {
|
||||
var n Num
|
||||
err := ScanToGo(src, &n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func TestScanToGo_Num(t *testing.T) {
|
||||
Test(t, Fn("ScanToGo", scanToGoNum), Table{
|
||||
Test(t, Fn("ScanToGo", scanToGo), Table{
|
||||
// Strings are automatically converted
|
||||
Args("12").Rets(12),
|
||||
Args(z).Rets(bigInt(z)),
|
||||
|
@ -74,6 +72,23 @@ func TestScanToGo_Num(t *testing.T) {
|
|||
Args(bigInt(z)).Rets(bigInt(z)),
|
||||
Args(big.NewRat(1, 2)).Rets(big.NewRat(1, 2)),
|
||||
Args(12.0).Rets(12.0),
|
||||
|
||||
Args("bad").Rets(Any, cannotParseAs{"number", "bad"}),
|
||||
Args(EmptyList).Rets(Any, errMustBeNumber),
|
||||
})
|
||||
}
|
||||
|
||||
func TestScanToGo_InterfaceDst(t *testing.T) {
|
||||
scanToGo := func(src interface{}) (interface{}, error) {
|
||||
var l List
|
||||
err := ScanToGo(src, &l)
|
||||
return l, err
|
||||
}
|
||||
|
||||
Test(t, Fn("ScanToGo", scanToGo), Table{
|
||||
Args(EmptyList).Rets(EmptyList),
|
||||
|
||||
Args("foo").Rets(Any, wrongType{"!!vector.Vector", "string"}),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user