-
Notifications
You must be signed in to change notification settings - Fork 171
Support multiple assignments #978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks. Can you add a test for this as well please? |
Let me try to understand. This:
creates this ASR:
So this is doing This in turn is the reason for this change: void visit_Assignment(const ASR::Assignment_t &x) {
if( x.m_overloaded ) {
this->visit_stmt(*x.m_overloaded);
- return ;
} But it will break LFortran, as in there we must do the overloaded operation instead of the original one. So I think the current approach will not work. So how should this be implemented? Well, what is Isn't that exactly equivalent to:
? Or is there some semantic difference? If it is equivalent, then the AST->ASR should encounter the AST node(s) for There is a slight issue of appending more than one statement, but I think we have some mechanism for it, and if not, we need to create it. |
Maybe we can follow the same logic but let's leave the overload for now, and implement a new argument in the stmt
= Allocate(alloc_arg* args, expr? stat, expr? errmsg, expr? source)
| Assign(int label, identifier variable)
- | Assignment(expr target, expr value, stmt? overloaded)
+ | Assignment(expr target, expr value, stmt? overloaded, stmt? multiple_assignment)
| Associate(expr target, expr value)
| Cycle() or, |
It seems quite complicated, because every backend then has to support it etc. We are trying to keep the ASR as minimal as possible, but without losing any semantic information. It's not black and white, but this feature seems quite rarely used, so using the workaround with multiple Assignments seems like a better way, than modifying ASR. We should only extend ASR when we need to represent the semantic operation, or it simplifies the backends. In this case, it seems we do not necessarily need to preserve this operation, and it makes backends more complicated. So it seems it is not worth doing that way. |
I think converting c = 10
b = c
a = b should be doable. We should do this because it keeps the ASR simple. And semantics of Appending multiple statements to body can be implemented in multiple ways. You can track the current body by making it a state of the visitor then modify it directly when you create multiple assignment statements. Not so safe approach. The other way is to make |
This is ready for review @czgdp1807 @certik |
overloaded); | ||
tmp_vec.push_back(tmp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than assigning to both tmp and tmp_vec, why not use the convention that if it is just one, it will be in tmp, and if tmp == nullptr
, then it will be in tmp_vec
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is how I am thinking about it:
- tmp is not null: we have exactly one statement, the most common case
- tmp is null: the tmp_vec is used to communicate what is returned: tmp_vec.size() == 0 (nothing), size() == 2 or more (two or more statements).
We could in principle only use tmp_vec even for 1 statement (and remove tmp
), but I think the tmp
convention is used for expressions as well, and it seems like the above idea is better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case we should update other code that currently returns tmp=null
to mean "none" to ensure it sets tmp_vec.size() == 0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Otherwise incorrect set of statements mind end up getting into ASR. Well we should always clear the tmp_vec
after pushing all the elements from it to the body. That way we will know that its always empty once used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. @czgdp1807 let me know if this looks good to you. See also my question above regarding the convention of tmp and tmp_vec.
integration_tests/expr_09.py
Outdated
@@ -8,4 +8,27 @@ def main0(): | |||
print(-i1 ^ -i2) | |||
assert -i1 ^ -i2 == 6 | |||
|
|||
|
|||
def test_multiple_assign_1(): | |||
a: i32; b:i32; c:i32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try with variables of different types as well. Something like,
d: f64; e: f32; f: c64; g: i32
c = d = e = g + 1.0
Also try with lists, tuples (of the same element types) variables everywhere in the multiple assignment statement.
tmp = make_DictInsert_t(al, x.base.base.loc, se, key, tmp_value); | ||
tmp_vec.push_back(tmp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like this?
tmp = make_DictInsert_t(al, x.base.base.loc, se, key, tmp_value); | |
tmp_vec.push_back(tmp); | |
tmp = nullptr; | |
tmp_vec.push_back(make_DictInsert_t(al, x.base.base.loc, se, key, tmp_value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, or is this just one? In that case, just put it into tmp
, and leave tmp_vec
be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we can have many of them. We have a continue
statement below this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is good to be merged, after adding the documentation comment (see my comment above) and polishing the git history.
Awesome, thanks for implementing this @Smit-create ! |
Fixes #928