remove the snapshots

This commit is contained in:
Folkert 2022-05-21 20:42:19 +02:00
parent cb40aab21f
commit 98ce9f4d09
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
9 changed files with 271 additions and 164 deletions

View file

@ -1849,18 +1849,8 @@ fn deep_copy_var_help(
} }
RangedNumber(typ, vars) => { RangedNumber(typ, vars) => {
let mut new_vars = Vec::with_capacity(vars.len());
for var_index in vars {
let var = subs[var_index];
let new_var = deep_copy_var_help(subs, max_rank, pools, var);
new_vars.push(new_var);
}
let new_slice = VariableSubsSlice::insert_into_subs(subs, new_vars.drain(..));
let new_real_type = deep_copy_var_help(subs, max_rank, pools, typ); let new_real_type = deep_copy_var_help(subs, max_rank, pools, typ);
let new_content = RangedNumber(new_real_type, new_slice); let new_content = RangedNumber(new_real_type, vars);
subs.set(copy, make_descriptor(new_content)); subs.set(copy, make_descriptor(new_content));

View file

@ -4,6 +4,7 @@ use roc_can::expected::Expected::{self, *};
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntWidth, NumBound, SignDemand}; use roc_can::num::{FloatBound, FloatWidth, IntBound, IntWidth, NumBound, SignDemand};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::Region; use roc_region::all::Region;
use roc_types::num::NumericBound;
use roc_types::subs::Variable; use roc_types::subs::Variable;
use roc_types::types::Type::{self, *}; use roc_types::types::Type::{self, *};
use roc_types::types::{AliasKind, Category}; use roc_types::types::{AliasKind, Category};
@ -19,14 +20,16 @@ pub fn add_numeric_bound_constr(
region: Region, region: Region,
category: Category, category: Category,
) -> Type { ) -> Type {
let range = bound.bounded_range(); let range = bound.numeric_bound();
let total_num_type = num_type; let total_num_type = num_type;
match range.len() { match range {
0 => total_num_type, NumericBound::None => {
1 => { // no additional constraints
let actual_type = Variable(range[0]); total_num_type
}
NumericBound::FloatExact(width) => {
let actual_type = Variable(float_width_to_variable(width));
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
let because_suffix = let because_suffix =
constraints.equal_types(total_num_type.clone(), expected, category, region); constraints.equal_types(total_num_type.clone(), expected, category, region);
@ -35,7 +38,20 @@ pub fn add_numeric_bound_constr(
total_num_type total_num_type
} }
_ => RangedNumber(Box::new(total_num_type), range), NumericBound::IntExact(width) => {
let actual_type = Variable(int_width_to_variable(width));
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
let because_suffix =
constraints.equal_types(total_num_type.clone(), expected, category, region);
num_constraints.extend([because_suffix]);
total_num_type
}
NumericBound::IntAtLeastSigned(_)
| NumericBound::IntAtLeastEitherSign(_)
| NumericBound::NumAtLeastSigned(_)
| NumericBound::NumAtLeastEitherSign(_) => RangedNumber(Box::new(total_num_type), range),
} }
} }
@ -265,6 +281,8 @@ pub fn num_num(typ: Type) -> Type {
pub trait TypedNumericBound { pub trait TypedNumericBound {
fn bounded_range(&self) -> Vec<Variable>; fn bounded_range(&self) -> Vec<Variable>;
fn numeric_bound(&self) -> NumericBound;
} }
const fn int_width_to_variable(w: IntWidth) -> Variable { const fn int_width_to_variable(w: IntWidth) -> Variable {
@ -323,6 +341,29 @@ impl TypedNumericBound for IntBound {
} }
} }
} }
fn numeric_bound(&self) -> NumericBound {
match self {
IntBound::None => NumericBound::None,
IntBound::Exact(w) => NumericBound::IntExact(*w),
IntBound::AtLeast {
sign: SignDemand::NoDemand,
width,
} => NumericBound::IntAtLeastEitherSign(*width),
IntBound::AtLeast {
sign: SignDemand::Signed,
width,
} => NumericBound::IntAtLeastSigned(*width),
}
}
}
const fn float_width_to_variable(w: FloatWidth) -> Variable {
match w {
FloatWidth::Dec => Variable::DEC,
FloatWidth::F32 => Variable::F32,
FloatWidth::F64 => Variable::F64,
}
} }
impl TypedNumericBound for FloatBound { impl TypedNumericBound for FloatBound {
@ -336,6 +377,13 @@ impl TypedNumericBound for FloatBound {
}], }],
} }
} }
fn numeric_bound(&self) -> NumericBound {
match self {
FloatBound::None => NumericBound::None,
FloatBound::Exact(w) => NumericBound::FloatExact(*w),
}
}
} }
impl TypedNumericBound for NumBound { impl TypedNumericBound for NumBound {
@ -349,4 +397,18 @@ impl TypedNumericBound for NumBound {
} }
} }
} }
fn numeric_bound(&self) -> NumericBound {
match self {
NumBound::None => NumericBound::None,
&NumBound::AtLeastIntOrFloat {
sign: SignDemand::NoDemand,
width,
} => NumericBound::NumAtLeastEitherSign(width),
&NumBound::AtLeastIntOrFloat {
sign: SignDemand::Signed,
width,
} => NumericBound::NumAtLeastSigned(width),
}
}
} }

