Skip to content

Commit c068d3f

Browse files
committed
Rework type mark to support 'subtype. Issue #123
1 parent 859f5aa commit c068d3f

File tree

16 files changed

+379
-140
lines changed

16 files changed

+379
-140
lines changed

vhdl_lang/src/analysis/concurrent.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl<'a> AnalyzeContext<'a> {
198198
if let Err(err) =
199199
self.resolve_selected_name(parent, entity_name)
200200
.and_then(|entities| {
201-
self.resolve_non_overloaded(
201+
self.resolve_non_overloaded_with_kind(
202202
entities,
203203
entity_name.suffix_pos(),
204204
&is_entity,
@@ -217,7 +217,7 @@ impl<'a> AnalyzeContext<'a> {
217217
if let Err(err) =
218218
self.resolve_selected_name(parent, component_name)
219219
.and_then(|entities| {
220-
self.resolve_non_overloaded(
220+
self.resolve_non_overloaded_with_kind(
221221
entities,
222222
component_name.suffix_pos(),
223223
&is_component,
@@ -236,7 +236,7 @@ impl<'a> AnalyzeContext<'a> {
236236
if let Err(err) =
237237
self.resolve_selected_name(parent, config_name)
238238
.and_then(|entities| {
239-
self.resolve_non_overloaded(
239+
self.resolve_non_overloaded_with_kind(
240240
entities,
241241
config_name.suffix_pos(),
242242
&is_configuration,

vhdl_lang/src/analysis/declarative.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,7 @@ impl<'a> AnalyzeContext<'a> {
682682
}
683683

684684
TypeDefinition::File(ref mut type_mark) => {
685-
if let Err(err) = self.resolve_type_mark(parent, type_mark) {
685+
if let Err(err) = self.resolve_type_mark_name(parent, type_mark) {
686686
err.add_to(diagnostics)?;
687687
}
688688

@@ -836,15 +836,15 @@ impl<'a> AnalyzeContext<'a> {
836836
ast::Signature::Function(ref mut args, ref mut ret) => {
837837
let args: Vec<_> = args
838838
.iter_mut()
839-
.map(|arg| self.resolve_type_mark(region, arg))
839+
.map(|arg| self.resolve_type_mark_name(region, arg))
840840
.collect();
841-
let return_type = self.resolve_type_mark(region, ret);
841+
let return_type = self.resolve_type_mark_name(region, ret);
842842
(args, Some(return_type))
843843
}
844844
ast::Signature::Procedure(args) => {
845845
let args: Vec<_> = args
846846
.iter_mut()
847-
.map(|arg| self.resolve_type_mark(region, arg))
847+
.map(|arg| self.resolve_type_mark_name(region, arg))
848848
.collect();
849849
(args, None)
850850
}
@@ -999,7 +999,7 @@ impl<'a> AnalyzeContext<'a> {
999999
) -> FatalNullResult {
10001000
match array_index {
10011001
ArrayIndex::IndexSubtypeDefintion(ref mut type_mark) => {
1002-
if let Err(err) = self.resolve_type_mark(region, type_mark) {
1002+
if let Err(err) = self.resolve_type_mark_name(region, type_mark) {
10031003
err.add_to(diagnostics)?;
10041004
}
10051005
}
@@ -1091,7 +1091,7 @@ impl<'a> AnalyzeContext<'a> {
10911091
SubprogramDeclaration::Function(fun) => {
10921092
let params =
10931093
self.analyze_parameter_list(region, &mut fun.parameter_list, diagnostics);
1094-
let return_type = self.resolve_type_mark(region, &mut fun.return_type);
1094+
let return_type = self.resolve_type_mark_name(region, &mut fun.return_type);
10951095
Ok(Signature::new(params?, Some(return_type?)))
10961096
}
10971097
SubprogramDeclaration::Procedure(procedure) => {

vhdl_lang/src/analysis/semantic.rs

Lines changed: 73 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -208,55 +208,78 @@ impl<'a> AnalyzeContext<'a> {
208208
}
209209
}
210210

211-
pub fn resolve_non_overloaded(
211+
pub fn resolve_non_overloaded_with_kind(
212212
&self,
213213
named_entities: NamedEntities,
214214
pos: &SrcPos,
215215
kind_ok: &impl Fn(&NamedEntityKind) -> bool,
216216
expected: &str,
217217
) -> AnalysisResult<Arc<NamedEntity>> {
218-
match named_entities.into_non_overloaded() {
219-
Ok(ent) => {
220-
if kind_ok(ent.actual_kind()) {
221-
Ok(ent)
222-
} else {
223-
let mut error = Diagnostic::error(
224-
pos,
225-
format!("Expected {}, got {}", expected, ent.describe()),
226-
);
227-
if let Some(decl_pos) = ent.decl_pos() {
228-
error.add_related(decl_pos, "Defined here");
229-
}
230-
Err(AnalysisError::NotFatal(error))
231-
}
232-
}
233-
Err(overloaded) => {
234-
let mut error =
235-
Diagnostic::error(pos, format!("Expected {}, got overloaded name", expected));
236-
for ent in overloaded.entities() {
237-
if let Some(decl_pos) = ent.decl_pos() {
238-
error.add_related(decl_pos, "Defined here");
239-
}
218+
let ent = self.resolve_non_overloaded(named_entities, pos, expected)?;
219+
if kind_ok(ent.actual_kind()) {
220+
Ok(ent)
221+
} else {
222+
Err(AnalysisError::NotFatal(ent.kind_error(pos, expected)))
223+
}
224+
}
225+
226+
pub fn resolve_non_overloaded(
227+
&self,
228+
named_entities: NamedEntities,
229+
pos: &SrcPos,
230+
expected: &str,
231+
) -> AnalysisResult<Arc<NamedEntity>> {
232+
named_entities.into_non_overloaded().map_err(|overloaded| {
233+
let mut error =
234+
Diagnostic::error(pos, format!("Expected {}, got overloaded name", expected));
235+
for ent in overloaded.entities() {
236+
if let Some(decl_pos) = ent.decl_pos() {
237+
error.add_related(decl_pos, "Defined here");
240238
}
241-
Err(AnalysisError::NotFatal(error))
242239
}
243-
}
240+
AnalysisError::NotFatal(error)
241+
})
244242
}
245243

246-
pub fn resolve_type_mark(
244+
pub fn resolve_type_mark_name(
247245
&self,
248246
region: &Region<'_>,
249247
type_mark: &mut WithPos<SelectedName>,
250248
) -> AnalysisResult<Arc<NamedEntity>> {
251249
let entities = self.resolve_selected_name(region, type_mark)?;
252-
self.resolve_non_overloaded(
250+
self.resolve_non_overloaded_with_kind(
253251
entities,
254252
type_mark.suffix_pos(),
255253
&NamedEntityKind::is_type,
256254
"type",
257255
)
258256
}
259257

258+
pub fn resolve_type_mark(
259+
&self,
260+
region: &Region<'_>,
261+
type_mark: &mut WithPos<TypeMark>,
262+
) -> AnalysisResult<Arc<NamedEntity>> {
263+
if !type_mark.item.subtype {
264+
self.resolve_type_mark_name(region, &mut type_mark.item.name)
265+
} else {
266+
let entities = self.resolve_selected_name(region, &mut type_mark.item.name)?;
267+
268+
let pos = type_mark.item.name.suffix_pos();
269+
let expected = "object or alias";
270+
let named_entity = self.resolve_non_overloaded(entities, pos, expected)?;
271+
272+
match named_entity.kind() {
273+
NamedEntityKind::Object(obj) => Ok(obj.subtype.type_mark().clone()),
274+
NamedEntityKind::ObjectAlias { type_mark, .. } => Ok(type_mark.clone()),
275+
NamedEntityKind::ElementDeclaration(subtype) => Ok(subtype.type_mark().clone()),
276+
_ => Err(AnalysisError::NotFatal(
277+
named_entity.kind_error(pos, expected),
278+
)),
279+
}
280+
}
281+
}
282+
260283
fn analyze_attribute_name(
261284
&self,
262285
region: &Region<'_>,
@@ -310,7 +333,7 @@ impl<'a> AnalyzeContext<'a> {
310333
) -> FatalNullResult {
311334
match drange {
312335
DiscreteRange::Discrete(ref mut type_mark, ref mut range) => {
313-
if let Err(err) = self.resolve_type_mark(region, type_mark) {
336+
if let Err(err) = self.resolve_type_mark_name(region, type_mark) {
314337
err.add_to(diagnostics)?;
315338
}
316339
if let Some(ref mut range) = range {
@@ -438,28 +461,15 @@ impl<'a> AnalyzeContext<'a> {
438461
qexpr: &mut QualifiedExpression,
439462
diagnostics: &mut dyn DiagnosticHandler,
440463
) -> FatalNullResult {
441-
let QualifiedExpression { name, expr } = qexpr;
442-
let entities = self.resolve_name(region, &name.pos, &mut name.item, diagnostics)?;
443-
444-
if let Some(entities) = entities {
445-
match self.resolve_non_overloaded(
446-
entities,
447-
&name.pos,
448-
&NamedEntityKind::is_type,
449-
"type",
450-
) {
451-
Ok(target_type) => {
452-
self.analyze_expression_with_target_type(
453-
region,
454-
&target_type,
455-
expr,
456-
diagnostics,
457-
)?;
458-
return Ok(());
459-
}
460-
Err(err) => {
461-
err.add_to(diagnostics)?;
462-
}
464+
let QualifiedExpression { type_mark, expr } = qexpr;
465+
466+
match self.resolve_type_mark(region, type_mark) {
467+
Ok(target_type) => {
468+
self.analyze_expression_with_target_type(region, &target_type, expr, diagnostics)?;
469+
return Ok(());
470+
}
471+
Err(e) => {
472+
e.add_to(diagnostics)?;
463473
}
464474
}
465475

@@ -963,6 +973,19 @@ fn ambiguous_overloaded_type(
963973
diagnostic
964974
}
965975

976+
impl NamedEntity {
977+
fn kind_error(&self, pos: &SrcPos, expected: &str) -> Diagnostic {
978+
let mut error = Diagnostic::error(
979+
pos,
980+
format!("Expected {}, got {}", expected, self.describe()),
981+
);
982+
if let Some(decl_pos) = self.decl_pos() {
983+
error.add_related(decl_pos, "Defined here");
984+
}
985+
error
986+
}
987+
}
988+
966989
fn overloaded_type_mismatch(pos: &SrcPos, name: &Name, expected_type: &NamedEntity) -> Diagnostic {
967990
Diagnostic::error(
968991
pos,

vhdl_lang/src/analysis/tests/resolves_type_mark.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,28 @@ constant foo : natural := bar'(0);
404404
}
405405

406406
#[test]
407-
fn error_on_type_mark_ok() {
407+
fn test_type_mark_with_subtype_attribute_is_ok() {
408+
let mut builder = LibraryBuilder::new();
409+
builder.in_declarative_region(
410+
"
411+
signal sig0 : integer_vector(0 to 7);
412+
413+
type rec_t is record
414+
field: integer_vector(0 to 7);
415+
end record;
416+
signal rec : rec_t;
417+
418+
attribute attr : sig0'subtype;
419+
signal sig1 : sig0'subtype;
420+
signal sig2 : rec.field'subtype;
421+
",
422+
);
423+
let diagnostics = builder.analyze();
424+
check_no_diagnostics(&diagnostics);
425+
}
426+
427+
#[test]
428+
fn check_good_type_marks() {
408429
check_code_with_no_diagnostics(
409430
"
410431
package gpkg is

vhdl_lang/src/analysis/tests/typecheck_expression.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,23 @@ constant bar : natural := foo(arg => 0);
347347
)],
348348
);
349349
}
350+
351+
#[test]
352+
fn test_typechecks_expression_for_type_mark_with_subtype_attribute() {
353+
let mut builder = LibraryBuilder::new();
354+
let code = builder.in_declarative_region(
355+
"
356+
signal sig0 : integer_vector(0 to 7);
357+
signal sig1 : sig0'subtype := false;
358+
signal sig2 : sig0'subtype := (others => 0); -- ok
359+
",
360+
);
361+
let diagnostics = builder.analyze();
362+
check_diagnostics(
363+
diagnostics,
364+
vec![Diagnostic::error(
365+
code.s1("false"),
366+
"'false' does not match array type 'INTEGER_VECTOR'",
367+
)],
368+
);
369+
}

vhdl_lang/src/ast.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ pub enum Allocator {
235235
/// LRM 9.3.5 Qualified expressions
236236
#[derive(PartialEq, Debug, Clone)]
237237
pub struct QualifiedExpression {
238-
pub name: Box<WithPos<Name>>,
239-
pub expr: Box<WithPos<Expression>>,
238+
pub type_mark: WithPos<TypeMark>,
239+
pub expr: WithPos<Expression>,
240240
}
241241

242242
/// LRM 9. Expressions
@@ -326,11 +326,18 @@ pub enum ResolutionIndication {
326326
Unresolved,
327327
}
328328

329+
#[derive(PartialEq, Debug, Clone)]
330+
pub struct TypeMark {
331+
pub name: WithPos<SelectedName>,
332+
// Is the 'subtype attribute of the selected name
333+
pub subtype: bool,
334+
}
335+
329336
/// LRM 6.3 Subtype declarations
330337
#[derive(PartialEq, Debug, Clone)]
331338
pub struct SubtypeIndication {
332339
pub resolution: ResolutionIndication,
333-
pub type_mark: WithPos<SelectedName>,
340+
pub type_mark: WithPos<TypeMark>,
334341
pub constraint: Option<WithPos<SubtypeConstraint>>,
335342
}
336343

@@ -396,7 +403,7 @@ pub struct AliasDeclaration {
396403
#[derive(PartialEq, Debug, Clone)]
397404
pub struct AttributeDeclaration {
398405
pub ident: Ident,
399-
pub type_mark: WithPos<SelectedName>,
406+
pub type_mark: WithPos<TypeMark>,
400407
}
401408

402409
/// LRM 7.2 Attribute specification

vhdl_lang/src/ast/display.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,8 @@ impl Display for Allocator {
285285
impl Display for QualifiedExpression {
286286
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
287287
match self.expr.item {
288-
Expression::Aggregate(..) => write!(f, "{}'{}", self.name, self.expr),
289-
_ => write!(f, "{}'({})", self.name, self.expr),
288+
Expression::Aggregate(..) => write!(f, "{}'{}", self.type_mark, self.expr),
289+
_ => write!(f, "{}'({})", self.type_mark, self.expr),
290290
}
291291
}
292292
}
@@ -575,6 +575,16 @@ impl Display for SubtypeIndication {
575575
}
576576
}
577577

578+
impl Display for TypeMark {
579+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
580+
write!(f, "{}", self.name)?;
581+
if self.subtype {
582+
write!(f, "'subtype")?;
583+
}
584+
Ok(())
585+
}
586+
}
587+
578588
impl Display for ArrayIndex {
579589
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
580590
match self {

vhdl_lang/src/ast/search.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,13 @@ impl Search for SubtypeIndication {
602602
}
603603
}
604604

605+
impl Search for WithPos<TypeMark> {
606+
fn search(&self, searcher: &mut impl Searcher) -> SearchResult {
607+
return_if_finished!(searcher.search_with_pos(&self.pos));
608+
self.item.name.search(searcher)
609+
}
610+
}
611+
605612
impl Search for RangeConstraint {
606613
fn search(&self, searcher: &mut impl Searcher) -> SearchResult {
607614
let RangeConstraint {
@@ -792,8 +799,8 @@ impl Search for ElementAssociation {
792799

793800
impl Search for QualifiedExpression {
794801
fn search(&self, searcher: &mut impl Searcher) -> SearchResult {
795-
let QualifiedExpression { name, expr } = self;
796-
return_if_found!(name.search(searcher));
802+
let QualifiedExpression { type_mark, expr } = self;
803+
return_if_found!(type_mark.search(searcher));
797804
return_if_found!(expr.search(searcher));
798805
NotFound
799806
}

0 commit comments

Comments
 (0)