Skip to content

Commit e73887c

Browse files
committed
refactor: Introduce StatementAnnotation::FunctionPointer
Previously function pointers were annotated using the `Value` variant which has been changed with this commit.
1 parent 86efe16 commit e73887c

File tree

8 files changed

+217
-148
lines changed

8 files changed

+217
-148
lines changed

compiler/plc_diagnostics/src/diagnostics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ impl Diagnostic {
280280

281281
pub fn cannot_generate_call_statement(operator: &AstNode) -> Diagnostic {
282282
//TODO: We could probably get a better slice here
283+
// todo!();
283284
Diagnostic::codegen_error(format!("cannot generate call statement for {:?}", operator), operator)
284285
}
285286

src/codegen/generators/data_type_generator.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ impl<'ink> DataTypeGenerator<'ink, '_> {
189189
.map(|opt| opt.as_any_type_enum())
190190
.unwrap_or(self.llvm.context.void_type().into());
191191

192+
dbg!(&return_type);
193+
192194
let mut parameter_types = vec![];
193195

194196
// We need to add the POU type as the first parameter when dealing with methods

src/codegen/generators/expression_generator.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,8 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
535535
panic!("{implementation:#?}");
536536
};
537537

538+
dbg!(method_instance, actual_parameters);
539+
538540
// TODO: Why alloca?
539541
// %fnPtr = alloca void (%FbA*)*, align 8
540542
let function_pointer_value = self.generate_expression_value(base)?;
@@ -617,12 +619,7 @@ impl<'ink, 'b> ExpressionCodeGenerator<'ink, 'b> {
617619
operator: &AstNode,
618620
parameters: Option<&AstNode>,
619621
) -> Result<ExpressionValue<'ink>, Diagnostic> {
620-
if operator.is_deref()
621-
&& self
622-
.annotations
623-
.get_type(operator, self.index)
624-
.is_some_and(|opt| opt.is_method_pointer(self.index))
625-
{
622+
if operator.is_deref() && self.annotations.get(operator).is_some_and(StatementAnnotation::is_fnptr) {
626623
return self.generate_function_pointer_call(operator, parameters);
627624
}
628625

src/codegen/tests/function_pointer_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ fn function_pointer_method_with_input_output_inout() {
145145
store i16 0, i16* %localInOutVariable, align 2
146146
store void (%FbA*, i16, i16*, i16*)* @FbA__foo, void (%FbA*, i16, i16*, i16*)** %fnPtr, align 8
147147
%1 = load void (%FbA*, i16, i16*, i16*)*, void (%FbA*, i16, i16*, i16*)** %fnPtr, align 8
148-
call void %1(%FbA* %instanceFbA, i16 12345, i16* %localOutVariable, i16* %localInOutVariable)
148+
call void %1(%FbA* %instanceFbA, i32 12345, i16* %localOutVariable, i16* %localInOutVariable)
149149
%2 = load void (%FbA*, i16, i16*, i16*)*, void (%FbA*, i16, i16*, i16*)** %fnPtr, align 8
150150
%load_localInVariable = load i16, i16* %localInVariable, align 2
151151
call void %2(%FbA* %instanceFbA, i16 %load_localInVariable, i16* %localOutVariable, i16* %localInOutVariable)

src/lowering/calls.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ use plc_ast::{
6060
};
6161
use plc_source::source_location::SourceLocation;
6262

63-
use crate::{index::Index, resolver::AnnotationMap};
63+
use crate::{
64+
index::Index,
65+
resolver::{AnnotationMap, StatementAnnotation},
66+
};
6467

6568
#[derive(Default, Debug, Clone)]
6669
struct VisitorContext {
@@ -272,16 +275,30 @@ impl AstVisitorMut for AggregateTypeLowerer {
272275
//Early exit if not annotated or indexed
273276
return;
274277
};
275-
//Get the function being called
276-
let Some(crate::resolver::StatementAnnotation::Function {
277-
qualified_name,
278-
return_type: return_type_name,
279-
generic_name,
280-
..
281-
}) = annotation.get(&stmt.operator).or_else(|| annotation.get_hint(&stmt.operator)).cloned()
282-
else {
283-
return;
278+
// //Get the function being called
279+
// let Some(crate::resolver::StatementAnnotation::Function {
280+
// qualified_name,
281+
// return_type: return_type_name,
282+
// generic_name,
283+
// ..
284+
// }) = annotation.get(&stmt.operator).or_else(|| annotation.get_hint(&stmt.operator)).cloned()
285+
// else {
286+
// return;
287+
// };
288+
let (qualified_name, return_type_name, generic_name) = match annotation
289+
.get(&stmt.operator)
290+
.or_else(|| annotation.get_hint(&stmt.operator))
291+
.cloned()
292+
{
293+
Some(StatementAnnotation::Function { return_type, qualified_name, generic_name, call_name }) => {
294+
(qualified_name, return_type, generic_name)
295+
}
296+
Some(StatementAnnotation::FunctionPointer { return_type, qualified_name }) => {
297+
(qualified_name, return_type, None)
298+
}
299+
_ => return,
284300
};
301+
285302
//If there's a call name in the function, it is a generic and needs to be replaced.
286303
//HACK: this is because we don't lower generics
287304
let function_entry = index.find_pou(&qualified_name).expect("Function not found");

src/resolver.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,15 @@ pub enum StatementAnnotation {
474474
/// The call name of the function iff it differs from the qualified name (generics)
475475
call_name: Option<String>,
476476
},
477+
FunctionPointer {
478+
/// The defined return type of the function
479+
return_type: String,
480+
/// The defined qualified name of the function
481+
qualified_name: String,
482+
// TODO: Is this needed?
483+
// The call name of the function iff it differs from the qualified name (generics)
484+
// call_name: Option<String>,
485+
},
477486
/// a reference to a type (e.g. `INT`)
478487
Type {
479488
type_name: String,
@@ -676,6 +685,17 @@ impl StatementAnnotation {
676685
StatementAnnotation::Value { resulting_type: type_name.into() }
677686
}
678687

688+
pub fn fnptr<T, U>(return_ty: T, qualified_name: U) -> Self
689+
where
690+
T: Into<String>,
691+
U: Into<String>,
692+
{
693+
StatementAnnotation::FunctionPointer {
694+
return_type: return_ty.into(),
695+
qualified_name: qualified_name.into(),
696+
}
697+
}
698+
679699
pub fn create_override(definitions: Vec<MethodDeclarationType>) -> Self {
680700
StatementAnnotation::Override { definitions }
681701
}
@@ -721,6 +741,10 @@ impl StatementAnnotation {
721741
matches!(self, StatementAnnotation::Property { .. })
722742
}
723743

744+
pub fn is_fnptr(&self) -> bool {
745+
matches!(self, StatementAnnotation::FunctionPointer { .. })
746+
}
747+
724748
pub fn qualified_name(&self) -> Option<&str> {
725749
match self {
726750
StatementAnnotation::Variable { qualified_name, .. }
@@ -851,6 +875,7 @@ pub trait AnnotationMap {
851875
| StatementAnnotation::Super { name: qualified_name, .. } => Some(qualified_name.as_str()),
852876
StatementAnnotation::Type { type_name } => Some(type_name),
853877
StatementAnnotation::Function { qualified_name, .. } => Some(qualified_name),
878+
StatementAnnotation::FunctionPointer { qualified_name, .. } => Some(qualified_name),
854879
StatementAnnotation::Label { .. }
855880
| StatementAnnotation::Override { .. }
856881
| StatementAnnotation::MethodDeclarations { .. }
@@ -2029,12 +2054,15 @@ impl<'i> TypeAnnotator<'i> {
20292054
.find_effective_type_by_name(inner_type_name)
20302055
.or(self.annotation_map.new_index.find_effective_type_by_name(inner_type_name))
20312056
{
2032-
// TODO(vosa): also add is_method() check
20332057
// We're dealing with a function pointer, hence annotate the deref node with the variables name
2034-
if inner_type.get_type_information().is_function()
2035-
|| inner_type.get_type_information().is_method()
2036-
{
2037-
self.annotate(stmt, StatementAnnotation::value(name));
2058+
// XXX: Functions are intentionally ignored here for now, as the feature as of writing
2059+
// this comment is only interesting for methods due to polymorphism.
2060+
if inner_type.get_type_information().is_method() {
2061+
let pou = self.index.find_pou(&inner_type.name).unwrap();
2062+
self.annotate(
2063+
stmt,
2064+
StatementAnnotation::fnptr(pou.get_return_type().unwrap(), pou.get_name()),
2065+
)
20382066
} else {
20392067
self.annotate(stmt, StatementAnnotation::value(inner_type.get_name()))
20402068
}
@@ -2223,6 +2251,9 @@ impl<'i> TypeAnnotator<'i> {
22232251
StatementAnnotation::Function { qualified_name, call_name, .. } => {
22242252
call_name.as_ref().cloned().or_else(|| Some(qualified_name.clone()))
22252253
}
2254+
StatementAnnotation::FunctionPointer { qualified_name, .. } => {
2255+
Some(qualified_name.to_string())
2256+
}
22262257
StatementAnnotation::Program { qualified_name } => Some(qualified_name.clone()),
22272258
StatementAnnotation::Variable { resulting_type, .. } => self
22282259
.index
@@ -2243,24 +2274,7 @@ impl<'i> TypeAnnotator<'i> {
22432274
AstStatement::ReferenceExpr(
22442275
ReferenceExpr { access: ReferenceAccess::Deref, .. },
22452276
..,
2246-
) => {
2247-
let mut resulting_type = resulting_type.to_string();
2248-
2249-
// When dealing with a pointer, we have to fetch the target type
2250-
if let Some(DataTypeInformation::Pointer { inner_type_name, .. }) = self
2251-
.index
2252-
.find_effective_type_by_name(&resulting_type)
2253-
.map(|opt| opt.get_type_information())
2254-
{
2255-
resulting_type = self
2256-
.index
2257-
.find_pou(inner_type_name)
2258-
.map(|opt| opt.get_name().to_string())
2259-
.expect("must exist")
2260-
}
2261-
2262-
self.index.find_pou(resulting_type.as_str()).map(|it| it.get_name().to_string())
2263-
}
2277+
) => self.index.find_pou(resulting_type.as_str()).map(|it| it.get_name().to_string()),
22642278

22652279
_ => None,
22662280
}

0 commit comments

Comments
 (0)