Skip to content

Commit e775906

Browse files
committed
Hover physical type literals
1 parent a060749 commit e775906

File tree

9 files changed

+196
-40
lines changed

9 files changed

+196
-40
lines changed

vhdl_lang/src/analysis/declarative.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,22 +692,37 @@ impl<'a> AnalyzeContext<'a> {
692692
&mut type_decl.ident,
693693
Type::Physical(Implicits::default()),
694694
);
695+
parent.add(phys_type.clone().into(), diagnostics);
695696

696697
parent.add(
697698
physical
698699
.primary_unit
699700
.define(NamedEntityKind::PhysicalLiteral(phys_type.clone())),
700701
diagnostics,
701702
);
702-
for (secondary_unit_name, _) in physical.secondary_units.iter_mut() {
703+
for (secondary_unit_name, value) in physical.secondary_units.iter_mut() {
704+
match self.resolve_physical_unit(parent, &mut value.unit) {
705+
Ok(secondary_unit_type) => {
706+
if secondary_unit_type.base_type() != &phys_type {
707+
diagnostics.error(
708+
&value.unit.item.pos,
709+
format!(
710+
"Physical unit of type '{}' does not match {}",
711+
secondary_unit_type.designator(),
712+
phys_type.describe()
713+
),
714+
)
715+
}
716+
}
717+
Err(err) => diagnostics.push(err),
718+
}
719+
703720
parent.add(
704721
secondary_unit_name
705722
.define(NamedEntityKind::PhysicalLiteral(phys_type.clone())),
706723
diagnostics,
707724
)
708725
}
709-
710-
parent.add(phys_type.into(), diagnostics);
711726
}
712727
TypeDefinition::Incomplete(..) => {
713728
unreachable!("Handled elsewhere");

vhdl_lang/src/analysis/semantic.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,15 @@ impl<'a> AnalyzeContext<'a> {
571571
self.analyze_subtype_indication(region, subtype, diagnostics)
572572
}
573573
},
574-
Expression::Literal(_) => Ok(()),
574+
Expression::Literal(ref mut literal) => match literal {
575+
Literal::Physical(PhysicalLiteral { ref mut unit, .. }) => {
576+
if let Err(diagnostic) = self.resolve_physical_unit(region, unit) {
577+
diagnostics.push(diagnostic);
578+
}
579+
Ok(())
580+
}
581+
_ => Ok(()),
582+
},
575583
}
576584
}
577585

@@ -1041,9 +1049,10 @@ impl<'a> AnalyzeContext<'a> {
10411049
/// None if it was uncertain
10421050
pub fn analyze_literal_with_target_type(
10431051
&self,
1052+
region: &Region<'_>,
10441053
target_type: &TypeEnt,
10451054
pos: &SrcPos,
1046-
literal: &Literal,
1055+
literal: &mut Literal,
10471056
diagnostics: &mut dyn DiagnosticHandler,
10481057
) -> FatalResult<Option<bool>> {
10491058
let target_base = target_type.base_type();
@@ -1154,12 +1163,48 @@ impl<'a> AnalyzeContext<'a> {
11541163
}
11551164
},
11561165

1166+
Literal::Physical(PhysicalLiteral { ref mut unit, .. }) => {
1167+
match self.resolve_physical_unit(region, unit) {
1168+
Ok(physical_type) => Some(physical_type.base_type() == target_base),
1169+
Err(diagnostic) => {
1170+
diagnostics.push(diagnostic);
1171+
Some(false)
1172+
}
1173+
}
1174+
}
11571175
_ => None,
11581176
};
11591177

11601178
Ok(is_correct)
11611179
}
11621180

