Skip to content

(towards #1960 and #1799) Improve ArrayAssingment2Loop using call/routinesymbol datatype information#3343

Open
sergisiso wants to merge 10 commits intomasterfrom
1960_improve_call_datatype_information
Open

(towards #1960 and #1799) Improve ArrayAssingment2Loop using call/routinesymbol datatype information#3343
sergisiso wants to merge 10 commits intomasterfrom
1960_improve_call_datatype_information

Conversation

@sergisiso
Copy link
Collaborator

@sergisiso sergisiso commented Feb 20, 2026

I started this branch to tackle the WHERE with reduction intrinsics, but as in my previous PRs I think this should be solved first in ArrayAssignment2Loop and then integrate it to the WHERE.

The reductions that end up with a scalar can are already be done because we know that that term does not need additional indexing after applying ArrayAssignment2Loop. However the call.datatype was quite limited. It worked for Intrinsics but not generic calls (even when we had a RoutineSymbol with information). And RoutineSymbols defaulted to NoType, even when that was not necessarely the case (I think UnresolvedType is a better default and use the frontend type, e.g. is a CallStmt, to give it the NoType).

I have made the changes needed to fix the above and I feel its already enough for a PR, the WHEREs will come in a follow up.

@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.95%. Comparing base (df4a4f1) to head (ee70564).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #3343   +/-   ##
=======================================
  Coverage   99.95%   99.95%           
=======================================
  Files         386      386           
  Lines       54187    54215   +28     
=======================================
+ Hits        54165    54193   +28     
  Misses         22       22           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sergisiso
Copy link
Collaborator Author

@arporter @LonelyCat124 This is ready for review

Copy link
Member

@arporter arporter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good Sergi - it's nice to see the improvements to the typing making their way 'upwards'. Just some tidying/clarification and I'm a bit puzzled by a couple of the tests.

if self.routine:
if isinstance(self.routine.symbol, RoutineSymbol):
dt = self.routine.symbol.datatype
if not isinstance(dt, UnresolvedType):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this if condition? Please could you add a comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


def _walk_until_non_elemental_call(
node: Node, search_type: type, stop_type: Optional[type] = None):
''' Custom walk operation that stops at Calls that it are not
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/that it/that/

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done



def _walk_until_non_elemental_call(
node: Node, search_type: type, stop_type: Optional[type] = None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls include the typehint for the return type.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if stop_type and isinstance(node, stop_type):
return local_list

if isinstance(node, Call) and not node.is_elemental:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for this PR, but, if we ever find ourselves needing another walk specialisation, perhaps we could add an optional stop_condition argument to walk that takes a routine that accepts a node as an argument and can do custom checks?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It crossed my mind but I thought it was too much for this PR, but I agree if we find the case again it may be worth it.

assert isinstance(routine_symbol.interface, UnresolvedInterface)
assert routine_symbol.name == "kernel"
assert routine_symbol in call_node.scope.symbol_table.symbols
# This this is a "call ..." expression, the Routine is NoType (subroutine)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/this //

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ups, deleted

assert isinstance(routine_symbol.interface, ImportInterface)
assert routine_symbol.name == "kernel"
assert routine_symbol in call_node.scope.symbol_table.symbols
# This this is a "call ..." expression, the Routine is NoType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/this //

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

assert errmsg in str(err.value)
with pytest.raises(TransformationError) as err:
trans.apply(assignments[3])
with pytest.raises(TransformationError) as err:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have asked for this originally but pls could you add a comment before the with ... saying which assignment is being tested.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea

# TODO #2429: This has the correct behaviour but for the wrong reason,
# once this issue is resolved the error message should be the expected
# one.
# assert errormsg in str(err.value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused here - you have this line commented out but then you have the same line at L876 apparently working?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The one in L876 checks the TransformationError after this one, the error message is different. The problem I am hitting here is that this returns
ArrayAssignment2LoopsTrans does not support array assignments that contain a CodeBlock anywhere in the expression because fparser considers the empty function calls as DerivedTypeConstructors and therefore codeblocks. I am planning to make these PSyIR calls soon, so I still want to test the right thing here, even if for now it is with a confusing error message.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the comment

trans.validate(invalid[3])
assert errormsg in str(err.value)

# There are impure (or we don't know the purity)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"These"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

# TODO #2429: This has the correct behaviour but for the wrong reason,
# once this issue is resolved the error message should be the expected
# one.
# assert errormsg in str(err.value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same confusion here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See response above

@sergisiso
Copy link
Collaborator Author

@arporter This is ready for another review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants