-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
f9d0ee9
commit aa1a719
Showing
13 changed files
with
1,097 additions
and
86 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,24 +5,56 @@ | |
//! Copyright (c) 2023, Olof Kraigher [email protected] | ||
|
||
use fnv::FnvHashMap; | ||
use vhdl_lang::SrcPos; | ||
|
||
use super::analyze::*; | ||
use super::names::ResolvedName; | ||
use super::scope::*; | ||
use crate::ast::ActualPart; | ||
use crate::ast::AssociationElement; | ||
use crate::ast::Expression; | ||
use crate::ast::Literal; | ||
use crate::ast::Name; | ||
use crate::ast::Operator; | ||
use crate::ast::PackageInstantiation; | ||
use crate::ast::{ActualPart, MapAspect}; | ||
use crate::data::DiagnosticHandler; | ||
use crate::named_entity::*; | ||
use crate::Diagnostic; | ||
use crate::NullDiagnostics; | ||
|
||
impl<'a> AnalyzeContext<'a> { | ||
fn package_generic_map( | ||
pub fn generic_package_instance( | ||
&self, | ||
scope: &Scope<'a>, | ||
package_ent: EntRef<'a>, | ||
unit: &mut PackageInstantiation, | ||
diagnostics: &mut dyn DiagnosticHandler, | ||
) -> EvalResult<Region<'a>> { | ||
let PackageInstantiation { | ||
package_name, | ||
generic_map, | ||
.. | ||
} = unit; | ||
|
||
match self.analyze_package_instance_name(scope, package_name) { | ||
Ok(package_region) => self | ||
.generic_instance( | ||
package_ent, | ||
scope, | ||
&unit.ident.tree.pos, | ||
package_region, | ||
generic_map, | ||
diagnostics, | ||
) | ||
.map(|(region, _)| region), | ||
Err(err) => { | ||
diagnostics.push(err.into_non_fatal()?); | ||
Err(EvalError::Unknown) | ||
} | ||
} | ||
} | ||
|
||
pub fn generic_map( | ||
&self, | ||
scope: &Scope<'a>, | ||
generics: GpkgRegion<'a>, | ||
|
@@ -124,7 +156,7 @@ impl<'a> AnalyzeContext<'a> { | |
let resolved = | ||
self.name_resolve(scope, &assoc.actual.pos, name, diagnostics)?; | ||
if let ResolvedName::Overloaded(des, overloaded) = resolved { | ||
let signature = target.signature().key().map(|base_type| { | ||
let signature = target.subprogram_key().map(|base_type| { | ||
mapping | ||
.get(&base_type.id()) | ||
.map(|ent| ent.base()) | ||
|
@@ -139,7 +171,7 @@ impl<'a> AnalyzeContext<'a> { | |
"Cannot map '{}' to subprogram generic {}{}", | ||
des, | ||
target.designator(), | ||
signature.describe() | ||
signature.key().describe() | ||
), | ||
); | ||
|
||
|
@@ -188,62 +220,50 @@ impl<'a> AnalyzeContext<'a> { | |
Ok(mapping) | ||
} | ||
|
||
pub fn generic_package_instance( | ||
pub fn generic_instance( | ||
&self, | ||
ent: EntRef<'a>, | ||
scope: &Scope<'a>, | ||
package_ent: EntRef<'a>, | ||
unit: &mut PackageInstantiation, | ||
decl_pos: &SrcPos, | ||
uninst_region: &Region<'a>, | ||
generic_map: &mut Option<MapAspect>, | ||
diagnostics: &mut dyn DiagnosticHandler, | ||
) -> EvalResult<Region<'a>> { | ||
let PackageInstantiation { | ||
package_name, | ||
generic_map, | ||
.. | ||
} = unit; | ||
) -> EvalResult<(Region<'a>, FnvHashMap<EntityId, TypeEnt>)> { | ||
let nested = scope.nested().in_package_declaration(); | ||
let (generics, other) = uninst_region.to_package_generic(); | ||
|
||
let mapping = if let Some(generic_map) = generic_map { | ||
self.generic_map( | ||
&nested, | ||
generics, | ||
generic_map.list.items.as_mut_slice(), | ||
diagnostics, | ||
)? | ||
} else { | ||
FnvHashMap::default() | ||
}; | ||
|
||
match self.analyze_package_instance_name(scope, package_name) { | ||
Ok(package_region) => { | ||
let nested = scope.nested().in_package_declaration(); | ||
let (generics, other) = package_region.to_package_generic(); | ||
|
||
let mapping = if let Some(generic_map) = generic_map { | ||
self.package_generic_map( | ||
&nested, | ||
generics, | ||
generic_map.list.items.as_mut_slice(), | ||
diagnostics, | ||
)? | ||
} else { | ||
FnvHashMap::default() | ||
}; | ||
|
||
for uninst in other { | ||
match self.instantiate(Some(package_ent), &mapping, uninst) { | ||
Ok(inst) => { | ||
// We ignore diagnostics here, for example when adding implicit operators EQ and NE for interface types | ||
// They can collide if there are more than one interface type that map to the same actual type | ||
nested.add(inst, &mut NullDiagnostics); | ||
} | ||
Err(err) => { | ||
let mut diag = Diagnostic::error(&unit.ident.tree.pos, err); | ||
if let Some(pos) = uninst.decl_pos() { | ||
diag.add_related(pos, "When instantiating this declaration"); | ||
} | ||
diagnostics.push(diag); | ||
} | ||
for uninst in other { | ||
match self.instantiate(Some(ent), &mapping, uninst) { | ||
Ok(inst) => { | ||
// We ignore diagnostics here, for example when adding implicit operators EQ and NE for interface types | ||
// They can collide if there are more than one interface type that map to the same actual type | ||
nested.add(inst, &mut NullDiagnostics); | ||
} | ||
Err(err) => { | ||
let mut diag = Diagnostic::error(decl_pos, err); | ||
if let Some(pos) = uninst.decl_pos() { | ||
diag.add_related(pos, "When instantiating this declaration"); | ||
} | ||
diagnostics.push(diag); | ||
} | ||
|
||
Ok(nested.into_region()) | ||
} | ||
Err(err) => { | ||
diagnostics.push(err.into_non_fatal()?); | ||
Err(EvalError::Unknown) | ||
} | ||
} | ||
|
||
Ok((nested.into_region(), mapping)) | ||
} | ||
|
||
fn instantiate( | ||
pub(crate) fn instantiate( | ||
&self, | ||
parent: Option<EntRef<'a>>, | ||
mapping: &FnvHashMap<EntityId, TypeEnt<'a>>, | ||
|
@@ -358,6 +378,16 @@ impl<'a> AnalyzeContext<'a> { | |
Overloaded::Subprogram(signature) => { | ||
Overloaded::Subprogram(self.map_signature(parent, mapping, signature)?) | ||
} | ||
Overloaded::UninstSubprogramDecl(signature, generic_map) => { | ||
Overloaded::UninstSubprogramDecl( | ||
self.map_signature(parent, mapping, signature)?, | ||
generic_map.clone(), | ||
) | ||
} | ||
Overloaded::UninstSubprogram(signature, generic_map) => Overloaded::UninstSubprogram( | ||
self.map_signature(parent, mapping, signature)?, | ||
generic_map.clone(), | ||
), | ||
Overloaded::InterfaceSubprogram(signature) => { | ||
Overloaded::InterfaceSubprogram(self.map_signature(parent, mapping, signature)?) | ||
} | ||
|
@@ -379,7 +409,7 @@ impl<'a> AnalyzeContext<'a> { | |
}) | ||
} | ||
|
||
fn map_signature( | ||
pub(crate) fn map_signature( | ||
&self, | ||
parent: Option<EntRef<'a>>, | ||
mapping: &FnvHashMap<EntityId, TypeEnt<'a>>, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.