Skip to content

Function Default Arguments #2618

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

Merged
merged 40 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1a2e739
Fixed Issue #2042
assem2002 Mar 6, 2024
1adbddc
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
9fbd33e
Fix Warning :UnInitialized Vec
assem2002 Mar 6, 2024
0e14c0a
Fixed Issue #2042
assem2002 Mar 6, 2024
abcd34a
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
d7869b1
Fixed Issue #2042
assem2002 Mar 6, 2024
fa18fa7
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
7f85dc2
Default Arguments Implemented
assem2002 Mar 20, 2024
649b079
Default_argumets_implemented -removed other branch edit
assem2002 Mar 20, 2024
2902eea
setting loc makes a serious problem with complex()
assem2002 Mar 20, 2024
d3734db
handled function call without apearent argument passed
assem2002 Mar 20, 2024
f8b7c97
removed print statement usedin debugging
assem2002 Mar 20, 2024
c4ac4f3
added proper handling for nullptr values (they won't break the code a…
assem2002 Mar 20, 2024
1f3d26f
minor edit
assem2002 Mar 20, 2024
2cf7f4f
handled problem in creating c code (c dosen't support default arguments)
assem2002 Mar 21, 2024
35b5faa
Apply suggestions from code review
assem2002 Mar 24, 2024
a4d4d9c
applied code review changes (by Shaikh Ubaid)
assem2002 Mar 27, 2024
8ec5b38
added integration test for function default arguments
assem2002 Mar 27, 2024
3bb336c
added the 'def_func_01.py' to cmake testing list
assem2002 Mar 27, 2024
c7ff531
searching in symbol table for default arguments
assem2002 Apr 28, 2024
3423d9b
Update src/lpython/semantics/python_ast_to_asr.cpp
assem2002 Apr 29, 2024
8748b42
Fixed Issue #2042
assem2002 Mar 6, 2024
be236f8
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
c286d39
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
b34a32b
added test_00
assem2002 Apr 29, 2024
11d1015
solved minor problem with previous commits
assem2002 Apr 29, 2024
ee07640
fixed some indentations in def_func_01.py test file
assem2002 Apr 29, 2024
fe4f162
Update src/lpython/semantics/python_ast_to_asr.cpp
assem2002 Apr 30, 2024
ae0f7a0
Fixed Issue #2042
assem2002 Mar 6, 2024
233eddd
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
b86819a
Fixed issue #2042 - dispatched the type of list and dict
assem2002 Mar 6, 2024
d912b71
added semantic error for insufficient arguments + some edits
assem2002 May 2, 2024
4860230
resolved minor problems
assem2002 May 2, 2024
7ca1987
minor edit
assem2002 May 2, 2024
0fee905
Update src/lpython/semantics/python_ast_to_asr.cpp
assem2002 May 2, 2024
fc1d61c
added reference tests
assem2002 May 2, 2024
262041a
minor edit
assem2002 May 2, 2024
b8a14b1
minor edit
assem2002 May 2, 2024
a474734
Update integration_tests/CMakeLists.txt
assem2002 May 3, 2024
2549f0b
typo edits
assem2002 May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@ RUN(NAME test_statistics_01 LABELS cpython llvm llvm_jit NOFAST)
RUN(NAME test_statistics_02 LABELS cpython llvm llvm_jit NOFAST REQ_PY_VER 3.10)
RUN(NAME test_str_attributes LABELS cpython llvm llvm_jit c)
RUN(NAME kwargs_01 LABELS cpython llvm llvm_jit c NOFAST)
RUN(NAME def_func_01 LABELS cpython llvm llvm_jit c)

RUN(NAME func_inline_01 LABELS llvm llvm_jit c wasm)
RUN(NAME func_inline_02 LABELS cpython llvm llvm_jit c)
Expand Down
76 changes: 76 additions & 0 deletions integration_tests/def_func_01.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from lpython import i32,i64

def factorial_1(x: i32, y:i32 =1) ->i32 :
if x <= 1:
return y
return x * factorial_1(x-1)

def factorial_2(x: i32, y:i32=3 ,z:i32 =2) ->i32:
if x ==4:
return x * y * z
return x * factorial_2(x-1)

def default_func(x : str ="Hello", y : str = " ", z : str = "World") ->str:
return x + y + z


def even_positions(iterator : i32, to_add : str = "?")-> str:
if (iterator == 10): return ""
if iterator%2 == 0 :
return to_add + even_positions(iterator+1,"X")
return to_add +even_positions(iterator+1)



def test_factorial_1():
test_00 : i32 = factorial_1(1)
print("test_00 is =>", test_00)
assert test_00 == 1

test_01 : i32 = factorial_1(5,0)
print("test_01 is =>", test_01)
assert test_01 == 120

test_02 : i32 = factorial_1(1,5555)
print("test_02 is =>", test_02)
assert test_02 == 5555

def test_factorial_2():
test_03 : i32 =factorial_2(5,99999,99999)
print("test_03 is =>", test_03)
assert test_03 == 120

test_04 : i32 = factorial_2(4,-1,100)
print("test_04 is =>", test_04)
assert test_04 == -400

def test_default_func():
test_05 :str = default_func()
print("test_05 is =>", test_05)
assert test_05 == "Hello World"

test_06 :str = default_func(y = "|||",x="Hi")
print("test_06 is =>", test_06)
assert test_06 == "Hi|||World"

test_07 :str = default_func(y = "++",z = "LPython")
print("test_07 is =>", test_07)
assert test_07 == "Hello++LPython"

test_8 :str = default_func("Welcome",z = "LPython")
print("test_8 is =>", test_8)
assert test_8 == "Welcome LPython"

def test_even_positions():
test_09 : str = even_positions(0)
print("test_09 is =>", test_09)
assert test_09 == "?X?X?X?X?X"

test_10 : str = even_positions(0,"W")
print("test_10 is =>", test_10)
assert test_10 == "WX?X?X?X?X"

test_factorial_1()
test_factorial_2()
test_default_func()
test_even_positions()
1 change: 1 addition & 0 deletions src/libasr/codegen/asr_to_c_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,7 @@ R"(#include <stdio.h>
if( is_c ) {
CDeclarationOptions c_decl_options;
c_decl_options.pre_initialise_derived_type = false;
c_decl_options.do_not_initialize = true;
func += self().convert_variable_decl(*arg, &c_decl_options);
} else {
CPPDeclarationOptions cpp_decl_options;
Expand Down
64 changes: 62 additions & 2 deletions src/lpython/semantics/python_ast_to_asr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {

// Fill the whole call_args_vec with nullptr
// This is for error handling later on.
for( size_t i = 0; i < n_pos_args + n_kwargs; i++ ) {
for( size_t i = 0; i < orig_func->n_args; i++ ) {
ASR::call_arg_t call_arg;
Location loc;
loc.first = loc.last = 1;
Expand Down Expand Up @@ -704,6 +704,31 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
call_args_vec.p[arg_pos].loc = expr->base.loc;
call_args_vec.p[arg_pos].m_value = expr;
}
// Filling missing arguments with their defaults passed in function definition (if present).
std::string missed_args_names;
size_t missed_args_count =0;
for(size_t i = 0; i < orig_func->n_args; i++ ){
if(call_args_vec.p[i].m_value == nullptr){
ASR::Variable_t* var = ASRUtils::EXPR2VAR(orig_func->m_args[i]);
if (var->m_symbolic_value == nullptr){
missed_args_names+="'" + (std::string) var->m_name + "' and ";
missed_args_count++;
} else {
call_args_vec.p[i].m_value = var->m_symbolic_value;
}
}
}
if(missed_args_count > 0){
missed_args_names = missed_args_names.substr(0,missed_args_names.length() - 5);
diag.add(diag::Diagnostic(
"Number of arguments does not match in the function call",
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
"Number of arguments does not match in the function call",
"Number of arguments in the function call do not match the function definition",

diag::Level::Error, diag::Stage::Semantic, {
diag::Label("missing " + std::to_string(missed_args_count) + " required arguments :" + missed_args_names,
{call_loc})
})
);
throw SemanticAbort();
}
return true;
}

Expand Down Expand Up @@ -1139,9 +1164,35 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
if (ASR::is_a<ASR::Function_t>(*s)) {
ASR::Function_t *func = ASR::down_cast<ASR::Function_t>(s);
if( n_kwargs > 0 && !is_generic_procedure ) {
args.reserve(al, n_pos_args + n_kwargs);
args.reserve(al, func->n_args);
visit_expr_list(pos_args, n_pos_args, kwargs, n_kwargs,
args, rt_subs, func, loc);
} else if (args.size() < func->n_args) {
std::string missed_args_names =" ";
size_t missed_args_count =0;
for (size_t def_arg = args.size(); def_arg < func->n_args; def_arg++){
ASR::Variable_t* var = ASRUtils::EXPR2VAR(func->m_args[def_arg]);
if(var->m_symbolic_value == nullptr) {
missed_args_names+= "'" + std::string(var->m_name) + "' and ";
missed_args_count++;
} else {
ASR::call_arg_t call_arg;
call_arg.m_value = var->m_symbolic_value;
call_arg.loc = (var->m_symbolic_value->base).loc;
args.push_back(al,call_arg);
}
}
if(missed_args_count > 0){
missed_args_names = missed_args_names.substr(0,missed_args_names.length() - 5);
diag.add(diag::Diagnostic(
"Number of arguments does not match in the function call",
Copy link
Collaborator

Choose a reason for hiding this comment

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

@assem2002 Do you mind adding an error reference test for this?

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
"Number of arguments does not match in the function call",
"Number of arguments in the function call do not match the function definition",

diag::Level::Error, diag::Stage::Semantic, {
diag::Label("missing " + std::to_string(missed_args_count) + " required arguments :" + missed_args_names,
{loc})
})
);
throw SemanticAbort();
}
}
if (ASRUtils::get_FunctionType(func)->m_is_restriction) {
rt_vec.push_back(s);
Expand Down Expand Up @@ -4269,6 +4320,7 @@ class SymbolTableVisitor : public CommonVisitor<SymbolTableVisitor> {
throw SemanticError("Function " + std::string(x.m_name) + " is already defined", x.base.base.loc);
}
bool is_allocatable = false, is_const = false;
size_t default_arg_index_start = x.m_args.n_args - x.m_args.n_defaults;
for (size_t i=0; i<x.m_args.n_args; i++) {
char *arg=x.m_args.m_args[i].m_arg;
Location loc = x.m_args.m_args[i].loc;
Expand All @@ -4290,6 +4342,11 @@ class SymbolTableVisitor : public CommonVisitor<SymbolTableVisitor> {
std::string arg_s = arg;
ASR::expr_t *value = nullptr;
ASR::expr_t *init_expr = nullptr;
if (i >= default_arg_index_start){
size_t default_arg_index = i - default_arg_index_start;
this->visit_expr(*(x.m_args.m_defaults[default_arg_index]));
Comment on lines +4345 to +4347
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
if (i >= default_arg_index_start){
size_t default_arg_index = i - default_arg_index_start;
this->visit_expr(*(x.m_args.m_defaults[default_arg_index]));
AST::expr_t *def_arg = nullptr;
size_t default_arg_index;
if (i >= default_arg_index_start){
default_arg_index = i - default_arg_index_start;
def_arg = x.m_args.m_defaults[default_arg_index];
this->visit_expr(*def_arg);

We can be a little readable here.

init_expr = ASRUtils::EXPR(tmp);
}
if (s_intent == ASRUtils::intent_unspecified) {
s_intent = ASRUtils::intent_in;
if (ASRUtils::is_array(arg_type)) {
Expand All @@ -4308,6 +4365,9 @@ class SymbolTableVisitor : public CommonVisitor<SymbolTableVisitor> {
}
ASR::accessType s_access = ASR::accessType::Public;
ASR::presenceType s_presence = ASR::presenceType::Required;
if (i >= default_arg_index_start){
s_presence = ASR::presenceType::Optional;
}
bool value_attr = false;
if (current_procedure_abi_type == ASR::abiType::BindC) {
value_attr = true;
Expand Down
5 changes: 5 additions & 0 deletions tests/errors/def_func_01.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lpython import i32
def func_01(x : str) -> str:
print(x)

func_01()
5 changes: 5 additions & 0 deletions tests/errors/def_func_02.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lpython import i32
def func_02(x : i32 ,y : i32) -> i32 :
print(x,y)

func_02()
5 changes: 5 additions & 0 deletions tests/errors/def_func_03.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lpython import i32
def func_03(x : i32 ,y : i32) -> i32 :
print(x,y)

func_03(1)
5 changes: 5 additions & 0 deletions tests/errors/def_func_04.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lpython import i32
def func_04(x : i32 ,y : i32) -> i32 :
print(x,y)

func_04(y=3)
5 changes: 5 additions & 0 deletions tests/errors/def_func_05.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lpython import i32
def func_05(x : i32 ,y : i32,z : i32) -> i32 :
print(x,y,z)

func_05(1,2)
5 changes: 5 additions & 0 deletions tests/errors/def_func_06.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from lpython import i32
def func_05(x : i32 ,y : i32,z : i32) -> i32 :
print(x,y,z)

func_05(z=3)
13 changes: 13 additions & 0 deletions tests/reference/asr-def_func_01-1c7f4cd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-def_func_01-1c7f4cd",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/def_func_01.py",
"infile_hash": "fda645ec7920824250cc2b5c28663061fe629b1dc341fc70ba3a691c",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-def_func_01-1c7f4cd.stderr",
"stderr_hash": "e96fc67b26c68ef0954595fb87bf261a1bfe6e9f55d83baf28e73032",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-def_func_01-1c7f4cd.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: Number of arguments does not match in the function call
--> tests/errors/def_func_01.py:5:1
|
5 | func_01()
| ^^^^^^^^^ missing 1 required arguments : 'x'
13 changes: 13 additions & 0 deletions tests/reference/asr-def_func_02-8bf7092.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-def_func_02-8bf7092",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/def_func_02.py",
"infile_hash": "fe3a3789ece86f790691ead17887dfebb8d60b882f58e06d333c9bb2",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-def_func_02-8bf7092.stderr",
"stderr_hash": "61aea2e70bfee634a40291abc98afa838c6ca173201d9d16f9dfb428",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-def_func_02-8bf7092.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: Number of arguments does not match in the function call
--> tests/errors/def_func_02.py:5:1
|
5 | func_02()
| ^^^^^^^^^ missing 2 required arguments : 'x' and 'y'
13 changes: 13 additions & 0 deletions tests/reference/asr-def_func_03-58ad7c5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-def_func_03-58ad7c5",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/def_func_03.py",
"infile_hash": "e69f130e474a8757368e7ad3e9afcd3553eaff1e819173febb66fd06",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-def_func_03-58ad7c5.stderr",
"stderr_hash": "5ac45e87ffbe795b9ca06dc4a82d3743c762f4f0a1f6bbfdc3e14ca2",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-def_func_03-58ad7c5.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: Number of arguments does not match in the function call
--> tests/errors/def_func_03.py:5:1
|
5 | func_03(1)
| ^^^^^^^^^^ missing 1 required arguments : 'y'
13 changes: 13 additions & 0 deletions tests/reference/asr-def_func_04-4af8c0d.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-def_func_04-4af8c0d",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/def_func_04.py",
"infile_hash": "522166d0c6c1a0cb273d67ce577ec42330f02822c75b1b317c97608c",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-def_func_04-4af8c0d.stderr",
"stderr_hash": "11bd3ae2f41227fd383927fa2f9fc4feff50c19784df51b56f50d3e9",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-def_func_04-4af8c0d.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: Number of arguments does not match in the function call
--> tests/errors/def_func_04.py:5:1
|
5 | func_04(y=3)
| ^^^^^^^^^^^^ missing 1 required arguments :'x'
13 changes: 13 additions & 0 deletions tests/reference/asr-def_func_05-6c33b29.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-def_func_05-6c33b29",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/def_func_05.py",
"infile_hash": "bc8d5377ec564a4d5758653dea39d5c6237992a54ec33fdef88f63f2",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-def_func_05-6c33b29.stderr",
"stderr_hash": "9dad35128e5da8dcc73f9c96bdb43ce15e3309d590bb794b14e3133c",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-def_func_05-6c33b29.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: Number of arguments does not match in the function call
--> tests/errors/def_func_05.py:5:1
|
5 | func_05(1,2)
| ^^^^^^^^^^^^ missing 1 required arguments : 'z'
13 changes: 13 additions & 0 deletions tests/reference/asr-def_func_06-9a3ebfc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-def_func_06-9a3ebfc",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/def_func_06.py",
"infile_hash": "5ad73c3f18ab4d9fe82108e65e0013687a70acc3eff495a402d4297e",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-def_func_06-9a3ebfc.stderr",
"stderr_hash": "f9c79e62d7ef7f411870195bfeb99615cb7da9216af328fda2fb0cd2",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-def_func_06-9a3ebfc.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: Number of arguments does not match in the function call
--> tests/errors/def_func_06.py:5:1
|
5 | func_05(z=3)
| ^^^^^^^^^^^^ missing 2 required arguments :'x' and 'y'
24 changes: 24 additions & 0 deletions tests/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1442,4 +1442,28 @@ run_with_dbg = true

[[test]]
filename = "errors/test_optional.py"
asr = true

[[test]]
filename = "errors/def_func_01.py"
asr = true

[[test]]
filename = "errors/def_func_02.py"
asr = true

[[test]]
filename = "errors/def_func_03.py"
asr = true

[[test]]
filename = "errors/def_func_04.py"
asr = true

[[test]]
filename = "errors/def_func_05.py"
asr = true

[[test]]
filename = "errors/def_func_06.py"
asr = true
Loading