From 2bed613b0eb47f8075fd88263a7eeeb1fc500fd6 Mon Sep 17 00:00:00 2001 From: dalance Date: Thu, 24 Oct 2024 09:50:03 +0900 Subject: [PATCH] Improve error message by unresolvable generic argument --- crates/analyzer/src/analyzer_error.rs | 31 ++++++++++++ .../analyzer/src/handlers/create_reference.rs | 50 ++++++++++++++----- crates/analyzer/src/namespace.rs | 10 ++++ crates/analyzer/src/symbol_path.rs | 33 ++++++------ crates/analyzer/src/tests.rs | 20 ++++++++ 5 files changed, 115 insertions(+), 29 deletions(-) diff --git a/crates/analyzer/src/analyzer_error.rs b/crates/analyzer/src/analyzer_error.rs index 87c4b741..7c1c8db5 100644 --- a/crates/analyzer/src/analyzer_error.rs +++ b/crates/analyzer/src/analyzer_error.rs @@ -716,6 +716,23 @@ pub enum AnalyzerError { error_location: SourceSpan, }, + #[diagnostic( + severity(Error), + code(unresolvable_generic_argument), + help(""), + url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#unresolvable_generic_argument") + )] + #[error("{identifier} can't be resolved from the definition of generics")] + UnresolvableGenericArgument { + identifier: String, + #[source_code] + input: NamedSource, + #[label("Error location")] + error_location: SourceSpan, + #[label("Definition")] + definition_location: SourceSpan, + }, + #[diagnostic( severity(Error), code(unknown_attribute), @@ -1465,6 +1482,20 @@ impl AnalyzerError { } } + pub fn unresolvable_generic_argument( + identifier: &str, + source: &str, + token: &TokenRange, + definition_token: &TokenRange, + ) -> Self { + AnalyzerError::UnresolvableGenericArgument { + identifier: identifier.to_string(), + input: AnalyzerError::named_source(source, token), + error_location: token.into(), + definition_location: definition_token.into(), + } + } + pub fn unknown_attribute(name: &str, source: &str, token: &TokenRange) -> Self { AnalyzerError::UnknownAttribute { name: name.to_string(), diff --git a/crates/analyzer/src/handlers/create_reference.rs b/crates/analyzer/src/handlers/create_reference.rs index b3d64a1b..57cecd7d 100644 --- a/crates/analyzer/src/handlers/create_reference.rs +++ b/crates/analyzer/src/handlers/create_reference.rs @@ -5,7 +5,7 @@ use crate::symbol::{GenericMap, SymbolKind}; use crate::symbol_path::{GenericSymbolPath, SymbolPath}; use crate::symbol_table::{self, ResolveError, ResolveErrorCause}; use veryl_parser::veryl_grammar_trait::*; -use veryl_parser::veryl_token::TokenRange; +use veryl_parser::veryl_token::{Token, TokenRange}; use veryl_parser::veryl_walker::{Handler, HandlerPoint}; use veryl_parser::ParolError; @@ -24,7 +24,12 @@ impl<'a> CreateReference<'a> { } } - fn push_resolve_error(&mut self, err: ResolveError, token: &TokenRange) { + fn push_resolve_error( + &mut self, + err: ResolveError, + token: &TokenRange, + generics_token: Option, + ) { if let Some(last_found) = err.last_found { let name = last_found.token.to_string(); match err.cause { @@ -41,14 +46,29 @@ impl<'a> CreateReference<'a> { } } else if let ResolveErrorCause::NotFound(not_found) = err.cause { let name = format!("{}", not_found); - self.errors - .push(AnalyzerError::undefined_identifier(&name, self.text, token)); + if let Some(generics_token) = generics_token { + self.errors + .push(AnalyzerError::unresolvable_generic_argument( + &name, + self.text, + token, + &generics_token.into(), + )); + } else { + self.errors + .push(AnalyzerError::undefined_identifier(&name, self.text, token)); + } } else { unreachable!(); } } - fn generic_symbol_path(&mut self, path: &GenericSymbolPath, namespace: &Namespace) { + fn generic_symbol_path( + &mut self, + path: &GenericSymbolPath, + namespace: &Namespace, + generics_token: Option, + ) { if path.is_generic_reference() { return; } @@ -103,7 +123,11 @@ impl<'a> CreateReference<'a> { let mut references = symbol.found.generic_references(); for path in &mut references { path.apply_map(&map); - self.generic_symbol_path(path, &symbol.found.inner_namespace()); + self.generic_symbol_path( + path, + &symbol.found.inner_namespace(), + Some(symbol.found.token), + ); } } } @@ -114,7 +138,7 @@ impl<'a> CreateReference<'a> { return; } - self.push_resolve_error(err, &path.range); + self.push_resolve_error(err, &path.range, generics_token); } } } @@ -144,7 +168,7 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> { } // TODO check SV-side member to suppress error - self.push_resolve_error(err, &arg.into()); + self.push_resolve_error(err, &arg.into(), None); } } } @@ -157,7 +181,7 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> { let path: GenericSymbolPath = arg.into(); let namespace = namespace_table::get(ident.id).unwrap(); - self.generic_symbol_path(&path, &namespace); + self.generic_symbol_path(&path, &namespace, None); } Ok(()) } @@ -177,7 +201,7 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> { symbol_table::add_reference(symbol.found.id, &ident); } Err(err) => { - self.push_resolve_error(err, &arg.into()); + self.push_resolve_error(err, &arg.into(), None); } } } @@ -194,7 +218,7 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> { } } Err(err) => { - self.push_resolve_error(err, &arg.identifier.as_ref().into()); + self.push_resolve_error(err, &arg.identifier.as_ref().into(), None); } } } @@ -212,7 +236,7 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> { } } Err(err) => { - self.push_resolve_error(err, &arg.identifier.as_ref().into()); + self.push_resolve_error(err, &arg.identifier.as_ref().into(), None); } } } @@ -239,7 +263,7 @@ impl<'a> VerylGrammarTrait for CreateReference<'a> { } } Err(err) => { - self.push_resolve_error(err, &arg.scoped_identifier.as_ref().into()); + self.push_resolve_error(err, &arg.scoped_identifier.as_ref().into(), None); } } } diff --git a/crates/analyzer/src/namespace.rs b/crates/analyzer/src/namespace.rs index e2d027f5..f22d334d 100644 --- a/crates/analyzer/src/namespace.rs +++ b/crates/analyzer/src/namespace.rs @@ -58,6 +58,16 @@ impl Namespace { } Self { paths } } + + pub fn strip_prefix(&mut self, x: &Namespace) { + let mut paths = vec![]; + for (i, p) in self.paths.iter().enumerate() { + if x.paths.get(i) != Some(p) { + paths.push(*p); + } + } + self.paths = paths; + } } impl Default for Namespace { diff --git a/crates/analyzer/src/symbol_path.rs b/crates/analyzer/src/symbol_path.rs index 40380992..399bb4ce 100644 --- a/crates/analyzer/src/symbol_path.rs +++ b/crates/analyzer/src/symbol_path.rs @@ -368,6 +368,7 @@ impl GenericSymbolPath { self.paths.clone_from(&x.paths); self.paths.append(&mut paths); self.kind = x.kind; + self.range = x.range; break; } } @@ -381,6 +382,7 @@ impl GenericSymbolPath { arg.paths.clone_from(&x.paths); arg.paths.append(&mut paths); arg.kind = x.kind; + arg.range = x.range; break; } } @@ -399,23 +401,22 @@ impl GenericSymbolPath { return; }; if let Ok(symbol) = symbol_table::resolve((&self.generic_path(), &self_namespace)) { - let mut prefix = Vec::new(); - let default_path = namespace_table::get_default(); - for (i, path) in symbol.found.namespace.paths.iter().enumerate() { - // if path is included by default_path, it is not appended - if default_path.paths.get(i) == Some(path) { - continue; + let mut parent = symbol.found.namespace.clone(); + parent.strip_prefix(&namespace_table::get_default()); + + // If symbol belongs Package, it can be expanded + if let Ok(parent_symbol) = symbol_table::resolve((&parent.paths, &self_namespace)) { + if matches!(parent_symbol.found.kind, SymbolKind::Package(_)) { + for (i, path) in parent.paths.iter().enumerate() { + let token = Token::generate(*path); + namespace_table::insert(token.id, self_file_path, &self_namespace); + let generic_symbol = GenericSymbol { + base: token, + arguments: vec![], + }; + self.paths.insert(i, generic_symbol); + } } - - let token = Token::generate(*path); - namespace_table::insert(token.id, self_file_path, &self_namespace); - prefix.push(GenericSymbol { - base: token, - arguments: vec![], - }); - } - for (i, p) in prefix.into_iter().enumerate() { - self.paths.insert(i, p); } } } diff --git a/crates/analyzer/src/tests.rs b/crates/analyzer/src/tests.rs index f2a2c5a5..352d615a 100644 --- a/crates/analyzer/src/tests.rs +++ b/crates/analyzer/src/tests.rs @@ -2535,3 +2535,23 @@ fn conflict_with_mangled_enum_member() { AnalyzerError::DuplicatedIdentifier { .. } )); } + +#[test] +fn unresolvable_generic_argument() { + let code = r#" + module ModuleA { + const X: u32 = 1; + const Y: u32 = PackageA::::W; + } + + package PackageA:: { + const W: u32 = T; + } + "#; + + let errors = analyze(code); + assert!(matches!( + errors[0], + AnalyzerError::UnresolvableGenericArgument { .. } + )); +}