1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _dsymbol.d)
9  */
10 
11 module ddmd.dsymbol;
12 
13 import core.stdc.stdarg;
14 import core.stdc.stdio;
15 import core.stdc..string;
16 import core.stdc.stdlib;
17 
18 import ddmd.aggregate;
19 import ddmd.aliasthis;
20 import ddmd.arraytypes;
21 import ddmd.attrib;
22 import ddmd.gluelayer;
23 import ddmd.dclass;
24 import ddmd.declaration;
25 import ddmd.denum;
26 import ddmd.dimport;
27 import ddmd.dmodule;
28 import ddmd.dscope;
29 import ddmd.dstruct;
30 import ddmd.dtemplate;
31 import ddmd.errors;
32 import ddmd.expression;
33 import ddmd.func;
34 import ddmd.globals;
35 import ddmd.id;
36 import ddmd.identifier;
37 import ddmd.init;
38 import ddmd.lexer;
39 import ddmd.mtype;
40 import ddmd.nspace;
41 import ddmd.opover;
42 import ddmd.root.aav;
43 import ddmd.root.rmem;
44 import ddmd.root.rootobject;
45 import ddmd.root.speller;
46 import ddmd.statement;
47 import ddmd.tokens;
48 import ddmd.visitor;
49 
50 struct Ungag
51 {
52     uint oldgag;
53 
54     extern (D) this(uint old)
55     {
56         this.oldgag = old;
57     }
58 
59     extern (C++) ~this()
60     {
61         global.gag = oldgag;
62     }
63 }
64 
65 enum PROTKIND : int
66 {
67     PROTundefined,
68     PROTnone,           // no access
69     PROTprivate,
70     PROTpackage,
71     PROTprotected,
72     PROTpublic,
73     PROTexport,
74 }
75 
76 alias PROTundefined = PROTKIND.PROTundefined;
77 alias PROTnone = PROTKIND.PROTnone;
78 alias PROTprivate = PROTKIND.PROTprivate;
79 alias PROTpackage = PROTKIND.PROTpackage;
80 alias PROTprotected = PROTKIND.PROTprotected;
81 alias PROTpublic = PROTKIND.PROTpublic;
82 alias PROTexport = PROTKIND.PROTexport;
83 
84 struct Prot
85 {
86     PROTKIND kind;
87     Package pkg;
88 
89     extern (D) this(PROTKIND kind)
90     {
91         this.kind = kind;
92     }
93 
94     extern (C++):
95 
96     /**
97      * Checks if `this` is superset of `other` restrictions.
98      * For example, "protected" is more restrictive than "public".
99      */
100     bool isMoreRestrictiveThan(const Prot other) const
101     {
102         return this.kind < other.kind;
103     }
104 
105     /**
106      * Checks if `this` is absolutely identical protection attribute to `other`
107      */
108     bool opEquals(ref const Prot other) const
109     {
110         if (this.kind == other.kind)
111         {
112             if (this.kind == PROTpackage)
113                 return this.pkg == other.pkg;
114             return true;
115         }
116         return false;
117     }
118 
119     /**
120      * Checks if parent defines different access restrictions than this one.
121      *
122      * Params:
123      *  parent = protection attribute for scope that hosts this one
124      *
125      * Returns:
126      *  'true' if parent is already more restrictive than this one and thus
127      *  no differentiation is needed.
128      */
129     bool isSubsetOf(ref const Prot parent) const
130     {
131         if (this.kind != parent.kind)
132             return false;
133         if (this.kind == PROTpackage)
134         {
135             if (!this.pkg)
136                 return true;
137             if (!parent.pkg)
138                 return false;
139             if (parent.pkg.isAncestorPackageOf(this.pkg))
140                 return true;
141         }
142         return true;
143     }
144 }
145 
146 enum PASS : int
147 {
148     PASSinit,           // initial state
149     PASSsemantic,       // semantic() started
150     PASSsemanticdone,   // semantic() done
151     PASSsemantic2,      // semantic2() started
152     PASSsemantic2done,  // semantic2() done
153     PASSsemantic3,      // semantic3() started
154     PASSsemantic3done,  // semantic3() done
155     PASSinline,         // inline started
156     PASSinlinedone,     // inline done
157     PASSobj,            // toObjFile() run
158 }
159 
160 alias PASSinit = PASS.PASSinit;
161 alias PASSsemantic = PASS.PASSsemantic;
162 alias PASSsemanticdone = PASS.PASSsemanticdone;
163 alias PASSsemantic2 = PASS.PASSsemantic2;
164 alias PASSsemantic2done = PASS.PASSsemantic2done;
165 alias PASSsemantic3 = PASS.PASSsemantic3;
166 alias PASSsemantic3done = PASS.PASSsemantic3done;
167 alias PASSinline = PASS.PASSinline;
168 alias PASSinlinedone = PASS.PASSinlinedone;
169 alias PASSobj = PASS.PASSobj;
170 
171 // Search options
172 enum : int
173 {
174     IgnoreNone              = 0x00, // default
175     IgnorePrivateImports    = 0x01, // don't search private imports
176     IgnoreErrors            = 0x02, // don't give error messages
177     IgnoreAmbiguous         = 0x04, // return NULL if ambiguous
178     SearchLocalsOnly        = 0x08, // only look at locals (don't search imports)
179     SearchImportsOnly       = 0x10, // only look in imports
180     SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
181                                     // meaning don't search imports in that scope,
182                                     // because qualified module searches search
183                                     // their imports
184     IgnoreSymbolVisibility  = 0x80, // also find private and package protected symbols
185 }
186 
187 extern (C++) alias Dsymbol_apply_ft_t = int function(Dsymbol, void*);
188 
189 /***********************************************************
190  */
191 extern (C++) class Dsymbol : RootObject
192 {
193     Identifier ident;
194     Dsymbol parent;
195     Symbol* csym;           // symbol for code generator
196     Symbol* isym;           // import version of csym
197     const(char)* comment;   // documentation comment for this Dsymbol
198     Loc loc;                // where defined
199     Scope* _scope;          // !=null means context to use for semantic()
200     const(char)* prettystring;  // cached value of toPrettyChars()
201     bool errors;            // this symbol failed to pass semantic()
202     PASS semanticRun;
203 
204     DeprecatedDeclaration depdecl;           // customized deprecation message
205     UserAttributeDeclaration userAttribDecl;    // user defined attributes
206 
207     // !=null means there's a ddoc unittest associated with this symbol
208     // (only use this with ddoc)
209     UnitTestDeclaration ddocUnittest;
210 
211     final extern (D) this()
212     {
213         //printf("Dsymbol::Dsymbol(%p)\n", this);
214         this.semanticRun = PASSinit;
215     }
216 
217     final extern (D) this(Identifier ident)
218     {
219         //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
220         this.ident = ident;
221         this.semanticRun = PASSinit;
222     }
223 
224     static Dsymbol create(Identifier ident)
225     {
226         return new Dsymbol(ident);
227     }
228 
229     override const(char)* toChars()
230     {
231         return ident ? ident.toChars() : "__anonymous";
232     }
233 
234     // helper to print fully qualified (template) arguments
235     const(char)* toPrettyCharsHelper()
236     {
237         return toChars();
238     }
239 
240     final ref Loc getLoc()
241     {
242         if (!loc.filename) // avoid bug 5861.
243         {
244             auto m = getModule();
245             if (m && m.srcfile)
246                 loc.filename = m.srcfile.toChars();
247         }
248         return loc;
249     }
250 
251     final const(char)* locToChars()
252     {
253         return getLoc().toChars();
254     }
255 
256     override bool equals(RootObject o)
257     {
258         if (this == o)
259             return true;
260         Dsymbol s = cast(Dsymbol)o;
261         // Overload sets don't have an ident
262         if (s && ident && s.ident && ident.equals(s.ident))
263             return true;
264         return false;
265     }
266 
267     final bool isAnonymous()
268     {
269         return ident is null;
270     }
271 
272     final void error(Loc loc, const(char)* format, ...)
273     {
274         va_list ap;
275         va_start(ap, format);
276         .verror(loc, format, ap, kind(), toPrettyChars());
277         va_end(ap);
278     }
279 
280     final void error(const(char)* format, ...)
281     {
282         va_list ap;
283         va_start(ap, format);
284         .verror(getLoc(), format, ap, kind(), toPrettyChars());
285         va_end(ap);
286     }
287 
288     final void deprecation(Loc loc, const(char)* format, ...)
289     {
290         va_list ap;
291         va_start(ap, format);
292         .vdeprecation(loc, format, ap, kind(), toPrettyChars());
293         va_end(ap);
294     }
295 
296     final void deprecation(const(char)* format, ...)
297     {
298         va_list ap;
299         va_start(ap, format);
300         .vdeprecation(getLoc(), format, ap, kind(), toPrettyChars());
301         va_end(ap);
302     }
303 
304     final void checkDeprecated(Loc loc, Scope* sc)
305     {
306         if (global.params.useDeprecated != 1 && isDeprecated())
307         {
308             // Don't complain if we're inside a deprecated symbol's scope
309             for (Dsymbol sp = sc.parent; sp; sp = sp.parent)
310             {
311                 if (sp.isDeprecated())
312                     goto L1;
313             }
314             for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
315             {
316                 if (sc2.scopesym && sc2.scopesym.isDeprecated())
317                     goto L1;
318                 // If inside a StorageClassDeclaration that is deprecated
319                 if (sc2.stc & STCdeprecated)
320                     goto L1;
321             }
322             const(char)* message = null;
323             for (Dsymbol p = this; p; p = p.parent)
324             {
325                 message = p.depdecl ? p.depdecl.getMessage() : null;
326                 if (message)
327                     break;
328             }
329             if (message)
330                 deprecation(loc, "is deprecated - %s", message);
331             else
332                 deprecation(loc, "is deprecated");
333         }
334     L1:
335         Declaration d = isDeclaration();
336         if (d && d.storage_class & STCdisable)
337         {
338             if (!(sc.func && sc.func.storage_class & STCdisable))
339             {
340                 if (d.toParent() && d.isPostBlitDeclaration())
341                     d.toParent().error(loc, "is not copyable because it is annotated with @disable");
342                 else
343                     error(loc, "is not callable because it is annotated with @disable");
344             }
345         }
346     }
347 
348     /**********************************
349      * Determine which Module a Dsymbol is in.
350      */
351     final Module getModule()
352     {
353         //printf("Dsymbol::getModule()\n");
354         if (TemplateInstance ti = isInstantiated())
355             return ti.tempdecl.getModule();
356         Dsymbol s = this;
357         while (s)
358         {
359             //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
360             Module m = s.isModule();
361             if (m)
362                 return m;
363             s = s.parent;
364         }
365         return null;
366     }
367 
368     /**********************************
369      * Determine which Module a Dsymbol is in, as far as access rights go.
370      */
371     final Module getAccessModule()
372     {
373         //printf("Dsymbol::getAccessModule()\n");
374         if (TemplateInstance ti = isInstantiated())
375             return ti.tempdecl.getAccessModule();
376         Dsymbol s = this;
377         while (s)
378         {
379             //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
380             Module m = s.isModule();
381             if (m)
382                 return m;
383             TemplateInstance ti = s.isTemplateInstance();
384             if (ti && ti.enclosing)
385             {
386                 /* Because of local template instantiation, the parent isn't where the access
387                  * rights come from - it's the template declaration
388                  */
389                 s = ti.tempdecl;
390             }
391             else
392                 s = s.parent;
393         }
394         return null;
395     }
396 
397     final inout(Dsymbol) pastMixin() inout
398     {
399         //printf("Dsymbol::pastMixin() %s\n", toChars());
400         if (!isTemplateMixin())
401             return this;
402         if (!parent)
403             return null;
404         return parent.pastMixin();
405     }
406 
407     /**********************************
408      * `parent` field returns a lexically enclosing scope symbol this is a member of.
409      *
410      * `toParent()` returns a logically enclosing scope symbol this is a member of.
411      * It skips over TemplateMixin's.
412      *
413      * `toParent2()` returns an enclosing scope symbol this is living at runtime.
414      * It skips over both TemplateInstance's and TemplateMixin's.
415      * It's used when looking for the 'this' pointer of the enclosing function/class.
416      *
417      * Examples:
418      *  module mod;
419      *  template Foo(alias a) { mixin Bar!(); }
420      *  mixin template Bar() {
421      *    public {  // ProtDeclaration
422      *      void baz() { a = 2; }
423      *    }
424      *  }
425      *  void test() {
426      *    int v = 1;
427      *    alias foo = Foo!(v);
428      *    foo.baz();
429      *    assert(v == 2);
430      *  }
431      *
432      *  // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
433      *  // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
434      *  // s.toParent() == TemplateInstance('mod.test.Foo!()')
435      *  // s.toParent2() == FuncDeclaration('mod.test')
436      */
437     final inout(Dsymbol) toParent() inout
438     {
439         return parent ? parent.pastMixin() : null;
440     }
441 
442     /// ditto
443     final inout(Dsymbol) toParent2() inout
444     {
445         if (!parent || !parent.isTemplateInstance)
446             return parent;
447         return parent.toParent2;
448     }
449 
450     final inout(TemplateInstance) isInstantiated() inout
451     {
452         if (!parent)
453             return null;
454         auto ti = parent.isTemplateInstance();
455         if (ti && !ti.isTemplateMixin())
456             return ti;
457         return parent.isInstantiated();
458     }
459 
460     // Check if this function is a member of a template which has only been
461     // instantiated speculatively, eg from inside is(typeof()).
462     // Return the speculative template instance it is part of,
463     // or NULL if not speculative.
464     final inout(TemplateInstance) isSpeculative() inout
465     {
466         if (!parent)
467             return null;
468         auto ti = parent.isTemplateInstance();
469         if (ti && ti.gagged)
470             return ti;
471         if (!parent.toParent())
472             return null;
473         return parent.isSpeculative();
474     }
475 
476     final Ungag ungagSpeculative() const
477     {
478         uint oldgag = global.gag;
479         if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
480             global.gag = 0;
481         return Ungag(oldgag);
482     }
483 
484     // kludge for template.isSymbol()
485     override final int dyncast() const
486     {
487         return DYNCAST_DSYMBOL;
488     }
489 
490     /*************************************
491      * Do syntax copy of an array of Dsymbol's.
492      */
493     static Dsymbols* arraySyntaxCopy(Dsymbols* a)
494     {
495         Dsymbols* b = null;
496         if (a)
497         {
498             b = a.copy();
499             for (size_t i = 0; i < b.dim; i++)
500             {
501                 (*b)[i] = (*b)[i].syntaxCopy(null);
502             }
503         }
504         return b;
505     }
506 
507     Identifier getIdent()
508     {
509         return ident;
510     }
511 
512     const(char)* toPrettyChars(bool QualifyTypes = false)
513     {
514         if (prettystring && !QualifyTypes)
515             return prettystring;
516 
517         //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
518         if (!parent)
519         {
520             auto s = toChars();
521             if (!QualifyTypes)
522                 prettystring = s;
523             return s;
524         }
525 
526         // Computer number of components
527         size_t complength = 0;
528         for (Dsymbol p = this; p; p = p.parent)
529             ++complength;
530 
531         // Allocate temporary array comp[]
532         alias T = const(char)[];
533         auto compptr = cast(T*)malloc(complength * T.sizeof);
534         if (!compptr)
535             Mem.error();
536         auto comp = compptr[0 .. complength];
537 
538         // Fill in comp[] and compute length of final result
539         size_t length = 0;
540         int i;
541         for (Dsymbol p = this; p; p = p.parent)
542         {
543             const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
544             const len = strlen(s);
545             comp[i] = s[0 .. len];
546             ++i;
547             length += len + 1;
548         }
549 
550         auto s = cast(char*)mem.xmalloc(length);
551         auto q = s + length - 1;
552         *q = 0;
553         foreach (j; 0 .. complength)
554         {
555             const t = comp[j].ptr;
556             const len = comp[j].length;
557             q -= len;
558             memcpy(q, t, len);
559             if (q == s)
560                 break;
561             *--q = '.';
562         }
563         free(comp.ptr);
564         if (!QualifyTypes)
565             prettystring = s;
566         return s;
567     }
568 
569     const(char)* kind() const
570     {
571         return "symbol";
572     }
573 
574     /*********************************
575      * If this symbol is really an alias for another,
576      * return that other.
577      * If needed, semantic() is invoked due to resolve forward reference.
578      */
579     Dsymbol toAlias()
580     {
581         return this;
582     }
583 
584     /*********************************
585      * Resolve recursive tuple expansion in eponymous template.
586      */
587     Dsymbol toAlias2()
588     {
589         return toAlias();
590     }
591 
592     /*********************************
593      * Iterate this dsymbol or members of this scoped dsymbol, then
594      * call `fp` with the found symbol and `param`.
595      * Params:
596      *  fp = function pointer to process the iterated symbol.
597      *       If it returns nonzero, the iteration will be aborted.
598      *  param = a parameter passed to fp.
599      * Returns:
600      *  nonzero if the iteration is aborted by the return value of fp,
601      *  or 0 if it's completed.
602      */
603     int apply(Dsymbol_apply_ft_t fp, void* param)
604     {
605         return (*fp)(this, param);
606     }
607 
608     void addMember(Scope* sc, ScopeDsymbol sds)
609     {
610         //printf("Dsymbol::addMember('%s')\n", toChars());
611         //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds->toChars());
612         //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds->symtab = %p)\n", this, toChars(), sds, sds->symtab);
613         parent = sds;
614         if (!isAnonymous()) // no name, so can't add it to symbol table
615         {
616             if (!sds.symtabInsert(this)) // if name is already defined
617             {
618                 Dsymbol s2 = sds.symtab.lookup(ident);
619                 if (!s2.overloadInsert(this))
620                 {
621                     sds.multiplyDefined(Loc(), this, s2);
622                     errors = true;
623                 }
624             }
625             if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
626             {
627                 if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
628                 {
629                     error(".%s property cannot be redefined", ident.toChars());
630                     errors = true;
631                 }
632             }
633         }
634     }
635 
636     /*************************************
637      * Set scope for future semantic analysis so we can
638      * deal better with forward references.
639      */
640     void setScope(Scope* sc)
641     {
642         //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc);
643         if (!sc.nofree)
644             sc.setNoFree(); // may need it even after semantic() finishes
645         _scope = sc;
646         if (sc.depdecl)
647             depdecl = sc.depdecl;
648         if (!userAttribDecl)
649             userAttribDecl = sc.userAttribDecl;
650     }
651 
652     void importAll(Scope* sc)
653     {
654     }
655 
656     /*************************************
657      * Does semantic analysis on the public face of declarations.
658      */
659     void semantic(Scope* sc)
660     {
661         error("%p has no semantic routine", this);
662     }
663 
664     /*************************************
665      * Does semantic analysis on initializers and members of aggregates.
666      */
667     void semantic2(Scope* sc)
668     {
669         // Most Dsymbols have no further semantic analysis needed
670     }
671 
672     /*************************************
673      * Does semantic analysis on function bodies.
674      */
675     void semantic3(Scope* sc)
676     {
677         // Most Dsymbols have no further semantic analysis needed
678     }
679 
680     /*********************************************
681      * Search for ident as member of s.
682      * Params:
683      *  loc = location to print for error messages
684      *  ident = identifier to search for
685      *  flags = IgnoreXXXX
686      * Returns:
687      *  null if not found
688      */
689     Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone)
690     {
691         //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
692         return null;
693     }
694 
695     final Dsymbol search_correct(Identifier ident)
696     {
697         /***************************************************
698          * Search for symbol with correct spelling.
699          */
700         extern (D) void* symbol_search_fp(const(char)* seed, ref int cost)
701         {
702             /* If not in the lexer's string table, it certainly isn't in the symbol table.
703              * Doing this first is a lot faster.
704              */
705             size_t len = strlen(seed);
706             if (!len)
707                 return null;
708             Identifier id = Identifier.lookup(seed, len);
709             if (!id)
710                 return null;
711             cost = 0;
712             Dsymbol s = this;
713             Module.clearCache();
714             return cast(void*)s.search(Loc(), id, IgnoreErrors);
715         }
716 
717         if (global.gag)
718             return null; // don't do it for speculative compiles; too time consuming
719         return cast(Dsymbol)speller(ident.toChars(), &symbol_search_fp, idchars);
720     }
721 
722     /***************************************
723      * Search for identifier id as a member of 'this'.
724      * id may be a template instance.
725      * Returns:
726      *      symbol found, NULL if not
727      */
728     final Dsymbol searchX(Loc loc, Scope* sc, RootObject id)
729     {
730         //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
731         Dsymbol s = toAlias();
732         Dsymbol sm;
733         if (Declaration d = s.isDeclaration())
734         {
735             if (d.inuse)
736             {
737                 .error(loc, "circular reference to '%s'", d.toPrettyChars());
738                 return null;
739             }
740         }
741         switch (id.dyncast())
742         {
743         case DYNCAST_IDENTIFIER:
744             sm = s.search(loc, cast(Identifier)id);
745             break;
746         case DYNCAST_DSYMBOL:
747             {
748                 // It's a template instance
749                 //printf("\ttemplate instance id\n");
750                 Dsymbol st = cast(Dsymbol)id;
751                 TemplateInstance ti = st.isTemplateInstance();
752                 sm = s.search(loc, ti.name);
753                 if (!sm)
754                 {
755                     sm = s.search_correct(ti.name);
756                     if (sm)
757                         .error(loc, "template identifier '%s' is not a member of %s '%s', did you mean %s '%s'?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars());
758                     else
759                         .error(loc, "template identifier '%s' is not a member of %s '%s'", ti.name.toChars(), s.kind(), s.toPrettyChars());
760                     return null;
761                 }
762                 sm = sm.toAlias();
763                 TemplateDeclaration td = sm.isTemplateDeclaration();
764                 if (!td)
765                 {
766                     .error(loc, "%s.%s is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
767                     return null;
768                 }
769                 ti.tempdecl = td;
770                 if (!ti.semanticRun)
771                     ti.semantic(sc);
772                 sm = ti.toAlias();
773                 break;
774             }
775         case DYNCAST_TYPE:
776         case DYNCAST_EXPRESSION:
777         default:
778             assert(0);
779         }
780         return sm;
781     }
782 
783     bool overloadInsert(Dsymbol s)
784     {
785         //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
786         return false;
787     }
788 
789     /*********************************
790      * Returns:
791      *  SIZE_INVALID when the size cannot be determined
792      */
793     d_uns64 size(Loc loc)
794     {
795         error("Dsymbol '%s' has no size", toChars());
796         return SIZE_INVALID;
797     }
798 
799     bool isforwardRef()
800     {
801         return false;
802     }
803 
804     // is a 'this' required to access the member
805     AggregateDeclaration isThis()
806     {
807         return null;
808     }
809 
810     // is Dsymbol exported?
811     bool isExport()
812     {
813         return false;
814     }
815 
816     // is Dsymbol imported?
817     bool isImportedSymbol()
818     {
819         return false;
820     }
821 
822     // is Dsymbol deprecated?
823     bool isDeprecated()
824     {
825         return false;
826     }
827 
828     bool isOverloadable()
829     {
830         return false;
831     }
832 
833     // is this a LabelDsymbol()?
834     LabelDsymbol isLabel()
835     {
836         return null;
837     }
838 
839     /// Returns an AggregateDeclaration when toParent() is that.
840     final AggregateDeclaration isMember()
841     {
842         //printf("Dsymbol::isMember() %s\n", toChars());
843         auto p = toParent();
844         //printf("parent is %s %s\n", p.kind(), p.toChars());
845         return p ? p.isAggregateDeclaration() : null;
846     }
847 
848     /// Returns an AggregateDeclaration when toParent2() is that.
849     final AggregateDeclaration isMember2()
850     {
851         //printf("Dsymbol::isMember2() '%s'\n", toChars());
852         auto p = toParent2();
853         //printf("parent is %s %s\n", p.kind(), p.toChars());
854         return p ? p.isAggregateDeclaration() : null;
855     }
856 
857     // is this a member of a ClassDeclaration?
858     final ClassDeclaration isClassMember()
859     {
860         auto ad = isMember();
861         return ad ? ad.isClassDeclaration() : null;
862     }
863 
864     // is this a type?
865     Type getType()
866     {
867         return null;
868     }
869 
870     // need a 'this' pointer?
871     bool needThis()
872     {
873         return false;
874     }
875 
876     /*************************************
877      */
878     Prot prot()
879     {
880         return Prot(PROTpublic);
881     }
882 
883     /**************************************
884      * Copy the syntax.
885      * Used for template instantiations.
886      * If s is NULL, allocate the new object, otherwise fill it in.
887      */
888     Dsymbol syntaxCopy(Dsymbol s)
889     {
890         print();
891         printf("%s %s\n", kind(), toChars());
892         assert(0);
893     }
894 
895     /**************************************
896      * Determine if this symbol is only one.
897      * Returns:
898      *      false, *ps = NULL: There are 2 or more symbols
899      *      true,  *ps = NULL: There are zero symbols
900      *      true,  *ps = symbol: The one and only one symbol
901      */
902     bool oneMember(Dsymbol* ps, Identifier ident)
903     {
904         //printf("Dsymbol::oneMember()\n");
905         *ps = this;
906         return true;
907     }
908 
909     /*****************************************
910      * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
911      */
912     static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
913     {
914         //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
915         Dsymbol s = null;
916         if (members)
917         {
918             for (size_t i = 0; i < members.dim; i++)
919             {
920                 Dsymbol sx = (*members)[i];
921                 bool x = sx.oneMember(ps, ident);
922                 //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
923                 if (!x)
924                 {
925                     //printf("\tfalse 1\n");
926                     assert(*ps is null);
927                     return false;
928                 }
929                 if (*ps)
930                 {
931                     static bool isOverloadableAlias(Dsymbol s)
932                     {
933                         auto ad = s.isAliasDeclaration();
934                         return ad && ad.aliassym && ad.aliassym.isOverloadable();
935                     }
936 
937                     assert(ident);
938                     if (!(*ps).ident || !(*ps).ident.equals(ident))
939                         continue;
940                     if (!s)
941                         s = *ps;
942                     else if ((   s .isOverloadable() || isOverloadableAlias(  s)) &&
943                              ((*ps).isOverloadable() || isOverloadableAlias(*ps)))
944                     {
945                         // keep head of overload set
946                         FuncDeclaration f1 = s.isFuncDeclaration();
947                         FuncDeclaration f2 = (*ps).isFuncDeclaration();
948                         if (f1 && f2)
949                         {
950                             assert(!f1.isFuncAliasDeclaration());
951                             assert(!f2.isFuncAliasDeclaration());
952                             for (; f1 != f2; f1 = f1.overnext0)
953                             {
954                                 if (f1.overnext0 is null)
955                                 {
956                                     f1.overnext0 = f2;
957                                     break;
958                                 }
959                             }
960                         }
961                     }
962                     else // more than one symbol
963                     {
964                         *ps = null;
965                         //printf("\tfalse 2\n");
966                         return false;
967                     }
968                 }
969             }
970         }
971         *ps = s; // s is the one symbol, null if none
972         //printf("\ttrue\n");
973         return true;
974     }
975 
976     void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion)
977     {
978     }
979 
980     /*****************************************
981      * Is Dsymbol a variable that contains pointers?
982      */
983     bool hasPointers()
984     {
985         //printf("Dsymbol::hasPointers() %s\n", toChars());
986         return false;
987     }
988 
989     bool hasStaticCtorOrDtor()
990     {
991         //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
992         return false;
993     }
994 
995     void addLocalClass(ClassDeclarations*)
996     {
997     }
998 
999     void checkCtorConstInit()
1000     {
1001     }
1002 
1003     /****************************************
1004      * Add documentation comment to Dsymbol.
1005      * Ignore NULL comments.
1006      */
1007     void addComment(const(char)* comment)
1008     {
1009         //if (comment)
1010         //    printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
1011         if (!this.comment)
1012             this.comment = comment;
1013         else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
1014         {
1015             // Concatenate the two
1016             this.comment = Lexer.combineComments(this.comment, comment);
1017         }
1018     }
1019 
1020     /****************************************
1021      * Returns true if this symbol is defined in a non-root module without instantiation.
1022      */
1023     final bool inNonRoot()
1024     {
1025         Dsymbol s = parent;
1026         for (; s; s = s.toParent())
1027         {
1028             if (auto ti = s.isTemplateInstance())
1029             {
1030                 return false;
1031             }
1032             if (auto m = s.isModule())
1033             {
1034                 if (!m.isRoot())
1035                     return true;
1036                 break;
1037             }
1038         }
1039         return false;
1040     }
1041 
1042     // Eliminate need for dynamic_cast
1043     inout(Package) isPackage() inout
1044     {
1045         return null;
1046     }
1047 
1048     inout(Module) isModule() inout
1049     {
1050         return null;
1051     }
1052 
1053     inout(EnumMember) isEnumMember() inout
1054     {
1055         return null;
1056     }
1057 
1058     inout(TemplateDeclaration) isTemplateDeclaration() inout
1059     {
1060         return null;
1061     }
1062 
1063     inout(TemplateInstance) isTemplateInstance() inout
1064     {
1065         return null;
1066     }
1067 
1068     inout(TemplateMixin) isTemplateMixin() inout
1069     {
1070         return null;
1071     }
1072 
1073     inout(Nspace) isNspace() inout
1074     {
1075         return null;
1076     }
1077 
1078     inout(Declaration) isDeclaration() inout
1079     {
1080         return null;
1081     }
1082 
1083     inout(ThisDeclaration) isThisDeclaration() inout
1084     {
1085         return null;
1086     }
1087 
1088     inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout
1089     {
1090         return null;
1091     }
1092 
1093     inout(TupleDeclaration) isTupleDeclaration() inout
1094     {
1095         return null;
1096     }
1097 
1098     inout(AliasDeclaration) isAliasDeclaration() inout
1099     {
1100         return null;
1101     }
1102 
1103     inout(AggregateDeclaration) isAggregateDeclaration() inout
1104     {
1105         return null;
1106     }
1107 
1108     inout(FuncDeclaration) isFuncDeclaration() inout
1109     {
1110         return null;
1111     }
1112 
1113     inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
1114     {
1115         return null;
1116     }
1117 
1118     inout(OverDeclaration) isOverDeclaration() inout
1119     {
1120         return null;
1121     }
1122 
1123     inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
1124     {
1125         return null;
1126     }
1127 
1128     inout(CtorDeclaration) isCtorDeclaration() inout
1129     {
1130         return null;
1131     }
1132 
1133     inout(PostBlitDeclaration) isPostBlitDeclaration() inout
1134     {
1135         return null;
1136     }
1137 
1138     inout(DtorDeclaration) isDtorDeclaration() inout
1139     {
1140         return null;
1141     }
1142 
1143     inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout
1144     {
1145         return null;
1146     }
1147 
1148     inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
1149     {
1150         return null;
1151     }
1152 
1153     inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
1154     {
1155         return null;
1156     }
1157 
1158     inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
1159     {
1160         return null;
1161     }
1162 
1163     inout(InvariantDeclaration) isInvariantDeclaration() inout
1164     {
1165         return null;
1166     }
1167 
1168     inout(UnitTestDeclaration) isUnitTestDeclaration() inout
1169     {
1170         return null;
1171     }
1172 
1173     inout(NewDeclaration) isNewDeclaration() inout
1174     {
1175         return null;
1176     }
1177 
1178     inout(VarDeclaration) isVarDeclaration() inout
1179     {
1180         return null;
1181     }
1182 
1183     inout(ClassDeclaration) isClassDeclaration() inout
1184     {
1185         return null;
1186     }
1187 
1188     inout(StructDeclaration) isStructDeclaration() inout
1189     {
1190         return null;
1191     }
1192 
1193     inout(UnionDeclaration) isUnionDeclaration() inout
1194     {
1195         return null;
1196     }
1197 
1198     inout(InterfaceDeclaration) isInterfaceDeclaration() inout
1199     {
1200         return null;
1201     }
1202 
1203     inout(ScopeDsymbol) isScopeDsymbol() inout
1204     {
1205         return null;
1206     }
1207 
1208     inout(WithScopeSymbol) isWithScopeSymbol() inout
1209     {
1210         return null;
1211     }
1212 
1213     inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
1214     {
1215         return null;
1216     }
1217 
1218     inout(Import) isImport() inout
1219     {
1220         return null;
1221     }
1222 
1223     inout(EnumDeclaration) isEnumDeclaration() inout
1224     {
1225         return null;
1226     }
1227 
1228     inout(DeleteDeclaration) isDeleteDeclaration() inout
1229     {
1230         return null;
1231     }
1232 
1233     inout(SymbolDeclaration) isSymbolDeclaration() inout
1234     {
1235         return null;
1236     }
1237 
1238     inout(AttribDeclaration) isAttribDeclaration() inout
1239     {
1240         return null;
1241     }
1242 
1243     inout(AnonDeclaration) isAnonDeclaration() inout
1244     {
1245         return null;
1246     }
1247 
1248     inout(OverloadSet) isOverloadSet() inout
1249     {
1250         return null;
1251     }
1252 
1253     /************
1254      */
1255     void accept(Visitor v)
1256     {
1257         v.visit(this);
1258     }
1259 }
1260 
1261 /***********************************************************
1262  * Dsymbol that generates a scope
1263  */
1264 extern (C++) class ScopeDsymbol : Dsymbol
1265 {
1266     Dsymbols* members;          // all Dsymbol's in this scope
1267     DsymbolTable symtab;        // members[] sorted into table
1268     uint endlinnum;             // the linnumber of the statement after the scope (0 if unknown)
1269 
1270 private:
1271     /// symbols whose members have been imported, i.e. imported modules and template mixins
1272     Dsymbols* importedScopes;
1273     PROTKIND* prots;            // array of PROTKIND, one for each import
1274 
1275     import ddmd.root.array : BitArray;
1276     BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
1277 
1278 public:
1279     final extern (D) this()
1280     {
1281     }
1282 
1283     final extern (D) this(Identifier id)
1284     {
1285         super(id);
1286     }
1287 
1288     override Dsymbol syntaxCopy(Dsymbol s)
1289     {
1290         //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1291         ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
1292         sds.members = arraySyntaxCopy(members);
1293         sds.endlinnum = endlinnum;
1294         return sds;
1295     }
1296 
1297     /*****************************************
1298      * This function is #1 on the list of functions that eat cpu time.
1299      * Be very, very careful about slowing it down.
1300      */
1301     override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1302     {
1303         //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1304         //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0;
1305 
1306         // Look in symbols declared in this module
1307         if (symtab && !(flags & SearchImportsOnly))
1308         {
1309             //printf(" look in locals\n");
1310             auto s1 = symtab.lookup(ident);
1311             if (s1)
1312             {
1313                 //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1314                 return s1;
1315             }
1316         }
1317         //printf(" not found in locals\n");
1318 
1319         // Look in imported scopes
1320         if (importedScopes)
1321         {
1322             //printf(" look in imports\n");
1323             Dsymbol s = null;
1324             OverloadSet a = null;
1325             // Look in imported modules
1326             for (size_t i = 0; i < importedScopes.dim; i++)
1327             {
1328                 // If private import, don't search it
1329                 if ((flags & IgnorePrivateImports) && prots[i] == PROTprivate)
1330                     continue;
1331                 int sflags = flags & (IgnoreErrors | IgnoreAmbiguous | IgnoreSymbolVisibility); // remember these in recursive searches
1332                 Dsymbol ss = (*importedScopes)[i];
1333                 //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
1334 
1335                 if (ss.isModule())
1336                 {
1337                     if (flags & SearchLocalsOnly)
1338                         continue;
1339                 }
1340                 else // mixin template
1341                 {
1342                     if (flags & SearchImportsOnly)
1343                         continue;
1344                     // compatibility with -transition=import (Bugzilla 15925)
1345                     // SearchLocalsOnly should always get set for new lookup rules
1346                     sflags |= (flags & SearchLocalsOnly);
1347                 }
1348 
1349                 /* Don't find private members if ss is a module
1350                  */
1351                 Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
1352                 import ddmd.access : symbolIsVisible;
1353                 if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
1354                     continue;
1355                 if (!s)
1356                 {
1357                     s = s2;
1358                     if (s && s.isOverloadSet())
1359                         a = mergeOverloadSet(ident, a, s);
1360                 }
1361                 else if (s2 && s != s2)
1362                 {
1363                     if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
1364                     {
1365                         /* After following aliases, we found the same
1366                          * symbol, so it's not an ambiguity.  But if one
1367                          * alias is deprecated or less accessible, prefer
1368                          * the other.
1369                          */
1370                         if (s.isDeprecated() || s.prot().isMoreRestrictiveThan(s2.prot()) && s2.prot().kind != PROTnone)
1371                             s = s2;
1372                     }
1373                     else
1374                     {
1375                         /* Two imports of the same module should be regarded as
1376                          * the same.
1377                          */
1378                         Import i1 = s.isImport();
1379                         Import i2 = s2.isImport();
1380                         if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
1381                         {
1382                             /* Bugzilla 8668:
1383                              * Public selective import adds AliasDeclaration in module.
1384                              * To make an overload set, resolve aliases in here and
1385                              * get actual overload roots which accessible via s and s2.
1386                              */
1387                             s = s.toAlias();
1388                             s2 = s2.toAlias();
1389                             /* If both s2 and s are overloadable (though we only
1390                              * need to check s once)
1391                              */
1392                             if ((s2.isOverloadSet() || s2.isOverloadable()) && (a || s.isOverloadable()))
1393                             {
1394                                 a = mergeOverloadSet(ident, a, s2);
1395                                 continue;
1396                             }
1397                             if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
1398                                 return null;
1399                             if (!(flags & IgnoreErrors))
1400                                 ScopeDsymbol.multiplyDefined(loc, s, s2);
1401                             break;
1402                         }
1403                     }
1404                 }
1405             }
1406             if (s)
1407             {
1408                 /* Build special symbol if we had multiple finds
1409                  */
1410                 if (a)
1411                 {
1412                     if (!s.isOverloadSet())
1413                     {
1414                         a = mergeOverloadSet(ident, a, s);
1415                         if (symtab)
1416                             symtabInsert(a);    // Bugzilla 15857
1417                     }
1418                     s = a;
1419                 }
1420                 // TODO: remove once private symbol visibility has been deprecated
1421                 if (!(flags & IgnoreErrors) && s.prot().kind == PROTprivate &&
1422                     !s.isOverloadable() && !s.parent.isTemplateMixin() && !s.parent.isNspace())
1423                 {
1424                     AliasDeclaration ad = void;
1425                     // accessing private selective and renamed imports is
1426                     // deprecated by restricting the symbol visibility
1427                     if (s.isImport() || (ad = s.isAliasDeclaration()) !is null && ad._import !is null)
1428                     {}
1429                     else
1430                         error(loc, "%s %s is private", s.kind(), s.toPrettyChars());
1431                 }
1432                 //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1433                 return s;
1434             }
1435             //printf(" not found in imports\n");
1436         }
1437         return null;
1438     }
1439 
1440     final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1441     {
1442         if (!os)
1443         {
1444             os = new OverloadSet(ident);
1445             os.parent = this;
1446         }
1447         if (OverloadSet os2 = s.isOverloadSet())
1448         {
1449             // Merge the cross-module overload set 'os2' into 'os'
1450             if (os.a.dim == 0)
1451             {
1452                 os.a.setDim(os2.a.dim);
1453                 memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
1454             }
1455             else
1456             {
1457                 for (size_t i = 0; i < os2.a.dim; i++)
1458                 {
1459                     os = mergeOverloadSet(ident, os, os2.a[i]);
1460                 }
1461             }
1462         }
1463         else
1464         {
1465             assert(s.isOverloadable());
1466             /* Don't add to os[] if s is alias of previous sym
1467              */
1468             for (size_t j = 0; j < os.a.dim; j++)
1469             {
1470                 Dsymbol s2 = os.a[j];
1471                 if (s.toAlias() == s2.toAlias())
1472                 {
1473                     if (s2.isDeprecated() || (s2.prot().isMoreRestrictiveThan(s.prot()) && s.prot().kind != PROTnone))
1474                     {
1475                         os.a[j] = s;
1476                     }
1477                     goto Lcontinue;
1478                 }
1479             }
1480             os.push(s);
1481         Lcontinue:
1482         }
1483         return os;
1484     }
1485 
1486     final void importScope(Dsymbol s, Prot protection)
1487     {
1488         //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
1489         // No circular or redundant import's
1490         if (s != this)
1491         {
1492             if (!importedScopes)
1493                 importedScopes = new Dsymbols();
1494             else
1495             {
1496                 for (size_t i = 0; i < importedScopes.dim; i++)
1497                 {
1498                     Dsymbol ss = (*importedScopes)[i];
1499                     if (ss == s) // if already imported
1500                     {
1501                         if (protection.kind > prots[i])
1502                             prots[i] = protection.kind; // upgrade access
1503                         return;
1504                     }
1505                 }
1506             }
1507             importedScopes.push(s);
1508             prots = cast(PROTKIND*)mem.xrealloc(prots, importedScopes.dim * (prots[0]).sizeof);
1509             prots[importedScopes.dim - 1] = protection.kind;
1510         }
1511     }
1512 
1513     final void addAccessiblePackage(Package p, Prot protection)
1514     {
1515         auto pary = protection.kind == PROTprivate ? &privateAccessiblePackages : &accessiblePackages;
1516         if (pary.length <= p.tag)
1517             pary.length = p.tag + 1;
1518         (*pary)[p.tag] = true;
1519     }
1520 
1521     bool isPackageAccessible(Package p, Prot protection, int flags = 0)
1522     {
1523         if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1524             protection.kind == PROTprivate && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1525             return true;
1526         foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1527         {
1528             // only search visible scopes && imported modules should ignore private imports
1529             if (protection.kind <= prots[i] &&
1530                 ss.isScopeDsymbol.isPackageAccessible(p, protection, IgnorePrivateImports))
1531                 return true;
1532         }
1533         return false;
1534     }
1535 
1536     override final bool isforwardRef()
1537     {
1538         return (members is null);
1539     }
1540 
1541     static void multiplyDefined(Loc loc, Dsymbol s1, Dsymbol s2)
1542     {
1543         version (none)
1544         {
1545             printf("ScopeDsymbol::multiplyDefined()\n");
1546             printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1547             printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1548         }
1549         if (loc.filename)
1550         {
1551             .error(loc, "%s at %s conflicts with %s at %s", s1.toPrettyChars(), s1.locToChars(), s2.toPrettyChars(), s2.locToChars());
1552         }
1553         else
1554         {
1555             s1.error(s1.loc, "conflicts with %s %s at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1556         }
1557     }
1558 
1559     override const(char)* kind() const
1560     {
1561         return "ScopeDsymbol";
1562     }
1563 
1564     /*******************************************
1565      * Look for member of the form:
1566      *      const(MemberInfo)[] getMembers(string);
1567      * Returns NULL if not found
1568      */
1569     final FuncDeclaration findGetMembers()
1570     {
1571         Dsymbol s = search_function(this, Id.getmembers);
1572         FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1573         version (none)
1574         {
1575             // Finish
1576             static __gshared TypeFunction tfgetmembers;
1577             if (!tfgetmembers)
1578             {
1579                 Scope sc;
1580                 auto parameters = new Parameters();
1581                 Parameters* p = new Parameter(STCin, Type.tchar.constOf().arrayOf(), null, null);
1582                 parameters.push(p);
1583                 Type tret = null;
1584                 tfgetmembers = new TypeFunction(parameters, tret, 0, LINKd);
1585                 tfgetmembers = cast(TypeFunction)tfgetmembers.semantic(Loc(), &sc);
1586             }
1587             if (fdx)
1588                 fdx = fdx.overloadExactMatch(tfgetmembers);
1589         }
1590         if (fdx && fdx.isVirtual())
1591             fdx = null;
1592         return fdx;
1593     }
1594 
1595     Dsymbol symtabInsert(Dsymbol s)
1596     {
1597         return symtab.insert(s);
1598     }
1599 
1600     /****************************************
1601      * Return true if any of the members are static ctors or static dtors, or if
1602      * any members have members that are.
1603      */
1604     override bool hasStaticCtorOrDtor()
1605     {
1606         if (members)
1607         {
1608             for (size_t i = 0; i < members.dim; i++)
1609             {
1610                 Dsymbol member = (*members)[i];
1611                 if (member.hasStaticCtorOrDtor())
1612                     return true;
1613             }
1614         }
1615         return false;
1616     }
1617 
1618     /***************************************
1619      * Determine number of Dsymbols, folding in AttribDeclaration members.
1620      */
1621     static size_t dim(Dsymbols* members)
1622     {
1623         size_t n = 0;
1624         int dimDg(size_t idx, Dsymbol s)
1625         {
1626             ++n;
1627             return 0;
1628         }
1629 
1630         _foreach(null, members, &dimDg, &n);
1631         return n;
1632     }
1633 
1634     /***************************************
1635      * Get nth Dsymbol, folding in AttribDeclaration members.
1636      * Returns:
1637      *      Dsymbol*        nth Dsymbol
1638      *      NULL            not found, *pn gets incremented by the number
1639      *                      of Dsymbols
1640      */
1641     static Dsymbol getNth(Dsymbols* members, size_t nth, size_t* pn = null)
1642     {
1643         Dsymbol sym = null;
1644 
1645         int getNthSymbolDg(size_t n, Dsymbol s)
1646         {
1647             if (n == nth)
1648             {
1649                 sym = s;
1650                 return 1;
1651             }
1652             return 0;
1653         }
1654 
1655         int res = _foreach(null, members, &getNthSymbolDg);
1656         return res ? sym : null;
1657     }
1658 
1659     extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1660 
1661     /***************************************
1662      * Expands attribute declarations in members in depth first
1663      * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1664      * member.
1665      * If dg returns !=0, stops and returns that value else returns 0.
1666      * Use this function to avoid the O(N + N^2/2) complexity of
1667      * calculating dim and calling N times getNth.
1668      * Returns:
1669      *  last value returned by dg()
1670      */
1671     extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1672     {
1673         assert(dg);
1674         if (!members)
1675             return 0;
1676         size_t n = pn ? *pn : 0; // take over index
1677         int result = 0;
1678         foreach (size_t i; 0 .. members.dim)
1679         {
1680             Dsymbol s = (*members)[i];
1681             if (AttribDeclaration a = s.isAttribDeclaration())
1682                 result = _foreach(sc, a.include(sc, null), dg, &n);
1683             else if (TemplateMixin tm = s.isTemplateMixin())
1684                 result = _foreach(sc, tm.members, dg, &n);
1685             else if (s.isTemplateInstance())
1686             {
1687             }
1688             else if (s.isUnitTestDeclaration())
1689             {
1690             }
1691             else
1692                 result = dg(n++, s);
1693             if (result)
1694                 break;
1695         }
1696         if (pn)
1697             *pn = n; // update index
1698         return result;
1699     }
1700 
1701     override final inout(ScopeDsymbol) isScopeDsymbol() inout
1702     {
1703         return this;
1704     }
1705 
1706     override void accept(Visitor v)
1707     {
1708         v.visit(this);
1709     }
1710 }
1711 
1712 /***********************************************************
1713  * With statement scope
1714  */
1715 extern (C++) final class WithScopeSymbol : ScopeDsymbol
1716 {
1717     WithStatement withstate;
1718 
1719     extern (D) this(WithStatement withstate)
1720     {
1721         this.withstate = withstate;
1722     }
1723 
1724     override Dsymbol search(Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1725     {
1726         //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1727         if (flags & SearchImportsOnly)
1728             return null;
1729         // Acts as proxy to the with class declaration
1730         Dsymbol s = null;
1731         Expression eold = null;
1732         for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e))
1733         {
1734             if (e.op == TOKscope)
1735             {
1736                 s = (cast(ScopeExp)e).sds;
1737             }
1738             else if (e.op == TOKtype)
1739             {
1740                 s = e.type.toDsymbol(null);
1741             }
1742             else
1743             {
1744                 Type t = e.type.toBasetype();
1745                 s = t.toDsymbol(null);
1746             }
1747             if (s)
1748             {
1749                 s = s.search(loc, ident, flags);
1750                 if (s)
1751                     return s;
1752             }
1753             eold = e;
1754         }
1755         return null;
1756     }
1757 
1758     override inout(WithScopeSymbol) isWithScopeSymbol() inout
1759     {
1760         return this;
1761     }
1762 
1763     override void accept(Visitor v)
1764     {
1765         v.visit(this);
1766     }
1767 }
1768 
1769 /***********************************************************
1770  * Array Index/Slice scope
1771  */
1772 extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1773 {
1774     Expression exp;         // IndexExp or SliceExp
1775     TypeTuple type;         // for tuple[length]
1776     TupleDeclaration td;    // for tuples of objects
1777     Scope* sc;
1778 
1779     extern (D) this(Scope* sc, Expression e)
1780     {
1781         assert(e.op == TOKindex || e.op == TOKslice || e.op == TOKarray);
1782         exp = e;
1783         this.sc = sc;
1784     }
1785 
1786     extern (D) this(Scope* sc, TypeTuple t)
1787     {
1788         type = t;
1789         this.sc = sc;
1790     }
1791 
1792     extern (D) this(Scope* sc, TupleDeclaration s)
1793     {
1794         td = s;
1795         this.sc = sc;
1796     }
1797 
1798     override Dsymbol search(Loc loc, Identifier ident, int flags = IgnoreNone)
1799     {
1800         //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
1801         if (ident == Id.dollar)
1802         {
1803             VarDeclaration* pvar;
1804             Expression ce;
1805         L1:
1806             if (td)
1807             {
1808                 /* $ gives the number of elements in the tuple
1809                  */
1810                 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1811                 Expression e = new IntegerExp(Loc(), td.objects.dim, Type.tsize_t);
1812                 v._init = new ExpInitializer(Loc(), e);
1813                 v.storage_class |= STCtemp | STCstatic | STCconst;
1814                 v.semantic(sc);
1815                 return v;
1816             }
1817             if (type)
1818             {
1819                 /* $ gives the number of type entries in the type tuple
1820                  */
1821                 auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1822                 Expression e = new IntegerExp(Loc(), type.arguments.dim, Type.tsize_t);
1823                 v._init = new ExpInitializer(Loc(), e);
1824                 v.storage_class |= STCtemp | STCstatic | STCconst;
1825                 v.semantic(sc);
1826                 return v;
1827             }
1828             if (exp.op == TOKindex)
1829             {
1830                 /* array[index] where index is some function of $
1831                  */
1832                 IndexExp ie = cast(IndexExp)exp;
1833                 pvar = &ie.lengthVar;
1834                 ce = ie.e1;
1835             }
1836             else if (exp.op == TOKslice)
1837             {
1838                 /* array[lwr .. upr] where lwr or upr is some function of $
1839                  */
1840                 SliceExp se = cast(SliceExp)exp;
1841                 pvar = &se.lengthVar;
1842                 ce = se.e1;
1843             }
1844             else if (exp.op == TOKarray)
1845             {
1846                 /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1847                  * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1848                  */
1849                 ArrayExp ae = cast(ArrayExp)exp;
1850                 pvar = &ae.lengthVar;
1851                 ce = ae.e1;
1852             }
1853             else
1854             {
1855                 /* Didn't find $, look in enclosing scope(s).
1856                  */
1857                 return null;
1858             }
1859             while (ce.op == TOKcomma)
1860                 ce = (cast(CommaExp)ce).e2;
1861             /* If we are indexing into an array that is really a type
1862              * tuple, rewrite this as an index into a type tuple and
1863              * try again.
1864              */
1865             if (ce.op == TOKtype)
1866             {
1867                 Type t = (cast(TypeExp)ce).type;
1868                 if (t.ty == Ttuple)
1869                 {
1870                     type = cast(TypeTuple)t;
1871                     goto L1;
1872                 }
1873             }
1874             /* *pvar is lazily initialized, so if we refer to $
1875              * multiple times, it gets set only once.
1876              */
1877             if (!*pvar) // if not already initialized
1878             {
1879                 /* Create variable v and set it to the value of $
1880                  */
1881                 VarDeclaration v;
1882                 Type t;
1883                 if (ce.op == TOKtuple)
1884                 {
1885                     /* It is for an expression tuple, so the
1886                      * length will be a const.
1887                      */
1888                     Expression e = new IntegerExp(Loc(), (cast(TupleExp)ce).exps.dim, Type.tsize_t);
1889                     v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc(), e));
1890                     v.storage_class |= STCtemp | STCstatic | STCconst;
1891                 }
1892                 else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
1893                 {
1894                     // Look for opDollar
1895                     assert(exp.op == TOKarray || exp.op == TOKslice);
1896                     AggregateDeclaration ad = isAggregate(t);
1897                     assert(ad);
1898                     Dsymbol s = ad.search(loc, Id.opDollar);
1899                     if (!s) // no dollar exists -- search in higher scope
1900                         return null;
1901                     s = s.toAlias();
1902                     Expression e = null;
1903                     // Check for multi-dimensional opDollar(dim) template.
1904                     if (TemplateDeclaration td = s.isTemplateDeclaration())
1905                     {
1906                         dinteger_t dim = 0;
1907                         if (exp.op == TOKarray)
1908                         {
1909                             dim = (cast(ArrayExp)exp).currentDimension;
1910                         }
1911                         else if (exp.op == TOKslice)
1912                         {
1913                             dim = 0; // slices are currently always one-dimensional
1914                         }
1915                         else
1916                         {
1917                             assert(0);
1918                         }
1919                         auto tiargs = new Objects();
1920                         Expression edim = new IntegerExp(Loc(), dim, Type.tsize_t);
1921                         edim = edim.semantic(sc);
1922                         tiargs.push(edim);
1923                         e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
1924                     }
1925                     else
1926                     {
1927                         /* opDollar exists, but it's not a template.
1928                          * This is acceptable ONLY for single-dimension indexing.
1929                          * Note that it's impossible to have both template & function opDollar,
1930                          * because both take no arguments.
1931                          */
1932                         if (exp.op == TOKarray && (cast(ArrayExp)exp).arguments.dim != 1)
1933                         {
1934                             exp.error("%s only defines opDollar for one dimension", ad.toChars());
1935                             return null;
1936                         }
1937                         Declaration d = s.isDeclaration();
1938                         assert(d);
1939                         e = new DotVarExp(loc, ce, d);
1940                     }
1941                     e = e.semantic(sc);
1942                     if (!e.type)
1943                         exp.error("%s has no value", e.toChars());
1944                     t = e.type.toBasetype();
1945                     if (t && t.ty == Tfunction)
1946                         e = new CallExp(e.loc, e);
1947                     v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc(), e));
1948                     v.storage_class |= STCtemp | STCctfe | STCrvalue;
1949                 }
1950                 else
1951                 {
1952                     /* For arrays, $ will either be a compile-time constant
1953                      * (in which case its value in set during constant-folding),
1954                      * or a variable (in which case an expression is created in
1955                      * toir.c).
1956                      */
1957                     auto e = new VoidInitializer(Loc());
1958                     e.type = Type.tsize_t;
1959                     v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
1960                     v.storage_class |= STCtemp | STCctfe; // it's never a true static variable
1961                 }
1962                 *pvar = v;
1963             }
1964             (*pvar).semantic(sc);
1965             return (*pvar);
1966         }
1967         return null;
1968     }
1969 
1970     override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
1971     {
1972         return this;
1973     }
1974 
1975     override void accept(Visitor v)
1976     {
1977         v.visit(this);
1978     }
1979 }
1980 
1981 /***********************************************************
1982  * Overload Sets
1983  */
1984 extern (C++) final class OverloadSet : Dsymbol
1985 {
1986     Dsymbols a;     // array of Dsymbols
1987 
1988     extern (D) this(Identifier ident, OverloadSet os = null)
1989     {
1990         super(ident);
1991         if (os)
1992         {
1993             for (size_t i = 0; i < os.a.dim; i++)
1994                 a.push(os.a[i]);
1995         }
1996     }
1997 
1998     void push(Dsymbol s)
1999     {
2000         a.push(s);
2001     }
2002 
2003     override inout(OverloadSet) isOverloadSet() inout
2004     {
2005         return this;
2006     }
2007 
2008     override const(char)* kind() const
2009     {
2010         return "overloadset";
2011     }
2012 
2013     override void accept(Visitor v)
2014     {
2015         v.visit(this);
2016     }
2017 }
2018 
2019 /***********************************************************
2020  * Table of Dsymbol's
2021  */
2022 extern (C++) final class DsymbolTable : RootObject
2023 {
2024     AA* tab;
2025 
2026     // Look up Identifier. Return Dsymbol if found, NULL if not.
2027     Dsymbol lookup(const Identifier ident)
2028     {
2029         //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string);
2030         return cast(Dsymbol)dmd_aaGetRvalue(tab, cast(void*)ident);
2031     }
2032 
2033     // Insert Dsymbol in table. Return NULL if already there.
2034     Dsymbol insert(Dsymbol s)
2035     {
2036         //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
2037         const ident = s.ident;
2038         Dsymbol* ps = cast(Dsymbol*)dmd_aaGet(&tab, cast(void*)ident);
2039         if (*ps)
2040             return null; // already in table
2041         *ps = s;
2042         return s;
2043     }
2044 
2045     // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
2046     Dsymbol update(Dsymbol s)
2047     {
2048         const ident = s.ident;
2049         Dsymbol* ps = cast(Dsymbol*)dmd_aaGet(&tab, cast(void*)ident);
2050         *ps = s;
2051         return s;
2052     }
2053 
2054     // when ident and s are not the same
2055     Dsymbol insert(const Identifier ident, Dsymbol s)
2056     {
2057         //printf("DsymbolTable::insert()\n");
2058         Dsymbol* ps = cast(Dsymbol*)dmd_aaGet(&tab, cast(void*)ident);
2059         if (*ps)
2060             return null; // already in table
2061         *ps = s;
2062         return s;
2063     }
2064 
2065     /*****
2066      * Returns:
2067      *  number of symbols in symbol table
2068      */
2069     uint len() const pure
2070     {
2071         return cast(uint)dmd_aaLen(tab);
2072     }
2073 }