diff --git a/vhdl_lang/src/analysis/names.rs b/vhdl_lang/src/analysis/names.rs index 10339a94..d3b94892 100644 --- a/vhdl_lang/src/analysis/names.rs +++ b/vhdl_lang/src/analysis/names.rs @@ -1506,8 +1506,25 @@ impl<'a, 't> AnalyzeContext<'a, 't> { return Err(EvalError::Unknown); } } - ResolvedName::Type(typ) => { - if let Suffix::CallOrIndexed(ref mut assocs) = suffix { + ResolvedName::Type(typ) => match suffix { + Suffix::Selected(selected) => { + let typed_selection = match typ.selected(self.ctx, prefix.span, selected) { + Ok(typed_selection) => typed_selection, + Err(diagnostic) => { + bail!(diagnostics, diagnostic); + } + }; + return Ok(match typed_selection { + TypedSelection::RecordElement(element) => { + ResolvedName::Type(element.type_mark()) + } + TypedSelection::ProtectedMethod(method) => ResolvedName::Overloaded( + selected.clone().map_into(|desi| desi.item), + method, + ), + }); + } + Suffix::CallOrIndexed(ref mut assocs) => { if let Some((expr_pos, expr)) = as_type_conversion(assocs) { self.check_type_conversion(scope, typ, expr_pos, expr, diagnostics)?; return Ok(ResolvedName::Expression(DisambiguatedType::Unambiguous( @@ -1515,14 +1532,13 @@ impl<'a, 't> AnalyzeContext<'a, 't> { ))); } } - - diagnostics.push(Diagnostic::cannot_be_prefix( - &span.pos(self.ctx), - resolved, - suffix, - )); - return Err(EvalError::Unknown); - } + _ => { + bail!( + diagnostics, + Diagnostic::cannot_be_prefix(&span.pos(self.ctx), resolved, suffix) + ); + } + }, ResolvedName::Final(_) => { diagnostics.push(Diagnostic::cannot_be_prefix( &span.pos(self.ctx), @@ -1535,6 +1551,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> { Ok(resolved) } + // Helper function: // Resolve a name that must be some kind of object selection, index or slice // Such names occur as assignment targets and aliases diff --git a/vhdl_lang/src/analysis/tests/resolves_names.rs b/vhdl_lang/src/analysis/tests/resolves_names.rs index 7b0a18d2..a9527e8b 100644 --- a/vhdl_lang/src/analysis/tests/resolves_names.rs +++ b/vhdl_lang/src/analysis/tests/resolves_names.rs @@ -2163,3 +2163,25 @@ end package;", let (_root, diagnostics) = builder.get_analyzed_root(); check_no_diagnostics(&diagnostics); } + +#[test] +pub fn resolve_selected_names_of_types() { + let mut builder = LibraryBuilder::new(); + builder.code( + "libname", + "\ +package foo is + type test_t is record + asdf: bit_vector(10 downto 0); + end record; + + signal a: integer := test_t.asdf'high; + signal b: bit_vector(test_t.asdf'high downto test_t.asdf'low); + signal c: bit_vector(test_t.asdf'range); + signal d: integer := test_t.asdf'high; + signal e: bit_vector(test_t.asdf'range); +end package; + ", + ); + check_no_diagnostics(&builder.analyze()) +} diff --git a/vhdl_lang/src/syntax/tokens/tokenizer.rs b/vhdl_lang/src/syntax/tokens/tokenizer.rs index d9e8bdb9..91d69143 100644 --- a/vhdl_lang/src/syntax/tokens/tokenizer.rs +++ b/vhdl_lang/src/syntax/tokens/tokenizer.rs @@ -357,12 +357,14 @@ macro_rules! expect_token { /// Unlike the try_token_kind this macro gives errors always on the next token /// Example: /// +/// ```vhdl /// entity ent is /// end entity; /// ~ <- error should not be here /// /// foo /// ~~~ <- error should be here +/// ``` #[macro_export] macro_rules! try_init_token_kind { ($token:expr, $($($kind:ident)|+ => $result:expr),*) => { diff --git a/vhdl_lang/src/syntax/tokens/tokenstream.rs b/vhdl_lang/src/syntax/tokens/tokenstream.rs index d657206b..2e9892a6 100644 --- a/vhdl_lang/src/syntax/tokens/tokenstream.rs +++ b/vhdl_lang/src/syntax/tokens/tokenstream.rs @@ -143,10 +143,12 @@ impl<'a> TokenStream<'a> { /// A position that aligns with the previous token /// /// Example: + /// ```vhdl /// signal sig : natural /// ~ <- want semi colon error here /// signal /// ~~~~~~ <- not here + /// ``` pub fn pos_before(&self, token: &Token) -> SrcPos { if let Some(prev_token) = self.token_before(token) { let prev_pos = prev_token.pos.end();