kubo39's blog

ただの雑記です。

小ネタ: D言語はいかなる型もタプル型へのキャストはできない

いかなる型であってもできない。これはタプル型そのものの値であっても例外ではない。

void main()
{
    alias tuple(A...) = A;
    tuple!int tup;
    cast(tuple!int) tup;
}
(dmd-2.098.1)$ dmd -c cast.d
cast.d(5): Error: cannot cast `__tup_field_0` to tuple type `(int)`

これは2022/01/05時点では仕様には記載されていない。 ちゃんと追ってはいないものの、ざっくりcommit追った感じではずっと前からこの仕様であったらしい。

あと構造体へのキャストを行う場合、 cast(S) xS(x) への書き換えが行われるので以下のコードは合法。

struct S
{
    this(int _) {}
}

void main()
{
    S s = cast() 42;
}
(dmd-2.098.1)$ dmd -c cast2.d
(dmd-2.098.1)$ # no compilation error

こちらはドキュメントにひっそりと書いている。

dlang.org

  1. Casting a value v to a struct S, when value is not a struct of the same type, is equivalent to:

S(v)

追記

以下のようなパッチを当てれば同じタプル型についてはキャストできる。

index 1e5f8b37e..ee54a6a83 100644
--- a/src/dmd/expressionsem.d
+++ b/src/dmd/expressionsem.d
@@ -7512,6 +7512,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (exp.e1.type.ty == Ttuple)
         {
             TupleExp te = exp.e1.isTupleExp();
+            if (exp.to)
+            {
+                if (TypeTuple tt = exp.to.isTypeTuple())
+                {
+                    if (exp.e1.type.equals(tt))
+                    {
+                        result = exp.e1;
+                        return;
+                    }
+                }
+            }
             if (te.exps.dim == 1)
                 exp.e1 = (*te.exps)[0];
         }

あてたDMDのgit revisionもいちおう。

$ git rev-parse HEAD
b14861d42ce3da9cf789988621c46dba1102ee0c
(dmd-2.098.1)$ ./dmd/generated/linux/release/64/dmd -c cast.d
(dmd-2.098.1)$ # no compileation error

違う型だとエラーになる。

alias tuple(T...) = T;
alias mytuple = tuple!(int, int);

void main()
{
    mytuple tup;
    auto tt = cast(tuple!(int, string)) tup;
}
(dmd-2.098.1)$ ./dmd/generated/linux/release/64/dmd -c invalid.d
invalid.d(7): Error: cannot cast `tuple(__tup_field_0, __tup_field_1)` to tuple type `(int, string)`

追記2

github.com

パッチ入りました、2.100から使えるはず。