-
Notifications
You must be signed in to change notification settings - Fork 251
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(to_cpp1): improve recognition of dependent types and deducible pa…
…rameters
- Loading branch information
Showing
16 changed files
with
762 additions
and
60 deletions.
There are no files selected for viewing
33 changes: 33 additions & 0 deletions
33
regression-tests/pure2-bugfix-for-deducible-parameters.cpp2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Dependent, non-deducible parameters | ||
// are wrapped like non-dependent parameters. | ||
init: <T> (out x: std::integral_constant<i32, T::value>) = { x = (); } | ||
init: <T> (out x: std::integral_constant<i32, T::value>, _: T) = { x = (); } | ||
id: <T> (x: std::integral_constant<i32, T::value>) -> forward _ = x; | ||
id: <T> (x: std::integral_constant<i32, T::value>, y: T) = { assert(x& == y&); } | ||
|
||
main: () = { | ||
zero: type == std::integral_constant<i32, 0>; | ||
|
||
z: zero; | ||
init<zero>(out z); | ||
assert(id<zero>(z)& == z&); | ||
|
||
// Deducible parameters. | ||
_ = :v = 0; | ||
_ = :<T> (x: std::vector<T>) = {}(:std::vector<i32> = ()); | ||
_ = :<T> (x: std::vector<std::vector<T>>) = {}(:std::vector<std::vector<i32>> = ()); | ||
// _ = :<T, U> (x: std::pair<T, typename U::value_type>, y: U) = {}(:std::pair = (0, 0), z); // Blocked on #727. | ||
_ = :<T, U> (x: std::array<T, U::value>, y: U) = {}(:std::array<i32, 0> = (), z); | ||
init(out z, z); | ||
id(z, z); | ||
|
||
// Test that these are emitted unwrapped in case they are deducible. | ||
(copy f := :<T> (x: std::vector<std::type_identity_t<T>>) = {}) | ||
static_assert(!std::is_invocable_v<decltype(f), std::vector<i32>>, "`T` is non-deducible."); | ||
(copy f := :<T> (x: std::vector<std::vector<T>>) = {}) | ||
static_assert(std::is_invocable_v<decltype(f), std::vector<std::vector<i32>>>, "`T` is deducible."); | ||
} | ||
|
||
v: <T> type = { | ||
operator=: (out this, x: T) = { } | ||
} |
6 changes: 6 additions & 0 deletions
6
regression-tests/pure2-bugfix-for-dependent-types-recursion.cpp2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
main: () = { | ||
a: type == b; | ||
b: type == a; | ||
_ = a::t; | ||
_ = b::t; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
identity: <T> type == T; | ||
|
||
f: <T, V: T::value_type> (x: T::value_type) -> T::value_type = { | ||
assert(x is T::value_type); | ||
y: T::value_type; | ||
y = x; | ||
z: type == T::value_type; | ||
return (:T::value_type = x); | ||
|
||
// Dependent *template-id*s. | ||
_ = :identity<T>::value_type = (); // First identifier. | ||
_ = :std::optional<T>::value_type = (); // Non-first identifier. | ||
_ = :std::array<i32, T::value>::value_type = (); | ||
_ = :std::array<i32, T::value + T::value>::value_type = (); | ||
|
||
// Emitted `template`. | ||
ptr: type == * T; // Also test lookup through type aliases. | ||
nptr: type == * i32; | ||
_ = :std::pointer_traits<ptr>::rebind<ptr> = (); // Type-only context. | ||
_ = :std::pointer_traits<nptr>::rebind<nptr> = (); // Non-dependent. | ||
_ = :std::pointer_traits<nptr>::rebind<ptr> = (); // Dependent on the nested template. | ||
_ = :std::pointer_traits<ptr>::rebind<nptr> = (); // Dependent on the outer template. | ||
// _ = :identity<typename std::pointer_traits<ptr>::rebind<ptr>> = (); // Non type-only context. Blocked on #727. | ||
|
||
// Aliases. | ||
w: type == T; | ||
_ = :w::value_type = x; | ||
v: type == w; | ||
_ = :v::value_type = x; | ||
a: type == T::type; | ||
_ = :a::value_type = x; | ||
|
||
{ | ||
// Test that there's no prefixed `typename` to.... | ||
_ = std::integral_constant<i32, T::value>(); // `T::value`. | ||
_ = :std::type_identity_t<T> = (); // `std::type_identity_t<T>`. | ||
|
||
// Test that non-dependent names aren't emitted with `typename`. | ||
a: type == std::integral_constant<i32, 0>; | ||
b: type == a; | ||
c: type == b; | ||
_ = :b::value_type = x; | ||
_ = :c::value_type = x; | ||
} | ||
} | ||
|
||
t: @struct <T: type> type = { | ||
u: @struct type = { | ||
x: T::value_type = (); | ||
this: T::type = (); | ||
} | ||
x: T::value_type = 0; | ||
} | ||
|
||
main: () = { | ||
zero: type == std::integral_constant<i32, 0>; | ||
_ = f<zero, 0>(0); | ||
|
||
// clang-format off | ||
_ = : ::t<zero> = (); // clang-format on | ||
|
||
// Emitted `template` (noop, taken care of by the UFCS macro). | ||
_ = :(f) = { _ = f.operator()<i32>(); }(:<T> () = {}); | ||
|
||
// Nesting is not relevant to lookup. | ||
_ = :<T> () = { _ = :T::value_type = (); }; | ||
_ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; | ||
_ = :() = { _ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; }; | ||
_ = :() = { _ = :() = { _ = :() = { _ = :<T> () = { _ = :T::value_type = (); }; }; }; }; | ||
_ = :() = { _ = :() = { _ = :<T> () = { _ = :() = { _ = :T::value_type = (); }; }; }; }; | ||
_ = :() = { _ = :<T> () = { _ = :() = { _ = :() = { _ = :T::value_type = (); }; }; }; }; | ||
_ = :<T> () = { _ = :() = { _ = :() = { _ = :() = { _ = :T::value_type = (); }; }; }; }; | ||
_ = :<T> () = { _ = :() = { _ = :() = { _ = :(x: T::value_type) = {}; }; }; }; | ||
_ = :<T> () = { _ = :() = { _ = :(x: T::value_type) = { _ = :() = {}; }; }; }; | ||
_ = :<T> () = { _ = :(x: T::value_type) = { _ = :() = { _ = :() = {}; }; }; }; | ||
_ = :<T> (x: T::value_type) = { _ = :() = { _ = :() = { _ = :() = {}; }; }; }; | ||
|
||
// Lookup. | ||
{ | ||
alias: type == std::integral_constant<i32, 0>; | ||
_ = :alias::value_type = 0; // Non-dependent. | ||
} | ||
_ = :<T> (_: T) = { | ||
alias: type == std::integral_constant<T, 0>; | ||
_ = :alias::value_type = 0; // Dependent. | ||
{ | ||
alias: type == std::integral_constant<i32, 0>; | ||
_ = :alias::value_type = 0; // Non-dependent. | ||
} | ||
}(0); | ||
} |
Empty file.
Empty file.
13 changes: 13 additions & 0 deletions
13
regression-tests/test-results/gcc-13/pure2-bugfix-for-dependent-types-recursion.cpp.output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
pure2-bugfix-for-dependent-types-recursion.cpp: In function ‘int main()’: | ||
pure2-bugfix-for-dependent-types-recursion.cpp:19:13: error: ‘b’ does not name a type | ||
19 | using a = b; | ||
| ^ | ||
pure2-bugfix-for-dependent-types-recursion.cpp:20:13: error: ‘a’ does not name a type | ||
20 | using b = a; | ||
| ^ | ||
pure2-bugfix-for-dependent-types-recursion.cpp:21:21: error: ‘a’ has not been declared | ||
21 | static_cast<void>(a::t); | ||
| ^ | ||
pure2-bugfix-for-dependent-types-recursion.cpp:22:21: error: ‘b’ has not been declared | ||
22 | static_cast<void>(b::t); | ||
| ^ |
Empty file.
Empty file.
87 changes: 87 additions & 0 deletions
87
regression-tests/test-results/pure2-bugfix-for-deducible-parameters.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
|
||
#define CPP2_IMPORT_STD Yes | ||
|
||
//=== Cpp2 type declarations ==================================================== | ||
|
||
|
||
#include "cpp2util.h" | ||
|
||
|
||
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> class v; | ||
|
||
|
||
//=== Cpp2 type definitions and function declarations =========================== | ||
|
||
// Dependent, non-deducible parameters | ||
// are wrapped like non-dependent parameters. | ||
#line 3 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x) -> void; | ||
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& param2) -> void; | ||
template<typename T> [[nodiscard]] auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x) -> auto&&; | ||
template<typename T> auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void; | ||
|
||
auto main() -> int; | ||
|
||
|
||
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> class v { | ||
public: explicit v(T const& x); | ||
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
public: auto operator=(T const& x) -> v& ; | ||
|
||
public: v(v const&) = delete; /* No 'that' constructor, suppress copy */ | ||
public: auto operator=(v const&) -> void = delete; | ||
#line 33 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
}; | ||
|
||
|
||
//=== Cpp2 function definitions ================================================= | ||
|
||
|
||
#line 3 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x) -> void{x.construct(); } | ||
template<typename T> auto init(cpp2::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& param2) -> void{x.construct(); } | ||
template<typename T> [[nodiscard]] auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x) -> auto&& { return x; } | ||
template<typename T> auto id(cpp2::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void{cpp2::Default.expects(&x == &y, ""); } | ||
|
||
auto main() -> int{ | ||
using zero = std::integral_constant<cpp2::i32,0>; | ||
|
||
cpp2::deferred_init<zero> z; | ||
init<zero>(cpp2::out(&z)); | ||
cpp2::Default.expects(&id<zero>(z.value()) == &z.value(), ""); | ||
|
||
// Deducible parameters. | ||
static_cast<void>(v{0}); | ||
static_cast<void>([]<typename T>(std::vector<T> const& x) -> void{}(std::vector<cpp2::i32>{})); | ||
static_cast<void>([]<typename T>(std::vector<std::vector<T>> const& x) -> void{}(std::vector<std::vector<cpp2::i32>>{})); | ||
// _ = :<T, U> (x: std::pair<T, typename U::value_type>, y: U) = {}(:std::pair = (0, 0), z); // Blocked on #727. | ||
static_cast<void>([]<typename T, typename U>(std::array<T,U::value> const& x, U const& y) -> void{}(std::array<cpp2::i32,0>{}, z.value())); | ||
init(cpp2::out(&z.value()), z.value()); | ||
id(z.value(), std::move(z.value())); | ||
{ | ||
auto f = []<typename T>(std::vector<std::type_identity_t<T>> const& x) -> void{}; | ||
|
||
// Test that these are emitted unwrapped in case they are deducible. | ||
|
||
#line 26 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
static_assert(!(std::is_invocable_v<decltype(f),std::vector<cpp2::i32>>), "`T` is non-deducible."); | ||
} | ||
{ | ||
auto f = []<typename T>(std::vector<std::vector<T>> const& x) -> void{}; | ||
|
||
#line 28 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
static_assert(std::is_invocable_v<decltype(std::move(f)),std::vector<std::vector<cpp2::i32>>>, "`T` is deducible."); | ||
} | ||
#line 29 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
} | ||
|
||
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template <typename T> v<T>::v(T const& x){} | ||
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template <typename T> auto v<T>::operator=(T const& x) -> v& { | ||
return *this; | ||
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
} | ||
|
2 changes: 2 additions & 0 deletions
2
regression-tests/test-results/pure2-bugfix-for-deducible-parameters.cpp2.output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pure2-bugfix-for-deducible-parameters.cpp2... ok (all Cpp2, passes safety checks) | ||
|
24 changes: 24 additions & 0 deletions
24
regression-tests/test-results/pure2-bugfix-for-dependent-types-recursion.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
|
||
#define CPP2_IMPORT_STD Yes | ||
|
||
//=== Cpp2 type declarations ==================================================== | ||
|
||
|
||
#include "cpp2util.h" | ||
|
||
|
||
|
||
//=== Cpp2 type definitions and function declarations =========================== | ||
|
||
auto main() -> int; | ||
|
||
|
||
//=== Cpp2 function definitions ================================================= | ||
|
||
auto main() -> int{ | ||
using a = b; | ||
using b = a; | ||
static_cast<void>(a::t); | ||
static_cast<void>(b::t); | ||
} | ||
|
2 changes: 2 additions & 0 deletions
2
regression-tests/test-results/pure2-bugfix-for-dependent-types-recursion.cpp2.output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pure2-bugfix-for-dependent-types-recursion.cpp2... ok (all Cpp2, passes safety checks) | ||
|
122 changes: 122 additions & 0 deletions
122
regression-tests/test-results/pure2-bugfix-for-dependent-types.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
|
||
#define CPP2_IMPORT_STD Yes | ||
|
||
//=== Cpp2 type declarations ==================================================== | ||
|
||
|
||
#include "cpp2util.h" | ||
|
||
|
||
#line 47 "pure2-bugfix-for-dependent-types.cpp2" | ||
template<typename T> class t; | ||
|
||
|
||
//=== Cpp2 type definitions and function declarations =========================== | ||
|
||
template<typename T> using identity = T; | ||
|
||
template<typename T, T::value_type V> [[nodiscard]] auto f(cpp2::in<typename T::value_type> x) -> T::value_type; | ||
|
||
|
||
#line 47 "pure2-bugfix-for-dependent-types.cpp2" | ||
template<typename T> class t { | ||
struct u_x_as_base { T::value_type x; }; | ||
|
||
#line 48 "pure2-bugfix-for-dependent-types.cpp2" | ||
public: class u: public u_x_as_base, public T::type { | ||
|
||
#line 51 "pure2-bugfix-for-dependent-types.cpp2" | ||
}; | ||
public: T::value_type x {0}; | ||
}; | ||
|
||
auto main() -> int; | ||
|
||
|
||
//=== Cpp2 function definitions ================================================= | ||
|
||
|
||
#line 3 "pure2-bugfix-for-dependent-types.cpp2" | ||
template<typename T, T::value_type V> [[nodiscard]] auto f(cpp2::in<typename T::value_type> x) -> T::value_type{ | ||
cpp2::Default.expects(cpp2::is<typename T::value_type>(x), ""); | ||
cpp2::deferred_init<typename T::value_type> y; | ||
y.construct(x); | ||
using z = T::value_type; | ||
return { typename T::value_type{x} }; | ||
|
||
// Dependent *template-id*s. | ||
static_cast<void>(typename identity<T>::value_type{});// First identifier. | ||
static_cast<void>(typename std::optional<T>::value_type{});// Non-first identifier. | ||
static_cast<void>(typename std::array<cpp2::i32,T::value>::value_type{}); | ||
static_cast<void>(typename std::array<cpp2::i32,T::value + T::value>::value_type{}); | ||
|
||
// Emitted `template`. | ||
using ptr = T*; // Also test lookup through type aliases. | ||
using nptr = cpp2::i32*; | ||
static_cast<void>(typename std::pointer_traits<ptr>::template rebind<ptr>{});// Type-only context. | ||
static_cast<void>(std::pointer_traits<nptr>::rebind<nptr>{});// Non-dependent. | ||
static_cast<void>(std::pointer_traits<nptr>::rebind<ptr>{});// Dependent on the nested template. | ||
static_cast<void>(typename std::pointer_traits<ptr>::template rebind<nptr>{});// Dependent on the outer template. | ||
// _ = :identity<typename std::pointer_traits<ptr>::rebind<ptr>> = (); // Non type-only context. Blocked on #727. | ||
|
||
// Aliases. | ||
using w = T; | ||
static_cast<void>(typename w::value_type{x}); | ||
using v = w; | ||
static_cast<void>(typename v::value_type{x}); | ||
using a = T::type; | ||
static_cast<void>(typename a::value_type{x}); | ||
|
||
{ | ||
// Test that there's no prefixed `typename` to.... | ||
static_cast<void>(std::integral_constant<cpp2::i32,T::value>());// `T::value`. | ||
static_cast<void>(std::type_identity_t<T>{});// `std::type_identity_t<T>`. | ||
|
||
// Test that non-dependent names aren't emitted with `typename`. | ||
using a = std::integral_constant<cpp2::i32,0>; | ||
using b = a; | ||
using c = b; | ||
static_cast<void>(b::value_type{x}); | ||
static_cast<void>(c::value_type{x}); | ||
} | ||
} | ||
|
||
#line 55 "pure2-bugfix-for-dependent-types.cpp2" | ||
auto main() -> int{ | ||
using zero = std::integral_constant<cpp2::i32,0>; | ||
static_cast<void>(f<zero,0>(0)); | ||
|
||
// clang-format off | ||
static_cast<void>(::t<zero>{});// clang-format on | ||
|
||
// Emitted `template` (noop, taken care of by the UFCS macro). | ||
static_cast<void>([](auto const& f) -> void{static_cast<void>(CPP2_UFCS_TEMPLATE_0(operator(), (<cpp2::i32>), f)); }([]<typename T>() -> void{})); | ||
|
||
// Nesting is not relevant to lookup. | ||
static_cast<void>([]<typename T>() -> void{static_cast<void>(typename T::value_type{}); }); | ||
static_cast<void>([]() -> void{static_cast<void>([]<typename T>() -> void{static_cast<void>(typename T::value_type{}); }); }); | ||
static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([]<typename T>() -> void{static_cast<void>(typename T::value_type{}); }); }); }); | ||
static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([]<typename T>() -> void{static_cast<void>(typename T::value_type{}); }); }); }); }); | ||
static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([]<typename T>() -> void{static_cast<void>([]() -> void{static_cast<void>(typename T::value_type{}); }); }); }); }); | ||
static_cast<void>([]() -> void{static_cast<void>([]<typename T>() -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>(typename T::value_type{}); }); }); }); }); | ||
static_cast<void>([]<typename T>() -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>(typename T::value_type{}); }); }); }); }); | ||
static_cast<void>([]<typename T>() -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([](cpp2::in<typename T::value_type> x) -> void{}); }); }); }); | ||
static_cast<void>([]<typename T>() -> void{static_cast<void>([]() -> void{static_cast<void>([](cpp2::in<typename T::value_type> x) -> void{static_cast<void>([]() -> void{}); }); }); }); | ||
static_cast<void>([]<typename T>() -> void{static_cast<void>([](cpp2::in<typename T::value_type> x) -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{}); }); }); }); | ||
static_cast<void>([]<typename T>(cpp2::in<typename T::value_type> x) -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{static_cast<void>([]() -> void{}); }); }); }); | ||
|
||
// Lookup. | ||
{ | ||
using alias = std::integral_constant<cpp2::i32,0>; | ||
static_cast<void>(alias::value_type{0});// Non-dependent. | ||
} | ||
static_cast<void>([]<typename T>([[maybe_unused]] T const& param1) -> void{ | ||
using alias = std::integral_constant<T,0>; | ||
static_cast<void>(typename alias::value_type{0});// Dependent. | ||
{ | ||
using alias = std::integral_constant<cpp2::i32,0>; | ||
static_cast<void>(typename alias::value_type{0});// Non-dependent. | ||
} | ||
}(0)); | ||
} | ||
|
2 changes: 2 additions & 0 deletions
2
regression-tests/test-results/pure2-bugfix-for-dependent-types.cpp2.output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pure2-bugfix-for-dependent-types.cpp2... ok (all Cpp2, passes safety checks) | ||
|
Oops, something went wrong.