Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Improve default argument processing #1102

Merged
merged 6 commits into from 10 months ago

5 participants

Hara Kenji Andrei Alexandrescu Walter Bright Daniel Murphy Yazan Dabain
Hara Kenji
Collaborator

Discussion in forum:
http://forum.dlang.org/thread/mailman.1421.1346020012.31962.digitalmars-d@puremagic.com

Status improved:
Issue 3866 - anonymous delegate with default parameters cross-talks to another anonymous delegate
Fixed:
Issue 3646 - Default values of function arguments are ignored when instantiating a template.
Issue 8579 - Default parameter appears a part of typeof().stringof of a function variable


From commit log f5dc225:

Default args and arg identifiers are now volatile information in TypeFunction.

  1. The extra informations would be kept after semantic analysis for function pointer and delegate types. But merging type would strip all the extras from the type structure, then cache the stripped copy into.

  2. The types has extra informations cannot be named. In other words, AliasDeclaration would always strip the aliased type. This rule also works for TemplateTypeParameter, and fixes issue 3646 well.

  3. CondExp would strip them from the type of its result.

Andrei Alexandrescu
Owner

@WalterBright okay to merge?

Walter Bright
Owner

I'll pull once the merge conflicts are resolved.

Hara Kenji
Collaborator
9rnsr commented June 28, 2013

Ok, I rebased commits. Note that, currently this change would break test/compilable/cppmangle.d in linux platforms. I don't know C++ mangling well, so I couldn't understand the actual problem...

Walter Bright
Owner

Hmm, default args should not affect name mangling.

Daniel Murphy
Collaborator

@9rnsr Could you post the c++ mangling error you are seeing? I can't find it in the tester results.

Hara Kenji
Collaborator
9rnsr commented June 29, 2013

@yebblies http://d.puremagic.com/test-results/pull.ghtml?projectid=1&runid=652536

../src/dmd -m32 -Icompilable   -odtest_results/compilable -oftest_results/compilable/cppmangle_0.o -c compilable/cppmangle.d
compilable/cppmangle.d(261): Error: static assert  ("_Z10test10058fPFPvS_EPFS_S_E"c == "_Z10test10058fPFPvS_ES1_") is false
Daniel Murphy
Collaborator

Ok, in C++ mangling types that are repeated can be referenced later with numbers. It looks like this is no longer happening in this case. I assume it's because pointer equality is used for comparison and the extra copying is making the type seem different.

added some commits September 06, 2012
When we check two type objects equality, we should use Type::equals i…
…nstead of directly pointer comparison.
dd67c8c
Default args and arg identifiers are now volatile information in Type…
…Function.

1. The extra informations would be kept after semantic analysis for function pointer and delegate types. But merging type would strip all the extras from the type structure, then cache the stripped copy into.

2. The types has extra informations cannot be named. In other words, AliasDeclaration would always strip the aliased type. This rule also works for Template Type Parameter, and fixes issue 3646 well.

3. CondExp would strip them from the type of its result.
877e7bf
Improved fix for Issue 3866 - anonymous delegate with default paramet…
…ers cross-talks to another anonymous delegate

This reverts commit acc22ce,
and moves original test into runnable/functype.d
d736289
fix Issue 3646 - Default values of function arguments are ignored whe…
…n instantiating a template.
bce2d07
fix Issue 8579 - Default parameter appears a part of typeof().stringo…
…f of a function variable
864d5a3
Fix CppMangle issue
Use merge2() result for function argument types mangling.
8762713
Hara Kenji
Collaborator
9rnsr commented June 29, 2013

@yebblies Thanks for the tip! I was able to fix the issue.

Hara Kenji
Collaborator
9rnsr commented June 30, 2013

@WalterBright Now auto tester result is all green.

Daniel Murphy
Collaborator

Here goes...

Daniel Murphy yebblies merged commit a711eb6 into from July 04, 2013
Daniel Murphy yebblies closed this July 04, 2013
Andrei Alexandrescu
Owner

@9rnsr @yebblies is there work on fixing the regression? thanks.

Hara Kenji
Collaborator
9rnsr commented July 10, 2013

@andralex Yes. I fixed the regression in #2311, by changing little language semantic.

Andrei Alexandrescu
Owner

@9rnsr awesome, thanks!

Deleted user Unknown referenced this pull request from a commit December 24, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 6 unique commits by 1 author.

