Skip to content

Commit

Permalink
Analyze alias specifications. #149
Browse files Browse the repository at this point in the history
  • Loading branch information
kraigher committed Jan 25, 2023
1 parent 917b9ea commit 4f17243
Show file tree
Hide file tree
Showing 14 changed files with 376 additions and 67 deletions.
2 changes: 1 addition & 1 deletion vhdl_lang/src/analysis/association.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> {
format!("Ambiguous call to function '{}'", des),
);

diagnostic.add_subprogram_candidates("migth be", &candidates);
diagnostic.add_subprogram_candidates("migth be", candidates);

return Err(diagnostic.into());
} else if let Some(ent) = candidates.pop() {
Expand Down
176 changes: 140 additions & 36 deletions vhdl_lang/src/analysis/declarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl<'a> AnalyzeContext<'a> {
match resolved_name {
ResolvedName::ObjectName(oname) => {
if let Some(ref signature) = signature {
diagnostics.push(signature_error(signature));
diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature));
}
match oname.base {
ObjectBase::Object(base_object) => AnyEntKind::ObjectAlias {
Expand All @@ -166,7 +166,7 @@ impl<'a> AnalyzeContext<'a> {
| ResolvedName::Design(_)
| ResolvedName::Expression(_) => {
if let Some(ref signature) = signature {
diagnostics.push(signature_error(signature));
diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature));
}
diagnostics.error(
&name.pos,
Expand All @@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> {
}
ResolvedName::Type(typ) => {
if let Some(ref signature) = signature {
diagnostics.push(signature_error(signature));
diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature));
}
AnyEntKind::Type(Type::Alias(typ))
}
Expand All @@ -190,22 +190,11 @@ impl<'a> AnalyzeContext<'a> {
}
AnyEntKind::Overloaded(Overloaded::Alias(ent))
} else {
let mut diagnostic = Diagnostic::error(
name,
format!(
"Could not find declaration of {} with given signature",
des.item.describe()
),
);
for ent in overloaded.entities() {
if let Some(pos) = ent.decl_pos() {
diagnostic.add_related(
pos,
format!("Found {}", ent.describe()),
);
}
}
diagnostics.push(diagnostic);
diagnostics.push(Diagnostic::no_overloaded_with_signature(
&des.pos,
&des.item,
&overloaded,
));
return Ok(None);
}
}
Expand All @@ -215,10 +204,7 @@ impl<'a> AnalyzeContext<'a> {
}
}
} else {
diagnostics.error(
name,
"Signature required for alias of subprogram and enum literals",
);
diagnostics.push(Diagnostic::signature_required(name));
return Ok(None);
}
}
Expand Down Expand Up @@ -350,17 +336,107 @@ impl<'a> AnalyzeContext<'a> {
}
Declaration::Attribute(ref mut attr) => match attr {
Attribute::Declaration(ref mut attr_decl) => {
if let Err(err) = self.resolve_type_mark(scope, &mut attr_decl.type_mark) {
err.add_to(diagnostics)?;
match self.resolve_type_mark(scope, &mut attr_decl.type_mark) {
Ok(typ) => {
scope.add(
self.arena
.define(&mut attr_decl.ident, AnyEntKind::Attribute(typ)),
diagnostics,
);
}
Err(err) => {
err.add_to(diagnostics)?;
}
}
scope.add(
self.arena
.define(&mut attr_decl.ident, AnyEntKind::Attribute),
diagnostics,
);
}
// @TODO Ignored for now
Attribute::Specification(..) => {}
Attribute::Specification(ref mut attr_spec) => {
let AttributeSpecification {
ident,
entity_name,
// @TODO also check the entity class
entity_class: _,
expr,
} = attr_spec;

match scope.lookup(
&ident.item.pos,
&Designator::Identifier(ident.item.name().clone()),
) {
Ok(NamedEntities::Single(ent)) => {
ident.set_unique_reference(ent);
if let AnyEntKind::Attribute(typ) = ent.actual_kind() {
self.analyze_expression_with_target_type(
scope,
*typ,
&expr.pos,
&mut expr.item,
diagnostics,
)?;
} else {
diagnostics.error(
&ident.item.pos,
format!("{} is not an attribute", ent.describe()),
);
}
}
Ok(NamedEntities::Overloaded(_)) => {
diagnostics.error(
&ident.item.pos,
format!("Overloaded name '{}' is not an attribute", ident.item),
);
}
Err(err) => {
diagnostics.push(err);
}
}

if let EntityName::Name(EntityTag {
designator,
signature,
}) = entity_name
{
match scope.lookup(&designator.pos, &designator.item.item) {
Ok(NamedEntities::Single(ent)) => {
designator.set_unique_reference(ent);

if let Some(signature) = signature {
diagnostics.push(Diagnostic::should_not_have_signature(
"Attribute specification",
&signature.pos,
));
}
}
Ok(NamedEntities::Overloaded(overloaded)) => {
if let Some(signature) = signature {
match self.resolve_signature(scope, signature) {
Ok(signature_key) => {
if let Some(ent) = overloaded.get(&signature_key) {
designator.set_unique_reference(&ent);
} else {
diagnostics.push(
Diagnostic::no_overloaded_with_signature(
&designator.pos,
&designator.item.item,
&overloaded,
),
);
}
}
Err(err) => {
err.add_to(diagnostics)?;
}
}
} else {
diagnostics.push(Diagnostic::signature_required(designator));
}
}
Err(err) => {
diagnostics.push(err);
}
}
}
}
},
Declaration::SubprogramBody(ref mut body) => {
let subpgm_region = scope.nested();
Expand Down Expand Up @@ -1119,11 +1195,39 @@ fn find_full_type_definition<'a>(
None
}

fn signature_error(pos: impl AsRef<SrcPos>) -> Diagnostic {
Diagnostic::error(
pos,
"Alias should only have a signature for subprograms and enum literals",
)
impl Diagnostic {
fn no_overloaded_with_signature(
pos: &SrcPos,
des: &Designator,
overloaded: &OverloadedName,
) -> Diagnostic {
let mut diagnostic = Diagnostic::error(
pos,
format!(
"Could not find declaration of {} with given signature",
des.describe()
),
);
diagnostic.add_subprogram_candidates("Found", overloaded.entities());
diagnostic
}

fn should_not_have_signature(prefix: &str, pos: impl AsRef<SrcPos>) -> Diagnostic {
Diagnostic::error(
pos,
format!(
"{} should only have a signature for subprograms and enum literals",
prefix
),
)
}

fn signature_required(pos: impl AsRef<SrcPos>) -> Diagnostic {
Diagnostic::error(
pos,
"Signature required for alias of subprogram and enum literals",
)
}
}

/// @TODO A simple and incomplete way to disambiguate integer and real in standard.vhd
Expand Down
2 changes: 1 addition & 1 deletion vhdl_lang/src/analysis/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ impl<'a> AnalyzeContext<'a> {
format!("Found no match for {}", designator.describe()),
);

diag.add_subprogram_candidates("Does not match", &overloaded);
diag.add_subprogram_candidates("Does not match", overloaded);
diagnostics.push(diag);
Ok(None)
} else if type_candidates.len() == 1 {
Expand Down
4 changes: 2 additions & 2 deletions vhdl_lang/src/analysis/named_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub enum AnyEntKind<'a> {
File(Subtype<'a>),
InterfaceFile(TypeEnt<'a>),
Component(Region<'a>),
Attribute,
Attribute(TypeEnt<'a>),
Overloaded(Overloaded<'a>),
Type(Type<'a>),
ElementDeclaration(Subtype<'a>),
Expand Down Expand Up @@ -109,7 +109,7 @@ impl<'a> AnyEntKind<'a> {
InterfaceFile(..) => "file",
ElementDeclaration(..) => "element declaration",
Component(..) => "component",
Attribute => "attribute",
Attribute(..) => "attribute",
Overloaded(overloaded) => overloaded.describe(),
Label => "label",
LoopParameter => "loop parameter",
Expand Down
11 changes: 7 additions & 4 deletions vhdl_lang/src/analysis/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<'a> ResolvedName<'a> {
| AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent),
AnyEntKind::Design(_)
| AnyEntKind::Library
| AnyEntKind::Attribute
| AnyEntKind::Attribute(_)
| AnyEntKind::ElementDeclaration(_)
| AnyEntKind::Label
| AnyEntKind::LoopParameter => {
Expand Down Expand Up @@ -221,7 +221,7 @@ impl<'a> ResolvedName<'a> {
| AnyEntKind::Label
| AnyEntKind::LoopParameter
| AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent),
AnyEntKind::Attribute | AnyEntKind::ElementDeclaration(_) => {
AnyEntKind::Attribute(_) | AnyEntKind::ElementDeclaration(_) => {
return Err(format!(
"{} should never be looked up from the current scope",
ent.kind().describe()
Expand Down Expand Up @@ -407,7 +407,7 @@ impl<'a> AnalyzeContext<'a> {
Ok(Some(ent.return_type().unwrap()))
}
Disambiguated::Ambiguous(overloaded) => {
Err(Diagnostic::ambiguous_call(des, &overloaded))
Err(Diagnostic::ambiguous_call(des, overloaded))
}
}
} else {
Expand Down Expand Up @@ -1214,7 +1214,10 @@ impl Diagnostic {
)
}

fn ambiguous_call(call_name: &WithPos<Designator>, candidates: &[OverloadedEnt]) -> Diagnostic {
fn ambiguous_call<'a>(
call_name: &WithPos<Designator>,
candidates: impl IntoIterator<Item = OverloadedEnt<'a>>,
) -> Diagnostic {
let mut diag = Diagnostic::error(
&call_name.pos,
format!("Ambiguous call to {}", call_name.item.describe()),
Expand Down
6 changes: 3 additions & 3 deletions vhdl_lang/src/analysis/overloaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl<'a> AnalyzeContext<'a> {
&call_name.pos,
format!("Could not resolve call to '{}'", call_name.designator()),
);
diag.add_subprogram_candidates("Does not match", &all_overloaded);
diag.add_subprogram_candidates("Does not match", all_overloaded);
diagnostics.push(diag);
return Ok(None);
}
Expand Down Expand Up @@ -262,7 +262,7 @@ impl<'a> AnalyzeContext<'a> {
&call_name.pos,
format!("Could not resolve call to '{}'", call_name.designator()),
);
diag.add_subprogram_candidates("Does not match", &overloaded);
diag.add_subprogram_candidates("Does not match", overloaded);
diagnostics.push(diag);
Ok(None)
};
Expand Down Expand Up @@ -313,7 +313,7 @@ impl<'a> AnalyzeContext<'a> {
&call_name.pos,
format!("Could not resolve call to '{}'", call_name.designator()),
);
diag.add_subprogram_candidates("Does not match", &overloaded);
diag.add_subprogram_candidates("Does not match", overloaded);
diagnostics.push(diag);
Ok(None)
} else {
Expand Down
8 changes: 6 additions & 2 deletions vhdl_lang/src/analysis/semantic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,12 @@ impl<'a> AnalyzeContext<'a> {
}

impl Diagnostic {
pub fn add_subprogram_candidates(&mut self, prefix: &str, candidates: &[OverloadedEnt]) {
let mut candidates = candidates.to_vec();
pub fn add_subprogram_candidates<'a>(
&mut self,
prefix: &str,
candidates: impl IntoIterator<Item = OverloadedEnt<'a>>,
) {
let mut candidates: Vec<_> = candidates.into_iter().collect();
candidates.sort_by(|x, y| x.decl_pos().cmp(&y.decl_pos()));

for ent in candidates {
Expand Down
Loading

0 comments on commit 4f17243

Please sign in to comment.