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`.
This commit is contained in:
Geod24 2020-07-28 23:42:54 +09:00
parent c216486512
commit 1e73cb8ca7

View file

@ -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;