Jun 29, 2013
When we check two type objects equality, we should use Type::equals i…
…nstead of directly pointer comparison.
dd67c8c
Default args and arg identifiers are now volatile information in Type…
…Function.

1. The extra informations would be kept after semantic analysis for function pointer and delegate types. But merging type would strip all the extras from the type structure, then cache the stripped copy into.

2. The types has extra informations cannot be named. In other words, AliasDeclaration would always strip the aliased type. This rule also works for Template Type Parameter, and fixes issue 3646 well.

3. CondExp would strip them from the type of its result.
877e7bf
Improved fix for Issue 3866 - anonymous delegate with default paramet…
…ers cross-talks to another anonymous delegate

This reverts commit acc22ce,
and moves original test into runnable/functype.d
d736289
fix Issue 3646 - Default values of function arguments are ignored whe…
…n instantiating a template.
bce2d07
fix Issue 8579 - Default parameter appears a part of typeof().stringo…
…f of a function variable
864d5a3
Fix CppMangle issue
Use merge2() result for function argument types mangling.
8762713
This page is out of date. Refresh to see the latest.
2  src/cppmangle.c
@@ -428,7 +428,7 @@ static int argsCppMangleDg(void *ctx, size_t n, Parameter *arg)
428 428
 {
429 429
     ArgsCppMangleCtx *p = (ArgsCppMangleCtx *)ctx;
430 430
 
431  
-    Type *t = arg->type;
  431
+    Type *t = arg->type->merge2();
432 432
     if (arg->storageClass & (STCout | STCref))
433 433
         t = t->referenceTo();
434 434
     else if (arg->storageClass & STClazy)
6  src/ctfeexpr.c
@@ -366,7 +366,7 @@ Expression *copyLiteral(Expression *e)
366 366
  */
367 367
 Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
368 368
 {
369  
-    if (lit->type == type)
  369
+    if (lit->type->equals(type))
370 370
         return lit;
371 371
     Expression *e;
372 372
     if (lit->op == TOKslice)
@@ -1758,10 +1758,10 @@ void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef)
1758 1758
     assert( ae->type->ty == Tsarray || ae->type->ty == Tarray);
1759 1759
 #if DMDV2
1760 1760
     Type *desttype = ((TypeArray *)ae->type)->next->castMod(0);
1761  
-    bool directblk = (val->type->toBasetype()->castMod(0)) == desttype;
  1761
+    bool directblk = (val->type->toBasetype()->castMod(0))->equals(desttype);
1762 1762
 #else
1763 1763
     Type *desttype = ((TypeArray *)ae->type)->next;
1764  
-    bool directblk = (val->type->toBasetype()) == desttype;
  1764
+    bool directblk = (val->type->toBasetype())->equals(desttype);
1765 1765
 #endif
1766 1766
 
1767 1767
     bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral
7  src/declaration.c
@@ -562,6 +562,13 @@ void AliasDeclaration::semantic(Scope *sc)
562 562
     else if (t)
563 563
     {
564 564
         type = t->semantic(loc, sc);
  565
+
  566
+        /* TypeTuple might have extra info,
  567
+         *    is(typeof(func) PT == __parameters)
  568
+         * Otherwise, strip all redundant informations.
  569
+         */
  570
+        if (type->ty != Ttuple)
  571
+            type = type->merge2();
565 572
         //printf("\talias resolved to type %s\n", type->toChars());
566 573
     }
567 574
     if (overnext)
5  src/expression.c
@@ -1322,7 +1322,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
1322 1322
 
1323 1323
             if (!arg)
1324 1324
             {
1325  
-                if (!p->defaultArg || !fd)
  1325
+                if (!p->defaultArg)
1326 1326
                 {
1327 1327
                     if (tf->varargs == 2 && i + 1 == nparams)
1328 1328
                         goto L2;
@@ -1483,7 +1483,7 @@ Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
1483 1483
                     arg = arg->implicitCastTo(sc, p->type->substWildTo(wildmatch));
1484 1484
                     arg = arg->optimize(WANTvalue, p->storageClass & STCref);
1485 1485
                 }
1486  
-                else if (p->type != arg->type)
  1486
+                else if (!p->type->equals(arg->type))
1487 1487
                 {
1488 1488
                     //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
1489 1489
                     if (arg->op == TOKtype)
@@ -13056,6 +13056,7 @@ Expression *CondExp::semantic(Scope *sc)
13056 13056
             e2 = e2->castTo(sc, type);
13057 13057
         }
13058 13058
     }
  13059
+    type = type->merge2();
13059 13060
 #if 0
13060 13061
     printf("res: %s\n", type->toChars());
13061 13062
     printf("e1 : %s\n", e1->type->toChars());
6  src/func.c
@@ -1420,7 +1420,7 @@ void FuncDeclaration::semantic3(Scope *sc)
1420 1420
                     ::error(loc, "%s '%s' is nothrow yet may throw", kind(), toPrettyChars());
1421 1421
                 if (flags & FUNCFLAGnothrowInprocess)
1422 1422
                 {
1423  
-                    if (type == f) f = f->copy();
  1423
+                    if (type == f) f = (TypeFunction *)f->copy();
1424 1424
                     f->isnothrow = !(blockexit & BEthrow);
1425 1425
                 }
1426 1426
 
@@ -1755,14 +1755,14 @@ void FuncDeclaration::semantic3(Scope *sc)
1755 1755
     if (flags & FUNCFLAGpurityInprocess)
1756 1756
     {
1757 1757
         flags &= ~FUNCFLAGpurityInprocess;
1758  
-        if (type == f) f = f->copy();
  1758
+        if (type == f) f = (TypeFunction *)f->copy();
1759 1759
         f->purity = PUREfwdref;
1760 1760
     }
1761 1761
 
1762 1762
     if (flags & FUNCFLAGsafetyInprocess)
1763 1763
     {
1764 1764
         flags &= ~FUNCFLAGsafetyInprocess;
1765  
-        if (type == f) f = f->copy();
  1765
+        if (type == f) f = (TypeFunction *)f->copy();
1766 1766
         f->trust = TRUSTsafe;
1767 1767
     }
1768 1768
 
14  src/interpret.c
@@ -3042,9 +3042,9 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
3042 3042
         {
3043 3043
             desttype = ((TypeArray *)desttype)->next;
3044 3044
 #if DMDV2
3045  
-            if (srctype == desttype->castMod(0))
  3045
+            if (srctype->equals(desttype->castMod(0)))
3046 3046
 #else
3047  
-            if (srctype == desttype)
  3047
+            if (srctype->equals(desttype))
3048 3048
 #endif
3049 3049
             {
3050 3050
                 isBlockAssignment = true;
@@ -3064,7 +3064,7 @@ Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_
3064 3064
     bool wantRef = false;
3065 3065
     bool wantLvalueRef = false;
3066 3066
 
3067  
-    if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() &&
  3067
+    if (!fp && this->e1->type->toBasetype()->equals(this->e2->type->toBasetype()) &&
3068 3068
         (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type)
3069 3069
              || e1->type->toBasetype()->ty == Tclass)
3070 3070
          //  e = *x is never a reference, because *x is always a value
@@ -4089,10 +4089,10 @@ Expression *interpretAssignToSlice(InterState *istate, CtfeGoal goal, Loc loc,
4089 4089
                 existingAE->type->ty == Tarray);
4090 4090
 #if DMDV2
4091 4091
         Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0);
4092  
-        bool directblk = (e2->type->toBasetype()->castMod(0)) == desttype;
  4092
+        bool directblk = (e2->type->toBasetype()->castMod(0))->equals(desttype);
4093 4093
 #else
4094 4094
         Type *desttype = ((TypeArray *)existingAE->type)->next;
4095  
-        bool directblk = (e2->type->toBasetype()) == desttype;
  4095
+        bool directblk = (e2->type->toBasetype())->equals(desttype);
4096 4096
 #endif
4097 4097
         bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral
4098 4098
             || newval->op == TOKstring);
@@ -5268,7 +5268,7 @@ Expression *CastExp::interpret(InterState *istate, CtfeGoal goal)
5268 5268
             e->type = type;
5269 5269
             return e;
5270 5270
         }
