add warning to if-statement in check mode

warning is shown if the condition of an
if statement can never be true or false,
and the user used the check command.
warnings are not shown when you use `mers run`.
This commit is contained in:
Mark 2024-08-29 15:48:01 +02:00
parent 385019e43c
commit 817ed25f96
5 changed files with 56 additions and 6 deletions

View File

@ -125,7 +125,8 @@ fn main() {
exit(20);
}
Ok(parsed) => {
let (i1, _, i3) = config.infos();
let (i1, _, mut i3) = config.infos();
i3.global.show_warnings_to_stderr();
match compile(&*parsed, i1) {
Err(e) => {
eprintln!("{e:?}");

View File

@ -97,6 +97,8 @@ pub enum EColor {
MaximumRuntimeExceeded,
InCodePositionLine,
Warning,
}
pub trait ETheme: ThemeGen<C = EColor, T = String> {}

View File

@ -42,6 +42,10 @@ pub fn default_theme<C>(
_ => return None,
});
}
if let Warning = color {
// same color as runtime errors, because warnings are only displayed in `check` mode, where the program won't run.
return Some(yellow);
}
let hard_err = red;
let type_right = blue;
let type_wrong = magenta;
@ -56,7 +60,7 @@ pub fn default_theme<C>(
drop(cyan_bright);
use EColor::*;
Some(match color {
Indent(_) => unreachable!(),
Indent(_) | Warning => unreachable!(),
// macros (#...)
WhitespaceAfterHashtag

View File

@ -1,7 +1,7 @@
use std::sync::Arc;
use crate::{
data::{self, tuple::TupleT, Data, MersType, Type},
data::{self, tuple::TupleT, Data, Type},
errors::{CheckError, EColor, SourceRange},
};
@ -47,18 +47,44 @@ impl MersStatement for If {
),
]));
}
let mut t = if Type::new(data::bool::TrueT).is_included_in(&cond_return_type) {
let may_be_true = Type::new(data::bool::TrueT).is_included_in(&cond_return_type);
let may_be_false = Type::new(data::bool::FalseT).is_included_in(&cond_return_type);
let mut t = if may_be_true {
self.on_true.check(info, None)?
} else {
Type::empty()
};
if Type::new(data::bool::FalseT).is_included_in(&cond_return_type) {
if may_be_false {
if let Some(f) = &self.on_false {
t.add_all(&f.check(info, None)?);
} else {
t.add(Arc::new(TupleT(vec![])));
}
}
if let Some(show_warning) = &info.global.show_warnings {
if !may_be_false || !may_be_true {
let mut e = CheckError::new().src(vec![
(self.pos_in_src.clone(), None),
(
self.condition.source_range(),
Some(EColor::IfConditionNotBool),
),
]);
if !may_be_true {
e.msg_mut(vec![(
"Condition in this if-statement is never true".to_owned(),
Some(EColor::Warning),
)]);
}
if !may_be_false {
e.msg_mut(vec![(
"Condition in this if-statement is never false".to_owned(),
Some(EColor::Warning),
)]);
}
show_warning(e);
}
}
Ok(t)
}
fn run_custom(&self, info: &mut super::Info) -> Result<Data, CheckError> {

View File

@ -142,10 +142,11 @@ pub struct CheckLocal {
>,
>,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Default)]
pub struct CheckLocalGlobalInfo {
pub depth: usize,
pub enable_hooks: bool,
pub show_warnings: Option<Arc<dyn Fn(CheckError) + Send + Sync>>,
/// ((results, byte_pos_in_src, deepest_statement))
/// you only have to set `byte_pos_in_src`. `deepest` is used internally.
/// These values should be initialized to `(vec![], _, 0)`, but `0` can be replaced by a minimum statement depth, i.e. `2` to exclude the outer scope (which has depth `1`).
@ -160,6 +161,22 @@ pub struct CheckLocalGlobalInfo {
>,
pub unused_try_statements: Arc<Mutex<Vec<(SourceRange, Vec<Option<SourceRange>>)>>>,
}
impl CheckLocalGlobalInfo {
pub fn show_warnings_to_stderr(&mut self) {
self.show_warnings = Some(Arc::new(|e| {
#[cfg(feature = "ecolor-term")]
let theme = crate::errors::themes::TermDefaultTheme;
#[cfg(not(feature = "ecolor-term"))]
let theme = crate::errors::themes::NoTheme;
eprintln!("{}", e.display(theme));
}));
}
}
impl Debug for CheckLocalGlobalInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CheckLocalGlobalInfo {{ depth: {}, enable_hooks: {}, show_warnings: {}, unused_try_statements: {} }}", self.depth, self.enable_hooks, self.show_warnings.is_some(), self.unused_try_statements.lock().unwrap().len())
}
}
impl Debug for CheckLocal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CheckLocal {:?}, {:?}", self.vars, self.types.keys())