diff --git a/unmarshaler.go b/unmarshaler.go index 418fc7c..b61a347 100644 --- a/unmarshaler.go +++ b/unmarshaler.go @@ -852,6 +852,9 @@ func (d *decoder) unmarshalDateTime(value *unstable.Node, v reflect.Value) error return err } + if v.Kind() != reflect.Interface && v.Type() != timeType { + return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("datetime", v.Type())) + } v.Set(reflect.ValueOf(dt)) return nil } @@ -862,14 +865,14 @@ func (d *decoder) unmarshalLocalDate(value *unstable.Node, v reflect.Value) erro return err } + if v.Kind() != reflect.Interface && v.Type() != timeType { + return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("local date", v.Type())) + } if v.Type() == timeType { - cast := ld.AsTime(time.Local) - v.Set(reflect.ValueOf(cast)) + v.Set(reflect.ValueOf(ld.AsTime(time.Local))) return nil } - v.Set(reflect.ValueOf(ld)) - return nil } @@ -883,6 +886,9 @@ func (d *decoder) unmarshalLocalTime(value *unstable.Node, v reflect.Value) erro return unstable.NewParserError(rest, "extra characters at the end of a local time") } + if v.Kind() != reflect.Interface { + return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("local time", v.Type())) + } v.Set(reflect.ValueOf(lt)) return nil } @@ -897,15 +903,14 @@ func (d *decoder) unmarshalLocalDateTime(value *unstable.Node, v reflect.Value) return unstable.NewParserError(rest, "extra characters at the end of a local date time") } + if v.Kind() != reflect.Interface && v.Type() != timeType { + return unstable.NewParserError(d.p.Raw(value.Raw), "%s", d.typeMismatchString("local datetime", v.Type())) + } if v.Type() == timeType { - cast := ldt.AsTime(time.Local) - - v.Set(reflect.ValueOf(cast)) + v.Set(reflect.ValueOf(ldt.AsTime(time.Local))) return nil } - v.Set(reflect.ValueOf(ldt)) - return nil } diff --git a/unmarshaler_test.go b/unmarshaler_test.go index 9f66483..3e3b2a3 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -4344,3 +4344,44 @@ value = "b" }, }, cfg) } + +func TestIssue1028(t *testing.T) { + // Datetime values assigned to incompatible types should return an error, + // not panic. + + type Item struct { + Name string `toml:"name"` + } + + type Config struct { + Items map[string]Item `toml:"items"` + } + + // Error: "cannot decode TOML datetime into struct field Config.Items of type map[string]Item" + t.Run("OffsetDateTime", func(t *testing.T) { + var c Config + err := toml.Unmarshal([]byte(`items = 2023-01-01T10:20:30Z`), &c) + assert.Error(t, err) + }) + + // Error: "cannot decode TOML local datetime into struct field Config.Items of type map[string]Item" + t.Run("LocalDateTime", func(t *testing.T) { + var c Config + err := toml.Unmarshal([]byte(`items = 2023-01-01T10:20:30`), &c) + assert.Error(t, err) + }) + + // Error: "cannot decode TOML local date into struct field Config.Items of type map[string]Item" + t.Run("LocalDate", func(t *testing.T) { + var c Config + err := toml.Unmarshal([]byte(`items = 2023-01-01`), &c) + assert.Error(t, err) + }) + + // Error: "cannot decode TOML local time into struct field Config.Items of type map[string]Item" + t.Run("LocalTime", func(t *testing.T) { + var c Config + err := toml.Unmarshal([]byte(`items = 10:20:30`), &c) + assert.Error(t, err) + }) +}