5271  
-        if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type != e1->type)
  5271
+        if (e1->op == TOKindex && !((IndexExp *)e1)->e1->type->equals(e1->type))
5272 5272
         {   // type painting operation
5273 5273
             IndexExp *ie = (IndexExp *)e1;
5274 5274
             e = new IndexExp(e1->loc, ie->e1, ie->e2);
@@ -5661,7 +5661,7 @@ Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal)
5661 5661
                  * CastExp.
5662 5662
                  */
5663 5663
                 if (goal == ctfeNeedLvalue && e->op == TOKindex &&
5664  
-                    e->type == type &&
  5664
+                    e->type->equals(type) &&
5665 5665
                     isPointer(type) )
5666 5666
                     return e;
5667 5667
                 // ...Otherwise, just return the (simplified) dotvar expression
119  src/mtype.c
@@ -154,6 +154,13 @@ const char *Type::kind()
154 154
     return NULL;
155 155
 }
156 156
 
  157
+Type *Type::copy()
  158
+{
  159
+    Type *t = (Type *)mem.malloc(sizeTy[ty]);
  160
+    memcpy(t, this, sizeTy[ty]);
  161
+    return t;
  162
+}
  163
+
157 164
 Type *Type::syntaxCopy()
158 165
 {
159 166
     print();
@@ -1176,10 +1183,15 @@ Type *Type::pointerTo()
1176 1183
     if (ty == Terror)
1177 1184
         return this;
1178 1185
     if (!pto)
1179  
-    {   Type *t;
1180  
-
1181  
-        t = new TypePointer(this);
1182  
-        pto = t->merge();
  1186
+    {
  1187
+        Type *t = new TypePointer(this);
  1188
+        if (ty == Tfunction)
  1189
+        {
  1190
+            t->deco = t->merge()->deco;
  1191
+            pto = t;
  1192
+        }
  1193
+        else
  1194
+            pto = t->merge();
1183 1195
     }
1184 1196
     return pto;
1185 1197
 }
@@ -1597,6 +1609,85 @@ char *Type::modToChars()
1597 1609
 }
