Skip to content

Commit 94ab52e

Browse files
committed
feat(analyzer): warn on mutable dynamic for bounds
1 parent b22fb96 commit 94ab52e

7 files changed

Lines changed: 1073 additions & 0 deletions

File tree

crates/analyzer/src/analyzer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::attribute_table;
33
use crate::comb_loop_detect;
44
use crate::conv::{Context, Conv};
55
use crate::definition_table;
6+
use crate::dynamic_for_check;
67
use crate::generic_inference_table;
78
use crate::handlers::*;
89
use crate::ir::{Ir, IrResult};
@@ -266,6 +267,7 @@ impl Analyzer {
266267

267268
ret.append(&mut symbol_table::check_unused_variable());
268269
ret.append(&mut symbol_table::check_wavedrom());
270+
ret.append(&mut dynamic_for_check::check(ir));
269271
ret.append(&mut comb_loop_detect::check(ir));
270272

271273
ret

crates/analyzer/src/analyzer_error.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,23 @@ pub enum AnalyzerError {
740740
token_source: TokenSource,
741741
},
742742

743+
#[diagnostic(
744+
severity(Warning),
745+
code(mutable_for_bound),
746+
help("move the assignment outside the loop or iterate over a separate, stable bound; this will become an error in a future release"),
747+
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
748+
)]
749+
#[error(
750+
"for-loop continuation bound is modified by the loop body, so backends may execute different iteration counts"
751+
)]
752+
MutableForBound {
753+
#[source_code]
754+
input: MultiSources,
755+
#[label("Warning location")]
756+
error_location: SourceSpan,
757+
token_source: TokenSource,
758+
},
759+
743760
#[diagnostic(
744761
severity(Error),
745762
code(invalid_for_step),
@@ -2076,6 +2093,7 @@ impl AnalyzerError {
20762093
AnalyzerError::MissingTri { input, .. } => input,
20772094
AnalyzerError::MixedFunctionArgument { input, .. } => input,
20782095
AnalyzerError::MixedStructUnionMember { input, .. } => input,
2096+
AnalyzerError::MutableForBound { input, .. } => input,
20792097
AnalyzerError::MultipleAssignment { input, .. } => input,
20802098
AnalyzerError::MultipleDefault { input, .. } => input,
20812099
AnalyzerError::NonConstantSelectWidth { input, .. } => input,
@@ -2197,6 +2215,7 @@ impl AnalyzerError {
21972215
AnalyzerError::MissingTri { token_source, .. } => *token_source,
21982216
AnalyzerError::MixedFunctionArgument { token_source, .. } => *token_source,
21992217
AnalyzerError::MixedStructUnionMember { token_source, .. } => *token_source,
2218+
AnalyzerError::MutableForBound { token_source, .. } => *token_source,
22002219
AnalyzerError::MultipleAssignment { token_source, .. } => *token_source,
22012220
AnalyzerError::MultipleDefault { token_source, .. } => *token_source,
22022221
AnalyzerError::PrivateMember { token_source, .. } => *token_source,
@@ -2638,6 +2657,13 @@ impl AnalyzerError {
26382657
token_source: token.source(),
26392658
}
26402659
}
2660+
pub fn mutable_for_bound(token: &TokenRange) -> Self {
2661+
AnalyzerError::MutableForBound {
2662+
input: source(token),
2663+
error_location: token.into(),
2664+
token_source: token.source(),
2665+
}
2666+
}
26412667
pub fn invalid_for_step(cause: InvalidForStepKind, token: &TokenRange) -> Self {
26422668
AnalyzerError::InvalidForStep {
26432669
cause,

crates/analyzer/src/attribute.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ struct Pattern {
196196
pub missing_reset_statement: StrId,
197197
pub unused_variable: StrId,
198198
pub unassign_variable: StrId,
199+
pub mutable_for_bound: StrId,
199200
pub enum_encoding: StrId,
200201
pub sequential: StrId,
201202
pub onehot: StrId,
@@ -231,6 +232,7 @@ impl Pattern {
231232
missing_reset_statement: resource_table::insert_str("missing_reset_statement"),
232233
unused_variable: resource_table::insert_str("unused_variable"),
233234
unassign_variable: resource_table::insert_str("unassign_variable"),
235+
mutable_for_bound: resource_table::insert_str("mutable_for_bound"),
234236
enum_encoding: resource_table::insert_str("enum_encoding"),
235237
sequential: resource_table::insert_str("sequential"),
236238
onehot: resource_table::insert_str("onehot"),
@@ -348,6 +350,9 @@ impl TryFrom<&veryl_parser::veryl_grammar_trait::Attribute> for Attribute {
348350
x if x == pat.unassign_variable => {
349351
Ok(Attribute::Allow(AllowItem::UnassignVariable))
350352
}
353+
x if x == pat.mutable_for_bound => {
354+
Ok(Attribute::Allow(AllowItem::MutableForBound))
355+
}
351356
_ => Err(err),
352357
}
353358
} else {
@@ -536,6 +541,7 @@ pub enum AllowItem {
536541
MissingResetStatement,
537542
UnusedVariable,
538543
UnassignVariable,
544+
MutableForBound,
539545
}
540546

541547
impl AllowItem {
@@ -558,6 +564,7 @@ impl fmt::Display for AllowItem {
558564
AllowItem::MissingResetStatement => "missing_reset_statement",
559565
AllowItem::UnusedVariable => "unused_variable",
560566
AllowItem::UnassignVariable => "unassign_variable",
567+
AllowItem::MutableForBound => "mutable_for_bound",
561568
};
562569
text.fmt(f)
563570
}

0 commit comments

Comments
 (0)