1181+
pub fn resolve_physical_unit(
1182+
&self,
1183+
region: &Region<'_>,
1184+
unit: &mut WithRef<Ident>,
1185+
) -> Result<TypeEnt, Diagnostic> {
1186+
match region.lookup_within(
1187+
&unit.item.pos,
1188+
&Designator::Identifier(unit.item.item.clone()),
1189+
)? {
1190+
NamedEntities::Single(unit_ent) => {
1191+
unit.set_unique_reference(&unit_ent);
1192+
if let NamedEntityKind::PhysicalLiteral(physical_ent) = unit_ent.actual_kind() {
1193+
Ok(physical_ent.clone())
1194+
} else {
1195+
Err(Diagnostic::error(
1196+
&unit.item.pos,
1197+
format!("{} is not a physical unit", unit_ent.describe()),
1198+
))
1199+
}
1200+
}
1201+
NamedEntities::Overloaded(_) => Err(Diagnostic::error(
1202+
&unit.item.pos,
1203+
"Overloaded name may not be physical unit",
1204+
)),
1205+
}
1206+
}
1207+
11631208
/// Returns true if the name actually matches the target type
11641209
/// None if it was uncertain
11651210
pub fn analyze_expression_with_target_type(
@@ -1171,9 +1216,13 @@ impl<'a> AnalyzeContext<'a> {
11711216
diagnostics: &mut dyn DiagnosticHandler,
11721217
) -> FatalResult<Option<bool>> {
11731218
match expr {
1174-
Expression::Literal(ref lit) => {
1175-
self.analyze_literal_with_target_type(target_type, expr_pos, lit, diagnostics)
1176-
}
1219+
Expression::Literal(ref mut lit) => self.analyze_literal_with_target_type(
1220+
region,
1221+
target_type,
1222+
expr_pos,
1223+
lit,
1224+
diagnostics,
1225+
),
11771226
Expression::Name(ref mut name) => {
11781227
self.analyze_name_with_target_type(region, target_type, expr_pos, name, diagnostics)
11791228
}

vhdl_lang/src/analysis/tests/homographs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,10 @@ end package;
815815
// Secondary units
816816
duplicate(&code, "bugs", 1, 2),
817817
duplicate(&code, "bugs", 1, 3),
818+
Diagnostic::error(
819+
code.s("10 bangs", 2).s1("bangs"),
820+
"Physical unit of type 'phys_t' does not match physical type 'phys2_t'",
821+
),
818822
],
819823
);
820824
}

vhdl_lang/src/analysis/tests/resolves_names.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,3 +1471,42 @@ end architecture;
14711471
],
14721472
);
14731473
}
1474+
1475+
#[test]
1476+
fn hover_for_physical_type_units() {
1477+
let mut builder = LibraryBuilder::new();
1478+
let code = builder.in_declarative_region(
1479+
"
1480+
type time_t is range -9223372036854775807 to 9223372036854775807
1481+
units
1482+
small;
1483+
big = 1000 small;
1484+
end units;
1485+
1486+
constant the_time1 : time_t := small;
1487+
constant the_time2 : time_t := 1000 small;
1488+
constant the_time3 : time_t := big;
1489+
constant the_time4 : time_t := 1000 big;
1490+
1491+
",
1492+
);
1493+
1494+
let (root, diagnostics) = builder.get_analyzed_root();
1495+
check_no_diagnostics(&diagnostics);
1496+
1497+
for i in 0..3 {
1498+
let ent = root
1499+
.search_reference(code.source(), code.s("small", 1 + i).start())
1500+
.unwrap();
1501+
assert_eq!(ent.decl_pos().unwrap(), &code.s1("small").pos());
1502+
assert_eq!(root.format_declaration(ent), Some("small".to_string()));
1503+
}
1504+
1505+
for i in 0..2 {
1506+
let ent = root
1507+
.search_reference(code.source(), code.s("big", 1 + i).start())
1508+
.unwrap();
1509+
assert_eq!(ent.decl_pos().unwrap(), &code.s1("big").pos());
1510+
assert_eq!(root.format_declaration(ent), Some("1000 small".to_string()));
1511+
}
1512+
}

vhdl_lang/src/ast.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,14 +214,20 @@ pub struct BitString {
214214
pub value: Latin1String,
215215
}
216216

217+
#[derive(PartialEq, Debug, Clone)]
218+
pub struct PhysicalLiteral {
219+
pub value: AbstractLiteral,
220+
pub unit: WithRef<Ident>,
221+
}
222+
217223
/// LRM 9.3.2 Literals
218224
#[derive(PartialEq, Debug, Clone)]
219225
pub enum Literal {
220226
String(Latin1String),
221227
BitString(BitString),
222228
Character(u8),
223229
AbstractLiteral(AbstractLiteral),
224-
Physical(AbstractLiteral, Symbol),
230+
Physical(PhysicalLiteral),
225231
Null,
226232
}
227233

@@ -498,7 +504,7 @@ pub struct ProtectedTypeBody {
498504
pub struct PhysicalTypeDeclaration {
499505
pub range: Range,
500506
pub primary_unit: WithDecl<Ident>,
501-
pub secondary_units: Vec<(WithDecl<Ident>, Literal)>,
507+
pub secondary_units: Vec<(WithDecl<Ident>, PhysicalLiteral)>,
502508
}
503509

504510
/// LRM 5.2.2 Enumeration types

vhdl_lang/src/ast/display.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,20 @@ impl Display for BitString {
266266
}
267267
}
268268

269+
impl Display for PhysicalLiteral {
270+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
271+
write!(f, "{} {}", self.value, self.unit)
272+
}
273+
}
274+
269275
impl Display for Literal {
270276
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
271277
match self {
272278
Literal::String(ref val) => write!(f, "\"{}\"", val),
273279
Literal::BitString(ref val) => write!(f, "{}", val),
274280
Literal::Character(byte) => write!(f, "'{}'", *byte as char),
275281
Literal::AbstractLiteral(ref val) => write!(f, "{}", val),
276-
Literal::Physical(ref val, ref sym) => write!(f, "{} {}", val, sym),
282+
Literal::Physical(ref val) => write!(f, "{}", val),
277283
Literal::Null => write!(f, "null"),
278284
}
279285
}

