Skip to content

Commit

Permalink
feat: support function types
Browse files Browse the repository at this point in the history
Add _function-type_ as an alternative production of _type-id_.
A parameter's identifier must be named `_`.
`!throws` needs to be specified for Cpp1-`noexcept` function types.

Some examples:
```Cpp2
main: () = {
  f0: * () = :()      = {};
  f7: * (move _: i32) = :(move x: i32) = {};
  [[assert: inspect f0 -> bool {
    is () !throws = (std::terminate(), false);
    is * ()       = true;
    is _          = false;
  }]]
}

// Test case from hsutter#343.
f2: () -> std::function<(_: std::string) -> std::string> = {
  return :(s: std::string) -> std::string = { return s + " World!"; };
}

// Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>.
            f:   (x: i32) -> * (_: i32) -> std::string = :(x: i32) -> std::string = "";
postfix_operators: () = {
  [[assert: f is (_: i32) -> * (_: i32) -> std::string]]
  //             /           |  |
  //            /            |  |
  [[assert: f(42)     is     * (_: i32) -> std::string]]
  //               _________/   |
  //              /             |
  [[assert: f(42)*     is      (_: i32) -> std::string]]
  //                   ________/
  //                  /
  [[assert: (f(42)*)(1)         is         std::string]]
}
  • Loading branch information
JohelEGP committed Aug 20, 2023
1 parent 11fc88d commit 66252fa
Show file tree
Hide file tree
Showing 22 changed files with 589 additions and 64 deletions.
25 changes: 18 additions & 7 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
// in our -pure-cpp2 "import std;" simulation mode... if you need this,
// use mixed mode (not -pure-cpp2) and #include all the headers you need
// including this one
//
//
// #include <execution>
#endif

Expand Down Expand Up @@ -277,6 +277,17 @@ using __schar = signed char; // normally use i8 instead
using __uchar = unsigned char; // normally use u8 instead


//-----------------------------------------------------------------------
//
// fn_t<R(ArgTypes...)> For emitted Cpp2 function types
//
//-----------------------------------------------------------------------
//
template<typename T>
requires std::is_function_v<T>
using fn_t = T;


//-----------------------------------------------------------------------
//
// String: A helper workaround for passing a string literal as a
Expand Down Expand Up @@ -466,7 +477,7 @@ template<typename T>
auto Typeid() -> decltype(auto) {
#ifdef CPP2_NO_RTTI
Type.expects(
!"'any' dynamic casting is disabled with -fno-rtti", // more likely to appear on console
!"'any' dynamic casting is disabled with -fno-rtti", // more likely to appear on console
"'any' dynamic casting is disabled with -fno-rtti" // make message available to hooked handlers
);
#else
Expand Down Expand Up @@ -828,17 +839,17 @@ auto is( X const& ) -> bool {

template< typename C, typename X >
requires (
( std::is_base_of_v<X, C> ||
( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
( std::is_base_of_v<X, C> ||
( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
) && !std::is_same_v<C,X>)
auto is( X const& x ) -> bool {
return Dynamic_cast<C const*>(&x) != nullptr;
}

template< typename C, typename X >
requires (
( std::is_base_of_v<X, C> ||
( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
( std::is_base_of_v<X, C> ||
( std::is_polymorphic_v<C> && std::is_polymorphic_v<X>)
) && !std::is_same_v<C,X>)
auto is( X const* x ) -> bool {
return Dynamic_cast<C const*>(x) != nullptr;
Expand Down Expand Up @@ -1426,7 +1437,7 @@ inline auto to_string(std::string const& s) -> std::string const&

template<typename T>
inline auto to_string(T const& sv) -> std::string
requires (std::is_convertible_v<T, std::string_view>
requires (std::is_convertible_v<T, std::string_view>
&& !std::is_convertible_v<T, const char*>)
{
return std::string{sv};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
main: (args) = { _ = :* int = args.argc&; }
3 changes: 3 additions & 0 deletions regression-tests/pure2-function-type-id-2-error.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main: () = {
f: * (x: i32) throws = :(_) = {};
}
3 changes: 3 additions & 0 deletions regression-tests/pure2-function-type-id-3-error.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main: () = {
f: * () [[pre: true]] = :() = {};
}
1 change: 1 addition & 0 deletions regression-tests/pure2-function-type-id-4-error.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
main: () = { f: * () -> (x: i32); }
3 changes: 3 additions & 0 deletions regression-tests/pure2-function-type-id-5-error.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main: () = {
f: * (_) throws = :(_) = {};
}
112 changes: 112 additions & 0 deletions regression-tests/pure2-function-type-id.cpp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
main: () = {
postfix_operators();

// Variables with type of a mix of `*`/`const` to `() throws -> void`.
f0: * () throws = :() = {};
f1: const * () throws = f0;
f2: * const () throws = f0;
f3: const * const () throws = f0;

// Uninitialized.
f4: * () throws;
f4 = f0;

f10: * * () throws = f0&;
f11: const * * () throws = f10;
f12: * const * () throws = f10;
f13: const * const * () throws = f10;

i: i32 = 0;
i0: * i32 = i&;
i1: const * i32 = i0;
i2: * const i32 = i0;
i3: const * const i32 = i0;

// Assert consistent '*'/'const' with non-function type variables.
static_assert((std::is_const_v<decltype(f10)>) == std::is_const_v<decltype(i0)>);
static_assert((std::is_const_v<decltype(f11)>) == std::is_const_v<decltype(i1)>);
static_assert((std::is_const_v<decltype(f12)>) == std::is_const_v<decltype(i2)>);
static_assert((std::is_const_v<decltype(f13)>) == std::is_const_v<decltype(i3)>);
_ = f10;
_ = f11;
_ = f12;
_ = f13;
_ = i0;
_ = i1;
_ = i2;
_ = i3;

// Variables with various kinds of parameter.
f5: * (_: i32) throws = :(x: i32) = {};
f6: * (_: std::any) throws = :(x: std::any) = {};
f7: * (move _: i32) throws = :(move x: i32) = {};
f8: * (out _: i32) throws = :(copy x) = {};

// In alternative.
[[assert: inspect f0 -> bool {
is () = (std::terminate(), false);
is () throws = (std::terminate(), false);
is * () throws = true;
is _ = false;
}]]
[[assert: inspect f0* -> bool {
is () throws = true;
is _ = false;
}]]

// As block variable.
(f: * () throws = f0) { }
(f: () throws = f0*) { }

// As local function parameter.
_ = :(f: () throws) = {};
_ = :(f: * () throws) = {};
_ = :(f: * () throws -> * () throws) = {};
_ = :(f: * () throws -> * () throws -> * () throws) = {};

// In local function return type.
_ = :() -> forward() throws = f0$*;
_ = :() -> * () throws = nullptr;
_ = :() -> * () throws -> * () throws = nullptr;

// Without `throws`.
_ = :* (copy _: std::string_view, copy _: CPP2_MESSAGE_PARAM) = cpp2::report_and_terminate;

// As template argument.
_ = :std::type_identity_t<* () throws> = f0;
static_assert(std::is_function_v<() throws>);
}

// As non-local function parameter.
g: (f: () throws) = { }
g: (f: * () throws) = { }
g: (f: * () throws -> * () throws) = { }
// As template parameter.
g: <V: * () throws> () = { }
g: <V: * () throws -> * () throws> () = { }

// In non-local function return type.
g1: () -> * () throws = nullptr;
g1: <V: bool> () -> * () throws requires V = { return nullptr; }
g2: () -> * () throws -> * () throws = nullptr;

// clang-format off
// Test case from #343.
f2: () -> std::function<(_: std::string) throws -> std::string> = {
return :(s: std::string) -> std::string = { return s + " World!"; };
}

// Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>.
f: (x: i32) -> * (_: i32) throws -> std::string = +:(x: i32) -> std::string = "";
postfix_operators: () = {
[[assert: f is (_: i32) throws -> * (_: i32) throws -> std::string]]
// / | |
// / | |
[[assert: f(42) is * (_: i32) throws -> std::string]]
// ________________/ |
// / |
[[assert: f(42)* is (_: i32) throws -> std::string]]
// _______________/
// /
[[assert: (f(42)*)(1) is std::string]]
} // clang-format on
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

#define CPP2_USE_MODULES Yes

//=== Cpp2 type declarations ====================================================


#include "cpp2util.h"



//=== Cpp2 type definitions and function declarations ===========================

#line 1 "pure2-bugfix-for-multi-token-type-prvalue.cpp2"
auto main(int const argc_, char const* const* const argv_) -> int;


//=== Cpp2 function definitions =================================================

#line 1 "pure2-bugfix-for-multi-token-type-prvalue.cpp2"
auto main(int const argc_, char const* const* const argv_) -> int{
auto args = cpp2::make_args(argc_, argv_);
#line 1 "pure2-bugfix-for-multi-token-type-prvalue.cpp2"
(void) std::type_identity_t<int*>{&args.argc}; }

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pure2-bugfix-for-multi-token-type-prvalue.cpp2... ok (all Cpp2, passes safety checks)

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-function-type-id-2-error.cpp2...
pure2-function-type-id-2-error.cpp2(2,9): error: the parameter of a function type must be named '_'

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-function-type-id-3-error.cpp2...
pure2-function-type-id-3-error.cpp2(2,11): error: a function type can't have contracts

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pure2-function-type-id-4-error.cpp2...
pure2-function-type-id-4-error.cpp2(1,25): error: a function type can't have an anonymous return type
pure2-function-type-id-4-error.cpp2(1,14): error: f - variable must be initialized on every branch path
==> program violates initialization safety guarantee - see previous errors

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pure2-function-type-id-5-error.cpp2...
pure2-function-type-id-5-error.cpp2(2,9): error: function type parameter must have a type

Loading

0 comments on commit 66252fa

Please sign in to comment.