From 1e73cb8ca716b0ad21c91c322d0a4935c060175c Mon Sep 17 00:00:00 2001 From: Geod24 Date: Tue, 28 Jul 2020 23:42:54 +0900 Subject: [PATCH] std.traits: Add support for 'in' storage class For a long time, the 'in' storage class was only a second class citizen, merely an alias for 'const', which is a type constructor. While it was also documented for a long time as being 'scope', this was removed when 'scope' actually started to have an effect (when DIP1000 started to be implemented). Currently, a switch (-preview=in) allows to get back this 'scope'. However, the 'in' storage class does not really exists, it gets lowered to 'const [scope]' at an early stage by the compiler, which means that we expose what is essentially an implementation detail to the user. There is a PR in DMD (dlang/dmd#11474) that aims to give 'in' an actual identity, instead of it being lowered to 'const [scope]'. The underlying motivation is to allow for extending 'in''s functionality, giving it the ability to pass by 'ref' when necessary, and accept rvalues. However, regardless of the second goal, having proper support for 'in' would lead to less confusing messages, better code generation, and less confusion w.r.t. the behavior of `std.traits.ParameterStorageClass`. --- std/traits.d | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/std/traits.d b/std/traits.d index bbc71ad33..1556f10b6 100644 --- a/std/traits.d +++ b/std/traits.d @@ -795,14 +795,17 @@ private template fqnType(T, string storageClassesString(uint psc)() @property { + import std.conv : text; + alias PSC = ParameterStorageClass; - return format("%s%s%s%s%s", + return text( psc & PSC.scope_ ? "scope " : "", psc & PSC.return_ ? "return " : "", + psc & PSC.in_ ? "in " : "", psc & PSC.out_ ? "out " : "", psc & PSC.ref_ ? "ref " : "", - psc & PSC.lazy_ ? "lazy " : "" + psc & PSC.lazy_ ? "lazy " : "", ); } @@ -1213,12 +1216,13 @@ enum ParameterStorageClass : uint * These flags can be bitwise OR-ed together to represent complex storage * class. */ - none = 0, - scope_ = 1, /// ditto - out_ = 2, /// ditto - ref_ = 4, /// ditto - lazy_ = 8, /// ditto - return_ = 0x10, /// ditto + none = 0x00, + in_ = 0x01, /// ditto + ref_ = 0x02, /// ditto + out_ = 0x04, /// ditto + lazy_ = 0x08, /// ditto + scope_ = 0x10, /// ditto + return_ = 0x20, /// ditto } /// ditto @@ -1254,14 +1258,22 @@ if (func.length == 1 && isCallable!func) { alias STC = ParameterStorageClass; // shorten the enum name - void func(ref int ctx, out real result, real param) + void func(ref int ctx, out real result, in real param, void* ptr) { } alias pstc = ParameterStorageClassTuple!func; - static assert(pstc.length == 3); // three parameters + static assert(pstc.length == 4); // number of parameters static assert(pstc[0] == STC.ref_); static assert(pstc[1] == STC.out_); - static assert(pstc[2] == STC.none); + version (none) + { + // TODO: When the DMD PR (dlang/dmd#11474) gets merged, + // remove the versioning and the second test + static assert(pstc[2] == STC.in_); + // This is the current behavior, before `in` is fixed to not be an alias + static assert(pstc[2] == STC.scope_); + } + static assert(pstc[3] == STC.none); } /** @@ -1285,6 +1297,7 @@ template extractParameterStorageClassFlags(Attribs...) final switch (attrib) with (ParameterStorageClass) { case "scope": result |= scope_; break; + case "in": result |= in_; break; case "out": result |= out_; break; case "ref": result |= ref_; break; case "lazy": result |= lazy_; break;