fix: misalignment of error display

This commit is contained in:
Shunsuke Shibayama 2024-10-13 18:31:06 +09:00
parent 8621139e64
commit c1f37108a0
6 changed files with 108 additions and 80 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
__pycache__/
test*.py
/site
.venv

22
Cargo.lock generated
View file

@ -145,23 +145,25 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "els"
version = "0.1.58-nightly.4"
version = "0.1.58-nightly.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82ca64c7e007a801f3c026026d4f7c65193ca2ccfab19018cf47b0946ed1de86"
checksum = "73c6e882638db2b88b5a529d52c94c493b48a802bf418974ff2aadc9dea2383d"
dependencies = [
"erg_common",
"erg_compiler",
"libc",
"lsp-types",
"molc",
"serde",
"serde_json",
"windows",
]
[[package]]
name = "erg_common"
version = "0.6.46-nightly.4"
version = "0.6.46-nightly.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c91d7308be743f27d0bcb6778d85d76bfad86fc54ae53ae5fab06b37bd54fd74"
checksum = "168c67e9de97fa12ade0f27a8e4f0037efd0576285cbb13c19e8724129abac53"
dependencies = [
"backtrace-on-stack-overflow",
"erg_proc_macros",
@ -172,9 +174,9 @@ dependencies = [
[[package]]
name = "erg_compiler"
version = "0.6.46-nightly.4"
version = "0.6.46-nightly.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ca9d5eb0b29b60d7ac8d7d639add33a4b331b35e4739775f0bd0f1e94be764"
checksum = "1c303d57ad8238b388bf90eb3660681668a8fb3c8b77fff2833b348b7a767617"
dependencies = [
"erg_common",
"erg_parser",
@ -182,9 +184,9 @@ dependencies = [
[[package]]
name = "erg_parser"
version = "0.6.46-nightly.4"
version = "0.6.46-nightly.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d0f70495239bd721afb1be7ba33c9146cbd7d4d578bd65fcb86e52561224e0"
checksum = "f0f1c0508bb6aa189c7ded5f4a260537aa4d16a40018be64f3bd4f65d140b46b"
dependencies = [
"erg_common",
"erg_proc_macros",
@ -193,9 +195,9 @@ dependencies = [
[[package]]
name = "erg_proc_macros"
version = "0.6.46-nightly.4"
version = "0.6.46-nightly.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61073a06b84b2e9c36b3645494102780936b560ba80f8c466cf2cdc374740f3e"
checksum = "ef2f7b89cccd974d2ab3dc31b79417c2a6d53490c9c96dcc1ad9ed7513ef4bf7"
dependencies = [
"quote",
"syn 1.0.109",

View file

@ -24,9 +24,9 @@ edition = "2021"
repository = "https://github.com/mtshiba/pylyzer"
[workspace.dependencies]
erg_common = { version = "0.6.46-nightly.4", features = ["py_compat", "els"] }
erg_compiler = { version = "0.6.46-nightly.4", features = ["py_compat", "els"] }
els = { version = "0.1.58-nightly.4", features = ["py_compat"] }
erg_common = { version = "0.6.46-nightly.5", features = ["py_compat", "els"] }
erg_compiler = { version = "0.6.46-nightly.5", features = ["py_compat", "els"] }
els = { version = "0.1.58-nightly.5", features = ["py_compat"] }
# rustpython-parser = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] }
# rustpython-ast = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] }
rustpython-parser = { git = "https://github.com/RustPython/Parser", version = "0.4.0", features = ["all-nodes-with-ranges", "location"] }

View file

@ -3,6 +3,7 @@ use std::path::Path;
use erg_common::config::ErgConfig;
use erg_common::dict::Dict as HashMap;
use erg_common::error::Location as ErgLocation;
use erg_common::fresh::FRESH_GEN;
use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, Stream};
@ -140,6 +141,17 @@ fn escape_name(name: String) -> String {
}
}
fn quoted_symbol(sym: &str, lineno: u32, col_begin: u32) -> Token {
let col_end = col_begin + sym.chars().count() as u32;
Token {
kind: TokenKind::StrLit,
content: format!("\"{sym}\"").into(),
lineno,
col_begin,
col_end,
}
}
fn op_to_token(op: Operator) -> Token {
let (kind, cont) = match op {
Operator::Add => (TokenKind::Plus, "+"),
@ -164,7 +176,7 @@ pub fn pyloc_to_ergloc(range: PySourceRange) -> erg_common::error::Location {
range.start.row.get(),
range.start.column.to_zero_indexed(),
range.end.unwrap().row.get(),
range.end.unwrap().column.get(),
range.end.unwrap().column.to_zero_indexed(),
)
}
@ -726,7 +738,7 @@ impl ASTConverter {
loc.row.get(),
loc.column.to_zero_indexed(),
);
Identifier::new(VisModifierSpec::Public(dot), name)
Identifier::new(VisModifierSpec::Public(dot.loc()), name)
}
// TODO: module member mangling
@ -744,7 +756,7 @@ impl ASTConverter {
loc.row.get(),
loc.column.to_zero_indexed(),
);
Identifier::new(VisModifierSpec::Public(dot), name)
Identifier::new(VisModifierSpec::Public(dot.loc()), name)
}
// Duplicate param names will result in an error at the parser. So we don't need to check it here.
@ -849,9 +861,10 @@ impl ASTConverter {
fn param_pattern_to_var(pat: ParamPattern) -> VarPattern {
match pat {
ParamPattern::VarName(name) => {
VarPattern::Ident(Identifier::new(VisModifierSpec::Public(DOT), name))
}
ParamPattern::VarName(name) => VarPattern::Ident(Identifier::new(
VisModifierSpec::Public(ErgLocation::Unknown),
name,
)),
ParamPattern::Discard(token) => VarPattern::Discard(token),
other => todo!("{other}"),
}
@ -887,7 +900,7 @@ impl ASTConverter {
let tmp = FRESH_GEN.fresh_varname();
let tmp_name = VarName::from_str_and_line(tmp, expr.location().row.get());
let tmp_expr = Expr::Accessor(Accessor::Ident(Identifier::new(
VisModifierSpec::Public(DOT),
VisModifierSpec::Public(ErgLocation::Unknown),
tmp_name.clone(),
)));
let mut block = vec![];
@ -991,7 +1004,7 @@ impl ASTConverter {
TokenKind::UBar,
"_",
loc.row.get(),
loc.column.get() - 1,
loc.column.to_zero_indexed(),
))
}
@ -1365,8 +1378,8 @@ impl ASTConverter {
.into_iter()
.map(|elem| self.convert_type_spec(elem))
.collect();
let parens = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
let tuple = TupleTypeSpec::new(Some(parens), tys);
let (l, r) = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
let tuple = TupleTypeSpec::new(Some((l.loc(), r.loc())), tys);
TypeSpec::Tuple(tuple)
}
_ => Self::gen_dummy_type_spec(args.location()),
@ -1527,14 +1540,18 @@ impl ASTConverter {
}
py_ast::Constant::Complex { real: _, imag: _ } => Expr::Dummy(Dummy::new(None, vec![])),
py_ast::Constant::Str(value) => {
let kind = if const_
.range
.end
.is_some_and(|end| end.row != const_.range.start.row)
{
TokenKind::DocComment
} else {
TokenKind::StrLit
};
let value = format!("\"{value}\"");
// column - 2 because of the quotes
let token = Token::new(
TokenKind::StrLit,
value,
loc.row.get(),
loc.column.to_zero_indexed(),
);
let token = Token::new(kind, value, loc.row.get(), loc.column.to_zero_indexed());
Expr::Literal(Literal::new(token))
}
py_ast::Constant::Bool(b) => {
@ -1646,7 +1663,7 @@ impl ASTConverter {
.and_then(|last| last.col_end())
.unwrap_or(function.col_end().unwrap_or(0) + 1)
},
|loc| loc.row.get(),
|loc| loc.column.to_zero_indexed().saturating_sub(1),
);
let paren = {
let lp = Token::new(
@ -1656,7 +1673,7 @@ impl ASTConverter {
function.col_end().unwrap_or(0),
);
let rp = Token::new(TokenKind::RParen, ")", loc.row.get(), last_col);
(lp, rp)
(lp.loc(), rp.loc())
};
let args = Args::new(pos_args, var_args, kw_args, kw_var, Some(paren));
function.call_expr(args)
@ -1816,7 +1833,7 @@ impl ASTConverter {
.into_iter()
.map(|ex| PosArg::new(self.convert_expr(ex)))
.collect::<Vec<_>>();
let elems = Args::pos_only(elements, Some((l, r)));
let elems = Args::pos_only(elements, Some((l.loc(), r.loc())));
Expr::Tuple(Tuple::Normal(NormalTuple::new(elems)))
}
py_ast::Expr::Subscript(subs) => {
@ -2021,7 +2038,7 @@ impl ASTConverter {
*base_type = Some(Expr::Record(record));
}
let call_ident = Identifier::new(
VisModifierSpec::Public(DOT),
VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("__call__"),
);
let class_ident = Identifier::public_with_line(
@ -2046,8 +2063,10 @@ impl ASTConverter {
params,
Some(class_spec),
));
let unreachable_acc =
Identifier::new(VisModifierSpec::Public(DOT), VarName::from_static("exit"));
let unreachable_acc = Identifier::new(
VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("exit"),
);
let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
let def = Def::new(sig, body);
@ -2056,7 +2075,7 @@ impl ASTConverter {
fn gen_default_init(&self, line: usize) -> Def {
let call_ident = Identifier::new(
VisModifierSpec::Public(DOT),
VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("__call__"),
);
let params = Params::empty();
@ -2071,8 +2090,10 @@ impl ASTConverter {
params,
Some(class_spec),
));
let unreachable_acc =
Identifier::new(VisModifierSpec::Public(DOT), VarName::from_static("exit"));
let unreachable_acc = Identifier::new(
VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("exit"),
);
let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
Def::new(sig, body)
@ -2172,7 +2193,7 @@ impl ASTConverter {
DefId(self.block_id_counter),
class,
class_as_expr,
VisModifierSpec::Public(DOT),
VisModifierSpec::Public(ErgLocation::Unknown),
attrs,
);
(base_type, vec![methods])
@ -2556,7 +2577,10 @@ impl ASTConverter {
let tmp = FRESH_GEN.fresh_varname();
let tmp_name =
VarName::from_str_and_line(tmp, tuple.location().row.get());
let tmp_ident = Identifier::new(VisModifierSpec::Public(DOT), tmp_name);
let tmp_ident = Identifier::new(
VisModifierSpec::Public(ErgLocation::Unknown),
tmp_name,
);
let tmp_expr = Expr::Accessor(Accessor::Ident(tmp_ident.clone()));
let sig = Signature::Var(VarSignature::new(
VarPattern::Ident(tmp_ident),
@ -2792,29 +2816,28 @@ impl ASTConverter {
assert_acc.call_expr(args)
}
py_ast::Stmt::Import(import) => {
let loc = import.location();
let import_loc = import.location();
let mut imports = vec![];
for name in import.names {
let import_acc = Expr::Accessor(Accessor::Ident(
self.convert_ident("__import__".to_string(), loc),
self.convert_ident("__import__".to_string(), import_loc),
));
let cont = if name.asname.is_some() {
format!("\"{}\"", name.name.replace('.', "/"))
let sym = if name.asname.is_some() {
name.name.replace('.', "/")
} else {
format!("\"{}\"", name.name.split('.').next().unwrap())
name.name.split('.').next().unwrap().to_string()
};
let mod_name = Expr::Literal(Literal::new(Token::new(
TokenKind::StrLit,
cont,
let mod_name = Expr::Literal(Literal::new(quoted_symbol(
&sym,
name.location().row.get(),
name.location().column.get() - 1,
name.location().column.to_zero_indexed(),
)));
let call = import_acc.call1(mod_name);
let loc = name.location();
let name_loc = name.location();
let def = if let Some(alias) = name.asname {
self.register_name_info(&alias, NameKind::Variable);
let var = VarSignature::new(
VarPattern::Ident(self.convert_ident(alias.to_string(), loc)),
VarPattern::Ident(self.convert_ident(alias.to_string(), name_loc)),
None,
);
Def::new(
@ -2841,7 +2864,8 @@ impl ASTConverter {
}
// from module import foo, bar
py_ast::Stmt::ImportFrom(import_from) => {
let loc = import_from.location();
let mut loc = import_from.location();
loc.column = loc.column.saturating_add(5);
self.convert_from_import(import_from.module, import_from.names, loc)
}
py_ast::Stmt::Try(try_) => {
@ -2881,14 +2905,9 @@ impl ASTConverter {
let import_acc = Expr::Accessor(Accessor::Ident(
self.convert_ident("__import__".to_string(), location),
));
let cont = if module == "." {
"\"__init__\"".to_string()
} else {
format!("\"{module}\"")
};
let mod_name = Expr::Literal(Literal::new(Token::new(
TokenKind::StrLit,
cont,
let sym = if module == "." { "__init__" } else { &module };
let mod_name = Expr::Literal(Literal::new(quoted_symbol(
sym,
location.row.get(),
location.column.to_zero_indexed(),
)));
@ -2935,14 +2954,9 @@ impl ASTConverter {
.map(|s| s.replace('.', "/"))
.unwrap_or_else(|| ".".to_string());
let module_path = Path::new(&module);
let cont = if module == "." {
"\"__init__\"".to_string()
} else {
format!("\"{module}\"")
};
let mod_name = Expr::Literal(Literal::new(Token::new(
TokenKind::StrLit,
cont,
let sym = if module == "." { "__init__" } else { &module };
let mod_name = Expr::Literal(Literal::new(quoted_symbol(
sym,
location.row.get(),
location.column.to_zero_indexed(),
)));
@ -2952,6 +2966,10 @@ impl ASTConverter {
if names.len() == 1 && names[0].name.as_str() == "*" {
return self.convert_glob_import(location, module);
}
let names_range = PySourceRange {
start: names[0].location(),
end: names[names.len() - 1].end_location(),
};
for name in names {
let name_path = self
.cfg
@ -2975,10 +2993,9 @@ impl ASTConverter {
}
let mod_name = path.file_name().unwrap();
if name.name.as_str() == mod_name.to_string_lossy().trim_end_matches(".py") {
let cont = format!("\"{module}/{}\"", name.name);
let mod_name = Expr::Literal(Literal::new(Token::new(
TokenKind::StrLit,
cont,
let sym = format!("{module}/{}", name.name);
let mod_name = Expr::Literal(Literal::new(quoted_symbol(
&sym,
location.row.get(),
location.column.to_zero_indexed(),
)));
@ -2998,7 +3015,8 @@ impl ASTConverter {
}
let no_import = imports.is_empty();
let attrs = VarRecordAttrs::new(imports);
let pat = VarRecordPattern::new(Token::DUMMY, attrs, Token::DUMMY);
let braces = pyloc_to_ergloc(names_range);
let pat = VarRecordPattern::new(braces, attrs);
let var = VarSignature::new(VarPattern::Record(pat), None);
let def = Expr::Def(Def::new(
Signature::Var(var),

View file

@ -127,7 +127,7 @@ impl DeclFileGenerator {
let decl = format!(".{class_name}: ClassType");
self.code += &decl;
self.code.push('\n');
if let GenTypeObj::Subclass(class) = &def.obj {
if let GenTypeObj::Subclass(class) = def.obj.as_ref() {
let sup = class
.sup
.as_ref()

View file

@ -1,6 +1,6 @@
use erg_common::error::ErrorKind;
use erg_common::log;
use erg_common::style::remove_style;
use erg_common::style::{remove_style, StyledStr};
// use erg_common::style::{remove_style, StyledString, Color};
use erg_compiler::context::ModuleContext;
use erg_compiler::error::{CompileError, CompileErrors};
@ -13,11 +13,18 @@ pub(crate) fn filter_errors(ctx: &ModuleContext, errors: CompileErrors) -> Compi
}
fn handle_name_error(error: CompileError) -> Option<CompileError> {
if error.core.main_message.contains("is already declared")
|| error
.core
.main_message
.contains("cannot be assigned more than once")
let main = &error.core.main_message;
if main.contains("is already declared")
|| main.contains("cannot be assigned more than once")
|| {
main.contains(" is not defined") && {
let name = StyledStr::destyle(main.trim_end_matches(" is not defined"));
error
.core
.get_hint()
.is_some_and(|hint| hint.contains(name))
}
}
{
None
} else {