Description
Go 1.17 adds conversions from []T
to *[N]T
, including via the reflect package. Such conversions may panic if N is larger than the slice length. Whether reflection-based conversion is possible without panicking is thus now no longer a function only of the types involved. As a result, even if v.Type().ConvertibleTo(w.Type())
returns true, v.Convert(w.Type())
may panic. This is documented in package reflect.
database/sql/convert.go contains code that appears to rely on that now-broken invariant:
func convertAssignRows(dest, src interface{}, rows *Rows) error {
// ...
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
dv.Set(sv.Convert(dv.Type()))
return nil
}
// ...
}
(text/template has similar code, but it is guarded with a check that the types are int-like.)
This sv.Convert
call couldn't panic in 1.16; now it can.
What should we do here?
- (a) recover from the panic and return an error saying the conversion failed
- (b) panic
- (c) recover from the panic and continue as if the types weren't convertible
(a) seems like the clearest error output. (b) is simple. It also matches the handling in the standard library of reflect.Type.Comparable: In a few places, we check reflect.Type.Comparable and then blindly use ==
, even though that can panic. (c) most closely preserves the 1.16 behavior.
I lean towards (a) but would like to discuss. And if we do (a) or (c), should we give reflect.Type.Comparable/==
the same treatment?
Marking as a 1.17 release-blocker, pending a decision about severity and how we want to proceed.