Skip to content

Commit b5aef24

Browse files
committed
Support slicing of formal inside formal conversion
1 parent f046969 commit b5aef24

File tree

2 files changed

+81
-14
lines changed

2 files changed

+81
-14
lines changed

vhdl_lang/src/analysis/association.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ impl<'a> ResolvedFormal<'a> {
6666
ResolvedFormal::Converted(idx, _, _) => idx,
6767
}
6868
}
69+
70+
fn formal(&self) -> InterfaceEnt<'a> {
71+
*match self {
72+
ResolvedFormal::Basic(_, ent) => ent,
73+
ResolvedFormal::Selected(_, ent, _) => ent,
74+
ResolvedFormal::Converted(_, ent, _) => ent,
75+
}
76+
}
6977
}
7078

7179
impl<'a> AnalyzeContext<'a> {
@@ -135,12 +143,19 @@ impl<'a> AnalyzeContext<'a> {
135143
// The prefix of the name was not found in the formal region
136144
// it must be a type conversion or a single parameter function call
137145

138-
let (idx, pos, formal_ent) = if let Some((pos, designator)) =
146+
let (pos, resolved_formal) = if let Some((inner_pos, inner_name)) =
139147
to_formal_conversion_argument(&mut fcall.parameters)
140148
{
141-
let (idx, ent) = formal_region.lookup(name_pos, designator.designator())?;
142-
designator.set_unique_reference(ent.inner());
143-
(idx, pos, ent)
149+
(
150+
inner_pos,
151+
self.resolve_formal(
152+
formal_region,
153+
scope,
154+
inner_pos,
155+
inner_name,
156+
diagnostics,
157+
)?,
158+
)
144159
} else {
145160
return Err(Diagnostic::error(name_pos, "Invalid formal conversion").into());
146161
};
@@ -152,7 +167,7 @@ impl<'a> AnalyzeContext<'a> {
152167
diagnostics,
153168
))? {
154169
Some(ResolvedName::Type(typ)) => {
155-
let ctyp = formal_ent.type_mark().base();
170+
let ctyp = resolved_formal.type_mark().base();
156171
if !typ.base().is_closely_related(ctyp) {
157172
return Err(Diagnostic::error(
158173
pos,
@@ -171,9 +186,9 @@ impl<'a> AnalyzeContext<'a> {
171186

172187
for ent in overloaded.entities() {
173188
if ent.is_function()
174-
&& ent
175-
.signature()
176-
.can_be_called_with_single_parameter(formal_ent.type_mark())
189+
&& ent.signature().can_be_called_with_single_parameter(
190+
resolved_formal.type_mark(),
191+
)
177192
{
178193
candidates.push(ent);
179194
}
@@ -199,7 +214,7 @@ impl<'a> AnalyzeContext<'a> {
199214
format!(
200215
"No function '{}' accepting {}",
201216
fcall.name,
202-
formal_ent.type_mark().describe()
217+
resolved_formal.type_mark().describe()
203218
),
204219
)
205220
.into());
@@ -212,7 +227,11 @@ impl<'a> AnalyzeContext<'a> {
212227
}
213228
};
214229

215-
Ok(ResolvedFormal::Converted(idx, formal_ent, converted_typ))
230+
Ok(ResolvedFormal::Converted(
231+
resolved_formal.idx(),
232+
resolved_formal.formal(),
233+
converted_typ,
234+
))
216235
} else if let Some(mut indexed_name) = fcall.as_indexed() {
217236
let resolved_prefix = self.resolve_formal(
218237
formal_region,
@@ -361,7 +380,7 @@ impl<'a> AnalyzeContext<'a> {
361380

362381
fn to_formal_conversion_argument(
363382
parameters: &mut [AssociationElement],
364-
) -> Option<(&SrcPos, &mut WithRef<Designator>)> {
383+
) -> Option<(&SrcPos, &mut Box<Name>)> {
365384
if let &mut [AssociationElement {
366385
ref formal,
367386
ref mut actual,
@@ -370,9 +389,7 @@ fn to_formal_conversion_argument(
370389
if formal.is_some() {
371390
return None;
372391
} else if let ActualPart::Expression(Expression::Name(ref mut actual_name)) = actual.item {
373-
if let Name::Designator(designator) = actual_name.as_mut() {
374-
return Some((&actual.pos, designator));
375-
}
392+
return Some((&actual.pos, actual_name));
376393
}
377394
}
378395
None

vhdl_lang/src/analysis/tests/association_formal.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,56 @@ end architecture;
418418
);
419419
}
420420

421+
#[test]
422+
fn conversion_of_sliced_formal() {
423+
let mut builder = LibraryBuilder::new();
424+
let code = builder.code(
425+
"libname",
426+
"
427+
entity module is
428+
port (
429+
theport : out bit_vector(0 to 5)
430+
);
431+
end;
432+
433+
architecture a of module is
434+
begin
435+
end architecture;
436+
437+
entity ent is
438+
end;
439+
440+
architecture behav of ent is
441+
signal data0 : bit_vector(0 to 5);
442+
signal data1 : bit_vector(0 to 5);
443+
begin
444+
445+
inst0: entity work.module
446+
port map (
447+
bit_vector(theport(data0'range)) => data0
448+
);
449+
450+
inst1: entity work.module
451+
port map (
452+
bit_vector(theport(0 to 5)) => data1
453+
);
454+
end;",
455+
);
456+
457+
let (root, diagnostics) = builder.get_analyzed_root();
458+
check_no_diagnostics(&diagnostics);
459+
460+
assert_eq!(
461+
root.search_reference_pos(code.source(), code.s("theport", 2).end()),
462+
Some(code.s1("theport").pos())
463+
);
464+
465+
assert_eq!(
466+
root.search_reference_pos(code.source(), code.s("theport", 3).end()),
467+
Some(code.s1("theport").pos())
468+
);
469+
}
470+
421471
#[test]
422472
fn output_ports_may_be_left_open() {
423473
let mut builder = LibraryBuilder::new();

0 commit comments

Comments
 (0)