1598 1610
 
1599 1611
 /************************************
  1612
+ * Strip all parameter's idenfiers and their default arguments for merging types.
  1613
+ * If some of parameter types or return type are function pointer, delegate, or
  1614
+ * the types which contains either, then strip also from them.
  1615
+ */
  1616
+
  1617
+Type *stripDefaultArgs(Type *t)
  1618
+{
  1619
+  struct N
  1620
+  {
  1621
+    static Parameters *stripParams(Parameters *arguments)
  1622
+    {
  1623
+        Parameters *args = arguments;
  1624
+        if (args && args->dim > 0)
  1625
+        {
  1626
+            for (size_t i = 0; i < args->dim; i++)
  1627
+            {
  1628
+                Parameter *a = (*args)[i];
  1629
+                Type *ta = stripDefaultArgs(a->type);
  1630
+                if (ta != a->type || a->defaultArg || a->ident)
  1631
+                {
  1632
+                    if (args == arguments)
  1633
+                    {
  1634
+                        args = new Parameters();
  1635
+                        args->setDim(arguments->dim);
  1636
+                        for (size_t j = 0; j < args->dim; j++)
  1637
+                            (*args)[j] = (*arguments)[j];
  1638
+                    }
  1639
+                    (*args)[i] = new Parameter(a->storageClass, ta, NULL, NULL);
  1640
+                }
  1641
+            }
  1642
+        }
  1643
+        return args;
  1644
+    }
  1645
+  };
  1646
+
  1647
+    if (t == NULL)
  1648
+        return t;
  1649
+
  1650
+    if (t->ty == Tfunction)
  1651
+    {
  1652
+        TypeFunction *tf = (TypeFunction *)t;
  1653
+        Type *tret = stripDefaultArgs(tf->next);
  1654
+        Parameters *args = N::stripParams(tf->parameters);
  1655
+        if (tret == tf->next && args == tf->parameters)
  1656
+            goto Lnot;
  1657
+        tf = (TypeFunction *)tf->copy();
  1658
+        tf->parameters = args;
  1659
+        tf->next = tret;
  1660
+        //printf("strip %s\n   <- %s\n", tf->toChars(), t->toChars());
  1661
+        t = tf;
  1662
+    }
  1663
+    else if (t->ty == Ttuple)
  1664
+    {
  1665
+        TypeTuple *tt = (TypeTuple *)t;
  1666
+        Parameters *args = N::stripParams(tt->arguments);
  1667
+        if (args == tt->arguments)
  1668
+            goto Lnot;
  1669
+        t = new TypeTuple(args);
  1670
+    }
  1671
+    else if (t->ty == Tenum)
  1672
+    {
  1673
+        // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
  1674
+        goto Lnot;
  1675
+    }
  1676
+    else
  1677
+    {
  1678
+        Type *tn = t->nextOf();
  1679
+        Type *n = stripDefaultArgs(tn);
  1680
+        if (n == tn)
  1681
+            goto Lnot;
  1682
+        t = t->copy();
  1683
+        ((TypeNext *)t)->next = n;
  1684
+    }
  1685
+    //printf("strip %s\n", t->toChars());
  1686
+Lnot:
  1687
+    return t;
  1688
+}
  1689
