mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
Fast-path for determining ability member impls for builtin opaques
This commit is contained in:
parent
297a571b34
commit
e6094df69b
8 changed files with 182 additions and 60 deletions
|
@ -78,24 +78,11 @@ impl FlatDecodable {
|
||||||
//
|
//
|
||||||
FlatType::Func(..) => Err(Underivable),
|
FlatType::Func(..) => Err(Underivable),
|
||||||
},
|
},
|
||||||
Content::Alias(sym, _, real_var, _) => match sym {
|
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
||||||
Symbol::BOOL_BOOL => Ok(Immediate(Symbol::DECODE_BOOL)),
|
Some(lambda) => Ok(lambda),
|
||||||
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Ok(Immediate(Symbol::DECODE_U8)),
|
|
||||||
Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Ok(Immediate(Symbol::DECODE_U16)),
|
|
||||||
Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Ok(Immediate(Symbol::DECODE_U32)),
|
|
||||||
Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => Ok(Immediate(Symbol::DECODE_U64)),
|
|
||||||
Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => Ok(Immediate(Symbol::DECODE_U128)),
|
|
||||||
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => Ok(Immediate(Symbol::DECODE_I8)),
|
|
||||||
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => Ok(Immediate(Symbol::DECODE_I16)),
|
|
||||||
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => Ok(Immediate(Symbol::DECODE_I32)),
|
|
||||||
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => Ok(Immediate(Symbol::DECODE_I64)),
|
|
||||||
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => Ok(Immediate(Symbol::DECODE_I128)),
|
|
||||||
Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Ok(Immediate(Symbol::DECODE_DEC)),
|
|
||||||
Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Ok(Immediate(Symbol::DECODE_F32)),
|
|
||||||
Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Ok(Immediate(Symbol::DECODE_F64)),
|
|
||||||
// NB: I believe it is okay to unwrap opaques here because derivers are only used
|
// NB: 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),
|
None => Self::from_var(subs, real_var),
|
||||||
},
|
},
|
||||||
Content::RangedNumber(range) => {
|
Content::RangedNumber(range) => {
|
||||||
Self::from_var(subs, range.default_compilation_variable())
|
Self::from_var(subs, range.default_compilation_variable())
|
||||||
|
@ -110,4 +97,29 @@ impl FlatDecodable {
|
||||||
Content::LambdaSet(_) => Err(Underivable),
|
Content::LambdaSet(_) => Err(Underivable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_builtin_symbol(symbol: Symbol) -> Result<FlatDecodable, DeriveError> {
|
||||||
|
from_builtin_symbol(symbol).ok_or(DeriveError::Underivable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn from_builtin_symbol(symbol: Symbol) -> Option<FlatDecodable> {
|
||||||
|
use FlatDecodable::*;
|
||||||
|
match symbol {
|
||||||
|
Symbol::BOOL_BOOL => Some(Immediate(Symbol::DECODE_BOOL)),
|
||||||
|
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Some(Immediate(Symbol::DECODE_U8)),
|
||||||
|
Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Some(Immediate(Symbol::DECODE_U16)),
|
||||||
|
Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Some(Immediate(Symbol::DECODE_U32)),
|
||||||
|
Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => Some(Immediate(Symbol::DECODE_U64)),
|
||||||
|
Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => Some(Immediate(Symbol::DECODE_U128)),
|
||||||
|
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => Some(Immediate(Symbol::DECODE_I8)),
|
||||||
|
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => Some(Immediate(Symbol::DECODE_I16)),
|
||||||
|
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => Some(Immediate(Symbol::DECODE_I32)),
|
||||||
|
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => Some(Immediate(Symbol::DECODE_I64)),
|
||||||
|
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => Some(Immediate(Symbol::DECODE_I128)),
|
||||||
|
Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Some(Immediate(Symbol::DECODE_DEC)),
|
||||||
|
Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Some(Immediate(Symbol::DECODE_F32)),
|
||||||
|
Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Some(Immediate(Symbol::DECODE_F64)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,22 +112,8 @@ impl FlatEncodable {
|
||||||
//
|
//
|
||||||
FlatType::Func(..) => Err(Underivable),
|
FlatType::Func(..) => Err(Underivable),
|
||||||
},
|
},
|
||||||
Content::Alias(sym, _, real_var, _) => match sym {
|
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
||||||
Symbol::BOOL_BOOL => Ok(Immediate(Symbol::ENCODE_BOOL)),
|
Some(lambda) => Ok(lambda),
|
||||||
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Ok(Immediate(Symbol::ENCODE_U8)),
|
|
||||||
Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Ok(Immediate(Symbol::ENCODE_U16)),
|
|
||||||
Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Ok(Immediate(Symbol::ENCODE_U32)),
|
|
||||||
Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => Ok(Immediate(Symbol::ENCODE_U64)),
|
|
||||||
Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => Ok(Immediate(Symbol::ENCODE_U128)),
|
|
||||||
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => Ok(Immediate(Symbol::ENCODE_I8)),
|
|
||||||
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => Ok(Immediate(Symbol::ENCODE_I16)),
|
|
||||||
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => Ok(Immediate(Symbol::ENCODE_I32)),
|
|
||||||
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => Ok(Immediate(Symbol::ENCODE_I64)),
|
|
||||||
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => Ok(Immediate(Symbol::ENCODE_I128)),
|
|
||||||
Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Ok(Immediate(Symbol::ENCODE_DEC)),
|
|
||||||
Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Ok(Immediate(Symbol::ENCODE_F32)),
|
|
||||||
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),
|
||||||
|
@ -145,4 +131,30 @@ impl FlatEncodable {
|
||||||
Content::LambdaSet(_) => Err(Underivable),
|
Content::LambdaSet(_) => Err(Underivable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_builtin_symbol(symbol: Symbol) -> Result<FlatEncodable, DeriveError> {
|
||||||
|
from_builtin_symbol(symbol).ok_or(DeriveError::Underivable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn from_builtin_symbol(symbol: Symbol) -> Option<FlatEncodable> {
|
||||||
|
use FlatEncodable::*;
|
||||||
|
match symbol {
|
||||||
|
Symbol::BOOL_BOOL => Some(Immediate(Symbol::ENCODE_BOOL)),
|
||||||
|
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 => Some(Immediate(Symbol::ENCODE_U8)),
|
||||||
|
Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 => Some(Immediate(Symbol::ENCODE_U16)),
|
||||||
|
Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 => Some(Immediate(Symbol::ENCODE_U32)),
|
||||||
|
Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 => Some(Immediate(Symbol::ENCODE_U64)),
|
||||||
|
Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 => Some(Immediate(Symbol::ENCODE_U128)),
|
||||||
|
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => Some(Immediate(Symbol::ENCODE_I8)),
|
||||||
|
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => Some(Immediate(Symbol::ENCODE_I16)),
|
||||||
|
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => Some(Immediate(Symbol::ENCODE_I32)),
|
||||||
|
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => Some(Immediate(Symbol::ENCODE_I64)),
|
||||||
|
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => Some(Immediate(Symbol::ENCODE_I128)),
|
||||||
|
Symbol::NUM_DEC | Symbol::NUM_DECIMAL => Some(Immediate(Symbol::ENCODE_DEC)),
|
||||||
|
Symbol::NUM_F32 | Symbol::NUM_BINARY32 => Some(Immediate(Symbol::ENCODE_F32)),
|
||||||
|
Symbol::NUM_F64 | Symbol::NUM_BINARY64 => Some(Immediate(Symbol::ENCODE_F64)),
|
||||||
|
Symbol::NUM_NAT | Symbol::NUM_NATURAL => None,
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,10 @@ impl FlatHash {
|
||||||
Content::LambdaSet(_) => Err(Underivable),
|
Content::LambdaSet(_) => Err(Underivable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_builtin_symbol(symbol: Symbol) -> Result<FlatHash, DeriveError> {
|
||||||
|
builtin_symbol_to_hash_lambda(symbol).ok_or(DeriveError::Underivable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn builtin_symbol_to_hash_lambda(symbol: Symbol) -> Option<FlatHash> {
|
const fn builtin_symbol_to_hash_lambda(symbol: Symbol) -> Option<FlatHash> {
|
||||||
|
|
|
@ -52,7 +52,7 @@ impl DeriveKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq, Debug)]
|
#[derive(Hash, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Derived {
|
pub enum Derived {
|
||||||
/// If a derived implementation name is well-known ahead-of-time, we can inline the symbol
|
/// If a derived implementation name is well-known ahead-of-time, we can inline the symbol
|
||||||
/// directly rather than associating a key for an implementation to be made later on.
|
/// directly rather than associating a key for an implementation to be made later on.
|
||||||
|
@ -123,4 +123,34 @@ impl Derived {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn builtin_with_builtin_symbol(
|
||||||
|
builtin: DeriveBuiltin,
|
||||||
|
symbol: Symbol,
|
||||||
|
) -> Result<Self, DeriveError> {
|
||||||
|
match builtin {
|
||||||
|
DeriveBuiltin::ToEncoder => match encoding::FlatEncodable::from_builtin_symbol(symbol)?
|
||||||
|
{
|
||||||
|
FlatEncodable::Immediate(imm) => Ok(Derived::Immediate(imm)),
|
||||||
|
FlatEncodable::Key(repr) => Ok(Derived::Key(DeriveKey::ToEncoder(repr))),
|
||||||
|
},
|
||||||
|
DeriveBuiltin::Decoder => match decoding::FlatDecodable::from_builtin_symbol(symbol)? {
|
||||||
|
FlatDecodable::Immediate(imm) => Ok(Derived::Immediate(imm)),
|
||||||
|
FlatDecodable::Key(repr) => Ok(Derived::Key(DeriveKey::Decoder(repr))),
|
||||||
|
},
|
||||||
|
DeriveBuiltin::Hash => match hash::FlatHash::from_builtin_symbol(symbol)? {
|
||||||
|
FlatHash::SingleLambdaSetImmediate(imm) => {
|
||||||
|
Ok(Derived::SingleLambdaSetImmediate(imm))
|
||||||
|
}
|
||||||
|
FlatHash::Key(repr) => Ok(Derived::Key(DeriveKey::Hash(repr))),
|
||||||
|
},
|
||||||
|
DeriveBuiltin::IsEq => {
|
||||||
|
// If obligation checking passes, we always lower derived implementations of `isEq`
|
||||||
|
// to the `Eq` low-level, to be fulfilled by the backends.
|
||||||
|
Ok(Derived::SingleLambdaSetImmediate(
|
||||||
|
Symbol::BOOL_STRUCTURAL_EQ,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5331,7 +5331,7 @@ pub fn with_hole<'a>(
|
||||||
|
|
||||||
let resolved_proc = match resolved_proc {
|
let resolved_proc = match resolved_proc {
|
||||||
Resolved::Specialization(symbol) => symbol,
|
Resolved::Specialization(symbol) => symbol,
|
||||||
Resolved::NeedsGenerated(_) => {
|
Resolved::Derive(_) => {
|
||||||
todo_abilities!("Generate impls for structural types")
|
todo_abilities!("Generate impls for structural types")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -5813,14 +5813,7 @@ fn late_resolve_ability_specialization<'a>(
|
||||||
|
|
||||||
match specialization {
|
match specialization {
|
||||||
Resolved::Specialization(symbol) => symbol,
|
Resolved::Specialization(symbol) => symbol,
|
||||||
Resolved::NeedsGenerated(var) => {
|
Resolved::Derive(derive_key) => {
|
||||||
let derive_key = roc_derive_key::Derived::builtin(
|
|
||||||
member.try_into().expect("derived symbols must be builtins"),
|
|
||||||
env.subs,
|
|
||||||
var,
|
|
||||||
)
|
|
||||||
.expect("specialization var not derivable!");
|
|
||||||
|
|
||||||
match derive_key {
|
match derive_key {
|
||||||
roc_derive_key::Derived::Immediate(imm)
|
roc_derive_key::Derived::Immediate(imm)
|
||||||
| roc_derive_key::Derived::SingleLambdaSetImmediate(imm) => {
|
| roc_derive_key::Derived::SingleLambdaSetImmediate(imm) => {
|
||||||
|
|
|
@ -4,8 +4,9 @@ use roc_collections::{VecMap, VecSet};
|
||||||
use roc_debug_flags::dbg_do;
|
use roc_debug_flags::dbg_do;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use roc_debug_flags::ROC_PRINT_UNDERIVABLE;
|
use roc_debug_flags::ROC_PRINT_UNDERIVABLE;
|
||||||
|
use roc_derive_key::Derived;
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_solve_problem::{
|
use roc_solve_problem::{
|
||||||
NotDerivableContext, NotDerivableDecode, NotDerivableEncode, NotDerivableEq, TypeError,
|
NotDerivableContext, NotDerivableDecode, NotDerivableEncode, NotDerivableEq, TypeError,
|
||||||
|
@ -1298,12 +1299,12 @@ pub fn type_implementing_specialization(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of trying to resolve an ability specialization.
|
/// Result of trying to resolve an ability specialization.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Resolved {
|
pub enum Resolved {
|
||||||
/// A user-defined specialization should be used.
|
/// A user-defined specialization should be used.
|
||||||
Specialization(Symbol),
|
Specialization(Symbol),
|
||||||
/// A specialization must be generated for the given type variable.
|
/// A specialization must be generated with the given derive key.
|
||||||
NeedsGenerated(Variable),
|
Derive(Derived),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An [`AbilityResolver`] is a shell of an abilities store that answers questions needed for
|
/// An [`AbilityResolver`] is a shell of an abilities store that answers questions needed for
|
||||||
|
@ -1346,6 +1347,13 @@ impl AbilityResolver for AbilitiesStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether this a module whose types' ability implementations should be checked via derive_key,
|
||||||
|
/// because they do not explicitly list ability implementations due to circular dependencies.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn builtin_module_with_unlisted_ability_impl(module_id: ModuleId) -> bool {
|
||||||
|
matches!(module_id, ModuleId::NUM | ModuleId::BOOL)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve_ability_specialization<R: AbilityResolver>(
|
pub fn resolve_ability_specialization<R: AbilityResolver>(
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
resolver: &R,
|
resolver: &R,
|
||||||
|
@ -1379,6 +1387,17 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
|
||||||
|
|
||||||
let resolved = match obligated {
|
let resolved = match obligated {
|
||||||
Obligated::Opaque(symbol) => {
|
Obligated::Opaque(symbol) => {
|
||||||
|
if builtin_module_with_unlisted_ability_impl(symbol.module_id()) {
|
||||||
|
let derive_key = roc_derive_key::Derived::builtin_with_builtin_symbol(
|
||||||
|
ability_member
|
||||||
|
.try_into()
|
||||||
|
.expect("derived symbols must be builtins"),
|
||||||
|
symbol,
|
||||||
|
)
|
||||||
|
.expect("specialization var not derivable!");
|
||||||
|
|
||||||
|
Resolved::Derive(derive_key)
|
||||||
|
} else {
|
||||||
let impl_key = roc_can::abilities::ImplKey {
|
let impl_key = roc_can::abilities::ImplKey {
|
||||||
opaque: symbol,
|
opaque: symbol,
|
||||||
ability_member,
|
ability_member,
|
||||||
|
@ -1390,12 +1409,23 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
|
||||||
}
|
}
|
||||||
// TODO this is not correct. We can replace `Resolved` with `MemberImpl` entirely,
|
// TODO this is not correct. We can replace `Resolved` with `MemberImpl` entirely,
|
||||||
// which will make this simpler.
|
// which will make this simpler.
|
||||||
roc_types::types::MemberImpl::Error => Resolved::Specialization(Symbol::UNDERSCORE),
|
roc_types::types::MemberImpl::Error => {
|
||||||
|
Resolved::Specialization(Symbol::UNDERSCORE)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Obligated::Adhoc(variable) => {
|
Obligated::Adhoc(variable) => {
|
||||||
// TODO: more rules need to be validated here, like is this a builtin ability?
|
let derive_key = roc_derive_key::Derived::builtin(
|
||||||
Resolved::NeedsGenerated(variable)
|
ability_member
|
||||||
|
.try_into()
|
||||||
|
.expect("derived symbols must be builtins"),
|
||||||
|
subs,
|
||||||
|
variable,
|
||||||
|
)
|
||||||
|
.expect("specialization var not derivable!");
|
||||||
|
|
||||||
|
Resolved::Derive(derive_key)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@ use roc_types::{
|
||||||
};
|
};
|
||||||
use roc_unify::unify::{unify, Env as UEnv, Mode, MustImplementConstraints};
|
use roc_unify::unify::{unify, Env as UEnv, Mode, MustImplementConstraints};
|
||||||
|
|
||||||
use crate::solve::{deep_copy_var_in, introduce, Pools};
|
use crate::{
|
||||||
|
ability::builtin_module_with_unlisted_ability_impl,
|
||||||
|
solve::{deep_copy_var_in, introduce, Pools},
|
||||||
|
};
|
||||||
|
|
||||||
/// What phase in the compiler is reaching out to specialize lambda sets?
|
/// What phase in the compiler is reaching out to specialize lambda sets?
|
||||||
/// This is important to distinguish subtle differences in the behavior of the solving algorithm.
|
/// This is important to distinguish subtle differences in the behavior of the solving algorithm.
|
||||||
|
@ -626,7 +629,7 @@ fn make_specialization_decision<P: Phase>(
|
||||||
use SpecializationTypeKey::*;
|
use SpecializationTypeKey::*;
|
||||||
match subs.get_content_without_compacting(var) {
|
match subs.get_content_without_compacting(var) {
|
||||||
Alias(opaque, _, _, AliasKind::Opaque)
|
Alias(opaque, _, _, AliasKind::Opaque)
|
||||||
if !matches!(opaque.module_id(), ModuleId::NUM | ModuleId::BOOL) =>
|
if !builtin_module_with_unlisted_ability_impl(opaque.module_id()) =>
|
||||||
{
|
{
|
||||||
if P::IS_LATE {
|
if P::IS_LATE {
|
||||||
SpecializeDecision::Specialize(Opaque(*opaque))
|
SpecializeDecision::Specialize(Opaque(*opaque))
|
||||||
|
|
|
@ -504,6 +504,25 @@ mod encode_immediate {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn bool() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" imports [Encode, Json] provides [main] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
when Str.fromUtf8 (Encode.toBytes Bool.false Json.toUtf8) is
|
||||||
|
Ok s -> s
|
||||||
|
_ -> "<bad>"
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
RocStr::from(r"false"),
|
||||||
|
RocStr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! num_immediate {
|
macro_rules! num_immediate {
|
||||||
($($num:expr, $typ:ident)*) => {$(
|
($($num:expr, $typ:ident)*) => {$(
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1001,6 +1020,25 @@ mod decode_immediate {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn bool() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" imports [Json] provides [main] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
when Str.toUtf8 "false" |> Decode.fromBytes Json.fromUtf8 is
|
||||||
|
Ok s -> s
|
||||||
|
_ -> Bool.true
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
bool
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! num_immediate {
|
macro_rules! num_immediate {
|
||||||
($($num:expr, $typ:ident)*) => {$(
|
($($num:expr, $typ:ident)*) => {$(
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue