Skip to content

Commit

Permalink
Merge pull request #1035 from veryl-lang/unresolavable_generic_argument
Browse files Browse the repository at this point in the history
Improve error message by unresolvable generic argument
  • Loading branch information
dalance authored Oct 24, 2024
2 parents a526bfe + 2bed613 commit c9b5a99
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 29 deletions.
31 changes: 31 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
#[label("Error location")]
error_location: SourceSpan,
#[label("Definition")]
definition_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(unknown_attribute),
Expand Down Expand Up @@ -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(),
Expand Down
50 changes: 37 additions & 13 deletions crates/analyzer/src/handlers/create_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<Token>,
) {
if let Some(last_found) = err.last_found {
let name = last_found.token.to_string();
match err.cause {
Expand All @@ -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<Token>,
) {
if path.is_generic_reference() {
return;
}
Expand Down Expand Up @@ -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),
);
}
}
}
Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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(())
}
Expand All @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions crates/analyzer/src/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
33 changes: 17 additions & 16 deletions crates/analyzer/src/symbol_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand All @@ -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;
}
}
Expand All @@ -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);
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions crates/analyzer/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<X>::W;
}
package PackageA::<T: const> {
const W: u32 = T;
}
"#;

let errors = analyze(code);
assert!(matches!(
errors[0],
AnalyzerError::UnresolvableGenericArgument { .. }
));
}

0 comments on commit c9b5a99

Please sign in to comment.