mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Record with optionally-typed fields cannot be derived for decoding
This commit is contained in:
parent
958f64c8fc
commit
d2b9cc056f
2 changed files with 64 additions and 7 deletions
|
@ -6,8 +6,10 @@ use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_solve_problem::{TypeError, UnderivableReason, Unfulfilled};
|
use roc_solve_problem::{TypeError, UnderivableReason, Unfulfilled};
|
||||||
use roc_types::num::NumericRange;
|
use roc_types::num::NumericRange;
|
||||||
use roc_types::subs::{instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, Subs, Variable};
|
use roc_types::subs::{
|
||||||
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory};
|
instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, Variable,
|
||||||
|
};
|
||||||
|
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory, RecordField};
|
||||||
use roc_unify::unify::{Env, MustImplementConstraints};
|
use roc_unify::unify::{Env, MustImplementConstraints};
|
||||||
use roc_unify::unify::{MustImplementAbility, Obligated};
|
use roc_unify::unify::{MustImplementAbility, Obligated};
|
||||||
|
|
||||||
|
@ -476,7 +478,11 @@ trait DerivableVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_record(var: Variable) -> Result<Descend, DerivableError> {
|
fn visit_record(
|
||||||
|
_subs: &Subs,
|
||||||
|
var: Variable,
|
||||||
|
_fields: RecordFields,
|
||||||
|
) -> Result<Descend, DerivableError> {
|
||||||
Err(DerivableError::NotDerivable(var))
|
Err(DerivableError::NotDerivable(var))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,7 +580,7 @@ trait DerivableVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Record(fields, ext) => {
|
Record(fields, ext) => {
|
||||||
let descend = Self::visit_record(var)?;
|
let descend = Self::visit_record(subs, var, fields)?;
|
||||||
if descend.0 {
|
if descend.0 {
|
||||||
push_var_slice!(fields.variables());
|
push_var_slice!(fields.variables());
|
||||||
if !matches!(
|
if !matches!(
|
||||||
|
@ -682,7 +688,11 @@ impl DerivableVisitor for DeriveEncoding {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_record(_var: Variable) -> Result<Descend, DerivableError> {
|
fn visit_record(
|
||||||
|
_subs: &Subs,
|
||||||
|
_var: Variable,
|
||||||
|
_fields: RecordFields,
|
||||||
|
) -> Result<Descend, DerivableError> {
|
||||||
Ok(Descend(true))
|
Ok(Descend(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,8 +763,21 @@ impl DerivableVisitor for DeriveDecoding {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_record(_var: Variable) -> Result<Descend, DerivableError> {
|
fn visit_record(
|
||||||
Ok(Descend(true))
|
subs: &Subs,
|
||||||
|
var: Variable,
|
||||||
|
fields: RecordFields,
|
||||||
|
) -> Result<Descend, DerivableError> {
|
||||||
|
let has_optional_field = subs
|
||||||
|
.get_subs_slice(fields.record_fields())
|
||||||
|
.iter()
|
||||||
|
.any(|field| matches!(field, RecordField::Optional(..)));
|
||||||
|
|
||||||
|
if has_optional_field {
|
||||||
|
Err(DerivableError::NotDerivable(var))
|
||||||
|
} else {
|
||||||
|
Ok(Descend(true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -10507,4 +10507,38 @@ All branches in an `if` must have the same type!
|
||||||
Note: `Decoding` cannot be generated for functions.
|
Note: `Decoding` cannot be generated for functions.
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
record_with_optional_field_types_cannot_derive_decoding,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" imports [Decode.{Decoder, DecoderFormatting, decoder}] provides [main] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
myDecoder : Decoder {x : Str, y ? Str} fmt | fmt has DecoderFormatting
|
||||||
|
myDecoder = decoder
|
||||||
|
|
||||||
|
myDecoder
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
This expression has a type that does not implement the abilities it's expected to:
|
||||||
|
|
||||||
|
5│ myDecoder = decoder
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
Roc can't generate an implementation of the `Decode.Decoding` ability
|
||||||
|
for
|
||||||
|
|
||||||
|
{ x : Str, y ? Str }
|
||||||
|
|
||||||
|
Note: I can't derive decoding for a record with an optional field,
|
||||||
|
which in this case is `.y`. Optional record fields are polymorphic over
|
||||||
|
records that may or may not contain them at compile time, but are not
|
||||||
|
a concept that extends to runtime!
|
||||||
|
Maybe you wanted to use a `Result`?
|
||||||
|
"###
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue