Thread overview
[Issue 24516] qualifiers lost when tupleof is aliased
May 01
basile-z
May 02
basile-z
May 01
https://issues.dlang.org/show_bug.cgi?id=24516

Nick Treleaven <nick@geany.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |nick@geany.org

--- Comment #1 from Nick Treleaven <nick@geany.org> ---
> S.tupleof

I don't think it makes sense to allow `tupleof` to be a type property. It should be instance only. The spec does not mention its use on a type. https://dlang.org/spec/class.html#tupleof

Also in dmd/typesem.d, dotExp:
```d
        else if (ident == Id._tupleof)
        {
            if (e.isTypeExp())
            {
                error(e.loc, "`.tupleof` cannot be used on type `%s`",
mt.toChars);
                return ErrorExp.get();
            }
```
For some reason that is not being triggered.

--
May 01
https://issues.dlang.org/show_bug.cgi?id=24516

--- Comment #2 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
(In reply to Nick Treleaven from comment #1)
> > S.tupleof
> 
> I don't think it makes sense to allow `tupleof` to be a type property. It should be instance only. The spec does not mention its use on a type. https://dlang.org/spec/class.html#tupleof

The spec uses tupleof on a type right there in the example that you're linking to even before it uses it on a variable:

---
class Foo { int x; long y; }

static assert(__traits(identifier, Foo.tupleof[0]) == "x");
static assert(is(typeof(Foo.tupleof)[1] == long));
---

And both druntime and Phobos having been using tupleof on types for years - e.g. std.traits.Fields. It would break a lot of existing code if tupleof stopped working on types.

Also, in most cases, it's less error-prone to do type introspection on types rather than values or symbols. Some kinds of type introspection have to be done on values or symbols, but pretty much any time that a trait takes an alias rather than a type, it makes it far trickier to write it correctly, and corner cases are frequently a problem. If anything, the fact that type qualifers are being lost when aliasing the result of tupleof is an example of why aliasing symbols when doing type introspection (as opposed to aliasing types) tends to be error-prone. We unfortunately have variety of bugs where weird stuff happens like type qualifiers disappearing when operating on symbols rather than on types, and it's why some of the traits in std.traits are overloaded so that they can explicitly take types or use an alias parameter.

Using tupleof on an instance has some uses, since then you can do stuff like

---
foo.tupleof[0] = 1;
---

but when doing type introspection, it makes far more sense to be operating on the type, and tupleof has worked that way for many years.

The problem in this bug report is that for some reason, aliasing the result of tupleof results in symbols that behave differently from the direct result of tupleof, and the qualifiers are lost. I see no reason why it should be reasonable for that to happen.

--
May 01
https://issues.dlang.org/show_bug.cgi?id=24516

--- Comment #3 from basile-z <b2.temp@gmx.com> ---
(In reply to Nick Treleaven from comment #1)
> > S.tupleof
> 
> I don't think it makes sense to allow `tupleof` to be a type property. It should be instance only. The spec does not mention its use on a type. https://dlang.org/spec/class.html#tupleof
> 
> Also in dmd/typesem.d, dotExp:
> ```d
>         else if (ident == Id._tupleof)
>         {
>             if (e.isTypeExp())
>             {
>                 error(e.loc, "`.tupleof` cannot be used on type `%s`",
> mt.toChars);
>                 return ErrorExp.get();
>             }
> ```
> For some reason that is not being triggered.

The reason must be that `S` in `S.tupleof` is not a TypeExp it's a DeclExp.

--
May 02
https://issues.dlang.org/show_bug.cgi?id=24516

--- Comment #4 from Nick Treleaven <nick@geany.org> ---
> The reason must be that `S` in `S.tupleof` is not a TypeExp it's a DeclExp.

No, the quoted code is for static array tupleof. I tried adding it for classes and structs but dotExp seems to have a phantom expression e which is a VarExp.

--
May 02
https://issues.dlang.org/show_bug.cgi?id=24516

--- Comment #5 from Nick Treleaven <nick@geany.org> ---
> The spec uses tupleof on a type right there in the example

Sorry, yes. We shouldn't break code then.

--
May 02
https://issues.dlang.org/show_bug.cgi?id=24516

basile-z <b2.temp@gmx.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |b2.temp@gmx.com

--- Comment #6 from basile-z <b2.temp@gmx.com> ---
(In reply to Nick Treleaven from comment #4)
> > The reason must be that `S` in `S.tupleof` is not a TypeExp it's a DeclExp.
> 
> No, the quoted code is for static array tupleof.
I see, the compiler code you quoted is not for `S.tupleof`

> I tried adding it for
> classes and structs but dotExp seems to have a phantom expression e which is a VarExp.
I'm not sure if that helps but, as you might already know ?, the D front-end rewrites the DotExp lhs to what it resolves to e.g either a VarExp, a TypeExp, a DeclExp, etc. If it's not that then maybe that VarExp is used to extract a side-effects or to create a lvalue. but I dont see why this would be done on a type, that would be a bug.

--