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__/ __pycache__/
test*.py test*.py
/site /site
.venv

22
Cargo.lock generated
View file

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

View file

@ -24,9 +24,9 @@ edition = "2021"
repository = "https://github.com/mtshiba/pylyzer" repository = "https://github.com/mtshiba/pylyzer"
[workspace.dependencies] [workspace.dependencies]
erg_common = { version = "0.6.46-nightly.4", features = ["py_compat", "els"] } erg_common = { version = "0.6.46-nightly.5", features = ["py_compat", "els"] }
erg_compiler = { version = "0.6.46-nightly.4", features = ["py_compat", "els"] } erg_compiler = { version = "0.6.46-nightly.5", features = ["py_compat", "els"] }
els = { version = "0.1.58-nightly.4", features = ["py_compat"] } els = { version = "0.1.58-nightly.5", features = ["py_compat"] }
# rustpython-parser = { version = "0.3.0", features = ["all-nodes-with-ranges", "location"] } # 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-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"] } 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::config::ErgConfig;
use erg_common::dict::Dict as HashMap; use erg_common::dict::Dict as HashMap;
use erg_common::error::Location as ErgLocation;
use erg_common::fresh::FRESH_GEN; use erg_common::fresh::FRESH_GEN;
use erg_common::set::Set as HashSet; use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, Stream}; 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 { fn op_to_token(op: Operator) -> Token {
let (kind, cont) = match op { let (kind, cont) = match op {
Operator::Add => (TokenKind::Plus, "+"), 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.row.get(),
range.start.column.to_zero_indexed(), range.start.column.to_zero_indexed(),
range.end.unwrap().row.get(), 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.row.get(),
loc.column.to_zero_indexed(), loc.column.to_zero_indexed(),
); );
Identifier::new(VisModifierSpec::Public(dot), name) Identifier::new(VisModifierSpec::Public(dot.loc()), name)
} }
// TODO: module member mangling // TODO: module member mangling
@ -744,7 +756,7 @@ impl ASTConverter {
loc.row.get(), loc.row.get(),
loc.column.to_zero_indexed(), 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. // 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 { fn param_pattern_to_var(pat: ParamPattern) -> VarPattern {
match pat { match pat {
ParamPattern::VarName(name) => { ParamPattern::VarName(name) => VarPattern::Ident(Identifier::new(
VarPattern::Ident(Identifier::new(VisModifierSpec::Public(DOT), name)) VisModifierSpec::Public(ErgLocation::Unknown),
} name,
)),
ParamPattern::Discard(token) => VarPattern::Discard(token), ParamPattern::Discard(token) => VarPattern::Discard(token),
other => todo!("{other}"), other => todo!("{other}"),
} }
@ -887,7 +900,7 @@ impl ASTConverter {
let tmp = FRESH_GEN.fresh_varname(); let tmp = FRESH_GEN.fresh_varname();
let tmp_name = VarName::from_str_and_line(tmp, expr.location().row.get()); let tmp_name = VarName::from_str_and_line(tmp, expr.location().row.get());
let tmp_expr = Expr::Accessor(Accessor::Ident(Identifier::new( let tmp_expr = Expr::Accessor(Accessor::Ident(Identifier::new(
VisModifierSpec::Public(DOT), VisModifierSpec::Public(ErgLocation::Unknown),
tmp_name.clone(), tmp_name.clone(),
))); )));
let mut block = vec![]; let mut block = vec![];
@ -991,7 +1004,7 @@ impl ASTConverter {
TokenKind::UBar, TokenKind::UBar,
"_", "_",
loc.row.get(), loc.row.get(),
loc.column.get() - 1, loc.column.to_zero_indexed(),
)) ))
} }
@ -1365,8 +1378,8 @@ impl ASTConverter {
.into_iter() .into_iter()
.map(|elem| self.convert_type_spec(elem)) .map(|elem| self.convert_type_spec(elem))
.collect(); .collect();
let parens = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range); let (l, r) = Self::gen_enclosure_tokens(TokenKind::LParen, tuple.range);
let tuple = TupleTypeSpec::new(Some(parens), tys); let tuple = TupleTypeSpec::new(Some((l.loc(), r.loc())), tys);
TypeSpec::Tuple(tuple) TypeSpec::Tuple(tuple)
} }
_ => Self::gen_dummy_type_spec(args.location()), _ => 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::Complex { real: _, imag: _ } => Expr::Dummy(Dummy::new(None, vec![])),
py_ast::Constant::Str(value) => { 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}\""); let value = format!("\"{value}\"");
// column - 2 because of the quotes // column - 2 because of the quotes
let token = Token::new( let token = Token::new(kind, value, loc.row.get(), loc.column.to_zero_indexed());
TokenKind::StrLit,
value,
loc.row.get(),
loc.column.to_zero_indexed(),
);
Expr::Literal(Literal::new(token)) Expr::Literal(Literal::new(token))
} }
py_ast::Constant::Bool(b) => { py_ast::Constant::Bool(b) => {
@ -1646,7 +1663,7 @@ impl ASTConverter {
.and_then(|last| last.col_end()) .and_then(|last| last.col_end())
.unwrap_or(function.col_end().unwrap_or(0) + 1) .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 paren = {
let lp = Token::new( let lp = Token::new(
@ -1656,7 +1673,7 @@ impl ASTConverter {
function.col_end().unwrap_or(0), function.col_end().unwrap_or(0),
); );
let rp = Token::new(TokenKind::RParen, ")", loc.row.get(), last_col); 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)); let args = Args::new(pos_args, var_args, kw_args, kw_var, Some(paren));
function.call_expr(args) function.call_expr(args)
@ -1816,7 +1833,7 @@ impl ASTConverter {
.into_iter() .into_iter()
.map(|ex| PosArg::new(self.convert_expr(ex))) .map(|ex| PosArg::new(self.convert_expr(ex)))
.collect::<Vec<_>>(); .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))) Expr::Tuple(Tuple::Normal(NormalTuple::new(elems)))
} }
py_ast::Expr::Subscript(subs) => { py_ast::Expr::Subscript(subs) => {
@ -2021,7 +2038,7 @@ impl ASTConverter {
*base_type = Some(Expr::Record(record)); *base_type = Some(Expr::Record(record));
} }
let call_ident = Identifier::new( let call_ident = Identifier::new(
VisModifierSpec::Public(DOT), VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("__call__"), VarName::from_static("__call__"),
); );
let class_ident = Identifier::public_with_line( let class_ident = Identifier::public_with_line(
@ -2046,8 +2063,10 @@ impl ASTConverter {
params, params,
Some(class_spec), Some(class_spec),
)); ));
let unreachable_acc = let unreachable_acc = Identifier::new(
Identifier::new(VisModifierSpec::Public(DOT), VarName::from_static("exit")); VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("exit"),
);
let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty()); let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0)); let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
let def = Def::new(sig, body); let def = Def::new(sig, body);
@ -2056,7 +2075,7 @@ impl ASTConverter {
fn gen_default_init(&self, line: usize) -> Def { fn gen_default_init(&self, line: usize) -> Def {
let call_ident = Identifier::new( let call_ident = Identifier::new(
VisModifierSpec::Public(DOT), VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("__call__"), VarName::from_static("__call__"),
); );
let params = Params::empty(); let params = Params::empty();
@ -2071,8 +2090,10 @@ impl ASTConverter {
params, params,
Some(class_spec), Some(class_spec),
)); ));
let unreachable_acc = let unreachable_acc = Identifier::new(
Identifier::new(VisModifierSpec::Public(DOT), VarName::from_static("exit")); VisModifierSpec::Public(ErgLocation::Unknown),
VarName::from_static("exit"),
);
let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty()); let body = Expr::Accessor(Accessor::Ident(unreachable_acc)).call_expr(Args::empty());
let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0)); let body = DefBody::new(EQUAL, Block::new(vec![body]), DefId(0));
Def::new(sig, body) Def::new(sig, body)
@ -2172,7 +2193,7 @@ impl ASTConverter {
DefId(self.block_id_counter), DefId(self.block_id_counter),
class, class,
class_as_expr, class_as_expr,
VisModifierSpec::Public(DOT), VisModifierSpec::Public(ErgLocation::Unknown),
attrs, attrs,
); );
(base_type, vec![methods]) (base_type, vec![methods])
@ -2556,7 +2577,10 @@ impl ASTConverter {
let tmp = FRESH_GEN.fresh_varname(); let tmp = FRESH_GEN.fresh_varname();
let tmp_name = let tmp_name =
VarName::from_str_and_line(tmp, tuple.location().row.get()); 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 tmp_expr = Expr::Accessor(Accessor::Ident(tmp_ident.clone()));
let sig = Signature::Var(VarSignature::new( let sig = Signature::Var(VarSignature::new(
VarPattern::Ident(tmp_ident), VarPattern::Ident(tmp_ident),
@ -2792,29 +2816,28 @@ impl ASTConverter {
assert_acc.call_expr(args) assert_acc.call_expr(args)
} }
py_ast::Stmt::Import(import) => { py_ast::Stmt::Import(import) => {
let loc = import.location(); let import_loc = import.location();
let mut imports = vec![]; let mut imports = vec![];
for name in import.names { for name in import.names {
let import_acc = Expr::Accessor(Accessor::Ident( 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() { let sym = if name.asname.is_some() {
format!("\"{}\"", name.name.replace('.', "/")) name.name.replace('.', "/")
} else { } else {
format!("\"{}\"", name.name.split('.').next().unwrap()) name.name.split('.').next().unwrap().to_string()
}; };
let mod_name = Expr::Literal(Literal::new(Token::new( let mod_name = Expr::Literal(Literal::new(quoted_symbol(
TokenKind::StrLit, &sym,
cont,
name.location().row.get(), name.location().row.get(),
name.location().column.get() - 1, name.location().column.to_zero_indexed(),
))); )));
let call = import_acc.call1(mod_name); let call = import_acc.call1(mod_name);
let loc = name.location(); let name_loc = name.location();
let def = if let Some(alias) = name.asname { let def = if let Some(alias) = name.asname {
self.register_name_info(&alias, NameKind::Variable); self.register_name_info(&alias, NameKind::Variable);
let var = VarSignature::new( let var = VarSignature::new(
VarPattern::Ident(self.convert_ident(alias.to_string(), loc)), VarPattern::Ident(self.convert_ident(alias.to_string(), name_loc)),
None, None,
); );
Def::new( Def::new(
@ -2841,7 +2864,8 @@ impl ASTConverter {
} }
// from module import foo, bar // from module import foo, bar
py_ast::Stmt::ImportFrom(import_from) => { 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) self.convert_from_import(import_from.module, import_from.names, loc)
} }
py_ast::Stmt::Try(try_) => { py_ast::Stmt::Try(try_) => {
@ -2881,14 +2905,9 @@ impl ASTConverter {
let import_acc = Expr::Accessor(Accessor::Ident( let import_acc = Expr::Accessor(Accessor::Ident(
self.convert_ident("__import__".to_string(), location), self.convert_ident("__import__".to_string(), location),
)); ));
let cont = if module == "." { let sym = if module == "." { "__init__" } else { &module };
"\"__init__\"".to_string() let mod_name = Expr::Literal(Literal::new(quoted_symbol(
} else { sym,
format!("\"{module}\"")
};
let mod_name = Expr::Literal(Literal::new(Token::new(
TokenKind::StrLit,
cont,
location.row.get(), location.row.get(),
location.column.to_zero_indexed(), location.column.to_zero_indexed(),
))); )));
@ -2935,14 +2954,9 @@ impl ASTConverter {
.map(|s| s.replace('.', "/")) .map(|s| s.replace('.', "/"))
.unwrap_or_else(|| ".".to_string()); .unwrap_or_else(|| ".".to_string());
let module_path = Path::new(&module); let module_path = Path::new(&module);
let cont = if module == "." { let sym = if module == "." { "__init__" } else { &module };
"\"__init__\"".to_string() let mod_name = Expr::Literal(Literal::new(quoted_symbol(
} else { sym,
format!("\"{module}\"")
};
let mod_name = Expr::Literal(Literal::new(Token::new(
TokenKind::StrLit,
cont,
location.row.get(), location.row.get(),
location.column.to_zero_indexed(), location.column.to_zero_indexed(),
))); )));
@ -2952,6 +2966,10 @@ impl ASTConverter {
if names.len() == 1 && names[0].name.as_str() == "*" { if names.len() == 1 && names[0].name.as_str() == "*" {
return self.convert_glob_import(location, module); 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 { for name in names {
let name_path = self let name_path = self
.cfg .cfg
@ -2975,10 +2993,9 @@ impl ASTConverter {
} }
let mod_name = path.file_name().unwrap(); let mod_name = path.file_name().unwrap();
if name.name.as_str() == mod_name.to_string_lossy().trim_end_matches(".py") { if name.name.as_str() == mod_name.to_string_lossy().trim_end_matches(".py") {
let cont = format!("\"{module}/{}\"", name.name); let sym = format!("{module}/{}", name.name);
let mod_name = Expr::Literal(Literal::new(Token::new( let mod_name = Expr::Literal(Literal::new(quoted_symbol(
TokenKind::StrLit, &sym,
cont,
location.row.get(), location.row.get(),
location.column.to_zero_indexed(), location.column.to_zero_indexed(),
))); )));
@ -2998,7 +3015,8 @@ impl ASTConverter {
} }
let no_import = imports.is_empty(); let no_import = imports.is_empty();
let attrs = VarRecordAttrs::new(imports); 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 var = VarSignature::new(VarPattern::Record(pat), None);
let def = Expr::Def(Def::new( let def = Expr::Def(Def::new(
Signature::Var(var), Signature::Var(var),

View file

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

View file

@ -1,6 +1,6 @@
use erg_common::error::ErrorKind; use erg_common::error::ErrorKind;
use erg_common::log; 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_common::style::{remove_style, StyledString, Color};
use erg_compiler::context::ModuleContext; use erg_compiler::context::ModuleContext;
use erg_compiler::error::{CompileError, CompileErrors}; 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> { fn handle_name_error(error: CompileError) -> Option<CompileError> {
if error.core.main_message.contains("is already declared") let main = &error.core.main_message;
|| error if main.contains("is already declared")
.core || main.contains("cannot be assigned more than once")
.main_message || {
.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 None
} else { } else {