@@ -698,88 +698,100 @@ foreach (string s, double d; aa)
698698
699699$(H3 $(LNAME2 foreach_over_struct_and_classes, Foreach over Structs and Classes with `opApply`))
700700
701-     $(P If the aggregate expression is a struct or class object,
702-         the  $(D foreach) is  defined by the
703-         special  $(LEGACY_LNAME2 opApply, op-apply, $(D opApply)) member function, and the
704-         `foreach_reverse` behavior is defined by the special 
701+     $(P If the aggregate expression is a ` struct`  or ` class`  object,
702+         iteration with  $(D foreach) can be  defined by implementing  the
703+         $(LEGACY_LNAME2 opApply, op-apply, $(D opApply)) member function, and the
704+         `foreach_reverse` behavior is defined by the
705705        $(LEGACY_LNAME2 opApplyReverse, op-apply-reverse, $(D opApplyReverse)) member function.
706706        These functions must each have the signature below:
707707    )
708708
709709$(GRAMMAR
710- $(GNAME OpApplyDeclaration):
711-     `int opApply` `(` `scope` `int delegate` `(` $(I OpApplyParameters) `)` `dg` `)` `;`
710+     `int opApply` `(` `scope` `int delegate` `(` $(I OpApplyParameters) `)` `body` `)` `;`
712711
713712$(GNAME OpApplyParameters):
714-     *OpApplyParameter* 
715-     *OpApplyParameter* , *OpApplyParameters*
713+     $(GLINK ParameterDeclaration) 
714+     $(GLINK ParameterDeclaration) , *OpApplyParameters*
716715
717716$(GNAME OpApplyParameter):
718-     $(GLINK ForeachTypeAttributes )$(OPT) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator)
717+     $(GLINK ParameterStorageClass )$(OPT) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator)
719718)
720719
721-     $(P where each $(I OpApplyParameter) of `dg` must match a $(GLINK ForeachType)
722-         in a $(GLINK ForeachStatement),
723-         otherwise the *ForeachStatement* will cause an error.)
724- 
725-     $(P Any *ForeachTypeAttribute* cannot be `enum`.)
726- 
727720    $(PANEL
728721    To support a `ref` iteration variable, the delegate must take a `ref` parameter:
729722
730723    $(SPEC_RUNNABLE_EXAMPLE_COMPILE
731724    ---
732725    struct S
733726    {
734-         int opApply(scope int delegate(ref uint n) dg);
727+         uint n;
728+         int opApply(scope int delegate(ref uint) body) => body(n);
735729    }
736-     void f(S s )
730+     void main( )
737731    {
732+ 		S s;
738733        foreach (ref uint i; s)
739-             i++;
734+         {
735+             i++; // effectively s.n++
736+         }
737+         foreach (i; s)
738+         {
739+             static assert(is(typeof(i) == uint));
740+             assert(i == 1);
741+         }
740742    }
741743    ---
742744    )
743-     Above, `opApply` is still matched when `i` is not `ref`, so by using
744-     a `ref` delegate parameter both forms are supported.
745-     )
745+     Above, `opApply` is matched both when `i` is and is not `ref`, so by using
746+     a `ref` delegate parameter, both forms are supported.
746747
747-     $(P There can be multiple $(D opApply) and $(D opApplyReverse) functions -
748-         one is selected
749-         by matching each parameter of `dg` to each $(I ForeachType)
750-         declared in the $(I ForeachStatement).)
748+     Stating the type of the variable like in the first loop is optional,
749+     as is showcased in the second loop, where the type is inferred.
750+     )
751751
752-     $(P The body of the apply
753-         function iterates over the elements it aggregates, passing each one
754-         in successive calls to the `dg` delegate. The delegate return value
755-         determines whether to interrupt iteration:)
752+     $(P The apply
753+         function iterates over the elements it aggregates by passing each one
754+         in successive calls to the `body` delegate. The delegate return value
755+         of the `body` delegate
756+         determines how to proceed iteration:)
756757
757758    $(UL
758-         $(LI If the result is nonzero, apply must cease
759+         $(LI If the result is nonzero, the  apply function  must cease
759760        iterating and return that value.)
760-         $(LI If the result is 0 , then iteration should continue.
761+         $(LI If the result is `0` , then iteration should continue.
761762        If there are no more elements to iterate,
762-         apply must return 0 .)
763+         the  apply function  must return `0` .)
763764    )
764765
765-     $(P The result of calling  the delegate will be nonzero if the *ForeachStatement*
766+     $(P The result of the `body`  delegate will be nonzero if the *ForeachStatement*
766767        body executes a matching $(GLINK BreakStatement), $(GLINK ReturnStatement), or
767768        $(GLINK GotoStatement) whose matching label is outside the *ForeachStatement*.
768769    )
769770
770-     $(P For example, consider a class that is a container for two elements:)
771+     $(P The $(D opApply) and $(D opApplyReverse) member functions can be overloaded.
772+         Selection works similar to overload resolution by
773+         comparing the number of `foreach` variables and number of parameters of `body` and,
774+         if more than one overload remains unique overload,
775+         matching the parameter types of `body` and each $(I ForeachType)
776+         declared in the $(I ForeachStatement) when given.)
777+ 
778+     $(BEST_PRACTICE Overload apply functions only with delegates differing in number of parameters
779+         to enable type inference for `foreach` variables.
780+     )
781+ 
782+     $(P For example, consider a class that is a container for some elements:)
771783
772784        $(SPEC_RUNNABLE_EXAMPLE_RUN
773785        --------------
774786        class Foo
775787        {
776788            uint[] array;
777789
778-             int opApply(scope int delegate(ref uint) dg )
790+             int opApply(scope int delegate(ref uint) body )
779791            {
780792                foreach (e; array)
781793                {
782-                     int result = dg (e);
794+                     int result = body (e);
783795                    if (result)
784796                        return result;
785797                }
@@ -811,57 +823,159 @@ $(CONSOLE
81182373
81282482
813825)
814-     $(PANEL
815-     The `scope` storage class on the $(D dg) parameter means that the delegate does
816-     not escape the scope of the $(D opApply) function (an example would be assigning $(D dg) to a
817-     global variable). If it cannot be statically guaranteed that $(D dg) does not escape, a closure may
818-     be allocated for it on the heap instead of the stack.
819826
820827    $(BEST_PRACTICE Annotate delegate parameters to `opApply` functions with `scope` when possible.)
828+ 
829+     $(PANEL
830+         The `scope` storage class on the `body` parameter means that the delegate does
831+         not escape the scope of the apply function (an example would be assigning`body` to a
832+         global variable). If it cannot be statically guaranteed that `body` does not escape, a closure may
833+         be allocated for it on the heap instead of the stack.
821834    )
822835
823-     $(P $(B Important:) If $(D opApply) catches  any exceptions, ensure that those
824-         exceptions did not originate from the delegate passed to $(D opApply) . The user would expect
836+     $(P $(B Important:) If apply functions catch  any exceptions, ensure that those
837+         exceptions did not originate from the delegate. The user would expect
825838        exceptions thrown from a `foreach` body to both terminate the loop, and propagate outside
826839        the `foreach` body.
827840     )
828841
829842$(H4 $(LNAME2 template-op-apply, Template `opApply`))
830843
831-     $(P $(D opApply) can also be a templated function,
832-         which will infer the types of parameters based on the $(I ForeachStatement).
833-         For example:)
844+     $(P `opApply` and `opApplyReverse` can also be a function templates,
845+         which can optionally infer the types of parameters based on the $(I ForeachStatement).
846+     )
847+ 
848+     $(P $(B Note:) An apply function template cannot infer `foreach` variable types.)
834849
835850        $(SPEC_RUNNABLE_EXAMPLE_RUN
836851        --------------
837852        struct S
838853        {
839-             import std.traits : ParameterTypeTuple;  // introspection template
840-             import std.stdio;
841- 
842-             int opApply(Dg)(scope Dg dg)
843-             if (ParameterTypeTuple!Dg.length == 2) // foreach with 2 parameters
854+             int opApply(Body)(scope Body body)
844855            {
845-                 writeln(2);
846-                 return 0;
847-             }
848- 
849-             int opApply(Dg)(scope Dg dg)
850-             if (ParameterTypeTuple!Dg.length == 3) // foreach with 3 parameters
851-             {
852-                 writeln(3);
856+                 pragma(msg, Body);
853857                return 0;
854858            }
855859        }
856860
857861        void main()
858862        {
859-             foreach (int a, int b; S()) { }  // calls first opApply function
860-             foreach (int a, int b, float c; S()) { }  // calls second opApply function
863+             foreach (int a, int b; S()) { } // int delegate(ref int, ref int) pure nothrow @nogc @safe
864+             foreach (bool b, string s; S()) { } // int delegate(ref bool, ref string) pure nothrow @nogc @safe
865+             foreach (x; S()) { } // Error: cannot infer type for `foreach` variable `x`, perhaps set it explicitly
861866        }
862867        --------------
863868        )
864869
870+ $(H4 $(LNAME2 template-instance-op-apply, `opApply` as an alias to a explicit function template instance))
871+ 
872+     $(P `opApply` and `opApplyReverse` can be aliases to an appropriate function or function template.
873+         However, special treatment is given to apply functions that are aliases of an appropriate function template instance.)
874+ 
875+     $(P In that case, the function template instance is used for overload selection and `foreach` variable type inference,
876+         but the template is instantiated again with the actual delegate type of the `foreach` body.
877+         This way, apply functions can infer attributes depending on the attributes of `body` delegate.)
878+ 
879+         $(SPEC_RUNNABLE_EXAMPLE_RUN
880+         --------------
881+         struct A
882+         {
883+             int opApply(scope int delegate(long) body) => body(42);
884+         }
885+         struct B
886+         {
887+             int opApply(Body)(scope Body body) => body(42);
888+         }
889+         struct C
890+         {
891+             int opApplyImpl(Body)(scope Body body) => body(42);
892+             alias opApply = opApplyImpl!(int delegate(long));
893+         }
894+         void main() @nogc nothrow pure @safe
895+         {
896+             // Error: `@nogc` function `D main` cannot call non-@nogc function `onlineapp.A.opApply`
897+             // Error: `pure` function `D main` cannot call impure function `onlineapp.A.opApply`
898+             // Error: `@safe` function `D main` cannot call `@system` function `onlineapp.A.opApply`
899+             // Error: function `onlineapp.A.opApply` is not `nothrow`
900+             static assert(!__traits(compiles, () @safe {
901+                 foreach (x; A()) { }
902+             }));
903+ 
904+             // Error: cannot infer type for `foreach` variable `x`, perhaps set it explicitly
905+             static assert(!__traits(compiles, {
906+                 foreach (x; B()) { }
907+             }));
908+ 
909+             // Good:
910+             foreach (x; C())
911+             {
912+                 static assert(is(typeof(x) == long));
913+                 assert(x == 42);
914+             }
915+         }
916+         --------------
917+         )
918+ 
919+     $(P The `opApplyImpl` pattern is generally preferable to
920+         overloading many apply functions with all possible combinations of attributes.)
921+ 
922+     $(P Multiple apply function aliases can exist, and selection and `foreach` variable type inference work:)
923+ 
924+     --------------
925+     class Tree(T)
926+     {
927+         private T label;
928+         private Tree[] children;
929+ 
930+         this(T label, Tree[] children = null)
931+         {
932+             this.label = label;
933+             this.children = children;
934+         }
935+ 
936+         alias opApply = opApplyImpl!(int delegate(ref T label));
937+         alias opApply = opApplyImpl!(int delegate(size_t depth, ref T label));
938+         alias opApply = opApplyImpl!(int delegate(size_t depth, bool isLastChild, ref T label));
939+ 
940+         int opApplyImpl(Body)(scope Body body) => opApplyImpl2(0, true, body);
941+         int opApplyImpl2(Body)(size_t depth, bool lastChild, scope Body body)
942+         {
943+             import std.meta : AliasSeq;
944+             static if (is(Body : int delegate(size_t, bool, ref T)))
945+                 alias args = AliasSeq!(depth, lastChild, label);
946+             else static if (is(Body : int delegate(size_t, ref T)))
947+                 alias args = AliasSeq!(depth, label);
948+             else
949+                 alias args = label;
950+             if (auto result = body(args)) return result;
951+             foreach (i, child; children)
952+             {
953+                 if (auto result = child.opApplyImpl2!Body(depth + 1, i + 1 == children.length, body))
954+                     return result;
955+             }
956+             return 0;
957+         }
958+     }
959+ 
960+     void printTree(Tree)(Tree tree)
961+     {
962+         // Selects the unique one with 2 parameters.
963+         // Infers types: size_t and whatever label type the tree has.
964+         foreach (depth, ref label; tree)
965+         {
966+             import std.stdio;
967+             foreach (_; 0 .. depth) write("  ");
968+             writeln(label);
969+         }
970+     }
971+ 
972+     void main() @safe
973+     {
974+         alias T = Tree!int;
975+         printTree(new T(0, [new T(1, [new T(2), new T(3)]), new T(4, [new T(5)])]));
976+     }
977+     --------------
978+ 
865979$(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Structs and Classes with Ranges))
866980
867981    $(P If the aggregate expression is a struct or class object, but the
@@ -1028,16 +1142,16 @@ $(H3 $(LNAME2 foreach_over_delegates, Foreach over Delegates))
10281142$(SPEC_RUNNABLE_EXAMPLE_RUN
10291143    --------------
10301144    // Custom loop implementation, that iterates over powers of 2 with
1031-     // alternating sign. The foreach loop body is passed in dg .
1032-     int myLoop(scope int delegate(int) dg )
1145+     // alternating sign. The foreach loop body is passed in `body` .
1146+     int myLoop(scope int delegate(int) body )
10331147    {
10341148        for (int z = 1; z < 128; z *= -2)
10351149        {
1036-             auto ret  = dg (z);
1150+             auto result  = body (z);
10371151
1038-             // If the loop body contains a break, ret  will be non-zero.
1039-             if (ret  != 0)
1040-                 return ret ;
1152+             // If the loop body contains a break, result  will be non-zero.
1153+             if (result  != 0)
1154+                 return result ;
10411155        }
10421156        return 0;
10431157    }
@@ -1583,7 +1697,7 @@ foreach (item; list)
15831697        $(P Any intervening $(RELATIVE_LINK2 try-statement, `finally`) clauses are executed,
15841698        and any intervening synchronization objects are released.)
15851699
1586-         $(P $(D  Note:) If a `finally` clause executes a `throw` out of the finally
1700+         $(P $(B  Note:) If a `finally` clause executes a `throw` out of the finally
15871701        clause, the continue target is never reached.)
15881702
15891703$(H2 $(LEGACY_LNAME2 BreakStatement, break-statement, Break Statement))
0 commit comments