use crate::multi_sources::{MultiSources, Source, SourceExcerpt};
use miette::{self, Diagnostic, Severity, SourceSpan};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
use thiserror::Error;
use veryl_parser::resource_table::StrId;
use veryl_parser::token_range::TokenRange;
use veryl_parser::veryl_token::TokenSource;
#[derive(Error, Diagnostic, Debug, PartialEq, Eq)]
pub enum AnalyzerError {
#[diagnostic(
severity(Error),
code(ambiguous_elsif),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("elsif/else attribute is ambiguous because {cause}")]
AmbiguousElsif {
cause: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(ambiguous_identifier),
help("disambiguate with an explicit scope or import"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is ambiguous because it is imported from multiple packages")]
AmbiguousIdentifier {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(anonymous_identifier_usage),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Anonymous identifier can't be placed at here")]
AnonymousIdentifierUsage {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(call_non_function),
help("remove call to non-function symbol"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Calling non-function symbol \"{identifier}\" which has kind \"{kind}\"")]
CallNonFunction {
identifier: String,
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label(collection, "instantiated at")]
inst_context: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(side_effect_function_call_in_always_ff),
help("move the external write into this always_ff, or use an output argument connected to a variable declared inside it"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"function \"{identifier}\" can't be called in always_ff because it may write an HDL object declared outside the function"
)]
SideEffectFunctionCallInAlwaysFf {
identifier: String,
#[source_code]
input: MultiSources,
#[label("called from always_ff")]
error_location: SourceSpan,
#[label(collection, "called from here")]
call_stack: Vec<SourceSpan>,
#[label(collection, "external write occurs here")]
external_writes: Vec<SourceSpan>,
#[label(collection, "function declared here")]
function_definition: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(function_output_in_always_ff),
help("connect \"{output}\" to a variable declared inside this always_ff, then assign that variable to \"{destination}\""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"output \"{output}\" of function \"{function}\" can't write \"{destination}\" directly from always_ff"
)]
FunctionOutputInAlwaysFf {
function: String,
output: String,
destination: String,
#[source_code]
input: MultiSources,
#[label("\"{destination}\" is declared outside this always_ff")]
error_location: SourceSpan,
#[label(collection, "\"{output}\" is declared as an output here")]
output_declaration: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(combinational_loop),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("combinational loop detected")]
CombinationalLoop {
identifier: String,
cycle: String,
#[source_code]
input: MultiSources,
#[label("involved in combinational feedback")]
error_location: SourceSpan,
#[label(collection, "also involved in combinational feedback")]
loop_participants: Vec<SourceSpan>,
#[label(collection, "dependency passes through this statement")]
dependency_sites: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(combinational_loop_position_overflow),
help("reduce the flattened width or array size used by this module"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("combinational-loop position exceeds the supported range")]
CombinationalLoopPositionOverflow {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(cyclic_type_dependency),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Cyclic dependency between \"{start}\" and \"{end}\"")]
CyclicTypeDependency {
start: String,
end: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(cyclic_file_dependency),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Cyclic dependency between \"{start}\" and \"{end}\"")]
CyclicFileDependency {
start: String,
end: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(duplicate_argument),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("named argument \"{identifier}\" is connected more than once")]
DuplicateArgument {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(duplicate_enum_variant),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("The value of enum variant \"{identifier}\" is the same as another variant")]
DuplicateEnumVariant {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(duplicated_identifier),
help("{kind}"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is duplicated")]
DuplicatedIdentifier {
identifier: String,
kind: DuplicatedIdentifierKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(exceed_limit),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("exceed {kind} limit: {value}")]
ExceedLimit {
kind: ExceedLimitKind,
value: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(fixed_type_with_signed_modifier),
help("remove 'signed` modifier"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("'signed' modifier can't be used with fixed type")]
FixedTypeWithSignedModifier {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(include_failure),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" can't be read because \"{cause}\"")]
IncludeFailure {
name: String,
cause: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(incompat_proto),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is incompatible with \"{proto}\" because {cause}")]
IncompatProto {
identifier: String,
proto: String,
cause: IncompatProtoKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(infinite_recursion),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("infinite instance recursion is detected")]
InfiniteRecursion {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_assignment),
help("remove the assignment"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" can't be assigned because it is {kind}")]
InvalidAssignment {
identifier: String,
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_cast),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Casting from {from} to {to} is incompatible")]
InvalidCast {
from: String,
to: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_clock),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"\"{identifier}\" can't be used as a clock because it is not 'clock' type nor a single bit signal"
)]
InvalidClock {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_clock_domain),
help("Remove the clock domain annotation"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Cannot specify clock domain annotation to module instance")]
InvalidClockDomain {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_connect_operand),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" can't be used as a connect operand because {reason}")]
InvalidConnectOperand {
identifier: String,
reason: InvalidConnectOperandKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_direction),
help("remove {kind} direction"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} direction can't be placed at here")]
InvalidDirection {
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_embed),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("embed (way: {way}/lang: {lang}) can't be used at here")]
InvalidEmbed {
way: String,
lang: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_embed_identifier),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("embed identifier can be used in (way: inline/lang: sv) code block only")]
InvalidEmbedIdentifier {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_enum_variant),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("The value of enum variant \"{identifier}\" is not encoded value by {encoding}")]
InvalidEnumVariant {
identifier: String,
encoding: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_factor),
help("remove {kind} from expression"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{} cannot be used as a factor in an expression", match .identifier {
Some(x) => format!("\"{}\" of {}", x, .kind),
None => format!("{}", .kind),
})]
InvalidFactor {
identifier: Option<String>,
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label(collection, "instantiated at")]
inst_context: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_size_type),
help("use `$bits` to get the bit width of a type (e.g. `logic<$bits(u32)>`)"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("a type can't be used as a width or an array size")]
InvalidSizeType {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_unsized_literal),
help("give the literal an explicit width (e.g. `1'b0`)"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("unsized literal can't be used in a self-determined context")]
InvalidUnsizedLiteral {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(invalid_identifier),
help("follow naming rule"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" violate \"{rule}\" naming rule")]
InvalidIdentifier {
identifier: String,
rule: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_import),
help("fix import item"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("This item can't be imported")]
InvalidImport {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(severity(Error),
code(invalid_mixin),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{identifier} can't be mixed-in because {reason}")]
InvalidMixin {
identifier: String,
reason: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(invalid_logical_operand),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} should be 1-bit value")]
InvalidLogicalOperand {
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(unsigned_arith_shift),
help("consider using logical shift (<<, >>) or casting the operand to signed"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Arithmetic shift on unsigned operand has no effect different from logical shift")]
UnsignedArithShift {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_lsb),
help("remove lsb"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("lsb can't be placed at here")]
InvalidLsb {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_modifier),
help("remove the modifier"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} modifier can't be used because {reason}")]
InvalidModifier {
kind: String,
reason: InvalidModifierKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_modport_item),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is not a {kind}")]
InvalidModportItem {
kind: InvalidModportItemKind,
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_msb),
help("remove msb"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("msb can't be placed at here")]
InvalidMsb {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_number_character),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} number can't contain {cause}")]
InvalidNumberCharacter {
cause: char,
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_operand),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} cannot be used as a operand of {op} operator")]
InvalidOperand {
kind: String,
op: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_port_default_value),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind}")]
InvalidPortDefaultValue {
kind: InvalidPortDefaultValueKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_range),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("range is invalid because {cause}")]
InvalidRange {
cause: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_reset),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"\"{identifier}\" can't be used as a reset because it is not 'reset' type nor a single bit signal"
)]
InvalidReset {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_select),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("invalid select caused by {kind}")]
InvalidSelect {
kind: InvalidSelectKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label(collection, "instantiated at")]
inst_context: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_range_assign),
help("use a constant, in-range, ascending slice"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"array range select on an assignment left-hand side must be a constant, in-range, ascending slice"
)]
InvalidRangeAssign {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(non_constant_select_width),
help("use a constant expression for the part-select width"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("`+:`/`-:`/`step` part-select width must be a constant")]
NonConstantSelectWidth {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_statement),
help("remove {kind} statement"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} statement can't be placed at here")]
InvalidStatement {
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_initial_assign),
help("add `#[allow(initial_assign)]` to the declaration of \"{identifier}\" if the target device initializes it at configuration time"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is assigned in an initial block")]
InvalidInitialAssign {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(non_portable_dependency),
help("add \"{item}\" to `lint.portability.allow_in_dependencies` in Veryl.toml to accept it"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("non-portable `#[allow({item})]` is used in dependency \"{project}\"")]
NonPortableDependency {
item: String,
project: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_for_range),
help("{help}"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind}")]
InvalidForRange {
kind: InvalidForRangeKind,
help: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_for_step),
help("make the step strictly advance the induction variable toward the end of the range"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{cause}")]
InvalidForStep {
cause: InvalidForStepKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(for_loop_overflow),
help("keep the loop variable within the 32-bit signed range, or narrow the range or step"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("for-loop step overflows the 32-bit signed loop variable")]
ForLoopOverflow {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_test),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("test is invalid because {cause}")]
InvalidTest {
cause: InvalidTestKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_tb_usage),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("$tb/$comp components can only be used inside a test module")]
InvalidTbUsage {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_tb_port),
help("add \"{port}\" port connection"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("$tb component \"{name}\" requires \"{port}\" port, but it is not connected")]
MissingTbPort {
name: String,
port: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_tb_port),
help("remove \"{port}\" connection"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("$tb component \"{name}\" has no \"{port}\" port")]
UnknownTbPort {
name: String,
port: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(component_interface_mismatch),
help("{help}"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind}")]
ComponentInterfaceMismatch {
kind: ComponentInterfaceMismatchKind,
help: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_type_declaration),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind} can't be declared in interface declaration")]
InvalidTypeDeclaration {
kind: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invisible_identifier),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("cannot refer indentifier \"{identifier}\" because it is invisible at here")]
InvisibleIndentifier {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(last_item_with_define),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"ifdef/ifndef/elsif/else attribute can't be used with the last item in comma-separated list"
)]
LastItemWithDefine {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(last_item_with_define),
help(
"declare \"{identifier}\" before a member without ifdef/ifndef/elsif/else so that it is not generated last"
),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"ifdef/ifndef/elsif/else attribute can't be used with \"{identifier}\", which is generated as the last member of modport \"{modport}\""
)]
LastItemWithDefineInModport {
identifier: String,
modport: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label(collection, "generated from")]
member_source: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(member_access_on_array),
help("\"{name}\" has {array_dims} array dimension(s); index all of them before accessing member \"{member}\""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is an array; index it before accessing member \"{member}\"")]
MemberAccessOnArray {
name: String,
member: String,
array_dims: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(mismatch_assignment),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{src}\" can't be assigned to \"{dst}\"")]
MismatchAssignment {
src: String,
dst: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label(collection, "instantiated at")]
inst_context: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(implicit_clock_conversion),
help(
"clock/reset-ness can be conferred only at a declaration: bind the value to a clock/reset-typed signal in the parent (e.g. `let g: '_ clock = expr;`) and connect that signal"
),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("implicit conversion from \"{src}\" to \"{dst}\" is not allowed at a port connection")]
ImplicitClockConversion {
src: String,
dst: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label(collection, "instantiated at")]
inst_context: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_clock_assignment),
help(
"toggle a logic variable in always_ff and bind it to a clock/reset-typed signal instead (e.g. `var t: logic;` ... `let d: '_ clock = t;`)"
),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{dst}\"-typed signal can't be assigned in always_ff")]
InvalidClockAssignment {
dst: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(non_positive_value),
help("positive types (p8/p16/p32/p64) can only accept values > 0"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Value {value} cannot be assigned to positive type \"{typ}\"")]
NonPositiveValue {
value: String,
typ: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(mismatch_attribute_args),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Arguments of \"{name}\" is expected to \"{expected}\"")]
MismatchAttributeArgs {
name: String,
expected: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(mismatch_clock_domain),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Clock domain crossing is detected")]
MismatchClockDomain {
clock_domain: String,
other_domain: String,
#[source_code]
input: MultiSources,
#[label("clock domain {clock_domain}")]
error_location: SourceSpan,
#[label("clock domain {other_domain}")]
other_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(mismatch_function_arg),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{src}\" type can't be used as an argument of function \"{name}\"")]
MismatchFunctionArg {
name: String,
src: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(mismatch_function_arity),
help("fix function arguments"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("function \"{name}\" has {arity} arguments, but {args} arguments are supplied")]
MismatchFunctionArity {
name: String,
arity: usize,
args: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(mismatch_generics_arity),
help("fix generics arguments"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("generics \"{name}\" has {arity} generic arguments, but {args} arguments are supplied")]
MismatchGenericsArity {
name: String,
arity: usize,
args: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(mismatch_type),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{kind}")]
MismatchType {
kind: MismatchTypeKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_clock_domain),
help("add clock domain annotation"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("clock domain annotation is required when there are multiple clocks")]
MissingClockDomain {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_clock_signal),
help("add clock port"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("clock signal is required for always_ff statement")]
MissingClockSignal {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_default_argument),
help("give default argument"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("missing default argument for parameter \"{identifier}\"")]
MissingDefaultArgument {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(generic_inference_failed),
help("provide explicit generic arguments like `{identifier}::<…>(…)`, or pass an argument whose width can be determined from a variable, port or parameter declaration"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("failed to infer generic arguments for `{identifier}`")]
GenericInferenceFailed {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(type_inference_not_supported),
help("use a simple variable reference, sized literal, or function call; otherwise provide an explicit type annotation"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("type inference is not supported for this expression")]
TypeInferenceNotSupported {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(type_inference_conflict),
help("all assignments to an untyped variable must agree on the same type"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("conflicting types in inference for `{identifier}`")]
TypeInferenceConflict {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_if_reset),
help("add if_reset statement"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("if_reset statement is required for always_ff with reset signal")]
MissingIfReset {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(missing_port),
help("add \"{port}\" port"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("module \"{name}\" has \"{port}\", but it is not connected")]
MissingPort {
name: String,
port: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_reset_signal),
help("add reset port"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("reset signal is required for always_ff with if_reset statement")]
MissingResetSignal {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(missing_reset_statement),
help("add reset statement"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is not reset in if_reset statement")]
MissingResetStatement {
name: String,
#[source_code]
input: MultiSources,
#[label(collection, "Not reset")]
error_locations: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(missing_tri),
help("add tri type modifier"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("tri type modifier is required at inout port")]
MissingTri {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(mixed_function_argument),
help("fix function arguments"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"positional arguments and named arguments are mixed. Both of them can't be used at the same time"
)]
MixedFunctionArgument {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(mixed_struct_union_member),
help("unify struct/union members to either 2-state member or 4-state member"),
url("")
)]
#[error("2-state member and 4-state member are mixed in the same struct/union")]
MixedStructUnionMember {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(multiple_assignment),
help("add `#[allow(multiple_assign)]` to the declaration of \"{identifier}\" if it is intentional"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is assigned in multiple procedural blocks or assignment statements")]
MultipleAssignment {
identifier: String,
#[source_code]
input: MultiSources,
#[label(collection, "Assigned")]
error_locations: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(multiple_default),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"\"{identifier}\" can't be used as the default {kind} because the default {kind} has already been specified."
)]
MultipleDefault {
kind: MultipleDefaultKind,
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(private_member),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is private member")]
PrivateMember {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(private_namespace),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is private namespace")]
PrivateNamespace {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(referring_before_definition),
help("move definition before reference point"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is referred before it is defined.")]
ReferringBeforeDefinition {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(reserved_identifier),
help("prefix `__` can't be used"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is reverved for compiler usage")]
ReservedIdentifier {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(sv_keyword_usage),
help("Change the identifier to a non-SystemVerilog keyword"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("SystemVerilog keyword may not be used as identifier")]
SvKeywordUsage {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(sv_with_implicit_reset),
help("Use types with explicit synchronisity and polarity like `reset_async_low`"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"Reset type with implicit synchronisity and polarity can't be connected to SystemVerilog module"
)]
SvWithImplicitReset {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(too_large_enum_variant),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"The value of enum variant \"{identifier}\" is {value}, it is can't be represented by {width} bits"
)]
TooLargeEnumVariant {
identifier: String,
value: isize,
width: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(too_large_number),
help("increase bit width"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("number is over the maximum size of {width} bits")]
TooLargeNumber {
width: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(zero_width_number),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("number can't have zero width")]
ZeroWidthNumber {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(too_much_enum_variant),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error(
"enum \"{identifier}\" has {number} variants, they are can't be represented by {width} bits"
)]
TooMuchEnumVariant {
identifier: String,
number: usize,
width: usize,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(unassign_variable),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is unassigned")]
UnassignVariable {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unassignable_output),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("unassignable type is connected to output port")]
UnassignableOutput {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(uncovered_branch),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is not covered by all branches, it causes latch generation")]
UncoveredBranch {
identifier: String,
#[source_code]
input: MultiSources,
#[label(collection, "Covered")]
error_locations: Vec<SourceSpan>,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(undefined_identifier),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is undefined")]
UndefinedIdentifier {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(unenclosed_inner_if_expression),
help("enclose the inner if expression in parenthesis"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("inner if expression should be enclosed in parenthesis, but is not")]
UnenclosedInnerIfExpression {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unevaluatable_value),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("Value, which is not evaluable at elaboration, can't be used as {kind}")]
UnevaluableValue {
kind: UnevaluableValueKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unexpandable_modport),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" can't be expanded")]
UnexpandableModport {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_attribute),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is not valid attribute")]
UnknownAttribute {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_embed_lang),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is not valid embed language")]
UnknownEmbedLang {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_embed_way),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is not valid embed way")]
UnknownEmbedWay {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_include_way),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is not valid include way")]
UnknownIncludeWay {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_member),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" doesn't have member \"{member}\"")]
UnknownMember {
name: String,
member: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_msb),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("resolving msb is failed")]
UnknownMsb {
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_param),
help("remove \"{param}\" param"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("module \"{name}\" doesn't have param \"{param}\", but it is overrided")]
UnknownParam {
name: String,
param: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_port),
help("remove \"{port}\" port"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("module \"{name}\" doesn't have port \"{port}\", but it is connected")]
UnknownPort {
name: String,
port: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unknown_unsafe),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{name}\" is not valid unsafe identifier")]
UnknownUnsafe {
name: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(unresolvable_generic_expression),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" can't be resolved from the definition of generics")]
UnresolvableGenericExpression {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
#[label("Definition")]
definition_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(unused_return),
help("add variable assignment for function return"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("return value of \"{identifier}\" is unused")]
UnusedReturn {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Warning),
code(unused_variable),
help("add prefix `_` to unused variable name"),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("\"{identifier}\" is unused")]
UnusedVariable {
identifier: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(wrong_seperator),
help("replace valid separator \"{valid_separator}\""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("separator \"{separator}\" can't be used at here")]
WrongSeparator {
separator: String,
valid_separator: String,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
#[diagnostic(
severity(Error),
code(invalid_wavedrom),
help(""),
url("https://doc.veryl-lang.org/book/07_appendix/02_semantic_error.html#{}", self.code().unwrap())
)]
#[error("{cause}")]
InvalidWavedrom {
cause: InvalidWavedromKind,
#[source_code]
input: MultiSources,
#[label("Error location")]
error_location: SourceSpan,
token_source: TokenSource,
},
}
fn source(token: &TokenRange) -> MultiSources {
let path = token.beg.source.to_string();
let text = token.beg.source.get_text();
MultiSources {
sources: vec![Source::new(path, text)],
}
}
fn source_with_context(
token: &TokenRange,
context: &[TokenRange],
) -> (MultiSources, Vec<SourceSpan>) {
let path = token.beg.source.to_string();
let text = token.beg.source.get_text();
let mut base = text.len();
let mut ranges = Vec::new();
let mut sources = Vec::new();
sources.push(Source::new(path, text));
for x in context.iter().rev() {
let path = x.beg.source.to_string();
let text = x.beg.source.get_text();
let mut range = *x;
range.offset(base as u32);
ranges.push(range.into());
base += text.len();
sources.push(Source::new(path, text));
}
let sources = MultiSources { sources };
(sources, ranges)
}
fn source_with_ordered_context(
token: &TokenRange,
context: &[TokenRange],
) -> (MultiSources, Vec<SourceSpan>) {
let text = token.source().get_text();
let mut base = text.len();
let mut sources = vec![Source::new(token.source().to_string(), text)];
let mut ranges = Vec::with_capacity(context.len());
let mut texts = HashMap::new();
let mut windows = HashMap::new();
let mut excerpt_bases = HashMap::new();
for token in context {
let token_source = token.source();
let text = texts
.entry(token_source)
.or_insert_with(|| token_source.get_text());
let span = (*token).into();
let window_key = (token_source, token.beg.line, token.end.line);
let excerpt = windows
.get(&window_key)
.copied()
.filter(|excerpt: &SourceExcerpt| excerpt.local_span(&span).is_some())
.or_else(|| {
Source::excerpt_window(text, &span, token.beg.line as usize, 1).inspect(|excerpt| {
windows.insert(window_key, *excerpt);
})
});
let (excerpt, local_span) = excerpt
.and_then(|excerpt| Some((excerpt, excerpt.local_span(&span)?)))
.unwrap_or_else(|| (SourceExcerpt::whole(text), span));
let excerpt_key = (token_source, excerpt);
let excerpt_base = if let Some(base) = excerpt_bases.get(&excerpt_key) {
*base
} else {
let source = Source::from_excerpt(token_source.to_string(), text, excerpt)
.unwrap_or_else(|| Source::new(token_source.to_string(), text.clone()));
let excerpt_base = base;
base += source.text.len();
sources.push(source);
excerpt_bases.insert(excerpt_key, excerpt_base);
excerpt_base
};
ranges.push((excerpt_base + local_span.offset(), local_span.len()).into());
}
(MultiSources { sources }, ranges)
}
#[cfg(test)]
mod ordered_context_tests {
use super::*;
use miette::SourceCode;
use std::path::Path;
use veryl_parser::resource_table;
use veryl_parser::text_table::{self, TextInfo};
use veryl_parser::veryl_token::{Token, TokenSource};
#[test]
fn labels_on_one_line_share_a_source_excerpt() {
let text = "before\na = b; b = c;\nafter\n";
let path = resource_table::insert_path(Path::new("shared_excerpt.veryl"));
let text_id = text_table::set_current_text(TextInfo {
text: text.into(),
path,
});
let source = TokenSource::File {
path,
text: text_id,
};
let primary = TokenRange::from(Token::new("before", 1, 1, 6, 0, source));
let first = TokenRange::from(Token::new("a = b;", 2, 1, 6, 7, source));
let second = TokenRange::from(Token::new("b = c;", 2, 8, 6, 14, source));
let (input, spans) = source_with_ordered_context(&primary, &[first, second]);
assert_eq!(input.sources.len(), 2);
assert_eq!(input.read_span(&spans[0], 0, 0).unwrap().data(), b"a = b;");
assert_eq!(input.read_span(&spans[1], 0, 0).unwrap().data(), b"b = c;");
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CachedSeverity {
Advice,
Warning,
Error,
}
impl From<Severity> for CachedSeverity {
fn from(value: Severity) -> Self {
match value {
Severity::Advice => CachedSeverity::Advice,
Severity::Warning => CachedSeverity::Warning,
Severity::Error => CachedSeverity::Error,
}
}
}
impl From<CachedSeverity> for Severity {
fn from(value: CachedSeverity) -> Self {
match value {
CachedSeverity::Advice => Severity::Advice,
CachedSeverity::Warning => Severity::Warning,
CachedSeverity::Error => Severity::Error,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CachedDiagnostic {
severity: Option<CachedSeverity>,
code: Option<String>,
url: Option<String>,
help: Option<String>,
message: String,
sources: MultiSources,
labels: Vec<(Option<String>, usize, usize)>,
token_path: Option<String>,
}
impl CachedDiagnostic {
pub fn from_error(error: &AnalyzerError) -> Self {
let labels = error
.labels()
.map(|labels| {
labels
.map(|x| (x.label().map(|s| s.to_string()), x.offset(), x.len()))
.collect()
})
.unwrap_or_default();
let token_path = error
.token_source()
.get_path()
.and_then(veryl_parser::resource_table::get_path_value)
.map(|x| x.to_string_lossy().to_string());
CachedDiagnostic {
severity: error.severity().map(CachedSeverity::from),
code: error.code().map(|x| x.to_string()),
url: error.url().map(|x| x.to_string()),
help: error.help().map(|x| x.to_string()),
message: error.to_string(),
sources: error.input_sources().clone(),
labels,
token_path,
}
}
pub fn is_error(&self) -> bool {
matches!(self.severity, Some(CachedSeverity::Error) | None)
}
pub fn token_path(&self) -> Option<&str> {
self.token_path.as_deref()
}
}
impl fmt::Display for CachedDiagnostic {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl std::error::Error for CachedDiagnostic {}
impl Diagnostic for CachedDiagnostic {
fn severity(&self) -> Option<Severity> {
self.severity.map(Severity::from)
}
fn code(&self) -> Option<Box<dyn fmt::Display + '_>> {
self.code
.as_ref()
.map(|x| Box::new(x.clone()) as Box<dyn fmt::Display>)
}
fn url(&self) -> Option<Box<dyn fmt::Display + '_>> {
self.url
.as_ref()
.map(|x| Box::new(x.clone()) as Box<dyn fmt::Display>)
}
fn help(&self) -> Option<Box<dyn fmt::Display + '_>> {
self.help
.as_ref()
.map(|x| Box::new(x.clone()) as Box<dyn fmt::Display>)
}
fn source_code(&self) -> Option<&dyn miette::SourceCode> {
Some(&self.sources)
}
fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
let labels = self.labels.clone();
Some(Box::new(labels.into_iter().map(|(label, offset, len)| {
miette::LabeledSpan::new(label, offset, len)
})))
}
}
impl AnalyzerError {
pub fn is_error(&self) -> bool {
matches!(self.severity(), Some(Severity::Error) | None)
}
pub fn input_sources(&self) -> &MultiSources {
match self {
AnalyzerError::AmbiguousElsif { input, .. } => input,
AnalyzerError::AmbiguousIdentifier { input, .. } => input,
AnalyzerError::AnonymousIdentifierUsage { input, .. } => input,
AnalyzerError::CallNonFunction { input, .. } => input,
AnalyzerError::SideEffectFunctionCallInAlwaysFf { input, .. } => input,
AnalyzerError::FunctionOutputInAlwaysFf { input, .. } => input,
AnalyzerError::CombinationalLoop { input, .. } => input,
AnalyzerError::CombinationalLoopPositionOverflow { input, .. } => input,
AnalyzerError::CyclicTypeDependency { input, .. } => input,
AnalyzerError::CyclicFileDependency { input, .. } => input,
AnalyzerError::DuplicateArgument { input, .. } => input,
AnalyzerError::DuplicatedIdentifier { input, .. } => input,
AnalyzerError::DuplicateEnumVariant { input, .. } => input,
AnalyzerError::ExceedLimit { input, .. } => input,
AnalyzerError::FixedTypeWithSignedModifier { input, .. } => input,
AnalyzerError::ForLoopOverflow { input, .. } => input,
AnalyzerError::GenericInferenceFailed { input, .. } => input,
AnalyzerError::ImplicitClockConversion { input, .. } => input,
AnalyzerError::IncludeFailure { input, .. } => input,
AnalyzerError::IncompatProto { input, .. } => input,
AnalyzerError::InfiniteRecursion { input, .. } => input,
AnalyzerError::InvalidAssignment { input, .. } => input,
AnalyzerError::InvalidCast { input, .. } => input,
AnalyzerError::InvalidClock { input, .. } => input,
AnalyzerError::InvalidClockAssignment { input, .. } => input,
AnalyzerError::InvalidClockDomain { input, .. } => input,
AnalyzerError::InvalidConnectOperand { input, .. } => input,
AnalyzerError::InvalidDirection { input, .. } => input,
AnalyzerError::InvalidEmbed { input, .. } => input,
AnalyzerError::InvalidEmbedIdentifier { input, .. } => input,
AnalyzerError::InvalidEnumVariant { input, .. } => input,
AnalyzerError::InvalidFactor { input, .. } => input,
AnalyzerError::InvalidForRange { input, .. } => input,
AnalyzerError::InvalidForStep { input, .. } => input,
AnalyzerError::InvalidIdentifier { input, .. } => input,
AnalyzerError::InvalidImport { input, .. } => input,
AnalyzerError::InvalidMixin { input, .. } => input,
AnalyzerError::InvalidLogicalOperand { input, .. } => input,
AnalyzerError::InvalidLsb { input, .. } => input,
AnalyzerError::InvalidModifier { input, .. } => input,
AnalyzerError::InvalidModportItem { input, .. } => input,
AnalyzerError::InvalidMsb { input, .. } => input,
AnalyzerError::InvalidNumberCharacter { input, .. } => input,
AnalyzerError::InvalidOperand { input, .. } => input,
AnalyzerError::InvalidPortDefaultValue { input, .. } => input,
AnalyzerError::InvalidRange { input, .. } => input,
AnalyzerError::InvalidRangeAssign { input, .. } => input,
AnalyzerError::InvalidReset { input, .. } => input,
AnalyzerError::InvalidSelect { input, .. } => input,
AnalyzerError::InvalidSizeType { input, .. } => input,
AnalyzerError::InvalidStatement { input, .. } => input,
AnalyzerError::InvalidInitialAssign { input, .. } => input,
AnalyzerError::InvalidTbUsage { input, .. } => input,
AnalyzerError::InvalidTest { input, .. } => input,
AnalyzerError::InvalidTypeDeclaration { input, .. } => input,
AnalyzerError::InvalidUnsizedLiteral { input, .. } => input,
AnalyzerError::InvalidWavedrom { input, .. } => input,
AnalyzerError::InvisibleIndentifier { input, .. } => input,
AnalyzerError::LastItemWithDefine { input, .. } => input,
AnalyzerError::LastItemWithDefineInModport { input, .. } => input,
AnalyzerError::MemberAccessOnArray { input, .. } => input,
AnalyzerError::MismatchAssignment { input, .. } => input,
AnalyzerError::MismatchAttributeArgs { input, .. } => input,
AnalyzerError::MismatchClockDomain { input, .. } => input,
AnalyzerError::MismatchFunctionArg { input, .. } => input,
AnalyzerError::MismatchFunctionArity { input, .. } => input,
AnalyzerError::MismatchGenericsArity { input, .. } => input,
AnalyzerError::MismatchType { input, .. } => input,
AnalyzerError::MissingClockDomain { input, .. } => input,
AnalyzerError::MissingClockSignal { input, .. } => input,
AnalyzerError::MissingDefaultArgument { input, .. } => input,
AnalyzerError::MissingIfReset { input, .. } => input,
AnalyzerError::MissingPort { input, .. } => input,
AnalyzerError::MissingResetSignal { input, .. } => input,
AnalyzerError::MissingResetStatement { input, .. } => input,
AnalyzerError::MissingTbPort { input, .. } => input,
AnalyzerError::MissingTri { input, .. } => input,
AnalyzerError::MixedFunctionArgument { input, .. } => input,
AnalyzerError::MixedStructUnionMember { input, .. } => input,
AnalyzerError::MultipleAssignment { input, .. } => input,
AnalyzerError::MultipleDefault { input, .. } => input,
AnalyzerError::NonConstantSelectWidth { input, .. } => input,
AnalyzerError::NonPositiveValue { input, .. } => input,
AnalyzerError::NonPortableDependency { input, .. } => input,
AnalyzerError::PrivateMember { input, .. } => input,
AnalyzerError::PrivateNamespace { input, .. } => input,
AnalyzerError::ReferringBeforeDefinition { input, .. } => input,
AnalyzerError::ReservedIdentifier { input, .. } => input,
AnalyzerError::SvKeywordUsage { input, .. } => input,
AnalyzerError::SvWithImplicitReset { input, .. } => input,
AnalyzerError::TooLargeEnumVariant { input, .. } => input,
AnalyzerError::TooLargeNumber { input, .. } => input,
AnalyzerError::TooMuchEnumVariant { input, .. } => input,
AnalyzerError::TypeInferenceConflict { input, .. } => input,
AnalyzerError::TypeInferenceNotSupported { input, .. } => input,
AnalyzerError::UnassignableOutput { input, .. } => input,
AnalyzerError::UnassignVariable { input, .. } => input,
AnalyzerError::UncoveredBranch { input, .. } => input,
AnalyzerError::UndefinedIdentifier { input, .. } => input,
AnalyzerError::UnenclosedInnerIfExpression { input, .. } => input,
AnalyzerError::UnevaluableValue { input, .. } => input,
AnalyzerError::UnexpandableModport { input, .. } => input,
AnalyzerError::UnknownAttribute { input, .. } => input,
AnalyzerError::UnknownEmbedLang { input, .. } => input,
AnalyzerError::UnknownEmbedWay { input, .. } => input,
AnalyzerError::UnknownIncludeWay { input, .. } => input,
AnalyzerError::UnknownMember { input, .. } => input,
AnalyzerError::UnknownMsb { input, .. } => input,
AnalyzerError::UnknownParam { input, .. } => input,
AnalyzerError::UnknownPort { input, .. } => input,
AnalyzerError::UnknownTbPort { input, .. } => input,
AnalyzerError::ComponentInterfaceMismatch { input, .. } => input,
AnalyzerError::UnknownUnsafe { input, .. } => input,
AnalyzerError::UnresolvableGenericExpression { input, .. } => input,
AnalyzerError::UnsignedArithShift { input, .. } => input,
AnalyzerError::UnusedReturn { input, .. } => input,
AnalyzerError::UnusedVariable { input, .. } => input,
AnalyzerError::WrongSeparator { input, .. } => input,
AnalyzerError::ZeroWidthNumber { input, .. } => input,
}
}
pub fn token_source(&self) -> TokenSource {
match self {
AnalyzerError::AmbiguousElsif { token_source, .. } => *token_source,
AnalyzerError::AmbiguousIdentifier { token_source, .. } => *token_source,
AnalyzerError::AnonymousIdentifierUsage { token_source, .. } => *token_source,
AnalyzerError::CallNonFunction { token_source, .. } => *token_source,
AnalyzerError::SideEffectFunctionCallInAlwaysFf { token_source, .. } => *token_source,
AnalyzerError::FunctionOutputInAlwaysFf { token_source, .. } => *token_source,
AnalyzerError::CombinationalLoop { token_source, .. } => *token_source,
AnalyzerError::CombinationalLoopPositionOverflow { token_source, .. } => *token_source,
AnalyzerError::CyclicTypeDependency { token_source, .. } => *token_source,
AnalyzerError::CyclicFileDependency { token_source, .. } => *token_source,
AnalyzerError::DuplicateArgument { token_source, .. } => *token_source,
AnalyzerError::DuplicateEnumVariant { token_source, .. } => *token_source,
AnalyzerError::DuplicatedIdentifier { token_source, .. } => *token_source,
AnalyzerError::ExceedLimit { token_source, .. } => *token_source,
AnalyzerError::FixedTypeWithSignedModifier { token_source, .. } => *token_source,
AnalyzerError::ForLoopOverflow { token_source, .. } => *token_source,
AnalyzerError::IncludeFailure { token_source, .. } => *token_source,
AnalyzerError::IncompatProto { token_source, .. } => *token_source,
AnalyzerError::InfiniteRecursion { token_source, .. } => *token_source,
AnalyzerError::InvalidAssignment { token_source, .. } => *token_source,
AnalyzerError::InvalidCast { token_source, .. } => *token_source,
AnalyzerError::InvalidClock { token_source, .. } => *token_source,
AnalyzerError::InvalidClockDomain { token_source, .. } => *token_source,
AnalyzerError::InvalidConnectOperand { token_source, .. } => *token_source,
AnalyzerError::InvalidDirection { token_source, .. } => *token_source,
AnalyzerError::InvalidEmbed { token_source, .. } => *token_source,
AnalyzerError::InvalidEmbedIdentifier { token_source, .. } => *token_source,
AnalyzerError::InvalidEnumVariant { token_source, .. } => *token_source,
AnalyzerError::InvalidFactor { token_source, .. } => *token_source,
AnalyzerError::InvalidIdentifier { token_source, .. } => *token_source,
AnalyzerError::InvalidImport { token_source, .. } => *token_source,
AnalyzerError::InvalidMixin { token_source, .. } => *token_source,
AnalyzerError::InvalidUnsizedLiteral { token_source, .. } => *token_source,
AnalyzerError::InvalidLogicalOperand { token_source, .. } => *token_source,
AnalyzerError::UnsignedArithShift { token_source, .. } => *token_source,
AnalyzerError::InvalidLsb { token_source, .. } => *token_source,
AnalyzerError::InvalidModifier { token_source, .. } => *token_source,
AnalyzerError::InvalidModportItem { token_source, .. } => *token_source,
AnalyzerError::InvalidMsb { token_source, .. } => *token_source,
AnalyzerError::InvalidNumberCharacter { token_source, .. } => *token_source,
AnalyzerError::InvalidOperand { token_source, .. } => *token_source,
AnalyzerError::InvalidPortDefaultValue { token_source, .. } => *token_source,
AnalyzerError::InvalidRange { token_source, .. } => *token_source,
AnalyzerError::InvalidReset { token_source, .. } => *token_source,
AnalyzerError::InvalidSelect { token_source, .. } => *token_source,
AnalyzerError::InvalidSizeType { token_source, .. } => *token_source,
AnalyzerError::InvalidRangeAssign { token_source, .. } => *token_source,
AnalyzerError::NonConstantSelectWidth { token_source, .. } => *token_source,
AnalyzerError::InvalidStatement { token_source, .. } => *token_source,
AnalyzerError::InvalidInitialAssign { token_source, .. } => *token_source,
AnalyzerError::InvalidForRange { token_source, .. } => *token_source,
AnalyzerError::InvalidForStep { token_source, .. } => *token_source,
AnalyzerError::InvalidTbUsage { token_source, .. } => *token_source,
AnalyzerError::MissingTbPort { token_source, .. } => *token_source,
AnalyzerError::UnknownTbPort { token_source, .. } => *token_source,
AnalyzerError::ComponentInterfaceMismatch { token_source, .. } => *token_source,
AnalyzerError::InvalidTest { token_source, .. } => *token_source,
AnalyzerError::InvalidTypeDeclaration { token_source, .. } => *token_source,
AnalyzerError::InvisibleIndentifier { token_source, .. } => *token_source,
AnalyzerError::LastItemWithDefine { token_source, .. } => *token_source,
AnalyzerError::LastItemWithDefineInModport { token_source, .. } => *token_source,
AnalyzerError::MemberAccessOnArray { token_source, .. } => *token_source,
AnalyzerError::MismatchAssignment { token_source, .. } => *token_source,
AnalyzerError::ImplicitClockConversion { token_source, .. } => *token_source,
AnalyzerError::InvalidClockAssignment { token_source, .. } => *token_source,
AnalyzerError::NonPositiveValue { token_source, .. } => *token_source,
AnalyzerError::NonPortableDependency { token_source, .. } => *token_source,
AnalyzerError::MismatchAttributeArgs { token_source, .. } => *token_source,
AnalyzerError::MismatchClockDomain { token_source, .. } => *token_source,
AnalyzerError::MismatchFunctionArg { token_source, .. } => *token_source,
AnalyzerError::MismatchFunctionArity { token_source, .. } => *token_source,
AnalyzerError::MismatchGenericsArity { token_source, .. } => *token_source,
AnalyzerError::MismatchType { token_source, .. } => *token_source,
AnalyzerError::MissingClockDomain { token_source, .. } => *token_source,
AnalyzerError::MissingClockSignal { token_source, .. } => *token_source,
AnalyzerError::MissingDefaultArgument { token_source, .. } => *token_source,
AnalyzerError::MissingIfReset { token_source, .. } => *token_source,
AnalyzerError::GenericInferenceFailed { token_source, .. } => *token_source,
AnalyzerError::TypeInferenceConflict { token_source, .. } => *token_source,
AnalyzerError::TypeInferenceNotSupported { token_source, .. } => *token_source,
AnalyzerError::MissingPort { token_source, .. } => *token_source,
AnalyzerError::MissingResetSignal { token_source, .. } => *token_source,
AnalyzerError::MissingResetStatement { token_source, .. } => *token_source,
AnalyzerError::MissingTri { token_source, .. } => *token_source,
AnalyzerError::MixedFunctionArgument { token_source, .. } => *token_source,
AnalyzerError::MixedStructUnionMember { token_source, .. } => *token_source,
AnalyzerError::MultipleAssignment { token_source, .. } => *token_source,
AnalyzerError::MultipleDefault { token_source, .. } => *token_source,
AnalyzerError::PrivateMember { token_source, .. } => *token_source,
AnalyzerError::PrivateNamespace { token_source, .. } => *token_source,
AnalyzerError::ReferringBeforeDefinition { token_source, .. } => *token_source,
AnalyzerError::ReservedIdentifier { token_source, .. } => *token_source,
AnalyzerError::SvKeywordUsage { token_source, .. } => *token_source,
AnalyzerError::SvWithImplicitReset { token_source, .. } => *token_source,
AnalyzerError::TooLargeEnumVariant { token_source, .. } => *token_source,
AnalyzerError::TooLargeNumber { token_source, .. } => *token_source,
AnalyzerError::ZeroWidthNumber { token_source, .. } => *token_source,
AnalyzerError::TooMuchEnumVariant { token_source, .. } => *token_source,
AnalyzerError::UnassignVariable { token_source, .. } => *token_source,
AnalyzerError::UnassignableOutput { token_source, .. } => *token_source,
AnalyzerError::UncoveredBranch { token_source, .. } => *token_source,
AnalyzerError::UndefinedIdentifier { token_source, .. } => *token_source,
AnalyzerError::UnenclosedInnerIfExpression { token_source, .. } => *token_source,
AnalyzerError::UnevaluableValue { token_source, .. } => *token_source,
AnalyzerError::UnexpandableModport { token_source, .. } => *token_source,
AnalyzerError::UnknownAttribute { token_source, .. } => *token_source,
AnalyzerError::UnknownEmbedLang { token_source, .. } => *token_source,
AnalyzerError::UnknownEmbedWay { token_source, .. } => *token_source,
AnalyzerError::UnknownIncludeWay { token_source, .. } => *token_source,
AnalyzerError::UnknownMember { token_source, .. } => *token_source,
AnalyzerError::UnknownMsb { token_source, .. } => *token_source,
AnalyzerError::UnknownParam { token_source, .. } => *token_source,
AnalyzerError::UnknownPort { token_source, .. } => *token_source,
AnalyzerError::UnknownUnsafe { token_source, .. } => *token_source,
AnalyzerError::UnresolvableGenericExpression { token_source, .. } => *token_source,
AnalyzerError::UnusedReturn { token_source, .. } => *token_source,
AnalyzerError::UnusedVariable { token_source, .. } => *token_source,
AnalyzerError::WrongSeparator { token_source, .. } => *token_source,
AnalyzerError::InvalidWavedrom { token_source, .. } => *token_source,
}
}
pub fn ambiguous_elsif(cause: &str, token: &TokenRange) -> Self {
AnalyzerError::AmbiguousElsif {
cause: cause.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn ambiguous_identifier(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::AmbiguousIdentifier {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn anonymous_identifier_usage(token: &TokenRange) -> Self {
AnalyzerError::AnonymousIdentifierUsage {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn call_non_function(identifier: &str, kind: &str, token: &TokenRange) -> Self {
AnalyzerError::CallNonFunction {
identifier: identifier.to_string(),
kind: kind.to_string(),
input: source(token),
error_location: token.into(),
inst_context: vec![],
token_source: token.source(),
}
}
pub fn side_effect_function_call_in_always_ff(
identifier: &str,
token: &TokenRange,
definition: &TokenRange,
calls: &[TokenRange],
writes: &[TokenRange],
) -> Self {
let (input, call_stack, external_writes, function_definition) = if writes.is_empty() {
let (input, function_definition) =
source_with_context(token, std::slice::from_ref(definition));
(input, vec![], vec![], function_definition)
} else {
let mut context = writes.iter().rev().copied().collect::<Vec<_>>();
context.extend(calls.iter().rev().copied());
let (input, context_spans) = source_with_context(token, &context);
let (call_stack, external_writes) = context_spans.split_at(calls.len());
(input, call_stack.to_vec(), external_writes.to_vec(), vec![])
};
AnalyzerError::SideEffectFunctionCallInAlwaysFf {
identifier: identifier.to_string(),
input,
error_location: token.into(),
call_stack,
external_writes,
function_definition,
token_source: token.source(),
}
}
pub fn function_output_in_always_ff(
function: &str,
output: &str,
destination: &str,
token: &TokenRange,
declaration: Option<&TokenRange>,
) -> Self {
let declarations = declaration.into_iter().copied().collect::<Vec<_>>();
let (input, output_declaration) = source_with_context(token, &declarations);
AnalyzerError::FunctionOutputInAlwaysFf {
function: function.to_string(),
output: output.to_string(),
destination: destination.to_string(),
input,
error_location: token.into(),
output_declaration,
token_source: token.source(),
}
}
pub fn combinational_loop(
identifier: &str,
cycle: &str,
token: &TokenRange,
participants: &[TokenRange],
sites: &[TokenRange],
) -> Self {
let mut context = participants.to_vec();
context.extend_from_slice(sites);
let (input, context_spans) = source_with_ordered_context(token, &context);
let (loop_participants, dependency_sites) = context_spans.split_at(participants.len());
AnalyzerError::CombinationalLoop {
identifier: identifier.to_string(),
cycle: cycle.to_string(),
input,
error_location: token.into(),
loop_participants: loop_participants.to_vec(),
dependency_sites: dependency_sites.to_vec(),
token_source: token.source(),
}
}
pub fn combinational_loop_position_overflow(token: &TokenRange) -> Self {
AnalyzerError::CombinationalLoopPositionOverflow {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn cyclic_type_dependency(start: &str, end: &str, token: &TokenRange) -> Self {
AnalyzerError::CyclicTypeDependency {
start: start.into(),
end: end.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn cyclic_file_dependency(start: &str, end: &str, token: &TokenRange) -> Self {
AnalyzerError::CyclicFileDependency {
start: start.into(),
end: end.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn duplicate_argument(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::DuplicateArgument {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn duplicate_enum_variant(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::DuplicateEnumVariant {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn duplicated_identifier(
identifier: &str,
kind: DuplicatedIdentifierKind,
token: &TokenRange,
) -> Self {
AnalyzerError::DuplicatedIdentifier {
identifier: identifier.to_string(),
kind,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn exceed_limit(kind: ExceedLimitKind, value: usize, token: &TokenRange) -> Self {
AnalyzerError::ExceedLimit {
kind,
value,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn fixed_type_with_signed_modifier(token: &TokenRange) -> Self {
AnalyzerError::FixedTypeWithSignedModifier {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn include_failure(name: &str, cause: &str, token: &TokenRange) -> Self {
AnalyzerError::IncludeFailure {
name: name.to_string(),
cause: cause.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn incompat_proto(
identifier: &str,
proto: &str,
cause: IncompatProtoKind,
token: &TokenRange,
) -> Self {
AnalyzerError::IncompatProto {
identifier: identifier.into(),
proto: proto.into(),
cause,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn infinite_recursion(token: &TokenRange) -> Self {
AnalyzerError::InfiniteRecursion {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_assignment(identifier: &str, kind: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidAssignment {
identifier: identifier.into(),
kind: kind.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_cast(from: &str, to: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidCast {
from: from.into(),
to: to.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_clock(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidClock {
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_clock_domain(token: &TokenRange) -> Self {
AnalyzerError::InvalidClockDomain {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_connect_operand(
identifier: &str,
reason: InvalidConnectOperandKind,
token: &TokenRange,
) -> Self {
AnalyzerError::InvalidConnectOperand {
identifier: identifier.into(),
reason,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_direction(kind: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidDirection {
kind: kind.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_embed(way: &str, lang: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidEmbed {
way: way.to_string(),
lang: lang.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_embed_identifier(token: &TokenRange) -> Self {
AnalyzerError::InvalidEmbedIdentifier {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_enum_variant(identifier: &str, encoding: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidEnumVariant {
identifier: identifier.to_string(),
encoding: encoding.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_factor(
identifier: Option<&str>,
kind: &str,
token: &TokenRange,
inst_context: &[TokenRange],
) -> Self {
let (input, inst_context) = source_with_context(token, inst_context);
AnalyzerError::InvalidFactor {
identifier: identifier.map(|x| x.to_string()),
kind: kind.to_string(),
input,
error_location: token.into(),
inst_context,
token_source: token.source(),
}
}
pub fn invalid_identifier(identifier: &str, rule: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidIdentifier {
identifier: identifier.to_string(),
rule: rule.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_import(token: &TokenRange) -> Self {
AnalyzerError::InvalidImport {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_mixin(identifier: &str, reason: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidMixin {
identifier: identifier.to_string(),
reason: reason.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_unsized_literal(token: &TokenRange) -> Self {
AnalyzerError::InvalidUnsizedLiteral {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_logical_operand(op: bool, token: &TokenRange) -> Self {
let kind = if op {
"Operand of logical operator"
} else {
"Conditional expression"
};
AnalyzerError::InvalidLogicalOperand {
kind: kind.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unsigned_arith_shift(token: &TokenRange) -> Self {
AnalyzerError::UnsignedArithShift {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_lsb(token: &TokenRange) -> Self {
AnalyzerError::InvalidLsb {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_modifier(kind: &str, reason: InvalidModifierKind, token: &TokenRange) -> Self {
AnalyzerError::InvalidModifier {
kind: kind.to_string(),
reason,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_modport_item(
kind: InvalidModportItemKind,
identifier: &str,
token: &TokenRange,
) -> Self {
AnalyzerError::InvalidModportItem {
kind,
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_msb(token: &TokenRange) -> Self {
AnalyzerError::InvalidMsb {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_number_character(cause: char, kind: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidNumberCharacter {
cause,
kind: kind.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_operand(kind: &str, op: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidOperand {
kind: kind.to_string(),
op: op.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_port_default_value(
kind: InvalidPortDefaultValueKind,
token: &TokenRange,
) -> Self {
AnalyzerError::InvalidPortDefaultValue {
kind,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_range(cause: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidRange {
cause: cause.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_reset(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidReset {
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_select(
kind: &InvalidSelectKind,
token: &TokenRange,
inst_context: &[TokenRange],
) -> Self {
let (input, inst_context) = source_with_context(token, inst_context);
AnalyzerError::InvalidSelect {
kind: kind.clone(),
input,
error_location: token.into(),
inst_context,
token_source: token.source(),
}
}
pub fn invalid_size_type(token: &TokenRange) -> Self {
AnalyzerError::InvalidSizeType {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_range_assign(token: &TokenRange) -> Self {
AnalyzerError::InvalidRangeAssign {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn non_constant_select_width(token: &TokenRange) -> Self {
AnalyzerError::NonConstantSelectWidth {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_statement(kind: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidStatement {
kind: kind.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_initial_assign(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidInitialAssign {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn non_portable_dependency(item: &str, project: &str, token: &TokenRange) -> Self {
AnalyzerError::NonPortableDependency {
item: item.to_string(),
project: project.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_for_range(kind: InvalidForRangeKind, token: &TokenRange) -> Self {
AnalyzerError::InvalidForRange {
help: kind.help().to_string(),
kind,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_for_step(cause: InvalidForStepKind, token: &TokenRange) -> Self {
AnalyzerError::InvalidForStep {
cause,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn for_loop_overflow(token: &TokenRange) -> Self {
AnalyzerError::ForLoopOverflow {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_test(cause: InvalidTestKind, token: &TokenRange) -> Self {
AnalyzerError::InvalidTest {
cause,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_tb_usage(token: &TokenRange) -> Self {
AnalyzerError::InvalidTbUsage {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_tb_port(name: &str, port: &str, token: &TokenRange) -> Self {
AnalyzerError::MissingTbPort {
name: name.into(),
port: port.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_tb_port(name: &str, port: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownTbPort {
name: name.into(),
port: port.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn component_interface_mismatch(
kind: ComponentInterfaceMismatchKind,
component: Option<StrId>,
token: &TokenRange,
) -> Self {
let mut help = "check the component's interface manifest".to_string();
if component.is_some_and(|x| x.to_string().contains("::")) {
help.push_str(
"; the interface comes from the locked dependency version — if the dependency was updated, run `veryl update` (and the dependency may need republishing)",
);
}
AnalyzerError::ComponentInterfaceMismatch {
kind,
help,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_type_declaration(kind: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidTypeDeclaration {
kind: kind.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invisible_identifier(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::InvisibleIndentifier {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn last_item_with_define(token: &TokenRange) -> Self {
AnalyzerError::LastItemWithDefine {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn last_item_with_define_in_modport(
identifier: &str,
modport: &str,
token: &TokenRange,
member_source: &TokenRange,
) -> Self {
let (input, member_source) = source_with_context(token, &[*member_source]);
AnalyzerError::LastItemWithDefineInModport {
identifier: identifier.to_string(),
modport: modport.to_string(),
input,
error_location: token.into(),
member_source,
token_source: token.source(),
}
}
pub fn member_access_on_array(
name: &str,
member: &str,
array_dims: usize,
token: &TokenRange,
) -> Self {
AnalyzerError::MemberAccessOnArray {
name: name.to_string(),
member: member.to_string(),
array_dims,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mismatch_assignment(
src: &str,
dst: &str,
token: &TokenRange,
inst_context: &[TokenRange],
) -> Self {
let (input, inst_context) = source_with_context(token, inst_context);
AnalyzerError::MismatchAssignment {
src: src.to_string(),
dst: dst.to_string(),
input,
error_location: token.into(),
inst_context,
token_source: token.source(),
}
}
pub fn implicit_clock_conversion(
src: &str,
dst: &str,
token: &TokenRange,
inst_context: &[TokenRange],
) -> Self {
let (input, inst_context) = source_with_context(token, inst_context);
AnalyzerError::ImplicitClockConversion {
src: src.to_string(),
dst: dst.to_string(),
input,
error_location: token.into(),
inst_context,
token_source: token.source(),
}
}
pub fn invalid_clock_assignment(dst: &str, token: &TokenRange) -> Self {
AnalyzerError::InvalidClockAssignment {
dst: dst.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn non_positive_value(value: &str, typ: &str, token: &TokenRange) -> Self {
AnalyzerError::NonPositiveValue {
value: value.to_string(),
typ: typ.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mismatch_attribute_args(name: &str, expected: String, token: &TokenRange) -> Self {
AnalyzerError::MismatchAttributeArgs {
name: name.to_string(),
expected,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mismatch_clock_domain(
clock_domain: &str,
other_domain: &str,
token: &TokenRange,
other_token: &TokenRange,
) -> Self {
AnalyzerError::MismatchClockDomain {
clock_domain: clock_domain.to_string(),
other_domain: other_domain.to_string(),
input: source(token),
error_location: token.into(),
other_location: other_token.into(),
token_source: token.source(),
}
}
pub fn mismatch_function_arg(name: &str, src: &str, token: &TokenRange) -> Self {
AnalyzerError::MismatchFunctionArg {
name: name.to_string(),
src: src.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mismatch_function_arity(
name: &str,
arity: usize,
args: usize,
token: &TokenRange,
) -> Self {
AnalyzerError::MismatchFunctionArity {
name: name.to_string(),
arity,
args,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mismatch_generics_arity(
name: &str,
arity: usize,
args: usize,
token: &TokenRange,
) -> Self {
AnalyzerError::MismatchGenericsArity {
name: name.to_string(),
arity,
args,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mismatch_type(kind: MismatchTypeKind, token: &TokenRange) -> Self {
AnalyzerError::MismatchType {
kind,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_clock_domain(token: &TokenRange) -> Self {
AnalyzerError::MissingClockDomain {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_clock_signal(token: &TokenRange) -> Self {
AnalyzerError::MissingClockSignal {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_default_argument(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::MissingDefaultArgument {
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn generic_inference_failed(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::GenericInferenceFailed {
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn type_inference_conflict(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::TypeInferenceConflict {
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn type_inference_not_supported(token: &TokenRange) -> Self {
AnalyzerError::TypeInferenceNotSupported {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_if_reset(token: &TokenRange) -> Self {
AnalyzerError::MissingIfReset {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_port(name: &str, port: &str, token: &TokenRange) -> Self {
AnalyzerError::MissingPort {
name: name.to_string(),
port: port.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_reset_signal(token: &TokenRange) -> Self {
AnalyzerError::MissingResetSignal {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn missing_reset_statement(name: &str, token: &TokenRange, tokens: &[TokenRange]) -> Self {
AnalyzerError::MissingResetStatement {
name: name.to_string(),
input: source(token),
error_locations: tokens.iter().map(|x| x.into()).collect(),
token_source: token.source(),
}
}
pub fn missing_tri(token: &TokenRange) -> Self {
AnalyzerError::MissingTri {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mixed_function_argument(token: &TokenRange) -> Self {
AnalyzerError::MixedFunctionArgument {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn mixed_struct_union_member(token: &TokenRange) -> Self {
AnalyzerError::MixedStructUnionMember {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn multiple_assignment(
identifier: &str,
token: &TokenRange,
assigned: &[TokenRange],
) -> Self {
AnalyzerError::MultipleAssignment {
identifier: identifier.to_string(),
input: source(token),
error_locations: assigned.iter().map(|x| x.into()).collect(),
token_source: token.source(),
}
}
pub fn multiple_default(
kind: MultipleDefaultKind,
identifier: &str,
token: &TokenRange,
) -> Self {
AnalyzerError::MultipleDefault {
kind,
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn private_member(name: &str, token: &TokenRange) -> Self {
AnalyzerError::PrivateMember {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn private_namespace(name: &str, token: &TokenRange) -> Self {
AnalyzerError::PrivateNamespace {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn referring_before_definition(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::ReferringBeforeDefinition {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn reserved_identifier(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::ReservedIdentifier {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn sv_keyword_usage(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::SvKeywordUsage {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn sv_with_implicit_reset(token: &TokenRange) -> Self {
AnalyzerError::SvWithImplicitReset {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn too_large_enum_variant(
identifier: &str,
value: isize,
width: usize,
token: &TokenRange,
) -> Self {
AnalyzerError::TooLargeEnumVariant {
identifier: identifier.to_string(),
value,
width,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn too_large_number(width: usize, token: &TokenRange) -> Self {
AnalyzerError::TooLargeNumber {
width,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn zero_width_number(token: &TokenRange) -> Self {
AnalyzerError::ZeroWidthNumber {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn too_much_enum_variant(
identifier: &str,
number: usize,
width: usize,
token: &TokenRange,
) -> Self {
AnalyzerError::TooMuchEnumVariant {
identifier: identifier.to_string(),
number,
width,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unassign_variable(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::UnassignVariable {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unassignable_output(token: &TokenRange) -> Self {
AnalyzerError::UnassignableOutput {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn uncovered_branch(identifier: &str, token: &TokenRange, covered: &[TokenRange]) -> Self {
AnalyzerError::UncoveredBranch {
identifier: identifier.to_string(),
input: source(token),
error_locations: covered.iter().map(|x| x.into()).collect(),
token_source: token.source(),
}
}
pub fn undefined_identifier(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::UndefinedIdentifier {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unenclosed_inner_if_expression(token: &TokenRange) -> Self {
AnalyzerError::UnenclosedInnerIfExpression {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unevaluable_value(kind: UnevaluableValueKind, token: &TokenRange) -> Self {
AnalyzerError::UnevaluableValue {
kind,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unexpandable_modport(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::UnexpandableModport {
identifier: identifier.into(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_attribute(name: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownAttribute {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_embed_lang(name: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownEmbedLang {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_embed_way(name: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownEmbedWay {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_include_way(name: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownIncludeWay {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_member(name: &str, member: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownMember {
name: name.to_string(),
member: member.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_msb(token: &TokenRange) -> Self {
AnalyzerError::UnknownMsb {
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_param(name: &str, param: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownParam {
name: name.to_string(),
param: param.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_port(name: &str, port: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownPort {
name: name.to_string(),
port: port.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unknown_unsafe(name: &str, token: &TokenRange) -> Self {
AnalyzerError::UnknownUnsafe {
name: name.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unresolvable_generic_expression(
identifier: &str,
token: &TokenRange,
definition_token: &TokenRange,
) -> Self {
AnalyzerError::UnresolvableGenericExpression {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
definition_location: definition_token.into(),
token_source: token.source(),
}
}
pub fn unused_return(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::UnusedReturn {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn unused_variable(identifier: &str, token: &TokenRange) -> Self {
AnalyzerError::UnusedVariable {
identifier: identifier.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn invalid_wavedrom(cause: InvalidWavedromKind, token: &TokenRange) -> Self {
AnalyzerError::InvalidWavedrom {
cause,
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
pub fn wrong_seperator(separator: &str, token: &TokenRange) -> Self {
let valid_separator = if separator == "." { "::" } else { "." };
AnalyzerError::WrongSeparator {
separator: separator.to_string(),
valid_separator: valid_separator.to_string(),
input: source(token),
error_location: token.into(),
token_source: token.source(),
}
}
}
#[derive(Error, Debug, PartialEq, Eq)]
pub enum ComponentInterfaceMismatchKind {
#[error(
"the method returns {returned} bit(s) but the destination is {destination} bit(s) wide"
)]
MethodReturnWidth { returned: usize, destination: usize },
#[error(
"generic parameters require the component's interface manifest (build the component once, or commit its prebuilt wasm)"
)]
GenericParamsNeedManifest,
#[error(
"the component declares {declared} parameter(s), but {supplied} generic argument(s) are supplied"
)]
TooManyGenericArgs { declared: usize, supplied: usize },
#[error("required parameter `{param}` is not given")]
RequiredParamMissing { param: String },
#[error("this is a clocked component; declare it with `inst`, not `var`")]
ClockedNeedsInst,
#[error("the inst form takes parameters with `#()`, not generic arguments")]
InstFormUsesParen,
#[error("this is a method-only component; declare it with `var`, not `inst`")]
MethodOnlyNeedsVar,
#[error("the component declares no parameter named `{param}`")]
UnknownParam { param: String },
#[error("the component declares no port named `{port}`")]
UnknownPort { port: String },
#[error(
"port `{port}` is declared as an input but the modport connection only allows driving it"
)]
PortNotInput { port: String },
#[error("port `{port}` is declared as an output but the connection cannot be driven")]
PortNotDrivable { port: String },
#[error("port `{port}` is declared as a clock but the connected expression is not a clock")]
PortNotClock { port: String },
#[error("port `{port}` is declared as a reset but the connected expression is not a reset")]
PortNotReset { port: String },
#[error(
"the `{port}` connection is a clock but the component does not declare the port as a clock (a ClockPort field)"
)]
ClockPortUndeclared { port: String },
#[error(
"the `{port}` connection is a reset but the component does not declare the port as a reset (a ResetPort field)"
)]
ResetPortUndeclared { port: String },
#[error("{role} port `{port}` is not connected")]
RolePortUnconnected { role: String, port: String },
#[error("port `{port}` is not connected")]
PortUnconnected { port: String },
#[error("port `{port}` is connected more than once")]
PortMultiplyConnected { port: String },
#[error("port `{port}` has invalid direction `{dir}` in the component's manifest")]
InvalidPortDirection { port: String, dir: String },
#[error("the component declares no interface port named `{group}`")]
UnknownGroup { group: String },
#[error("the component's manifest is invalid: {reason}")]
InvalidManifest { reason: String },
#[error(
"port `{group}.{member}` is not connected — the interface connected to `{group}` has no member `{member}`"
)]
GroupMemberUnconnected { group: String, member: String },
#[error("interface port `{group}` is not connected")]
GroupUnconnected { group: String },
#[error("component method calls take the form `instance.method(...)`")]
MethodCallForm,
#[error("component methods take no generic arguments")]
MethodNoGenericArgs,
#[error("the component declares no method named `{method}`")]
UnknownMethod { method: String },
#[error("method `{method}` returns no value")]
MethodReturnsNoValue { method: String },
#[error(
"cannot resolve the declared width `{expr}` of {what} (unknown parameter or invalid expression)"
)]
UnresolvableWidth { expr: String, what: String },
#[error(
"method `{method}` declares a {declared}-bit return value, but the ABI supports at most {max} bits"
)]
MethodReturnTooWide {
method: String,
declared: u32,
max: u32,
},
#[error(
"interface port `{group}` is bound to interface `{expected}`, but a different interface is connected"
)]
InterfaceMismatch { group: String, expected: String },
#[error(
"interface port `{group}` is bound to modport `{expected}`, but modport `{connected}` is connected"
)]
ModportMismatch {
group: String,
expected: String,
connected: String,
},
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ExceedLimitKind {
EvaluateSize,
HierarchyDepth,
TotalInstance,
}
impl fmt::Display for ExceedLimitKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ExceedLimitKind::EvaluateSize => "evaluate size".fmt(f),
ExceedLimitKind::HierarchyDepth => "hierarchy depth".fmt(f),
ExceedLimitKind::TotalInstance => "total instance".fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IncompatProtoKind {
IncompatibleAlias(StrId),
IncompatibleFunction(StrId),
IncompatibleGenericParam(StrId),
IncompatibleMember(StrId),
IncompatibleModport(StrId),
IncompatibleParam(StrId),
IncompatiblePort(StrId),
IncompatibleType,
IncompatibleTypedef(StrId),
IncompatibleVar(StrId),
MissignMember(StrId),
MissingAlias(StrId),
MissingFunction(StrId),
MissingGenericParam(StrId),
MissingModport(StrId),
MissingParam(StrId),
MissingPort(StrId),
MissingType,
MissingTypedef(StrId),
MissingVar(StrId),
UnnecessaryGenericParam(StrId),
UnnecessaryMember(StrId),
UnnecessaryParam(StrId),
UnnecessaryPort(StrId),
UnnecessaryType,
}
impl fmt::Display for IncompatProtoKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IncompatProtoKind::IncompatibleAlias(x) => {
format!("alias \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::IncompatibleFunction(x) => {
format!("function \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::IncompatibleGenericParam(x) => {
format!("generic parameter \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::IncompatibleMember(x) => {
format!("member \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::IncompatibleModport(x) => {
format!("modport \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::IncompatibleParam(x) => {
format!("parameter \"{x}\" has incompatible type").fmt(f)
}
IncompatProtoKind::IncompatiblePort(x) => {
format!("port \"{x}\" has incompatible type").fmt(f)
}
IncompatProtoKind::IncompatibleType => "type specification is incompatible".fmt(f),
IncompatProtoKind::IncompatibleTypedef(x) => {
format!("type definition \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::IncompatibleVar(x) => {
format!("variable \"{x}\" is incompatible").fmt(f)
}
IncompatProtoKind::MissignMember(x) => format!("member \"{x}\" is missing").fmt(f),
IncompatProtoKind::MissingAlias(x) => format!("alias \"{x}\" is missing").fmt(f),
IncompatProtoKind::MissingFunction(x) => format!("function \"{x}\" is missing").fmt(f),
IncompatProtoKind::MissingGenericParam(x) => {
format!("generic parameter \"{x}\" is missing").fmt(f)
}
IncompatProtoKind::MissingModport(x) => format!("modport \"{x}\" is missing").fmt(f),
IncompatProtoKind::MissingParam(x) => format!("parameter \"{x}\" is missing").fmt(f),
IncompatProtoKind::MissingPort(x) => format!("port \"{x}\" is missing").fmt(f),
IncompatProtoKind::MissingType => "type specification is missing".fmt(f),
IncompatProtoKind::MissingTypedef(x) => {
format!("type definition \"{x}\" is missing").fmt(f)
}
IncompatProtoKind::MissingVar(x) => format!("variable \"{x}\" is missing").fmt(f),
IncompatProtoKind::UnnecessaryGenericParam(x) => {
format!("generic parameter \"{x}\" is unnecessary").fmt(f)
}
IncompatProtoKind::UnnecessaryMember(x) => {
format!("member \"{x}\" is unnecessary").fmt(f)
}
IncompatProtoKind::UnnecessaryParam(x) => {
format!("parameter \"{x}\" is unnecessary").fmt(f)
}
IncompatProtoKind::UnnecessaryPort(x) => format!("port \"{x}\" is unnecessary").fmt(f),
IncompatProtoKind::UnnecessaryType => "type specification is unnecessary".fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InvalidConnectOperandKind {
IncludeInout,
InstanceArray,
ModportArray,
UnemittableCast,
}
impl fmt::Display for InvalidConnectOperandKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidConnectOperandKind::IncludeInout => {
"modport including inout ports can't be used at here".fmt(f)
}
InvalidConnectOperandKind::InstanceArray => "it is an array interface instance".fmt(f),
InvalidConnectOperandKind::ModportArray => "it is an array modport".fmt(f),
InvalidConnectOperandKind::UnemittableCast => "modport including variables of which type is defined in the interface can't be used for a connect operand".fmt(f),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidWavedromKind {
InvalidJson(String),
MissingSignalArray,
UnknownWaveChar { signal: String, ch: char },
JavaScriptInTestBlock,
PipeSeparatorInTest { signal: String },
NoMatchingPorts,
}
impl fmt::Display for InvalidWavedromKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidWavedromKind::InvalidJson(e) => write!(f, "invalid WaveDrom JSON: {e}"),
InvalidWavedromKind::MissingSignalArray => {
write!(f, "WaveDrom JSON missing 'signal' array")
}
InvalidWavedromKind::UnknownWaveChar { signal, ch } => {
write!(
f,
"WaveDrom signal '{signal}' contains unknown wave character '{ch}'"
)
}
InvalidWavedromKind::JavaScriptInTestBlock => {
write!(
f,
"WaveDrom test blocks must use JSON, not JavaScript expressions"
)
}
InvalidWavedromKind::PipeSeparatorInTest { signal } => {
write!(
f,
"WaveDrom signal '{signal}' contains '|' separator (indeterminate timing, not testable)"
)
}
InvalidWavedromKind::NoMatchingPorts => {
write!(f, "WaveDrom test has no signals matching module ports")
}
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InvalidModifierKind {
NotTopModule,
NotClockReset,
}
impl fmt::Display for InvalidModifierKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidModifierKind::NotTopModule => "here is not the module top layer".fmt(f),
InvalidModifierKind::NotClockReset => {
"the given type is not a single bit clock nor a single bit reset".fmt(f)
}
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InvalidModportItemKind {
Function,
Variable,
}
impl fmt::Display for InvalidModportItemKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidModportItemKind::Function => "function".fmt(f),
InvalidModportItemKind::Variable => "variable".fmt(f),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidPortDefaultValueKind {
NotGlobal,
InFunction,
NonAnonymousInOutput,
InvalidDirection(String),
}
impl fmt::Display for InvalidPortDefaultValueKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidPortDefaultValueKind::NotGlobal => {
"port default value should be accessable globally".fmt(f)
}
InvalidPortDefaultValueKind::InFunction => {
"port default value in function is not supported".fmt(f)
}
InvalidPortDefaultValueKind::NonAnonymousInOutput => {
"Only '_' is supported for output default value".fmt(f)
}
InvalidPortDefaultValueKind::InvalidDirection(x) => {
format!("Port default value for {x} is not supported").fmt(f)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MismatchTypeKind {
SymbolKind {
name: String,
expected: String,
actual: String,
},
GenericArgument {
name: String,
expected: String,
actual: String,
},
ArrayDimension {
expected: usize,
actual: usize,
},
ConnectMultipleExpression,
NonStructType {
actual: String,
},
UnionConstructor,
}
impl fmt::Display for MismatchTypeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MismatchTypeKind::SymbolKind {
name,
expected,
actual,
} => {
write!(
f,
"\"{name}\" is expected to \"{expected}\", but it is \"{actual}\""
)
}
MismatchTypeKind::GenericArgument {
name,
expected,
actual,
} => {
write!(
f,
"\"{name}\" is expected to \"{expected}\", but it is \"{actual}\""
)
}
MismatchTypeKind::ArrayDimension { expected, actual } => {
write!(
f,
"array literal is expected to {expected} elements, but it has {actual} elements"
)
}
MismatchTypeKind::ConnectMultipleExpression => {
"connect requires a single expression, but multiple expressions are provided".fmt(f)
}
MismatchTypeKind::NonStructType { actual } => {
write!(
f,
"struct constructor is expected to \"struct\", but it is \"{actual}\""
)
}
MismatchTypeKind::UnionConstructor => {
"a union holds one member at a time, so it has no constructor; assign to a member instead".fmt(f)
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InvalidSelectKind {
WrongOrder { beg: usize, end: usize },
OutOfRange { beg: usize, end: usize, size: usize },
OutOfDimension { dim: usize, size: usize },
SelectAfterRange,
}
impl fmt::Display for InvalidSelectKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidSelectKind::WrongOrder { beg, end } => {
format!("wrong index order [{beg}:{end}]").fmt(f)
}
InvalidSelectKind::OutOfRange { beg, end, size } => {
if beg == end {
format!("out of range [{beg}] > {size}").fmt(f)
} else {
format!("out of range [{beg}:{end}] > {size}").fmt(f)
}
}
InvalidSelectKind::OutOfDimension { .. } => "out of dimension".fmt(f),
InvalidSelectKind::SelectAfterRange => "select after range is not allowed".fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InvalidForRangeKind {
BareExpression,
NegativeBound,
}
impl InvalidForRangeKind {
fn help(&self) -> &'static str {
match self {
InvalidForRangeKind::BareExpression => "use a range with `..` or `..=`, e.g. `0..N`",
InvalidForRangeKind::NegativeBound => {
"for-loop range bounds are elaborated as unsigned; rewrite the range to start at 0 and offset inside the body"
}
}
}
}
impl fmt::Display for InvalidForRangeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidForRangeKind::BareExpression => {
"for-loop range must use `..` or `..=`; a bare expression is not a valid range"
.fmt(f)
}
InvalidForRangeKind::NegativeBound => "for-loop range bound is negative".fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InvalidForStepKind {
ZeroStep,
NonAdditiveReverse,
NeverAdvances,
StopsAdvancing,
}
impl fmt::Display for InvalidForStepKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidForStepKind::ZeroStep => "for-loop with a zero step never advances".fmt(f),
InvalidForStepKind::NonAdditiveReverse => {
"reverse for-loop with a non-additive step never terminates".fmt(f)
}
InvalidForStepKind::NeverAdvances => {
"for-loop step can never advance toward the end of the range".fmt(f)
}
InvalidForStepKind::StopsAdvancing => {
"for-loop step stops advancing before reaching the end of the range".fmt(f)
}
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InvalidTestKind {
NoTopModuleCocotb,
}
impl fmt::Display for InvalidTestKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InvalidTestKind::NoTopModuleCocotb => "`cocotb` test requires top module name at the second argument of `#[test]` attribute".fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum MultipleDefaultKind {
Clock,
Reset,
ArrayLiteral,
}
impl fmt::Display for MultipleDefaultKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MultipleDefaultKind::Clock => "clock".fmt(f),
MultipleDefaultKind::Reset => "reset".fmt(f),
MultipleDefaultKind::ArrayLiteral => "value in array literal".fmt(f),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DuplicatedIdentifierKind {
Normal,
RawIdentifier { raw: String },
}
impl fmt::Display for DuplicatedIdentifierKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DuplicatedIdentifierKind::Normal => "".fmt(f),
DuplicatedIdentifierKind::RawIdentifier { raw } => {
write!(
f,
"r#-prefixed identifier \"{raw}\" is treated as the same identifier without the prefix"
)
}
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum UnevaluableValueKind {
CaseCondition,
ConstValue,
EnumVariant,
ForRange,
ParameterValue,
ResetValue,
SystemFunctionArg(&'static str),
}
impl fmt::Display for UnevaluableValueKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
UnevaluableValueKind::CaseCondition => "case condition".fmt(f),
UnevaluableValueKind::ConstValue => "const value".fmt(f),
UnevaluableValueKind::EnumVariant => "enum variant".fmt(f),
UnevaluableValueKind::ForRange => "for range".fmt(f),
UnevaluableValueKind::ParameterValue => "parameter value".fmt(f),
UnevaluableValueKind::ResetValue => "reset value".fmt(f),
UnevaluableValueKind::SystemFunctionArg(name) => {
write!(f, "{name} argument")
}
}
}
}