Skip to content

Commit

Permalink
raise error for package referecne before defnition
Browse files Browse the repository at this point in the history
(refs: #1166)
  • Loading branch information
taichi-ishitani committed Dec 27, 2024
1 parent d50cbfe commit f7515bb
Show file tree
Hide file tree
Showing 22 changed files with 255 additions and 101 deletions.
27 changes: 27 additions & 0 deletions crates/analyzer/src/analyzer_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,21 @@ pub enum AnalyzerError {
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(referring_package_before_definition),
help("change order of package definitions"),
url("")
)]
#[error("pakcakge {identifier} is referred before it is defined.")]
ReferringPackageBeforeDefinition {
identifier: String,
#[source_code]
input: NamedSource<String>,
#[label("Error location")]
error_location: SourceSpan,
},

#[diagnostic(
severity(Error),
code(unresolvable_generic_argument),
Expand Down Expand Up @@ -1569,6 +1584,18 @@ impl AnalyzerError {
}
}

pub fn referring_package_before_definition(
identifier: &str,
source: &str,
token: &TokenRange,
) -> Self {
AnalyzerError::ReferringPackageBeforeDefinition {
identifier: identifier.to_string(),
input: AnalyzerError::named_source(source, token),
error_location: token.into(),
}
}

pub fn unresolvable_generic_argument(
identifier: &str,
source: &str,
Expand Down
62 changes: 58 additions & 4 deletions crates/analyzer/src/handlers/create_reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::type_dag::{self, Context, DagError};
use std::collections::HashMap;
use veryl_parser::resource_table;
use veryl_parser::veryl_grammar_trait::*;
use veryl_parser::veryl_token::{is_anonymous_text, Token, TokenRange};
use veryl_parser::veryl_token::{is_anonymous_text, Token, TokenRange, TokenSource};
use veryl_parser::veryl_walker::{Handler, HandlerPoint};
use veryl_parser::ParolError;

Expand All @@ -20,6 +20,7 @@ pub struct CreateReference<'a> {
text: &'a str,
point: HandlerPoint,
inst_ports: Vec<Port>,
definition_token: Option<Token>,
inst_sv_module: bool,
is_anonymous_identifier: bool,
port_direction: Option<Direction>,
Expand Down Expand Up @@ -107,6 +108,10 @@ impl<'a> CreateReference<'a> {

match symbol_table::resolve((&base_path, namespace)) {
Ok(symbol) => {
if (i + 1) == path.len() {
self.check_pacakge_reference(self.definition_token, &symbol.found);
}

symbol_table::add_reference(symbol.found.id, &path.paths[0].base);

// Check number of arguments
Expand Down Expand Up @@ -181,6 +186,39 @@ impl<'a> CreateReference<'a> {
}
}

fn check_pacakge_reference(&mut self, base_token: Option<Token>, symbol: &Symbol) {
if base_token.is_none() {
return;
}

let package_symbol = symbol
.get_ancestors()
.into_iter()
.find(|x| matches!(x.kind, SymbolKind::Package(_)));
if package_symbol.is_none() {
return;
}

let base_token = base_token.unwrap();
let package_token = package_symbol.unwrap().token;
if let (TokenSource::File(package_file), TokenSource::File(base_file)) =
(package_token.source, base_token.source)
{
let referecne_before_definition = package_file == base_file
&& (package_token.line > base_token.line
|| package_token.line == base_token.line
&& package_token.column > base_token.column);
if referecne_before_definition {
self.errors
.push(AnalyzerError::referring_package_before_definition(
&package_token.to_string(),
self.text,
&package_token.into(),
));
}
}
}

fn insert_declaration_dag_node(&mut self, symbol: &Symbol) -> Option<u32> {
if let Some(child) = self.insert_dag_node(symbol) {
if let Some(parent) = self.dag_scope_parent.last().cloned() {
Expand Down Expand Up @@ -599,9 +637,13 @@ impl VerylGrammarTrait for CreateReference<'_> {
match self.point {
HandlerPoint::Before => {
let symbol = symbol_table::resolve(arg.identifier.as_ref()).unwrap();
self.definition_token = Some(symbol.found.token);
self.insert_scope_declaration_dag_node(&symbol.found, Context::Module);
}
HandlerPoint::After => self.pop_scope_dag(),
HandlerPoint::After => {
self.definition_token = None;
self.pop_scope_dag();
}
}
Ok(())
}
Expand All @@ -610,9 +652,13 @@ impl VerylGrammarTrait for CreateReference<'_> {
match self.point {
HandlerPoint::Before => {
let symbol = symbol_table::resolve(arg.identifier.as_ref()).unwrap();
self.definition_token = Some(symbol.found.token);
self.insert_scope_declaration_dag_node(&symbol.found, Context::Interface);
}
HandlerPoint::After => self.pop_scope_dag(),
HandlerPoint::After => {
self.definition_token = None;
self.pop_scope_dag();
}
}
Ok(())
}
Expand All @@ -621,9 +667,13 @@ impl VerylGrammarTrait for CreateReference<'_> {
match self.point {
HandlerPoint::Before => {
let symbol = symbol_table::resolve(arg.identifier.as_ref()).unwrap();
self.definition_token = Some(symbol.found.token);
self.insert_scope_declaration_dag_node(&symbol.found, Context::Package);
}
HandlerPoint::After => self.pop_scope_dag(),
HandlerPoint::After => {
self.definition_token = None;
self.pop_scope_dag();
}
}
Ok(())
}
Expand All @@ -638,6 +688,10 @@ impl VerylGrammarTrait for CreateReference<'_> {
if let Ok(symbol) = symbol_table::resolve(
x.import_declaration.scoped_identifier.as_ref(),
) {
self.check_pacakge_reference(
Some(x.import_declaration.import.import_token.token),
&symbol.found,
);
if let Some(child) = self.insert_dag_node(&symbol.found) {
self.dag_file_imports.push(child);
}
Expand Down
11 changes: 11 additions & 0 deletions crates/analyzer/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ impl Symbol {
None
}

pub fn get_ancestors(&self) -> Vec<Symbol> {
let mut ancestors = Vec::new();

ancestors.push(self.clone());
if let Some(parent) = self.get_parent() {
ancestors.append(&mut parent.get_ancestors());
}

ancestors
}

pub fn evaluate(&self) -> Evaluated {
if let Some(evaluated) = self.evaluated.get() {
evaluated
Expand Down
61 changes: 61 additions & 0 deletions crates/analyzer/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,67 @@ fn undefined_identifier() {
));
}

#[test]
fn referring_package_before_definition() {
let code = r#"
module ModuleA {
const A: u32 = PakcageB::B;
}
package PakcageB {
const B: u32 = 0;
}
"#;

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

let code = r#"
interface InterfaceA {
const A: u32 = PakcageB::B;
}
package PakcageB {
const B: u32 = 0;
}
"#;

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

let code = r#"
package PackageA {
const A: u32 = PakcageB::B;
}
package PakcageB {
const B: u32 = 0;
}
"#;

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

let code = r#"
import PakcageB::B;
package PakcageB {
const B: u32 = 0;
}
"#;

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

#[test]
fn unknown_attribute() {
let code = r#"
Expand Down
2 changes: 1 addition & 1 deletion testcases/map/testcases/sv/19_import_export.sv.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion testcases/map/testcases/sv/37_package_ref.sv.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion testcases/map/testcases/sv/44_import_resolve.sv.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion testcases/map/testcases/sv/56_generic_interface.sv.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion testcases/map/testcases/sv/57_generic_package.sv.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f7515bb

Please sign in to comment.