From 939c2ff89f77d40b12967c058eb72cbb267d8a69 Mon Sep 17 00:00:00 2001 From: He1pa <56333845+He1pa@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:27:40 +0800 Subject: [PATCH] Feat: Change diagnostic position from pos(start) to range(start, end) (#638) * feat: change position of diag. Change the position of diagnostic from pos(start) to range(start, end) * define type alias `type Range = (Position, Position)` --- kclvm/ast/src/ast.rs | 6 +- kclvm/ast/src/pos.rs | 4 +- kclvm/compiler/src/codegen/llvm/context.rs | 14 +- kclvm/error/src/diagnostic.rs | 12 +- kclvm/error/src/error.rs | 4 +- kclvm/error/src/lib.rs | 71 ++++---- kclvm/parser/src/lib.rs | 9 +- kclvm/sema/src/lint/lints_def.rs | 37 ++-- kclvm/sema/src/resolver/arg.rs | 12 +- kclvm/sema/src/resolver/attr.rs | 11 +- kclvm/sema/src/resolver/calculation.rs | 19 +- kclvm/sema/src/resolver/config.rs | 26 +-- kclvm/sema/src/resolver/global.rs | 95 +++++----- kclvm/sema/src/resolver/import.rs | 14 +- kclvm/sema/src/resolver/loop.rs | 26 +-- kclvm/sema/src/resolver/mod.rs | 3 +- kclvm/sema/src/resolver/node.rs | 192 +++++++++++++-------- kclvm/sema/src/resolver/para.rs | 2 +- kclvm/sema/src/resolver/schema.rs | 17 +- kclvm/sema/src/resolver/scope.rs | 23 ++- kclvm/sema/src/resolver/tests.rs | 63 ++++--- kclvm/sema/src/resolver/ty.rs | 53 +++--- kclvm/sema/src/resolver/var.rs | 48 +++--- kclvm/tools/src/LSP/src/tests.rs | 81 +++++++-- kclvm/tools/src/LSP/src/to_lsp.rs | 8 +- kclvm/tools/src/lint/mod.rs | 17 +- 26 files changed, 501 insertions(+), 366 deletions(-) diff --git a/kclvm/ast/src/ast.rs b/kclvm/ast/src/ast.rs index 72548f381..8206d599a 100644 --- a/kclvm/ast/src/ast.rs +++ b/kclvm/ast/src/ast.rs @@ -42,7 +42,7 @@ use compiler_base_span::{Loc, Span}; use super::token; use crate::{node_ref, pos::ContainsPos}; -use kclvm_error::Position; +use kclvm_error::{diagnostic::Range, Position}; /// PosTuple denotes the tuple `(filename, line, column, end_line, end_column)`. pub type PosTuple = (String, u64, u64, u64, u64); @@ -62,8 +62,8 @@ impl Into for Pos { } } -impl Into<(Position, Position)> for Pos { - fn into(self) -> (Position, Position) { +impl Into for Pos { + fn into(self) -> Range { ( Position { filename: self.0.clone(), diff --git a/kclvm/ast/src/pos.rs b/kclvm/ast/src/pos.rs index c437faab7..1ed481c71 100644 --- a/kclvm/ast/src/pos.rs +++ b/kclvm/ast/src/pos.rs @@ -1,4 +1,4 @@ -use kclvm_error::Position; +use kclvm_error::{diagnostic::Range, Position}; use crate::ast; @@ -9,7 +9,7 @@ pub trait ContainsPos { pub trait GetPos { /// Get start and end position from node. - fn get_span_pos(&self) -> (Position, Position) { + fn get_span_pos(&self) -> Range { (self.get_pos(), self.get_end_pos()) } /// Get start pos from node. diff --git a/kclvm/compiler/src/codegen/llvm/context.rs b/kclvm/compiler/src/codegen/llvm/context.rs index 4954e6109..9873659b0 100644 --- a/kclvm/compiler/src/codegen/llvm/context.rs +++ b/kclvm/compiler/src/codegen/llvm/context.rs @@ -1777,14 +1777,12 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { let is_in_schema = self.schema_stack.borrow().len() > 0; if !is_in_schema { let mut handler = self.handler.borrow_mut(); - handler.add_compile_error( - &err.message, - Position { - filename: self.current_filename(), - line: *self.current_line.borrow(), - column: None, - }, - ); + let pos = Position { + filename: self.current_filename(), + line: *self.current_line.borrow(), + column: None, + }; + handler.add_compile_error(&err.message, (pos.clone(), pos)); handler.abort_if_any_errors() } result diff --git a/kclvm/error/src/diagnostic.rs b/kclvm/error/src/diagnostic.rs index 2ba7fdd27..6e7f96df5 100644 --- a/kclvm/error/src/diagnostic.rs +++ b/kclvm/error/src/diagnostic.rs @@ -95,8 +95,8 @@ impl From for Position { } impl Diagnostic { - pub fn new(level: Level, message: &str, pos: Position) -> Self { - Diagnostic::new_with_code(level, message, None, pos, None) + pub fn new(level: Level, message: &str, range: Range) -> Self { + Diagnostic::new_with_code(level, message, None, range, None) } /// New a diagnostic with error code. @@ -104,13 +104,13 @@ impl Diagnostic { level: Level, message: &str, note: Option<&str>, - pos: Position, + range: Range, code: Option, ) -> Self { Diagnostic { level, messages: vec![Message { - pos, + range, style: Style::LineAndColumn, message: message.to_string(), note: note.map(|s| s.to_string()), @@ -125,9 +125,11 @@ impl Diagnostic { } } +pub type Range = (Position, Position); + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Message { - pub pos: Position, + pub range: Range, pub style: Style, pub message: String, pub note: Option, diff --git a/kclvm/error/src/error.rs b/kclvm/error/src/error.rs index 10fdcdce6..577d343c3 100644 --- a/kclvm/error/src/error.rs +++ b/kclvm/error/src/error.rs @@ -142,7 +142,7 @@ pub enum WarningKind { /// let mut handler = Handler::default(); /// handler.add_warning(WarningKind::UnusedImportWarning, &[ /// Message { -/// pos: Position::dummy_pos(), +/// range: (Position::dummy_pos(), Position::dummy_pos()), /// style: Style::LineAndColumn, /// message: "Module 'a' imported but unused.".to_string(), /// note: None, @@ -168,7 +168,7 @@ impl std::fmt::Display for WarningKind { /// let mut handler = Handler::default(); /// handler.add_warning(WarningKind::UnusedImportWarning, &[ /// Message { -/// pos: Position::dummy_pos(), +/// range: (Position::dummy_pos(), Position::dummy_pos()), /// style: Style::LineAndColumn, /// message: "Module 'a' imported but unused.".to_string(), /// note: None, diff --git a/kclvm/error/src/lib.rs b/kclvm/error/src/lib.rs index b0fdf8e48..7a736cb20 100644 --- a/kclvm/error/src/lib.rs +++ b/kclvm/error/src/lib.rs @@ -18,6 +18,7 @@ use compiler_base_error::{ }; use compiler_base_session::{Session, SessionDiagnostic}; use compiler_base_span::{span::new_byte_pos, Span}; +use diagnostic::Range; use indexmap::IndexSet; use kclvm_runtime::PanicInfo; use std::{any::Any, sync::Arc}; @@ -91,13 +92,13 @@ impl Handler { } /// Construct a parse error and put it into the handler diagnostic buffer - pub fn add_syntex_error(&mut self, msg: &str, pos: Position) -> &mut Self { + pub fn add_syntex_error(&mut self, msg: &str, range: Range) -> &mut Self { let message = format!("Invalid syntax: {msg}"); let diag = Diagnostic::new_with_code( Level::Error, &message, None, - pos, + range, Some(DiagnosticId::Error(E1001.kind)), ); self.add_diagnostic(diag); @@ -106,12 +107,12 @@ impl Handler { } /// Construct a type error and put it into the handler diagnostic buffer - pub fn add_type_error(&mut self, msg: &str, pos: Position) -> &mut Self { + pub fn add_type_error(&mut self, msg: &str, range: Range) -> &mut Self { let diag = Diagnostic::new_with_code( Level::Error, msg, None, - pos, + range, Some(DiagnosticId::Error(E2G22.kind)), ); self.add_diagnostic(diag); @@ -120,12 +121,12 @@ impl Handler { } /// Construct a type error and put it into the handler diagnostic buffer - pub fn add_compile_error(&mut self, msg: &str, pos: Position) -> &mut Self { + pub fn add_compile_error(&mut self, msg: &str, range: Range) -> &mut Self { let diag = Diagnostic::new_with_code( Level::Error, msg, None, - pos, + range, Some(DiagnosticId::Error(E2L23.kind)), ); self.add_diagnostic(diag); @@ -146,7 +147,7 @@ impl Handler { /// let mut handler = Handler::default(); /// handler.add_error(ErrorKind::InvalidSyntax, &[ /// Message { - /// pos: Position::dummy_pos(), + /// range: (Position::dummy_pos(), Position::dummy_pos()), /// style: Style::LineAndColumn, /// message: "Invalid syntax: expected '+', got '-'".to_string(), /// note: None, @@ -170,7 +171,7 @@ impl Handler { /// let mut handler = Handler::default(); /// handler.add_warning(WarningKind::UnusedImportWarning, &[ /// Message { - /// pos: Position::dummy_pos(), + /// range: (Position::dummy_pos(), Position::dummy_pos()), /// style: Style::LineAndColumn, /// message: "Module 'a' imported but unused.".to_string(), /// note: None, @@ -210,7 +211,7 @@ impl Handler { /// ``` /// use kclvm_error::*; /// let mut handler = Handler::default(); - /// handler.add_diagnostic(Diagnostic::new_with_code(Level::Error, "error message", None, Position::dummy_pos(), Some(DiagnosticId::Error(E1001.kind)))); + /// handler.add_diagnostic(Diagnostic::new_with_code(Level::Error, "error message", None, (Position::dummy_pos(), Position::dummy_pos()), Some(DiagnosticId::Error(E1001.kind)))); /// ``` #[inline] pub fn add_diagnostic(&mut self, diagnostic: Diagnostic) -> &mut Self { @@ -229,17 +230,12 @@ impl From for Diagnostic { }; let mut diag = if panic_info.backtrace.is_empty() { - Diagnostic::new_with_code( - Level::Error, - &panic_msg, - None, - Position { - filename: panic_info.kcl_file.clone(), - line: panic_info.kcl_line as u64, - column: None, - }, - None, - ) + let pos = Position { + filename: panic_info.kcl_file.clone(), + line: panic_info.kcl_line as u64, + column: None, + }; + Diagnostic::new_with_code(Level::Error, &panic_msg, None, (pos.clone(), pos), None) } else { let mut backtrace_msg = "backtrace:\n".to_string(); let mut backtrace = panic_info.backtrace.clone(); @@ -254,15 +250,16 @@ impl From for Diagnostic { } backtrace_msg.push_str("\n") } + let pos = Position { + filename: panic_info.kcl_file.clone(), + line: panic_info.kcl_line as u64, + column: None, + }; Diagnostic::new_with_code( Level::Error, &panic_msg, Some(&backtrace_msg), - Position { - filename: panic_info.kcl_file.clone(), - line: panic_info.kcl_line as u64, - column: None, - }, + (pos.clone(), pos), None, ) }; @@ -270,15 +267,16 @@ impl From for Diagnostic { if panic_info.kcl_config_meta_file.is_empty() { return diag; } + let pos = Position { + filename: panic_info.kcl_config_meta_file.clone(), + line: panic_info.kcl_config_meta_line as u64, + column: Some(panic_info.kcl_config_meta_col as u64), + }; let mut config_meta_diag = Diagnostic::new_with_code( Level::Error, &panic_info.kcl_config_meta_arg_msg, None, - Position { - filename: panic_info.kcl_config_meta_file.clone(), - line: panic_info.kcl_config_meta_line as u64, - column: Some(panic_info.kcl_config_meta_col as u64), - }, + (pos.clone(), pos), None, ); config_meta_diag.messages.append(&mut diag.messages); @@ -329,11 +327,12 @@ impl ParseError { ParseError::Message { span, .. } => span, }; let loc = sess.sm.lookup_char_pos(span.lo()); + let pos: Position = loc.into(); Ok(Diagnostic::new_with_code( Level::Error, &self.to_string(), None, - loc.into(), + (pos.clone(), pos), Some(DiagnosticId::Error(ErrorKind::InvalidSyntax)), )) } @@ -399,10 +398,10 @@ impl SessionDiagnostic for Diagnostic { }, } for msg in &self.messages { - match Session::new_with_file_and_code(&msg.pos.filename, None) { + match Session::new_with_file_and_code(&msg.range.0.filename, None) { Ok(sess) => { let source = sess.sm.lookup_source_file(new_byte_pos(0)); - let line = source.get_line((msg.pos.line - 1) as usize); + let line = source.get_line((msg.range.0.line - 1) as usize); match line.as_ref() { Some(content) => { let snippet = Snippet { @@ -410,10 +409,10 @@ impl SessionDiagnostic for Diagnostic { footer: vec![], slices: vec![Slice { source: content, - line_start: msg.pos.line as usize, - origin: Some(&msg.pos.filename), + line_start: msg.range.0.line as usize, + origin: Some(&msg.range.0.filename), annotations: vec![SourceAnnotation { - range: match msg.pos.column { + range: match msg.range.0.column { Some(column) if content.len() >= 1 => { let column = column as usize; // If the position exceeds the length of the content, diff --git a/kclvm/parser/src/lib.rs b/kclvm/parser/src/lib.rs index 818258183..cbc7a6c68 100644 --- a/kclvm/parser/src/lib.rs +++ b/kclvm/parser/src/lib.rs @@ -17,7 +17,8 @@ use compiler_base_session::Session; use compiler_base_span::span::new_byte_pos; use kclvm_ast::ast; use kclvm_config::modfile::{get_vendor_home, KCL_FILE_EXTENSION, KCL_FILE_SUFFIX, KCL_MOD_FILE}; -use kclvm_error::{ErrorKind, Message, Position, Style}; +use kclvm_error::diagnostic::Range; +use kclvm_error::{ErrorKind, Message, Style}; use kclvm_sema::plugin::PLUGIN_MODULE_PREFIX; use kclvm_utils::path::PathPrefix; use kclvm_utils::pkgpath::parse_external_pkg_name; @@ -354,7 +355,7 @@ impl Loader { self.sess.1.borrow_mut().add_error( ErrorKind::CannotFindModule, &[Message { - pos: Into::<(Position, Position)>::into(pos).0, + range: Into::::into(pos), style: Style::Line, message: format!( "the `{}` is found multiple times in the current package and vendor package", @@ -373,7 +374,7 @@ impl Loader { self.sess.1.borrow_mut().add_error( ErrorKind::CannotFindModule, &[Message { - pos: Into::<(Position, Position)>::into(pos).0, + range: Into::::into(pos), style: Style::Line, message: format!("pkgpath {} not found in the program", pkg_path), note: None, @@ -469,7 +470,7 @@ impl Loader { self.sess.1.borrow_mut().add_error( ErrorKind::CannotFindModule, &[Message { - pos: Into::<(Position, Position)>::into(pos).0, + range: Into::::into(pos), style: Style::Line, message: format!("the plugin package `{}` is not found, please confirm if plugin mode is enabled", pkgpath), note: None, diff --git a/kclvm/sema/src/lint/lints_def.rs b/kclvm/sema/src/lint/lints_def.rs index 1495bfbef..d2d778d6f 100644 --- a/kclvm/sema/src/lint/lints_def.rs +++ b/kclvm/sema/src/lint/lints_def.rs @@ -4,7 +4,8 @@ use crate::resolver::scope::Scope; use crate::{declare_lint_pass, resolver::scope::ScopeObjectKind}; use indexmap::IndexSet; use kclvm_ast::ast; -use kclvm_error::{Handler, Level, Message, Position, Style, WarningKind}; +use kclvm_ast::pos::GetPos; +use kclvm_error::{Handler, Level, Message, Style, WarningKind}; /// The 'import_position' lint detects import statements that are not declared at the top of file. /// ### Example @@ -30,7 +31,12 @@ pub static IMPORT_POSITION: &Lint = &Lint { declare_lint_pass!(ImportPosition => [IMPORT_POSITION]); impl LintPass for ImportPosition { - fn check_module(&mut self, handler: &mut Handler, ctx: &mut LintContext, module: &ast::Module) { + fn check_module( + &mut self, + handler: &mut Handler, + _ctx: &mut LintContext, + module: &ast::Module, + ) { let mut first_non_importstmt = std::u64::MAX; for stmt in &module.body { match &stmt.node { @@ -48,11 +54,7 @@ impl LintPass for ImportPosition { handler.add_warning( WarningKind::ImportPositionWarning, &[Message { - pos: Position { - filename: ctx.filename.clone(), - line: stmt.line, - column: None, - }, + range: stmt.get_span_pos(), style: Style::Line, message: format!( "Importstmt should be placed at the top of the module" @@ -97,16 +99,12 @@ impl LintPass for UnusedImport { let scope_objs = &scope.elems; for (_, scope_obj) in scope_objs { let scope_obj = scope_obj.borrow(); - if let ScopeObjectKind::Module(_) = scope_obj.kind { + if let ScopeObjectKind::Module(_) = &scope_obj.kind { if !scope_obj.used { handler.add_warning( WarningKind::UnusedImportWarning, &[Message { - pos: Position { - filename: scope_obj.start.filename.clone(), - line: scope_obj.start.line, - column: None, - }, + range: scope_obj.get_span_pos(), style: Style::Line, message: format!("Module '{}' imported but unused", scope_obj.name), note: Some("Consider removing this statement".to_string()), @@ -143,7 +141,12 @@ pub static REIMPORT: &Lint = &Lint { declare_lint_pass!(ReImport => [REIMPORT]); impl LintPass for ReImport { - fn check_module(&mut self, handler: &mut Handler, ctx: &mut LintContext, module: &ast::Module) { + fn check_module( + &mut self, + handler: &mut Handler, + _ctx: &mut LintContext, + module: &ast::Module, + ) { let mut import_names = IndexSet::::new(); for stmt in &module.body { if let ast::Stmt::Import(import_stmt) = &stmt.node { @@ -151,11 +154,7 @@ impl LintPass for ReImport { handler.add_warning( WarningKind::ReimportWarning, &[Message { - pos: Position { - filename: ctx.filename.clone(), - line: stmt.line, - column: None, - }, + range: stmt.get_span_pos(), style: Style::Line, message: format!( "Module '{}' is reimported multiple times", diff --git a/kclvm/sema/src/resolver/arg.rs b/kclvm/sema/src/resolver/arg.rs index 423c027f3..410835913 100644 --- a/kclvm/sema/src/resolver/arg.rs +++ b/kclvm/sema/src/resolver/arg.rs @@ -41,7 +41,7 @@ impl<'ctx> Resolver<'ctx> { if check_table.contains(arg_name) { self.handler.add_compile_error( &format!("{} has duplicated keyword argument {}", func_name, arg_name), - kw.get_pos(), + kw.get_span_pos(), ); } check_table.insert(arg_name.to_string()); @@ -49,7 +49,7 @@ impl<'ctx> Resolver<'ctx> { kwarg_types.push((arg_name.to_string(), arg_value_type.clone())); } else { self.handler - .add_compile_error("missing argument", kw.get_pos()); + .add_compile_error("missing argument", kw.get_span_pos()); } } if !params.is_empty() { @@ -64,12 +64,12 @@ impl<'ctx> Resolver<'ctx> { params.len(), args.len(), ), - args[i].get_pos(), + args[i].get_span_pos(), ); return; } }; - self.must_assignable_to(ty.clone(), expected_ty, args[i].get_pos(), None) + self.must_assignable_to(ty.clone(), expected_ty, args[i].get_span_pos(), None) } for (i, (arg_name, kwarg_ty)) in kwarg_types.iter().enumerate() { if !params @@ -82,7 +82,7 @@ impl<'ctx> Resolver<'ctx> { "{} got an unexpected keyword argument '{}'", func_name, arg_name ), - kwargs[i].get_pos(), + kwargs[i].get_span_pos(), ); } let expected_types: Vec> = params @@ -94,7 +94,7 @@ impl<'ctx> Resolver<'ctx> { self.must_assignable_to( kwarg_ty.clone(), expected_types[0].clone(), - kwargs[i].get_pos(), + kwargs[i].get_span_pos(), None, ); }; diff --git a/kclvm/sema/src/resolver/attr.rs b/kclvm/sema/src/resolver/attr.rs index 68ca18dfd..958eb0bcc 100644 --- a/kclvm/sema/src/resolver/attr.rs +++ b/kclvm/sema/src/resolver/attr.rs @@ -4,17 +4,18 @@ use crate::builtin::system_module::{get_system_module_members, UNITS, UNITS_NUMB use crate::builtin::STRING_MEMBER_FUNCTIONS; use crate::resolver::Resolver; use crate::ty::{ModuleKind, Type, TypeKind}; +use kclvm_error::diagnostic::Range; use kclvm_error::*; use super::node::ResolvedResult; impl<'ctx> Resolver<'ctx> { - pub fn check_attr_ty(&mut self, attr_ty: &Type, pos: Position) { + pub fn check_attr_ty(&mut self, attr_ty: &Type, range: Range) { if !attr_ty.is_any() && !attr_ty.is_key() { self.handler.add_error( ErrorKind::IllegalAttributeError, &[Message { - pos, + range, style: Style::LineAndColumn, message: format!( "A attribute must be string type, got '{}'", @@ -26,7 +27,7 @@ impl<'ctx> Resolver<'ctx> { } } - pub fn load_attr(&mut self, obj: Rc, attr: &str, pos: Position) -> ResolvedResult { + pub fn load_attr(&mut self, obj: Rc, attr: &str, range: Range) -> ResolvedResult { let (result, return_ty) = match &obj.kind { TypeKind::Any => (true, self.any_ty()), TypeKind::None @@ -76,7 +77,7 @@ impl<'ctx> Resolver<'ctx> { Some(v) => { if v.borrow().ty.is_module() { self.handler - .add_compile_error(&format!("can not import the attribute '{}' from the module '{}'", attr, module_ty.pkgpath), pos.clone()); + .add_compile_error(&format!("can not import the attribute '{}' from the module '{}'", attr, module_ty.pkgpath), range.clone()); } (true, v.borrow().ty.clone()) } @@ -107,7 +108,7 @@ impl<'ctx> Resolver<'ctx> { attr } ), - pos, + range, ); } return_ty diff --git a/kclvm/sema/src/resolver/calculation.rs b/kclvm/sema/src/resolver/calculation.rs index bbe2e1644..e63369295 100644 --- a/kclvm/sema/src/resolver/calculation.rs +++ b/kclvm/sema/src/resolver/calculation.rs @@ -3,6 +3,7 @@ use std::rc::Rc; use crate::resolver::Resolver; use crate::ty::{has_any_type, is_upper_bound, sup, Type, TypeInferMethods, ZERO_LIT_TYPES}; use kclvm_ast::ast; +use kclvm_error::diagnostic::Range; use kclvm_error::Position; const DIV_OR_MOD_ZERO_MSG: &str = "integer division or modulo by zero"; @@ -56,7 +57,7 @@ impl<'ctx> Resolver<'ctx> { left: Rc, right: Rc, op: &ast::BinOp, - pos: Position, + range: Range, ) -> Rc { let t1 = self .ctx @@ -123,7 +124,7 @@ impl<'ctx> Resolver<'ctx> { if t1.is_number() && t2.is_number() { if ZERO_LIT_TYPES.contains(&t2) { self.handler - .add_type_error(DIV_OR_MOD_ZERO_MSG, pos.clone()); + .add_type_error(DIV_OR_MOD_ZERO_MSG, range.clone()); } (true, number_binary(&t1, &t2)) } else { @@ -134,7 +135,7 @@ impl<'ctx> Resolver<'ctx> { if t1.is_number() && t2.is_number() { if ZERO_LIT_TYPES.contains(&t2) { self.handler - .add_type_error(DIV_OR_MOD_ZERO_MSG, pos.clone()); + .add_type_error(DIV_OR_MOD_ZERO_MSG, range.clone()); } (true, self.int_ty()) } else { @@ -186,7 +187,7 @@ impl<'ctx> Resolver<'ctx> { t1.ty_str(), t2.ty_str() ), - pos.clone(), + range.clone(), ); } (true, t2) @@ -201,7 +202,7 @@ impl<'ctx> Resolver<'ctx> { left.ty_str(), right.ty_str() ), - pos, + range, ); } return_ty @@ -213,7 +214,7 @@ impl<'ctx> Resolver<'ctx> { /// - number unary negation (int, float) /// ~ number unary bitwise inversion (int) /// not x logical negation (any type) - pub fn unary(&mut self, ty: Rc, op: &ast::UnaryOp, pos: Position) -> Rc { + pub fn unary(&mut self, ty: Rc, op: &ast::UnaryOp, range: Range) -> Rc { if has_any_type(&[ty.clone()]) { return self.any_ty(); } @@ -235,7 +236,7 @@ impl<'ctx> Resolver<'ctx> { op.symbol(), ty.ty_str(), ), - pos, + range, ); self.any_ty() } @@ -254,7 +255,7 @@ impl<'ctx> Resolver<'ctx> { left: Rc, right: Rc, op: &ast::CmpOp, - pos: Position, + range: Range, ) -> Rc { let t1 = self.ctx.ty_ctx.literal_union_type_to_variable_type(left); let t2 = self.ctx.ty_ctx.literal_union_type_to_variable_type(right); @@ -313,7 +314,7 @@ impl<'ctx> Resolver<'ctx> { t1.ty_str(), t2.ty_str(), ), - pos, + range, ); self.any_ty() } diff --git a/kclvm/sema/src/resolver/config.rs b/kclvm/sema/src/resolver/config.rs index 902eb4a47..4754fea72 100644 --- a/kclvm/sema/src/resolver/config.rs +++ b/kclvm/sema/src/resolver/config.rs @@ -10,7 +10,7 @@ use crate::ty::SchemaType; use crate::ty::{Type, TypeKind}; use kclvm_ast::ast; use kclvm_ast::pos::GetPos; -use kclvm_error::{ErrorKind, Message, Position, Style}; +use kclvm_error::{diagnostic::Range, ErrorKind, Message, Position, Style}; /// Config Expr type check state. /// @@ -243,7 +243,7 @@ impl<'ctx> Resolver<'ctx> { if let Some(Some(obj)) = self.ctx.config_expr_context.last() { let obj = obj.clone(); if let TypeKind::Schema(schema_ty) = &obj.ty.kind { - self.check_config_attr(name, &key.get_pos(), schema_ty); + self.check_config_attr(name, &key.get_span_pos(), schema_ty); } } } @@ -301,8 +301,12 @@ impl<'ctx> Resolver<'ctx> { } if let Some(Some(obj_last)) = self.ctx.config_expr_context.last() { let ty = obj_last.ty.clone(); - let pos = obj_last.start.clone(); - self.must_assignable_to(val_ty, ty, key.get_pos(), Some(pos)); + self.must_assignable_to( + val_ty, + ty, + key.get_span_pos(), + Some(obj_last.get_span_pos()), + ); } self.clear_config_expr_context(stack_depth, false); } @@ -310,7 +314,7 @@ impl<'ctx> Resolver<'ctx> { } /// Check config attr has been defined. - pub(crate) fn check_config_attr(&mut self, attr: &str, pos: &Position, schema_ty: &SchemaType) { + pub(crate) fn check_config_attr(&mut self, attr: &str, range: &Range, schema_ty: &SchemaType) { let runtime_type = kclvm_runtime::schema_runtime_type(&schema_ty.name, &schema_ty.pkgpath); match self.ctx.schema_mapping.get(&runtime_type) { Some(schema_mapping_ty) => { @@ -324,7 +328,7 @@ impl<'ctx> Resolver<'ctx> { "Cannot add member '{}' to schema '{}'", attr, schema_ty.name ), - pos.clone(), + range.clone(), ); } } @@ -338,7 +342,7 @@ impl<'ctx> Resolver<'ctx> { "Cannot add member '{}' to schema '{}'", attr, schema_ty.name ), - pos.clone(), + range.clone(), ); } } @@ -412,7 +416,7 @@ impl<'ctx> Resolver<'ctx> { } else { Rc::new(Type::str_lit(name)) }; - self.check_attr_ty(&key_ty, key.get_pos()); + self.check_attr_ty(&key_ty, key.get_span_pos()); self.insert_object( name, ScopeObject { @@ -445,7 +449,7 @@ impl<'ctx> Resolver<'ctx> { _ => { let key_ty = self.expr(key); let val_ty = self.expr(value); - self.check_attr_ty(&key_ty, key.get_pos()); + self.check_attr_ty(&key_ty, key.get_span_pos()); if let ast::Expr::StringLit(string_lit) = &key.node { self.insert_object( &string_lit.value, @@ -500,7 +504,7 @@ impl<'ctx> Resolver<'ctx> { "only dict and schema can be used ** unpack, got '{}'", val_ty.ty_str() ), - value.get_pos(), + value.get_span_pos(), ); } } @@ -515,7 +519,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalAttributeError, &[Message { - pos: value.get_pos(), + range: value.get_span_pos(), style: Style::LineAndColumn, message: format!( "only list type can in inserted, got '{}'", diff --git a/kclvm/sema/src/resolver/global.rs b/kclvm/sema/src/resolver/global.rs index 319270000..6f9c011aa 100644 --- a/kclvm/sema/src/resolver/global.rs +++ b/kclvm/sema/src/resolver/global.rs @@ -53,7 +53,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::UniqueKeyError, &[Message { - pos: start.clone(), + range: stmt.get_span_pos(), style: Style::LineAndColumn, message: format!("unique key error name '{}'", name), note: None, @@ -170,14 +170,15 @@ impl<'ctx> Resolver<'ctx> { } } None => { + let pos = Position { + filename: self.ctx.filename.clone(), + line: 1, + column: None, + }; self.handler.add_error( ErrorKind::CannotFindModule, &[Message { - pos: Position { - filename: self.ctx.filename.clone(), - line: 1, - column: None, - }, + range: (pos.clone(), pos), style: Style::Line, message: format!("pkgpath {} not found in the program", self.ctx.pkgpath), note: None, @@ -216,8 +217,10 @@ impl<'ctx> Resolver<'ctx> { ) { for target in &assign_stmt.targets { if target.node.names.is_empty() { - self.handler - .add_compile_error("missing target in the assign statement", target.get_pos()); + self.handler.add_compile_error( + "missing target in the assign statement", + target.get_span_pos(), + ); continue; } let name = &target.node.names[0].node; @@ -227,7 +230,7 @@ impl<'ctx> Resolver<'ctx> { ErrorKind::ImmutableError, &[ Message { - pos: start.clone(), + range: target.get_span_pos(), style: Style::LineAndColumn, message: format!( "Can not change the value of '{}', because it was declared immutable", @@ -236,15 +239,14 @@ impl<'ctx> Resolver<'ctx> { note: None, }, Message { - pos: self + range: self .scope .borrow() .elems .get(name) .unwrap() .borrow() - .start - .clone(), + .get_span_pos(), style: Style::LineAndColumn, message: format!("The variable '{}' is declared here", name), note: Some(format!( @@ -258,7 +260,7 @@ impl<'ctx> Resolver<'ctx> { } let ty = if let Some(ty_annotation) = &assign_stmt.ty { let ty = &ty_annotation.node; - let ty = self.parse_ty_with_scope(ty, ty_annotation.get_pos()); + let ty = self.parse_ty_with_scope(ty, ty_annotation.get_span_pos()); if let Some(obj) = self.scope.borrow().elems.get(name) { let obj = obj.borrow(); if !is_upper_bound(obj.ty.clone(), ty.clone()) { @@ -266,7 +268,7 @@ impl<'ctx> Resolver<'ctx> { ErrorKind::TypeError, &[ Message { - pos: start.clone(), + range: target.get_span_pos(), style: Style::LineAndColumn, message: format!( "can not change the type of '{}' to {}", @@ -276,7 +278,7 @@ impl<'ctx> Resolver<'ctx> { note: None, }, Message { - pos: obj.start.clone(), + range: obj.get_span_pos(), style: Style::LineAndColumn, message: format!("expected {}", obj.ty.ty_str()), note: None, @@ -322,7 +324,7 @@ impl<'ctx> Resolver<'ctx> { ErrorKind::ImmutableError, &[ Message { - pos: start, + range: target.get_span_pos(), style: Style::LineAndColumn, message: format!( "Can not change the value of '{}', because it was declared immutable", @@ -331,15 +333,14 @@ impl<'ctx> Resolver<'ctx> { note: None, }, Message { - pos: self + range: self .scope .borrow() .elems .get(name) .unwrap() .borrow() - .start - .clone(), + .get_span_pos(), style: Style::LineAndColumn, message: format!("The variable '{}' is declared here", name), note: Some(format!( @@ -380,7 +381,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: host_name.get_pos(), + range: host_name.get_span_pos(), style: Style::LineAndColumn, message: format!( "invalid schema inherit object type, expect protocol, got '{}'", @@ -406,7 +407,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: host_name.get_pos(), + range: host_name.get_span_pos(), style: Style::LineAndColumn, message: "only schema mixin can inherit from protocol".to_string(), note: None, @@ -424,7 +425,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: host_name.get_pos(), + range: host_name.get_span_pos(), style: Style::LineAndColumn, message: format!( "invalid schema inherit object type, expect protocol, got '{}'", @@ -457,7 +458,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: parent_name.get_pos(), + range: parent_name.get_span_pos(), style: Style::LineAndColumn, message: format!( "invalid schema inherit object type, expect schema, got '{}'", @@ -489,14 +490,14 @@ impl<'ctx> Resolver<'ctx> { "schema name '{}' cannot be the same as the built-in types ({:?})", name, RESERVED_TYPE_IDENTIFIERS ), - pos.clone(), + schema_stmt.name.get_span_pos(), ); } if schema_stmt.is_protocol && !name.ends_with(PROTOCOL_SUFFIX) { self.handler.add_error( ErrorKind::CompileError, &[Message { - pos: pos.clone(), + range: schema_stmt.name.get_span_pos(), style: Style::LineAndColumn, message: format!("schema protocol name must end with '{}'", PROTOCOL_SUFFIX), note: None, @@ -506,7 +507,7 @@ impl<'ctx> Resolver<'ctx> { if schema_stmt.is_protocol && !schema_stmt.has_only_attribute_definitions() { self.handler.add_compile_error( "a protocol is only allowed to define attributes in it", - pos.clone(), + schema_stmt.name.get_span_pos(), ); } let parent_name = parent_ty @@ -516,7 +517,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: pos.clone(), + range: schema_stmt.name.get_span_pos(), style: Style::LineAndColumn, message: format!("mixin inheritance {} is prohibited", parent_name), note: None, @@ -534,7 +535,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IndexSignatureError, &[Message { - pos: index_signature.get_pos(), + range: index_signature.get_span_pos(), style: Style::LineAndColumn, message: format!("index signature attribute name '{}' cannot have the same name as schema attributes", index_sign_name), note: None, @@ -544,11 +545,11 @@ impl<'ctx> Resolver<'ctx> { } let key_ty = self.parse_ty_str_with_scope( &index_signature.node.key_type.node, - index_signature.node.key_type.get_pos(), + index_signature.node.key_type.get_span_pos(), ); let val_ty = self.parse_ty_with_scope( &index_signature.node.value_ty.node, - index_signature.node.value_type.get_pos(), + index_signature.node.value_type.get_span_pos(), ); if !self .ctx @@ -558,7 +559,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IndexSignatureError, &[Message { - pos: pos.clone(), + range: schema_stmt.name.get_span_pos(), style: Style::LineAndColumn, message: format!("invalid index signature key type: '{}'", key_ty.ty_str()), note: None, @@ -592,11 +593,10 @@ impl<'ctx> Resolver<'ctx> { ); let parsed_doc = parse_doc_string(&schema_stmt.doc); for stmt in &schema_stmt.body { - let pos = stmt.get_pos(); let (name, ty, is_optional, has_default) = match &stmt.node { ast::Stmt::Unification(unification_stmt) => { let name = unification_stmt.value.node.name.node.get_name(); - let ty = self.parse_ty_str_with_scope(&name, pos.clone()); + let ty = self.parse_ty_str_with_scope(&name, stmt.get_span_pos()); let is_optional = true; let has_default = true; ( @@ -610,7 +610,7 @@ impl<'ctx> Resolver<'ctx> { let name = schema_attr.name.node.clone(); let ty = self.parse_ty_with_scope( &schema_attr.ty.node.clone(), - schema_attr.ty.get_pos(), + schema_attr.ty.get_span_pos(), ); let is_optional = schema_attr.is_optional; let has_default = schema_attr.value.is_some(); @@ -652,7 +652,7 @@ impl<'ctx> Resolver<'ctx> { attr_obj_map.get(&name).unwrap().ty.clone().ty_str(), ty.ty_str() ), - pos.clone(), + stmt.get_span_pos(), ); } if is_optional && !attr_obj_map.get(&name).unwrap().is_optional { @@ -661,7 +661,7 @@ impl<'ctx> Resolver<'ctx> { "can't change the required schema attribute of '{}' to optional", name ), - pos.clone(), + stmt.get_span_pos(), ); } if let Some(ref index_signature_obj) = index_signature { @@ -671,7 +671,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IndexSignatureError, &[Message { - pos: pos.clone(), + range: stmt.get_span_pos(), style: Style::LineAndColumn, message: format!("the type '{}' of schema attribute '{}' does not meet the index signature definition {}", ty.ty_str(), name, index_signature_obj.ty_str()), note: None, @@ -688,7 +688,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::NameError, &[Message { - pos: mixin.get_pos(), + range: mixin.get_span_pos(), style: Style::LineAndColumn, message: format!( "a valid mixin name should end with 'Mixin', got '{}'", @@ -709,7 +709,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: mixin.get_pos(), + range: mixin.get_span_pos(), style: Style::LineAndColumn, message: format!( "illegal schema mixin object type, expected mixin, got '{}'", @@ -736,18 +736,17 @@ impl<'ctx> Resolver<'ctx> { if let Some(args) = &schema_stmt.args { for (i, para) in args.node.args.iter().enumerate() { let name = para.node.get_name(); - let pos = para.get_pos(); if schema_attr_names.contains(&name) { self.handler.add_compile_error( &format!( "Unexpected parameter name '{}' with the same name as the schema attribute", name ), - pos.clone(), + para.get_span_pos(), ); } let ty = args.node.get_arg_type(i); - let ty = self.parse_ty_with_scope(&ty, pos); + let ty = self.parse_ty_with_scope(&ty, para.get_span_pos()); params.push(Parameter { name, ty: ty.clone(), @@ -769,7 +768,7 @@ impl<'ctx> Resolver<'ctx> { "There is a circular reference between schema {} and {}", name, parent_ty.name, ), - schema_stmt.get_pos(), + schema_stmt.get_span_pos(), ); } } @@ -816,14 +815,13 @@ impl<'ctx> Resolver<'ctx> { should_add_schema_ref: bool, ) -> SchemaType { let name = &rule_stmt.name.node; - let pos = rule_stmt.name.get_end_pos(); if RESERVED_TYPE_IDENTIFIERS.contains(&name.as_str()) { self.handler.add_compile_error( &format!( "rule name '{}' cannot be the same as the built-in types ({:?})", name, RESERVED_TYPE_IDENTIFIERS ), - pos, + rule_stmt.name.get_span_pos(), ); } // Parent types @@ -838,7 +836,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalInheritError, &[Message { - pos: rule.get_pos(), + range: rule.get_span_pos(), style: Style::LineAndColumn, message: format!("illegal rule type '{}'", ty.ty_str()), note: None, @@ -856,9 +854,8 @@ impl<'ctx> Resolver<'ctx> { if let Some(args) = &rule_stmt.args { for (i, para) in args.node.args.iter().enumerate() { let name = para.node.get_name(); - let pos = para.get_pos(); let ty = args.node.get_arg_type(i); - let ty = self.parse_ty_with_scope(&ty, pos); + let ty = self.parse_ty_with_scope(&ty, para.get_span_pos()); params.push(Parameter { name, ty: ty.clone(), @@ -880,7 +877,7 @@ impl<'ctx> Resolver<'ctx> { "There is a circular reference between rule {} and {}", name, parent_ty.name, ), - rule_stmt.get_pos(), + rule_stmt.get_span_pos(), ); } } diff --git a/kclvm/sema/src/resolver/import.rs b/kclvm/sema/src/resolver/import.rs index d5878d79f..f45b3e8a8 100644 --- a/kclvm/sema/src/resolver/import.rs +++ b/kclvm/sema/src/resolver/import.rs @@ -37,11 +37,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::CannotFindModule, &[Message { - pos: Position { - filename: m.filename.clone(), - line: stmt.line, - column: None, - }, + range: stmt.get_span_pos(), style: Style::Line, message: format!( "Cannot find the module {} from {}", @@ -57,11 +53,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::CompileError, &[Message { - pos: Position { - filename: self.ctx.filename.clone(), - line: stmt.line, - column: None, - }, + range: stmt.get_span_pos(), style: Style::Line, message: format!( "Cannot import {} in the main package", @@ -190,7 +182,7 @@ impl<'ctx> Resolver<'ctx> { "There is a circular import reference between module {} and {}", self.ctx.pkgpath, import_stmt.path, ), - stmt.get_pos(), + stmt.get_span_pos(), ); } // Switch pkgpath context diff --git a/kclvm/sema/src/resolver/loop.rs b/kclvm/sema/src/resolver/loop.rs index 315f0caca..cdff8b773 100644 --- a/kclvm/sema/src/resolver/loop.rs +++ b/kclvm/sema/src/resolver/loop.rs @@ -4,7 +4,7 @@ use crate::resolver::Resolver; use crate::ty::{sup, Type, TypeKind}; use kclvm_ast::ast; use kclvm_ast::pos::GetPos; -use kclvm_error::Position; +use kclvm_error::diagnostic::Range; impl<'ctx> Resolver<'ctx> { /// Do loop type check including quant and comp for expression. @@ -14,7 +14,7 @@ impl<'ctx> Resolver<'ctx> { first_var_name: Option, second_var_name: Option, iter_ty: Rc, - iter_pos: Position, + iter_range: Range, ) { let types = match &iter_ty.kind { TypeKind::Union(types) => types.clone(), @@ -26,7 +26,7 @@ impl<'ctx> Resolver<'ctx> { if !(iter_ty.is_iterable() || iter_ty.is_any()) { self.handler.add_compile_error( &format!("'{}' object is not iterable", iter_ty.ty_str()), - iter_pos.clone(), + iter_range.clone(), ); } match &iter_ty.kind { @@ -37,19 +37,19 @@ impl<'ctx> Resolver<'ctx> { self.set_type_to_scope( first_var_name.as_ref().unwrap(), first_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); self.set_type_to_scope( second_var_name.as_ref().unwrap(), second_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); } else { first_var_ty = sup(&[item_ty.clone(), first_var_ty.clone()]); self.set_type_to_scope( first_var_name.as_ref().unwrap(), first_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); } } @@ -58,14 +58,14 @@ impl<'ctx> Resolver<'ctx> { self.set_type_to_scope( first_var_name.as_ref().unwrap(), first_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); if second_var_name.is_some() { second_var_ty = sup(&[val_ty.clone(), second_var_ty.clone()]); self.set_type_to_scope( second_var_name.as_ref().unwrap(), second_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); } } @@ -75,14 +75,14 @@ impl<'ctx> Resolver<'ctx> { self.set_type_to_scope( first_var_name.as_ref().unwrap(), first_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); if second_var_name.is_some() { second_var_ty = sup(&[val_ty, second_var_ty.clone()]); self.set_type_to_scope( second_var_name.as_ref().unwrap(), second_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); } } @@ -93,19 +93,19 @@ impl<'ctx> Resolver<'ctx> { self.set_type_to_scope( first_var_name.as_ref().unwrap(), first_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); self.set_type_to_scope( second_var_name.as_ref().unwrap(), second_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); } else { first_var_ty = sup(&[self.str_ty(), first_var_ty.clone()]); self.set_type_to_scope( first_var_name.as_ref().unwrap(), first_var_ty.clone(), - target_node.get_pos(), + target_node.get_span_pos(), ); } } diff --git a/kclvm/sema/src/resolver/mod.rs b/kclvm/sema/src/resolver/mod.rs index 5c89b1230..a104bf53b 100644 --- a/kclvm/sema/src/resolver/mod.rs +++ b/kclvm/sema/src/resolver/mod.rs @@ -19,6 +19,7 @@ mod var; mod tests; use indexmap::IndexMap; +use kclvm_error::diagnostic::Range; use std::{cell::RefCell, rc::Rc}; use crate::lint::{CombinedLintPass, Linter}; @@ -118,7 +119,7 @@ pub struct Context { /// Import pkgpath and name pub import_names: IndexMap>, /// Global names at top level of the program. - pub global_names: IndexMap>, + pub global_names: IndexMap>, /// Are we resolving the left value. pub l_value: bool, /// Are we resolving the statement start position. diff --git a/kclvm/sema/src/resolver/node.rs b/kclvm/sema/src/resolver/node.rs index e0657fe21..ab8cad5de 100644 --- a/kclvm/sema/src/resolver/node.rs +++ b/kclvm/sema/src/resolver/node.rs @@ -34,7 +34,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if expr_types.len() > 1 { self.handler.add_compile_error( "expression statement can only have one expression", - expr_stmt.exprs[1].get_pos(), + expr_stmt.exprs[1].get_span_pos(), ); } ty @@ -51,13 +51,15 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if names.len() > 1 { self.handler.add_compile_error( "unification identifier can not be selected", - unification_stmt.target.get_pos(), + unification_stmt.target.get_span_pos(), ); } let (start, end) = unification_stmt.value.get_span_pos(); if names.is_empty() { - self.handler - .add_compile_error("missing target in the unification statement", start); + self.handler.add_compile_error( + "missing target in the unification statement", + unification_stmt.value.get_span_pos(), + ); return self.any_ty(); } self.ctx.l_value = true; @@ -71,11 +73,11 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.must_assignable_to( ty.clone(), expected_ty.clone(), - unification_stmt.target.get_pos(), + unification_stmt.target.get_span_pos(), None, ); if !ty.is_any() && expected_ty.is_any() { - self.set_type_to_scope(&names[0].node, ty, unification_stmt.target.get_pos()); + self.set_type_to_scope(&names[0].node, ty, unification_stmt.target.get_span_pos()); } expected_ty } @@ -83,7 +85,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_type_alias_stmt(&mut self, type_alias_stmt: &'ctx ast::TypeAliasStmt) -> Self::Result { let (start, end) = type_alias_stmt.type_name.get_span_pos(); let mut ty = self - .parse_ty_with_scope(&type_alias_stmt.ty.node, start.clone()) + .parse_ty_with_scope(&type_alias_stmt.ty.node, (start.clone(), end.clone())) .as_ref() .clone(); if let TypeKind::Schema(schema_ty) = &mut ty.kind { @@ -103,7 +105,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "type alias '{}' cannot be the same as the built-in types ({:?})", name, RESERVED_TYPE_IDENTIFIERS ), - start.clone(), + type_alias_stmt.type_name.get_span_pos(), ); } self.insert_object( @@ -138,7 +140,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if (is_private_field(name) || is_config || !self.contains_global_name(name)) && self.scope_level == 0 { - self.insert_global_name(name, &target.get_pos()); + self.insert_global_name(name, &target.get_span_pos()); } if target.node.names.len() == 1 { self.ctx.l_value = true; @@ -160,14 +162,14 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.must_assignable_to( value_ty.clone(), expected_ty.clone(), - target.get_pos(), + target.get_span_pos(), None, ); if !value_ty.is_any() && expected_ty.is_any() && assign_stmt.type_annotation.is_none() { - self.set_type_to_scope(name, value_ty.clone(), target.get_pos()); + self.set_type_to_scope(name, value_ty.clone(), target.get_span_pos()); if let Some(schema_ty) = &self.ctx.schema { let mut schema_ty = schema_ty.borrow_mut(); schema_ty.set_type_of_attr( @@ -177,12 +179,12 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } } } else { - self.lookup_type_from_scope(name, target.get_pos()); + self.lookup_type_from_scope(name, target.get_span_pos()); self.ctx.l_value = true; let expected_ty = self.walk_identifier_expr(target); self.ctx.l_value = false; value_ty = self.expr(&assign_stmt.value); - self.must_assignable_to(value_ty.clone(), expected_ty, target.get_pos(), None) + self.must_assignable_to(value_ty.clone(), expected_ty, target.get_span_pos(), None) } } value_ty @@ -196,18 +198,18 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { // Add global names. if is_private_field(name) || is_config || !self.contains_global_name(name) { if self.scope_level == 0 { - self.insert_global_name(name, &aug_assign_stmt.target.get_pos()); + self.insert_global_name(name, &aug_assign_stmt.target.get_span_pos()); } } else { let mut msgs = vec![Message { - pos: aug_assign_stmt.target.get_pos(), + range: aug_assign_stmt.target.get_span_pos(), style: Style::LineAndColumn, message: format!("Immutable variable '{}' is modified during compiling", name), note: None, }]; if let Some(pos) = self.get_global_name_pos(name) { msgs.push(Message { - pos: pos.clone(), + range: pos.clone(), style: Style::LineAndColumn, message: format!("The variable '{}' is declared here firstly", name), note: Some(format!( @@ -225,13 +227,18 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { Ok(op) => op, Err(msg) => bug!("{}", msg), }; - let new_target_ty = self.binary(left_ty, right_ty, &op, aug_assign_stmt.target.get_pos()); + let new_target_ty = self.binary( + left_ty, + right_ty, + &op, + aug_assign_stmt.target.get_span_pos(), + ); self.ctx.l_value = true; let expected_ty = self.walk_identifier_expr(&aug_assign_stmt.target); self.must_assignable_to( new_target_ty.clone(), expected_ty, - aug_assign_stmt.target.get_pos(), + aug_assign_stmt.target.get_span_pos(), None, ); self.ctx.l_value = false; @@ -283,7 +290,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if target.node.names.len() > 1 { self.handler.add_compile_error( "loop variables can only be ordinary identifiers", - target.get_pos(), + target.get_span_pos(), ); } target_node = Some(target); @@ -298,7 +305,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "the number of loop variables is {}, which can only be 1 or 2", quant_expr.variables.len() ), - target.get_pos(), + target.get_span_pos(), ); break; } @@ -322,7 +329,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { key_name, val_name, iter_ty.clone(), - quant_expr.target.get_pos(), + quant_expr.target.get_span_pos(), ); self.expr_or_any_type(&quant_expr.if_cond); let item_ty = self.expr(&quant_expr.test); @@ -339,8 +346,10 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.ctx.local_vars.clear(); let (start, end) = schema_attr.name.get_span_pos(); let name = if schema_attr.name.node.contains('.') { - self.handler - .add_compile_error("schema attribute can not be selected", start.clone()); + self.handler.add_compile_error( + "schema attribute can not be selected", + schema_attr.name.get_span_pos(), + ); schema_attr.name.node.split('.').collect::>()[0] } else { &schema_attr.name.node @@ -384,17 +393,31 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } else { self.expr(value) }; - let pos = schema_attr.name.get_pos(); match &schema_attr.op { Some(bin_or_aug) => match bin_or_aug { // Union ast::BinOrAugOp::Aug(ast::AugOp::BitOr) => { let op = ast::BinOp::BitOr; - let value_ty = self.binary(value_ty, expected_ty.clone(), &op, pos.clone()); - self.must_assignable_to(value_ty, expected_ty, pos, None); + let value_ty = self.binary( + value_ty, + expected_ty.clone(), + &op, + schema_attr.name.get_span_pos(), + ); + self.must_assignable_to( + value_ty, + expected_ty, + schema_attr.name.get_span_pos(), + None, + ); } // Assign - _ => self.must_assignable_to(value_ty, expected_ty, pos, None), + _ => self.must_assignable_to( + value_ty, + expected_ty, + schema_attr.name.get_span_pos(), + None, + ), }, None => bug!("invalid ast schema attr op kind"), } @@ -412,20 +435,23 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_unary_expr(&mut self, unary_expr: &'ctx ast::UnaryExpr) -> Self::Result { let operand_ty = self.expr(&unary_expr.operand); - self.unary(operand_ty, &unary_expr.op, unary_expr.operand.get_pos()) + self.unary( + operand_ty, + &unary_expr.op, + unary_expr.operand.get_span_pos(), + ) } fn walk_binary_expr(&mut self, binary_expr: &'ctx ast::BinaryExpr) -> Self::Result { let left_ty = self.expr(&binary_expr.left); let mut right_ty = self.expr(&binary_expr.right); - let pos = binary_expr.left.get_pos(); match &binary_expr.op { ast::BinOrCmpOp::Bin(bin_op) => match bin_op { ast::BinOp::As => { if let ast::Expr::Identifier(identifier) = &binary_expr.right.node { right_ty = self.parse_ty_str_with_scope( &identifier.get_name(), - binary_expr.right.get_pos(), + binary_expr.right.get_span_pos(), ); if right_ty.is_schema() { let mut schema_ty = right_ty.into_schema_type(); @@ -438,21 +464,24 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { &ty_str_replace_pkgpath(&ty_annotation_str, &self.ctx.pkgpath), ); } else { - self.handler - .add_compile_error("keyword 'as' right operand must be a type", pos); + self.handler.add_compile_error( + "keyword 'as' right operand must be a type", + binary_expr.left.get_span_pos(), + ); return left_ty; } - self.binary(left_ty, right_ty, bin_op, pos) + self.binary(left_ty, right_ty, bin_op, binary_expr.left.get_span_pos()) } - _ => self.binary(left_ty, right_ty, bin_op, pos), + _ => self.binary(left_ty, right_ty, bin_op, binary_expr.left.get_span_pos()), }, - ast::BinOrCmpOp::Cmp(cmp_op) => self.compare(left_ty, right_ty, cmp_op, pos), + ast::BinOrCmpOp::Cmp(cmp_op) => { + self.compare(left_ty, right_ty, cmp_op, binary_expr.left.get_span_pos()) + } } } fn walk_selector_expr(&mut self, selector_expr: &'ctx ast::SelectorExpr) -> Self::Result { let mut value_ty = self.expr(&selector_expr.value); - let pos = selector_expr.attr.get_pos(); if value_ty.is_module() && selector_expr.has_question { let attr = selector_expr.attr.node.get_name(); self.handler.add_compile_error( @@ -461,18 +490,22 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { attr, attr ), - selector_expr.value.get_pos(), + selector_expr.value.get_span_pos(), ); } for name in &selector_expr.attr.node.names { - value_ty = self.load_attr(value_ty.clone(), &name.node, pos.clone()); + value_ty = self.load_attr( + value_ty.clone(), + &name.node, + selector_expr.attr.get_span_pos(), + ); } value_ty } fn walk_call_expr(&mut self, call_expr: &'ctx ast::CallExpr) -> Self::Result { let call_ty = self.expr(&call_expr.func); - let pos = call_expr.func.get_pos(); + let range = call_expr.func.get_span_pos(); if call_ty.is_any() { self.do_arguments_type_check( &call_expr.func.node, @@ -493,7 +526,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if schema_ty.is_instance { self.handler.add_compile_error( &format!("schema '{}' instance is not callable", call_ty.ty_str()), - pos, + range, ); self.any_ty() } else { @@ -510,7 +543,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } else { self.handler.add_compile_error( &format!("'{}' object is not callable", call_ty.ty_str()), - pos, + range, ); self.any_ty() } @@ -518,7 +551,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_subscript(&mut self, subscript: &'ctx ast::Subscript) -> Self::Result { let value_ty = self.expr(&subscript.value); - let pos = subscript.value.get_pos(); + let range = subscript.value.get_span_pos(); if value_ty.is_any() { value_ty } else { @@ -557,17 +590,17 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "invalid dict/schema key type: '{}'", index_key_ty.ty_str() ), - pos, + range, ); self.any_ty() } else if let ast::Expr::StringLit(string_lit) = &subscript.value.node { - self.load_attr(value_ty, &string_lit.value, pos) + self.load_attr(value_ty, &string_lit.value, range) } else { val_ty.clone() } } else { self.handler - .add_compile_error("unhashable type: 'slice'", pos); + .add_compile_error("unhashable type: 'slice'", range); self.any_ty() } } @@ -582,24 +615,24 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "invalid dict/schema key type: '{}'", index_key_ty.ty_str() ), - pos, + range, ); self.any_ty() } else if let ast::Expr::StringLit(string_lit) = &subscript.value.node { - self.load_attr(value_ty, &string_lit.value, pos) + self.load_attr(value_ty, &string_lit.value, range) } else { schema_ty.val_ty() } } else { self.handler - .add_compile_error("unhashable type: 'slice'", pos); + .add_compile_error("unhashable type: 'slice'", range); self.any_ty() } } _ => { self.handler.add_compile_error( &format!("'{}' object is not subscriptable", value_ty.ty_str()), - subscript.value.get_pos(), + subscript.value.get_span_pos(), ); self.any_ty() } @@ -627,8 +660,10 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.walk_comp_clause(&comp_clause.node); } if let ast::Expr::Starred(_) = list_comp.elt.node { - self.handler - .add_compile_error("list unpacking cannot be used in list comprehension", start); + self.handler.add_compile_error( + "list unpacking cannot be used in list comprehension", + list_comp.elt.get_span_pos(), + ); } let item_ty = self.expr(&list_comp.elt); self.leave_scope(); @@ -648,7 +683,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } let key_ty = self.expr(key); // TODO: Naming both dict keys and schema attributes as `attribute` - self.check_attr_ty(&key_ty, start); + self.check_attr_ty(&key_ty, key.get_span_pos()); let val_ty = self.expr(&dict_comp.entry.value); self.leave_scope(); Type::dict_ref(key_ty, val_ty) @@ -700,7 +735,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "only list, dict, schema object can be used * unpacked, got {}", ty.ty_str() ), - starred_expr.value.get_pos(), + starred_expr.value.get_span_pos(), ); } ty @@ -731,7 +766,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if target.node.names.len() > 1 { self.handler.add_compile_error( "loop variables can only be ordinary identifiers", - target.get_pos(), + target.get_span_pos(), ); } target_node = Some(target); @@ -746,7 +781,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { "the number of loop variables is {}, which can only be 1 or 2", comp_clause.targets.len() ), - target.get_pos(), + target.get_span_pos(), ); break; } @@ -773,7 +808,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { key_name, val_name, iter_ty, - comp_clause.iter.get_pos(), + comp_clause.iter.get_span_pos(), ); self.exprs(&comp_clause.ifs); self.any_ty() @@ -785,10 +820,10 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if !matches!(&schema_expr.config.node, ast::Expr::Config(_)) { self.handler.add_compile_error( "Invalid schema config expr, expect config entries, e.g., {k1 = v1, k2 = v2}", - schema_expr.config.get_pos(), + schema_expr.config.get_span_pos(), ); } - let mut pos = schema_expr.name.get_pos(); + let mut range = schema_expr.name.get_span_pos(); let ret_ty = match &def_ty.kind { TypeKind::Dict(_, _) => { let obj = self.new_config_expr_context_item( @@ -800,7 +835,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { let init_stack_depth = self.switch_config_expr_context(Some(obj)); let config_ty = self.expr(&schema_expr.config); self.clear_config_expr_context(init_stack_depth as usize, false); - self.binary(def_ty.clone(), config_ty, &ast::BinOp::BitOr, pos) + self.binary(def_ty.clone(), config_ty, &ast::BinOp::BitOr, range) } TypeKind::Schema(schema_ty) => { if !schema_ty.is_instance { @@ -824,7 +859,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if !schema_expr.args.is_empty() || !schema_expr.kwargs.is_empty() { self.handler.add_compile_error( "Arguments cannot be used in the schema modification expression", - pos, + range, ); } } else { @@ -840,9 +875,12 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.any_ty() } _ => { - pos.filename = self.ctx.filename.clone(); - self.handler - .add_compile_error(&format!("Invalid schema type '{}'", def_ty.ty_str()), pos); + range.0.filename = self.ctx.filename.clone(); + range.1.filename = self.ctx.filename.clone(); + self.handler.add_compile_error( + &format!("Invalid schema type '{}'", def_ty.ty_str()), + range, + ); return self.any_ty(); } }; @@ -878,7 +916,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { for (i, arg) in args.node.args.iter().enumerate() { let name = arg.node.get_name(); let arg_ty = args.node.get_arg_type(i); - let ty = self.parse_ty_with_scope(&arg_ty, arg.get_pos()); + let ty = self.parse_ty_with_scope(&arg_ty, arg.get_span_pos()); params.push(Parameter { name, ty: ty.clone(), @@ -890,7 +928,8 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { } let (start, end) = (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()); if let Some(ret_annotation_ty) = &lambda_expr.return_ty { - ret_ty = self.parse_ty_with_scope(&ret_annotation_ty.node, start.clone()); + ret_ty = + self.parse_ty_with_scope(&ret_annotation_ty.node, (start.clone(), end.clone())); } self.enter_scope(start.clone(), end.clone(), ScopeKind::Lambda); self.ctx.in_lambda_expr.push(true); @@ -916,14 +955,14 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { ) { self.handler.add_compile_error( "The last statement of the lambda body must be a expression e.g., x, 1, etc.", - stmt.get_pos(), + stmt.get_span_pos(), ); } } let real_ret_ty = self.stmts(&lambda_expr.body); self.leave_scope(); self.ctx.in_lambda_expr.pop(); - self.must_assignable_to(real_ret_ty.clone(), ret_ty.clone(), end, None); + self.must_assignable_to(real_ret_ty.clone(), ret_ty.clone(), (start, end), None); if !real_ret_ty.is_any() && ret_ty.is_any() && lambda_expr.return_type_str.is_none() { ret_ty = real_ret_ty; } @@ -938,7 +977,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { fn walk_arguments(&mut self, arguments: &'ctx ast::Arguments) -> Self::Result { for (i, arg) in arguments.args.iter().enumerate() { let ty = arguments.get_arg_type(i); - self.parse_ty_with_scope(&ty, arg.get_pos()); + self.parse_ty_with_scope(&ty, arg.get_span_pos()); let value = &arguments.defaults[i]; self.expr_or_any_type(value); } @@ -952,11 +991,16 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { t1.clone(), t2.clone(), &compare.ops[0], - compare.comparators[0].get_pos(), + compare.comparators[0].get_span_pos(), ); for i in 1..compare.comparators.len() - 1 { let op = &compare.ops[i + 1]; - self.compare(t1.clone(), t2.clone(), op, compare.comparators[i].get_pos()); + self.compare( + t1.clone(), + t2.clone(), + op, + compare.comparators[i].get_span_pos(), + ); } self.bool_ty() } @@ -965,7 +1009,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { self.resolve_var( &identifier.get_names(), &identifier.pkgpath, - self.ctx.start_pos.clone(), + (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()), ) } @@ -977,7 +1021,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { ast::NumberLitValue::Float(float_val) => { self.handler.add_compile_error( "float literal can not be followed the unit suffix", - self.ctx.start_pos.clone(), + (self.ctx.start_pos.clone(), self.ctx.end_pos.clone()), ); float_val as i64 } @@ -1024,7 +1068,7 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { if !VALID_FORMAT_SPEC_SET.contains(&spec_lower.as_str()) { self.handler.add_compile_error( &format!("{} is a invalid format spec", spec), - formatted_value.value.get_pos(), + formatted_value.value.get_span_pos(), ); } } @@ -1094,7 +1138,7 @@ impl<'ctx> Resolver<'ctx> { self.resolve_var( &identifier.node.get_names(), &identifier.node.pkgpath, - identifier.get_pos(), + identifier.get_span_pos(), ) } } diff --git a/kclvm/sema/src/resolver/para.rs b/kclvm/sema/src/resolver/para.rs index 3635ce3f6..6a213d8f3 100644 --- a/kclvm/sema/src/resolver/para.rs +++ b/kclvm/sema/src/resolver/para.rs @@ -17,7 +17,7 @@ impl<'ctx> Resolver<'ctx> { self.handler.add_error( ErrorKind::IllegalParameterError, &[Message { - pos: default.get_pos(), + range: default.get_span_pos(), style: Style::LineAndColumn, message: "non-default argument follows default argument" .to_string(), diff --git a/kclvm/sema/src/resolver/schema.rs b/kclvm/sema/src/resolver/schema.rs index 5f3ebcb7f..26dc620df 100644 --- a/kclvm/sema/src/resolver/schema.rs +++ b/kclvm/sema/src/resolver/schema.rs @@ -17,15 +17,16 @@ impl<'ctx> Resolver<'ctx> { &mut self, schema_stmt: &'ctx ast::SchemaStmt, ) -> ResolvedResult { - self.resolve_unique_key(&schema_stmt.name.node, &schema_stmt.name.get_pos()); - let ty = self.lookup_type_from_scope(&schema_stmt.name.node, schema_stmt.name.get_pos()); + self.resolve_unique_key(&schema_stmt.name.node, &schema_stmt.name.get_span_pos()); + let ty = + self.lookup_type_from_scope(&schema_stmt.name.node, schema_stmt.name.get_span_pos()); let scope_ty = if ty.is_schema() { ty.into_schema_type() } else { self.handler.add_error( ErrorKind::TypeError, &[Message { - pos: schema_stmt.get_pos(), + range: schema_stmt.get_span_pos(), style: Style::LineAndColumn, message: format!("expected schema type, got {}", ty.ty_str()), note: None, @@ -108,15 +109,15 @@ impl<'ctx> Resolver<'ctx> { } pub(crate) fn resolve_rule_stmt(&mut self, rule_stmt: &'ctx ast::RuleStmt) -> ResolvedResult { - self.resolve_unique_key(&rule_stmt.name.node, &rule_stmt.name.get_pos()); - let ty = self.lookup_type_from_scope(&rule_stmt.name.node, rule_stmt.name.get_pos()); + self.resolve_unique_key(&rule_stmt.name.node, &rule_stmt.name.get_span_pos()); + let ty = self.lookup_type_from_scope(&rule_stmt.name.node, rule_stmt.name.get_span_pos()); let scope_ty = if ty.is_schema() { ty.into_schema_type() } else { self.handler.add_error( ErrorKind::TypeError, &[Message { - pos: rule_stmt.get_pos(), + range: rule_stmt.get_span_pos(), style: Style::LineAndColumn, message: format!("expected rule type, got {}", ty.ty_str()), note: None, @@ -193,14 +194,14 @@ impl<'ctx> Resolver<'ctx> { None => { self.handler.add_compile_error( &format!("UnKnown decorator {}", name), - decorator.get_pos(), + decorator.get_span_pos(), ); } }, None => { self.handler.add_type_error( "decorator name must be a single identifier", - decorator.get_pos(), + decorator.get_span_pos(), ); } } diff --git a/kclvm/sema/src/resolver/scope.rs b/kclvm/sema/src/resolver/scope.rs index dd72b5c5b..ab1d13ff9 100644 --- a/kclvm/sema/src/resolver/scope.rs +++ b/kclvm/sema/src/resolver/scope.rs @@ -2,6 +2,7 @@ use anyhow::bail; use compiler_base_session::Session; use indexmap::{IndexMap, IndexSet}; use kclvm_ast::{ast, MAIN_PKG}; +use kclvm_error::diagnostic::Range; use kclvm_error::{Handler, Level}; use std::sync::Arc; use std::{ @@ -13,6 +14,7 @@ use crate::resolver::Resolver; use crate::ty::Type; use crate::{builtin::BUILTIN_FUNCTIONS, ty::TypeInferMethods}; use kclvm_ast::pos::ContainsPos; +use kclvm_ast::pos::GetPos; use kclvm_error::Position; /// The object stored in the scope. @@ -48,6 +50,19 @@ impl ContainsPos for ScopeObject { } } +impl GetPos for ScopeObject { + fn get_span_pos(&self) -> Range { + (self.start.clone(), self.end.clone()) + } + fn get_pos(&self) -> Position { + self.start.clone() + } + + fn get_end_pos(&self) -> Position { + self.end.clone() + } +} + #[derive(PartialEq, Clone, Debug)] pub enum ScopeObjectKind { Variable, @@ -385,13 +400,13 @@ impl<'ctx> Resolver<'ctx> { /// Lookup type from the scope by name, if not found, emit a compile error and /// return the any type. - pub fn lookup_type_from_scope(&mut self, name: &str, pos: Position) -> Rc { + pub fn lookup_type_from_scope(&mut self, name: &str, range: Range) -> Rc { match self.find_type_in_scope(name) { Some(ty) => ty, None => { self.handler.add_compile_error( &format!("name '{}' is not defined", name.replace('@', "")), - pos, + range, ); self.any_ty() } @@ -399,7 +414,7 @@ impl<'ctx> Resolver<'ctx> { } /// Set type to the scope exited object, if not found, emit a compile error. - pub fn set_type_to_scope(&mut self, name: &str, ty: Rc, pos: Position) { + pub fn set_type_to_scope(&mut self, name: &str, ty: Rc, range: Range) { let mut scope = self.scope.borrow_mut(); match scope.elems.get_mut(name) { Some(obj) => { @@ -409,7 +424,7 @@ impl<'ctx> Resolver<'ctx> { None => { self.handler.add_compile_error( &format!("name '{}' is not defined", name.replace('@', "")), - pos, + range, ); } } diff --git a/kclvm/sema/src/resolver/tests.rs b/kclvm/sema/src/resolver/tests.rs index 6e346f18d..4299240d9 100644 --- a/kclvm/sema/src/resolver/tests.rs +++ b/kclvm/sema/src/resolver/tests.rs @@ -186,7 +186,7 @@ fn test_resolve_program_illegal_attr_fail() { Some(DiagnosticId::Error(ErrorKind::IllegalAttributeError)) ); assert_eq!(diag.messages.len(), 1); - assert_eq!(diag.messages[0].pos.line, 4); + assert_eq!(diag.messages[0].range.0.line, 4); assert_eq!(diag.messages[0].message, expect_err_msg,); let diag = &scope.handler.diagnostics[1]; assert_eq!( @@ -195,7 +195,7 @@ fn test_resolve_program_illegal_attr_fail() { ); assert_eq!(diag.messages.len(), 1); assert_eq!(diag.messages[0].message, expect_err_msg,); - assert_eq!(diag.messages[0].pos.line, 5); + assert_eq!(diag.messages[0].range.0.line, 5); } #[test] @@ -210,7 +210,7 @@ fn test_resolve_program_unmatched_args_fail() { Some(DiagnosticId::Error(ErrorKind::CompileError)) ); assert_eq!(diag.messages.len(), 1); - assert_eq!(diag.messages[0].pos.line, 6); + assert_eq!(diag.messages[0].range.0.line, 6); assert_eq!(diag.messages[0].message, expect_err_msg); let expect_err_msg = "\"f\" takes 1 positional argument but 2 were given"; @@ -220,7 +220,7 @@ fn test_resolve_program_unmatched_args_fail() { Some(DiagnosticId::Error(ErrorKind::CompileError)) ); assert_eq!(diag.messages.len(), 1); - assert_eq!(diag.messages[0].pos.line, 7); + assert_eq!(diag.messages[0].range.0.line, 7); assert_eq!(diag.messages[0].message, expect_err_msg); } @@ -238,7 +238,7 @@ fn test_resolve_program_module_optional_select_fail() { Some(DiagnosticId::Error(ErrorKind::CompileError)) ); assert_eq!(diag.messages.len(), 1); - assert_eq!(diag.messages[0].pos.line, 3); + assert_eq!(diag.messages[0].range.0.line, 3); assert_eq!(diag.messages[0].message, expect_err_msg); let expect_err_msg = "Module 'math' imported but unused"; @@ -248,7 +248,7 @@ fn test_resolve_program_module_optional_select_fail() { Some(DiagnosticId::Warning(WarningKind::UnusedImportWarning)) ); assert_eq!(diag.messages.len(), 1); - assert_eq!(diag.messages[0].pos.line, 1); + assert_eq!(diag.messages[0].range.0.line, 1); assert_eq!(diag.messages[0].message, expect_err_msg); } @@ -278,11 +278,18 @@ fn test_lint() { handler.add_warning( WarningKind::ImportPositionWarning, &[Message { - pos: Position { - filename: filename.clone(), - line: 10, - column: None, - }, + range: ( + Position { + filename: filename.clone(), + line: 10, + column: Some(0), + }, + Position { + filename: filename.clone(), + line: 10, + column: Some(20), + }, + ), style: Style::Line, message: format!("Importstmt should be placed at the top of the module"), note: Some("Consider moving tihs statement to the top of the file".to_string()), @@ -291,11 +298,18 @@ fn test_lint() { handler.add_warning( WarningKind::ReimportWarning, &[Message { - pos: Position { - filename: filename.clone(), - line: 2, - column: None, - }, + range: ( + Position { + filename: filename.clone(), + line: 2, + column: Some(0), + }, + Position { + filename: filename.clone(), + line: 2, + column: Some(20), + }, + ), style: Style::Line, message: format!("Module 'a' is reimported multiple times"), note: Some("Consider removing this statement".to_string()), @@ -304,11 +318,18 @@ fn test_lint() { handler.add_warning( WarningKind::UnusedImportWarning, &[Message { - pos: Position { - filename, - line: 1, - column: None, - }, + range: ( + Position { + filename: filename.clone(), + line: 1, + column: Some(0), + }, + Position { + filename: filename.clone(), + line: 1, + column: Some(20), + }, + ), style: Style::Line, message: format!("Module 'import_test.a' imported but unused"), note: Some("Consider removing this statement".to_string()), diff --git a/kclvm/sema/src/resolver/ty.rs b/kclvm/sema/src/resolver/ty.rs index 261aa9699..e9c754f62 100644 --- a/kclvm/sema/src/resolver/ty.rs +++ b/kclvm/sema/src/resolver/ty.rs @@ -6,6 +6,7 @@ use crate::ty::{assignable_to, SchemaType, Type, TypeKind}; use indexmap::IndexMap; use kclvm_ast::ast; use kclvm_ast::pos::GetPos; +use kclvm_error::diagnostic::Range; use kclvm_error::*; use super::node::ResolvedResult; @@ -56,10 +57,10 @@ impl<'ctx> Resolver<'ctx> { } /// Parse the type string with the scope, if parse_ty returns a Named type(schema type or type alias), /// found it from the scope. - pub fn parse_ty_with_scope(&mut self, ty: &ast::Type, pos: Position) -> ResolvedResult { + pub fn parse_ty_with_scope(&mut self, ty: &ast::Type, range: Range) -> ResolvedResult { let ty: Rc = Rc::new(ty.clone().into()); // If a named type, find it from scope to get the specific type - let ret_ty = self.upgrade_named_ty_with_scope(ty.clone(), &pos); + let ret_ty = self.upgrade_named_ty_with_scope(ty.clone(), &range); self.add_type_alias( &ty.into_type_annotation_str(), &ret_ty.into_type_annotation_str(), @@ -67,10 +68,10 @@ impl<'ctx> Resolver<'ctx> { ret_ty } - pub fn parse_ty_str_with_scope(&mut self, ty_str: &str, pos: Position) -> ResolvedResult { + pub fn parse_ty_str_with_scope(&mut self, ty_str: &str, range: Range) -> ResolvedResult { let ty: Rc = parse_type_str(ty_str); // If a named type, find it from scope to get the specific type - let ret_ty = self.upgrade_named_ty_with_scope(ty, &pos); + let ret_ty = self.upgrade_named_ty_with_scope(ty, &range); self.add_type_alias(ty_str, &ret_ty.into_type_annotation_str()); ret_ty } @@ -79,7 +80,7 @@ impl<'ctx> Resolver<'ctx> { #[inline] pub fn must_be_type(&mut self, expr: &'ctx ast::NodeRef, expected_ty: Rc) { let ty = self.expr(expr); - self.must_assignable_to(ty, expected_ty, expr.get_pos(), None); + self.must_assignable_to(ty, expected_ty, expr.get_span_pos(), None); } /// Must assignable to the expected type. @@ -88,12 +89,12 @@ impl<'ctx> Resolver<'ctx> { &mut self, ty: Rc, expected_ty: Rc, - pos: Position, - expected_pos: Option, + range: Range, + expected_pos: Option, ) { - if !self.check_type(ty.clone(), expected_ty.clone(), &pos) { + if !self.check_type(ty.clone(), expected_ty.clone(), &range) { let mut msgs = vec![Message { - pos, + range, style: Style::LineAndColumn, message: format!("expected {}, got {}", expected_ty.ty_str(), ty.ty_str(),), note: None, @@ -101,7 +102,7 @@ impl<'ctx> Resolver<'ctx> { if let Some(expected_pos) = expected_pos { msgs.push(Message { - pos: expected_pos, + range: expected_pos, style: Style::LineAndColumn, message: format!( "variable is defined here, its type is {}, but got {}", @@ -117,24 +118,24 @@ impl<'ctx> Resolver<'ctx> { /// The check type main function, returns a boolean result. #[inline] - pub fn check_type(&mut self, ty: Rc, expected_ty: Rc, pos: &Position) -> bool { + pub fn check_type(&mut self, ty: Rc, expected_ty: Rc, range: &Range) -> bool { match (&ty.kind, &expected_ty.kind) { (TypeKind::List(item_ty), TypeKind::List(expected_item_ty)) => { - self.check_type(item_ty.clone(), expected_item_ty.clone(), pos) + self.check_type(item_ty.clone(), expected_item_ty.clone(), range) } (TypeKind::Dict(key_ty, val_ty), TypeKind::Dict(expected_key_ty, expected_val_ty)) => { - self.check_type(key_ty.clone(), expected_key_ty.clone(), pos) - && self.check_type(val_ty.clone(), expected_val_ty.clone(), pos) + self.check_type(key_ty.clone(), expected_key_ty.clone(), range) + && self.check_type(val_ty.clone(), expected_val_ty.clone(), range) } (TypeKind::Dict(key_ty, val_ty), TypeKind::Schema(schema_ty)) => { - self.dict_assignable_to_schema(key_ty.clone(), val_ty.clone(), schema_ty, pos) + self.dict_assignable_to_schema(key_ty.clone(), val_ty.clone(), schema_ty, range) } (TypeKind::Union(types), _) => types .iter() - .all(|ty| self.check_type(ty.clone(), expected_ty.clone(), pos)), + .all(|ty| self.check_type(ty.clone(), expected_ty.clone(), range)), (_, TypeKind::Union(types)) => types .iter() - .any(|expected_ty| self.check_type(ty.clone(), expected_ty.clone(), pos)), + .any(|expected_ty| self.check_type(ty.clone(), expected_ty.clone(), range)), _ => assignable_to(ty, expected_ty), } } @@ -146,7 +147,7 @@ impl<'ctx> Resolver<'ctx> { key_ty: Rc, val_ty: Rc, schema_ty: &SchemaType, - pos: &Position, + range: &Range, ) -> bool { if let Some(index_signature) = &schema_ty.index_signature { if !assignable_to(val_ty.clone(), index_signature.val_ty.clone()) { @@ -156,7 +157,7 @@ impl<'ctx> Resolver<'ctx> { index_signature.val_ty.ty_str(), val_ty.ty_str() ), - pos.clone(), + range.clone(), ); } if index_signature.any_other { @@ -169,19 +170,19 @@ impl<'ctx> Resolver<'ctx> { } } - fn upgrade_named_ty_with_scope(&mut self, ty: Rc, pos: &Position) -> ResolvedResult { + fn upgrade_named_ty_with_scope(&mut self, ty: Rc, range: &Range) -> ResolvedResult { match &ty.kind { TypeKind::List(item_ty) => { - Type::list_ref(self.upgrade_named_ty_with_scope(item_ty.clone(), pos)) + Type::list_ref(self.upgrade_named_ty_with_scope(item_ty.clone(), range)) } TypeKind::Dict(key_ty, val_ty) => Type::dict_ref( - self.upgrade_named_ty_with_scope(key_ty.clone(), pos), - self.upgrade_named_ty_with_scope(val_ty.clone(), pos), + self.upgrade_named_ty_with_scope(key_ty.clone(), range), + self.upgrade_named_ty_with_scope(val_ty.clone(), range), ), TypeKind::Union(types) => Type::union_ref( &types .iter() - .map(|ty| self.upgrade_named_ty_with_scope(ty.clone(), pos)) + .map(|ty| self.upgrade_named_ty_with_scope(ty.clone(), range)) .collect::>>(), ), TypeKind::Named(ty_str) => { @@ -194,7 +195,7 @@ impl<'ctx> Resolver<'ctx> { }; if names.is_empty() { self.handler - .add_compile_error("missing type annotation", pos.clone()); + .add_compile_error("missing type annotation", range.clone()); return self.any_ty(); } let mut pkgpath = "".to_string(); @@ -210,7 +211,7 @@ impl<'ctx> Resolver<'ctx> { self.resolve_var( &names.iter().map(|n| n.to_string()).collect::>(), &pkgpath, - pos.clone(), + range.clone(), ) } _ => ty.clone(), diff --git a/kclvm/sema/src/resolver/var.rs b/kclvm/sema/src/resolver/var.rs index 5f1aeb579..028ace36c 100644 --- a/kclvm/sema/src/resolver/var.rs +++ b/kclvm/sema/src/resolver/var.rs @@ -1,6 +1,7 @@ use crate::resolver::Resolver; use crate::ty::TypeKind; use indexmap::IndexMap; +use kclvm_error::diagnostic::Range; use kclvm_error::*; use super::node::ResolvedResult; @@ -8,16 +9,11 @@ use super::scope::{ScopeObject, ScopeObjectKind}; impl<'ctx> Resolver<'ctx> { /// Resolve variables. - pub fn resolve_var( - &mut self, - names: &[String], - pkgpath: &str, - pos: Position, - ) -> ResolvedResult { + pub fn resolve_var(&mut self, names: &[String], pkgpath: &str, range: Range) -> ResolvedResult { if !pkgpath.is_empty() && self.ctx.l_value { self.handler.add_compile_error( "only schema and dict object can be updated attribute", - pos.clone(), + range.clone(), ); } if names.len() == 1 { @@ -45,8 +41,8 @@ impl<'ctx> Resolver<'ctx> { name, ScopeObject { name: name.to_string(), - start: pos.clone(), - end: pos.clone(), + start: range.0.clone(), + end: range.1.clone(), ty: self.any_ty(), kind: ScopeObjectKind::Variable, used: false, @@ -59,12 +55,12 @@ impl<'ctx> Resolver<'ctx> { return self.any_ty(); } // FIXME: self.check_config_attr(name, &pos, &schema_ty); - ty.map_or(self.lookup_type_from_scope(name, pos.clone()), |ty| ty) + ty.map_or(self.lookup_type_from_scope(name, range.clone()), |ty| ty) } } else { // Load from schema if in schema if !self.ctx.l_value { - self.lookup_type_from_scope(name, pos) + self.lookup_type_from_scope(name, range) } // Store else { @@ -73,8 +69,8 @@ impl<'ctx> Resolver<'ctx> { name, ScopeObject { name: name.to_string(), - start: pos.clone(), - end: pos.clone(), + start: range.0.clone(), + end: range.1.clone(), ty: self.any_ty(), kind: ScopeObjectKind::Variable, used: false, @@ -83,7 +79,7 @@ impl<'ctx> Resolver<'ctx> { ); return self.any_ty(); } - self.lookup_type_from_scope(name, pos) + self.lookup_type_from_scope(name, range) } } } else if !names.is_empty() { @@ -102,39 +98,39 @@ impl<'ctx> Resolver<'ctx> { names[0].clone() }], pkgpath, - pos.clone(), + range.clone(), ); for name in &names[1..] { // Store and config attr check if self.ctx.l_value { if let TypeKind::Schema(schema_ty) = &ty.kind { - self.check_config_attr(name, &pos, schema_ty); + self.check_config_attr(name, &range, schema_ty); } } - ty = self.load_attr(ty, name, pos.clone()) + ty = self.load_attr(ty, name, range.clone()) } ty } else { self.handler - .add_compile_error("missing variable", pos.clone()); + .add_compile_error("missing variable", range.clone()); self.any_ty() } } /// Resolve an unique key in the current package. - pub(crate) fn resolve_unique_key(&mut self, name: &str, pos: &Position) { + pub(crate) fn resolve_unique_key(&mut self, name: &str, range: &Range) { if !self.contains_global_name(name) && self.scope_level == 0 { - self.insert_global_name(name, pos); + self.insert_global_name(name, range); } else { let mut msgs = vec![Message { - pos: pos.clone(), + range: range.clone(), style: Style::LineAndColumn, message: format!("Unique key error name '{}'", name), note: None, }]; if let Some(pos) = self.get_global_name_pos(name) { msgs.push(Message { - pos: pos.clone(), + range: pos.clone(), style: Style::LineAndColumn, message: format!("The variable '{}' is declared here", name), note: None, @@ -145,14 +141,14 @@ impl<'ctx> Resolver<'ctx> { } /// Insert global name in the current package. - pub(crate) fn insert_global_name(&mut self, name: &str, pos: &Position) { + pub(crate) fn insert_global_name(&mut self, name: &str, range: &Range) { match self.ctx.global_names.get_mut(&self.ctx.pkgpath) { Some(mapping) => { - mapping.insert(name.to_string(), pos.clone()); + mapping.insert(name.to_string(), range.clone()); } None => { let mut mapping = IndexMap::default(); - mapping.insert(name.to_string(), pos.clone()); + mapping.insert(name.to_string(), range.clone()); self.ctx .global_names .insert(self.ctx.pkgpath.clone(), mapping); @@ -169,7 +165,7 @@ impl<'ctx> Resolver<'ctx> { } /// Get global name position in the current package. - pub(crate) fn get_global_name_pos(&mut self, name: &str) -> Option<&Position> { + pub(crate) fn get_global_name_pos(&mut self, name: &str) -> Option<&Range> { match self.ctx.global_names.get_mut(&self.ctx.pkgpath) { Some(mapping) => mapping.get(name), None => None, diff --git a/kclvm/tools/src/LSP/src/tests.rs b/kclvm/tools/src/LSP/src/tests.rs index 0021c856e..9ae528bf9 100644 --- a/kclvm/tools/src/LSP/src/tests.rs +++ b/kclvm/tools/src/LSP/src/tests.rs @@ -4,13 +4,15 @@ use std::process::Command; use indexmap::IndexSet; use kclvm_ast::ast::Program; -use kclvm_error::Diagnostic; +use kclvm_error::Diagnostic as KCLDiagnostic; use kclvm_error::Position as KCLPos; use kclvm_sema::builtin::MATH_FUNCTION_NAMES; use kclvm_sema::builtin::STRING_MEMBER_FUNCTIONS; use kclvm_sema::resolver::scope::ProgramScope; use lsp_types::request::GotoTypeDefinitionResponse; use lsp_types::CompletionResponse; +use lsp_types::Diagnostic; +use lsp_types::DiagnosticSeverity; use lsp_types::DocumentSymbol; use lsp_types::DocumentSymbolResponse; use lsp_types::MarkedString; @@ -22,13 +24,14 @@ use crate::completion::KCLCompletionItem; use crate::document_symbol::document_symbol; use crate::from_lsp::file_path_from_url; use crate::hover::hover; +use crate::to_lsp::kcl_diag_to_lsp_diags; use crate::{ completion::{completion, into_completion_items}, goto_def::goto_definition, util::{apply_document_changes, parse_param_and_compile, Param}, }; -fn compile_test_file(testfile: &str) -> (String, Program, ProgramScope, IndexSet) { +fn compile_test_file(testfile: &str) -> (String, Program, ProgramScope, IndexSet) { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut test_file = path; test_file.push(testfile); @@ -68,6 +71,33 @@ fn compare_goto_res(res: Option, pos: (&String, u32, #[test] fn diagnostics_test() { + fn build_lsp_diag( + pos: (u32, u32, u32, u32), + message: String, + severity: Option, + ) -> Diagnostic { + Diagnostic { + range: lsp_types::Range { + start: Position { + line: pos.0, + character: pos.1, + }, + end: Position { + line: pos.2, + character: pos.3, + }, + }, + severity, + code: None, + code_description: None, + source: None, + message, + related_information: None, + tags: None, + data: None, + } + } + let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut test_file = path.clone(); test_file.push("src/test_data/diagnostics.k"); @@ -81,19 +111,44 @@ fn diagnostics_test() { ) .unwrap(); - let msgs = [ - "expected one of [\"identifier\", \"literal\", \"(\", \"[\", \"{\"] got newline", - "pkgpath abc not found in the program", - &format!( - "Cannot find the module abc from {}/src/test_data/abc", - path.to_str().unwrap() + let diagnostics = diags + .iter() + .flat_map(|diag| kcl_diag_to_lsp_diags(diag, file)) + .collect::>(); + + let expected_diags: Vec = vec![ + build_lsp_diag( + (1, 4, 1, 4), + "expected one of [\"identifier\", \"literal\", \"(\", \"[\", \"{\"] got newline" + .to_string(), + Some(DiagnosticSeverity::ERROR), + ), + build_lsp_diag( + (0, 0, 0, 10), + "pkgpath abc not found in the program".to_string(), + Some(DiagnosticSeverity::ERROR), + ), + build_lsp_diag( + (0, 0, 0, 10), + format!( + "Cannot find the module abc from {}/src/test_data/abc", + path.to_str().unwrap() + ), + Some(DiagnosticSeverity::ERROR), + ), + build_lsp_diag( + (2, 0, 2, 1), + "expected str, got int(1)".to_string(), + Some(DiagnosticSeverity::ERROR), + ), + build_lsp_diag( + (0, 0, 0, 10), + "Module 'abc' imported but unused".to_string(), + Some(DiagnosticSeverity::WARNING), ), - "expected str, got int(1)", - "Module 'abc' imported but unused", ]; - assert_eq!(diags.len(), msgs.len()); - for (diag, m) in diags.iter().zip(msgs.iter()) { - assert_eq!(diag.messages[0].message, m.to_string()); + for (get, expected) in diagnostics.iter().zip(expected_diags.iter()) { + assert_eq!(get, expected); } } diff --git a/kclvm/tools/src/LSP/src/to_lsp.rs b/kclvm/tools/src/LSP/src/to_lsp.rs index 0fbcd9012..732f81eb3 100644 --- a/kclvm/tools/src/LSP/src/to_lsp.rs +++ b/kclvm/tools/src/LSP/src/to_lsp.rs @@ -22,9 +22,9 @@ pub fn lsp_pos(pos: &KCLPos) -> Position { /// Convert KCL Message to LSP Diagnostic fn kcl_msg_to_lsp_diags(msg: &Message, severity: DiagnosticSeverity) -> Diagnostic { - let kcl_pos = msg.pos.clone(); - let start_position = lsp_pos(&kcl_pos); - let end_position = lsp_pos(&kcl_pos); + let range = msg.range.clone(); + let start_position = lsp_pos(&range.0); + let end_position = lsp_pos(&range.1); Diagnostic { range: Range::new(start_position, end_position), @@ -52,7 +52,7 @@ fn kcl_err_level_to_severity(level: Level) -> DiagnosticSeverity { pub fn kcl_diag_to_lsp_diags(diag: &KCLDiagnostic, file_name: &str) -> Vec { diag.messages .iter() - .filter(|msg| msg.pos.filename == file_name) + .filter(|msg| msg.range.0.filename == file_name) .map(|msg| kcl_msg_to_lsp_diags(msg, kcl_err_level_to_severity(diag.level))) .collect() } diff --git a/kclvm/tools/src/lint/mod.rs b/kclvm/tools/src/lint/mod.rs index 7f885e442..7faea784d 100644 --- a/kclvm/tools/src/lint/mod.rs +++ b/kclvm/tools/src/lint/mod.rs @@ -45,11 +45,18 @@ mod tests; /// Diagnostic { /// level: Warning /// messages: [Message { -/// pos: Position { -/// filename: test.k, -/// line: 1, -/// column: None, -/// }, +/// range: ( +/// Position { +/// filename: test.k, +/// line: 1, +/// column: None, +/// }, +/// Position { +/// filename: test.k, +/// line: 1, +/// column: None, +/// }, +/// ), /// style: Style::Line, /// message: "Module 'math' imported but unused", /// note: Some("Consider removing this statement".to_string()),