Skip to content

Commit 189b5fb

Browse files
committed
Improve analysis of 'range attribute prefix
1 parent 8d02494 commit 189b5fb

File tree

3 files changed

+116
-137
lines changed

3 files changed

+116
-137
lines changed

vhdl_lang/src/analysis/named_entity/types.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -151,24 +151,11 @@ impl<'a> TypeEnt<'a> {
151151
}
152152

153153
pub fn accessed_type(&self) -> Option<TypeEnt<'a>> {
154-
if let Type::Access(subtype) = self.base_type().kind() {
155-
Some(subtype.type_mark())
156-
} else {
157-
None
158-
}
154+
self.base().accessed_type()
159155
}
160156

161157
pub fn array_type(&self) -> Option<(TypeEnt<'a>, &'a Vec<Option<BaseType<'a>>>)> {
162-
if let Type::Array {
163-
elem_type, indexes, ..
164-
} = self.base_type().kind()
165-
{
166-
Some((*elem_type, indexes))
167-
} else if let Some(accessed_typ) = self.accessed_type() {
168-
accessed_typ.array_type()
169-
} else {
170-
None
171-
}
158+
self.base().array_type()
172159
}
173160

174161
pub fn is_scalar(&self) -> bool {
@@ -342,6 +329,27 @@ impl<'a> BaseType<'a> {
342329
}
343330
}
344331

