diff --git a/mers/Cargo.toml b/mers/Cargo.toml index 95377cc..a455596 100644 --- a/mers/Cargo.toml +++ b/mers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers" -version = "0.9.22" +version = "0.9.23" edition = "2021" license = "MIT OR Apache-2.0" description = "dynamically typed but type-checked programming language" @@ -15,7 +15,7 @@ default = ["colored-output"] colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"] [dependencies] -mers_lib = "0.9.22" +mers_lib = "0.9.23" # mers_lib = { path = "../mers_lib" } clap = { version = "4.3.19", features = ["derive"] } colored = { version = "2.1.0", optional = true } diff --git a/mers_lib/Cargo.toml b/mers_lib/Cargo.toml index d35c356..6ccd167 100755 --- a/mers_lib/Cargo.toml +++ b/mers_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mers_lib" -version = "0.9.22" +version = "0.9.23" edition = "2021" license = "MIT OR Apache-2.0" description = "library to use the mers language in other projects" diff --git a/mers_lib/src/data/bool.rs b/mers_lib/src/data/bool.rs index f859ae7..3399dc4 100755 --- a/mers_lib/src/data/bool.rs +++ b/mers_lib/src/data/bool.rs @@ -61,8 +61,12 @@ impl MersType for TrueT { fn is_included_in(&self, target: &dyn MersType) -> bool { self.is_same_type_as(target) } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn Any { self @@ -88,8 +92,12 @@ impl MersType for FalseT { fn is_included_in(&self, target: &dyn MersType) -> bool { self.is_same_type_as(target) } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn Any { self diff --git a/mers_lib/src/data/byte.rs b/mers_lib/src/data/byte.rs index 01ceca9..918b443 100644 --- a/mers_lib/src/data/byte.rs +++ b/mers_lib/src/data/byte.rs @@ -1,4 +1,4 @@ -use std::{any::Any, fmt::Display, sync::Arc}; +use std::{any::Any, fmt::Display}; use crate::info::DisplayInfo; @@ -51,8 +51,12 @@ impl MersType for ByteT { fn is_included_in(&self, target: &dyn MersType) -> bool { self.is_same_type_as(target) } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn Any { self diff --git a/mers_lib/src/data/float.rs b/mers_lib/src/data/float.rs index d590872..57cb22a 100755 --- a/mers_lib/src/data/float.rs +++ b/mers_lib/src/data/float.rs @@ -1,4 +1,4 @@ -use std::{any::Any, fmt::Display, sync::Arc}; +use std::{any::Any, fmt::Display}; use crate::info::DisplayInfo; @@ -51,8 +51,12 @@ impl MersType for FloatT { fn is_included_in(&self, target: &dyn MersType) -> bool { self.is_same_type_as(target) } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn Any { self diff --git a/mers_lib/src/data/function.rs b/mers_lib/src/data/function.rs index 882ca1a..45b0fb1 100755 --- a/mers_lib/src/data/function.rs +++ b/mers_lib/src/data/function.rs @@ -7,6 +7,7 @@ use std::{ use crate::{ errors::CheckError, info::DisplayInfo, + parsing::types::ParsedType, program::run::{CheckInfo, Info}, }; @@ -15,6 +16,8 @@ use super::{Data, MersData, MersType, Type}; pub struct Function { pub info: Info, pub info_check: Arc>, + pub fixed_type: Option, Option>)>>, + pub fixed_type_out: Arc>, CheckError>>>>, pub out: Result< Arc Result + Send + Sync>, Arc>, @@ -31,6 +34,8 @@ impl Clone for Function { Self { info: self.info.duplicate(), info_check: self.info_check.clone(), + fixed_type: self.fixed_type.clone(), + fixed_type_out: self.fixed_type_out.clone(), out: self.out.clone(), run: self.run.clone(), inner_statements: self.inner_statements.clone(), @@ -45,6 +50,8 @@ impl Function { Self { info: crate::info::Info::neverused(), info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Err(Arc::new(out)), run: Arc::new(run), inner_statements: None, @@ -57,6 +64,8 @@ impl Function { Self { info: crate::info::Info::neverused(), info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |a, i| out(a, i))), run: Arc::new(run), inner_statements: None, @@ -66,6 +75,8 @@ impl Function { Self { info, info_check: Arc::clone(&self.info_check), + fixed_type: self.fixed_type.clone(), + fixed_type_out: self.fixed_type_out.clone(), out: self.out.clone(), run: Arc::clone(&self.run), inner_statements: self @@ -75,11 +86,56 @@ impl Function { } } pub fn with_info_check(&self, check: CheckInfo) { + if let Some(fixed_type) = &self.fixed_type { + if let Ok(out_func) = &self.out { + let mut nout = Ok(Vec::with_capacity(fixed_type.len())); + for (in_type, out_type) in fixed_type { + if let Ok(new_out) = &mut nout { + let in_type = crate::parsing::types::type_from_parsed(in_type, &check) + .expect("failed to get intype from parsed type"); + let out_type_want = out_type.as_ref().map(|out_type| { + crate::parsing::types::type_from_parsed(out_type, &check) + .expect("failed to get intype from parsed type") + }); + let mut out_type = match out_func(&in_type, &mut check.clone()) { + Ok(t) => t, + Err(e) => { + nout = Err(e); + break; + } + }; + if let Some(out_type_want) = out_type_want { + if out_type.is_included_in(&out_type_want) { + out_type = out_type_want; + } else { + nout = Err(format!( + "function must return {} for input {} because of its definition, but it returns {}.", + out_type_want.with_info(&check), + in_type.with_info(&check), + out_type.with_info(&check), + ) + .into()); + break; + } + } + new_out.push((in_type, out_type)); + } else { + break; + } + } + *self.fixed_type_out.lock().unwrap() = Some(nout.map(Arc::new)); + } + } *self.info_check.lock().unwrap() = check; } pub fn check(&self, arg: &Type) -> Result { + // TODO: this should require a CheckInfo and call `with_info_check`. self.get_as_type().o(arg) } + pub fn check_try(&self, arg: &Type) -> Result)> { + // TODO: this should require a CheckInfo and call `with_info_check`. + self.get_as_type().o_try(arg) + } pub fn run_mut( &mut self, arg: Data, @@ -102,6 +158,19 @@ impl Function { } pub fn get_as_type(&self) -> FunctionT { let info = self.info_check.lock().unwrap().clone(); + if self.fixed_type.is_some() { + match &*self.fixed_type_out.lock().unwrap() { + Some(Ok(types)) => return FunctionT(Err(types.clone()), info), + Some(Err(e)) => { + let e = e.clone(); + return FunctionT( + Ok(Arc::new(move |_, _| Err(e.clone()))), + crate::info::Info::neverused(), + ); + } + _ => {} + } + } match &self.out { Ok(out) => { let out = Arc::clone(out); @@ -189,13 +258,26 @@ pub struct FunctionT( impl FunctionT { /// get output type pub fn o(&self, i: &Type) -> Result { + self.o_try(i).map_err(|(e, _)| e) + } + /// get output type + pub fn o_try(&self, i: &Type) -> Result)> { match &self.0 { - Ok(f) => f(i, &self.1), + Ok(f) => f(i, &self.1).map_err(|e| (e, vec![])), Err(v) => v .iter() .find(|(a, _)| i.is_included_in(a)) .map(|(_, o)| o.clone()) - .ok_or_else(|| format!("This function, which was defined with an explicit type, cannot be called with an argument of type {}.", i.with_info(&self.1)).into()), + .ok_or_else(|| + ( + format!("This function, which was defined with an explicit type, cannot be called with an argument of type {}.", i.with_info(&self.1)).into(), + v.iter() + .filter(|(a, _)| i.types.iter().any(|i| a.types.iter().any(|a| + i.without(a.as_ref()).is_some()))) + .map(|(a, o)| (a.clone(), o.clone())) + .collect() + ) + ), } } } @@ -280,8 +362,12 @@ impl MersType for FunctionT { false } } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn Any { self diff --git a/mers_lib/src/data/int.rs b/mers_lib/src/data/int.rs index 1c9e60c..dbf07ab 100755 --- a/mers_lib/src/data/int.rs +++ b/mers_lib/src/data/int.rs @@ -96,27 +96,35 @@ impl MersType for IntT { false } } - fn subtypes(&self, acc: &mut Type) { - // INT_MIN .. INT32U_MIN .. INT32S_MIN .. -128 .. -1 .. 0 .. 1 .. 127 .. 255 .. 65535 .. INT32S_MAX .. INT32U_MAX .. INT_MAX - let mut add_range = |min, max| { - // the range is non-empty, self starts before or where the range ends, and self ends after or where the range starts. - if min <= max && self.0 <= max && min <= self.1 { - acc.add(Arc::new(IntT(self.0.max(min), self.1.min(max)))); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else if let Some(remove) = remove.as_any().downcast_ref::() { + if remove.0 <= self.0 && self.1 <= remove.1 { + Some(Type::empty()) + } else if remove.0 <= self.0 && self.0 <= remove.1 && remove.1 <= self.1 { + if remove.1 + 1 <= self.1 { + Some(Type::new(Self(remove.1 + 1, self.1))) + } else { + Some(Type::empty()) + } + } else if self.0 <= remove.0 && remove.0 <= self.1 && self.1 <= remove.1 { + if self.0 <= remove.0 + 1 { + Some(Type::new(Self(self.0, remove.0 - 1))) + } else { + Some(Type::empty()) + } + } else if self.0 < remove.0 && remove.0 <= remove.1 && remove.1 < self.1 { + Some(Type::newm(vec![ + Arc::new(Self(self.0, remove.0 - 1)), + Arc::new(Self(remove.1 + 1, self.1)), + ])) + } else { + None } - }; - add_range(INT_MIN, INT32U_MIN.saturating_sub(1)); - add_range(INT32U_MIN, INT32S_MIN.saturating_sub(1)); - add_range(INT32S_MIN, -129); - add_range(-128, -2); - add_range(-1, -1); - add_range(0, 0); - add_range(1, 1); - add_range(2, 127); - add_range(128, 255); - add_range(256, 65535); - add_range(65536, INT32S_MAX); - add_range(INT32S_MAX.saturating_add(1), INT32U_MAX); - add_range(INT32U_MAX.saturating_add(1), INT_MAX); + } else { + None + } } fn as_any(&self) -> &dyn Any { self diff --git a/mers_lib/src/data/mod.rs b/mers_lib/src/data/mod.rs index 9420e32..724babe 100755 --- a/mers_lib/src/data/mod.rs +++ b/mers_lib/src/data/mod.rs @@ -142,20 +142,10 @@ pub trait MersType: Any + Debug + Send + Sync { fn is_same_type_as(&self, other: &dyn MersType) -> bool; /// This doesn't handle the case where target is Type (Type::is_included_in handles it) fn is_included_in(&self, target: &dyn MersType) -> bool; - /// Returns all types that can result from the use of this type. - /// Usually, this is just `acc.add(Arc::new(self.clone()))` - /// but if there exists one or more inner types, this becomes interesting: - /// Using `(int/string)` will end up being either `(int)` or `(string)`, - /// so this function should add `(int)` and `(string)`. - /// Since `(int/string)` can't exist at runtime, we don't need to list `self`. - /// note also: `subtypes` has to be called recursively, i.e. you would have to call `.substring` on `int` and `string`. - fn subtypes(&self, acc: &mut Type); - /// like `subtypes`, but returns the accumulator - fn subtypes_type(&self) -> Type { - let mut acc = Type::empty(); - self.subtypes(&mut acc); - acc - } + /// Returns `self` with `remove` removed, if it is different from `self`. + /// This must, at least, return `Some(Type::empty())` if `self.is_included_in(remove)`. + /// For example, `(Int<1..9>).remove(Int<4..6>)` would return `Some(Int<1..3>/Int<7..9>)`. + fn without(&self, remove: &dyn MersType) -> Option; fn as_any(&self) -> &dyn Any; fn mut_any(&mut self) -> &mut dyn Any; fn to_any(self) -> Box; @@ -189,8 +179,8 @@ impl MersType for TypeWithOnlyName { fn is_included_in(&self, _target: &dyn MersType) -> bool { false } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())) + fn without(&self, _remove: &dyn MersType) -> Option { + None } fn as_any(&self) -> &dyn Any { self @@ -478,6 +468,29 @@ impl Type { self.add(Arc::clone(t)); } } + pub fn without_in_place(&mut self, remove: &dyn MersType) { + let mut rm = vec![]; + let mut add = vec![]; + for (i, t) in self.types.iter_mut().enumerate() { + if t.is_included_in(remove) { + rm.push(i); + } else if let Some(without) = t.without(remove) { + rm.push(i); + add.push(without); + } + } + for i in rm.into_iter().rev() { + self.types.swap_remove(i); + } + for t in add { + self.add_all(&t); + } + } + pub fn without_in_place_all(&mut self, remove: &Self) { + for t in &remove.types { + self.without_in_place(t.as_ref()); + } + } pub fn dereference(&self) -> Option { let mut o = Self::empty(); for t in &self.types { @@ -514,17 +527,6 @@ impl Type { pub fn is_included_in_single(&self, target: &dyn MersType) -> bool { self.types.iter().all(|s| s.is_included_in(target)) } - pub fn subtypes(&self, acc: &mut Type) { - for t in &self.types { - t.subtypes(acc); - } - } - pub fn subtypes_type(&self) -> Type { - let mut acc = Type::empty(); - acc.smart_type_simplification = false; - self.subtypes(&mut acc); - acc - } pub fn iterable(&self) -> Option { let mut o = Self::empty(); for t in self.types.iter() { diff --git a/mers_lib/src/data/object.rs b/mers_lib/src/data/object.rs index e80af7d..044c18d 100644 --- a/mers_lib/src/data/object.rs +++ b/mers_lib/src/data/object.rs @@ -128,8 +128,62 @@ impl MersType for ObjectT { }) }) } - fn subtypes(&self, acc: &mut Type) { - self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.len())); + fn without(&self, remove: &dyn MersType) -> Option { + let m = self.0.len(); + if let Some(remove) = remove + .as_any() + .downcast_ref::() + .filter(|r| r.0.len() <= m) + { + let mut out = Type::empty(); + for i1 in 0usize.. { + let mut self_tuple = Vec::with_capacity(m); + let mut i1 = i1; + for j in 0..m { + let mm = self.0[j].1.types.len(); + self_tuple.push((self.0[j].0, &self.0[j].1.types[i1 % mm])); + i1 /= mm; + } + if i1 != 0 { + break; + } + let mut covered = false; + for i2 in 0usize.. { + let mut remove_tuple = Vec::with_capacity(m); + let mut i2 = i2; + for j in 0..remove.0.len() { + let mm = remove.0[j].1.types.len(); + remove_tuple.push((remove.0[j].0, &remove.0[j].1.types[i2 % mm])); + i2 /= mm; + } + if i2 != 0 { + break; + } + if (0..m).all(|j| { + remove_tuple + .iter() + .find(|(v, _)| *v == self_tuple[j].0) + .is_none_or(|(_, r)| { + self_tuple[j].1.as_ref().is_included_in(r.as_ref()) + }) + }) { + covered = true; + break; + } + } + if !covered { + out.add(Arc::new(Self( + self_tuple + .iter() + .map(|(vi, v)| (*vi, Type::newm(vec![Arc::clone(v)]))) + .collect(), + ))); + } + } + Some(out) + } else { + None + } } fn as_any(&self) -> &dyn std::any::Any { self @@ -150,30 +204,6 @@ impl MersType for ObjectT { } } -impl ObjectT { - pub fn gen_subtypes_recursively( - &self, - acc: &mut Type, - types: &mut Vec<(usize, Arc)>, - ) { - if types.len() >= self.len() { - let nt = Self( - types - .iter() - .map(|(s, v)| (s.clone(), Type::newm(vec![Arc::clone(v)]))) - .collect(), - ); - acc.add(Arc::new(nt)); - } else { - for t in self.0[types.len()].1.subtypes_type().types { - types.push((self.0[types.len()].0.clone(), t)); - self.gen_subtypes_recursively(acc, types); - types.pop(); - } - } - } -} - pub trait ObjectFieldsMap { fn get_or_add_field(&self, field: &str) -> usize; } diff --git a/mers_lib/src/data/reference.rs b/mers_lib/src/data/reference.rs index d56553a..1cd6303 100755 --- a/mers_lib/src/data/reference.rs +++ b/mers_lib/src/data/reference.rs @@ -155,16 +155,11 @@ impl MersType for ReferenceT { // &int isn't included in &(int/float), otherwise we could assign a float to it self.is_same_type_as(target) } - fn subtypes(&self, acc: &mut Type) { - // // we don't call subtypes because (int/string) must stay that so we can assign either - // // NOTE: this might not be right...? - // acc.add(Arc::new(self.clone())); - // FOR NOW (until we can put the compile-time type in ReferenceT), add all these types, too - // TODO: Figure out how to fix - // x := if true 1 else 0.5 - // &x.debug // prints &Int instead of &{Int/Float} at runtime :( - for t in self.0.subtypes_type().types { - acc.add(Arc::new(Self(Type::newm(vec![t])))); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None } } fn as_any(&self) -> &dyn Any { diff --git a/mers_lib/src/data/string.rs b/mers_lib/src/data/string.rs index 1adebdc..2240a2b 100755 --- a/mers_lib/src/data/string.rs +++ b/mers_lib/src/data/string.rs @@ -1,4 +1,4 @@ -use std::{any::Any, fmt::Display, sync::Arc}; +use std::{any::Any, fmt::Display}; use crate::info::DisplayInfo; @@ -51,8 +51,12 @@ impl MersType for StringT { fn is_included_in(&self, target: &dyn MersType) -> bool { self.is_same_type_as(target) } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn Any { self diff --git a/mers_lib/src/data/tuple.rs b/mers_lib/src/data/tuple.rs index cf70749..e4ab58b 100755 --- a/mers_lib/src/data/tuple.rs +++ b/mers_lib/src/data/tuple.rs @@ -107,8 +107,59 @@ impl MersType for TupleT { false } } - fn subtypes(&self, acc: &mut Type) { - self.gen_subtypes_recursively(acc, &mut Vec::with_capacity(self.0.len())); + fn without(&self, remove: &dyn MersType) -> Option { + let m = self.0.len(); + if let Some(remove) = remove + .as_any() + .downcast_ref::() + .filter(|r| r.0.len() == m) + { + let mut out = Type::empty(); + for i1 in 0usize.. { + let mut self_tuple = Vec::with_capacity(m); + let mut i1 = i1; + for j in 0..m { + let mm = self.0[j].types.len(); + self_tuple.push(&self.0[j].types[i1 % mm]); + i1 /= mm; + } + if i1 != 0 { + break; + } + let mut covered = false; + for i2 in 0usize.. { + let mut remove_tuple = Vec::with_capacity(m); + let mut i2 = i2; + for j in 0..m { + let mm = remove.0[j].types.len(); + remove_tuple.push(&remove.0[j].types[i2 % mm]); + i2 /= mm; + } + if i2 != 0 { + break; + } + if (0..m).all(|j| { + self_tuple[j] + .as_ref() + .is_included_in(remove_tuple[j].as_ref()) + }) { + covered = true; + break; + } + } + if !covered { + out.add(Arc::new(Self( + self_tuple + .iter() + .map(|v| Type::newm(vec![Arc::clone(v)])) + .collect(), + ))); + } + } + Some(out) + } else { + None + } } fn as_any(&self) -> &dyn Any { self @@ -128,23 +179,3 @@ impl MersType for TupleT { ))) } } - -impl TupleT { - pub fn gen_subtypes_recursively(&self, acc: &mut Type, types: &mut Vec>) { - if types.len() >= self.0.len() { - let nt = Self( - types - .iter() - .map(|v| Type::newm(vec![Arc::clone(v)])) - .collect(), - ); - acc.add(Arc::new(nt)); - } else { - for t in self.0[types.len()].subtypes_type().types { - types.push(t); - self.gen_subtypes_recursively(acc, types); - types.pop(); - } - } - } -} diff --git a/mers_lib/src/parsing/statements.rs b/mers_lib/src/parsing/statements.rs index a544754..3a2cf48 100755 --- a/mers_lib/src/parsing/statements.rs +++ b/mers_lib/src/parsing/statements.rs @@ -114,6 +114,68 @@ pub fn parse( let mut pos_after_first = src.get_pos(); loop { src.skip_whitespace(); + // check for `arg [types] -> expr` function syntax + if let Some('[') = src.peek_char() { + let reset_no_func_pos = src.get_pos(); + let _ = src.next_char(); + let mut fixed_type = Vec::new(); + loop { + src.skip_whitespace(); + if let Ok(ty) = super::types::parse_type(src, srca) { + src.skip_whitespace(); + if src.peek_word() == "->" { + src.next_word(); + if let Ok(ot) = super::types::parse_type(src, srca) { + fixed_type.push((ty, Some(ot))); + } else { + fixed_type.clear(); + break; + } + } else { + fixed_type.push((ty, None)); + } + } else { + fixed_type.clear(); + break; + } + src.skip_whitespace(); + match src.next_char() { + Some(']') => break, + Some(',') => continue, + _ => { + fixed_type.clear(); + break; + } + } + } + if fixed_type.is_empty() { + src.set_pos(reset_no_func_pos); + } else { + src.skip_whitespace(); + let pos_in_src = src.get_pos(); + if src.next_word() != "->" { + src.set_pos(reset_no_func_pos); + } else { + src.skip_whitespace(); + let run = match parse(src, srca) { + Ok(Some(v)) => v, + Ok(None) => { + return Err(CheckError::new() + .src(vec![((pos_in_src, src.get_pos(), srca).into(), None)]) + .msg_str(format!("EOF after `->`"))) + } + Err(e) => return Err(e), + }; + first = Box::new(program::parsed::function::Function { + pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(), + arg: first, + run, + fixed_type: Some(fixed_type), + }); + break; + } + } + } match src.peek_word_allow_colon() { ":=" => { let pos_in_src = src.get_pos(); @@ -164,6 +226,7 @@ pub fn parse( pos_in_src: (first.source_range().start(), src.get_pos(), srca).into(), arg: first, run, + fixed_type: None, }); break; } diff --git a/mers_lib/src/program/configs/util.rs b/mers_lib/src/program/configs/util.rs index 9745d69..438d949 100644 --- a/mers_lib/src/program/configs/util.rs +++ b/mers_lib/src/program/configs/util.rs @@ -19,6 +19,8 @@ pub fn to_mers_func( data::function::Function { info: Info::neverused(), info_check: Arc::new(Mutex::new(Info::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |a, i| out(a, i))), run: Arc::new(move |a, i| run(a, i)), inner_statements: None, diff --git a/mers_lib/src/program/configs/with_base.rs b/mers_lib/src/program/configs/with_base.rs index 29b13e4..5325bcd 100755 --- a/mers_lib/src/program/configs/with_base.rs +++ b/mers_lib/src/program/configs/with_base.rs @@ -30,6 +30,8 @@ impl Config { .add_var("lock_update", data::function::Function { info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { for t in a.types.iter() { if let Some(t) = t.as_any().downcast_ref::() { @@ -95,6 +97,8 @@ impl Config { data::function::Function { info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { for t in &a.types { if t.as_any().downcast_ref::().is_none() && t.as_any().downcast_ref::().is_none() && t.iterable().is_none() { @@ -122,6 +126,8 @@ impl Config { data::function::Function { info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, _i| { for t in &a.types { if t.iterable().is_none() { @@ -158,6 +164,8 @@ impl Config { data::function::Function { info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, _i| Ok(Type::new(data::reference::ReferenceT(a.clone()))))), run: Arc::new(|a, _i| { Ok(Data::new(data::reference::Reference(Arc::new(RwLock::new(a.clone()))))) @@ -170,6 +178,8 @@ impl Config { data::function::Function { info: Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| if let Some(v) = a.dereference() { Ok(v) } else { Err(format!("cannot dereference type {}", a.with_info(i)).into()) })), run: Arc::new(|a, _i| { diff --git a/mers_lib/src/program/configs/with_command_running.rs b/mers_lib/src/program/configs/with_command_running.rs index b6ffae4..6c8e98a 100755 --- a/mers_lib/src/program/configs/with_command_running.rs +++ b/mers_lib/src/program/configs/with_command_running.rs @@ -34,6 +34,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.types.iter().all(|t| t.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) { Ok(Type::newm(vec![ @@ -89,6 +91,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.types.iter().all(|t| t.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&data::string::StringT) && t.0[1].iterable().is_some_and(|t| t.is_included_in_single(&data::string::StringT)))) { Ok(Type::newm(vec![ @@ -133,6 +137,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&ChildProcessT) { Ok(Type::newm(vec![ @@ -161,6 +167,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&ChildProcessT) { Ok(Type::newm(vec![ @@ -195,6 +203,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.types.iter().all(|a| a.as_any().downcast_ref::().is_some_and(|t| t.0.len() == 2 && t.0[0].is_included_in_single(&ChildProcessT) && t.0[1].iterable().is_some_and(|i| i.is_included_in_single(&data::byte::ByteT)))) { Ok(data::bool::bool_type()) @@ -224,6 +234,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&data::tuple::TupleT(vec![Type::new(ChildProcessT), Type::new(data::string::StringT)])) { Ok(data::bool::bool_type()) @@ -253,6 +265,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&ChildProcessT) { Ok(Type::newm(vec![ @@ -282,6 +296,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&ChildProcessT) { Ok(Type::newm(vec![ @@ -311,6 +327,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&ChildProcessT) { Ok(Type::newm(vec![ @@ -340,6 +358,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new( CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if a.is_included_in_single(&ChildProcessT) { Ok(Type::newm(vec![ @@ -431,8 +451,12 @@ impl MersType for ChildProcessT { fn is_included_in(&self, target: &dyn MersType) -> bool { target.as_any().is::() } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(self.clone())); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn std::any::Any { self diff --git a/mers_lib/src/program/configs/with_get.rs b/mers_lib/src/program/configs/with_get.rs index 50624c0..c783019 100755 --- a/mers_lib/src/program/configs/with_get.rs +++ b/mers_lib/src/program/configs/with_get.rs @@ -15,6 +15,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { let mut out = Type::empty(); for a in a.types.iter() { diff --git a/mers_lib/src/program/configs/with_iters.rs b/mers_lib/src/program/configs/with_iters.rs index fbd4e8a..7b256fa 100755 --- a/mers_lib/src/program/configs/with_iters.rs +++ b/mers_lib/src/program/configs/with_iters.rs @@ -144,6 +144,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { for a in &a.types { if let Some(tuple) = a.as_any().downcast_ref::() { @@ -229,6 +231,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { let data = if let Some(a) = a.iterable() { a @@ -246,6 +250,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { let data = if let Some(a) = a.iterable() { a @@ -301,6 +307,8 @@ fn genfunc_iter_and_func( data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |a, i| iter_out_arg(a, i, name, |f| ft(f)))), run: Arc::new(move |a, _i| { if let Some(tuple) = a.get().as_any().downcast_ref::() { @@ -359,6 +367,8 @@ fn genfunc_iter_and_arg( data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |a, i| { iter_out_arg(a, i, name, |f: &T| ft(f), type_sample) })), @@ -607,13 +617,16 @@ impl MersType for IterT { false } } + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } + } fn iterable(&self) -> Option { Some(self.2.clone()) } - fn subtypes(&self, acc: &mut Type) { - // NOTE: This might not be good enough - acc.add(Arc::new(self.clone())); - } fn as_any(&self) -> &dyn std::any::Any { self } @@ -655,6 +668,8 @@ fn genfunc_iter_in_val_out( Function { info: crate::info::Info::neverused(), info_check: Arc::new(Mutex::new(crate::info::Info::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |a, i| { if let Some(iter_over) = a.iterable() { if iter_over.is_included_in(&iter_type) { @@ -748,8 +763,12 @@ impl MersType for RangeT { self.is_empty() || (!target.is_empty() && self.0 >= target.0 && self.1 <= target.1) }) } - fn subtypes(&self, acc: &mut Type) { - acc.add(Arc::new(Clone::clone(self))) + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None + } } fn as_any(&self) -> &dyn std::any::Any { self diff --git a/mers_lib/src/program/configs/with_list.rs b/mers_lib/src/program/configs/with_list.rs index 6b6e55a..9638536 100755 --- a/mers_lib/src/program/configs/with_list.rs +++ b/mers_lib/src/program/configs/with_list.rs @@ -37,6 +37,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if let Some(a) = a.dereference() { let mut out = Type::empty(); @@ -85,6 +87,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { for t in a.types.iter() { if let Some(t) = t.as_any().downcast_ref::() { @@ -148,6 +152,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { for t in a.types.iter() { if let Some(t) = t.as_any().downcast_ref::() { @@ -221,6 +227,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { let mut o = Type::empty(); for t in a.types.iter() { @@ -298,6 +306,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { let mut o = Type::empty(); for t in a.types.iter() { @@ -369,6 +379,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { if let Some(v) = a.iterable() { Ok(Type::new(ListT(v))) @@ -464,12 +476,11 @@ impl MersType for ListT { .downcast_ref::() .is_some_and(|v| self.0.is_included_in(&v.0)) } - fn subtypes(&self, acc: &mut Type) { - // The type of an empty list is a list where the items are `` - acc.add(Arc::new(Self(Type::empty()))); - // All possible list types - for t in self.0.subtypes_type().types { - acc.add(Arc::new(Self(Type::newm(vec![t])))); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None } } fn as_any(&self) -> &dyn std::any::Any { diff --git a/mers_lib/src/program/configs/with_multithreading.rs b/mers_lib/src/program/configs/with_multithreading.rs index 6c13a51..087ba86 100755 --- a/mers_lib/src/program/configs/with_multithreading.rs +++ b/mers_lib/src/program/configs/with_multithreading.rs @@ -33,6 +33,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, _i| { let mut out = Type::empty(); for t in a.types.iter() { @@ -59,6 +61,8 @@ impl Config { .add_var("thread_finished", data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { for t in a.types.iter() { if !t.as_any().is::() { @@ -80,6 +84,8 @@ impl Config { .add_var("thread_await", data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, i| { let mut out = Type::empty(); for t in a.types.iter() { @@ -162,9 +168,11 @@ impl MersType for ThreadT { false } } - fn subtypes(&self, acc: &mut Type) { - for t in self.0.subtypes_type().types { - acc.add(Arc::new(Self(Type::newm(vec![t])))); + fn without(&self, remove: &dyn MersType) -> Option { + if self.is_included_in(remove) { + Some(Type::empty()) + } else { + None } } fn as_any(&self) -> &dyn std::any::Any { diff --git a/mers_lib/src/program/configs/with_stdio.rs b/mers_lib/src/program/configs/with_stdio.rs index 213a9be..11060dd 100755 --- a/mers_lib/src/program/configs/with_stdio.rs +++ b/mers_lib/src/program/configs/with_stdio.rs @@ -91,6 +91,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|a, _i| Ok(a.clone()))), run: Arc::new(|a, i| { let a2 = a.get(); @@ -114,6 +116,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() { @@ -133,6 +137,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { if let Some((_, stderr)) = &mut *i.global.stdout.lock().unwrap() { @@ -151,6 +157,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() { @@ -170,6 +178,8 @@ impl Config { data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(|_a, _i| Ok(Type::empty_tuple()))), run: Arc::new(|a, i| { if let Some((stdout, _)) = &mut *i.global.stdout.lock().unwrap() { diff --git a/mers_lib/src/program/parsed/function.rs b/mers_lib/src/program/parsed/function.rs index 25562b6..8f373b6 100755 --- a/mers_lib/src/program/parsed/function.rs +++ b/mers_lib/src/program/parsed/function.rs @@ -3,6 +3,7 @@ use std::sync::{Arc, Mutex}; use crate::{ data, errors::{CheckError, SourceRange}, + parsing::types::ParsedType, program::{self, run::CheckInfo}, }; @@ -13,6 +14,7 @@ pub struct Function { pub pos_in_src: SourceRange, pub arg: Box, pub run: Box, + pub fixed_type: Option, Option>)>>, } impl MersStatement for Function { @@ -38,6 +40,8 @@ impl MersStatement for Function { func_no_info: data::function::Function { info: program::run::Info::neverused(), info_check: Arc::new(Mutex::new(CheckInfo::neverused())), + fixed_type: self.fixed_type.clone(), + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |a, i| { arg2.check(i, Some(a))?; Ok(run2.check(i, None)?) diff --git a/mers_lib/src/program/parsed/include_mers.rs b/mers_lib/src/program/parsed/include_mers.rs index 8a43079..57d93b6 100644 --- a/mers_lib/src/program/parsed/include_mers.rs +++ b/mers_lib/src/program/parsed/include_mers.rs @@ -56,6 +56,8 @@ impl MersStatement for IncludeMers { func_no_info: data::function::Function { info: info::Info::neverused(), info_check: Arc::new(Mutex::new(info::Info::neverused())), + fixed_type: None, + fixed_type_out: Arc::new(Mutex::new(None)), out: Ok(Arc::new(move |_, i| { compiled.check(&mut i.duplicate(), None) })), diff --git a/mers_lib/src/program/run/try.rs b/mers_lib/src/program/run/try.rs index 8cc8202..ae45f0b 100644 --- a/mers_lib/src/program/run/try.rs +++ b/mers_lib/src/program/run/try.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use crate::{ data::{self, Data, Type}, @@ -25,7 +25,7 @@ impl MersStatement for Try { return Err("can't init to statement type Try".to_string().into()); } let mut t = Type::empty(); - let arg = self.arg.check(info, init_to)?; + let mut arg = self.arg.check(info, init_to)?; let funcs = self .funcs .iter() @@ -46,62 +46,75 @@ impl MersStatement for Try { }; drop(unused_try_statements_lock); drop(index_lock); - for arg in arg.subtypes_type().types.iter() { - let mut found = false; - let mut errs = vec![]; - for (i, func) in funcs.iter().enumerate() { - let mut func_res = Type::empty(); - let mut func_err = None; - for ft in func.types.iter() { - if let Some(ft) = ft.executable() { - match ft.o(&Type::newm(vec![Arc::clone(arg)])) { - Ok(res) => { - func_res.add_all(&res); - } - Err(e) => func_err = Some(e), + 'func_options: for (i, func) in funcs.iter().enumerate() { + // TODO! handle the case where a function is a one-of-multiple type... + if func.types.len() != 1 { + return Err(format!( + "Try-statement requires clearly defined functions, but got type {}", + func.with_info(info) + ) + .into()); + } + for ft in func.types.iter() { + if let Some(ft) = ft.executable() { + let using_func = |t: &mut Type, func_res: &Type| { + // found the function to use + info.global.unused_try_statements.lock().unwrap()[my_index].1[i] = None; + t.add_all(func_res); + }; + match ft.o_try(&arg) { + Ok(res) => { + using_func(&mut t, &res); + arg = Type::empty(); + break 'func_options; + } + Err((_, covered)) => { + for (t_in, t_out) in &covered { + arg.without_in_place_all(t_in); + using_func(&mut t, t_out); + } } - } else { - return Err(CheckError::new() - .msg_str(format!( - "try: #{} is not a function, type is {} within {}.", - i + 1, - ft.simplified_as_string(info), - func.simplify_for_display(info).with_info(info), - )) - .src(vec![ - (self.source_range(), None), - (self.funcs[i].source_range(), Some(EColor::TryNotAFunction)), - ])); } - } - if let Some(err) = func_err { - // can't use this function for this argument - errs.push(err); } else { - // found the function to use - info.global.unused_try_statements.lock().unwrap()[my_index].1[i] = None; - found = true; - t.add_all(&func_res); - break; + return Err(CheckError::new() + .msg_str(format!( + "try: #{} is not a function, type is {} within {}.", + i + 1, + ft.simplified_as_string(info), + func.simplify_for_display(info).with_info(info), + )) + .src(vec![ + (self.source_range(), None), + (self.funcs[i].source_range(), Some(EColor::TryNotAFunction)), + ])); } } - if !found { - let mut err = CheckError::new() - .msg_str(format!( - "try: no function found for argument of type {}.", - arg.simplified_as_string(info) - )) - .src(vec![( - self.pos_in_src.clone(), - Some(EColor::TryNoFunctionFound), - )]); - for (i, e) in errs.into_iter().enumerate() { - err = err - .msg_str(format!("Error for function #{}:", i + 1)) - .err(e); + } + if !arg.types.is_empty() { + let mut err = CheckError::new() + .msg_str(format!( + "try: uncovered argument type {}.", + arg.simplified_as_string(info) + )) + .src(vec![( + self.pos_in_src.clone(), + Some(EColor::TryNoFunctionFound), + )]); + for (i, func) in funcs.iter().enumerate() { + err = err.msg_str(format!( + "Error for function #{} {}:", + i + 1, + func.with_info(info) + )); + for e in func + .types + .iter() + .filter_map(|t| t.executable().unwrap().o(&arg).err()) + { + err = err.err(e); } - return Err(err); } + return Err(err); } Ok(t) }