diff --git a/compiler/constrain/src/builtins.rs b/compiler/constrain/src/builtins.rs index 9f1b4c918d..aa957729a2 100644 --- a/compiler/constrain/src/builtins.rs +++ b/compiler/constrain/src/builtins.rs @@ -267,47 +267,53 @@ pub trait TypedNumericBound { fn bounded_range(&self) -> Vec; } +const fn int_width_to_variable(w: IntWidth) -> Variable { + match w { + IntWidth::U8 => Variable::U8, + IntWidth::U16 => Variable::U16, + IntWidth::U32 => Variable::U32, + IntWidth::U64 => Variable::U64, + IntWidth::U128 => Variable::U128, + IntWidth::I8 => Variable::I8, + IntWidth::I16 => Variable::I16, + IntWidth::I32 => Variable::I32, + IntWidth::I64 => Variable::I64, + IntWidth::I128 => Variable::I128, + IntWidth::Nat => Variable::NAT, + } +} + +const NO_DEMAND_INT_VARIABLES: &[(IntWidth, Variable)] = &[ + (IntWidth::I8, Variable::I8), + (IntWidth::U8, Variable::U8), + (IntWidth::I16, Variable::I16), + (IntWidth::U16, Variable::U16), + (IntWidth::I32, Variable::I32), + (IntWidth::U32, Variable::U32), + (IntWidth::I64, Variable::I64), + (IntWidth::Nat, Variable::NAT), // FIXME: Nat's order here depends on the platform! + (IntWidth::U64, Variable::U64), + (IntWidth::I128, Variable::I128), + (IntWidth::U128, Variable::U128), +]; + +const SIGNED_INT_VARIABLES: &[(IntWidth, Variable)] = &[ + (IntWidth::I8, Variable::I8), + (IntWidth::I16, Variable::I16), + (IntWidth::I32, Variable::I32), + (IntWidth::I64, Variable::I64), + (IntWidth::I128, Variable::I128), +]; + impl TypedNumericBound for IntBound { fn bounded_range(&self) -> Vec { match self { IntBound::None => vec![], - IntBound::Exact(w) => vec![match w { - IntWidth::U8 => Variable::U8, - IntWidth::U16 => Variable::U16, - IntWidth::U32 => Variable::U32, - IntWidth::U64 => Variable::U64, - IntWidth::U128 => Variable::U128, - IntWidth::I8 => Variable::I8, - IntWidth::I16 => Variable::I16, - IntWidth::I32 => Variable::I32, - IntWidth::I64 => Variable::I64, - IntWidth::I128 => Variable::I128, - IntWidth::Nat => Variable::NAT, - }], + IntBound::Exact(w) => vec![int_width_to_variable(*w)], IntBound::AtLeast { sign, width } => { let whole_range: &[(IntWidth, Variable)] = match sign { - SignDemand::NoDemand => { - &[ - (IntWidth::I8, Variable::I8), - (IntWidth::U8, Variable::U8), - (IntWidth::I16, Variable::I16), - (IntWidth::U16, Variable::U16), - (IntWidth::I32, Variable::I32), - (IntWidth::U32, Variable::U32), - (IntWidth::I64, Variable::I64), - (IntWidth::Nat, Variable::NAT), // FIXME: Nat's order here depends on the platform! - (IntWidth::U64, Variable::U64), - (IntWidth::I128, Variable::I128), - (IntWidth::U128, Variable::U128), - ] - } - SignDemand::Signed => &[ - (IntWidth::I8, Variable::I8), - (IntWidth::I16, Variable::I16), - (IntWidth::I32, Variable::I32), - (IntWidth::I64, Variable::I64), - (IntWidth::I128, Variable::I128), - ], + SignDemand::NoDemand => NO_DEMAND_INT_VARIABLES, + SignDemand::Signed => SIGNED_INT_VARIABLES, }; whole_range .iter() diff --git a/compiler/unify/src/unify.rs b/compiler/unify/src/unify.rs index fe75e8726f..d0767bc3ac 100644 --- a/compiler/unify/src/unify.rs +++ b/compiler/unify/src/unify.rs @@ -454,9 +454,46 @@ fn check_valid_range( range: VariableSubsSlice, mode: Mode, ) -> Outcome { - let slice = subs.get_subs_slice(range).to_vec(); + let slice = subs.get_subs_slice(range); + let content = subs.get_content_without_compacting(var); - let mut it = slice.iter().peekable(); + macro_rules! is_in_range { + ($var:expr) => { + if slice.contains(&$var) { + return Outcome::default(); + } + }; + } + + if let Content::Alias(symbol, _, _, _) = content { + match *symbol { + Symbol::NUM_I8 => is_in_range!(Variable::I8), + Symbol::NUM_U8 => is_in_range!(Variable::U8), + Symbol::NUM_I16 => is_in_range!(Variable::I16), + Symbol::NUM_U16 => is_in_range!(Variable::U16), + Symbol::NUM_I32 => is_in_range!(Variable::I32), + Symbol::NUM_U32 => is_in_range!(Variable::U32), + Symbol::NUM_I64 => is_in_range!(Variable::I64), + Symbol::NUM_NAT => is_in_range!(Variable::NAT), + Symbol::NUM_U64 => is_in_range!(Variable::U64), + Symbol::NUM_I128 => is_in_range!(Variable::I128), + Symbol::NUM_U128 => is_in_range!(Variable::U128), + + Symbol::NUM_DEC => is_in_range!(Variable::DEC), + Symbol::NUM_F32 => is_in_range!(Variable::F32), + Symbol::NUM_F64 => is_in_range!(Variable::F64), + + Symbol::NUM_NUM | Symbol::NUM_INT | Symbol::NUM_FRAC => { + // these satisfy any range that they are given + return Outcome::default(); + } + + _ => {} + } + } + + let vec = slice.to_vec(); + let mut it = vec.iter().peekable(); while let Some(&possible_var) = it.next() { let snapshot = subs.snapshot(); let old_pool = pool.clone();