332+
pub fn array_type(&self) -> Option<(TypeEnt<'a>, &'a Vec<Option<BaseType<'a>>>)> {
333+
if let Type::Array {
334+
elem_type, indexes, ..
335+
} = self.kind()
336+
{
337+
Some((*elem_type, indexes))
338+
} else if let Some(accessed_typ) = self.accessed_type() {
339+
accessed_typ.array_type()
340+
} else {
341+
None
342+
}
343+
}
344+
345+
pub fn accessed_type(&self) -> Option<TypeEnt<'a>> {
346+
if let Type::Access(subtype) = self.kind() {
347+
Some(subtype.type_mark())
348+
} else {
349+
None
350+
}
351+
}
352+
345353
pub fn is_discrete(&self) -> bool {
346354
matches!(
347355
self.kind(),

vhdl_lang/src/analysis/names.rs

Lines changed: 43 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ impl<'a> ResolvedName<'a> {
267267
}
268268
}
269269

270-
fn as_type_of_attr_prefix(
270+
pub(crate) fn as_type_of_attr_prefix(
271271
&self,
272272
prefix_pos: &SrcPos,
273273
attr: &AttributeSuffix,
@@ -656,6 +656,43 @@ impl<'a> AnalyzeContext<'a> {
656656
}
657657
}
658658

659+
// Resolve an index used in an array attribute such as arr_t'left(0) to an index type
660+
pub(crate) fn array_index_expression_in_attribute(
661+
&self,
662+
indexes: &[Option<BaseType<'a>>],
663+
mut expr: Option<&mut WithPos<Expression>>,
664+
diagnostics: &mut dyn DiagnosticHandler,
665+
) -> EvalResult<BaseType<'a>> {
666+
let idx = if let Some(expr) = expr.as_mut() {
667+
if let Expression::Literal(Literal::AbstractLiteral(AbstractLiteral::Integer(idx))) =
668+
expr.item
669+
{
670+
idx as usize
671+
} else {
672+
diagnostics.error(&expr.pos, "Expected an integer literal");
673+
return Err(EvalError::Unknown);
674+
}
675+
} else {
676+
1
677+
};
678+
679+
if let Some(idx_typ) = indexes.get(idx - 1) {
680+
if let Some(idx_typ) = idx_typ {
681+
Ok(*idx_typ)
682+
} else {
683+
// Array index was not analyzed
684+
Err(EvalError::Unknown)
685+
}
686+
} else {
687+
if let Some(expr) = expr {
688+
let ndims = indexes.len();
689+
let dimensions = plural("dimension", "dimensions", ndims);
690+
diagnostics.error(&expr.pos, format!("Index {idx} out of range for array with {ndims} {dimensions}, expected 1 to {ndims}"));
691+
}
692+
Err(EvalError::Unknown)
693+
}
694+
}
695+
659696
pub fn attribute_suffix(
660697
&self,
661698
name_pos: &SrcPos,
@@ -673,35 +710,11 @@ impl<'a> AnalyzeContext<'a> {
673710
let typ = prefix.as_type_of_attr_prefix(prefix_pos, attr, diagnostics)?;
674711

675712
if let Some((_, indexes)) = typ.array_type() {
676-
let idx = if let Some(expr) = attr.expr {
677-
if let Expression::Literal(Literal::AbstractLiteral(
678-
AbstractLiteral::Integer(idx),
679-
)) = expr.item
680-
{
681-
idx as usize
682-
} else {
683-
diagnostics.error(&expr.pos, "Expected an integer literal");
684-
return Err(EvalError::Unknown);
685-
}
686-
} else {
687-
1
688-
};
689-
690-
if let Some(idx_typ) = indexes.get(idx - 1) {
691-
if let Some(idx_typ) = idx_typ {
692-
Ok(*idx_typ)
693-
} else {
694-
// Array index was not analyzed
695-
Err(EvalError::Unknown)
696-
}
697-
} else {
698-
if let Some(expr) = attr.expr {
699-
let ndims = indexes.len();
700-
let dimensions = plural("dimension", "dimensions", ndims);
701-
diagnostics.error(&expr.pos, format!("Index {idx} out of range for array with {ndims} {dimensions}, expected 1 to {ndims}"));
702-
}
703-
Err(EvalError::Unknown)
704-
}
713+
self.array_index_expression_in_attribute(
714+
indexes,
715+
attr.expr.as_mut().map(|expr| expr.as_mut()),
716+
diagnostics,
717+
)
705718
} else if typ.is_scalar() {
706719
check_no_attr_argument(attr, diagnostics);
707720
Ok(typ.into())
@@ -1369,96 +1382,6 @@ impl<'a> AnalyzeContext<'a> {
13691382
Ok(())
13701383
}
13711384

1372-
/// Fallback solution that just lookups names
1373-
pub fn resolve_name(
1374-
&self,
1375-
scope: &Scope<'a>,
1376-
name_pos: &SrcPos,
1377-
name: &mut Name,
1378-
diagnostics: &mut dyn DiagnosticHandler,
1379-
) -> EvalResult<NamedEntities<'a>> {
1380-
match name {
1381-
Name::Selected(prefix, suffix) => {
1382-
match self.resolve_name(scope, &prefix.pos, &mut prefix.item, diagnostics)? {
1383-
NamedEntities::Single(named_entity) => {
1384-
match self.lookup_selected(&prefix.pos, named_entity, suffix) {
1385-
Ok(visible) => {
1386-
suffix.set_reference(&visible);
1387-
Ok(visible)
1388-
}
1389-
Err(err) => {
1390-
err.add_to(diagnostics)?;
1391-
Err(EvalError::Unknown)
1392-
}
1393-
}
1394-
}
1395-
NamedEntities::Overloaded(..) => Err(EvalError::Unknown),
1396-
}
1397-
}
1398-
1399-
Name::SelectedAll(prefix) => {
1400-
self.resolve_name(scope, &prefix.pos, &mut prefix.item, diagnostics)?;
1401-
Err(EvalError::Unknown)
1402-
}
1403-
Name::Designator(designator) => match scope.lookup(name_pos, designator.designator()) {
1404-
Ok(visible) => {
1405-
designator.set_reference(&visible);
1406-
Ok(visible)
1407-
}
1408-
Err(diagnostic) => {
1409-
diagnostics.push(diagnostic);
1410-
Err(EvalError::Unknown)
1411-
}
1412-
},
1413-
Name::Slice(ref mut prefix, ref mut drange) => {
1414-
self.resolve_name(scope, &prefix.pos, &mut prefix.item, diagnostics)?;
1415-
self.drange_unknown_type(scope, drange.as_mut(), diagnostics)?;
1416-
Err(EvalError::Unknown)
1417-
}
1418-
Name::Attribute(ref mut attr) => {
1419-
self.analyze_attribute_name(scope, attr, diagnostics)?;
1420-
Err(EvalError::Unknown)
1421-
}
1422-
Name::CallOrIndexed(ref mut call) => {
1423-
self.resolve_name(scope, &call.name.pos, &mut call.name.item, diagnostics)?;
1424-
self.analyze_assoc_elems(scope, &mut call.parameters, diagnostics)?;
1425-
Err(EvalError::Unknown)
1426-
}
1427-
Name::External(ref mut ename) => {
1428-
let ExternalName { subtype, .. } = ename.as_mut();
1429-
self.analyze_subtype_indication(scope, subtype, diagnostics)?;
1430-
Err(EvalError::Unknown)
1431-
}
1432-
}
1433-
}
1434-
1435-
pub fn analyze_attribute_name(
1436-
&self,
1437-
scope: &Scope<'a>,
1438-
attr: &mut AttributeName,
1439-
diagnostics: &mut dyn DiagnosticHandler,
1440-
) -> FatalResult {
1441-
// @TODO more, attr must be checked inside the scope of attributes of prefix
1442-
let AttributeName {
1443-
name,
1444-
signature,
1445-
expr,
1446-
..
1447-
} = attr;
1448-
1449-
as_fatal(self.resolve_name(scope, &name.pos, &mut name.item, diagnostics))?;
1450-
1451-
if let Some(ref mut signature) = signature {
1452-
if let Err(err) = self.resolve_signature(scope, signature) {
1453-
err.add_to(diagnostics)?;
1454-
}
1455-
}
1456-
if let Some(ref mut expr) = expr {
1457-
self.expr_unknown_ttyp(scope, expr, diagnostics)?;
1458-
}
1459-
Ok(())
1460-
}
1461-
14621385
/// Analyze an indexed name where the prefix entity is already known
14631386
/// Returns the type of the array element
14641387
pub fn analyze_indexed_name(

vhdl_lang/src/analysis/range.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use super::analyze::*;
88
use super::expression::ExpressionType;
99
use super::named_entity::*;
10+
use super::names::AttributeSuffix;
1011
use super::names::ResolvedName;
1112
use super::overloaded::Disambiguated;
1213
use super::overloaded::DisambiguatedType;
@@ -273,8 +274,55 @@ impl<'a> AnalyzeContext<'a> {
273274
diagnostics,
274275
)?;
275276
}
276-
Range::Attribute(ref mut attr) => {
277-
self.analyze_attribute_name(scope, attr, diagnostics)?;
277+
Range::Attribute(ref mut name) => {
278+
let AttributeName {
279+
name,
280+
signature,
281+
expr,
282+
attr, // Parser ensures this must be 'range or we would not end up here
283+
} = name.as_mut();
284+
285+
let prefix_typ = as_fatal(
286+
self.name_resolve(scope, &name.pos, &mut name.item, diagnostics)
287+
.and_then(|prefix| {
288+
prefix.as_type_of_attr_prefix(
289+
&name.pos,
290+
&AttributeSuffix {
291+
signature,
292+
attr,
293+
expr,
294+
},
295+
diagnostics,
296+
)
297+
}),
298+
)?;
299+
300+
if let Some(ref mut signature) = signature {
301+
diagnostics.error(
302+
&signature.pos,
303+
format!("Did not expect signature for '{attr} attribute"),
304+
);
305+
}
306+
307+
if let Some(prefix_typ) = prefix_typ {
308+
if let Some((_, indexes)) = prefix_typ.array_type() {
309+
if let Some(index_typ) =
310+
as_fatal(self.array_index_expression_in_attribute(
311+
indexes,
312+
expr.as_mut().map(|expr| expr.as_mut()),
313+
diagnostics,
314+
))?
315+
{
316+
if !self.can_be_target_type(index_typ.into(), target_type.base()) {
317+
diagnostics.push(Diagnostic::type_mismatch(
318+
&range.pos(),
319+
&index_typ.describe(),
320+
target_type,
321+
))
322+
}
323+
}
324+
}
325+
}
278326
}
279327
}
280328
Ok(())

0 commit comments

Comments
 (0)