Skip to content

Commit a346d96

Browse files
committed
Fix formal type conversion
1 parent bed5dbc commit a346d96

File tree

2 files changed

+51
-19
lines changed

2 files changed

+51
-19
lines changed

vhdl_lang/src/analysis/association.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use super::analyze::*;
1111
use super::formal_region::FormalRegion;
1212
use super::formal_region::InterfaceEnt;
1313
use super::named_entity::*;
14-
use super::names::as_type_conversion;
1514
use super::names::ResolvedName;
1615
use super::region::*;
1716
use crate::ast::*;
@@ -136,12 +135,12 @@ impl<'a> AnalyzeContext<'a> {
136135
// The prefix of the name was not found in the formal region
137136
// it must be a type conversion or a single parameter function call
138137

139-
let (idx, formal_ent) = if let Some(designator) =
138+
let (idx, pos, formal_ent) = if let Some((pos, designator)) =
140139
to_formal_conversion_argument(&mut fcall.parameters)
141140
{
142141
let (idx, ent) = formal_region.lookup(name_pos, designator.designator())?;
143142
designator.set_unique_reference(ent.inner());
144-
(idx, ent)
143+
(idx, pos, ent)
145144
} else {
146145
return Err(Diagnostic::error(name_pos, "Invalid formal conversion").into());
147146
};
@@ -153,24 +152,19 @@ impl<'a> AnalyzeContext<'a> {
153152
diagnostics,
154153
))? {
155154
Some(ResolvedName::Type(typ)) => {
156-
if let Some((expr_pos, expr)) =
157-
as_type_conversion(&mut fcall.parameters)
158-
{
159-
self.check_type_conversion(
160-
scope,
161-
typ,
162-
expr_pos,
163-
expr,
164-
diagnostics,
165-
)?;
166-
typ
167-
} else {
155+
let ctyp = formal_ent.type_mark().base();
156+
if !typ.base().is_closely_related(ctyp) {
168157
return Err(Diagnostic::error(
169-
name_pos,
170-
"Invalid formal type conversion",
158+
pos,
159+
format!(
160+
"{} cannot be converted to {}",
161+
ctyp.describe(),
162+
typ.describe()
163+
),
171164
)
172165
.into());
173166
}
167+
typ
174168
}
175169
Some(ResolvedName::Overloaded(des, overloaded)) => {
176170
let mut candidates = Vec::with_capacity(overloaded.len());
@@ -367,7 +361,7 @@ impl<'a> AnalyzeContext<'a> {
367361

368362
fn to_formal_conversion_argument(
369363
parameters: &mut [AssociationElement],
370-
) -> Option<&mut WithRef<Designator>> {
364+
) -> Option<(&SrcPos, &mut WithRef<Designator>)> {
371365
if let &mut [AssociationElement {
372366
ref formal,
373367
ref mut actual,
@@ -377,7 +371,7 @@ fn to_formal_conversion_argument(
377371
return None;
378372
} else if let ActualPart::Expression(Expression::Name(ref mut actual_name)) = actual.item {
379373
if let Name::Designator(designator) = actual_name.as_mut() {
380-
return Some(designator);
374+
return Some((&actual.pos, designator));
381375
}
382376
}
383377
}

vhdl_lang/src/analysis/tests/association_formal.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,44 @@ end architecture;
292292
);
293293
}
294294

295+
#[test]
296+
fn type_conversion_of_port_name() {
297+
let mut builder = LibraryBuilder::new();
298+
let code = builder.code(
299+
"libname",
300+
"
301+
entity ent is
302+
port (
303+
theport: out natural
304+
);
305+
end entity;
306+
307+
architecture a of ent is
308+
begin
309+
end architecture;
310+
311+
entity ent2 is
312+
end entity;
313+
314+
architecture a of ent2 is
315+
signal sig : real;
316+
begin
317+
inst: entity work.ent
318+
port map (
319+
real(theport) => sig);
320+
end architecture;
321+
",
322+
);
323+
324+
let (root, diagnostics) = builder.get_analyzed_root();
325+
check_no_diagnostics(&diagnostics);
326+
327+
assert_eq!(
328+
root.search_reference_pos(code.source(), code.s("theport", 2).end()),
329+
Some(code.s1("theport").pos())
330+
);
331+
}
332+
295333
#[test]
296334
fn function_conversion_of_port_name_must_be_single_argument() {
297335
let mut builder = LibraryBuilder::new();

0 commit comments

Comments
 (0)