Skip to content

Starting over on function types - initial support for function types in <> lists #1183

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 5 commits into from
Jul 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion docs/cpp2/contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Contract groups are useful to enable or disable or [set custom handlers](#violat

You can create new contract groups just by creating new objects that have a `.report_violation` function. The object's name is the contract group's name. The object can be at any scope: local, global, or heap.

For example, here are some ways to use contract groups of type [`cpp2::contract_group`](#violation_handlers), which is a convenient group type:
For example, here are some ways to use contract groups of type [`cpp2::contract_group`](#violation-handlers), which is a convenient group type:

``` cpp title="Using contract groups" hl_lines="1 4 6 10-12"
group_a: cpp2::contract_group = (); // a global group
Expand Down
34 changes: 28 additions & 6 deletions docs/cpp2/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ func: ( /* no parameters */ ) = { /* empty body */ }
```


## <a id="parameters"></a> Parameters
## <a id="function-signatures"></a> Function signatures: Parameters, returns, and using function types

### <a id="parameters"></a> Parameters

The parameter list is a [list](common.md#lists) enclosed by `(` `)` parentheses. Each parameter is declared using the [same unified syntax](declarations.md) as used for all declarations. For example:

Expand Down Expand Up @@ -72,7 +74,7 @@ wrap_f: (
```


## <a id="return-values"></a> Return values
### <a id="return-values"></a> Return values

A function can return either of the following. The default is `#!cpp -> void`.

Expand Down Expand Up @@ -152,7 +154,7 @@ main: () = {
```


### <a id="nodiscard-outputs"></a> Function outputs are not implicitly discardable
#### <a id="nodiscard-outputs"></a> Function outputs are not implicitly discardable

A function's outputs are its return values, and the "out" state of any `out` and `inout` parameters.

Expand Down Expand Up @@ -200,9 +202,29 @@ main: ()
> - A function call written in Cpp2 `x.f()` member call syntax always treats a non-`#!cpp void` return type as not discardable, even if the function was written in Cpp1 syntax that did not write `[[nodiscard]]`.


### <a id = "function-types"></a> Using function types

The same function parameter/return syntax can be used as a function type, for example to instantiate `std::function` or to declare a pointer to function variable. For example:

``` cpp title="Using function types with std::function and *pfunc" hl_lines="4 7"
decorate_int: (i: i32) -> std::string = "--> (i)$ <--";

main: () = {
pf1: std::function< (i: i32) -> std::string > = decorate_int&;
std::cout << "pf1(123) returned \"(pf1(123))$\"\n";

pf2: * (i: i32) -> std::string = decorate_int&;
std::cout << "pf2(456) returned \"(pf2(456))$\"\n";
}
// Prints:
// pf1 returned "--> 123 <--"
// pf2 returned "--> 456 <--"
```


## <a id="control flow"></a> Control flow

## <a id="branches"></a> `#!cpp if`, `#!cpp else` — Branches
### <a id="branches"></a> `#!cpp if`, `#!cpp else` — Branches

`if` and `else` are like always in C++, except that `(` `)` parentheses around the condition are not required. Instead, `{` `}` braces around a branch body *are* required. For example:

Expand All @@ -216,7 +238,7 @@ else {
```


## <a id="loops"></a> `#!cpp for`, `#!cpp while`, `#!cpp do` — Loops
### <a id="loops"></a> `#!cpp for`, `#!cpp while`, `#!cpp do` — Loops

**`#!cpp do`** and **`#!cpp while`** are like always in C++, except that `(` `)` parentheses around the condition are not required. Instead, `{` `}` braces around the loop body *are* required.

Expand Down Expand Up @@ -296,7 +318,7 @@ Line by line:
- `next i++`: The end-of-loop-iteration statement. Note `++` is always postfix in Cpp2.


### Loop names, `#!cpp break`, and `#!cpp continue`
#### Loop names, `#!cpp break`, and `#!cpp continue`

Loops can be named using the usual **name `:`** syntax that introduces all names, and `#!cpp break` and `#!cpp continue` can refer to those names. For example:

Expand Down
12 changes: 7 additions & 5 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,15 +518,17 @@ inline std::string join(List const& list) {
//
// Conveniences for expressing Cpp1 references (rarely useful)
//
// Note: Only needed in rare cases to take full control of matching a
// Cpp1 signature exactly. Most cases don't need this, for example
// a Cpp1 virtual function signature declaration like
// Note: Only needed in rare cases to take full control of matching an
// odd Cpp1 signature exactly. Most cases don't need this... for
// example, a Cpp1 virtual function signature declaration like
//
// virtual void f(int&) const
// virtual void myfunc(int& val) const
//
// can already be directly overriden by a Cpp2 declaration of
//
// f: (override this, inout val : int)
// myfunc: (override this, inout val: int)
// // identical to this in Cpp1 syntax:
// // void myfunc(int& val) const override
//
// without any need to say cpp1_ref on the int parameter.
//
Expand Down
102 changes: 102 additions & 0 deletions regression-tests/pure2-function-typeids.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@

// --- Scaffolding

f: () = std::cout << "hello world!\n";

g_in : ( s: std::string) = std::cout << "Come in, (s)$\n";
g_inout: (inout s: std::string) = std::cout << "Come in awhile, but take some biscuits on your way out, (s)$!\n";
g_out : (out s: std::string) = s = "A Powerful Mage";
g_move : (move s: std::string) = std::cout << "I hear you've moving, (s)$?\n";

h_forward: (inout s: std::string) -> forward std::string = { std::cout << "Inout (s)$ ... "; return s; }
h_out : ( s: std::string) -> std::string = { std::cout << "In (s)$ ... "; return "yohoho"; }

f1: (a: std::function< (x:int) -> int >) -> int = a(1);
f2: (a: * (x:int) -> int ) -> int = a(2);
g : (x:int) -> int = x+42;


// --- Tests for type aliases

A_h_forward: type == (inout s: std::string) -> forward std::string;


main: () =
{
// --- Test basic/degenerate cases

// Test std::function< void() >
ff: std::function< () -> void > = f&;
ff();

// Ordinary pointer to function, deduced (always worked)
pf: * () -> void = f&;
pf();


// --- Tests for parameters
// Note: Not forward parameters which imply a template...
// function type-ids are for single function signatures

fg_in : std::function< ( s: std::string) -> void > = g_in&;
fg_inout: std::function< (inout s: std::string) -> void > = g_inout&;
fg_out : std::function< (out s: std::string) -> void > = g_out&;
fg_move : std::function< (move s: std::string) -> void > = g_move&;
pg_in : * ( s: std::string) -> void = g_in&;
pg_inout: * (inout s: std::string) -> void = g_inout&;
pg_out : * (out s: std::string) -> void = g_out&;
pg_move : * (move s: std::string) -> void = g_move&;

frodo: std::string = "Frodo";
sam : std::string = "Sam";

// Test in param
fg_in(frodo);
pg_in(sam);

// Test inout
fg_inout(frodo);
pg_inout(sam);

// Test out
gandalf : std::string;
galadriel: std::string;
fg_out(out gandalf);
std::cout << "fg_out initialized gandalf to: (gandalf)$\n";
pg_out(out galadriel);
std::cout << "pg_out initialized galadriel to: (galadriel)$\n";
gandalf = "Gandalf";
galadriel = "Galadriel";

// Test move
fg_move(frodo); // last use, so (move frodo) is not required
pg_move(sam); // last use, so (move sam) is not required


// --- Tests for single anonymous returns
// Note: Not multiple named return values... function-type-ids
// are for Cpp1-style (single anonymous, possibly void) returns

fh_forward: std::function< (inout s: std::string) -> forward std::string > = h_forward&;
fh_out : std::function< ( s: std::string) -> std::string > = h_out&;
ph_forward: * (inout s: std::string) -> forward std::string = h_forward&;
ph_out : * ( s: std::string) -> std::string = h_out&;

ph_forward2: * A_h_forward = h_forward&;

// Test forward return
std::cout << "fh_forward returned: (fh_forward(gandalf))$\n";
std::cout << "ph_forward returned: (ph_forward(galadriel))$\n";
std::cout << "ph_forward2 returned: (ph_forward2(galadriel))$\n";

// Test out return
std::cout << "fh_out returned: (fh_out(gandalf))$\n";
std::cout << "ph_out returned: (ph_out(galadriel))$\n";


// --- Tests for function parameters
std::cout << "(f1(g&))$\n";
std::cout << "(f2(g&))$\n";


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
hello world!
hello world!
Come in, Frodo
Come in, Sam
Come in awhile, but take some biscuits on your way out, Frodo!
Come in awhile, but take some biscuits on your way out, Sam!
fg_out initialized gandalf to: A Powerful Mage
pg_out initialized galadriel to: A Powerful Mage
I hear you've moving, Frodo?
I hear you've moving, Sam?
Inout Gandalf ... fh_forward returned: Gandalf
Inout Galadriel ... ph_forward returned: Galadriel
Inout Galadriel ... ph_forward2 returned: Galadriel
In Gandalf ... fh_out returned: yohoho
In Galadriel ... ph_out returned: yohoho
43
44
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ do
fi
done
rm -f *.obj *.exp *.lib
find . -type f -exec bash -c "[ ! -s \"{}\" ] && rm \"{}\"" \;
printf "\nDone: %s .cpp tests compiled\n" "$count"
printf "\n %s .cpp executables generated and run\n" "$exe_count"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
hello world!
hello world!
Come in, Frodo
Come in, Sam
Come in awhile, but take some biscuits on your way out, Frodo!
Come in awhile, but take some biscuits on your way out, Sam!
fg_out initialized gandalf to: A Powerful Mage
pg_out initialized galadriel to: A Powerful Mage
I hear you've moving, Frodo?
I hear you've moving, Sam?
Inout Gandalf ... fh_forward returned: Gandalf
Inout Galadriel ... ph_forward returned: Galadriel
Inout Galadriel ... ph_forward2 returned: Galadriel
In Gandalf ... fh_out returned: yohoho
In Galadriel ... ph_out returned: yohoho
43
44
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ do
fi
done
rm -f *.obj *.exp *.lib
find . -type f -exec bash -c "[ ! -s \"{}\" ] && rm \"{}\"" \;
printf "\nDone: %s .cpp tests compiled\n" "$count"
printf "\n %s .cpp executables generated and run\n" "$exe_count"
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
In file included from mixed-bugfix-for-ufcs-non-local.cpp:6:
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | class finally_success
2100 |
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 | finally(finally&& that) noexcept
2137 | ~finally() noexcept { f(); }
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:13:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:13:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | class finally_success
2100 |
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 | finally(finally&& that) noexcept
2137 | ~finally() noexcept { f(); }
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | class finally_success
2100 |
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 | finally(finally&& that) noexcept
2137 | ~finally() noexcept { f(); }
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:31:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:31:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | class finally_success
2100 |
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 | finally(finally&& that) noexcept
2137 | ~finally() noexcept { f(); }
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:33:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:33:36: error: template argument 1 is invalid
../../../include/cpp2util.h:2100:1: error: lambda-expression in template parameter type
2100 | class finally_success
2100 |
| ^
../../../include/cpp2util.h:2137:59: note: in expansion of macro ‘CPP2_UFCS_’
2137 | finally(finally&& that) noexcept
2137 | ~finally() noexcept { f(); }
| ^
mixed-bugfix-for-ufcs-non-local.cpp2:21:12: note: in expansion of macro ‘CPP2_UFCS_NONLOCAL’
mixed-bugfix-for-ufcs-non-local.cpp2:21:36: error: template argument 1 is invalid
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
hello world!
hello world!
Come in, Frodo
Come in, Sam
Come in awhile, but take some biscuits on your way out, Frodo!
Come in awhile, but take some biscuits on your way out, Sam!
fg_out initialized gandalf to: A Powerful Mage
pg_out initialized galadriel to: A Powerful Mage
I hear you've moving, Frodo?
I hear you've moving, Sam?
Inout Gandalf ... fh_forward returned: Gandalf
Inout Galadriel ... ph_forward returned: Galadriel
Inout Galadriel ... ph_forward2 returned: Galadriel
In Gandalf ... fh_out returned: yohoho
In Galadriel ... ph_out returned: yohoho
43
44
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ do
fi
done
rm -f *.obj *.exp *.lib
find . -type f -exec bash -c "[ ! -s \"{}\" ] && rm \"{}\"" \;
printf "\nDone: %s .cpp tests compiled\n" "$count"
printf "\n %s .cpp executables generated and run\n" "$exe_count"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
hello world!
hello world!
Come in, Frodo
Come in, Sam
Come in awhile, but take some biscuits on your way out, Frodo!
Come in awhile, but take some biscuits on your way out, Sam!
fg_out initialized gandalf to: A Powerful Mage
pg_out initialized galadriel to: A Powerful Mage
I hear you've moving, Frodo?
I hear you've moving, Sam?
Inout Gandalf ... fh_forward returned: Gandalf
Inout Galadriel ... ph_forward returned: Galadriel
Inout Galadriel ... ph_forward2 returned: Galadriel
In Gandalf ... fh_out returned: yohoho
In Galadriel ... ph_out returned: yohoho
43
44
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pure2-function-typeids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ for %%f in (*.cpp) do (
)
)
del pure2-*.obj mixed-*.obj *.exp *.lib
..\..\rm-empty-files.bat
echo.
echo Done: %count% .cpp tests compiled
echo.
Expand Down
Loading
Loading