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