diff --git a/vhdl_lang/src/analysis/assignment.rs b/vhdl_lang/src/analysis/assignment.rs index 940ade676..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( @@ -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/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 f1f684d24..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>, @@ -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..ac54cde97 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 afc873150..de2509400 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) { @@ -213,6 +213,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>, @@ -684,7 +700,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 +713,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, ); @@ -741,13 +757,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 +782,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 +818,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/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 239e92986..66d78759f 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -292,46 +292,49 @@ 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(), + ObjectName(oname) => oname.base.describe(), + Final(ent) => ent.describe(), + Expression(DisambiguatedType::Unambiguous(_)) => "Expression".to_owned(), + Expression(_) => "Ambiguous expression".to_owned(), } } 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, + Expression(_) | Final(_) => 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) => Some(*typ), + ObjectName(oname) => Some(oname.type_mark()), + Expression(DisambiguatedType::Unambiguous(typ)) => Some(*typ), _ => None, } } @@ -380,21 +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, + Type(typ) => Some((*typ).into()), + Design(des) => Some((*des).into()), + Library(..) | Overloaded(..) | Expression(_) | Final(_) => None, } } } @@ -469,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, @@ -517,7 +521,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>, @@ -570,9 +574,12 @@ impl<'a, 't> AnalyzeContext<'a, 't> { /// 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>, @@ -1067,14 +1074,18 @@ 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::Type(*typ)), + ResolvedName::ObjectName(oname) => Ok(ResolvedName::Type(oname.type_mark())), + _ => { + 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())), @@ -1708,25 +1719,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 @@ -3075,30 +3095,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 cannot be used as an expression", - ErrorCode::MismatchedKinds, - )], - ) - } - #[test] fn name_attributes() { let test = TestSetup::new(); 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 f2e4119f2..8adacbd5f 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 4407df034..b94cf71b4 100644 --- a/vhdl_lang/src/analysis/semantic.rs +++ b/vhdl_lang/src/analysis/semantic.rs @@ -14,32 +14,66 @@ use crate::data::error_codes::ErrorCode; use crate::data::*; use crate::named_entity::*; -impl<'a, 't> AnalyzeContext<'a, 't> { - pub fn choice_with_ttyp( +impl<'a> AnalyzeContext<'a, '_> { + pub fn choices_with_ttyp( &self, scope: &Scope<'a>, ttyp: Option>, choices: &mut [WithTokenSpan], 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)?; + choices + .iter_mut() + .try_for_each(|choice| self.choice_with_ttyp(scope, ttyp, choice, diagnostics)) + } + + 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) => { + // 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) => { + if let Some(ttyp) = ttyp { + self.check_type_mismatch(typ, ttyp, choice.span, diagnostics); + } + } + _ => { + 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 +214,7 @@ impl Diagnostic { } } - pub fn add_type_candididates<'a>( + pub fn add_type_candidates<'a>( &mut self, prefix: &str, candidates: impl IntoIterator>, @@ -196,7 +230,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 795c436bf..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>, @@ -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/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/discrete_ranges.rs b/vhdl_lang/src/analysis/tests/discrete_ranges.rs new file mode 100644 index 000000000..a5e88d4ad --- /dev/null +++ b/vhdl_lang/src/analysis/tests/discrete_ranges.rs @@ -0,0 +1,83 @@ +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 t_my_enum => 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 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, + ), + ], + ); +} 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/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; 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()) +} 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 376390a52..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) } } @@ -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/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..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. @@ -37,7 +38,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..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>), @@ -25,7 +26,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..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 @@ -45,7 +46,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/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(), + } + )) } ); } 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) }