Skip to content

Commit ae17851

Browse files
committed
Make real a real type
1 parent de6489a commit ae17851

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

vhdl_lang/src/analysis/declarative.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -717,11 +717,13 @@ impl<'a> AnalyzeContext<'a> {
717717
self.analyze_range(parent, range, diagnostics)?;
718718
let implicit = ImplicitVecBuilder::default();
719719

720-
let type_ent = TypeEnt::define_with_opt_id(
721-
overwrite_id,
722-
&mut type_decl.ident,
723-
Type::Integer(implicit.inner()),
724-
);
720+
let kind = match integer_or_real_range(range) {
721+
ScalarType::Integer => Type::Integer(implicit.inner()),
722+
ScalarType::Real => Type::Real(implicit.inner()),
723+
};
724+
725+
let type_ent =
726+
TypeEnt::define_with_opt_id(overwrite_id, &mut type_decl.ident, kind);
725727
parent.add(type_ent.clone().into(), diagnostics);
726728

727729
if !self.is_standard_package() {
@@ -1062,3 +1064,25 @@ fn signature_error(pos: impl AsRef<SrcPos>) -> Diagnostic {
10621064
"Alias should only have a signature for subprograms and enum literals",
10631065
)
10641066
}
1067+
1068+
enum ScalarType {
1069+
Integer,
1070+
Real,
1071+
}
1072+
1073+
/// @TODO A simple and incomplete way to disambiguate integer and real in standard.vhd
1074+
fn integer_or_real_range(range: &ast::Range) -> ScalarType {
1075+
if let ast::Range::Range(RangeConstraint { left_expr, .. }) = range {
1076+
let expr = if let Expression::Unary(_, ref expr) = left_expr.item {
1077+
&expr.item
1078+
} else {
1079+
&left_expr.item
1080+
};
1081+
1082+
if let Expression::Literal(Literal::AbstractLiteral(AbstractLiteral::Real(_))) = expr {
1083+
return ScalarType::Real;
1084+
}
1085+
}
1086+
1087+
ScalarType::Integer
1088+
}

vhdl_lang/src/analysis/named_entity.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub enum Type {
2727
},
2828
Enum(ImplicitVec, FnvHashSet<Designator>),
2929
Integer(ImplicitVec),
30+
Real(ImplicitVec),
3031
Physical(ImplicitVec),
3132
Access(Subtype, ImplicitVec),
3233
Record(Arc<Region<'static>>),
@@ -50,6 +51,7 @@ impl Type {
5051
match self {
5152
Type::Array { ref implicit, .. } => Some(implicit),
5253
Type::Enum(ref implicit, _) => Some(implicit),
54+
Type::Real(ref implicit) => Some(implicit),
5355
Type::Integer(ref implicit) => Some(implicit),
5456
Type::Physical(ref implicit) => Some(implicit),
5557
Type::File(ref implicit) => Some(implicit),
@@ -70,6 +72,7 @@ impl Type {
7072
Type::Array { .. } => "array type",
7173
Type::Enum(..) => "type",
7274
Type::Integer(..) => "integer type",
75+
Type::Real(..) => "real type",
7376
Type::Physical(..) => "physical type",
7477
Type::Access(..) => "access type",
7578
Type::Subtype(..) => "subtype",

vhdl_lang/src/analysis/semantic.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,17 @@ impl<'a> AnalyzeContext<'a> {
10601060
}
10611061
Some(is_correct)
10621062
}
1063+
Literal::AbstractLiteral(AbstractLiteral::Real(_)) => {
1064+
let is_correct = matches!(target_base.kind(), Type::Real(..));
1065+
1066+
if !is_correct {
1067+
diagnostics.push(Diagnostic::error(
1068+
pos,
1069+
format!("real literal does not match {}", target_type.describe()),
1070+
));
1071+
}
1072+
Some(is_correct)
1073+
}
10631074
Literal::Character(char) => match target_base.kind() {
10641075
Type::Enum(_, literals) => {
10651076
if literals.contains(&Designator::Character(*char)) {

vhdl_lang/src/analysis/tests/typecheck_expression.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,3 +567,32 @@ constant const : natural := thefun('c');
567567
],
568568
);
569569
}
570+
571+
#[test]
572+
fn check_real_vs_integer() {
573+
let mut builder = LibraryBuilder::new();
574+
let code = builder.in_declarative_region(
575+
"
576+
constant rgood : real := 1.2;
577+
constant rbad : real := 3;
578+
579+
constant igood : integer := 4;
580+
constant ibad : integer := 5.6;
581+
582+
",
583+
);
584+
let diagnostics = builder.analyze();
585+
check_diagnostics(
586+
diagnostics,
587+
vec![
588+
Diagnostic::error(
589+
code.s1("3"),
590+
"integer literal does not match real type 'REAL'",
591+
),
592+
Diagnostic::error(
593+
code.s1("5.6"),
594+
"real literal does not match integer type 'INTEGER'",
595+
),
596+
],
597+
);
598+
}

0 commit comments

Comments
 (0)