Skip to content

Commit d004b34

Browse files
committed
Add range type detection
1 parent 3a30c23 commit d004b34

File tree

9 files changed

+517
-28
lines changed

9 files changed

+517
-28
lines changed

vhdl_lang/src/analysis/declarative.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ impl<'a> AnalyzeContext<'a> {
737737
}
738738
}
739739
TypeDefinition::Array(ref mut array_indexes, ref mut subtype_indication) => {
740-
let mut indexes: Vec<Option<TypeEnt>> = Vec::with_capacity(array_indexes.len());
740+
let mut indexes: Vec<Option<BaseType>> = Vec::with_capacity(array_indexes.len());
741741
for index in array_indexes.iter_mut() {
742742
indexes.push(as_fatal(self.analyze_array_index(
743743
scope,
@@ -1086,20 +1086,19 @@ impl<'a> AnalyzeContext<'a> {
10861086
scope: &Scope<'a>,
10871087
array_index: &mut ArrayIndex,
10881088
diagnostics: &mut dyn DiagnosticHandler,
1089-
) -> EvalResult<TypeEnt<'a>> {
1089+
) -> EvalResult<BaseType<'a>> {
10901090
match array_index {
10911091
ArrayIndex::IndexSubtypeDefintion(ref mut type_mark) => {
10921092
match self.resolve_type_mark(scope, type_mark) {
1093-
Ok(typ) => Ok(typ),
1093+
Ok(typ) => Ok(typ.base()),
10941094
Err(err) => {
10951095
err.add_to(diagnostics)?;
10961096
Err(EvalError::Unknown)
10971097
}
10981098
}
10991099
}
11001100
ArrayIndex::Discrete(ref mut drange) => {
1101-
self.analyze_discrete_range(scope, drange, diagnostics)?;
1102-
Err(EvalError::Unknown)
1101+
self.discrete_range_type(scope, drange, diagnostics)
11031102
}
11041103
}
11051104
}

vhdl_lang/src/analysis/expression.rs

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,29 @@ impl<'a> AnalyzeContext<'a> {
120120
self.matcher().is_possible(types, ttyp)
121121
}
122122

123+
pub fn common_type(&self, typ1: BaseType<'a>, typ2: BaseType<'a>) -> Option<BaseType<'a>> {
124+
if typ1.id() == typ2.id() {
125+
Some(typ1)
126+
} else if typ1.is_universal_of(typ2) {
127+
Some(typ2)
128+
} else if typ2.is_universal_of(typ1) {
129+
Some(typ1)
130+
} else {
131+
None
132+
}
133+
}
134+
135+
pub fn common_types(
136+
&self,
137+
types: FnvHashSet<BaseType<'a>>,
138+
typ: BaseType<'a>,
139+
) -> FnvHashSet<BaseType<'a>> {
140+
types
141+
.into_iter()
142+
.filter_map(|t| self.common_type(t, typ))
143+
.collect()
144+
}
145+
123146
pub fn can_be_target_type(&self, typ: TypeEnt<'a>, ttyp: BaseType<'a>) -> bool {
124147
self.matcher().can_be_target_type(typ, ttyp)
125148
}
@@ -235,20 +258,44 @@ impl<'a> AnalyzeContext<'a> {
235258
if candidates.len() > 1 {
236259
self.matcher()
237260
.disambiguate_op_by_arguments(&mut candidates, &operand_types);
261+
}
238262

239-
if candidates.len() > 1 && ttyp.is_some() {
240-
self.matcher()
241-
.disambiguate_op_by_return_type(&mut candidates, ttyp);
263+
if candidates.len() > 1 && ttyp.is_some() {
264+
self.matcher()
265+
.disambiguate_op_by_return_type(&mut candidates, ttyp);
266+
}
242267

243-
if candidates.len() > 1 {
244-
self.matcher_no_implicit()
245-
.disambiguate_op_by_arguments(&mut candidates, &operand_types);
268+
// Try to further disambiguate by removing implicit universal casts
269+
if candidates.len() > 1 {
270+
let return_types: FnvHashSet<_> = candidates
271+
.iter()
272+
.map(|c| c.return_type().unwrap().base())
273+
.collect();
246274

247-
if candidates.len() > 1 {
248-
self.matcher_no_implicit()
249-
.disambiguate_op_by_return_type(&mut candidates, ttyp);
275+
if return_types.len() == 1 {
276+
self.matcher_no_implicit()
277+
.disambiguate_op_by_arguments(&mut candidates, &operand_types);
278+
}
279+
}
280+
281+
if candidates.len() > 1 {
282+
if ttyp.is_some() {
283+
self.matcher_no_implicit()
284+
.disambiguate_op_by_return_type(&mut candidates, ttyp);
285+
} else {
286+
let return_types: FnvHashSet<_> = candidates
287+
.iter()
288+
.map(|c| c.return_type().unwrap().base())
289+
.collect();
290+
291+
// Remove INTEGER if universal integer is a candidate
292+
candidates.retain(|cand| {
293+
if let Some(univ) = self.as_universal(cand.return_type().unwrap().base()) {
294+
!return_types.contains(&univ)
295+
} else {
296+
true
250297
}
251-
}
298+
})
252299
}
253300
}
254301

@@ -268,6 +315,14 @@ impl<'a> AnalyzeContext<'a> {
268315
}
269316
}
270317

318+
fn as_universal(&self, typ: BaseType<'a>) -> Option<BaseType<'a>> {
319+
match typ.kind() {
320+
Type::Integer => Some(self.universal_integer()),
321+
Type::Real => Some(self.universal_real()),
322+
_ => None,
323+
}
324+
}
325+
271326
pub fn operator_type(
272327
&self,
273328
scope: &Scope<'a>,
@@ -734,7 +789,7 @@ impl<'a> AnalyzeContext<'a> {
734789
&self,
735790
scope: &Scope<'a>,
736791
array_type: TypeEnt<'a>,
737-
index_type: Option<TypeEnt<'a>>,
792+
index_type: Option<BaseType<'a>>,
738793
elem_type: TypeEnt<'a>,
739794
assoc: &mut ElementAssociation,
740795
diagnostics: &mut dyn DiagnosticHandler,
@@ -760,7 +815,7 @@ impl<'a> AnalyzeContext<'a> {
760815
if let Some(index_type) = index_type {
761816
self.expr_with_ttyp(
762817
scope,
763-
index_type,
818+
index_type.into(),
764819
&index_expr.pos,
765820
&mut index_expr.item,
766821
diagnostics,
@@ -778,7 +833,7 @@ impl<'a> AnalyzeContext<'a> {
778833
if let Some(index_type) = index_type {
779834
self.analyze_discrete_range_with_target_type(
780835
scope,
781-
index_type,
836+
index_type.into(),
782837
drange,
783838
diagnostics,
784839
)?;
@@ -1145,4 +1200,40 @@ constant c0 : rec_t := (0, 1);
11451200
Some(ExpressionType::Unambiguous(test.lookup_type("boolean")))
11461201
);
11471202
}
1203+
1204+
#[test]
1205+
fn does_not_remove_universal_candidates_when_return_types_differ() {
1206+
let test = TestSetup::new();
1207+
test.declarative_part(
1208+
"
1209+
function \"+\"(a : integer; b : character) return character;
1210+
function \"+\"(a : integer; b : character) return integer;
1211+
",
1212+
);
1213+
1214+
let code = test.snippet("0 + 'c'");
1215+
assert_eq!(
1216+
test.expr_type(&code, &mut NoDiagnostics),
1217+
Some(ExpressionType::Ambiguous(
1218+
vec![
1219+
test.lookup_type("integer").base(),
1220+
test.lookup_type("character").base()
1221+
]
1222+
.into_iter()
1223+
.collect()
1224+
))
1225+
);
1226+
}
1227+
1228+
#[test]
1229+
fn universal_expression_is_not_ambiguous() {
1230+
let test = TestSetup::new();
1231+
let code = test.snippet("-1");
1232+
assert_eq!(
1233+
test.expr_type(&code, &mut NoDiagnostics),
1234+
Some(ExpressionType::Unambiguous(
1235+
test.ctx().universal_integer().into()
1236+
))
1237+
);
1238+
}
11481239
}

vhdl_lang/src/analysis/named_entity.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ impl<'a> AnyEnt<'a> {
317317
format!("{}{}", self.designator, overloaded.signature().describe())
318318
}
319319

320+
AnyEntKind::Type(Type::Universal(typ)) => format!("type {}", typ.describe().to_owned()),
320321
_ => format!("{} '{}'", self.kind.describe(), self.designator),
321322
}
322323
}

vhdl_lang/src/analysis/named_entity/types.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub enum Type<'a> {
2626
// Use Weak reference since implicit declaration typically reference the type itself
2727
Array {
2828
// Indexes are Option<> to handle unknown types
29-
indexes: Vec<Option<TypeEnt<'a>>>,
29+
indexes: Vec<Option<BaseType<'a>>>,
3030
elem_type: TypeEnt<'a>,
3131
},
3232
Enum(FnvHashSet<Designator>),
@@ -282,6 +282,16 @@ impl<'a> BaseType<'a> {
282282
}
283283
}
284284

285+
pub fn is_universal_of(&self, other: BaseType<'a>) -> bool {
286+
let i = matches!(self.kind(), Type::Universal(UniversalType::Integer))
287+
&& matches!(other.kind(), Type::Integer);
288+
289+
let r = matches!(self.kind(), Type::Universal(UniversalType::Real))
290+
&& matches!(other.kind(), Type::Real);
291+
292+
i || r
293+
}
294+
285295
pub fn sliced_as(&self) -> Option<TypeEnt<'a>> {
286296
let typ = if let Type::Access(ref subtype, ..) = self.kind() {
287297
subtype.type_mark()
@@ -295,6 +305,13 @@ impl<'a> BaseType<'a> {
295305
None
296306
}
297307
}
308+
309+
pub fn is_discrete(&self) -> bool {
310+
matches!(
311+
self.kind(),
312+
Type::Integer | Type::Enum(_) | Type::Universal(UniversalType::Integer)
313+
)
314+
}
298315
}
299316

300317
impl<'a> From<BaseType<'a>> for EntRef<'a> {

vhdl_lang/src/analysis/package_instance.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ impl<'a> AnalyzeContext<'a> {
414414
let mut mapped_indexes = Vec::with_capacity(indexes.len());
415415
for index_typ in indexes.iter() {
416416
mapped_indexes.push(if let Some(index_typ) = index_typ {
417-
Some(self.map_type_ent(mapping, *index_typ)?)
417+
Some(self.map_type_ent(mapping, (*index_typ).into())?.base())
418418
} else {
419419
None
420420
})

0 commit comments

Comments
 (0)