+
  1690
+/************************************
1600 1691
  */
1601 1692
 
1602 1693
 Type *Type::merge()
@@ -1633,8 +1724,8 @@ Type *Type::merge()
1633 1724
         }
1634 1725
         else
1635 1726
         {
1636  
-            sv->ptrvalue = this;
1637  
-            deco = (char *)sv->toDchars();
  1727
+            sv->ptrvalue = (t = stripDefaultArgs(t));
  1728
+            deco = t->deco = (char *)sv->toDchars();
1638 1729
             //printf("new value, deco = '%s' %p\n", t->deco, t->deco);
1639 1730
         }
1640 1731
     }
@@ -4394,6 +4485,7 @@ Type *TypeAArray::semantic(Loc loc, Scope *sc)
4394 4485
     }
4395 4486
     else
4396 4487
         index = index->semantic(loc,sc);
  4488
+    index = index->merge2();
4397 4489
 
4398 4490
     if (index->nextOf() && !index->nextOf()->isImmutable())
4399 4491
     {
@@ -4420,7 +4512,7 @@ printf("index->ito->ito = x%x\n", index->ito->ito);
4420 4512
         case Terror:
4421 4513
             return Type::terror;
4422 4514
     }
4423  
-    next = next->semantic(loc,sc);
  4515
+    next = next->semantic(loc,sc)->merge2();
4424 4516
     transitive();
4425 4517
 
4426 4518
     switch (next->toBasetype()->ty)
@@ -4723,7 +4815,7 @@ Type *TypePointer::semantic(Loc loc, Scope *sc)
4723 4815
     {   transitive();
4724 4816
         return merge();
4725 4817
     }
4726  
-#if 1
  4818
+#if 0
4727 4819
     return merge();
4728 4820
 #else
4729 4821
     deco = merge()->deco;
@@ -4968,13 +5060,6 @@ const char *TypeFunction::kind()
4968 5060
     return "function";
4969 5061
 }
4970 5062
 
4971  
-TypeFunction *TypeFunction::copy()
4972  
-{
4973  
-    TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction));
4974  
-    memcpy(tf, this, sizeof(TypeFunction));
4975  
-    return tf;
4976  
-}
4977  
-
4978 5063
 Type *TypeFunction::syntaxCopy()
4979 5064
 {
4980 5065
     Type *treturn = next ? next->syntaxCopy() : NULL;
@@ -5406,7 +5491,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc)
5406 5491
      * This can produce redundant copies if inferring return type,
5407 5492
      * as semantic() will get called again on this.
5408 5493
      */
5409  
-    TypeFunction *tf = copy();
  5494
+    TypeFunction *tf = (TypeFunction *)copy();
5410 5495
     if (parameters)
