From 77f31d57f40c1507435b9d5eabb8145922443455 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Thu, 5 Dec 2024 22:22:35 +0100 Subject: [PATCH 01/12] Fix: discrete ranges can be used as choice statements --- vhdl_lang/src/analysis/assignment.rs | 4 +- vhdl_lang/src/analysis/concurrent.rs | 2 +- vhdl_lang/src/analysis/declarative.rs | 3 + vhdl_lang/src/analysis/expression.rs | 4 +- vhdl_lang/src/analysis/names.rs | 104 +++++++++++------- vhdl_lang/src/analysis/range.rs | 2 +- vhdl_lang/src/analysis/semantic.rs | 91 ++++++++++++--- vhdl_lang/src/analysis/sequential.rs | 2 +- .../src/analysis/tests/discrete_ranges.rs | 88 +++++++++++++++ vhdl_lang/src/analysis/tests/mod.rs | 1 + 10 files changed, 240 insertions(+), 61 deletions(-) create mode 100644 vhdl_lang/src/analysis/tests/discrete_ranges.rs diff --git a/vhdl_lang/src/analysis/assignment.rs b/vhdl_lang/src/analysis/assignment.rs index 940ade676..c6bc63ba6 100644 --- a/vhdl_lang/src/analysis/assignment.rs +++ b/vhdl_lang/src/analysis/assignment.rs @@ -55,7 +55,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { } in alternatives.iter_mut() { self.analyze_expression_for_target(scope, ttyp, item, diagnostics)?; - self.choice_with_ttyp(scope, ctyp, choices, diagnostics)?; + self.choices_with_ttyp(scope, ctyp, choices, diagnostics)?; } } } @@ -105,7 +105,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { } in alternatives.iter_mut() { self.analyze_waveform(scope, ttyp, item, diagnostics)?; - self.choice_with_ttyp(scope, ctyp, choices, diagnostics)?; + self.choices_with_ttyp(scope, ctyp, choices, diagnostics)?; } } } diff --git a/vhdl_lang/src/analysis/concurrent.rs b/vhdl_lang/src/analysis/concurrent.rs index f1f684d24..4a24ca675 100644 --- a/vhdl_lang/src/analysis/concurrent.rs +++ b/vhdl_lang/src/analysis/concurrent.rs @@ -188,7 +188,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { ref mut item, span: _, } = alternative; - self.choice_with_ttyp(scope, ctyp, choices, diagnostics)?; + self.choices_with_ttyp(scope, ctyp, choices, diagnostics)?; let nested = scope.nested(); self.analyze_generate_body(&nested, parent, item, src_span, diagnostics)?; } diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index c6f8288c9..a3a4215a7 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -350,6 +350,9 @@ impl<'a, 't> AnalyzeContext<'a, 't> { return Err(EvalError::Unknown); } } + ResolvedName::Range(_) => { + return Err(EvalError::Unknown); + } } }; diff --git a/vhdl_lang/src/analysis/expression.rs b/vhdl_lang/src/analysis/expression.rs index afc873150..db21ea946 100644 --- a/vhdl_lang/src/analysis/expression.rs +++ b/vhdl_lang/src/analysis/expression.rs @@ -684,7 +684,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { "Ambiguous use of implicit boolean conversion ??", ErrorCode::AmbiguousCall, ); - diag.add_type_candididates("Could be", implicit_bool_types); + diag.add_type_candidates("Could be", implicit_bool_types); diagnostics.push(diag); } @@ -697,7 +697,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { ), ErrorCode::AmbiguousExpression, ); - diag.add_type_candididates( + diag.add_type_candidates( "Implicit boolean conversion operator ?? is not defined for", types, ); diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index 239e92986..38e4f7620 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -157,6 +157,7 @@ pub enum ResolvedName<'a> { Expression(DisambiguatedType<'a>), // Something that cannot be further selected Final(EntRef<'a>), + Range(TypeEnt<'a>), } impl<'a> ResolvedName<'a> { @@ -307,6 +308,7 @@ impl<'a> ResolvedName<'a> { ResolvedName::Final(ent) => ent.describe(), ResolvedName::Expression(DisambiguatedType::Unambiguous(_)) => "Expression".to_owned(), ResolvedName::Expression(_) => "Ambiguous expression".to_owned(), + ResolvedName::Range(_) => "Range".to_owned(), } } @@ -324,6 +326,7 @@ impl<'a> ResolvedName<'a> { ObjectBase::ExternalName(_) => None, }, ResolvedName::Expression(_) | ResolvedName::Final(_) => None, + ResolvedName::Range(typ) => typ.decl_pos(), } } @@ -395,6 +398,7 @@ impl<'a> ResolvedName<'a> { ResolvedName::Overloaded(_, _) => None, ResolvedName::Expression(_) => None, ResolvedName::Final(_) => None, + ResolvedName::Range(typ) => Some((*typ).into()), } } } @@ -478,12 +482,13 @@ impl<'a, 't> AnalyzeContext<'a, 't> { name: ResolvedName<'a>, ) -> Result>, Diagnostic> { match name { - ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => { - Err(Diagnostic::mismatched_kinds( - pos.pos(self.ctx), - format!("{} cannot be used in an expression", name.describe_type()), - )) - } + ResolvedName::Library(_) + | ResolvedName::Design(_) + | ResolvedName::Type(_) + | ResolvedName::Range(_) => Err(Diagnostic::mismatched_kinds( + pos.pos(self.ctx), + format!("{} cannot be used in an expression", name.describe_type()), + )), ResolvedName::Final(ent) => match ent.actual_kind() { AnyEntKind::LoopParameter(typ) => { Ok(typ.map(|typ| DisambiguatedType::Unambiguous(typ.into()))) @@ -517,7 +522,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { } } - fn name_to_unambiguous_type( + pub(crate) fn name_to_unambiguous_type( &self, span: TokenSpan, name: &ResolvedName<'a>, @@ -526,12 +531,13 @@ impl<'a, 't> AnalyzeContext<'a, 't> { suffix_ref: Option<&mut Reference>, ) -> Result>, Diagnostic> { match name { - ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => { - Err(Diagnostic::mismatched_kinds( - span.pos(self.ctx), - format!("{} cannot be used in an expression", name.describe_type()), - )) - } + ResolvedName::Library(_) + | ResolvedName::Design(_) + | ResolvedName::Type(_) + | ResolvedName::Range(_) => Err(Diagnostic::mismatched_kinds( + span.pos(self.ctx), + format!("{} cannot be used in an expression", name.describe_type()), + )), ResolvedName::Final(ent) => match ent.actual_kind() { AnyEntKind::LoopParameter(typ) => Ok(typ.map(|typ| typ.into())), AnyEntKind::PhysicalLiteral(typ) => Ok(Some(*typ)), @@ -1067,14 +1073,17 @@ impl<'a, 't> AnalyzeContext<'a, 't> { Err(EvalError::Unknown) } } - AttributeDesignator::Range(_) => { - diagnostics.add( - name_pos.pos(self.ctx), - "Range cannot be used as an expression", - ErrorCode::MismatchedKinds, - ); - Err(EvalError::Unknown) - } + AttributeDesignator::Range(_) => match prefix { + ResolvedName::Type(typ) => Ok(ResolvedName::Range(*typ)), + _ => { + diagnostics.add( + name_pos.pos(self.ctx), + format!("Range attribute cannot be used on {}", prefix.describe()), + ErrorCode::MismatchedKinds, + ); + Err(EvalError::Unknown) + } + }, AttributeDesignator::Type(attr) => self .resolve_type_attribute_suffix(prefix, prefix_pos, &attr, name_pos, diagnostics) .map(|typ| ResolvedName::Type(typ.base().into())), @@ -1526,6 +1535,12 @@ impl<'a, 't> AnalyzeContext<'a, 't> { return Err(EvalError::Unknown); } } + ResolvedName::Range(_) => { + bail!( + diagnostics, + Diagnostic::cannot_be_prefix(&span.pos(self.ctx), resolved, suffix) + ); + } ResolvedName::Type(typ) => match suffix { Suffix::Selected(selected) => { let typed_selection = match typ.selected(self.ctx, prefix.span, selected) { @@ -1593,7 +1608,8 @@ impl<'a, 't> AnalyzeContext<'a, 't> { | ResolvedName::Type(_) | ResolvedName::Overloaded { .. } | ResolvedName::Expression(_) - | ResolvedName::Final(_) => { + | ResolvedName::Final(_) + | ResolvedName::Range(_) => { diagnostics.add( name_pos.pos(self.ctx), format!("{} {}", resolved.describe(), err_msg), @@ -1619,6 +1635,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { | ResolvedName::ObjectName(_) | ResolvedName::Overloaded { .. } | ResolvedName::Expression(_) + | ResolvedName::Range(_) | ResolvedName::Final(_) => { bail!( diagnostics, @@ -1708,25 +1725,34 @@ impl<'a, 't> AnalyzeContext<'a, 't> { false, diagnostics, ))? { - // @TODO target_type already used above, functions could probably be simplified - match self.name_to_unambiguous_type(span, &resolved, ttyp, name.suffix_reference_mut()) - { - Ok(Some(type_mark)) => { - if !self.can_be_target_type(type_mark, ttyp.base()) { - diagnostics.push(Diagnostic::type_mismatch( - &span.pos(self.ctx), - &resolved.describe_type(), - ttyp, - )); - } - } - Ok(None) => {} - Err(diag) => { - diagnostics.push(diag); + self.check_resolved_name_type(span, &resolved, ttyp, name, diagnostics); + } + Ok(()) + } + + pub fn check_resolved_name_type( + &self, + span: TokenSpan, + resolved: &ResolvedName<'a>, + ttyp: TypeEnt<'a>, + name: &mut Name, + diagnostics: &mut dyn DiagnosticHandler, + ) { + match self.name_to_unambiguous_type(span, &resolved, ttyp, name.suffix_reference_mut()) { + Ok(Some(type_mark)) => { + if !self.can_be_target_type(type_mark, ttyp.base()) { + diagnostics.push(Diagnostic::type_mismatch( + &span.pos(self.ctx), + &resolved.describe_type(), + ttyp, + )); } } + Ok(None) => {} + Err(diag) => { + diagnostics.push(diag); + } } - Ok(()) } /// Analyze an indexed name where the prefix entity is already known @@ -3093,7 +3119,7 @@ variable thevar : integer_vector(0 to 1); diagnostics, vec![Diagnostic::new( code, - "Range cannot be used as an expression", + "Range attribute cannot be used on variable 'thevar'", ErrorCode::MismatchedKinds, )], ) diff --git a/vhdl_lang/src/analysis/range.rs b/vhdl_lang/src/analysis/range.rs index f2e4119f2..1086d4f71 100644 --- a/vhdl_lang/src/analysis/range.rs +++ b/vhdl_lang/src/analysis/range.rs @@ -81,7 +81,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { let resolved = self.name_resolve(scope, attr.name.span, &mut attr.name.item, diagnostics)?; let typ = match resolved { - ResolvedName::Type(typ) => typ, + ResolvedName::Type(typ) | ResolvedName::Range(typ) => typ, ResolvedName::ObjectName(oname) => oname.type_mark(), ResolvedName::Overloaded(ref des, ref overloaded) => { let disamb = self diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index 4407df034..9f46c5bf8 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -15,7 +15,7 @@ use crate::data::*; use crate::named_entity::*; impl<'a, 't> AnalyzeContext<'a, 't> { - pub fn choice_with_ttyp( + pub fn choices_with_ttyp( &self, scope: &Scope<'a>, ttyp: Option>, @@ -23,23 +23,84 @@ impl<'a, 't> AnalyzeContext<'a, 't> { diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { for choice in choices.iter_mut() { - match choice.item { - Choice::Expression(ref mut expr) => { - if let Some(ttyp) = ttyp { - self.expr_pos_with_ttyp(scope, ttyp, choice.span, expr, diagnostics)?; - } else { - self.expr_pos_unknown_ttyp(scope, choice.span, expr, diagnostics)?; + self.choice_with_ttyp(scope, ttyp, choice, diagnostics)?; + } + Ok(()) + } + + fn check_resolved_name( + &self, + ttyp: Option>, + typ: TypeEnt<'a>, + diagnostics: &mut dyn DiagnosticHandler, + pos: &WithTokenSpan, + ) { + if let Some(ttyp) = ttyp { + if !self.can_be_target_type(typ, ttyp.base()) { + diagnostics.push(Diagnostic::type_mismatch( + &pos.pos(self.ctx), + &typ.describe(), + ttyp, + )); + } + } + } + + pub fn choice_with_ttyp( + &self, + scope: &Scope<'a>, + ttyp: Option>, + choice: &mut WithTokenSpan, + diagnostics: &mut dyn DiagnosticHandler, + ) -> FatalResult { + match choice.item { + Choice::Expression(ref mut expr) => { + if let Expression::Name(name) = expr { + if let Some(resolved_name) = + as_fatal(self.name_resolve(scope, choice.span, name, diagnostics))? + { + match resolved_name { + ResolvedName::Range(typ) => { + self.check_resolved_name(ttyp, typ, diagnostics, choice) + } + ResolvedName::Type(typ) => { + if !matches!(typ.kind(), Type::Subtype(_)) { + diagnostics.add( + choice.pos(self.ctx), + format!("{} must be a subtype", typ.describe(),), + ErrorCode::MismatchedKinds, + ) + } else { + self.check_resolved_name(ttyp, typ, diagnostics, choice) + } + } + _ => { + if let Some(ttyp) = ttyp { + self.check_resolved_name_type( + choice.span, + &resolved_name, + ttyp, + name, + diagnostics, + ); + } + } + } } + } else if let Some(ttyp) = ttyp { + self.expr_pos_with_ttyp(scope, ttyp, choice.span, expr, diagnostics)?; + } else { + self.expr_pos_unknown_ttyp(scope, choice.span, expr, diagnostics)?; } - Choice::DiscreteRange(ref mut drange) => { - if let Some(ttyp) = ttyp { - self.drange_with_ttyp(scope, ttyp, drange, diagnostics)?; - } else { - self.drange_unknown_type(scope, drange, diagnostics)?; - } + } + Choice::DiscreteRange(ref mut drange) => { + if let Some(ttyp) = ttyp { + self.drange_with_ttyp(scope, ttyp, drange, diagnostics)?; + } else { + self.drange_unknown_type(scope, drange, diagnostics)?; } - Choice::Others => {} } + Choice::Others => {} } Ok(()) } @@ -180,7 +241,7 @@ impl Diagnostic { } } - pub fn add_type_candididates<'a>( + pub fn add_type_candidates<'a>( &mut self, prefix: &str, candidates: impl IntoIterator>, diff --git a/vhdl_lang/src/analysis/sequential.rs b/vhdl_lang/src/analysis/sequential.rs index 795c436bf..61329ff38 100644 --- a/vhdl_lang/src/analysis/sequential.rs +++ b/vhdl_lang/src/analysis/sequential.rs @@ -252,7 +252,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { item, span: _, } = alternative; - self.choice_with_ttyp(scope, ctyp, choices, diagnostics)?; + self.choices_with_ttyp(scope, ctyp, choices, diagnostics)?; self.analyze_sequential_part(scope, parent, item, diagnostics)?; } } diff --git a/vhdl_lang/src/analysis/tests/discrete_ranges.rs b/vhdl_lang/src/analysis/tests/discrete_ranges.rs new file mode 100644 index 000000000..f4b002007 --- /dev/null +++ b/vhdl_lang/src/analysis/tests/discrete_ranges.rs @@ -0,0 +1,88 @@ +use crate::analysis::tests::{check_no_diagnostics, LibraryBuilder}; +use crate::data::ErrorCode; +use crate::syntax::test::check_diagnostics; +use crate::Diagnostic; + +#[test] +fn allows_ranges_with_case_statements() { + let mut builder = LibraryBuilder::new(); + builder.code( + "libname", + " +entity test is +end entity; + +architecture rtl of test is + type t_my_enum is (A1, A2, A3); + subtype t_my_enum_range is t_my_enum range A1 to A2; + signal my_sig_sub : t_my_enum; +begin + + process + begin + case my_sig_sub is + when t_my_enum'range => null; + when t_my_enum_range => null; + when t_my_enum_range'range => null; + when A1 to A2 => null; + when others => null; + end case; + end process; +end architecture; +", + ); + + let diagnostics = builder.analyze(); + check_no_diagnostics(&diagnostics); +} + +#[test] +fn disallows_ranges_with_wrong_type() { + let mut builder = LibraryBuilder::new(); + let code = builder.code( + "libname", + " +entity test is +end entity; + +architecture rtl of test is + type t_my_enum is (A1, A2, A3); + type t_my_other_enum is (B1, B2, B3); + subtype t_my_other_enum_range is t_my_other_enum range B1 to B2; + signal my_sig_sub : t_my_enum; +begin + + process + begin + case my_sig_sub is + when t_my_other_enum'range => null; + when t_my_other_enum_range => null; + when t_my_enum => null; + when others => null; + end case; + end process; +end architecture; +", + ); + + check_diagnostics( + builder.analyze(), + vec![ + Diagnostic::new( + code.s1("t_my_other_enum'range"), + "type 't_my_other_enum' does not match type 't_my_enum'", + ErrorCode::TypeMismatch, + ), + Diagnostic::new( + code.s("t_my_other_enum_range", 2), + "subtype 't_my_other_enum_range' does not match type 't_my_enum'", + ErrorCode::TypeMismatch, + ), + Diagnostic::new( + code.s("t_my_enum", 3), + "type 't_my_enum' must be a subtype", + ErrorCode::MismatchedKinds, + ), + ], + ); +} diff --git a/vhdl_lang/src/analysis/tests/mod.rs b/vhdl_lang/src/analysis/tests/mod.rs index e64a6e23b..e2be56697 100644 --- a/vhdl_lang/src/analysis/tests/mod.rs +++ b/vhdl_lang/src/analysis/tests/mod.rs @@ -11,6 +11,7 @@ mod context_clause; mod custom_attributes; mod declarations; mod deferred_constant; +mod discrete_ranges; mod hierarchy; mod homographs; mod implicit; From c58c8e1d3635e4fd57406a37bd1842f21d53a8ce Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Thu, 5 Dec 2024 22:26:44 +0100 Subject: [PATCH 02/12] Happy clippy --- vhdl_lang/src/analysis/names.rs | 2 +- vhdl_lang/src/ast.rs | 2 +- vhdl_lang/src/ast/ast_span.rs | 14 ++++ vhdl_lang/src/syntax/subprogram.rs | 118 ++++++++++++++++------------- 4 files changed, 80 insertions(+), 56 deletions(-) diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index 38e4f7620..5b7db1ded 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -1738,7 +1738,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { name: &mut Name, diagnostics: &mut dyn DiagnosticHandler, ) { - match self.name_to_unambiguous_type(span, &resolved, ttyp, name.suffix_reference_mut()) { + match self.name_to_unambiguous_type(span, resolved, ttyp, name.suffix_reference_mut()) { Ok(Some(type_mark)) => { if !self.can_be_target_type(type_mark, ttyp.base()) { diagnostics.push(Diagnostic::type_mismatch( diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index 376390a52..18d030ddf 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -759,7 +759,7 @@ pub enum Signature { #[derive(PartialEq, Debug, Clone, TokenSpan)] pub enum SubprogramSpecification { - Procedure(ProcedureSpecification), + Procedure(Box), Function(FunctionSpecification), } diff --git a/vhdl_lang/src/ast/ast_span.rs b/vhdl_lang/src/ast/ast_span.rs index 59531daeb..0a3b26a5d 100644 --- a/vhdl_lang/src/ast/ast_span.rs +++ b/vhdl_lang/src/ast/ast_span.rs @@ -1,6 +1,7 @@ use crate::ast::token_range::WithTokenSpan; use crate::ast::{LabeledConcurrentStatement, LabeledSequentialStatement, WithDecl}; use crate::{HasTokenSpan, TokenId}; +use std::ops::Deref; use vhdl_lang::ast::WithToken; use vhdl_lang::TokenSpan; @@ -54,6 +55,19 @@ impl HasTokenSpan for WithTokenSpan { } } +impl HasTokenSpan for Box +where + T: HasTokenSpan, +{ + fn get_start_token(&self) -> TokenId { + self.deref().get_start_token() + } + + fn get_end_token(&self) -> TokenId { + self.deref().get_end_token() + } +} + impl HasTokenSpan for LabeledConcurrentStatement { fn get_start_token(&self) -> TokenId { if let Some(label) = &self.label.tree { diff --git a/vhdl_lang/src/syntax/subprogram.rs b/vhdl_lang/src/syntax/subprogram.rs index e6072c43f..71f1ab5cd 100644 --- a/vhdl_lang/src/syntax/subprogram.rs +++ b/vhdl_lang/src/syntax/subprogram.rs @@ -192,12 +192,14 @@ pub fn parse_subprogram_specification( })) } else { let end_token = ctx.stream.get_last_token_id(); - Ok(SubprogramSpecification::Procedure(ProcedureSpecification { - designator: designator.into(), - header, - parameter_list, - span: TokenSpan::new(start_token, end_token), - })) + Ok(SubprogramSpecification::Procedure(Box::new( + ProcedureSpecification { + designator: designator.into(), + header, + parameter_list, + span: TokenSpan::new(start_token, end_token), + }, + ))) } } @@ -310,16 +312,18 @@ procedure foo; code.with_stream_no_diagnostics(parse_subprogram_declaration), SubprogramDeclaration { span: code.token_span(), - specification: SubprogramSpecification::Procedure(ProcedureSpecification { - designator: code - .s1("foo") - .ident() - .map_into(SubprogramDesignator::Identifier) - .into(), - header: None, - parameter_list: None, - span: code.s1("procedure foo").token_span(), - }) + specification: SubprogramSpecification::Procedure(Box::new( + ProcedureSpecification { + designator: code + .s1("foo") + .ident() + .map_into(SubprogramDesignator::Identifier) + .into(), + header: None, + parameter_list: None, + span: code.s1("procedure foo").token_span(), + } + )) } ); } @@ -442,20 +446,22 @@ procedure foo(foo : natural); code.with_stream_no_diagnostics(parse_subprogram_declaration), SubprogramDeclaration { span: code.token_span(), - specification: SubprogramSpecification::Procedure(ProcedureSpecification { - designator: code - .s1("foo") - .ident() - .map_into(SubprogramDesignator::Identifier) - .into(), - header: None, - parameter_list: Some(InterfaceList { - interface_type: InterfaceType::Parameter, - items: vec![code.s1("foo : natural").parameter()], - span: code.between("(", ")").token_span() - }), - span: code.between("procedure", "natural)").token_span(), - }) + specification: SubprogramSpecification::Procedure(Box::new( + ProcedureSpecification { + designator: code + .s1("foo") + .ident() + .map_into(SubprogramDesignator::Identifier) + .into(), + header: None, + parameter_list: Some(InterfaceList { + interface_type: InterfaceType::Parameter, + items: vec![code.s1("foo : natural").parameter()], + span: code.between("(", ")").token_span() + }), + span: code.between("procedure", "natural)").token_span(), + } + )) } ); } @@ -814,18 +820,20 @@ procedure my_proc decl, SubprogramDeclaration { span: code.token_span(), - specification: SubprogramSpecification::Procedure(ProcedureSpecification { - designator: code - .s1("my_proc") - .ident() - .map_into(SubprogramDesignator::Identifier) - .into(), - header: code - .s1("generic (x: natural := 4; y: real := 4)") - .subprogram_header(), - parameter_list: None, - span: code.between("procedure", "4)").token_span(), - }) + specification: SubprogramSpecification::Procedure(Box::new( + ProcedureSpecification { + designator: code + .s1("my_proc") + .ident() + .map_into(SubprogramDesignator::Identifier) + .into(), + header: code + .s1("generic (x: natural := 4; y: real := 4)") + .subprogram_header(), + parameter_list: None, + span: code.between("procedure", "4)").token_span(), + } + )) } ); } @@ -844,19 +852,21 @@ procedure my_proc decl, SubprogramDeclaration { span: code.token_span(), - specification: SubprogramSpecification::Procedure(ProcedureSpecification { - designator: code - .s1("my_proc") - .ident() - .map_into(SubprogramDesignator::Identifier) - .into(), - header: code - .s1("generic (x: natural := 4; y: real := 4) + specification: SubprogramSpecification::Procedure(Box::new( + ProcedureSpecification { + designator: code + .s1("my_proc") + .ident() + .map_into(SubprogramDesignator::Identifier) + .into(), + header: code + .s1("generic (x: natural := 4; y: real := 4) generic map (x => 42)") - .subprogram_header(), - parameter_list: None, - span: code.between("procedure", "42)").token_span(), - }) + .subprogram_header(), + parameter_list: None, + span: code.between("procedure", "42)").token_span(), + } + )) } ); } From 6a548abc757741a3e2b8eb00d10194012d051cd6 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Thu, 5 Dec 2024 22:42:40 +0100 Subject: [PATCH 03/12] Even happier clippy --- vhdl_lang/src/analysis/assignment.rs | 2 +- vhdl_lang/src/analysis/association.rs | 2 +- vhdl_lang/src/analysis/concurrent.rs | 2 +- vhdl_lang/src/analysis/declarative.rs | 2 +- vhdl_lang/src/analysis/design_unit.rs | 2 +- vhdl_lang/src/analysis/expression.rs | 2 +- vhdl_lang/src/analysis/literals.rs | 2 +- vhdl_lang/src/analysis/lock.rs | 8 ++++---- vhdl_lang/src/analysis/names.rs | 2 +- vhdl_lang/src/analysis/overloaded.rs | 2 +- vhdl_lang/src/analysis/package_instance.rs | 2 +- vhdl_lang/src/analysis/range.rs | 2 +- vhdl_lang/src/analysis/semantic.rs | 4 ++-- vhdl_lang/src/analysis/sequential.rs | 2 +- vhdl_lang/src/analysis/standard.rs | 2 +- vhdl_lang/src/analysis/subprogram.rs | 2 +- vhdl_lang/src/analysis/target.rs | 2 +- vhdl_lang/src/analysis/tests/hierarchy.rs | 2 +- vhdl_lang/src/analysis/types.rs | 2 +- vhdl_lang/src/ast.rs | 2 +- vhdl_lang/src/ast/search.rs | 10 +++++----- vhdl_lang/src/ast/util.rs | 2 +- vhdl_lang/src/completion/generic.rs | 4 ++-- vhdl_lang/src/completion/map_aspect.rs | 2 +- vhdl_lang/src/data/diagnostic.rs | 2 +- vhdl_lang/src/lint/dead_code.rs | 2 +- vhdl_lang/src/named_entity.rs | 10 +++++----- vhdl_lang/src/named_entity/arena.rs | 2 +- vhdl_lang/src/named_entity/design.rs | 2 +- vhdl_lang/src/named_entity/overloaded.rs | 2 +- vhdl_lang/src/named_entity/types.rs | 2 +- vhdl_lang/src/named_entity/visibility.rs | 2 +- vhdl_lang/src/project.rs | 2 +- vhdl_lang/src/syntax/tokens/tokenizer.rs | 2 +- vhdl_lang/src/syntax/tokens/tokenstream.rs | 2 +- 35 files changed, 48 insertions(+), 48 deletions(-) diff --git a/vhdl_lang/src/analysis/assignment.rs b/vhdl_lang/src/analysis/assignment.rs index c6bc63ba6..67a06ed4b 100644 --- a/vhdl_lang/src/analysis/assignment.rs +++ b/vhdl_lang/src/analysis/assignment.rs @@ -12,7 +12,7 @@ use crate::ast::*; use crate::data::*; use crate::named_entity::*; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { // @TODO maybe make generic function for expression/waveform. // wait until type checking to see if it makes sense pub fn analyze_expr_assignment( diff --git a/vhdl_lang/src/analysis/association.rs b/vhdl_lang/src/analysis/association.rs index 599a587e1..5c9a4572b 100644 --- a/vhdl_lang/src/analysis/association.rs +++ b/vhdl_lang/src/analysis/association.rs @@ -84,7 +84,7 @@ impl<'a> ResolvedFormal<'a> { } } -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { fn resolve_formal( &self, formal_region: &FormalRegion<'a>, diff --git a/vhdl_lang/src/analysis/concurrent.rs b/vhdl_lang/src/analysis/concurrent.rs index 4a24ca675..0aac8a0cb 100644 --- a/vhdl_lang/src/analysis/concurrent.rs +++ b/vhdl_lang/src/analysis/concurrent.rs @@ -14,7 +14,7 @@ use crate::named_entity::*; use crate::{HasTokenSpan, TokenSpan}; use analyze::*; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn analyze_concurrent_part( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index a3a4215a7..f62929620 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -134,7 +134,7 @@ impl Declaration { } } -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn analyze_declarative_part( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/design_unit.rs b/vhdl_lang/src/analysis/design_unit.rs index 65a0dfb72..39f845820 100644 --- a/vhdl_lang/src/analysis/design_unit.rs +++ b/vhdl_lang/src/analysis/design_unit.rs @@ -14,7 +14,7 @@ use crate::named_entity::*; use crate::HasTokenSpan; use analyze::*; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn analyze_primary_unit( &self, unit: &mut AnyPrimaryUnit, diff --git a/vhdl_lang/src/analysis/expression.rs b/vhdl_lang/src/analysis/expression.rs index db21ea946..3ac88aadc 100644 --- a/vhdl_lang/src/analysis/expression.rs +++ b/vhdl_lang/src/analysis/expression.rs @@ -69,7 +69,7 @@ pub(super) struct TypeMatcher<'c, 'a, 't> { context: &'c AnalyzeContext<'a, 't>, } -impl<'c, 'a, 't> TypeMatcher<'c, 'a, 't> { +impl<'a> TypeMatcher<'_, 'a, '_> { // Returns true if the expression types is possible given the target type pub fn is_possible(&self, types: &ExpressionType<'a>, ttyp: BaseType<'a>) -> bool { if types.match_type(ttyp) { diff --git a/vhdl_lang/src/analysis/literals.rs b/vhdl_lang/src/analysis/literals.rs index 64ad6e546..e480ad067 100644 --- a/vhdl_lang/src/analysis/literals.rs +++ b/vhdl_lang/src/analysis/literals.rs @@ -14,7 +14,7 @@ use crate::data::*; use crate::named_entity::*; use crate::TokenSpan; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { /// Analyze a string literal or expanded bit-string literal for type-matching fn analyze_string_literal( &self, diff --git a/vhdl_lang/src/analysis/lock.rs b/vhdl_lang/src/analysis/lock.rs index f13036e4c..c389d2ce1 100644 --- a/vhdl_lang/src/analysis/lock.rs +++ b/vhdl_lang/src/analysis/lock.rs @@ -112,7 +112,7 @@ pub struct ReadGuard<'a, T, R> { guard: RwLockReadGuard<'a, AnalysisState>, } -impl<'a, T, R> ReadGuard<'a, T, R> { +impl ReadGuard<'_, T, R> { pub fn result(&self) -> &R { self.guard.result.as_ref().unwrap() } @@ -122,7 +122,7 @@ impl<'a, T, R> ReadGuard<'a, T, R> { } } -impl<'a, T, R> std::ops::Deref for ReadGuard<'a, T, R> { +impl std::ops::Deref for ReadGuard<'_, T, R> { type Target = T; fn deref(&self) -> &Self::Target { @@ -148,7 +148,7 @@ impl<'a, T, R> WriteGuard<'a, T, R> { } } -impl<'a, T, R> std::ops::Deref for WriteGuard<'a, T, R> { +impl std::ops::Deref for WriteGuard<'_, T, R> { type Target = T; fn deref(&self) -> &Self::Target { @@ -156,7 +156,7 @@ impl<'a, T, R> std::ops::Deref for WriteGuard<'a, T, R> { } } -impl<'a, T, R> std::ops::DerefMut for WriteGuard<'a, T, R> { +impl std::ops::DerefMut for WriteGuard<'_, T, R> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.guard.data } diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index 5b7db1ded..0af613306 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -473,7 +473,7 @@ pub fn as_type_conversion( None } -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { fn name_to_type( &self, pos: TokenSpan, diff --git a/vhdl_lang/src/analysis/overloaded.rs b/vhdl_lang/src/analysis/overloaded.rs index 2763a935f..a037081b4 100644 --- a/vhdl_lang/src/analysis/overloaded.rs +++ b/vhdl_lang/src/analysis/overloaded.rs @@ -186,7 +186,7 @@ impl<'a> AsRef> for ResolvedCall<'a> { } } -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { /// Typecheck one overloaded call where the exact subprogram is known pub fn check_call( &self, diff --git a/vhdl_lang/src/analysis/package_instance.rs b/vhdl_lang/src/analysis/package_instance.rs index 95b3fdea6..80f44633f 100644 --- a/vhdl_lang/src/analysis/package_instance.rs +++ b/vhdl_lang/src/analysis/package_instance.rs @@ -23,7 +23,7 @@ use crate::named_entity::*; use crate::Diagnostic; use crate::NullDiagnostics; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn generic_package_instance( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/range.rs b/vhdl_lang/src/analysis/range.rs index 1086d4f71..1af63cfea 100644 --- a/vhdl_lang/src/analysis/range.rs +++ b/vhdl_lang/src/analysis/range.rs @@ -18,7 +18,7 @@ use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn range_unknown_typ( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index 9f46c5bf8..dcc154910 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -14,7 +14,7 @@ use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn choices_with_ttyp( &self, scope: &Scope<'a>, @@ -257,7 +257,7 @@ impl Diagnostic { } } -impl<'a> ResolvedName<'a> { +impl ResolvedName<'_> { pub(super) fn kind_error(&self, pos: impl AsRef, expected: &str) -> Diagnostic { let mut error = Diagnostic::mismatched_kinds( pos, diff --git a/vhdl_lang/src/analysis/sequential.rs b/vhdl_lang/src/analysis/sequential.rs index 61329ff38..3e079cbe9 100644 --- a/vhdl_lang/src/analysis/sequential.rs +++ b/vhdl_lang/src/analysis/sequential.rs @@ -13,7 +13,7 @@ use crate::HasTokenSpan; use analyze::*; use target::AssignmentType; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn define_labels_for_sequential_part( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/standard.rs b/vhdl_lang/src/analysis/standard.rs index b06fae41e..a6cf1debb 100644 --- a/vhdl_lang/src/analysis/standard.rs +++ b/vhdl_lang/src/analysis/standard.rs @@ -169,7 +169,7 @@ impl StandardTypes { } } -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { fn ident(&self, name: &str) -> Designator { Designator::Identifier(self.root.symbol_utf8(name)) } diff --git a/vhdl_lang/src/analysis/subprogram.rs b/vhdl_lang/src/analysis/subprogram.rs index abfabbcde..33f8fd90f 100644 --- a/vhdl_lang/src/analysis/subprogram.rs +++ b/vhdl_lang/src/analysis/subprogram.rs @@ -15,7 +15,7 @@ use analyze::*; use itertools::Itertools; use vhdl_lang::TokenSpan; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { fn subprogram_header( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/target.rs b/vhdl_lang/src/analysis/target.rs index b04210fcf..77ef848b9 100644 --- a/vhdl_lang/src/analysis/target.rs +++ b/vhdl_lang/src/analysis/target.rs @@ -12,7 +12,7 @@ use vhdl_lang::TokenSpan; /// examples: /// target <= 1; /// target(0).elem := 1 -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn resolve_target( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/analysis/tests/hierarchy.rs b/vhdl_lang/src/analysis/tests/hierarchy.rs index d98973e6d..0cb2fed33 100644 --- a/vhdl_lang/src/analysis/tests/hierarchy.rs +++ b/vhdl_lang/src/analysis/tests/hierarchy.rs @@ -262,7 +262,7 @@ fn single(name: &str) -> NameHierarchy { } } -impl<'a> From> for NameHierarchy { +impl From> for NameHierarchy { fn from(ent: EntHierarchy<'_>) -> Self { NameHierarchy { name: if matches!(ent.ent.designator(), Designator::Anonymous(_)) { diff --git a/vhdl_lang/src/analysis/types.rs b/vhdl_lang/src/analysis/types.rs index 35fa1fe22..beaad8611 100644 --- a/vhdl_lang/src/analysis/types.rs +++ b/vhdl_lang/src/analysis/types.rs @@ -12,7 +12,7 @@ use crate::named_entity::{Signature, *}; use crate::HasTokenSpan; use analyze::*; -impl<'a, 't> AnalyzeContext<'a, 't> { +impl<'a> AnalyzeContext<'a, '_> { pub fn resolve_subtype_indication( &self, scope: &Scope<'a>, diff --git a/vhdl_lang/src/ast.rs b/vhdl_lang/src/ast.rs index 18d030ddf..d3d7bb5bf 100644 --- a/vhdl_lang/src/ast.rs +++ b/vhdl_lang/src/ast.rs @@ -469,7 +469,7 @@ impl WithDecl { } impl WithDecl> { - pub fn pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &SrcPos { + pub fn pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &'a SrcPos { self.tree.pos(ctx) } } diff --git a/vhdl_lang/src/ast/search.rs b/vhdl_lang/src/ast/search.rs index 1bc8a267a..37d9ed7ad 100644 --- a/vhdl_lang/src/ast/search.rs +++ b/vhdl_lang/src/ast/search.rs @@ -1603,7 +1603,7 @@ impl<'a> ItemAtCursor<'a> { } } -impl<'a> Searcher for ItemAtCursor<'a> { +impl Searcher for ItemAtCursor<'_> { fn search_with_pos(&mut self, _ctx: &dyn TokenAccess, pos: &SrcPos) -> SearchState { // cursor is the gap between character cursor and cursor + 1 // Thus cursor will match character cursor and cursor + 1 @@ -1722,7 +1722,7 @@ impl<'a> FormatDeclaration<'a> { } } -impl<'a> Searcher for FormatDeclaration<'a> { +impl Searcher for FormatDeclaration<'_> { fn search_decl(&mut self, _ctx: &dyn TokenAccess, decl: FoundDeclaration<'_>) -> SearchState { let id = if let Some(id) = decl.ent_id() { id @@ -1780,7 +1780,7 @@ impl<'a> FindAllReferences<'a> { } } -impl<'a> Searcher for FindAllReferences<'a> { +impl Searcher for FindAllReferences<'_> { fn search_decl(&mut self, ctx: &dyn TokenAccess, decl: FoundDeclaration<'_>) -> SearchState { if let Some(id) = decl.ent_id() { let other = self.root.get_ent(id); @@ -1813,7 +1813,7 @@ impl<'a> Searcher for FindAllReferences<'a> { } } -impl<'a> FoundDeclaration<'a> { +impl FoundDeclaration<'_> { fn end_ident_pos(&self) -> Option { match &self.ast { DeclarationItem::InterfaceObject(_) => None, @@ -1863,7 +1863,7 @@ impl SubprogramSpecification { } } -impl<'a> HasEntityId for FoundDeclaration<'a> { +impl HasEntityId for FoundDeclaration<'_> { fn ent_id(&self) -> Option { self.ent_id_ref().get() } diff --git a/vhdl_lang/src/ast/util.rs b/vhdl_lang/src/ast/util.rs index 02d1f6b95..3eea77908 100644 --- a/vhdl_lang/src/ast/util.rs +++ b/vhdl_lang/src/ast/util.rs @@ -120,7 +120,7 @@ pub trait HasIdent { &self.ident().item } - fn ident_pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &SrcPos { + fn ident_pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &'a SrcPos { self.ident().pos(ctx) } } diff --git a/vhdl_lang/src/completion/generic.rs b/vhdl_lang/src/completion/generic.rs index fa4b1a234..e267fa326 100644 --- a/vhdl_lang/src/completion/generic.rs +++ b/vhdl_lang/src/completion/generic.rs @@ -45,7 +45,7 @@ impl<'a> CompletionSearcher<'a> { } } -impl<'a> CompletionSearcher<'a> { +impl CompletionSearcher<'_> { /// Add entity instantiation completions that are visible from within an architecture body fn add_entity_instantiations(&mut self, body: &ArchitectureBody) { let Some(ent_id) = body.ident.decl.get() else { @@ -59,7 +59,7 @@ impl<'a> CompletionSearcher<'a> { } } -impl<'a> Searcher for CompletionSearcher<'a> { +impl Searcher for CompletionSearcher<'_> { fn search_decl(&mut self, ctx: &dyn TokenAccess, decl: FoundDeclaration<'_>) -> SearchState { let ent_id = match &decl.ast { DeclarationItem::Entity(ent_decl) => { diff --git a/vhdl_lang/src/completion/map_aspect.rs b/vhdl_lang/src/completion/map_aspect.rs index 7498dcb0b..002b05d1c 100644 --- a/vhdl_lang/src/completion/map_aspect.rs +++ b/vhdl_lang/src/completion/map_aspect.rs @@ -74,7 +74,7 @@ impl<'a> MapAspectSearcher<'a> { } } -impl<'a> Searcher for MapAspectSearcher<'a> { +impl Searcher for MapAspectSearcher<'_> { /// Visit an instantiation statement extracting completions for ports or generics. fn search_decl(&mut self, ctx: &dyn TokenAccess, decl: FoundDeclaration<'_>) -> SearchState { match &decl.ast { diff --git a/vhdl_lang/src/data/diagnostic.rs b/vhdl_lang/src/data/diagnostic.rs index 99c119ee6..59ffb574d 100644 --- a/vhdl_lang/src/data/diagnostic.rs +++ b/vhdl_lang/src/data/diagnostic.rs @@ -107,7 +107,7 @@ pub trait DiagnosticHandler { fn push(&mut self, diagnostic: Diagnostic); } -impl<'a> dyn DiagnosticHandler + 'a { +impl dyn DiagnosticHandler + '_ { pub fn add(&mut self, item: impl AsRef, msg: impl Into, code: ErrorCode) { self.push(Diagnostic::new(item, msg, code)) } diff --git a/vhdl_lang/src/lint/dead_code.rs b/vhdl_lang/src/lint/dead_code.rs index fd84e4565..271efec92 100644 --- a/vhdl_lang/src/lint/dead_code.rs +++ b/vhdl_lang/src/lint/dead_code.rs @@ -43,7 +43,7 @@ impl<'a> DeadCodeSearcher<'a> { } } -impl<'a> Searcher for DeadCodeSearcher<'a> { +impl Searcher for DeadCodeSearcher<'_> { fn search_pos_with_ref( &mut self, _ctx: &dyn TokenAccess, diff --git a/vhdl_lang/src/named_entity.rs b/vhdl_lang/src/named_entity.rs index 04a9d679e..7384288cc 100644 --- a/vhdl_lang/src/named_entity.rs +++ b/vhdl_lang/src/named_entity.rs @@ -204,13 +204,13 @@ impl<'a> AnyEntKind<'a> { } } -impl<'a> std::fmt::Debug for AnyEntKind<'a> { +impl std::fmt::Debug for AnyEntKind<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.describe()) } } -impl<'a> std::fmt::Debug for AnyEnt<'a> { +impl std::fmt::Debug for AnyEnt<'_> { // We need a custom debug implementation for AnyEnt to avoid stack overflow on circular references fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let AnyEnt { @@ -636,19 +636,19 @@ impl<'a> AnyEnt<'a> { } } -impl<'a> std::cmp::PartialEq for AnyEnt<'a> { +impl std::cmp::PartialEq for AnyEnt<'_> { fn eq(&self, other: &Self) -> bool { self.id == other.id } } -impl<'a> std::hash::Hash for AnyEnt<'a> { +impl std::hash::Hash for AnyEnt<'_> { fn hash(&self, state: &mut H) { self.id().hash(state) } } -impl<'a> Eq for AnyEnt<'a> {} +impl Eq for AnyEnt<'_> {} /// This trait is implemented for Ast-nodes which declare named entities pub trait HasEntityId { diff --git a/vhdl_lang/src/named_entity/arena.rs b/vhdl_lang/src/named_entity/arena.rs index 77a021b0f..ab7757b06 100644 --- a/vhdl_lang/src/named_entity/arena.rs +++ b/vhdl_lang/src/named_entity/arena.rs @@ -41,7 +41,7 @@ impl Default for ArenaId { pub struct LocalId(u32); /// Arena allocators used to store named entities - +/// /// Local arena used for single design unit in a separate thread struct LocalArena { pub id: ArenaId, diff --git a/vhdl_lang/src/named_entity/design.rs b/vhdl_lang/src/named_entity/design.rs index a430dec22..802d43254 100644 --- a/vhdl_lang/src/named_entity/design.rs +++ b/vhdl_lang/src/named_entity/design.rs @@ -37,7 +37,7 @@ pub enum Design<'a> { Context(Region<'a>), } -impl<'a> Design<'a> { +impl Design<'_> { pub fn describe(&self) -> &'static str { use Design::*; match self { diff --git a/vhdl_lang/src/named_entity/overloaded.rs b/vhdl_lang/src/named_entity/overloaded.rs index 1d9df7542..5bd0d17d9 100644 --- a/vhdl_lang/src/named_entity/overloaded.rs +++ b/vhdl_lang/src/named_entity/overloaded.rs @@ -25,7 +25,7 @@ pub enum Overloaded<'a> { Alias(OverloadedEnt<'a>), } -impl<'a> Debug for Overloaded<'a> { +impl Debug for Overloaded<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Overloaded::UninstSubprogramDecl(..) => { diff --git a/vhdl_lang/src/named_entity/types.rs b/vhdl_lang/src/named_entity/types.rs index d4046a10e..4386ec36d 100644 --- a/vhdl_lang/src/named_entity/types.rs +++ b/vhdl_lang/src/named_entity/types.rs @@ -45,7 +45,7 @@ pub enum UniversalType { Integer, } -impl<'a> Type<'a> { +impl Type<'_> { pub fn describe(&self) -> &'static str { match self { Type::Alias(..) => "alias", diff --git a/vhdl_lang/src/named_entity/visibility.rs b/vhdl_lang/src/named_entity/visibility.rs index c71926496..0e91758ba 100644 --- a/vhdl_lang/src/named_entity/visibility.rs +++ b/vhdl_lang/src/named_entity/visibility.rs @@ -112,7 +112,7 @@ impl<'a> Visibility<'a> { } pub fn all_in_region(&self) -> impl Iterator> { - return self.all_in_regions.iter(); + self.all_in_regions.iter() } pub fn visible(&self) -> impl Iterator> + '_ { diff --git a/vhdl_lang/src/project.rs b/vhdl_lang/src/project.rs index 933b2afc5..0d9462012 100644 --- a/vhdl_lang/src/project.rs +++ b/vhdl_lang/src/project.rs @@ -284,7 +284,7 @@ impl Project { &'a self, library_name: &Symbol, source: &Source, - ) -> Vec<(EntHierarchy<'a>, &Vec)> { + ) -> Vec<(EntHierarchy<'a>, &'a Vec)> { self.root.document_symbols(library_name, source) } diff --git a/vhdl_lang/src/syntax/tokens/tokenizer.rs b/vhdl_lang/src/syntax/tokens/tokenizer.rs index 3b48a6c13..fe4c01afe 100644 --- a/vhdl_lang/src/syntax/tokens/tokenizer.rs +++ b/vhdl_lang/src/syntax/tokens/tokenizer.rs @@ -446,7 +446,7 @@ impl TokenId { TokenId(idx) } - pub fn pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &SrcPos { + pub fn pos<'a>(&'a self, ctx: &'a dyn TokenAccess) -> &'a SrcPos { ctx.get_pos(*self) } } diff --git a/vhdl_lang/src/syntax/tokens/tokenstream.rs b/vhdl_lang/src/syntax/tokens/tokenstream.rs index 6e7b53933..182ab48a3 100644 --- a/vhdl_lang/src/syntax/tokens/tokenstream.rs +++ b/vhdl_lang/src/syntax/tokens/tokenstream.rs @@ -291,7 +291,7 @@ impl<'a> TokenStream<'a> { } } -impl<'a> TokenAccess for TokenStream<'a> { +impl TokenAccess for TokenStream<'_> { fn get_token(&self, id: TokenId) -> Option<&Token> { self.tokens[self.token_offset.get()..].get_token(id) } From 6af87c96f4add722099aa30910c4fb9188008118 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sat, 7 Dec 2024 18:39:28 +0100 Subject: [PATCH 04/12] Resolve to range names for objects --- vhdl_lang/src/analysis/declarative.rs | 5 ++++ vhdl_lang/src/analysis/names.rs | 25 +------------------ vhdl_lang/src/analysis/tests/declarations.rs | 26 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index f62929620..c6cc6e8fd 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -351,6 +351,11 @@ impl<'a> AnalyzeContext<'a, '_> { } } ResolvedName::Range(_) => { + diagnostics.add( + name.pos(self.ctx), + "Range cannot be aliased", + ErrorCode::MismatchedKinds, + ); return Err(EvalError::Unknown); } } diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index 0af613306..5396180ce 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -1075,6 +1075,7 @@ impl<'a> AnalyzeContext<'a, '_> { } AttributeDesignator::Range(_) => match prefix { ResolvedName::Type(typ) => Ok(ResolvedName::Range(*typ)), + ResolvedName::ObjectName(oname) => Ok(ResolvedName::Range(oname.type_mark())), _ => { diagnostics.add( name_pos.pos(self.ctx), @@ -3101,30 +3102,6 @@ variable thevar : integer; ) } - #[test] - fn range_attribute() { - let test = TestSetup::new(); - test.declarative_part( - " -variable thevar : integer_vector(0 to 1); - ", - ); - let code = test.snippet("thevar'range"); - let mut diagnostics = Vec::new(); - assert_eq!( - test.name_resolve(&code, None, &mut diagnostics), - Err(EvalError::Unknown) - ); - check_diagnostics( - diagnostics, - vec![Diagnostic::new( - code, - "Range attribute cannot be used on variable 'thevar'", - ErrorCode::MismatchedKinds, - )], - ) - } - #[test] fn name_attributes() { let test = TestSetup::new(); diff --git a/vhdl_lang/src/analysis/tests/declarations.rs b/vhdl_lang/src/analysis/tests/declarations.rs index fbca954aa..7ceff0c5a 100644 --- a/vhdl_lang/src/analysis/tests/declarations.rs +++ b/vhdl_lang/src/analysis/tests/declarations.rs @@ -100,3 +100,29 @@ end entity test; )], ) } + +#[test] +fn aliases_of_ranges() { + let mut builder = LibraryBuilder::new(); + let code = builder.code( + "libname", + "\ +entity foo is +end foo; + +architecture arch of foo is + constant x: bit_vector(12 downto 0) := \"000000000000\"; + alias x_range is x'range; +begin +end arch; + ", + ); + check_diagnostics( + builder.analyze(), + vec![Diagnostic::new( + code.s1("x'range"), + "Range cannot be aliased", + ErrorCode::MismatchedKinds, + )], + ) +} From 5e0c0c0ebd661b718bb404a7a9554ffb312029d8 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Dec 2024 17:48:23 +0100 Subject: [PATCH 05/12] Replace diagnostics.add and return Err with bail --- vhdl_lang/src/analysis/declarative.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index c6cc6e8fd..903bd632d 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -351,12 +351,14 @@ impl<'a> AnalyzeContext<'a, '_> { } } ResolvedName::Range(_) => { - diagnostics.add( - name.pos(self.ctx), - "Range cannot be aliased", - ErrorCode::MismatchedKinds, + bail!( + diagnostics, + Diagnostic::new( + name.pos(self.ctx), + "Range cannot be aliased", + ErrorCode::MismatchedKinds + ) ); - return Err(EvalError::Unknown); } } }; From e66fa4feb57e57275fdc66189a01183e9c432554 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Dec 2024 17:59:20 +0100 Subject: [PATCH 06/12] Enable attributes after range type --- vhdl_lang/src/analysis/names.rs | 21 ++++++++++--------- .../src/analysis/tests/resolves_names.rs | 15 +++++++++++++ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index 5396180ce..c7d559dfd 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -313,28 +313,29 @@ impl<'a> ResolvedName<'a> { } pub fn decl_pos(&self) -> Option<&SrcPos> { + use ResolvedName::*; match self { - ResolvedName::Library(_) => None, - ResolvedName::Design(design) => design.decl_pos(), - ResolvedName::Type(typ) => typ.decl_pos(), - ResolvedName::Overloaded(_, names) => names.as_unique().and_then(|it| it.decl_pos()), - ResolvedName::ObjectName(name) => match name.base { + Library(_) => None, + Design(design) => design.decl_pos(), + Type(typ) => typ.decl_pos(), + Overloaded(_, names) => names.as_unique().and_then(|it| it.decl_pos()), + ObjectName(name) => match name.base { ObjectBase::Object(ent) => ent.decl_pos(), ObjectBase::DeferredConstant(ent) | ObjectBase::ObjectAlias(_, ent) => { ent.decl_pos() } ObjectBase::ExternalName(_) => None, }, - ResolvedName::Expression(_) | ResolvedName::Final(_) => None, - ResolvedName::Range(typ) => typ.decl_pos(), + Expression(_) | Final(_) | Range(_) => None, } } fn type_mark(&self) -> Option> { + use ResolvedName::*; match self { - ResolvedName::Type(typ) => Some(*typ), - ResolvedName::ObjectName(oname) => Some(oname.type_mark()), - ResolvedName::Expression(DisambiguatedType::Unambiguous(typ)) => Some(*typ), + Type(typ) | Range(typ) => Some(*typ), + ObjectName(oname) => Some(oname.type_mark()), + Expression(DisambiguatedType::Unambiguous(typ)) => Some(*typ), _ => None, } } diff --git a/vhdl_lang/src/analysis/tests/resolves_names.rs b/vhdl_lang/src/analysis/tests/resolves_names.rs index a9527e8b9..96095d0b6 100644 --- a/vhdl_lang/src/analysis/tests/resolves_names.rs +++ b/vhdl_lang/src/analysis/tests/resolves_names.rs @@ -2185,3 +2185,18 @@ end package; ); check_no_diagnostics(&builder.analyze()) } + +#[test] +fn attribute_after_range() { + let mut builder = LibraryBuilder::new(); + builder.code( + "libname", + r#" +package foo is + constant x: bit_vector(12 downto 0) := "0000000000000"; + constant y: natural := x'range'high; +end package; + "#, + ); + check_no_diagnostics(&builder.analyze()) +} From 1ef4e0a23b50d22a310d44890f62b60f4b4e59db Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Dec 2024 18:46:22 +0100 Subject: [PATCH 07/12] Remove ResolvedName::Range as this should be expressed with a subtype --- vhdl_lang/src/analysis/declarative.rs | 10 --- vhdl_lang/src/analysis/names.rs | 86 +++++++++----------- vhdl_lang/src/analysis/range.rs | 2 +- vhdl_lang/src/analysis/semantic.rs | 3 - vhdl_lang/src/analysis/tests/declarations.rs | 26 ------ vhdl_lang/src/named_entity/design.rs | 1 + vhdl_lang/src/named_entity/overloaded.rs | 1 + vhdl_lang/src/named_entity/types.rs | 1 + 8 files changed, 43 insertions(+), 87 deletions(-) diff --git a/vhdl_lang/src/analysis/declarative.rs b/vhdl_lang/src/analysis/declarative.rs index 903bd632d..ac54cde97 100644 --- a/vhdl_lang/src/analysis/declarative.rs +++ b/vhdl_lang/src/analysis/declarative.rs @@ -350,16 +350,6 @@ impl<'a> AnalyzeContext<'a, '_> { return Err(EvalError::Unknown); } } - ResolvedName::Range(_) => { - bail!( - diagnostics, - Diagnostic::new( - name.pos(self.ctx), - "Range cannot be aliased", - ErrorCode::MismatchedKinds - ) - ); - } } }; diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index c7d559dfd..66d78759f 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -157,7 +157,6 @@ pub enum ResolvedName<'a> { Expression(DisambiguatedType<'a>), // Something that cannot be further selected Final(EntRef<'a>), - Range(TypeEnt<'a>), } impl<'a> ResolvedName<'a> { @@ -293,22 +292,22 @@ impl<'a> ResolvedName<'a> { /// This is used in contexts where the type is not relevant /// Such as when assigning to a constant pub fn describe(&self) -> String { + use ResolvedName::*; match self { - ResolvedName::Library(sym) => format!("library {sym}"), - ResolvedName::Design(ent) => ent.describe(), - ResolvedName::Type(ent) => ent.describe(), - ResolvedName::Overloaded(des, name) => { + Library(sym) => format!("library {sym}"), + Design(ent) => ent.describe(), + Type(ent) => ent.describe(), + Overloaded(des, name) => { if let Some(ent) = name.as_unique() { ent.describe() } else { format!("Overloaded name {des}") } } - ResolvedName::ObjectName(oname) => oname.base.describe(), - ResolvedName::Final(ent) => ent.describe(), - ResolvedName::Expression(DisambiguatedType::Unambiguous(_)) => "Expression".to_owned(), - ResolvedName::Expression(_) => "Ambiguous expression".to_owned(), - ResolvedName::Range(_) => "Range".to_owned(), + ObjectName(oname) => oname.base.describe(), + Final(ent) => ent.describe(), + Expression(DisambiguatedType::Unambiguous(_)) => "Expression".to_owned(), + Expression(_) => "Ambiguous expression".to_owned(), } } @@ -326,14 +325,14 @@ impl<'a> ResolvedName<'a> { } ObjectBase::ExternalName(_) => None, }, - Expression(_) | Final(_) | Range(_) => None, + Expression(_) | Final(_) => None, } } fn type_mark(&self) -> Option> { use ResolvedName::*; match self { - Type(typ) | Range(typ) => Some(*typ), + Type(typ) => Some(*typ), ObjectName(oname) => Some(oname.type_mark()), Expression(DisambiguatedType::Unambiguous(typ)) => Some(*typ), _ => None, @@ -384,22 +383,22 @@ impl<'a> ResolvedName<'a> { Err(EvalError::Unknown) } - // The actual underlying entity + /// Returns the entity that this resolved name represents. + /// For example, when referencing a constant from some other context like + /// `work.some_pkg.some_constant`, the `ResolvedName` is an `ObjectName`. + /// The underlying entity is then the entity representing `some_constant`. fn as_actual_entity(&self) -> Option> { + use ResolvedName::*; match self { - ResolvedName::ObjectName(oname) => match oname.base { + ObjectName(oname) => match oname.base { ObjectBase::Object(obj) => Some(*obj), ObjectBase::ObjectAlias(obj, _) => Some(*obj), ObjectBase::DeferredConstant(ent) => Some(ent), ObjectBase::ExternalName(_) => None, }, - ResolvedName::Type(typ) => Some((*typ).into()), - ResolvedName::Design(des) => Some((*des).into()), - ResolvedName::Library(..) => None, - ResolvedName::Overloaded(_, _) => None, - ResolvedName::Expression(_) => None, - ResolvedName::Final(_) => None, - ResolvedName::Range(typ) => Some((*typ).into()), + Type(typ) => Some((*typ).into()), + Design(des) => Some((*des).into()), + Library(..) | Overloaded(..) | Expression(_) | Final(_) => None, } } } @@ -483,13 +482,12 @@ impl<'a> AnalyzeContext<'a, '_> { name: ResolvedName<'a>, ) -> Result>, Diagnostic> { match name { - ResolvedName::Library(_) - | ResolvedName::Design(_) - | ResolvedName::Type(_) - | ResolvedName::Range(_) => Err(Diagnostic::mismatched_kinds( - pos.pos(self.ctx), - format!("{} cannot be used in an expression", name.describe_type()), - )), + ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => { + Err(Diagnostic::mismatched_kinds( + pos.pos(self.ctx), + format!("{} cannot be used in an expression", name.describe_type()), + )) + } ResolvedName::Final(ent) => match ent.actual_kind() { AnyEntKind::LoopParameter(typ) => { Ok(typ.map(|typ| DisambiguatedType::Unambiguous(typ.into()))) @@ -532,13 +530,12 @@ impl<'a> AnalyzeContext<'a, '_> { suffix_ref: Option<&mut Reference>, ) -> Result>, Diagnostic> { match name { - ResolvedName::Library(_) - | ResolvedName::Design(_) - | ResolvedName::Type(_) - | ResolvedName::Range(_) => Err(Diagnostic::mismatched_kinds( - span.pos(self.ctx), - format!("{} cannot be used in an expression", name.describe_type()), - )), + ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => { + Err(Diagnostic::mismatched_kinds( + span.pos(self.ctx), + format!("{} cannot be used in an expression", name.describe_type()), + )) + } ResolvedName::Final(ent) => match ent.actual_kind() { AnyEntKind::LoopParameter(typ) => Ok(typ.map(|typ| typ.into())), AnyEntKind::PhysicalLiteral(typ) => Ok(Some(*typ)), @@ -577,9 +574,12 @@ impl<'a> AnalyzeContext<'a, '_> { /// An array type may be sliced with a type name /// For the parser this looks like a call or indexed name - /// Example: + /// + /// # Example: + /// ```vhdl /// subtype sub_t is natural range 0 to 1; /// arr(sub_t) := (others => 0); + /// ``` fn assoc_as_discrete_range_type( &self, scope: &Scope<'a>, @@ -1075,8 +1075,8 @@ impl<'a> AnalyzeContext<'a, '_> { } } AttributeDesignator::Range(_) => match prefix { - ResolvedName::Type(typ) => Ok(ResolvedName::Range(*typ)), - ResolvedName::ObjectName(oname) => Ok(ResolvedName::Range(oname.type_mark())), + ResolvedName::Type(typ) => Ok(ResolvedName::Type(*typ)), + ResolvedName::ObjectName(oname) => Ok(ResolvedName::Type(oname.type_mark())), _ => { diagnostics.add( name_pos.pos(self.ctx), @@ -1537,12 +1537,6 @@ impl<'a> AnalyzeContext<'a, '_> { return Err(EvalError::Unknown); } } - ResolvedName::Range(_) => { - bail!( - diagnostics, - Diagnostic::cannot_be_prefix(&span.pos(self.ctx), resolved, suffix) - ); - } ResolvedName::Type(typ) => match suffix { Suffix::Selected(selected) => { let typed_selection = match typ.selected(self.ctx, prefix.span, selected) { @@ -1610,8 +1604,7 @@ impl<'a> AnalyzeContext<'a, '_> { | ResolvedName::Type(_) | ResolvedName::Overloaded { .. } | ResolvedName::Expression(_) - | ResolvedName::Final(_) - | ResolvedName::Range(_) => { + | ResolvedName::Final(_) => { diagnostics.add( name_pos.pos(self.ctx), format!("{} {}", resolved.describe(), err_msg), @@ -1637,7 +1630,6 @@ impl<'a> AnalyzeContext<'a, '_> { | ResolvedName::ObjectName(_) | ResolvedName::Overloaded { .. } | ResolvedName::Expression(_) - | ResolvedName::Range(_) | ResolvedName::Final(_) => { bail!( diagnostics, diff --git a/vhdl_lang/src/analysis/range.rs b/vhdl_lang/src/analysis/range.rs index 1af63cfea..8adacbd5f 100644 --- a/vhdl_lang/src/analysis/range.rs +++ b/vhdl_lang/src/analysis/range.rs @@ -81,7 +81,7 @@ impl<'a> AnalyzeContext<'a, '_> { let resolved = self.name_resolve(scope, attr.name.span, &mut attr.name.item, diagnostics)?; let typ = match resolved { - ResolvedName::Type(typ) | ResolvedName::Range(typ) => typ, + ResolvedName::Type(typ) => typ, ResolvedName::ObjectName(oname) => oname.type_mark(), ResolvedName::Overloaded(ref des, ref overloaded) => { let disamb = self diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index dcc154910..f941ad489 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -60,9 +60,6 @@ impl<'a> AnalyzeContext<'a, '_> { as_fatal(self.name_resolve(scope, choice.span, name, diagnostics))? { match resolved_name { - ResolvedName::Range(typ) => { - self.check_resolved_name(ttyp, typ, diagnostics, choice) - } ResolvedName::Type(typ) => { if !matches!(typ.kind(), Type::Subtype(_)) { diagnostics.add( diff --git a/vhdl_lang/src/analysis/tests/declarations.rs b/vhdl_lang/src/analysis/tests/declarations.rs index 7ceff0c5a..fbca954aa 100644 --- a/vhdl_lang/src/analysis/tests/declarations.rs +++ b/vhdl_lang/src/analysis/tests/declarations.rs @@ -100,29 +100,3 @@ end entity test; )], ) } - -#[test] -fn aliases_of_ranges() { - let mut builder = LibraryBuilder::new(); - let code = builder.code( - "libname", - "\ -entity foo is -end foo; - -architecture arch of foo is - constant x: bit_vector(12 downto 0) := \"000000000000\"; - alias x_range is x'range; -begin -end arch; - ", - ); - check_diagnostics( - builder.analyze(), - vec![Diagnostic::new( - code.s1("x'range"), - "Range cannot be aliased", - ErrorCode::MismatchedKinds, - )], - ) -} diff --git a/vhdl_lang/src/named_entity/design.rs b/vhdl_lang/src/named_entity/design.rs index 802d43254..929b741af 100644 --- a/vhdl_lang/src/named_entity/design.rs +++ b/vhdl_lang/src/named_entity/design.rs @@ -13,6 +13,7 @@ use crate::ast::WithRef; use crate::named_entity::visibility::Visibility; use crate::Diagnostic; +#[derive(Clone)] pub enum Design<'a> { Entity(Visibility<'a>, Region<'a>), /// A VHDL architecture. diff --git a/vhdl_lang/src/named_entity/overloaded.rs b/vhdl_lang/src/named_entity/overloaded.rs index 5bd0d17d9..ed010be8d 100644 --- a/vhdl_lang/src/named_entity/overloaded.rs +++ b/vhdl_lang/src/named_entity/overloaded.rs @@ -7,6 +7,7 @@ use super::*; use crate::ast::Designator; use std::fmt::{Debug, Formatter}; +#[derive(Clone)] pub enum Overloaded<'a> { /// A subprogram declaration (meaning: without implementation). SubprogramDecl(Signature<'a>), diff --git a/vhdl_lang/src/named_entity/types.rs b/vhdl_lang/src/named_entity/types.rs index 4386ec36d..48f3f47dc 100644 --- a/vhdl_lang/src/named_entity/types.rs +++ b/vhdl_lang/src/named_entity/types.rs @@ -14,6 +14,7 @@ use fnv::FnvHashSet; use super::{Arena, EntRef, Related}; +#[derive(Clone)] pub enum Type<'a> { // Some types have an optional list of implicit declarations // Use Weak reference since implicit declaration typically reference the type itself From 0355e550d349297861050ed3dae177e8aefc0cd7 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Dec 2024 18:54:50 +0100 Subject: [PATCH 08/12] choices likely do not have to be subtypes --- vhdl_lang/src/analysis/semantic.rs | 10 +--------- vhdl_lang/src/analysis/tests/discrete_ranges.rs | 6 +----- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index f941ad489..1844c83c4 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -61,15 +61,7 @@ impl<'a> AnalyzeContext<'a, '_> { { match resolved_name { ResolvedName::Type(typ) => { - if !matches!(typ.kind(), Type::Subtype(_)) { - diagnostics.add( - choice.pos(self.ctx), - format!("{} must be a subtype", typ.describe(),), - ErrorCode::MismatchedKinds, - ) - } else { - self.check_resolved_name(ttyp, typ, diagnostics, choice) - } + self.check_resolved_name(ttyp, typ, diagnostics, choice) } _ => { if let Some(ttyp) = ttyp { diff --git a/vhdl_lang/src/analysis/tests/discrete_ranges.rs b/vhdl_lang/src/analysis/tests/discrete_ranges.rs index f4b002007..b6c965ef2 100644 --- a/vhdl_lang/src/analysis/tests/discrete_ranges.rs +++ b/vhdl_lang/src/analysis/tests/discrete_ranges.rs @@ -25,6 +25,7 @@ begin when t_my_enum_range => null; when t_my_enum_range'range => null; when A1 to A2 => null; + when ty_my_enum => null; when others => null; end case; end process; @@ -78,11 +79,6 @@ end architecture; "subtype 't_my_other_enum_range' does not match type 't_my_enum'", ErrorCode::TypeMismatch, ), - Diagnostic::new( - code.s("t_my_enum", 3), - "type 't_my_enum' must be a subtype", - ErrorCode::MismatchedKinds, - ), ], ); } From 940efc70995321968b9a44a977517358acf048bb Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Sun, 8 Dec 2024 18:57:39 +0100 Subject: [PATCH 09/12] fix typo --- vhdl_lang/src/analysis/tests/discrete_ranges.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdl_lang/src/analysis/tests/discrete_ranges.rs b/vhdl_lang/src/analysis/tests/discrete_ranges.rs index b6c965ef2..915fe4bd8 100644 --- a/vhdl_lang/src/analysis/tests/discrete_ranges.rs +++ b/vhdl_lang/src/analysis/tests/discrete_ranges.rs @@ -25,7 +25,7 @@ begin when t_my_enum_range => null; when t_my_enum_range'range => null; when A1 to A2 => null; - when ty_my_enum => null; + when t_my_enum => null; when others => null; end case; end process; From fc66a8154f9c582fc46eb9b4275cf7186de92b83 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Mon, 9 Dec 2024 10:01:15 +0100 Subject: [PATCH 10/12] Simplification --- vhdl_lang/src/analysis/expression.rs | 50 +++++++++++++++------------- vhdl_lang/src/analysis/semantic.rs | 38 +++++++++------------ 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/vhdl_lang/src/analysis/expression.rs b/vhdl_lang/src/analysis/expression.rs index 3ac88aadc..3be320ef5 100644 --- a/vhdl_lang/src/analysis/expression.rs +++ b/vhdl_lang/src/analysis/expression.rs @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2024, Lukas Scheller lukasscheller@icloud.com + */ + //! This Source Code Form is subject to the terms of the Mozilla Public //! License, v. 2.0. If a copy of the MPL was not distributed with this file, //! You can obtain one at http://mozilla.org/MPL/2.0/. @@ -213,6 +221,22 @@ impl<'a, 't> AnalyzeContext<'a, 't> { self.any_matcher().can_be_target_type(typ, ttyp) } + pub fn check_type_mismatch( + &self, + typ: TypeEnt<'a>, + ttyp: TypeEnt<'a>, + pos: TokenSpan, + diagnostics: &mut dyn DiagnosticHandler, + ) { + if !self.can_be_target_type(typ, ttyp.base()) { + diagnostics.push(Diagnostic::type_mismatch( + &pos.pos(self.ctx), + &typ.describe(), + ttyp, + )); + } + } + pub fn expr_unknown_ttyp( &self, scope: &Scope<'a>, @@ -741,13 +765,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { if let Some(type_mark) = as_fatal(self.analyze_qualified_expression(scope, qexpr, diagnostics))? { - if !self.can_be_target_type(type_mark, target_base.base()) { - diagnostics.push(Diagnostic::type_mismatch( - &span.pos(self.ctx), - &type_mark.describe(), - target_type, - )); - } + self.check_type_mismatch(type_mark, target_type, span, diagnostics); } } Expression::Binary(ref mut op, ref mut left, ref mut right) => { @@ -772,14 +790,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { ))? { Some(Disambiguated::Unambiguous(overloaded)) => { let op_type = overloaded.return_type().unwrap(); - - if !self.can_be_target_type(op_type, target_type.base()) { - diagnostics.push(Diagnostic::type_mismatch( - &span.pos(self.ctx), - &op_type.describe(), - target_type, - )); - } + self.check_type_mismatch(op_type, target_type, span, diagnostics); } Some(Disambiguated::Ambiguous(candidates)) => { diagnostics.push(Diagnostic::ambiguous_op( @@ -815,14 +826,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { ))? { Some(Disambiguated::Unambiguous(overloaded)) => { let op_type = overloaded.return_type().unwrap(); - - if !self.can_be_target_type(op_type, target_type.base()) { - diagnostics.push(Diagnostic::type_mismatch( - &span.pos(self.ctx), - &op_type.describe(), - target_type, - )); - } + self.check_type_mismatch(op_type, target_type, span, diagnostics); } Some(Disambiguated::Ambiguous(candidates)) => { diagnostics.push(Diagnostic::ambiguous_op( diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index 1844c83c4..20f81eb16 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -1,3 +1,11 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2024, Lukas Scheller lukasscheller@icloud.com + */ + //! This Source Code Form is subject to the terms of the Mozilla Public //! License, v. 2.0. If a copy of the MPL was not distributed with this file, //! You can obtain one at http://mozilla.org/MPL/2.0/. @@ -22,28 +30,9 @@ impl<'a> AnalyzeContext<'a, '_> { choices: &mut [WithTokenSpan], diagnostics: &mut dyn DiagnosticHandler, ) -> FatalResult { - for choice in choices.iter_mut() { - self.choice_with_ttyp(scope, ttyp, choice, diagnostics)?; - } - Ok(()) - } - - fn check_resolved_name( - &self, - ttyp: Option>, - typ: TypeEnt<'a>, - diagnostics: &mut dyn DiagnosticHandler, - pos: &WithTokenSpan, - ) { - if let Some(ttyp) = ttyp { - if !self.can_be_target_type(typ, ttyp.base()) { - diagnostics.push(Diagnostic::type_mismatch( - &pos.pos(self.ctx), - &typ.describe(), - ttyp, - )); - } - } + choices + .iter_mut() + .try_for_each(|choice| self.choice_with_ttyp(scope, ttyp, choice, diagnostics)) } pub fn choice_with_ttyp( @@ -55,13 +44,16 @@ impl<'a> AnalyzeContext<'a, '_> { ) -> FatalResult { match choice.item { Choice::Expression(ref mut expr) => { + // Check any names like `typ'range` before checking for any expressions if let Expression::Name(name) = expr { if let Some(resolved_name) = as_fatal(self.name_resolve(scope, choice.span, name, diagnostics))? { match resolved_name { ResolvedName::Type(typ) => { - self.check_resolved_name(ttyp, typ, diagnostics, choice) + if let Some(ttyp) = ttyp { + self.check_type_mismatch(typ, ttyp, choice.span, diagnostics); + } } _ => { if let Some(ttyp) = ttyp { From a4e0325da047b83ea8bca5650ddd63d4416f2d26 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Mon, 9 Dec 2024 10:12:14 +0100 Subject: [PATCH 11/12] Remove erroneous Copyright header --- vhdl_lang/src/analysis/expression.rs | 8 -------- vhdl_lang/src/analysis/semantic.rs | 8 -------- 2 files changed, 16 deletions(-) diff --git a/vhdl_lang/src/analysis/expression.rs b/vhdl_lang/src/analysis/expression.rs index 3be320ef5..de2509400 100644 --- a/vhdl_lang/src/analysis/expression.rs +++ b/vhdl_lang/src/analysis/expression.rs @@ -1,11 +1,3 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright (c) 2024, Lukas Scheller lukasscheller@icloud.com - */ - //! This Source Code Form is subject to the terms of the Mozilla Public //! License, v. 2.0. If a copy of the MPL was not distributed with this file, //! You can obtain one at http://mozilla.org/MPL/2.0/. diff --git a/vhdl_lang/src/analysis/semantic.rs b/vhdl_lang/src/analysis/semantic.rs index 20f81eb16..b94cf71b4 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -1,11 +1,3 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright (c) 2024, Lukas Scheller lukasscheller@icloud.com - */ - //! This Source Code Form is subject to the terms of the Mozilla Public //! License, v. 2.0. If a copy of the MPL was not distributed with this file, //! You can obtain one at http://mozilla.org/MPL/2.0/. From a27d2587dba3083bbbb3e96b9c6360f988b11359 Mon Sep 17 00:00:00 2001 From: Lukas Scheller Date: Mon, 9 Dec 2024 10:14:29 +0100 Subject: [PATCH 12/12] Omit theoretically working case statement in test that should fail --- vhdl_lang/src/analysis/tests/discrete_ranges.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/vhdl_lang/src/analysis/tests/discrete_ranges.rs b/vhdl_lang/src/analysis/tests/discrete_ranges.rs index 915fe4bd8..a5e88d4ad 100644 --- a/vhdl_lang/src/analysis/tests/discrete_ranges.rs +++ b/vhdl_lang/src/analysis/tests/discrete_ranges.rs @@ -58,7 +58,6 @@ begin case my_sig_sub is when t_my_other_enum'range => null; when t_my_other_enum_range => null; - when t_my_enum => null; when others => null; end case; end process;