Skip to content
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

check array rank and dimensions before assignment #3521

Merged
merged 11 commits into from
Mar 8, 2024
Merged

Conversation

gxyd
Copy link
Contributor

@gxyd gxyd commented Feb 25, 2024

Fixes #3517

@gxyd
Copy link
Contributor Author

gxyd commented Feb 25, 2024

I don't fully understand how the below program is valid:

integer function a(n,m)
implicit real (n)
implicit integer (m)
implicit real*8 (k)
integer :: X(m), Y(m)
n = 5
m = 8
X = [1,2,3,4,5]
end function

since we first assign m as 8 and then the size of X (which when initialized as set to m) is 5. This is a test-case in out test-suite.

@certik
Copy link
Contributor

certik commented Feb 25, 2024

That program is invalid. Needs to be fixed.

@gxyd
Copy link
Contributor Author

gxyd commented Feb 26, 2024

The failing test from pack (i.e.)

semantic error: Dimensions not equal
 --> /home/runner/work/lfortran/lfortran/integration_tests/array_01_pack.f90:4:3
  |
4 |   p = pack(m, m /= 0)
  |   ^^^^^^^^^^^^^^^^^^^ 

would be there because of an issue in pack #3155 (comment)

@gxyd
Copy link
Contributor Author

gxyd commented Feb 26, 2024

I will put in some more work on this, before someone can review this.

@gxyd
Copy link
Contributor Author

gxyd commented Feb 27, 2024

Currently the failing test is:

semantic error: Different shape for array assignment on dimension 1(5 and 2)
  --> /home/runner/work/lfortran/lfortran/integration_tests/intrinsics_51.f90:29:1
   |
29 | cr = sin([[1., 2., 3.], [4., 5.]])
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

as cr is already declared to be of size '5', while we currently don't return sin([[1., 2., 3.], [4., 5.]]) of size '5' (It's a separate bug I believe). I guess this MR has nothing wrong on that part.

@gxyd gxyd marked this pull request as ready for review February 27, 2024 11:04
@gxyd
Copy link
Contributor Author

gxyd commented Feb 27, 2024

This is ready for a review now, let me know how to handle the failing test (if you have any opinion on that).

integer :: arr1(2:4)
! array with size 3 and start index 1
integer :: arr2(1:3)
arr1 = (/1, 2, 3/)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
arr1 = (/1, 2, 3/)
arr1 = [1, 2, 3]

Copy link
Contributor Author

@gxyd gxyd Feb 28, 2024

Choose a reason for hiding this comment

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

Ah, so it seems like [1, 2, 3] is a more modern syntax for arrays followed by Fortran.

integer :: arr1(1)
! arr1 (which is of size 1) is being assigned
! an array of size 3
arr1 = (/1, 2, 3/)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
arr1 = (/1, 2, 3/)
arr1 = [1, 2, 3]


! RHS is a constant array of rank 1
! incompatible assignment
arr1 = (/1, 2, 3/)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
arr1 = (/1, 2, 3/)
arr1 = [1, 2, 3]

@certik
Copy link
Contributor

certik commented Feb 27, 2024

If your PR uncovered a bug, then comment out the failing lines in tests, and ensure everything passes.

Then we'll decide what to do next.

@gxyd
Copy link
Contributor Author

gxyd commented Feb 28, 2024

I've commented out the failing test (which needs a change). Can you please help me understand the error CI error?

@certik
Copy link
Contributor

certik commented Feb 28, 2024

The Windows error is real:

