-
Notifications
You must be signed in to change notification settings - Fork 261
fix(to_cpp1): improve recognition of dependent types and deducible parameters #533
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// 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> (in_ref x: std::integral_constant<i32, T::value>) = 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> (_: std::vector<T>) = {}(:std::vector<i32> = ()); | ||
:<T> (_: 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> (_: std::array<T, U::value>, _: 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> (_: 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> (_: 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, _: T) = { } | ||
} |
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; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
identity: <T> type == T; | ||
|
||
f: <T> (inout _: T::value_type) = { } | ||
f: <T> (move _: T::value_type) = { } | ||
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: @cpp1_rule_of_zero <T: type> type = { | ||
u: type = { | ||
x: T::value_type = (); | ||
this: T::type = (); | ||
// Test that there's no `typename` in the member initializer list. | ||
operator=: (out this, that) = { } | ||
} | ||
x: T::value_type = 0; | ||
} | ||
|
||
main: () = { | ||
zero: type == std::integral_constant<i32, 0>; | ||
_ = f<zero, 0>(0); | ||
|
||
_ = : ::t<zero> = (); | ||
|
||
// Emitted `template` (noop, taken care of by the UFCS macro). | ||
_ = :(move 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> () = { _ = :() = { _ = :() = { _ = :(_: T::value_type) = {}; }; }; }; | ||
_ = :<T> () = { _ = :() = { _ = :(_: T::value_type) = { _ = :() = {}; }; }; }; | ||
_ = :<T> () = { _ = :(_: T::value_type) = { _ = :() = { _ = :() = {}; }; }; }; | ||
_ = :<T> (_: 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); | ||
|
||
_ = :(r) -> std::type_identity_t<decltype(begin(r)*)> = r[0];(std::vector<int>(1)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:2:13: error: unknown type name 'b' | ||
using a = b; | ||
^ | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:3:13: error: unknown type name 'a' | ||
using b = a; | ||
^ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it intended that these test cases fail?
For some reason the latter works on GCC 14? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
pure2-bugfix-for-dependent-types-recursion.cpp2:4:21: error: use of undeclared identifier 'a' | ||
static_cast<void>(a::t); | ||
^ | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:5:21: error: use of undeclared identifier 'b' | ||
static_cast<void>(b::t); | ||
^ | ||
4 errors generated. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
pure2-bugfix-for-dependent-types.cpp2:5:22: error: missing 'typename' prior to dependent type name 'T::value_type' | ||
template<typename T, T::value_type V> [[nodiscard]] auto f(cpp2::impl::in<typename T::value_type> x) -> T::value_type; | ||
^~~~~~~~~~~~~ | ||
typename | ||
pure2-bugfix-for-dependent-types.cpp2:5:105: error: missing 'typename' prior to dependent type name 'T::value_type' | ||
template<typename T, T::value_type V> [[nodiscard]] auto f(cpp2::impl::in<typename T::value_type> x) -> T::value_type; | ||
^~~~~~~~~~~~~ | ||
typename | ||
pure2-bugfix-for-dependent-types.cpp2:56:12: error: missing 'typename' prior to dependent type name 'T::value_type' | ||
private: T::value_type x {0}; | ||
^~~~~~~~~~~~~ | ||
typename | ||
pure2-bugfix-for-dependent-types.cpp2:5:22: error: missing 'typename' prior to dependent type name 'T::value_type' | ||
template<typename T, T::value_type V> [[nodiscard]] auto f(cpp2::impl::in<typename T::value_type> x) -> T::value_type{ | ||
^~~~~~~~~~~~~ | ||
typename | ||
pure2-bugfix-for-dependent-types.cpp2:5:105: error: missing 'typename' prior to dependent type name 'T::value_type' | ||
template<typename T, T::value_type V> [[nodiscard]] auto f(cpp2::impl::in<typename T::value_type> x) -> T::value_type{ | ||
^~~~~~~~~~~~~ | ||
typename | ||
pure2-bugfix-for-dependent-types.cpp2:9:13: error: missing 'typename' prior to dependent type name 'T::value_type' | ||
using z = T::value_type; | ||
^~~~~~~~~~~~~ | ||
typename | ||
pure2-bugfix-for-dependent-types.cpp2:32:13: error: missing 'typename' prior to dependent type name 'T::type' | ||
using a = T::type; | ||
^~~~~~~ | ||
typename | ||
7 errors generated. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pure2-bugfix-for-dependent-types-recursion.cpp2: In function ‘int main()’: | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:2:13: error: ‘b’ does not name a type | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:3:13: error: ‘a’ does not name a type | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:4:21: error: ‘a’ has not been declared | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:5:21: error: ‘b’ has not been declared |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pure2-bugfix-for-dependent-types.cpp2: In function ‘typename T::value_type f(cpp2::impl::in<typename T::value_type>) [with T = std::integral_constant<int, 0>; typename T::value_type V = 0]’: | ||
pure2-bugfix-for-dependent-types.cpp2:47:1: warning: control reaches end of non-void function [-Wreturn-type] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pure2-bugfix-for-dependent-types-recursion.cpp2: In function ‘int main()’: | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:2:13: error: ‘b’ does not name a type | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:3:13: error: ‘a’ does not name a type | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:4:21: error: ‘a’ has not been declared | ||
pure2-bugfix-for-dependent-types-recursion.cpp2:5:21: error: ‘b’ has not been declared |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pure2-bugfix-for-deducible-parameters.cpp |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
pure2-bugfix-for-dependent-types-recursion.cpp | ||
pure2-bugfix-for-dependent-types-recursion.cpp2(2): error C2061: syntax error: identifier 'b' | ||
pure2-bugfix-for-dependent-types-recursion.cpp2(3): error C2061: syntax error: identifier 'a' | ||
pure2-bugfix-for-dependent-types-recursion.cpp2(4): error C2653: 'a': is not a class or namespace name | ||
pure2-bugfix-for-dependent-types-recursion.cpp2(4): error C2065: 't': undeclared identifier | ||
pure2-bugfix-for-dependent-types-recursion.cpp2(5): error C2653: 'b': is not a class or namespace name | ||
pure2-bugfix-for-dependent-types-recursion.cpp2(5): error C2065: 't': undeclared identifier |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pure2-bugfix-for-dependent-types.cpp | ||
pure2-bugfix-for-dependent-types.cpp2(66): fatal error C1202: recursive type or function dependency context too complex |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
|
||
#define CPP2_IMPORT_STD Yes | ||
|
||
//=== Cpp2 type declarations ==================================================== | ||
|
||
|
||
#include "cpp2util.h" | ||
|
||
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
|
||
#line 30 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> class v; | ||
|
||
|
||
//=== Cpp2 type definitions and function declarations =========================== | ||
|
||
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
// Dependent, non-deducible parameters are wrapped like non-dependent parameters. | ||
#line 2 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x) -> void; | ||
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& unnamed_param_2) -> void; | ||
template<typename T> [[nodiscard]] auto id(std::integral_constant<cpp2::i32,T::value> const& x) -> decltype(auto); | ||
template<typename T> auto id(cpp2::impl::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void; | ||
|
||
auto main() -> int; | ||
|
||
#line 30 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> class v { | ||
public: explicit v([[maybe_unused]] T const& unnamed_param_2); | ||
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
public: auto operator=([[maybe_unused]] T const& unnamed_param_2) -> v& ; | ||
public: v(v const&) = delete; /* No 'that' constructor, suppress copy */ | ||
public: auto operator=(v const&) -> void = delete; | ||
|
||
#line 32 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
}; | ||
|
||
|
||
//=== Cpp2 function definitions ================================================= | ||
|
||
#line 1 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
|
||
#line 2 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x) -> void{x.construct(); } | ||
#line 3 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> auto init(cpp2::impl::out<std::integral_constant<cpp2::i32,T::value>> x, [[maybe_unused]] T const& unnamed_param_2) -> void{x.construct(); } | ||
#line 4 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> [[nodiscard]] auto id(std::integral_constant<cpp2::i32,T::value> const& x) -> decltype(auto) { return x; } | ||
#line 5 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template<typename T> auto id(cpp2::impl::in<std::integral_constant<cpp2::i32,T::value>> x, T const& y) -> void{if (cpp2::cpp2_default.is_active() && !(&x == &y) ) { cpp2::cpp2_default.report_violation(""); }} | ||
|
||
#line 7 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
auto main() -> int{ | ||
using zero = std::integral_constant<cpp2::i32,0>; | ||
|
||
cpp2::impl::deferred_init<zero> z; | ||
init<zero>(cpp2::impl::out(&z)); | ||
if (cpp2::cpp2_default.is_active() && !(&id<zero>(z.value()) == &z.value()) ) { cpp2::cpp2_default.report_violation(""); } | ||
|
||
// Deducible parameters. | ||
static_cast<void>(v{ 0}); | ||
[]<typename T>([[maybe_unused]] std::vector<T> const& unnamed_param_1) -> void{}(std::vector<cpp2::i32>{}); | ||
[]<typename T>([[maybe_unused]] std::vector<std::vector<T>> const& unnamed_param_1) -> 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. | ||
[]<typename T, typename U>([[maybe_unused]] std::array<T,U::value> const& unnamed_param_1, [[maybe_unused]] U const& unnamed_param_2) -> void{}(std::array<cpp2::i32,0>{}, z.value()); | ||
init(cpp2::impl::out(&z.value()), z.value()); | ||
id(z.value(), cpp2::move(z.value())); | ||
{ | ||
auto f{[]<typename T>([[maybe_unused]] std::vector<std::type_identity_t<T>> const& unnamed_param_1) -> void{}}; | ||
|
||
// Test that these are emitted unwrapped in case they are deducible. | ||
|
||
#line 25 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
static_assert(!(std::is_invocable_v<decltype(cpp2::move(f)),std::vector<cpp2::i32>>), "`T` is non-deducible."); | ||
} | ||
{ | ||
auto f{[]<typename T>([[maybe_unused]] std::vector<std::vector<T>> const& unnamed_param_1) -> void{}}; | ||
|
||
#line 27 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
static_assert(std::is_invocable_v<decltype(cpp2::move(f)),std::vector<std::vector<cpp2::i32>>>, "`T` is deducible."); | ||
} | ||
#line 28 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
} | ||
|
||
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template <typename T> v<T>::v([[maybe_unused]] T const& unnamed_param_2){} | ||
#line 31 "pure2-bugfix-for-deducible-parameters.cpp2" | ||
template <typename T> auto v<T>::operator=([[maybe_unused]] T const& unnamed_param_2) -> v& { | ||
return *this; } | ||
|
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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
#define CPP2_IMPORT_STD Yes | ||
|
||
//=== Cpp2 type declarations ==================================================== | ||
|
||
|
||
#include "cpp2util.h" | ||
|
||
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2" | ||
|
||
|
||
//=== Cpp2 type definitions and function declarations =========================== | ||
|
||
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2" | ||
auto main() -> int; | ||
|
||
//=== Cpp2 function definitions ================================================= | ||
|
||
#line 1 "pure2-bugfix-for-dependent-types-recursion.cpp2" | ||
auto main() -> int{ | ||
#line 2 "pure2-bugfix-for-dependent-types-recursion.cpp2" | ||
using a = b; | ||
using b = a; | ||
static_cast<void>(a::t); | ||
static_cast<void>(b::t); | ||
} | ||
|
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) | ||
|
Uh oh!
There was an error while loading. Please reload this page.