diff --git a/compiler/mono/src/expr.rs b/compiler/mono/src/expr.rs index 38cc5f2de9..f214420019 100644 --- a/compiler/mono/src/expr.rs +++ b/compiler/mono/src/expr.rs @@ -131,7 +131,12 @@ impl<'a> Expr<'a> { } } -fn from_can_num<'a>(subs: &Subs, var: Variable, num: i64) -> Expr<'a> { +enum IntOrFloat { + IntType, + FloatType, +} + +fn to_int_or_float<'a>(subs: &Subs, var: Variable) -> IntOrFloat { // TODO FIXME Investigate why both INT_INT and INT_INTEGER (and same with // FLOAT_FLOAT and FLOAT_FLOATINGPOINT) are necessary here. It should // be one or the other, but not both! The fact that both are necessary @@ -141,16 +146,16 @@ fn from_can_num<'a>(subs: &Subs, var: Variable, num: i64) -> Expr<'a> { match subs.get_without_compacting(var).content { Content::Alias(Symbol::INT_INT, args, _) | Content::Alias(Symbol::INT_INTEGER, args, _) => { debug_assert!(args.len() == 0); - Expr::Int(num) + IntOrFloat::IntType } Content::FlexVar(_) => { // If this was still a (Num *), assume compiling it to an Int - Expr::Int(num) + IntOrFloat::IntType } Content::Alias(Symbol::FLOAT_FLOAT, args, _) | Content::Alias(Symbol::FLOAT_FLOATINGPOINT, args, _) => { debug_assert!(args.len() == 0); - Expr::Float(num as f64) + IntOrFloat::FloatType } Content::Alias(Symbol::NUM_NUM, args, _) => { debug_assert!(args.len() == 1); @@ -158,21 +163,21 @@ fn from_can_num<'a>(subs: &Subs, var: Variable, num: i64) -> Expr<'a> { match subs.get_without_compacting(args[0].1).content { Content::Alias(Symbol::INT_INTEGER, args, _) => { debug_assert!(args.len() == 0); - Expr::Int(num) + IntOrFloat::IntType } Content::FlexVar(_) => { // If this was still a (Num *), assume compiling it to an Int - Expr::Int(num) + IntOrFloat::IntType } Content::Alias(Symbol::FLOAT_FLOATINGPOINT, args, _) => { debug_assert!(args.len() == 0); - Expr::Float(num as f64) + IntOrFloat::FloatType } Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => { debug_assert!(attr_args.len() == 2); // Recurse on the second argument - from_can_num(subs, attr_args[1], num) + to_int_or_float(subs, attr_args[1]) } other => panic!( "Unrecognized Num.Num alias type argument Content: {:?}", @@ -184,7 +189,7 @@ fn from_can_num<'a>(subs: &Subs, var: Variable, num: i64) -> Expr<'a> { debug_assert!(attr_args.len() == 2); // Recurse on the second argument - from_can_num(subs, attr_args[1], num) + to_int_or_float(subs, attr_args[1]) } other => panic!("Unrecognized Num type argument Content: {:?}", other), } @@ -200,7 +205,10 @@ fn from_can<'a>( use roc_can::pattern::Pattern::*; match can_expr { - Num(var, num) => from_can_num(env.subs, var, num), + Num(var, num) => match to_int_or_float(env.subs, var) { + IntOrFloat::IntType => Expr::Int(num), + IntOrFloat::FloatType => Expr::Float(num as f64), + }, Int(_, num) => Expr::Int(num), Float(_, num) => Expr::Float(num), Str(string) | BlockStr(string) => Expr::Str(env.arena.alloc(string)), @@ -564,6 +572,30 @@ fn from_can_when<'a>( let (loc_when_pat2, loc_else) = iter.next().unwrap(); match (&loc_when_pat1.value, &loc_when_pat2.value) { + (NumLiteral(var, num), NumLiteral(_, _)) | (NumLiteral(var, num), Underscore) => { + let cond_lhs = arena.alloc(from_can(env, loc_cond.value, procs, None)); + let (builtin, cond_rhs_expr) = match to_int_or_float(env.subs, *var) { + IntOrFloat::IntType => (Builtin::Int64, Expr::Int(*num)), + IntOrFloat::FloatType => (Builtin::Float64, Expr::Float(*num as f64)), + }; + + let cond_rhs = arena.alloc(cond_rhs_expr); + let pass = arena.alloc(from_can(env, loc_then.value, procs, None)); + let fail = arena.alloc(from_can(env, loc_else.value, procs, None)); + let ret_layout = + Layout::from_var(arena, expr_var, env.subs).unwrap_or_else(|err| { + panic!("TODO turn this into a RuntimeError {:?}", err) + }); + + Expr::Cond { + cond_layout: Layout::Builtin(builtin), + cond_lhs, + cond_rhs, + pass, + fail, + ret_layout, + } + } (IntLiteral(int), IntLiteral(_)) | (IntLiteral(int), Underscore) => { let cond_lhs = arena.alloc(from_can(env, loc_cond.value, procs, None)); let cond_rhs = arena.alloc(Expr::Int(*int));