D:\a\lfortran\lfortran\lfortran-0.33.1-532-gccc42db11\src\lfortran\semantics\ast_body_visitor.cpp(2273): error C2146: syntax error: missing ')' before identifier 'and'
D:\a\lfortran\lfortran\lfortran-0.33.1-532-gccc42db11\src\lfortran\semantics\ast_body_visitor.cpp(2273): error C2065: 'and': undeclared identifier
D:\a\lfortran\lfortran\lfortran-0.33.1-532-gccc42db11\src\lfortran\semantics\ast_body_visitor.cpp(2273): error C2146: syntax error: missing ';' before identifier 'dim_b_int'
D:\a\lfortran\lfortran\lfortran-0.33.1-532-gccc42db11\src\lfortran\semantics\ast_body_visitor.cpp(2273): error C2059: syntax error: ')'

}
ASRUtils::extract_value(ASRUtils::expr_value(dim_a.m_length), dim_a_int);
ASRUtils::extract_value(ASRUtils::expr_value(dim_b.m_length), dim_b_int);
if (dim_a_int > 0 and dim_b_int > 0 && dim_a_int != dim_b_int) {
Copy link
Contributor

Choose a reason for hiding this comment

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

To fix the Windows error:

Suggested change
if (dim_a_int > 0 and dim_b_int > 0 && dim_a_int != dim_b_int) {
if (dim_a_int > 0 && dim_b_int > 0 && dim_a_int != dim_b_int) {

!print *, "cr: ", cr
!do i = lbound(cr, 1), ubound(cr, 1)
! if( abs(cr(i) - sin(real(i))) > 1e-6 ) error stop
!end do
Copy link
Contributor

Choose a reason for hiding this comment

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

@Pranavchiku can you please have a look at this test and see why it fails? There might be a bug.

Copy link
Contributor

Choose a reason for hiding this comment

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

MRE:

program intrinsics_51
    implicit none
    real :: cr(5)
    
    cr = sin([[1., 2., 3.], [4., 5.]])
    print *, "cr: ", cr
end program
% lfortran b.f90 --show-stacktrace
Traceback (most recent call last):
  File "/Users/pranavchiku/repos/lfortran/src/bin/lfortran.cpp", line 2391
    LCompilers::print_stack_on_segfault();
  File "/Users/pranavchiku/repos/lfortran/src/bin/lfortran.cpp", line 2355
    err = compile_to_object_file(arg_file, tmp_o, false,
  File "/Users/pranavchiku/repos/lfortran/src/bin/lfortran.cpp", line 907
    result = fe.get_asr2(input, lm, diagnostics);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/fortran_evaluator.cpp", line 253
    Result<ASR::TranslationUnit_t*> res2 = get_asr3(*ast, diagnostics);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/fortran_evaluator.cpp", line 275
    compiler_options.symtab_only, compiler_options);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_to_asr.cpp", line 127
    if (res.ok) {
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_body_visitor.cpp", line 3445
    b.is_body_visitor = true;
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_body_visitor.cpp", line 143
    visit_ast(*x.m_items[i]);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/ast.h", line 4848
    void visit_ast(const ast_t &b) { visit_ast_t(b, self()); }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/ast.h", line 4804
    case astType::unit: { v.visit_unit((const unit_t &)x); return; }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/ast.h", line 4851
    void visit_mod(const mod_t &b) { visit_mod_t(b, self()); }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/ast.h", line 4438
    case modType::BlockData: { v.visit_BlockData((const BlockData_t &)x); return; }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_body_visitor.cpp", line 1510
    transform_stmts(body, x.n_body, x.m_body);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_body_visitor.cpp", line 114
    this->visit_stmt(*m_body[i]);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/ast.h", line 4894
    void visit_stmt(const stmt_t &b) { visit_stmt_t(b, self()); }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/ast.h", line 4540
    case stmtType::Assign: { v.visit_Assign((const Assign_t &)x); return; }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_body_visitor.cpp", line 2385
    check_ArrayAssignmentCompatibility(target, value, x);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/ast_body_visitor.cpp", line 2277
    std::to_string(dim_b_int) + ")", x.base.base.loc);
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/semantic_exception.h", line 20
    { }
  File "/Users/pranavchiku/repos/lfortran/src/lfortran/semantics/semantic_exception.h", line 17
    : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::Semantic, {
semantic error: Different shape for array assignment on dimension 1(5 and 2)
 --> b.f90:5:5
  |
5 |     cr = sin([[1., 2., 3.], [4., 5.]])
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 


Note: Please report unclear or confusing messages as bugs at
https://github.com/lfortran/lfortran/issues.

Copy link
Contributor

@certik certik Feb 28, 2024

Choose a reason for hiding this comment

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

Yes, but the issue is that the RHS should be length 5, not 2. I think this is the case in master as well. So that's the bug, that is unrelated to this PR, that we should investigate.

Copy link
Contributor

Choose a reason for hiding this comment

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

(IntrinsicScalarFunction
                            Sin
                            [(ArrayPhysicalCast
                                (ArrayConstant
                                    [(ArrayConstant
                                        [(RealConstant
                                            1.000000
                                            (Real 4)
                                        )
                                        (RealConstant
                                            2.000000
                                            (Real 4)
                                        )
                                        (RealConstant
                                            3.000000
                                            (Real 4)
                                        )]
                                        (Array
                                            (Real 4)
                                            [((IntegerConstant 1 (Integer 4))
                                            (IntegerConstant 3 (Integer 4)))]
                                            FixedSizeArray
                                        )
                                        ColMajor
                                    )
                                    (ArrayConstant
                                        [(RealConstant
                                            4.000000
                                            (Real 4)
                                        )
                                        (RealConstant
                                            5.000000
                                            (Real 4)
                                        )]
                                        (Array
                                            (Real 4)
                                            [((IntegerConstant 1 (Integer 4))
                                            (IntegerConstant 2 (Integer 4)))]
                                            FixedSizeArray
                                        )
                                        ColMajor
                                    )]
                                    (Array
                                        (Real 4)
                                        [((IntegerConstant 1 (Integer 4))
                                        (IntegerConstant 2 (Integer 4)))]
                                        FixedSizeArray
                                    )
                                    ColMajor
                                )
                                FixedSizeArray
                                DescriptorArray
                                (Array
                                    (Real 4)
                                    [((IntegerConstant 1 (Integer 4))
                                    (IntegerConstant 2 (Integer 4)))]
                                    DescriptorArray
                                )
                                ()
                            )]
                            0
                            (Array
                                (Real 4)
                                [((IntegerConstant 1 (Integer 4))
                                (IntegerConstant 2 (Integer 4)))]
                                FixedSizeArray
                            )
                            () --------------------------------------> This should have value, but it does not have
                        )

I faced the same in #3485.

Copy link
Contributor

Choose a reason for hiding this comment

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

The trouble is eval_Sin is not functioning properly. It should evaluate cr = sin([[1., 2., 3.], [4., 5.]]) the RHS but is not doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I understood the bug, I have been (if possible) looking to make a change to the test case functionality, so that this MR can move forward without necessarily needing the bug to be fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you change it to something like:

a = [[1., 2., 3.], [4., 5.]]
!print *, a
!cr = sin(a)

As well as

cr = sin([1., 2., 3., 4., 5.])

That will test both compile time and runtime and hopefully it works.

Copy link
Contributor

Choose a reason for hiding this comment

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

@gxyd to make tests pass you just have to skip if value is an IntrinsicElementalFunction or IntrinsicArrayFunction and add a TODO to remove this later

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems like there is another issue:

> cat b.f90
program main
    implicit none
    print *, "rank is:", rank([[1., 2., 3.], [4., 5.]])
    print *, "shape is:", shape([[1., 2., 3.], [4., 5.]])
end program

> lfortran b.f90
rank is: 1
shape is: 2 

> gfortran b.f90 -o b.out && ./b.out
 rank is:           1
 shape is:           5

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can't look into the issue in detail right now, but I'll once I get my monitor back on Saturday (my eyes aren't liking it right now).

@gxyd
Copy link
Contributor Author

gxyd commented Mar 2, 2024

I don't understand this new CI error, it's origination from stdlib, I don't understand how stdlib is used in LFortran repo.

@certik certik marked this pull request as draft March 2, 2024 14:27
@certik
Copy link
Contributor

certik commented Mar 2, 2024

The CI downloads stdlib and compiles it. It fails. It means your new checks uncovered some issues there, that are not caught by our integration tests. We need to understand the issue and write a dedicated integration test for it, and fix it. We can also report it as an issue (to fix later) and workaround the problem in stdlib.

@gxyd
Copy link
Contributor Author

gxyd commented Mar 2, 2024

It means your new checks uncovered some issues there

"there" as in "within stdlib"?

@certik
Copy link
Contributor

certik commented Mar 2, 2024

Since stdlib compiles with gfortran, the bug is not in stdlib, it's a bug in LFortran, that is either introduced by this PR, or it has always been in LFortran and only uncovered by this PR's stricter checks.

@gxyd
Copy link
Contributor Author

gxyd commented Mar 2, 2024

I see the stacktrace to have

semantic error: Different shape for array assignment on dimension 1(4 and 16)
   --> /home/runner/work/lfortran/lfortran/stdlib/test/linalg/test_linalg.f90:267:9
    |
267 |         c = pack(a, mask)
    |         ^^^^^^^^^^^^^^^^^ 

which repository contains the file: "test_linalg"? I don't see it on our repo, nor in stdlib.

This PR highlighted (was already known) the issue with pack (as seen in one of the modified integration tests), probably could be similar here.

@certik
Copy link
Contributor

certik commented Mar 2, 2024

See here, which sets up the stdlib at the CI. You can follow the same steps to reproduce this locally:

- name: Test stdlib

There is a link to check out the exact git repository and branch and a hash.

@Pranavchiku
Copy link
Contributor

If pack is a blocker, let me know, I'll try to remove the TODO, but that will need to have intrinsic count ( https://gcc.gnu.org/onlinedocs/gfortran/COUNT.html ).

@gxyd
Copy link
Contributor Author

gxyd commented Mar 5, 2024

@Pranavchiku , I think to make the tests pass, either it will require changes in the stdlib (in the below code to change c's dimension to n**2:

semantic error: Different shape for array assignment on dimension 1(4 and 16)
   --> /home/runner/work/lfortran/lfortran/stdlib/test/linalg/test_linalg.f90:267:9
    |
267 |         c = pack(a, mask)
    |         ^^^^^^^^^^^^^^^^^ 

Or the other solution is to actually fix the issue with pack. (I'll re-think for what's a better solution here).

@certik
Copy link
Contributor

certik commented Mar 5, 2024

We can workaround this in stdlib for now, and open up an issue for pack and reference it from there. I think that would be fine. Let's get this PR merged, as it adds many useful checks that uncover bugs.

@Pranavchiku
Copy link
Contributor

I am working on implementation of count, will be done by EOD. Then it will be a small change in pack intrinsic.

@Pranavchiku
Copy link
Contributor

I have fix for pack almost ready, there are a few cases that fail, will get it done by tomorrow. I am sorry for making you wait to merge this PR.

@gxyd
Copy link
Contributor Author

gxyd commented Mar 6, 2024

I am sorry for making you wait to merge this PR.

Don't worry about that. I'm glad that we are doing things the right way.

@Pranavchiku
Copy link
Contributor

I have made progress on it, will open PR soon.

@Pranavchiku
Copy link
Contributor

With #3605, for p = pack(m, m/=0), node looks like:

                    (Assignment
                        (Var 2 p)
                        (IntrinsicArrayFunction
                            Pack
                            [(ArrayPhysicalCast
                                (Var 2 m)
                                FixedSizeArray
                                DescriptorArray
                                (Array
                                    (Integer 4)
                                    [((IntegerConstant 1 (Integer 4))
                                    (IntegerConstant 6 (Integer 4)))]
                                    DescriptorArray
                                )
                                ()
                            )
                            (ArrayPhysicalCast
                                (IntegerCompare
                                    (Var 2 m)
                                    NotEq
                                    (IntegerConstant 0 (Integer 4))
                                    (Array
                                        (Logical 4)
                                        [((IntegerConstant 1 (Integer 4))
                                        (IntegerConstant 6 (Integer 4)))]
                                        FixedSizeArray
                                    )
                                    ()
                                )
                                FixedSizeArray
                                DescriptorArray
                                (Array
                                    (Logical 4)
                                    [((IntegerConstant 1 (Integer 4))
                                    (IntegerConstant 6 (Integer 4)))]
                                    DescriptorArray
                                )
                                ()
                            )]
                            2
                            (Array
                                (Integer 4)
                                [((IntegerConstant 1 (Integer 4))
                                (IntrinsicArrayFunction
                                    Count
                                    [(ArrayPhysicalCast
                                        (IntegerCompare
                                            (Var 2 m)
                                            NotEq
                                            (IntegerConstant 0 (Integer 4))
                                            (Array
                                                (Logical 4)
                                                [((IntegerConstant 1 (Integer 4))
                                                (IntegerConstant 6 (Integer 4)))]
                                                FixedSizeArray
                                            )
                                            ()
                                        )
                                        FixedSizeArray
                                        DescriptorArray
                                        (Array
                                            (Logical 4)
                                            [((IntegerConstant 1 (Integer 4))
                                            (IntegerConstant 6 (Integer 4)))]
                                            DescriptorArray
                                        )
                                        ()
                                    )]
                                    0
                                    (Integer 4)
                                    ()
                                ))]
                                DescriptorArray
                            )
                            ()
                        )
                        ()
                    )

@Pranavchiku
Copy link
Contributor

We cannot get the fixed size at compile time, you'll have to bypass this case.

@Pranavchiku
Copy link
Contributor

@gxyd it is merged, I am sorry for delaying this PR. You may rebase it as instructed at #3589 and see if CI works now.

@gxyd gxyd marked this pull request as ready for review March 8, 2024 09:22
@gxyd gxyd marked this pull request as draft March 8, 2024 09:32
@gxyd gxyd marked this pull request as ready for review March 8, 2024 10:32
@gxyd
Copy link
Contributor Author

gxyd commented Mar 8, 2024

Seems like an unrelated failure on Windows

ASR::ttype_t *value_type = ASRUtils::type_get_past_allocatable(ASRUtils::expr_type(value));
// we don't want to check by "check_equal_type" because we want to allow
// real :: x(4); x = [1, 2, 3, 4] to be a valid assignment (as RHS is "integer array")
// TODO: the only reason to not do this check for "reshape" is because
Copy link
Contributor Author

@gxyd gxyd Mar 8, 2024

Choose a reason for hiding this comment

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

I would like to maybe figure out how to fix this error in another PR, I see there are few open issues for "reshape", but I definitely think that this should be made to work.

Copy link
Contributor

@certik certik left a comment

Choose a reason for hiding this comment

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

I think this looks good to merge.

@certik certik merged commit 250647a into lfortran:main Mar 8, 2024
21 checks passed
@gxyd gxyd deleted the arrayBug branch March 8, 2024 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Different shape array assignment shouldn't work
3 participants