show custom type names in error messages

This commit is contained in:
Mark 2024-08-31 13:14:12 +02:00
parent 817ed25f96
commit 062f100d40
13 changed files with 128 additions and 28 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mers" name = "mers"
version = "0.9.1" version = "0.9.2"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "dynamically typed but type-checked programming language" 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"] colored-output = ["mers_lib/ecolor-term", "mers_lib/pretty-print", "dep:colored"]
[dependencies] [dependencies]
# mers_lib = "0.9.1" mers_lib = "0.9.2"
mers_lib = { path = "../mers_lib" } # mers_lib = { path = "../mers_lib" }
clap = { version = "4.3.19", features = ["derive"] } clap = { version = "4.3.19", features = ["derive"] }
colored = { version = "2.1.0", optional = true } colored = { version = "2.1.0", optional = true }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mers_lib" name = "mers_lib"
version = "0.9.1" version = "0.9.2"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "library to use the mers language in other projects" description = "library to use the mers language in other projects"

View File

@ -86,6 +86,43 @@ pub trait MersType: Any + Debug + Display + Send + Sync {
fn is_reference_to(&self) -> Option<&Type> { fn is_reference_to(&self) -> Option<&Type> {
None None
} }
/// may mutate `self` to simplify it
#[allow(unused)]
fn simplify_for_display(&self, info: &crate::program::run::CheckInfo) -> Option<Type> {
None
}
fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
self.simplify_for_display(info)
.map(|s| s.to_string())
.unwrap_or_else(|| self.to_string())
}
}
#[derive(Clone, Debug)]
pub(crate) struct TypeWithOnlyName(pub(crate) String);
impl MersType for TypeWithOnlyName {
fn is_same_type_as(&self, _other: &dyn MersType) -> bool {
false
}
fn is_included_in(&self, _target: &dyn MersType) -> bool {
false
}
fn subtypes(&self, acc: &mut Type) {
acc.add(Arc::new(self.clone()))
}
fn as_any(&self) -> &dyn Any {
self
}
fn mut_any(&mut self) -> &mut dyn Any {
self
}
fn to_any(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl Display for TypeWithOnlyName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -380,6 +417,38 @@ impl Type {
} }
Some(o) Some(o)
} }
pub fn simplify_for_display(&self, info: &crate::program::run::CheckInfo) -> Type {
let mut out = Type::empty();
'foreachtype: for ty in &self.types {
// find the outmost type alias that isn't shadowed
for (i, scope) in info.scopes.iter().enumerate() {
if let Some((n, _)) = scope.types.iter().find(|(_, t)| {
t.as_ref()
.is_ok_and(|t| t.is_same_type_as(&Type::newm(vec![Arc::clone(ty)])))
}) {
if info
.scopes
.iter()
.skip(i + 1)
.all(|scope| !scope.types.contains_key(n))
{
out.add(Arc::new(TypeWithOnlyName(n.clone())));
continue 'foreachtype;
}
}
}
// no type alias
if let Some(ty) = ty.simplify_for_display(info) {
out.add_all(&ty);
} else {
out.add(Arc::clone(ty))
}
}
out
}
pub fn simplified_as_string(&self, info: &crate::program::run::CheckInfo) -> String {
self.simplify_for_display(info).to_string()
}
} }
impl Display for Type { impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@ -73,6 +73,14 @@ impl MersType for ObjectT {
fn to_any(self) -> Box<dyn std::any::Any> { fn to_any(self) -> Box<dyn std::any::Any> {
Box::new(self) Box::new(self)
} }
fn simplify_for_display(&self, info: &crate::program::run::CheckInfo) -> Option<Type> {
Some(Type::new(Self(
self.0
.iter()
.map(|(n, t)| (n.clone(), t.simplify_for_display(info)))
.collect(),
)))
}
} }
impl Display for Object { impl Display for Object {

View File

@ -90,6 +90,14 @@ impl MersType for TupleT {
fn to_any(self) -> Box<dyn Any> { fn to_any(self) -> Box<dyn Any> {
Box::new(self) Box::new(self)
} }
fn simplify_for_display(&self, info: &crate::program::run::CheckInfo) -> Option<Type> {
Some(Type::new(Self(
self.0
.iter()
.map(|v| v.simplify_for_display(info))
.collect(),
)))
}
} }
impl Display for Tuple { impl Display for Tuple {

View File

@ -320,6 +320,9 @@ impl MersType for ListT {
fn to_any(self) -> Box<dyn std::any::Any> { fn to_any(self) -> Box<dyn std::any::Any> {
Box::new(self) Box::new(self)
} }
fn simplify_for_display(&self, info: &crate::program::run::CheckInfo) -> Option<Type> {
Some(Type::new(Self(self.0.simplify_for_display(info))))
}
} }
impl Display for List { impl Display for List {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@ -50,10 +50,13 @@ impl MersStatement for AsType {
]) ])
.msg(vec![ .msg(vec![
("Type must be included in ".to_owned(), None), ("Type must be included in ".to_owned(), None),
(as_type.to_string(), Some(EColor::AsTypeTypeAnnotation)), (
as_type.simplified_as_string(info),
Some(EColor::AsTypeTypeAnnotation),
),
(", but the actual type ".to_owned(), None), (", but the actual type ".to_owned(), None),
( (
return_type.to_string(), return_type.simplified_as_string(info),
Some(EColor::AsTypeStatementWithTooBroadType), Some(EColor::AsTypeStatementWithTooBroadType),
), ),
(" isn't.".to_owned(), None), (" isn't.".to_owned(), None),

View File

@ -53,11 +53,11 @@ impl MersStatement for AssignTo {
]) ])
.msg(vec![ .msg(vec![
("can't assign ".to_owned(), None), ("can't assign ".to_owned(), None),
(source.to_string(), Some(EColor::AssignFrom)), (source.simplified_as_string(info), Some(EColor::AssignFrom)),
(" to ".to_owned(), None), (" to ".to_owned(), None),
(target.to_string(), Some(EColor::AssignTo)), (target.simplified_as_string(info), Some(EColor::AssignTo)),
(" because it isn't included in ".to_owned(), None), (" because it isn't included in ".to_owned(), None),
(t.to_string(), None), (t.simplified_as_string(info), None),
])); ]));
} }
} else { } else {

View File

@ -57,7 +57,10 @@ impl MersStatement for Chain {
("Can't call ".to_owned(), None), ("Can't call ".to_owned(), None),
("this function".to_owned(), Some(EColor::Function)), ("this function".to_owned(), Some(EColor::Function)),
(" with an argument of type ".to_owned(), None), (" with an argument of type ".to_owned(), None),
(arg.to_string(), Some(EColor::FunctionArgument)), (
arg.simplified_as_string(info),
Some(EColor::FunctionArgument),
),
(":".to_owned(), None), (":".to_owned(), None),
]) ])
.err(e) .err(e)
@ -75,7 +78,10 @@ impl MersStatement for Chain {
]) ])
.msg(vec![ .msg(vec![
("cannot chain with a non-function (".to_owned(), None), ("cannot chain with a non-function (".to_owned(), None),
(func.to_string(), Some(EColor::ChainWithNonFunction)), (
func.simplified_as_string(info),
Some(EColor::ChainWithNonFunction),
),
(")".to_owned(), None), (")".to_owned(), None),
])); ]));
} }

