Skip to content

Commit

Permalink
Simplify analysis for TypeMark in favour of existing name analysis (#…
Browse files Browse the repository at this point in the history
…316)

This removes the special `TypeMark` AST element and replaces it's usage with the `Name` AST element.
  • Loading branch information
Schottkyc137 committed Jul 5, 2024
1 parent 94f3fd2 commit 9b06eca
Show file tree
Hide file tree
Showing 28 changed files with 199 additions and 357 deletions.
7 changes: 4 additions & 3 deletions vhdl_lang/src/analysis/declarative.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,9 +507,10 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
}
Declaration::Attribute(ref mut attr) => match attr {
Attribute::Declaration(ref mut attr_decl) => {
if let Some(typ) = as_fatal(self.resolve_type_mark(
if let Some(typ) = as_fatal(self.type_name(
scope,
&mut attr_decl.type_mark,
attr_decl.type_mark.span,
&mut attr_decl.type_mark.item,
diagnostics,
))? {
scope.add(
Expand Down Expand Up @@ -1088,7 +1089,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
) -> EvalResult<BaseType<'a>> {
match array_index {
ArrayIndex::IndexSubtypeDefintion(ref mut type_mark) => self
.resolve_type_mark(scope, type_mark, diagnostics)
.type_name(scope, type_mark.span, &mut type_mark.item, diagnostics)
.map(|typ| typ.base()),
ArrayIndex::Discrete(ref mut drange) => self.drange_type(scope, drange, diagnostics),
}
Expand Down
26 changes: 7 additions & 19 deletions vhdl_lang/src/analysis/design_unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,11 +258,8 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
if let Design::Entity(ref visibility, ref region) = primary.kind() {
(visibility, region)
} else {
let mut diagnostic = Diagnostic::new(
unit.ident_pos(self.ctx),
"Expected an entity",
ErrorCode::MismatchedKinds,
);
let mut diagnostic =
Diagnostic::mismatched_kinds(unit.ident_pos(self.ctx), "Expected an entity");

if let Some(pos) = primary.decl_pos() {
diagnostic.add_related(pos, format!("Found {}", primary.describe()))
Expand Down Expand Up @@ -329,11 +326,8 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
Design::Package(ref visibility, ref region)
| Design::UninstPackage(ref visibility, ref region) => (visibility, region),
_ => {
let mut diagnostic = Diagnostic::new(
unit.ident_pos(self.ctx),
"Expected a package",
ErrorCode::MismatchedKinds,
);
let mut diagnostic =
Diagnostic::mismatched_kinds(unit.ident_pos(self.ctx), "Expected a package");

if let Some(pos) = primary.decl_pos() {
diagnostic.add_related(pos, format!("Found {}", primary.describe()))
Expand Down Expand Up @@ -491,21 +485,19 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
Err(_) => {
bail!(
diagnostics,
Diagnostic::new(
Diagnostic::mismatched_kinds(
&prefix.pos(self.ctx),
"Invalid prefix of a selected name",
ErrorCode::MismatchedKinds
)
);
}
},
UsedNames::AllWithin(..) => {
bail!(
diagnostics,
Diagnostic::new(
Diagnostic::mismatched_kinds(
&prefix.pos(self.ctx),
"'.all' may not be the prefix of a selected name",
ErrorCode::MismatchedKinds
)
);
}
Expand Down Expand Up @@ -545,11 +537,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
| Name::External(..) => {
bail!(
diagnostics,
Diagnostic::new(
&name.pos(self.ctx),
"Invalid selected name",
ErrorCode::MismatchedKinds
)
Diagnostic::mismatched_kinds(&name.pos(self.ctx), "Invalid selected name",)
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion vhdl_lang/src/analysis/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
) -> EvalResult<TypeEnt<'a>> {
let QualifiedExpression { type_mark, expr } = qexpr;

match as_fatal(self.resolve_type_mark(scope, type_mark, diagnostics))? {
match as_fatal(self.type_name(scope, type_mark.span, &mut type_mark.item, diagnostics))? {
Some(target_type) => {
self.expr_pos_with_ttyp(
scope,
Expand Down
3 changes: 1 addition & 2 deletions vhdl_lang/src/analysis/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,9 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
))
}
}
NamedEntities::Overloaded(_) => Err(Diagnostic::new(
NamedEntities::Overloaded(_) => Err(Diagnostic::mismatched_kinds(
unit.item.pos(self.ctx),
"Overloaded name may not be physical unit",
ErrorCode::MismatchedKinds,
)),
}
}
Expand Down
116 changes: 62 additions & 54 deletions vhdl_lang/src/analysis/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,14 +399,6 @@ impl<'a> ResolvedName<'a> {
ResolvedName::Final(_) => None,
}
}

/// Convenience function that returns `Some(name)` when self is an object name, else `None`
fn as_object_name(&self) -> Option<ObjectName<'a>> {
match self {
ResolvedName::ObjectName(oname) => Some(*oname),
_ => None,
}
}
}

/// Represents the result when resolving an attribute.
Expand Down Expand Up @@ -505,10 +497,9 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
) -> Result<Option<DisambiguatedType<'a>>, Diagnostic> {
match name {
ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => {
Err(Diagnostic::new(
Err(Diagnostic::mismatched_kinds(
pos.pos(self.ctx),
format!("{} cannot be used in an expression", name.describe_type()),
ErrorCode::MismatchedKinds,
))
}
ResolvedName::Final(ent) => match ent.actual_kind() {
Expand All @@ -520,10 +511,9 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
Ok(Some(DisambiguatedType::Unambiguous(subtype.type_mark())))
}
AnyEntKind::InterfaceFile(typ) => Ok(Some(DisambiguatedType::Unambiguous(*typ))),
_ => Err(Diagnostic::new(
_ => Err(Diagnostic::mismatched_kinds(
pos.pos(self.ctx),
format!("{} cannot be used in an expression", name.describe_type()),
ErrorCode::MismatchedKinds,
)),
},
ResolvedName::Overloaded(des, overloaded) => {
Expand Down Expand Up @@ -555,21 +545,19 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
) -> Result<Option<TypeEnt<'a>>, Diagnostic> {
match name {
ResolvedName::Library(_) | ResolvedName::Design(_) | ResolvedName::Type(_) => {
Err(Diagnostic::new(
Err(Diagnostic::mismatched_kinds(
span.pos(self.ctx),
format!("{} cannot be used in an expression", name.describe_type()),
ErrorCode::MismatchedKinds,
))
}
ResolvedName::Final(ent) => match ent.actual_kind() {
AnyEntKind::LoopParameter(typ) => Ok(typ.map(|typ| typ.into())),
AnyEntKind::PhysicalLiteral(typ) => Ok(Some(*typ)),
AnyEntKind::File(subtype) => Ok(Some(subtype.type_mark())),
AnyEntKind::InterfaceFile(typ) => Ok(Some(*typ)),
_ => Err(Diagnostic::new(
_ => Err(Diagnostic::mismatched_kinds(
span.pos(self.ctx),
format!("{} cannot be used in an expression", name.describe_type()),
ErrorCode::MismatchedKinds,
)),
},
ResolvedName::Overloaded(des, overloaded) => {
Expand Down Expand Up @@ -659,10 +647,9 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
} else {
bail!(
diagnostics,
Diagnostic::new(
Diagnostic::mismatched_kinds(
expr_pos.pos(self.ctx),
format!("{} cannot be used as a discrete range", typ.describe()),
ErrorCode::MismatchedKinds,
)
);
};
Expand Down Expand Up @@ -1131,7 +1118,7 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
Err(EvalError::Unknown)
}
AttributeDesignator::Type(attr) => self
.resolve_type_attribute_suffix(prefix, &attr, name_pos, diagnostics)
.resolve_type_attribute_suffix(prefix, prefix_pos, &attr, name_pos, diagnostics)
.map(|typ| AttrResolveResult::Type(typ.base())),
AttributeDesignator::Converse => {
let view = self.resolve_view_ent(prefix, diagnostics, prefix_pos)?;
Expand All @@ -1154,35 +1141,49 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
fn resolve_type_attribute_suffix(
&self,
prefix: &ResolvedName<'a>,
prefix_pos: TokenSpan,
suffix: &TypeAttribute,
pos: TokenSpan,
diagnostics: &mut dyn DiagnosticHandler,
) -> EvalResult<TypeEnt<'a>> {
// all type attribute suffixes require that the prefix be an object type
let Some(obj) = prefix.as_object_name() else {
diagnostics.add(
pos.pos(self.ctx),
format!(
"The {} attribute can only be used on objects, not {}",
suffix,
prefix.describe()
),
ErrorCode::IllegalAttribute,
);
return Err(EvalError::Unknown);
let typ = match prefix {
ResolvedName::Type(typ) => {
if *suffix == TypeAttribute::Element {
*typ
} else {
let diag = Diagnostic::illegal_attribute(
pos.pos(self.ctx),
format!(
"The {suffix} attribute can only be used on objects, not {}",
typ.describe()
),
)
.opt_related(typ.decl_pos(), "Defined here");
bail!(diagnostics, diag);
}
}
ResolvedName::ObjectName(obj) => obj.type_mark(),
other => {
let diag = Diagnostic::mismatched_kinds(
pos.pos(self.ctx),
format!("Expected type, got {}", other.describe()),
)
.opt_related(other.decl_pos(), "Defined here");
bail!(diagnostics, diag);
}
};

match suffix {
TypeAttribute::Subtype => Ok(obj.type_mark()),
TypeAttribute::Subtype => Ok(typ),
TypeAttribute::Element => {
if let Some((elem_type, _)) = obj.type_mark().array_type() {
if let Some((elem_type, _)) = typ.array_type() {
Ok(elem_type)
} else {
diagnostics.add(
pos.pos(self.ctx),
"The element attribute can only be used for array types",
ErrorCode::IllegalAttribute,
let diag = Diagnostic::illegal_attribute(
prefix_pos.pos(self.ctx),
format!("array type expected for '{suffix} attribute"),
);
Err(EvalError::Unknown)
bail!(diagnostics, diag);
}
}
}
Expand Down Expand Up @@ -1582,12 +1583,14 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
| ResolvedName::Overloaded { .. }
| ResolvedName::Expression(_)
| ResolvedName::Final(_) => {
diagnostics.add(
name_pos.pos(self.ctx),
format!("Expected type name, got {}", resolved.describe()),
ErrorCode::MismatchedKinds,
bail!(
diagnostics,
Diagnostic::mismatched_kinds(
name_pos.pos(self.ctx),
format!("Expected type, got {}", resolved.describe())
)
.opt_related(resolved.decl_pos(), "Defined here")
);
Err(EvalError::Unknown)
}
}
}
Expand Down Expand Up @@ -2104,18 +2107,17 @@ variable thevar : integer;
);
check_diagnostics(
diagnostics,
vec![Diagnostic::new(
code.s1("thevar'element"),
"The element attribute can only be used for array types",
ErrorCode::IllegalAttribute,
vec![Diagnostic::illegal_attribute(
code.s1("thevar"),
"array type expected for 'element attribute",
)],
)
}

#[test]
fn element_type_attributes_on_non_object_types() {
let test = TestSetup::new();
test.declarative_part(
let declarative_code = test.declarative_part(
"
type my_type is array(natural range<>) of integer;
",
Expand All @@ -2128,11 +2130,11 @@ type my_type is array(natural range<>) of integer;
);
check_diagnostics(
diagnostics,
vec![Diagnostic::new(
vec![Diagnostic::illegal_attribute(
code.s1("my_type'subtype"),
"The subtype attribute can only be used on objects, not array type 'my_type'",
ErrorCode::IllegalAttribute,
)],
)
.related(declarative_code.s1("my_type"), "Defined here")],
)
}

Expand All @@ -2150,13 +2152,19 @@ variable x: integer;
test.name_resolve(&code, None, &mut diagnostics),
Err(EvalError::Unknown)
);
let integer_pos = test
.ctx(&Vec::new())
.root
.find_standard_symbol("INTEGER")
.decl_pos()
.unwrap();
check_diagnostics(
diagnostics,
vec![Diagnostic::new(
vec![Diagnostic::illegal_attribute(
code.s1("x'subtype'subtype"),
"The subtype attribute can only be used on objects, not integer type 'INTEGER'",
ErrorCode::IllegalAttribute,
)],
)
.related(integer_pos, "Defined here")],
)
}

Expand Down
6 changes: 2 additions & 4 deletions vhdl_lang/src/analysis/package_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,13 @@ impl<'a, 't> AnalyzeContext<'a, 't> {
if let Some(ent) = overloaded.get(&signature) {
name.set_unique_reference(&ent);
} else {
let mut diag = Diagnostic::new(
let mut diag = Diagnostic::mismatched_kinds(
&assoc.actual.pos(self.ctx),
format!(
"Cannot map '{}' to subprogram generic {}{}",
des,
"Cannot map '{des}' to subprogram generic {}{}",
target.designator(),
signature.key().describe()
),
ErrorCode::MismatchedKinds,
);

diag.add_subprogram_candidates(
Expand Down
Loading

0 comments on commit 9b06eca

Please sign in to comment.