Repository: pyccel/pyccel
Pull request #1866 (2024-05-08 09:46:53)

Raise an error for issue #1339
Raise an error indicating that C should be used to mix scalar and array return types (see #1339).

pyccel-bot[bot]: Hello again! Thank you for this new pull request :star_struck:.

Please begin by requesting your checklist using the command `/bot checklist`

EmilyBourne: /bot checklist
pyccel-bot[bot]: It seems like you have forgotten to complete your checklist for this pull request. Please check the list [here](https://github.com/pyccel/pyccel/pull/1866#issuecomment-2100193266), fix the missing items and let me know when everything is ticked and fixed with `/bot mark as ready`.

pyccel-bot[bot]: Hey @pyccel/pyccel-dev ! @EmilyBourne has just created this great new pull request! Check it out and let me know what you think!

pyccel-bot[bot]: @EmilyBourne, @yguclu has a few questions/comments about your code. Can you go through and see if you agree with them. If not go ahead and explain why. Once you've adressed all the comments let me know with `/bot mark as ready` and we will see if we can get approval.


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2821911b..5b74668a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,6 +47,7 @@ All notable changes to this project will be documented in this file.
 -   #1836 : Move `epyccel` module to `pyccel.commands.epyccel` and add support for shortcut import `from pyccel import epyccel`.
 -   #1720 : functions with the `@inline` decorator are no longer exposed to Python in the shared library.
 -   #1720 : Error raised when incompatible arguments are passed to an `inlined` function is now fatal.
+-   #1866 : Raise a more informative error when mixing scalar and array return types.
 -   \[TESTS\] Filter out cast warnings in cast tests.
 -   \[INTERNALS\] `FunctionDef` is annotated when it is called, or at the end of the `CodeBlock` if it is never called.
 -   \[INTERNALS\] `InlinedFunctionDef` is only annotated if it is called.
diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py
index bc839db1..51e6bb41 100644
--- a/pyccel/codegen/printing/fcode.py
+++ b/pyccel/codegen/printing/fcode.py
@@ -1875,15 +1875,28 @@ class FCodePrinter(CodePrinter):
         return ' // '.join(formatted_str)
 
     def _print_Interface(self, expr):
+        interface_funcs = expr.functions
+
+        example_func = interface_funcs[0]
+
         # ... we don't print 'hidden' functions
-        if expr.functions[0].is_inline:
+        if example_func.is_inline:
             return ''
 
+        if len(example_func.results) == 1:
+            if len(set(f.results[0].var.rank == 0 for f in interface_funcs)) != 1:
+                message = ("Fortran cannot yet handle a templated function returning either a scalar or an array. "
+                           "If you are using the terminal interface, please pass --language c, "
+                           "if you are using the interactive interfaces epyccel or lambdify, please pass language='c'. "
+                           "See https://github.com/pyccel/pyccel/issues/1339 to monitor the advancement of this issue.")
+                errors.report(message,
+                        severity='error', symbol=expr)
+
         name = self._print(expr.name)
-        if all(isinstance(f, FunctionAddress) for f in expr.functions):
-            funcs = expr.functions
+        if all(isinstance(f, FunctionAddress) for f in interface_funcs):
+            funcs = interface_funcs
         else:
-            funcs = [f for f in expr.functions if f is \
+            funcs = [f for f in interface_funcs if f is \
                     expr.point([FunctionCallArgument(a.var.clone('arg_'+str(i))) \
                         for i,a in enumerate(f.arguments)])]
 
diff --git a/pyccel/parser/semantic.py b/pyccel/parser/semantic.py
index c51beea0..b54a930e 100644
--- a/pyccel/parser/semantic.py
+++ b/pyccel/parser/semantic.py
@@ -4008,6 +4008,8 @@ class SemanticParser(BasicParser):
                     bound_class.add_new_method(func)
 
             new_semantic_funcs += [func]
+            if expr.python_ast:
+                func.set_current_ast(expr.python_ast)
 
         if function_call_args is not None and len(new_semantic_funcs) == 0:
             for args in annotated_args[:-1]:
@@ -4026,6 +4028,8 @@ class SemanticParser(BasicParser):
                 self.insert_function(f)
 
             new_semantic_funcs = Interface(interface_name, new_semantic_funcs, syntactic_node=expr)
+            if expr.python_ast:
+                new_semantic_funcs.set_current_ast(expr.python_ast)
             if cls_name:
                 bound_class.add_new_interface(new_semantic_funcs)
             self.insert_function(new_semantic_funcs)


Test patch:
diff --git a/tests/errors/codegen/fortran/FORTRAN_ALLOCATABLE_IN_EXPRESSION.py b/tests/errors/codegen/fortran_blocking/FORTRAN_ALLOCATABLE_IN_EXPRESSION.py
similarity index 100%
rename from tests/errors/codegen/fortran/FORTRAN_ALLOCATABLE_IN_EXPRESSION.py
rename to tests/errors/codegen/fortran_blocking/FORTRAN_ALLOCATABLE_IN_EXPRESSION.py
diff --git a/tests/errors/codegen/fortran/randint.py b/tests/errors/codegen/fortran_blocking/randint.py
similarity index 100%
rename from tests/errors/codegen/fortran/randint.py
rename to tests/errors/codegen/fortran_blocking/randint.py
diff --git a/tests/errors/codegen/fortran_non_blocking/issue_1339.py b/tests/errors/codegen/fortran_non_blocking/issue_1339.py
new file mode 100644
index 00000000..5d1d710c
--- /dev/null
+++ b/tests/errors/codegen/fortran_non_blocking/issue_1339.py
@@ -0,0 +1,7 @@
+# pylint: disable=missing-function-docstring, missing-module-docstring
+from pyccel.decorators import types
+
+@types('int')
+@types('int[:]')
+def f(a):
+    return a+3
diff --git a/tests/errors/test_errors.py b/tests/errors/test_errors.py
index 62ee5522..2eb7b74f 100644
--- a/tests/errors/test_errors.py
+++ b/tests/errors/test_errors.py
@@ -133,8 +133,8 @@ def test_semantic_non_blocking_developer_errors(f):
     error_mode.set_mode('user')
     assert errors.has_errors()
 
-@pytest.mark.parametrize("f",get_files_from_folder("codegen/fortran"))
-def test_codegen_errors(f):
+@pytest.mark.parametrize("f",get_files_from_folder("codegen/fortran_blocking"))
+def test_codegen_blocking_errors(f):
     # reset Errors singleton
     errors = Errors()
     errors.reset()
@@ -154,6 +154,26 @@ def test_codegen_errors(f):
 
     assert errors.has_errors()
 
+@pytest.mark.parametrize("f",get_files_from_folder("codegen/fortran_non_blocking"))
+def test_codegen_non_blocking_errors(f):
+    # reset Errors singleton
+    errors = Errors()
+    errors.reset()
+
+    pyccel = Parser(f)
+    ast = pyccel.parse()
+
+    settings = {}
+    ast = pyccel.annotate(**settings)
+
+    name = os.path.basename(f)
+    name = os.path.splitext(name)[0]
+
+    codegen = Codegen(ast, name, 'fortran')
+    codegen.printer.doprint(codegen.ast)
+
+    assert errors.has_errors()
+
 @pytest.mark.parametrize("f",get_files_from_folder("known_bugs"))
 def test_neat_errors_for_known_bugs(f):
     # reset Errors singleton