View File

@ -42,7 +42,7 @@ impl MersStatement for If {
None, None,
), ),
( (
cond_return_type.to_string(), cond_return_type.simplified_as_string(info),
Some(EColor::IfConditionNotBool), Some(EColor::IfConditionNotBool),
), ),
])); ]));

View File

@ -1,7 +1,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::{ use crate::{
data::{self, object::ObjectT, Data, Type}, data::{self, object::ObjectT, Data, MersType, Type},
errors::{CheckError, EColor, SourceRange}, errors::{CheckError, EColor, SourceRange},
}; };
@ -33,14 +33,14 @@ impl MersStatement for Object {
("can't init an ".to_owned(), None), ("can't init an ".to_owned(), None),
("object".to_owned(), Some(EColor::InitTo)), ("object".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None), (" with type ".to_owned(), None),
(t.to_string(), Some(EColor::InitFrom)), (t.simplified_as_string(info), Some(EColor::InitFrom)),
if print_is_part_of { if print_is_part_of {
(", which is part of ".to_owned(), None) (", which is part of ".to_owned(), None)
} else { } else {
(String::new(), None) (String::new(), None)
}, },
if print_is_part_of { if print_is_part_of {
(init_to.to_string(), Some(EColor::InitFrom)) (init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else { } else {
(String::new(), None) (String::new(), None)
}, },
@ -57,14 +57,14 @@ impl MersStatement for Object {
("can't init an ".to_owned(), None), ("can't init an ".to_owned(), None),
("object".to_owned(), Some(EColor::InitTo)), ("object".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None), (" with type ".to_owned(), None),
(t.to_string(), Some(EColor::InitFrom)), (t.simplified_as_string(info), Some(EColor::InitFrom)),
if print_is_part_of { if print_is_part_of {
(", which is part of ".to_owned(), None) (", which is part of ".to_owned(), None)
} else { } else {
(format!(""), None) (format!(""), None)
}, },
if print_is_part_of { if print_is_part_of {
(init_to.to_string(), Some(EColor::InitFrom)) (init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else { } else {
(format!(""), None) (format!(""), None)
}, },
@ -83,7 +83,7 @@ impl MersStatement for Object {
format!(", {n}: _") format!(", {n}: _")
}) })
.collect::<String>(), .collect::<String>(),
data::object::ObjectT(t.0.iter().take(self.elems.len()).cloned().collect()) data::object::ObjectT(t.0.iter().take(self.elems.len()).cloned().collect()).simplified_as_string(info)
) )
}, None) }, None)
])); ]));
@ -93,14 +93,14 @@ impl MersStatement for Object {
("can't init an ".to_owned(), None), ("can't init an ".to_owned(), None),
("object".to_owned(), Some(EColor::InitTo)), ("object".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None), (" with type ".to_owned(), None),
(t.to_string(), Some(EColor::InitFrom)), (t.simplified_as_string(info), Some(EColor::InitFrom)),
if print_is_part_of { if print_is_part_of {
(", which is part of ".to_owned(), None) (", which is part of ".to_owned(), None)
} else { } else {
(format!(""), None) (format!(""), None)
}, },
if print_is_part_of { if print_is_part_of {
(init_to.to_string(), Some(EColor::InitFrom)) (init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else { } else {
(format!(""), None) (format!(""), None)
}, },

View File

@ -63,8 +63,10 @@ impl MersStatement for Try {
} else { } else {
return Err(CheckError::new() return Err(CheckError::new()
.msg_str(format!( .msg_str(format!(
"try: #{} is not a function, type is {ft} within {func}.", "try: #{} is not a function, type is {} within {}.",
i + 1 i + 1,
ft.simplified_as_string(info),
func.simplify_for_display(info),
)) ))
.src(vec![ .src(vec![
(self.source_range(), None), (self.source_range(), None),
@ -86,7 +88,8 @@ impl MersStatement for Try {
if !found { if !found {
let mut err = CheckError::new() let mut err = CheckError::new()
.msg_str(format!( .msg_str(format!(
"try: no function found for argument of type {arg}." "try: no function found for argument of type {}.",
arg.simplified_as_string(info)
)) ))
.src(vec![( .src(vec![(
self.pos_in_src.clone(), self.pos_in_src.clone(),

View File

@ -1,7 +1,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::{ use crate::{
data::{self, tuple::TupleT, Data, Type}, data::{self, tuple::TupleT, Data, MersType, Type},
errors::{CheckError, EColor, SourceRange}, errors::{CheckError, EColor, SourceRange},
}; };
@ -34,7 +34,7 @@ impl MersStatement for Tuple {
("can't init a ".to_owned(), None), ("can't init a ".to_owned(), None),
("tuple".to_owned(), Some(EColor::InitTo)), ("tuple".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None), (" with type ".to_owned(), None),
(t.to_string(), Some(EColor::InitFrom)), (t.simplified_as_string(info), Some(EColor::InitFrom)),
( (
if print_is_part_of { if print_is_part_of {
", which is part of ".to_owned() ", which is part of ".to_owned()
@ -44,7 +44,7 @@ impl MersStatement for Tuple {
None, None,
), ),
if print_is_part_of { if print_is_part_of {
(init_to.to_string(), Some(EColor::InitFrom)) (init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else { } else {
(String::new(), None) (String::new(), None)
}, },
@ -62,7 +62,7 @@ impl MersStatement for Tuple {
("can't init a ".to_owned(), None), ("can't init a ".to_owned(), None),
("tuple".to_owned(), Some(EColor::InitTo)), ("tuple".to_owned(), Some(EColor::InitTo)),
(" with type ".to_owned(), None), (" with type ".to_owned(), None),
(t.to_string(), Some(EColor::InitFrom)), (t.simplified_as_string(info), Some(EColor::InitFrom)),
( (
if print_is_part_of { if print_is_part_of {
", which is part of ".to_owned() ", which is part of ".to_owned()
@ -72,7 +72,7 @@ impl MersStatement for Tuple {
None, None,
), ),
if print_is_part_of { if print_is_part_of {
(init_to.to_string(), Some(EColor::InitFrom)) (init_to.simplified_as_string(info), Some(EColor::InitFrom))
} else { } else {
(String::new(), None) (String::new(), None)
}, },