Skip to content

Commit 4f17243

Browse files
committed
Analyze alias specifications. #149
1 parent 917b9ea commit 4f17243

File tree

14 files changed

+376
-67
lines changed

14 files changed

+376
-67
lines changed

vhdl_lang/src/analysis/association.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> {
176176
format!("Ambiguous call to function '{}'", des),
177177
);
178178

179-
diagnostic.add_subprogram_candidates("migth be", &candidates);
179+
diagnostic.add_subprogram_candidates("migth be", candidates);
180180

181181
return Err(diagnostic.into());
182182
} else if let Some(ent) = candidates.pop() {

vhdl_lang/src/analysis/declarative.rs

Lines changed: 140 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ impl<'a> AnalyzeContext<'a> {
141141
match resolved_name {
142142
ResolvedName::ObjectName(oname) => {
143143
if let Some(ref signature) = signature {
144-
diagnostics.push(signature_error(signature));
144+
diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature));
145145
}
146146
match oname.base {
147147
ObjectBase::Object(base_object) => AnyEntKind::ObjectAlias {
@@ -166,7 +166,7 @@ impl<'a> AnalyzeContext<'a> {
166166
| ResolvedName::Design(_)
167167
| ResolvedName::Expression(_) => {
168168
if let Some(ref signature) = signature {
169-
diagnostics.push(signature_error(signature));
169+
diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature));
170170
}
171171
diagnostics.error(
172172
&name.pos,
@@ -176,7 +176,7 @@ impl<'a> AnalyzeContext<'a> {
176176
}
177177
ResolvedName::Type(typ) => {
178178
if let Some(ref signature) = signature {
179-
diagnostics.push(signature_error(signature));
179+
diagnostics.push(Diagnostic::should_not_have_signature("Alias", signature));
180180
}
181181
AnyEntKind::Type(Type::Alias(typ))
182182
}
@@ -190,22 +190,11 @@ impl<'a> AnalyzeContext<'a> {
190190
}
191191
AnyEntKind::Overloaded(Overloaded::Alias(ent))
192192
} else {
193-
let mut diagnostic = Diagnostic::error(
194-
name,
195-
format!(
196-
"Could not find declaration of {} with given signature",
197-
des.item.describe()
198-
),
199-
);
200-
for ent in overloaded.entities() {
201-
if let Some(pos) = ent.decl_pos() {
202-
diagnostic.add_related(
203-
pos,
204-
format!("Found {}", ent.describe()),
205-
);
206-
}
207-
}
208-
diagnostics.push(diagnostic);
193+
diagnostics.push(Diagnostic::no_overloaded_with_signature(
194+
&des.pos,
195+
&des.item,
196+
&overloaded,
197+
));
209198
return Ok(None);
210199
}
211200
}
@@ -215,10 +204,7 @@ impl<'a> AnalyzeContext<'a> {
215204
}
216205
}
217206
} else {
218-
diagnostics.error(
219-
name,
220-
"Signature required for alias of subprogram and enum literals",
221-
);
207+
diagnostics.push(Diagnostic::signature_required(name));
222208
return Ok(None);
223209
}
224210
}
@@ -350,17 +336,107 @@ impl<'a> AnalyzeContext<'a> {
350336
}
351337
Declaration::Attribute(ref mut attr) => match attr {
352338
Attribute::Declaration(ref mut attr_decl) => {
353-
if let Err(err) = self.resolve_type_mark(scope, &mut attr_decl.type_mark) {
354-
err.add_to(diagnostics)?;
339+
match self.resolve_type_mark(scope, &mut attr_decl.type_mark) {
340+
Ok(typ) => {
341+
scope.add(
342+
self.arena
343+
.define(&mut attr_decl.ident, AnyEntKind::Attribute(typ)),
344+
diagnostics,
345+
);
346+
}
347+
Err(err) => {
348+
err.add_to(diagnostics)?;
349+
}
355350
}
356-
scope.add(
357-
self.arena
358-
.define(&mut attr_decl.ident, AnyEntKind::Attribute),
359-
diagnostics,
360-
);
361351
}
362352
// @TODO Ignored for now
363-
Attribute::Specification(..) => {}
353+
Attribute::Specification(ref mut attr_spec) => {
354+
let AttributeSpecification {
355+
ident,
356+
entity_name,
357+
// @TODO also check the entity class
358+
entity_class: _,
359+
expr,
360+
} = attr_spec;
361+
362+
match scope.lookup(
363+
&ident.item.pos,
364+
&Designator::Identifier(ident.item.name().clone()),
365+
) {
366+
Ok(NamedEntities::Single(ent)) => {
367+
ident.set_unique_reference(ent);
368+
if let AnyEntKind::Attribute(typ) = ent.actual_kind() {
369+
self.analyze_expression_with_target_type(
370+
scope,
371+
*typ,
372+
&expr.pos,
373+
&mut expr.item,
374+
diagnostics,
375+
)?;
376+
} else {
377+
diagnostics.error(
378+
&ident.item.pos,
379+
format!("{} is not an attribute", ent.describe()),
380+
);
381+
}
382+
}
383+
Ok(NamedEntities::Overloaded(_)) => {
384+
diagnostics.error(
385+
&ident.item.pos,
386+
format!("Overloaded name '{}' is not an attribute", ident.item),
387+
);
388+
}
389+
Err(err) => {
390+
diagnostics.push(err);
391+
}
392+
}
393+
394+
if let EntityName::Name(EntityTag {
395+
designator,
396+
signature,
397+
}) = entity_name
398+
{
399+
match scope.lookup(&designator.pos, &designator.item.item) {
400+
Ok(NamedEntities::Single(ent)) => {
401+
designator.set_unique_reference(ent);
402+
403+
if let Some(signature) = signature {
404+
diagnostics.push(Diagnostic::should_not_have_signature(
405+
"Attribute specification",
406+
&signature.pos,
407+
));
408+
}
409+
}
410+
Ok(NamedEntities::Overloaded(overloaded)) => {
411+
if let Some(signature) = signature {
412+
match self.resolve_signature(scope, signature) {
413+
Ok(signature_key) => {
414+
if let Some(ent) = overloaded.get(&signature_key) {
415+
designator.set_unique_reference(&ent);
416+
} else {
417+
diagnostics.push(
418+
Diagnostic::no_overloaded_with_signature(
419+
&designator.pos,
420+
&designator.item.item,
421+
&overloaded,
422+
),
423+
);
424+
}
425+
}
426+
Err(err) => {
427+
err.add_to(diagnostics)?;
428+
}
429+
}
430+
} else {
431+
diagnostics.push(Diagnostic::signature_required(designator));
432+
}
433+
}
434+
Err(err) => {
435+
diagnostics.push(err);
436+
}
437+
}
438+
}
439+
}
364440
},
365441
Declaration::SubprogramBody(ref mut body) => {
366442
let subpgm_region = scope.nested();
@@ -1119,11 +1195,39 @@ fn find_full_type_definition<'a>(
11191195
None
11201196
}
11211197

1122-
fn signature_error(pos: impl AsRef<SrcPos>) -> Diagnostic {
1123-
Diagnostic::error(
1124-
pos,
1125-
"Alias should only have a signature for subprograms and enum literals",
1126-
)
1198+
impl Diagnostic {
1199+
fn no_overloaded_with_signature(
1200+
pos: &SrcPos,
1201+
des: &Designator,
1202+
overloaded: &OverloadedName,
1203+
) -> Diagnostic {
1204+
let mut diagnostic = Diagnostic::error(
1205+
pos,
1206+
format!(
1207+
"Could not find declaration of {} with given signature",
1208+
des.describe()
1209+
),
1210+
);
1211+
diagnostic.add_subprogram_candidates("Found", overloaded.entities());
1212+
diagnostic
1213+
}
1214+
1215+
fn should_not_have_signature(prefix: &str, pos: impl AsRef<SrcPos>) -> Diagnostic {
1216+
Diagnostic::error(
1217+
pos,
1218+
format!(
1219+
"{} should only have a signature for subprograms and enum literals",
1220+
prefix
1221+
),
1222+
)
1223+
}
1224+
1225+
fn signature_required(pos: impl AsRef<SrcPos>) -> Diagnostic {
1226+
Diagnostic::error(
1227+
pos,
1228+
"Signature required for alias of subprogram and enum literals",
1229+
)
1230+
}
11271231
}
11281232

11291233
/// @TODO A simple and incomplete way to disambiguate integer and real in standard.vhd

vhdl_lang/src/analysis/expression.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ impl<'a> AnalyzeContext<'a> {
168168
format!("Found no match for {}", designator.describe()),
169169
);
170170

171-
diag.add_subprogram_candidates("Does not match", &overloaded);
171+
diag.add_subprogram_candidates("Does not match", overloaded);
172172
diagnostics.push(diag);
173173
Ok(None)
174174
} else if type_candidates.len() == 1 {

vhdl_lang/src/analysis/named_entity.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub enum AnyEntKind<'a> {
4040
File(Subtype<'a>),
4141
InterfaceFile(TypeEnt<'a>),
4242
Component(Region<'a>),
43-
Attribute,
43+
Attribute(TypeEnt<'a>),
4444
Overloaded(Overloaded<'a>),
4545
Type(Type<'a>),
4646
ElementDeclaration(Subtype<'a>),
@@ -109,7 +109,7 @@ impl<'a> AnyEntKind<'a> {
109109
InterfaceFile(..) => "file",
110110
ElementDeclaration(..) => "element declaration",
111111
Component(..) => "component",
112-
Attribute => "attribute",
112+
Attribute(..) => "attribute",
113113
Overloaded(overloaded) => overloaded.describe(),
114114
Label => "label",
115115
LoopParameter => "loop parameter",

vhdl_lang/src/analysis/names.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl<'a> ResolvedName<'a> {
166166
| AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent),
167167
AnyEntKind::Design(_)
168168
| AnyEntKind::Library
169-
| AnyEntKind::Attribute
169+
| AnyEntKind::Attribute(_)
170170
| AnyEntKind::ElementDeclaration(_)
171171
| AnyEntKind::Label
172172
| AnyEntKind::LoopParameter => {
@@ -221,7 +221,7 @@ impl<'a> ResolvedName<'a> {
221221
| AnyEntKind::Label
222222
| AnyEntKind::LoopParameter
223223
| AnyEntKind::PhysicalLiteral(_) => ResolvedName::Final(ent),
224-
AnyEntKind::Attribute | AnyEntKind::ElementDeclaration(_) => {
224+
AnyEntKind::Attribute(_) | AnyEntKind::ElementDeclaration(_) => {
225225
return Err(format!(
226226
"{} should never be looked up from the current scope",
227227
ent.kind().describe()
@@ -407,7 +407,7 @@ impl<'a> AnalyzeContext<'a> {
407407
Ok(Some(ent.return_type().unwrap()))
408408
}
409409
Disambiguated::Ambiguous(overloaded) => {
410-
Err(Diagnostic::ambiguous_call(des, &overloaded))
410+
Err(Diagnostic::ambiguous_call(des, overloaded))
411411
}
412412
}
413413
} else {
@@ -1214,7 +1214,10 @@ impl Diagnostic {
12141214
)
12151215
}
12161216

1217-
fn ambiguous_call(call_name: &WithPos<Designator>, candidates: &[OverloadedEnt]) -> Diagnostic {
1217+
fn ambiguous_call<'a>(
1218+
call_name: &WithPos<Designator>,
1219+
candidates: impl IntoIterator<Item = OverloadedEnt<'a>>,
1220+
) -> Diagnostic {
12181221
let mut diag = Diagnostic::error(
12191222
&call_name.pos,
12201223
format!("Ambiguous call to {}", call_name.item.describe()),

vhdl_lang/src/analysis/overloaded.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl<'a> AnalyzeContext<'a> {
222222
&call_name.pos,
223223
format!("Could not resolve call to '{}'", call_name.designator()),
224224
);
225-
diag.add_subprogram_candidates("Does not match", &all_overloaded);
225+
diag.add_subprogram_candidates("Does not match", all_overloaded);
226226
diagnostics.push(diag);
227227
return Ok(None);
228228
}
@@ -262,7 +262,7 @@ impl<'a> AnalyzeContext<'a> {
262262
&call_name.pos,
263263
format!("Could not resolve call to '{}'", call_name.designator()),
264264
);
265-
diag.add_subprogram_candidates("Does not match", &overloaded);
265+
diag.add_subprogram_candidates("Does not match", overloaded);
266266
diagnostics.push(diag);
267267
Ok(None)
268268
};
@@ -313,7 +313,7 @@ impl<'a> AnalyzeContext<'a> {
313313
&call_name.pos,
314314
format!("Could not resolve call to '{}'", call_name.designator()),
315315
);
316-
diag.add_subprogram_candidates("Does not match", &overloaded);
316+
diag.add_subprogram_candidates("Does not match", overloaded);
317317
diagnostics.push(diag);
318318
Ok(None)
319319
} else {

vhdl_lang/src/analysis/semantic.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,12 @@ impl<'a> AnalyzeContext<'a> {
309309
}
310310

311311
impl Diagnostic {
312-
pub fn add_subprogram_candidates(&mut self, prefix: &str, candidates: &[OverloadedEnt]) {
313-
let mut candidates = candidates.to_vec();
312+
pub fn add_subprogram_candidates<'a>(
313+
&mut self,
314+
prefix: &str,
315+
candidates: impl IntoIterator<Item = OverloadedEnt<'a>>,
316+
) {
317+
let mut candidates: Vec<_> = candidates.into_iter().collect();
314318
candidates.sort_by(|x, y| x.decl_pos().cmp(&y.decl_pos()));
315319

316320
for ent in candidates {

0 commit comments

Comments
 (0)