1 /**
2  * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`.
3  *
4  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d)
8  * Documentation:  https://dlang.org/phobos/dmd_init.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/init.d
10  */
11 
12 module dmd.init;
13 
14 import core.stdc.stdio;
15 import core.checkedint;
16 
17 import dmd.arraytypes;
18 import dmd.astenums;
19 import dmd.ast_node;
20 import dmd.dsymbol;
21 import dmd.expression;
22 import dmd.globals;
23 import dmd.hdrgen;
24 import dmd.identifier;
25 import dmd.location;
26 import dmd.mtype;
27 import dmd.common.outbuffer;
28 import dmd.rootobject;
29 import dmd.tokens;
30 import dmd.visitor;
31 
32 enum NeedInterpret : int
33 {
34     INITnointerpret,
35     INITinterpret,
36 }
37 
38 alias INITnointerpret = NeedInterpret.INITnointerpret;
39 alias INITinterpret = NeedInterpret.INITinterpret;
40 
41 /***********************************************************
42  */
43 extern (C++) class Initializer : ASTNode
44 {
45     Loc loc;
46     InitKind kind;
47 
48     override DYNCAST dyncast() const
49     {
50         return DYNCAST.initializer;
51     }
52 
53 
54     extern (D) this(const ref Loc loc, InitKind kind) @safe
55     {
56         this.loc = loc;
57         this.kind = kind;
58     }
59 
60     final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure
61     {
62         // Use void* cast to skip dynamic casting call
63         return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null;
64     }
65 
66     final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure
67     {
68         return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
69     }
70 
71     final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
72     {
73         return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
74     }
75 
76     final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure
77     {
78         return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null;
79     }
80 
81     final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure
82     {
83         return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null;
84     }
85 
86     final inout(CInitializer) isCInitializer() inout @nogc nothrow pure
87     {
88         return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null;
89     }
90 
91     override void accept(Visitor v)
92     {
93         v.visit(this);
94     }
95 }
96 
97 /***********************************************************
98  */
99 extern (C++) final class VoidInitializer : Initializer
100 {
101     Type type;      // type that this will initialize to
102 
103     extern (D) this(const ref Loc loc) @safe
104     {
105         super(loc, InitKind.void_);
106     }
107 
108     override void accept(Visitor v)
109     {
110         v.visit(this);
111     }
112 }
113 
114 /***********************************************************
115  */
116 extern (C++) final class ErrorInitializer : Initializer
117 {
118     extern (D) this() @safe
119     {
120         super(Loc.initial, InitKind.error);
121     }
122 
123     override void accept(Visitor v)
124     {
125         v.visit(this);
126     }
127 }
128 
129 /***********************************************************
130  */
131 extern (C++) final class StructInitializer : Initializer
132 {
133     Identifiers field;      // of Identifier *'s
134     Initializers value;     // parallel array of Initializer *'s
135 
136     extern (D) this(const ref Loc loc)
137     {
138         super(loc, InitKind.struct_);
139     }
140 
141     extern (D) void addInit(Identifier field, Initializer value)
142     {
143         //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
144         this.field.push(field);
145         this.value.push(value);
146     }
147 
148     override void accept(Visitor v)
149     {
150         v.visit(this);
151     }
152 }
153 
154 /***********************************************************
155  */
156 extern (C++) final class ArrayInitializer : Initializer
157 {
158     Expressions index;      // indices
159     Initializers value;     // of Initializer *'s
160     uint dim;               // length of array being initialized
161     Type type;              // type that array will be used to initialize
162     bool sem;               // true if semantic() is run
163     bool isCarray;          // C array semantics
164 
165     extern (D) this(const ref Loc loc)
166     {
167         super(loc, InitKind.array);
168     }
169 
170     extern (D) void addInit(Expression index, Initializer value)
171     {
172         this.index.push(index);
173         this.value.push(value);
174         dim = 0;
175         type = null;
176     }
177 
178     bool isAssociativeArray() const pure
179     {
180         foreach (idx; index)
181         {
182             if (idx)
183                 return true;
184         }
185         return false;
186     }
187 
188     override void accept(Visitor v)
189     {
190         v.visit(this);
191     }
192 }
193 
194 /***********************************************************
195  */
196 extern (C++) final class ExpInitializer : Initializer
197 {
198     bool expandTuples;
199     Expression exp;
200 
201     extern (D) this(const ref Loc loc, Expression exp) @safe
202     {
203         super(loc, InitKind.exp);
204         this.exp = exp;
205     }
206 
207     override void accept(Visitor v)
208     {
209         v.visit(this);
210     }
211 }
212 
213 /*********************************************
214  * Holds the `designator` for C initializers
215  */
216 struct Designator
217 {
218     Expression exp;     /// [ constant-expression ]
219     Identifier ident;   /// . identifier
220 
221     this(Expression exp) @safe { this.exp = exp; }
222     this(Identifier ident) @safe  { this.ident = ident; }
223 }
224 
225 /*********************************************
226  * Holds the `designation (opt) initializer` for C initializers
227  */
228 struct DesigInit
229 {
230     Designators* designatorList; /// designation (opt)
231     Initializer initializer;     /// initializer
232 }
233 
234 /********************************
235  * C11 6.7.9 Initialization
236  * Represents the C initializer-list
237  */
238 extern (C++) final class CInitializer : Initializer
239 {
240     DesigInits initializerList; /// initializer-list
241     Type type;              /// type that array will be used to initialize
242     bool sem;               /// true if semantic() is run
243 
244     extern (D) this(const ref Loc loc)
245     {
246         super(loc, InitKind.C_);
247     }
248 
249     override void accept(Visitor v)
250     {
251         v.visit(this);
252     }
253 }
254 
255 /****************************************
256  * Copy the AST for Initializer.
257  * Params:
258  *      inx = Initializer AST to copy
259  * Returns:
260  *      the copy
261  */
262 Initializer syntaxCopy(Initializer inx)
263 {
264     static Initializer visitVoid(VoidInitializer vi)
265     {
266         return new VoidInitializer(vi.loc);
267     }
268 
269     static Initializer visitError(ErrorInitializer vi)
270     {
271         return vi;
272     }
273 
274     static Initializer visitExp(ExpInitializer vi)
275     {
276         return new ExpInitializer(vi.loc, vi.exp.syntaxCopy());
277     }
278 
279     static Initializer visitStruct(StructInitializer vi)
280     {
281         auto si = new StructInitializer(vi.loc);
282         assert(vi.field.length == vi.value.length);
283         si.field.setDim(vi.field.length);
284         si.value.setDim(vi.value.length);
285         foreach (const i; 0 .. vi.field.length)
286         {
287             si.field[i] = vi.field[i];
288             si.value[i] = vi.value[i].syntaxCopy();
289         }
290         return si;
291     }
292 
293     static Initializer visitArray(ArrayInitializer vi)
294     {
295         auto ai = new ArrayInitializer(vi.loc);
296         assert(vi.index.length == vi.value.length);
297         ai.index.setDim(vi.index.length);
298         ai.value.setDim(vi.value.length);
299         foreach (const i; 0 .. vi.value.length)
300         {
301             ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null;
302             ai.value[i] = vi.value[i].syntaxCopy();
303         }
304         return ai;
305     }
306 
307     static Initializer visitC(CInitializer vi)
308     {
309         auto ci = new CInitializer(vi.loc);
310         ci.initializerList.setDim(vi.initializerList.length);
311         foreach (const i; 0 .. vi.initializerList.length)
312         {
313             DesigInit* cdi = &ci.initializerList[i];
314             DesigInit* vdi = &ci.initializerList[i];
315             cdi.initializer = vdi.initializer.syntaxCopy();
316             if (vdi.designatorList)
317             {
318                 cdi.designatorList = new Designators();
319                 cdi.designatorList.setDim(vdi.designatorList.length);
320                 foreach (const j; 0 .. vdi.designatorList.length)
321                 {
322                     Designator* cdid = &(*cdi.designatorList)[j];
323                     Designator* vdid = &(*vdi.designatorList)[j];
324                     cdid.exp = vdid.exp ? vdid.exp.syntaxCopy() : null;
325                     cdid.ident = vdid.ident;
326                 }
327             }
328         }
329         return ci;
330     }
331 
332     mixin VisitInitializer!Initializer visit;
333     return visit.VisitInitializer(inx);
334 }
335 
336 /***********************************************************
337  * Visit each Initializer in init. Call a function visit%s(init) for
338  * each node, where %s is the op of the node. Otherwise call visitDefault(init)
339  * for that node. If the visit function returns R.init, continue
340  * visiting each node, otherwise return the value of R.
341  * Params:
342  *      Result = return type
343  *      init = Initializer tree to traverse
344  * Returns:
345  *      Result.init for continue, value of type Result for early exit
346  */
347 
348 mixin template VisitInitializer(Result)
349 {
350     Result VisitInitializer(Initializer init)
351     {
352         final switch (init.kind)
353         {
354             case InitKind.void_:    mixin(visitCase("Void"));    break;
355             case InitKind.error:    mixin(visitCase("Error"));   break;
356             case InitKind.struct_:  mixin(visitCase("Struct"));  break;
357             case InitKind.array:    mixin(visitCase("Array"));   break;
358             case InitKind.exp:      mixin(visitCase("Exp"));     break;
359             case InitKind.C_:       mixin(visitCase("C"));       break;
360         }
361         static if (is(Result == void)) { } else
362             return Result.init;
363     }
364 }
365 
366 /****************************************
367  * CTFE-only helper function for VisitInitializer.
368  * Params:
369  *      handler = string for the name of the visit handler
370  * Returns: boilerplate code for a case
371  */
372 string visitCase(string handler) pure @safe
373 {
374     if (__ctfe)
375     {
376         return
377             "
378             auto ix = init.is"~handler~"Initializer();
379             static if (is(Result == void))
380                 visit"~handler~"(ix);
381             else
382             {
383                 Result r = visit"~handler~"(ix);
384                 if (r !is Result.init)
385                     return r;
386             }
387             ";
388     }
389     assert(0);
390 }