View file

@ -611,15 +611,10 @@ fn deep_copy_type_vars<'a>(
}) })
} }
RangedNumber(typ, range_vars) => { RangedNumber(typ, range) => {
let new_typ = descend_var!(typ); let new_typ = descend_var!(typ);
descend_slice!(range_vars);
perform_clone!({ perform_clone!(RangedNumber(new_typ, range))
let new_range_vars = clone_var_slice!(range_vars);
RangedNumber(new_typ, new_range_vars)
})
} }
Error => Error, Error => Error,
}; };

View file

@ -1854,10 +1854,9 @@ fn type_to_variable<'a>(
Variable(_) | EmptyRec | EmptyTagUnion => { Variable(_) | EmptyRec | EmptyTagUnion => {
unreachable!("This variant should never be deferred!") unreachable!("This variant should never be deferred!")
} }
RangedNumber(typ, vars) => { RangedNumber(typ, range) => {
let ty_var = helper!(typ); let ty_var = helper!(typ);
let vars = VariableSubsSlice::insert_into_subs(subs, vars.iter().copied()); let content = Content::RangedNumber(ty_var, *range);
let content = Content::RangedNumber(ty_var, vars);
register_with_known_var(subs, destination, rank, pools, content) register_with_known_var(subs, destination, rank, pools, content)
} }
@ -3015,10 +3014,8 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
stack.push(var); stack.push(var);
} }
&RangedNumber(typ, vars) => { &RangedNumber(typ, _) => {
stack.push(typ); stack.push(typ);
stack.extend(var_slice!(vars));
} }
} }
} }
@ -3267,12 +3264,10 @@ fn deep_copy_var_help(
copy copy
} }
RangedNumber(typ, range_vars) => { RangedNumber(typ, range) => {
let new_type_var = deep_copy_var_help(subs, max_rank, pool, visited, typ); let new_type_var = deep_copy_var_help(subs, max_rank, pool, visited, typ);
let new_variables = copy_sequence!(range_vars.len(), range_vars); let new_content = RangedNumber(new_type_var, range);
let new_content = RangedNumber(new_type_var, new_variables);
subs.set_content_unchecked(copy, new_content); subs.set_content_unchecked(copy, new_content);

View file

@ -1,3 +1,106 @@
use crate::subs::Variable;
use roc_module::symbol::Symbol;
/// A bound placed on a number because of its literal value.
/// e.g. `-5` cannot be unsigned, and 300 does not fit in a U8
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NumericBound {
None,
FloatExact(FloatWidth),
IntExact(IntWidth),
IntAtLeastSigned(IntWidth),
IntAtLeastEitherSign(IntWidth),
NumAtLeastSigned(IntWidth),
NumAtLeastEitherSign(IntWidth),
}
impl NumericBound {
pub fn contains_symbol(&self, symbol: Symbol) -> bool {
match symbol {
Symbol::NUM_I8 => self.contains_int_width(IntWidth::I8),
Symbol::NUM_U8 => self.contains_int_width(IntWidth::U8),
Symbol::NUM_I16 => self.contains_int_width(IntWidth::I16),
Symbol::NUM_U16 => self.contains_int_width(IntWidth::U16),
Symbol::NUM_I32 => self.contains_int_width(IntWidth::I32),
Symbol::NUM_U32 => self.contains_int_width(IntWidth::U32),
Symbol::NUM_I64 => self.contains_int_width(IntWidth::I64),
Symbol::NUM_NAT => self.contains_int_width(IntWidth::Nat),
Symbol::NUM_U64 => self.contains_int_width(IntWidth::U64),
Symbol::NUM_I128 => self.contains_int_width(IntWidth::I128),
Symbol::NUM_U128 => self.contains_int_width(IntWidth::U128),
Symbol::NUM_DEC => self.contains_float_width(FloatWidth::Dec),
Symbol::NUM_F32 => self.contains_float_width(FloatWidth::F32),
Symbol::NUM_F64 => self.contains_float_width(FloatWidth::F64),
Symbol::NUM_NUM | Symbol::NUM_INT | Symbol::NUM_FRAC => {
// these satisfy any range that they are given
true
}
_ => unreachable!("weird number symbol {:?}", symbol),
}
}
fn contains_float_width(&self, _width: FloatWidth) -> bool {
false
}
fn contains_int_width(&self, width: IntWidth) -> bool {
use NumericBound::*;
let (range_sign, at_least_width) = match self {
IntAtLeastSigned(width) => (SignDemand::Signed, width),
IntAtLeastEitherSign(width) => (SignDemand::NoDemand, width),
NumAtLeastSigned(width) => (SignDemand::Signed, width),
NumAtLeastEitherSign(width) => (SignDemand::NoDemand, width),
_ => panic!(),
};
let (actual_sign, _) = width.sign_and_width();
if let (IntSign::Unsigned, SignDemand::Signed) = (actual_sign, range_sign) {
return false;
}
width.sign_and_width().1 >= at_least_width.sign_and_width().1
}
pub fn variable_slice(&self) -> &'static [Variable] {
use NumericBound::*;
match self {
IntAtLeastSigned(width) => {
let target = int_width_to_variable(*width);
let start = SIGNED_VARIABLES.iter().position(|v| *v == target).unwrap();
let end = SIGNED_VARIABLES.len() - 3;
&SIGNED_VARIABLES[start..end]
}
IntAtLeastEitherSign(width) => {
let target = int_width_to_variable(*width);
let start = ALL_VARIABLES.iter().position(|v| *v == target).unwrap();
let end = ALL_VARIABLES.len() - 3;
&ALL_VARIABLES[start..end]
}
NumAtLeastSigned(width) => {
let target = int_width_to_variable(*width);
let start = SIGNED_VARIABLES.iter().position(|v| *v == target).unwrap();
&SIGNED_VARIABLES[start..]
}
NumAtLeastEitherSign(width) => {
let target = int_width_to_variable(*width);
let start = ALL_VARIABLES.iter().position(|v| *v == target).unwrap();
&ALL_VARIABLES[start..]
}
_ => panic!(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum IntSign { pub enum IntSign {
Unsigned, Unsigned,
@ -163,3 +266,47 @@ pub enum NumBound {
width: IntWidth, width: IntWidth,
}, },
} }
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 ALL_VARIABLES: &[Variable] = &[
Variable::I8,
Variable::U8,
Variable::I16,
Variable::U16,
Variable::I32,
Variable::U32,
Variable::I64,
Variable::NAT, // FIXME: Nat's order here depends on the platfor,
Variable::U64,
Variable::I128,
Variable::U128,
Variable::F32,
Variable::F64,
Variable::DEC,
];
const SIGNED_VARIABLES: &[Variable] = &[
Variable::I8,
Variable::I16,
Variable::I32,
Variable::I64,
Variable::I128,
Variable::F32,
Variable::F64,
Variable::DEC,
];

View file

@ -220,12 +220,8 @@ fn find_names_needed(
// TODO should we also look in the actual variable? // TODO should we also look in the actual variable?
// find_names_needed(_actual, subs, roots, root_appearances, names_taken); // find_names_needed(_actual, subs, roots, root_appearances, names_taken);
} }
&RangedNumber(typ, vars) => { &RangedNumber(typ, _) => {
find_names_needed(typ, subs, roots, root_appearances, names_taken); find_names_needed(typ, subs, roots, root_appearances, names_taken);
for var_index in vars {
let var = subs[var_index];
find_names_needed(var, subs, roots, root_appearances, names_taken);
}
} }
Error | Structure(Erroneous(_)) | Structure(EmptyRecord) | Structure(EmptyTagUnion) => { Error | Structure(Erroneous(_)) | Structure(EmptyRecord) | Structure(EmptyTagUnion) => {
// Errors and empty records don't need names. // Errors and empty records don't need names.

View file

@ -713,8 +713,7 @@ fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt:
) )
} }
Content::RangedNumber(typ, range) => { Content::RangedNumber(typ, range) => {
let slice = subs.get_subs_slice(*range); write!(f, "RangedNumber({:?}, {:?})", typ, range)
write!(f, "RangedNumber({:?}, {:?})", typ, slice)
} }
Content::Error => write!(f, "Error"), Content::Error => write!(f, "Error"),
} }
@ -2009,7 +2008,7 @@ pub enum Content {
}, },
Structure(FlatType), Structure(FlatType),
Alias(Symbol, AliasVariables, Variable, AliasKind), Alias(Symbol, AliasVariables, Variable, AliasKind),
RangedNumber(Variable, VariableSubsSlice), RangedNumber(Variable, crate::num::NumericBound),
Error, Error,
} }
@ -3025,16 +3024,10 @@ fn explicit_substitute(
in_var in_var
} }
RangedNumber(typ, vars) => { RangedNumber(typ, range) => {
for index in vars.into_iter() {
let var = subs[index];
let new_var = explicit_substitute(subs, from, to, var, seen);
subs[index] = new_var;
}
let new_typ = explicit_substitute(subs, from, to, typ, seen); let new_typ = explicit_substitute(subs, from, to, typ, seen);
subs.set_content(in_var, RangedNumber(new_typ, vars)); subs.set_content(in_var, RangedNumber(new_typ, range));
in_var in_var
} }
@ -3094,12 +3087,7 @@ fn get_var_names(
get_var_names(subs, subs[arg_var], answer) get_var_names(subs, subs[arg_var], answer)
}), }),
RangedNumber(typ, vars) => { RangedNumber(typ, _) => get_var_names(subs, typ, taken_names),
let taken_names = get_var_names(subs, typ, taken_names);
vars.into_iter().fold(taken_names, |answer, var| {
get_var_names(subs, subs[var], answer)
})
}
Structure(flat_type) => match flat_type { Structure(flat_type) => match flat_type {
FlatType::Apply(_, args) => { FlatType::Apply(_, args) => {
@ -3340,12 +3328,12 @@ fn content_to_err_type(
RangedNumber(typ, range) => { RangedNumber(typ, range) => {
let err_type = var_to_err_type(subs, state, typ); let err_type = var_to_err_type(subs, state, typ);
if state.context == ErrorTypeContext::ExpandRanges { dbg!(range);
let mut types = Vec::with_capacity(range.len());
for var_index in range {
let var = subs[var_index];
types.push(var_to_err_type(subs, state, var)); if state.context == ErrorTypeContext::ExpandRanges {
let mut types = Vec::new();
for var in range.variable_slice() {
types.push(var_to_err_type(subs, state, *var));
} }
ErrorType::Range(Box::new(err_type), types) ErrorType::Range(Box::new(err_type), types)
} else { } else {
@ -3645,9 +3633,8 @@ fn restore_help(subs: &mut Subs, initial: Variable) {
stack.push(*var); stack.push(*var);
} }
RangedNumber(typ, vars) => { RangedNumber(typ, _vars) => {
stack.push(*typ); stack.push(*typ);
stack.extend(var_slice(*vars));
} }
} }
} }
@ -3833,10 +3820,7 @@ impl StorageSubs {
Self::offset_variable(offsets, *actual), Self::offset_variable(offsets, *actual),
*kind, *kind,
), ),
RangedNumber(typ, vars) => RangedNumber( RangedNumber(typ, range) => RangedNumber(Self::offset_variable(offsets, *typ), *range),
Self::offset_variable(offsets, *typ),
Self::offset_variable_slice(offsets, *vars),
),
Error => Content::Error, Error => Content::Error,
} }
} }
@ -4262,18 +4246,10 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
copy copy
} }
RangedNumber(typ, vars) => { RangedNumber(typ, range) => {
let new_typ = deep_copy_var_to_help(env, typ); let new_typ = deep_copy_var_to_help(env, typ);
let new_vars = SubsSlice::reserve_into_subs(env.target, vars.len()); let new_content = RangedNumber(new_typ, range);
for (target_index, var_index) in (new_vars.indices()).zip(vars) {
let var = env.source[var_index];
let copy_var = deep_copy_var_to_help(env, var);
env.target.variables[target_index] = copy_var;
}
let new_content = RangedNumber(new_typ, new_vars);
env.target.set(copy, make_descriptor(new_content)); env.target.set(copy, make_descriptor(new_content));
copy copy
@ -4731,18 +4707,10 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
copy copy
} }
RangedNumber(typ, vars) => { RangedNumber(typ, range) => {
let new_typ = copy_import_to_help(env, max_rank, typ); let new_typ = copy_import_to_help(env, max_rank, typ);
let new_vars = SubsSlice::reserve_into_subs(env.target, vars.len()); let new_content = RangedNumber(new_typ, range);
for (target_index, var_index) in (new_vars.indices()).zip(vars) {
let var = env.source[var_index];
let copy_var = copy_import_to_help(env, max_rank, var);
env.target.variables[target_index] = copy_var;
}
let new_content = RangedNumber(new_typ, new_vars);
env.target.set(copy, make_descriptor(new_content)); env.target.set(copy, make_descriptor(new_content));
copy copy

View file

@ -1,3 +1,4 @@
use crate::num::NumericBound;
use crate::pretty_print::Parens; use crate::pretty_print::Parens;
use crate::subs::{ use crate::subs::{
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice, GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
@ -254,7 +255,7 @@ pub enum Type {
/// Applying a type to some arguments (e.g. Dict.Dict String Int) /// Applying a type to some arguments (e.g. Dict.Dict String Int)
Apply(Symbol, Vec<Type>, Region), Apply(Symbol, Vec<Type>, Region),
Variable(Variable), Variable(Variable),
RangedNumber(Box<Type>, Vec<Variable>), RangedNumber(Box<Type>, NumericBound),
/// A type error, which will code gen to a runtime error /// A type error, which will code gen to a runtime error
Erroneous(Problem), Erroneous(Problem),
} }
@ -324,7 +325,7 @@ impl Clone for Type {
} }
Self::Apply(arg0, arg1, arg2) => Self::Apply(*arg0, arg1.clone(), *arg2), Self::Apply(arg0, arg1, arg2) => Self::Apply(*arg0, arg1.clone(), *arg2),
Self::Variable(arg0) => Self::Variable(*arg0), Self::Variable(arg0) => Self::Variable(*arg0),
Self::RangedNumber(arg0, arg1) => Self::RangedNumber(arg0.clone(), arg1.clone()), Self::RangedNumber(arg0, arg1) => Self::RangedNumber(arg0.clone(), *arg1),
Self::Erroneous(arg0) => Self::Erroneous(arg0.clone()), Self::Erroneous(arg0) => Self::Erroneous(arg0.clone()),
} }
} }
@ -1089,9 +1090,7 @@ impl Type {
} => actual_type.contains_variable(rep_variable), } => actual_type.contains_variable(rep_variable),
HostExposedAlias { actual, .. } => actual.contains_variable(rep_variable), HostExposedAlias { actual, .. } => actual.contains_variable(rep_variable),
Apply(_, args, _) => args.iter().any(|arg| arg.contains_variable(rep_variable)), Apply(_, args, _) => args.iter().any(|arg| arg.contains_variable(rep_variable)),
RangedNumber(typ, vars) => { RangedNumber(typ, _) => typ.contains_variable(rep_variable),
typ.contains_variable(rep_variable) || vars.iter().any(|&v| v == rep_variable)
}
EmptyRec | EmptyTagUnion | Erroneous(_) => false, EmptyRec | EmptyTagUnion | Erroneous(_) => false,
} }
} }
@ -1594,9 +1593,8 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
} }
variables_help(actual, accum); variables_help(actual, accum);
} }
RangedNumber(typ, vars) => { RangedNumber(typ, _) => {
variables_help(typ, accum); variables_help(typ, accum);
accum.extend(vars.iter().copied());
} }
Apply(_, args, _) => { Apply(_, args, _) => {
for x in args { for x in args {
@ -1730,9 +1728,8 @@ fn variables_help_detailed(tipe: &Type, accum: &mut VariableDetail) {
} }
variables_help_detailed(actual, accum); variables_help_detailed(actual, accum);
} }
RangedNumber(typ, vars) => { RangedNumber(typ, _) => {
variables_help_detailed(typ, accum); variables_help_detailed(typ, accum);
accum.type_variables.extend(vars);
} }
Apply(_, args, _) => { Apply(_, args, _) => {
for x in args { for x in args {

View file

@ -5,6 +5,7 @@ use roc_debug_flags::{ROC_PRINT_MISMATCHES, ROC_PRINT_UNIFICATIONS};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::ident::{Lowercase, TagName}; use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_types::num::NumericBound;
use roc_types::subs::Content::{self, *}; use roc_types::subs::Content::{self, *};
use roc_types::subs::{ use roc_types::subs::{
AliasVariables, Descriptor, ErrorTypeContext, FlatType, GetSubsSlice, Mark, OptVariable, AliasVariables, Descriptor, ErrorTypeContext, FlatType, GetSubsSlice, Mark, OptVariable,
@ -413,7 +414,7 @@ fn unify_ranged_number(
pool: &mut Pool, pool: &mut Pool,
ctx: &Context, ctx: &Context,
real_var: Variable, real_var: Variable,
range_vars: VariableSubsSlice, range_vars: NumericBound,
) -> Outcome { ) -> Outcome {
let other_content = &ctx.second_desc.content; let other_content = &ctx.second_desc.content;
@ -431,7 +432,7 @@ fn unify_ranged_number(
&RangedNumber(other_real_var, other_range_vars) => { &RangedNumber(other_real_var, other_range_vars) => {
let outcome = unify_pool(subs, pool, real_var, other_real_var, ctx.mode); let outcome = unify_pool(subs, pool, real_var, other_real_var, ctx.mode);
if outcome.mismatches.is_empty() { if outcome.mismatches.is_empty() {
check_valid_range(subs, pool, ctx.first, other_range_vars, ctx.mode) check_valid_range(subs, ctx.first, other_range_vars)
} else { } else {
outcome outcome
} }
@ -444,80 +445,36 @@ fn unify_ranged_number(
return outcome; return outcome;
} }
check_valid_range(subs, pool, ctx.second, range_vars, ctx.mode) check_valid_range(subs, ctx.second, range_vars)
} }
fn check_valid_range( fn check_valid_range(subs: &mut Subs, var: Variable, range: NumericBound) -> Outcome {
subs: &mut Subs,
pool: &mut Pool,
var: Variable,
range: VariableSubsSlice,
mode: Mode,
) -> Outcome {
let slice = subs.get_subs_slice(range);
let content = subs.get_content_without_compacting(var); let content = subs.get_content_without_compacting(var);
macro_rules! is_in_range { match content {
($var:expr) => { Content::Alias(symbol, _, _, _) => {
if slice.contains(&$var) { if !range.contains_symbol(*symbol) {
return Outcome::default(); let outcome = Outcome {
}
};
}
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();
let outcome = unify_pool(subs, pool, var, possible_var, mode | Mode::RIGID_AS_FLEX);
if outcome.mismatches.is_empty() {
// Okay, we matched some type in the range.
subs.rollback_to(snapshot);
*pool = old_pool;
return Outcome::default();
} else if it.peek().is_some() {
// We failed to match something in the range, but there are still things we can try.
subs.rollback_to(snapshot);
*pool = old_pool;
} else {
subs.commit_snapshot(snapshot);
}
}
Outcome {
mismatches: vec![Mismatch::TypeNotInRange], mismatches: vec![Mismatch::TypeNotInRange],
..Outcome::default() must_implement_ability: Default::default(),
};
return outcome;
} }
} }
Content::RangedNumber(_, _) => {
// these ranges always intersect, we need more information before we can say more
}
_ => {
// anything else is definitely a type error, and will be reported elsewhere
}
}
Outcome::default()
}
#[inline(always)] #[inline(always)]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn unify_two_aliases( fn unify_two_aliases(
@ -613,7 +570,7 @@ fn unify_alias(
RangedNumber(other_real_var, other_range_vars) => { RangedNumber(other_real_var, other_range_vars) => {
let outcome = unify_pool(subs, pool, real_var, *other_real_var, ctx.mode); let outcome = unify_pool(subs, pool, real_var, *other_real_var, ctx.mode);
if outcome.mismatches.is_empty() { if outcome.mismatches.is_empty() {
check_valid_range(subs, pool, real_var, *other_range_vars, ctx.mode) check_valid_range(subs, real_var, *other_range_vars)
} else { } else {
outcome outcome
} }
@ -674,7 +631,7 @@ fn unify_opaque(
// This opaque might be a number, check if it unifies with the target ranged number var. // This opaque might be a number, check if it unifies with the target ranged number var.
let outcome = unify_pool(subs, pool, ctx.first, *other_real_var, ctx.mode); let outcome = unify_pool(subs, pool, ctx.first, *other_real_var, ctx.mode);
if outcome.mismatches.is_empty() { if outcome.mismatches.is_empty() {
check_valid_range(subs, pool, ctx.first, *other_range_vars, ctx.mode) check_valid_range(subs, ctx.first, *other_range_vars)
} else { } else {
outcome outcome
} }
@ -805,7 +762,7 @@ fn unify_structure(
RangedNumber(other_real_var, other_range_vars) => { RangedNumber(other_real_var, other_range_vars) => {
let outcome = unify_pool(subs, pool, ctx.first, *other_real_var, ctx.mode); let outcome = unify_pool(subs, pool, ctx.first, *other_real_var, ctx.mode);
if outcome.mismatches.is_empty() { if outcome.mismatches.is_empty() {
check_valid_range(subs, pool, ctx.first, *other_range_vars, ctx.mode) check_valid_range(subs, ctx.first, *other_range_vars)
} else { } else {
outcome outcome
} }