5411 5496
     {   tf->parameters = (Parameters *)parameters->copy();
5412 5497
         for (size_t i = 0; i < parameters->dim; i++)
@@ -6123,7 +6208,7 @@ Type *TypeDelegate::semantic(Loc loc, Scope *sc)
6123 6208
      * be removed from next before the merge.
6124 6209
      */
6125 6210
 
6126  
-#if 1
  6211
+#if 0
6127 6212
     return merge();
6128 6213
 #else
6129 6214
     /* Don't return merge(), because arg identifiers and default args
2  src/mtype.h
@@ -228,6 +228,7 @@ class Type : public RootObject
228 228
 
229 229
     Type(TY ty);
230 230
     virtual const char *kind();
  231
+    Type *copy();
231 232
     virtual Type *syntaxCopy();
232 233
     bool equals(RootObject *o);
233 234
     int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType()
@@ -669,7 +670,6 @@ class TypeFunction : public TypeNext
669 670
 
670 671
     TypeFunction(Parameters *parameters, Type *treturn, int varargs, LINK linkage, StorageClass stc = 0);
671 672
     const char *kind();
672  
-    TypeFunction *copy();
673 673
     Type *syntaxCopy();
674 674
     Type *semantic(Loc loc, Scope *sc);
675 675
     void purityLevel();
10  test/fail_compilation/fail3866.d
... ...
@@ -1,10 +0,0 @@
1  
-
2  
-void main() {
3  
-
4  
-    auto foo = (int a = 1) { return a;};
5  
-    auto bar = (int a) { return a;};
6  
-
7  
-    foo();
8  
-    bar();
9  
-}
10  
-
263  test/runnable/functype.d
... ...
@@ -0,0 +1,263 @@
  1
+extern(C) int printf(const char*, ...);
  2
+
  3
+/***************************************************/
  4
+
  5
+void testfp()
  6
+{
  7
+    static int func1(int n = 1) { return n; }
  8
+    static int func2(int n    ) { return n; }
  9
+    static assert(typeof(func1).stringof == "int(int n = 1)");
  10
+    static assert(typeof(func2).stringof == "int(int n)");
  11
+    static assert( is(typeof(func1())));     // OK
  12
+    static assert(!is(typeof(func2())));     // NG
  13
+
  14
+    alias typeof(func1) Func1;
  15
+    alias typeof(func2) Func2;
  16
+    static assert(is(Func1 == Func2));
  17
+    static assert(Func1.stringof == "int(int)");            // removed defaultArgs
  18
+    static assert(Func2.stringof == "int(int)");
  19
+
  20
+    auto fp1 = &func1;
  21
+    auto fp2 = &func2;
  22
+    static assert(typeof(fp1).stringof == "int function(int n = 1)");
  23
+    static assert(typeof(fp2).stringof == "int function(int n)");
  24
+    static assert( is(typeof(fp1())));     // OK
  25
+    static assert(!is(typeof(fp2())));     // NG
  26
+
  27
+    alias typeof(fp1) Fp1;
  28
+    alias typeof(fp2) Fp2;
  29
+    static assert(is(Fp1 == Fp2));
  30
+    static assert(Fp1.stringof == "int function(int)");     // removed defaultArgs
  31
+    static assert(Fp2.stringof == "int function(int)");
  32
+
  33
+    typeof(fp1) fp3 = fp1;
  34
+    typeof(fp2) fp4 = fp2;
  35
+    static assert(is(typeof(fp3) == typeof(fp4)));
  36
+    static assert(typeof(fp3).stringof == "int function(int n = 1)");
  37
+    static assert(typeof(fp4).stringof == "int function(int n)");
  38
+    static assert( is(typeof(fp3())));     // OK
  39
+    static assert(!is(typeof(fp4())));     // NG
  40
+
  41
+    alias typeof(fp3) Fp3;
  42
+    alias typeof(fp4) Fp4;
  43
+    static assert(is(Fp3 == Fp4));
  44
+    static assert(Fp3.stringof == "int function(int)");     // removed defaultArgs
  45
+    static assert(Fp4.stringof == "int function(int)");
  46
+
  47
+    auto fplit1 = function(int n = 1) { return n; };
  48
+    auto fplit2 = function(int n    ) { return n; };
  49
+    static assert( is(typeof(fplit1())));   // OK
  50
+    static assert(!is(typeof(fplit2())));   // NG
  51
+}
  52
+
  53
+void testdg()
  54
+{
  55
+    int nest1(int n = 1) { return n; }
  56
+    int nest2(int n    ) { return n; }
  57
+    static assert(typeof(nest1).stringof == "int(int n = 1)");
  58
+    static assert(typeof(nest2).stringof == "int(int n)");
  59
+    static assert( is(typeof(nest1())));     // OK
  60
+    static assert(!is(typeof(nest2())));     // NG
  61
+
  62
+    alias typeof(nest1) Nest1;
  63
+    alias typeof(nest2) Nest2;
  64
+    static assert(is(Nest1 == Nest2));
  65
+    static assert(Nest1.stringof == "int(int)");            // removed defaultArgs
  66
+    static assert(Nest2.stringof == "int(int)");
  67
+
  68
+    auto dg1 = &nest1;
  69
+    auto dg2 = &nest2;
  70
+    static assert(typeof(dg1).stringof == "int delegate(int n = 1)");
  71
+    static assert(typeof(dg2).stringof == "int delegate(int n)");
  72
+    static assert( is(typeof(dg1())));     // OK
  73
+    static assert(!is(typeof(dg2())));     // NG
  74
+
  75
+    alias typeof(dg1) Dg1;
  76
+    alias typeof(dg2) Dg2;
  77
+    static assert(is(Dg1 == Dg2));
  78
+    static assert(Dg1.stringof == "int delegate(int)");     // removed defaultArgs
  79
+    static assert(Dg2.stringof == "int delegate(int)");
  80
+
  81
+    typeof(dg1) dg3 = dg1;
  82
+    typeof(dg2) dg4 = dg2;
  83
+    static assert(typeof(dg3).stringof == "int delegate(int n = 1)");
  84
+    static assert(typeof(dg4).stringof == "int delegate(int n)");
  85
+    static assert( is(typeof(dg3())));     // OK
  86
+    static assert(!is(typeof(dg4())));     // NG
  87
+
  88
+    alias typeof(dg3) Dg3;
  89
+    alias typeof(dg4) Dg4;
  90
+    static assert(is(Dg3 == Dg4));
  91
+    static assert(Dg3.stringof == "int delegate(int)");     // removed defaultArgs
  92
+    static assert(Dg4.stringof == "int delegate(int)");
  93
+
  94
+    auto dglit1 = delegate(int n = 1) { return n; };
  95
+    auto dglit2 = delegate(int n    ) { return n; };
  96
+    static assert( is(typeof(dglit1())));   // OK
  97
+    static assert(!is(typeof(dglit2())));   // NG
  98
+}
  99
+
  100
+void testda()
  101
+{
  102
+    // Unsupported cases with current implementation.
  103
+
  104
+    int function(int n = 1)[] fpda = [n => n + 1, n => n+2];
  105
+    assert(fpda[0](1) == 2);
  106
+    assert(fpda[1](1) == 3);
  107
+    static assert(!is(typeof(fpda[0]() == 1)));     // cannot call with using defArgs
  108
+    static assert(!is(typeof(fpda[1]() == 2)));     // cannot call with using defArgs
  109
+    static assert(typeof(fpda).stringof == "int function(int)[]");
  110
+    static assert(typeof(fpda).stringof != "int funciton(int n = 1)[]");
  111
+
  112
+    int delegate(int n = 1)[] dgda = [n => n + 1, n => n+2];
  113
+    assert(dgda[0](1) == 2);
  114
+    assert(dgda[1](1) == 3);
  115
+    static assert(!is(typeof(dgda[0]() == 1)));     // cannot call with using defArgs
  116
+    static assert(!is(typeof(dgda[1]() == 2)));     // cannot call with using defArgs
  117
+    static assert(typeof(dgda).stringof == "int delegate(int)[]");
  118
+    static assert(typeof(fpda).stringof != "int delegate(int n = 1)[]");
  119
+}
  120
+
  121
+template StringOf(T)
  122
+{
  123
+    // template type parameter cannot have redundant informations
  124
+    enum StringOf = T.stringof;
  125
+}
  126
+
  127
+void testti()
  128
+{
  129
+    int[] test(int[] a = []) { return a; }
  130
+    static assert(typeof(test).stringof == "int[](int[] a = [])");
  131
+    static assert(StringOf!(typeof(test)) == "int[](int[])");
  132
+
  133
+    float function(float x = 0F) fp = x => x;
  134
+    static assert(typeof(fp).stringof == "float function(float x = " ~ (0F).stringof ~ "F)");
  135
+    static assert(StringOf!(typeof(fp)) == "float function(float)");
  136
+
  137
+    double delegate(double x = 0.0) dg = x => x;
  138
+    static assert(typeof(dg).stringof == "double delegate(double x = " ~ (0.0).stringof ~ ")");
  139
+    static assert(StringOf!(typeof(dg)) == "double delegate(double)");
  140
+}
  141
+
  142
+void testxx()
  143
+{
  144
+    // The corner cases which I had introduced in forum discussion
  145
+
  146
+    // f will inherit default args from its initializer, if it's declared with 'auto'
  147
+    auto f1 = (int n = 10){ return 10; };
  148
+    assert(f1() == 10);
  149
+
  150
+    // what is the actual default arg of f?
  151
+    int function(int n = 10) f2 = (int n = 20){ return n; };
  152
+    int function(int n     ) f3 = (int n = 30){ return n; };
  153
+    int function(int n = 40) f4 = (int n     ){ return n; };
  154
+    assert(f2() == 10);
  155
+    static assert(!is(typeof(f3())));
  156
+    assert(f4() == 40);
  157
+
  158
+    // conditional expression and the type of its result
  159
+    auto f5 = true ? (int n = 10){ return n; }
  160
+                   : (int n = 20){ return n; } ;
  161
+    auto f6 = true ? (int n = 10, string s = "hello"){ return n; }
  162
+                   : (int n = 10, string s = "world"){ return n; } ;
  163
+    static assert(!is(typeof(f5())));   // cannot call
  164
+    static assert(!is(typeof(f6())));   // cannot call
  165
+
  166
+    int function(int n = 10) f7;    // default arg of the first parameter is 10
  167
+    f7 = (int n = 20){ return n; }; // function literal's default arg will be ignored
  168
+    assert(f7() == 10);
  169
+
  170
+    // returning function pointer/delegate type can have default args
  171
+    int delegate(int n = 10) foo(int x) { return n => n + x; }
  172
+    auto f = foo(1);
  173
+    assert(f() == 11);
  174
+}
  175
+
  176
+/***************************************************/
  177
+// 3646
  178
+
  179
+int bar3646(int x = 10) { printf("bar %d\n", x); return x; }
  180
+int bam3646(int y)      { printf("bam %d\n", y); return y; }
  181
+
  182
+int qux3646()      { printf("quux\n");       return 20; }
  183
+int qux3646(int i) { printf("quux %d\n", i); return 30; }
  184
+
  185
+void foo3646a(Fn)(Fn fn)
  186
+{
  187
+    fn();
  188
+}
  189
+
  190
+void foo3646b(alias fn)(int res1, int res2)
  191
+{
  192
+    assert(fn() == res1);
  193
+    assert(fn(42) == res2);
  194
+}
  195
+
  196
+void test3646()
  197
+{
  198
+    static assert(!is(typeof(foo3646(&bar3646))));
  199
+    static assert(!is(typeof(foo3646(&bam3646))));
  200
+    static assert(typeof(&bar3646).stringof == "int function(int x = 10)");
  201
+    static assert(typeof(&bam3646).stringof == "int function(int y)");
  202
+
  203
+    foo3646b!bar3646(10, 42);
  204
+    static assert(!is(typeof(foo3646b!bam3646(0, 0))));
  205
+    foo3646b!qux3646(20, 30);
  206
+}
  207
+
  208
+/***************************************************/
  209
+// 3866
  210
+
  211
+void test3866()
  212
+{
  213
+
  214
+    auto foo = (int a = 1) { return a; };
  215
+    auto bar = (int a) { return a; };
  216
+
  217
+    assert(foo() == 1);
  218
+    static assert(!is(typeof(bar())));
  219
+    assert(foo(2) == 2);
  220
+    assert(bar(3) == 3);
  221
+}
  222
+
  223
+/***************************************************/
  224
+// 8579
  225
+
  226
+void test8579()
  227
+{
  228
+    static void func1(int i, double j = 1.0) {}
  229
+    static void func2(int x, double y) {}
  230
+    auto fn1 = &func1;
  231
+    auto fn2 = &func2;
  232
+    static assert(is(typeof(fn1) == typeof(fn2)));
  233
+           assert(   typeid(fn1) is typeid(fn2) );
  234
+    static assert(typeof(fn1).stringof == "void function(int i, double j = " ~ (1.0).stringof ~ ")");
  235
+    static assert(typeof(fn2).stringof == "void function(int x, double y)");
  236
+
  237
+    static int func3(int x, double y) { return 0; }
  238
+    static int func4(int i, double j = 1.0) { return 0; }
  239
+    auto fn3 = &func3;
  240
+    auto fn4 = &func4;
  241
+    static assert(is(typeof(fn3) == typeof(fn4)));
  242
+           assert(   typeid(fn3) is typeid(fn4) );
  243
+    static assert(typeof(fn3).stringof == "int function(int x, double y)");
  244
+    static assert(typeof(fn4).stringof == "int function(int i, double j = " ~ (1.0).stringof ~ ")");
  245
+}
  246
+
  247
+/***************************************************/
  248
+
  249
+int main()
  250
+{
  251
+    testfp();
  252
+    testdg();
  253
+    testda();
  254
+    testti();
  255
+    testxx();
  256
+    test3646();
  257
+    test3866();
  258
+    test8579();
  259
+
  260
+    printf("Success\n");
  261
+    return 0;
  262
+}
  263
+
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.