vhdl_lang/src/ast/search.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub enum FoundDeclaration<'a> {
4747
InterfaceObject(&'a InterfaceObjectDeclaration),
4848
File(&'a FileDeclaration),
4949
Type(&'a TypeDeclaration),
50+
PhysicalTypePrimary(&'a WithDecl<Ident>),
51+
PhysicalTypeSecondary(&'a WithDecl<Ident>, &'a PhysicalLiteral),
5052
Component(&'a ComponentDeclaration),
5153
//Attribute(&'a AttributeDeclaration),
5254
Alias(&'a AliasDeclaration),
@@ -750,11 +752,22 @@ impl Search for TypeDeclaration {
750752
.or_not_found());
751753
}
752754
}
753-
// @TODO others
754-
_ => {
755+
TypeDefinition::Physical(ref physical) => {
756+
let PhysicalTypeDeclaration {
757+
range,
758+
primary_unit,
759+
secondary_units,
760+
} = physical;
761+
return_if_found!(range.search(searcher));
755762
return_if_found!(searcher
756-
.search_decl(FoundDeclaration::Type(self))
763+
.search_decl(FoundDeclaration::PhysicalTypePrimary(primary_unit))
757764
.or_not_found());
765+
for (ident, literal) in secondary_units.iter() {
766+
return_if_found!(searcher
767+
.search_decl(FoundDeclaration::PhysicalTypeSecondary(ident, literal))
768+
.or_not_found());
769+
return_if_found!(searcher.search_ident_ref(&literal.unit).or_not_found());
770+
}
758771
}
759772
}
760773
NotFound
@@ -779,7 +792,12 @@ fn search_pos_expr(pos: &SrcPos, expr: &Expression, searcher: &mut impl Searcher
779792
Allocator::Subtype(ref subtype) => subtype.search(searcher),
780793
}
781794
}
782-
Expression::Literal(_) => NotFound,
795+
Expression::Literal(literal) => match literal {
796+
Literal::Physical(PhysicalLiteral { unit, .. }) => {
797+
searcher.search_ident_ref(unit).or_not_found()
798+
}
799+
_ => NotFound,
800+
},
783801
}
784802
}
785803

@@ -1329,6 +1347,8 @@ impl<'a> HasNamedEntity for FoundDeclaration<'a> {
13291347
FoundDeclaration::EnumerationLiteral(_, elem) => elem.decl.as_ref(),
13301348
FoundDeclaration::File(value) => value.ident.decl.as_ref(),
13311349
FoundDeclaration::Type(value) => value.ident.decl.as_ref(),
1350+
FoundDeclaration::PhysicalTypePrimary(value) => value.decl.as_ref(),
1351+
FoundDeclaration::PhysicalTypeSecondary(value, _) => value.decl.as_ref(),
13321352
FoundDeclaration::Component(value) => value.ident.decl.as_ref(),
13331353
FoundDeclaration::Alias(value) => value.designator.decl.as_ref(),
13341354
FoundDeclaration::Package(value) => value.ident.decl.as_ref(),
@@ -1357,6 +1377,8 @@ impl<'a> HasSrcPos for FoundDeclaration<'a> {
13571377
FoundDeclaration::EnumerationLiteral(_, elem) => &elem.tree.pos,
13581378
FoundDeclaration::File(value) => value.ident.pos(),
13591379
FoundDeclaration::Type(value) => value.ident.pos(),
1380+
FoundDeclaration::PhysicalTypePrimary(value) => value.pos(),
1381+
FoundDeclaration::PhysicalTypeSecondary(value, _) => value.as_ref(),
13601382
FoundDeclaration::Component(value) => value.ident.pos(),
13611383
FoundDeclaration::Alias(value) => &value.designator.tree.pos,
13621384
FoundDeclaration::Package(value) => value.ident.pos(),
@@ -1407,6 +1429,12 @@ impl std::fmt::Display for FoundDeclaration<'_> {
14071429
FoundDeclaration::File(ref value) => {
14081430
write!(f, "{}", value)
14091431
}
1432+
FoundDeclaration::PhysicalTypePrimary(ref value) => {
1433+
write!(f, "{}", value)
1434+
}
1435+
FoundDeclaration::PhysicalTypeSecondary(_, ref literal) => {
1436+
write!(f, "{}", literal)
1437+
}
14101438
FoundDeclaration::Type(ref value) => {
14111439
write!(f, "{}", value)
14121440
}

0 commit comments

Comments
 (0)