mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
No Encode/Decode for Nat
This commit is contained in:
parent
99050956d3
commit
572a666780
5 changed files with 131 additions and 14 deletions
|
@ -126,6 +126,7 @@ impl FlatEncodable {
|
||||||
Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Ok(Immediate(Symbol::ENCODE_DEC)),
|
Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Ok(Immediate(Symbol::ENCODE_DEC)),
|
||||||
Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Ok(Immediate(Symbol::ENCODE_F32)),
|
Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Ok(Immediate(Symbol::ENCODE_F32)),
|
||||||
Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Ok(Immediate(Symbol::ENCODE_F64)),
|
Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Ok(Immediate(Symbol::ENCODE_F64)),
|
||||||
|
Symbol::NUM_NAT | Symbol::NUM_NATURAL => Err(Underivable),
|
||||||
// TODO: I believe it is okay to unwrap opaques here because derivers are only used
|
// TODO: I believe it is okay to unwrap opaques here because derivers are only used
|
||||||
// by the backend, and the backend treats opaques like structural aliases.
|
// by the backend, and the backend treats opaques like structural aliases.
|
||||||
_ => Self::from_var(subs, real_var),
|
_ => Self::from_var(subs, real_var),
|
||||||
|
|
|
@ -8,8 +8,8 @@ use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_solve_problem::{
|
use roc_solve_problem::{
|
||||||
NotDerivableContext, NotDerivableDecode, NotDerivableEq, TypeError, UnderivableReason,
|
NotDerivableContext, NotDerivableDecode, NotDerivableEncode, NotDerivableEq, TypeError,
|
||||||
Unfulfilled,
|
UnderivableReason, Unfulfilled,
|
||||||
};
|
};
|
||||||
use roc_types::num::NumericRange;
|
use roc_types::num::NumericRange;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
|
@ -451,9 +451,9 @@ impl ObligationCache {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn is_builtin_int_alias(symbol: Symbol) -> bool {
|
fn is_builtin_fixed_int_alias(symbol: Symbol) -> bool {
|
||||||
matches!(symbol,
|
matches!(symbol,
|
||||||
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8
|
| Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8
|
||||||
| Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16
|
| Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16
|
||||||
| Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32
|
| Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32
|
||||||
| Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64
|
| Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64
|
||||||
|
@ -463,6 +463,13 @@ fn is_builtin_int_alias(symbol: Symbol) -> bool {
|
||||||
| Symbol::NUM_I32 | Symbol::NUM_SIGNED32
|
| Symbol::NUM_I32 | Symbol::NUM_SIGNED32
|
||||||
| Symbol::NUM_I64 | Symbol::NUM_SIGNED64
|
| Symbol::NUM_I64 | Symbol::NUM_SIGNED64
|
||||||
| Symbol::NUM_I128 | Symbol::NUM_SIGNED128
|
| Symbol::NUM_I128 | Symbol::NUM_SIGNED128
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[rustfmt::skip]
|
||||||
|
fn is_builtin_nat_alias(symbol: Symbol) -> bool {
|
||||||
|
matches!(symbol,
|
||||||
| Symbol::NUM_NAT | Symbol::NUM_NATURAL
|
| Symbol::NUM_NAT | Symbol::NUM_NATURAL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -487,7 +494,7 @@ fn is_builtin_dec_alias(symbol: Symbol) -> bool {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
fn is_builtin_number_alias(symbol: Symbol) -> bool {
|
fn is_builtin_number_alias(symbol: Symbol) -> bool {
|
||||||
is_builtin_int_alias(symbol) || is_builtin_float_alias(symbol) || is_builtin_dec_alias(symbol)
|
is_builtin_fixed_int_alias(symbol) || is_builtin_nat_alias(symbol) || is_builtin_float_alias(symbol) || is_builtin_dec_alias(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NotDerivable {
|
struct NotDerivable {
|
||||||
|
@ -826,7 +833,7 @@ impl DerivableVisitor for DeriveEncoding {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||||
is_builtin_number_alias(symbol)
|
is_builtin_number_alias(symbol) && !is_builtin_nat_alias(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -884,9 +891,16 @@ impl DerivableVisitor for DeriveEncoding {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_alias(_var: Variable, symbol: Symbol) -> Result<Descend, NotDerivable> {
|
fn visit_alias(var: Variable, symbol: Symbol) -> Result<Descend, NotDerivable> {
|
||||||
if is_builtin_number_alias(symbol) {
|
if is_builtin_number_alias(symbol) {
|
||||||
Ok(Descend(false))
|
if is_builtin_nat_alias(symbol) {
|
||||||
|
Err(NotDerivable {
|
||||||
|
var,
|
||||||
|
context: NotDerivableContext::Encode(NotDerivableEncode::Nat),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(Descend(false))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Descend(true))
|
Ok(Descend(true))
|
||||||
}
|
}
|
||||||
|
@ -914,7 +928,7 @@ impl DerivableVisitor for DeriveDecoding {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||||
is_builtin_number_alias(symbol)
|
is_builtin_number_alias(symbol) && !is_builtin_nat_alias(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -983,9 +997,16 @@ impl DerivableVisitor for DeriveDecoding {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn visit_alias(_var: Variable, symbol: Symbol) -> Result<Descend, NotDerivable> {
|
fn visit_alias(var: Variable, symbol: Symbol) -> Result<Descend, NotDerivable> {
|
||||||
if is_builtin_number_alias(symbol) {
|
if is_builtin_number_alias(symbol) {
|
||||||
Ok(Descend(false))
|
if is_builtin_nat_alias(symbol) {
|
||||||
|
Err(NotDerivable {
|
||||||
|
var,
|
||||||
|
context: NotDerivableContext::Decode(NotDerivableDecode::Nat),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(Descend(false))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Descend(true))
|
Ok(Descend(true))
|
||||||
}
|
}
|
||||||
|
@ -1112,7 +1133,9 @@ impl DerivableVisitor for DeriveEq {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
fn is_derivable_builtin_opaque(symbol: Symbol) -> bool {
|
||||||
is_builtin_int_alias(symbol) || is_builtin_dec_alias(symbol)
|
is_builtin_fixed_int_alias(symbol)
|
||||||
|
|| is_builtin_nat_alias(symbol)
|
||||||
|
|| is_builtin_dec_alias(symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -87,12 +87,19 @@ pub enum NotDerivableContext {
|
||||||
Function,
|
Function,
|
||||||
UnboundVar,
|
UnboundVar,
|
||||||
Opaque(Symbol),
|
Opaque(Symbol),
|
||||||
|
Encode(NotDerivableEncode),
|
||||||
Decode(NotDerivableDecode),
|
Decode(NotDerivableDecode),
|
||||||
Eq(NotDerivableEq),
|
Eq(NotDerivableEq),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
|
pub enum NotDerivableEncode {
|
||||||
|
Nat,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||||
pub enum NotDerivableDecode {
|
pub enum NotDerivableDecode {
|
||||||
|
Nat,
|
||||||
OptionalRecordField(Lowercase),
|
OptionalRecordField(Lowercase),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ use roc_module::symbol::Symbol;
|
||||||
use roc_problem::Severity;
|
use roc_problem::Severity;
|
||||||
use roc_region::all::{LineInfo, Region};
|
use roc_region::all::{LineInfo, Region};
|
||||||
use roc_solve_problem::{
|
use roc_solve_problem::{
|
||||||
NotDerivableContext, NotDerivableDecode, NotDerivableEq, TypeError, UnderivableReason,
|
NotDerivableContext, NotDerivableDecode, NotDerivableEncode, NotDerivableEq, TypeError,
|
||||||
Unfulfilled,
|
UnderivableReason, Unfulfilled,
|
||||||
};
|
};
|
||||||
use roc_std::RocDec;
|
use roc_std::RocDec;
|
||||||
use roc_types::pretty_print::{Parens, WILDCARD};
|
use roc_types::pretty_print::{Parens, WILDCARD};
|
||||||
|
@ -371,7 +371,29 @@ fn underivable_hint<'b>(
|
||||||
])),
|
])),
|
||||||
])))
|
])))
|
||||||
}
|
}
|
||||||
|
NotDerivableContext::Encode(reason) => match reason {
|
||||||
|
NotDerivableEncode::Nat => {
|
||||||
|
Some(alloc.note("").append(alloc.concat([
|
||||||
|
alloc.reflow("Encoding a "),
|
||||||
|
alloc.type_str("Nat"),
|
||||||
|
alloc.reflow(" is not supported. Consider using a fixed-sized unsigned integer, like a "),
|
||||||
|
alloc.type_str("U64"),
|
||||||
|
alloc.reflow("instead."),
|
||||||
|
])))
|
||||||
|
}
|
||||||
|
},
|
||||||
NotDerivableContext::Decode(reason) => match reason {
|
NotDerivableContext::Decode(reason) => match reason {
|
||||||
|
NotDerivableDecode::Nat => {
|
||||||
|
Some(alloc.note("").append(alloc.concat([
|
||||||
|
alloc.reflow("Decoding to a "),
|
||||||
|
alloc.type_str("Nat"),
|
||||||
|
alloc.reflow(" is not supported. Consider decoding to a fixed-sized unsigned integer, like "),
|
||||||
|
alloc.type_str("U64"),
|
||||||
|
alloc.reflow(", then converting to a "),
|
||||||
|
alloc.type_str("Nat"),
|
||||||
|
alloc.reflow(" if needed."),
|
||||||
|
])))
|
||||||
|
}
|
||||||
NotDerivableDecode::OptionalRecordField(field) => {
|
NotDerivableDecode::OptionalRecordField(field) => {
|
||||||
Some(alloc.note("").append(alloc.concat([
|
Some(alloc.note("").append(alloc.concat([
|
||||||
alloc.reflow("I can't derive decoding for a record with an optional field, which in this case is "),
|
alloc.reflow("I can't derive decoding for a record with an optional field, which in this case is "),
|
||||||
|
|
|
@ -13028,4 +13028,68 @@ I recommend using camelCase. It's the standard style in Roc code!
|
||||||
"#
|
"#
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
derive_decoding_for_nat,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" imports [Decode.{decoder}] provides [main] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
myDecoder : Decoder Nat 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
|
||||||
|
^^^^^^^
|
||||||
|
|
||||||
|
I can't generate an implementation of the `Decoding` ability for
|
||||||
|
|
||||||
|
Nat
|
||||||
|
|
||||||
|
Note: Decoding to a Nat is not supported. Consider decoding to a
|
||||||
|
fixed-sized unsigned integer, like U64, then converting to a Nat if
|
||||||
|
needed.
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
derive_encoding_for_nat,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" imports [] provides [main] to "./platform"
|
||||||
|
|
||||||
|
x : Nat
|
||||||
|
|
||||||
|
main = Encode.toEncoder x
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
This expression has a type that does not implement the abilities it's expected to:
|
||||||
|
|
||||||
|
5│ main = Encode.toEncoder x
|
||||||
|
^
|
||||||
|
|
||||||
|
I can't generate an implementation of the `Encoding` ability for
|
||||||
|
|
||||||
|
Int Natural
|
||||||
|
|
||||||
|
In particular, an implementation for
|
||||||
|
|
||||||
|
Natural
|
||||||
|
|
||||||
|
cannot be generated.
|
||||||
|
|
||||||
|
Tip: `Natural` does not implement `Encoding`.
|
||||||
|
"###
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue