Skip to content

Commit aa1a719

Browse files
authored
Analyze Subprogram Instantiation Declarations (#209)
* Parse subprogram instantiation to declaration * Fix logic for identifier * Make item and token public * Check kind mismatch and resolve declaration * revert accidentally deleted test * Error on ambiguously instantiated subprograms * Resolve overloaded uninstantiated subprograms * return Err when the signature of the instantiated subprogram does not match * Add comments * Disallow instantiating an instantiable subprogram * Disallow instantiating a non-instantiable subprogram * Disallow calling an uninstantiated subprogram * Disambiguate based on uninstantiated subprogram * Fix: no longer always complain when instantiating a function * Merge master aftermath * Revert: Signature no longer contains optional generic map * Refactor boolean to two-state enum * Refactor: Region to GpkgRegion * Refactor: subprogram instantiation to own function * Revert: Use region instead of GpkgRegion * Instantiate subprograms * Remove debug print * Refactor into more generic code * Inline check_ent_is_uninstantiated_subprogram * Fill in todos and false unreachable calls * Add documentation * Add more checks to subprogram instance testcase * Set reference to the uninstantiated subprogram * Fix: Analyze the return of a function type in the correct scope * Add subprogram instance tests for future improvements * Enable subprogram declarations as reference to the overloaded entity * Add comment explaining the limitations of the current uninstantiated subprogram resolution * Rename is_uninst* for less ambiguity * Revert making fields public * Revert accidental change * Improve test case and add other ognored one * Add copyright header * Refactor SignatureKey to SubprogramKey * Add uninstantiated subprograms to checked declarations
1 parent f9d0ee9 commit aa1a719

File tree

13 files changed

+1097
-86
lines changed

13 files changed

+1097
-86
lines changed

vhdl_lang/src/analysis/declarative.rs

Lines changed: 338 additions & 25 deletions
Large diffs are not rendered by default.

vhdl_lang/src/analysis/overloaded.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,21 @@ impl<'a> AnalyzeContext<'a> {
286286
return Err(EvalError::Unknown);
287287
}
288288

289+
// Disambiguate based on uninstantiated subprogram
290+
ok_kind.retain(|ent| !ent.is_uninst_subprogram());
291+
292+
if ok_kind.len() == 1 {
293+
let ent = ok_kind[0];
294+
self.check_call(scope, call_pos, ent, assocs, diagnostics)?;
295+
return Ok(Disambiguated::Unambiguous(ent));
296+
} else if ok_kind.is_empty() {
297+
diagnostics.push(Diagnostic::error(
298+
call_name,
299+
format!("uninstantiated subprogram {} cannot be called", call_name),
300+
));
301+
return Err(EvalError::Unknown);
302+
}
303+
289304
let ok_formals = self.disambiguate_by_assoc_formals(scope, call_pos, &ok_kind, assocs)?;
290305

291306
// Only one candidate matched actual/formal profile

vhdl_lang/src/analysis/package_instance.rs

Lines changed: 81 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,56 @@
55
//! Copyright (c) 2023, Olof Kraigher [email protected]
66
77
use fnv::FnvHashMap;
8+
use vhdl_lang::SrcPos;
89

910
use super::analyze::*;
1011
use super::names::ResolvedName;
1112
use super::scope::*;
12-
use crate::ast::ActualPart;
1313
use crate::ast::AssociationElement;
1414
use crate::ast::Expression;
1515
use crate::ast::Literal;
1616
use crate::ast::Name;
1717
use crate::ast::Operator;
1818
use crate::ast::PackageInstantiation;
19+
use crate::ast::{ActualPart, MapAspect};
1920
use crate::data::DiagnosticHandler;
2021
use crate::named_entity::*;
2122
use crate::Diagnostic;
2223
use crate::NullDiagnostics;
2324

2425
impl<'a> AnalyzeContext<'a> {
25-
fn package_generic_map(
26+
pub fn generic_package_instance(
27+
&self,
28+
scope: &Scope<'a>,
29+
package_ent: EntRef<'a>,
30+
unit: &mut PackageInstantiation,
31+
diagnostics: &mut dyn DiagnosticHandler,
32+
) -> EvalResult<Region<'a>> {
33+
let PackageInstantiation {
34+
package_name,
35+
generic_map,
36+
..
37+
} = unit;
38+
39+
match self.analyze_package_instance_name(scope, package_name) {
40+
Ok(package_region) => self
41+
.generic_instance(
42+
package_ent,
43+
scope,
44+
&unit.ident.tree.pos,
45+
package_region,
46+
generic_map,
47+
diagnostics,
48+
)
49+
.map(|(region, _)| region),
50+
Err(err) => {
51+
diagnostics.push(err.into_non_fatal()?);
52+
Err(EvalError::Unknown)
53+
}
54+
}
55+
}
56+
57+
pub fn generic_map(
2658
&self,
2759
scope: &Scope<'a>,
2860
generics: GpkgRegion<'a>,
@@ -124,7 +156,7 @@ impl<'a> AnalyzeContext<'a> {
124156
let resolved =
125157
self.name_resolve(scope, &assoc.actual.pos, name, diagnostics)?;
126158
if let ResolvedName::Overloaded(des, overloaded) = resolved {
127-
let signature = target.signature().key().map(|base_type| {
159+
let signature = target.subprogram_key().map(|base_type| {
128160
mapping
129161
.get(&base_type.id())
130162
.map(|ent| ent.base())
@@ -139,7 +171,7 @@ impl<'a> AnalyzeContext<'a> {
139171
"Cannot map '{}' to subprogram generic {}{}",
140172
des,
141173
target.designator(),
142-
signature.describe()
174+
signature.key().describe()
143175
),
144176
);
145177

@@ -188,62 +220,50 @@ impl<'a> AnalyzeContext<'a> {
188220
Ok(mapping)
189221
}
190222

191-
pub fn generic_package_instance(
223+
pub fn generic_instance(
192224
&self,
225+
ent: EntRef<'a>,
193226
scope: &Scope<'a>,
194-
package_ent: EntRef<'a>,
195-
unit: &mut PackageInstantiation,
227+
decl_pos: &SrcPos,
228+
uninst_region: &Region<'a>,
229+
generic_map: &mut Option<MapAspect>,
196230
diagnostics: &mut dyn DiagnosticHandler,
197-
) -> EvalResult<Region<'a>> {
198-
let PackageInstantiation {
199-
package_name,
200-
generic_map,
201-
..
202-
} = unit;
231+
) -> EvalResult<(Region<'a>, FnvHashMap<EntityId, TypeEnt>)> {
232+
let nested = scope.nested().in_package_declaration();
233+
let (generics, other) = uninst_region.to_package_generic();
234+
235+
let mapping = if let Some(generic_map) = generic_map {
236+
self.generic_map(
237+
&nested,
238+
generics,
239+
generic_map.list.items.as_mut_slice(),
240+
diagnostics,
241+
)?
242+
} else {
243+
FnvHashMap::default()
244+
};
203245

204-
match self.analyze_package_instance_name(scope, package_name) {
205-
Ok(package_region) => {
206-
let nested = scope.nested().in_package_declaration();
207-
let (generics, other) = package_region.to_package_generic();
208-
209-
let mapping = if let Some(generic_map) = generic_map {
210-
self.package_generic_map(
211-
&nested,
212-
generics,
213-
generic_map.list.items.as_mut_slice(),
214-
diagnostics,
215-
)?
216-
} else {
217-
FnvHashMap::default()
218-
};
219-
220-
for uninst in other {
221-
match self.instantiate(Some(package_ent), &mapping, uninst) {
222-
Ok(inst) => {
223-
// We ignore diagnostics here, for example when adding implicit operators EQ and NE for interface types
224-
// They can collide if there are more than one interface type that map to the same actual type
225-
nested.add(inst, &mut NullDiagnostics);
226-
}
227-
Err(err) => {
228-
let mut diag = Diagnostic::error(&unit.ident.tree.pos, err);
229-
if let Some(pos) = uninst.decl_pos() {
230-
diag.add_related(pos, "When instantiating this declaration");
231-
}
232-
diagnostics.push(diag);
233-
}
246+
for uninst in other {
247+
match self.instantiate(Some(ent), &mapping, uninst) {
248+
Ok(inst) => {
249+
// We ignore diagnostics here, for example when adding implicit operators EQ and NE for interface types
250+
// They can collide if there are more than one interface type that map to the same actual type
251+
nested.add(inst, &mut NullDiagnostics);
252+
}
253+
Err(err) => {
254+
let mut diag = Diagnostic::error(decl_pos, err);
255+
if let Some(pos) = uninst.decl_pos() {
256+
diag.add_related(pos, "When instantiating this declaration");
234257
}
258+
diagnostics.push(diag);
235259
}
236-
237-
Ok(nested.into_region())
238-
}
239-
Err(err) => {
240-
diagnostics.push(err.into_non_fatal()?);
241-
Err(EvalError::Unknown)
242260
}
243261
}
262+
263+
Ok((nested.into_region(), mapping))
244264
}
245265

246-
fn instantiate(
266+
pub(crate) fn instantiate(
247267
&self,
248268
parent: Option<EntRef<'a>>,
249269
mapping: &FnvHashMap<EntityId, TypeEnt<'a>>,
@@ -358,6 +378,16 @@ impl<'a> AnalyzeContext<'a> {
358378
Overloaded::Subprogram(signature) => {
359379
Overloaded::Subprogram(self.map_signature(parent, mapping, signature)?)
360380
}
381+
Overloaded::UninstSubprogramDecl(signature, generic_map) => {
382+
Overloaded::UninstSubprogramDecl(
383+
self.map_signature(parent, mapping, signature)?,
384+
generic_map.clone(),
385+
)
386+
}
387+
Overloaded::UninstSubprogram(signature, generic_map) => Overloaded::UninstSubprogram(
388+
self.map_signature(parent, mapping, signature)?,
389+
generic_map.clone(),
390+
),
361391
Overloaded::InterfaceSubprogram(signature) => {
362392
Overloaded::InterfaceSubprogram(self.map_signature(parent, mapping, signature)?)
363393
}
@@ -379,7 +409,7 @@ impl<'a> AnalyzeContext<'a> {
379409
})
380410
}
381411

382-
fn map_signature(
412+
pub(crate) fn map_signature(
383413
&self,
384414
parent: Option<EntRef<'a>>,
385415
mapping: &FnvHashMap<EntityId, TypeEnt<'a>>,

vhdl_lang/src/analysis/semantic.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ impl<'a> AnalyzeContext<'a> {
195195
}
196196
}
197197
diagnostics.push(diagnostic);
198+
} else if ent.is_uninst_subprogram_body() {
199+
diagnostics.error(
200+
&name.pos,
201+
format!("uninstantiated {} cannot be called", ent.describe()),
202+
)
198203
}
199204
}
200205
None => {}

vhdl_lang/src/analysis/standard.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,6 @@ impl<'a> AnalyzeContext<'a> {
326326

327327
fn binary(
328328
&self,
329-
330329
op: Operator,
331330
implicit_of: TypeEnt<'a>,
332331
left: TypeEnt<'a>,

vhdl_lang/src/analysis/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ mod resolves_names;
2323
mod resolves_type_mark;
2424
mod sensitivity_list;
2525
mod subprogram_arguments;
26+
mod subprogram_instance;
2627
mod tool_directive;
2728
mod typecheck_expression;
2829
mod util;

0 commit comments

Comments
 (0)