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
int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
66
{
67 1
    assert(dg);
68 1
    if (symbols)
69
    {
70
        /* Do not use foreach, as the size of the array may expand during iteration
71
         */
72 1
        for (size_t i = 0; i < symbols.dim; ++i)
73
        {
74 1
            Dsymbol s = (*symbols)[i];
75 1
            const result = dg(s);
76 1
            if (result)
77 1
                return result;
78
        }
79
    }
80 1
    return 0;
81
}
82

83
/***************************************
84
 * Calls dg(Dsymbol *sym) for each Dsymbol.
85
 * Params:
86
 *    symbols = Dsymbols
87
 *    dg = delegate to call for each Dsymbol
88
 */
89
void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
90
{
91 1
    assert(dg);
92 1
    if (symbols)
93
    {
94
        /* Do not use foreach, as the size of the array may expand during iteration
95
         */
96 1
        for (size_t i = 0; i < symbols.dim; ++i)
97
        {
98 1
            Dsymbol s = (*symbols)[i];
99 1
            dg(s);
100
        }
101
    }
102
}
103

104

105
struct Ungag
106
{
107
    uint oldgag;
108

109 1
    extern (D) this(uint old)
110
    {
111 1
        this.oldgag = old;
112
    }
113

114
    extern (C++) ~this()
115
    {
116 1
        global.gag = oldgag;
117
    }
118
}
119

120
struct Prot
121
{
122
    ///
123
    enum Kind : int
124
    {
125
        undefined,
126
        none,           // no access
127
        private_,
128
        package_,
129
        protected_,
130
        public_,
131
        export_,
132
    }
133

134
    Kind kind;
135
    Package pkg;
136

137 1
    extern (D) this(Prot.Kind kind) pure nothrow @nogc @safe
138
    {
139 1
        this.kind = kind;
140
    }
141

142
    extern (C++):
143

144
    /**
145
     * Checks if `this` is superset of `other` restrictions.
146
     * For example, "protected" is more restrictive than "public".
147
     */
148
    bool isMoreRestrictiveThan(const Prot other) const
149
    {
150 1
        return this.kind < other.kind;
151
    }
152

153
    /**
154
     * Checks if `this` is absolutely identical protection attribute to `other`
155
     */
156
    bool opEquals(ref const Prot other) const
157
    {
158 1
        if (this.kind == other.kind)
159
        {
160 1
            if (this.kind == Prot.Kind.package_)
161 0
                return this.pkg == other.pkg;
162 1
            return true;
163
        }
164 0
        return false;
165
    }
166

167
    /**
168
     * Checks if parent defines different access restrictions than this one.
169
     *
170
     * Params:
171
     *  parent = protection attribute for scope that hosts this one
172
     *
173
     * Returns:
174
     *  'true' if parent is already more restrictive than this one and thus
175
     *  no differentiation is needed.
176
     */
177
    bool isSubsetOf(ref const Prot parent) const
178
    {
179 1
        if (this.kind != parent.kind)
180 1
            return false;
181 1
        if (this.kind == Prot.Kind.package_)
182
        {
183 1
            if (!this.pkg)
184 1
                return true;
185 1
            if (!parent.pkg)
186 1
                return false;
187 1
            if (parent.pkg.isAncestorPackageOf(this.pkg))
188 1
                return true;
189
        }
190 1
        return true;
191
    }
192
}
193

194
enum PASS : int
195
{
196
    init,           // initial state
197
    semantic,       // semantic() started
198
    semanticdone,   // semantic() done
199
    semantic2,      // semantic2() started
200
    semantic2done,  // semantic2() done
201
    semantic3,      // semantic3() started
202
    semantic3done,  // semantic3() done
203
    inline,         // inline started
204
    inlinedone,     // inline done
205
    obj,            // toObjFile() run
206
}
207

208
// Search options
209
enum : int
210
{
211
    IgnoreNone              = 0x00, // default
212
    IgnorePrivateImports    = 0x01, // don't search private imports
213
    IgnoreErrors            = 0x02, // don't give error messages
214
    IgnoreAmbiguous         = 0x04, // return NULL if ambiguous
215
    SearchLocalsOnly        = 0x08, // only look at locals (don't search imports)
216
    SearchImportsOnly       = 0x10, // only look in imports
217
    SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
218
                                    // meaning don't search imports in that scope,
219
                                    // because qualified module searches search
220
                                    // their imports
221
    IgnoreSymbolVisibility  = 0x80, // also find private and package protected symbols
222
}
223

224
/***********************************************************
225
 */
226
extern (C++) class Dsymbol : ASTNode
227
{
228
    Identifier ident;
229
    Dsymbol parent;
230
    /// C++ namespace this symbol belongs to
231
    CPPNamespaceDeclaration cppnamespace;
232
    Symbol* csym;           // symbol for code generator
233
    Symbol* isym;           // import version of csym
234
    const(char)* comment;   // documentation comment for this Dsymbol
235
    const Loc loc;          // where defined
236
    Scope* _scope;          // !=null means context to use for semantic()
237
    const(char)* prettystring;  // cached value of toPrettyChars()
238
    bool errors;            // this symbol failed to pass semantic()
239
    PASS semanticRun = PASS.init;
240

241
    DeprecatedDeclaration depdecl;           // customized deprecation message
242
    UserAttributeDeclaration userAttribDecl;    // user defined attributes
243

244
    // !=null means there's a ddoc unittest associated with this symbol
245
    // (only use this with ddoc)
246
    UnitTestDeclaration ddocUnittest;
247

248 1
    final extern (D) this()
249
    {
250
        //printf("Dsymbol::Dsymbol(%p)\n", this);
251 1
        loc = Loc(null, 0, 0);
252
    }
253

254 1
    final extern (D) this(Identifier ident)
255
    {
256
        //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
257 1
        this.loc = Loc(null, 0, 0);
258 1
        this.ident = ident;
259
    }
260

261 1
    final extern (D) this(const ref Loc loc, Identifier ident)
262
    {
263
        //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
264 1
        this.loc = loc;
265 1
        this.ident = ident;
266
    }
267

268
    static Dsymbol create(Identifier ident)
269
    {
270 1
        return new Dsymbol(ident);
271
    }
272

273
    override const(char)* toChars() const
274
    {
275 1
        return ident ? ident.toChars() : "__anonymous";
276
    }
277

278
    // helper to print fully qualified (template) arguments
279
    const(char)* toPrettyCharsHelper()
280
    {
281 1
        return toChars();
282
    }
283

284
    final const(Loc) getLoc()
285
    {
286 1
        if (!loc.isValid()) // avoid bug 5861.
287 1
            if (const m = getModule())
288 1
                return Loc(m.srcfile.toChars(), 0, 0);
289 1
        return loc;
290
    }
291

292
    final const(char)* locToChars()
293
    {
294 1
        return getLoc().toChars();
295
    }
296

297
    override bool equals(const RootObject o) const
298
    {
299 1
        if (this == o)
300 1
            return true;
301 1
        if (o.dyncast() != DYNCAST.dsymbol)
302 0
            return false;
303 1
        auto s = cast(Dsymbol)o;
304
        // Overload sets don't have an ident
305 1
        if (s && ident && s.ident && ident.equals(s.ident))
306 1
            return true;
307 1
        return false;
308
    }
309

310
    bool isAnonymous()
311
    {
312 1
        return ident is null;
313
    }
314

315
    extern(D) private const(char)[] prettyFormatHelper()
316
    {
317 1
        const cstr = toPrettyChars();
318 1
        return '`' ~ cstr.toDString() ~ "`\0";
319
    }
320

321
    final void error(const ref Loc loc, const(char)* format, ...)
322
    {
323 1
        va_list ap;
324 1
        va_start(ap, format);
325 1
        .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
326 1
        va_end(ap);
327
    }
328

329
    final void error(const(char)* format, ...)
330
    {
331 1
        va_list ap;
332 1
        va_start(ap, format);
333 1
        const loc = getLoc();
334 1
        .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
335 1
        va_end(ap);
336
    }
337

338
    final void deprecation(const ref Loc loc, const(char)* format, ...)
339
    {
340 1
        va_list ap;
341 1
        va_start(ap, format);
342 1
        .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
343 1
        va_end(ap);
344
    }
345

346
    final void deprecation(const(char)* format, ...)
347
    {
348 0
        va_list ap;
349 0
        va_start(ap, format);
350 0
        const loc = getLoc();
351 0
        .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
352 0
        va_end(ap);
353
    }
354

355
    final bool checkDeprecated(const ref Loc loc, Scope* sc)
356
    {
357 1
        if (global.params.useDeprecated == DiagnosticReporting.off)
358 1
            return false;
359 1
        if (!this.isDeprecated())
360 1
            return false;
361
        // Don't complain if we're inside a deprecated symbol's scope
362 1
        if (sc.isDeprecated())
363 1
            return false;
364

365 1
        const(char)* message = null;
366 1
        for (Dsymbol p = this; p; p = p.parent)
367
        {
368 1
            message = p.depdecl ? p.depdecl.getMessage() : null;
369 1
            if (message)
370 1
                break;
371
        }
372 1
        if (message)
373 1
            deprecation(loc, "is deprecated - %s", message);
374
        else
375 1
            deprecation(loc, "is deprecated");
376

377 1
        return true;
378
    }
379

380
    /**********************************
381
     * Determine which Module a Dsymbol is in.
382
     */
383
    final Module getModule()
384
    {
385
        //printf("Dsymbol::getModule()\n");
386 1
        if (TemplateInstance ti = isInstantiated())
387 1
            return ti.tempdecl.getModule();
388 1
        Dsymbol s = this;
389 1
        while (s)
390
        {
391
            //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
392 1
            Module m = s.isModule();
393 1
            if (m)
394 1
                return m;
395 1
            s = s.parent;
396
        }
397 1
        return null;
398
    }
399

400
    /**********************************
401
     * Determine which Module a Dsymbol is in, as far as access rights go.
402
     */
403
    final Module getAccessModule()
404
    {
405
        //printf("Dsymbol::getAccessModule()\n");
406 1
        if (TemplateInstance ti = isInstantiated())
407 1
            return ti.tempdecl.getAccessModule();
408 1
        Dsymbol s = this;
409 1
        while (s)
410
        {
411
            //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
412 1
            Module m = s.isModule();
413 1
            if (m)
414 1
                return m;
415 1
            TemplateInstance ti = s.isTemplateInstance();
416 1
            if (ti && ti.enclosing)
417
            {
418
                /* Because of local template instantiation, the parent isn't where the access
419
                 * rights come from - it's the template declaration
420
                 */
421 0
                s = ti.tempdecl;
422
            }
423
            else
424 1
                s = s.parent;
425
        }
426 0
        return null;
427
    }
428

429
    /**
430
     * `pastMixin` returns the enclosing symbol if this is a template mixin.
431
     *
432
     * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
433
     * are mangleOnly.
434
     *
435
     * See also `parent`, `toParent` and `toParent2`.
436
     */
437
    final inout(Dsymbol) pastMixin() inout
438
    {
439
        //printf("Dsymbol::pastMixin() %s\n", toChars());
440 1
        if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
441 1
            return this;
442 1
        if (!parent)
443 0
            return null;
444 1
        return parent.pastMixin();
445
    }
446

447
    /**********************************
448
     * `parent` field returns a lexically enclosing scope symbol this is a member of.
449
     *
450
     * `toParent()` returns a logically enclosing scope symbol this is a member of.
451
     * It skips over TemplateMixin's.
452
     *
453
     * `toParent2()` returns an enclosing scope symbol this is living at runtime.
454
     * It skips over both TemplateInstance's and TemplateMixin's.
455
     * It's used when looking for the 'this' pointer of the enclosing function/class.
456
     *
457
     * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
458
     * instead of the instantiation scope.
459
     *
460
     * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
461
     * if a template declaration is non-local i.e. global or static.
462
     *
463
     * Examples:
464
     * ---
465
     *  module mod;
466
     *  template Foo(alias a) { mixin Bar!(); }
467
     *  mixin template Bar() {
468
     *    public {  // ProtDeclaration
469
     *      void baz() { a = 2; }
470
     *    }
471
     *  }
472
     *  void test() {
473
     *    int v = 1;
474
     *    alias foo = Foo!(v);
475
     *    foo.baz();
476
     *    assert(v == 2);
477
     *  }
478
     *
479
     *  // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
480
     *  // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
481
     *  // s.toParent() == TemplateInstance('mod.test.Foo!()')
482
     *  // s.toParent2() == FuncDeclaration('mod.test')
483
     *  // s.toParentDecl() == Module('mod')
484
     *  // s.toParentLocal() == FuncDeclaration('mod.test')
485
     * ---
486
     */
487
    final inout(Dsymbol) toParent() inout
488
    {
489 1
        return parent ? parent.pastMixin() : null;
490
    }
491

492
    /// ditto
493
    final inout(Dsymbol) toParent2() inout
494
    {
495 1
        if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
496 1
            return parent;
497 1
        return parent.toParent2;
498
    }
499

500
    /// ditto
501
    final inout(Dsymbol) toParentDecl() inout
502
    {
503 1
        return toParentDeclImpl(false);
504
    }
505

506
    /// ditto
507
    final inout(Dsymbol) toParentLocal() inout
508
    {
509 1
        return toParentDeclImpl(true);
510
    }
511

512
    private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout
513
    {
514 1
        auto p = toParent();
515 1
        if (!p || !p.isTemplateInstance())
516 1
            return p;
517 1
        auto ti = p.isTemplateInstance();
518 1
        if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic))
519 1
            return ti.tempdecl.toParentDeclImpl(localOnly);
520 1
        return parent.toParentDeclImpl(localOnly);
521
    }
522

523
    /**
524
     * Returns the declaration scope scope of `this` unless any of the symbols
525
     * `p1` or `p2` resides in its enclosing instantiation scope then the
526
     * latter is returned.
527
     */
528
    final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null)
529
    {
530 1
        return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal();
531
    }
532

533
    final inout(TemplateInstance) isInstantiated() inout
534
    {
535 1
        if (!parent)
536 1
            return null;
537 1
        auto ti = parent.isTemplateInstance();
538 1
        if (ti && !ti.isTemplateMixin())
539 1
            return ti;
540 1
        return parent.isInstantiated();
541
    }
542

543
    /***
544
     * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
545
     * instantiation scope of `this`.
546
     */
547
    final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null)
548
    {
549
        static bool has2This(Dsymbol s)
550
        {
551 1
            if (auto f = s.isFuncDeclaration())
552 1
                return f.isThis2;
553 1
            if (auto ad = s.isAggregateDeclaration())
554 1
                return ad.vthis2 !is null;
555 1
            return false;
556
        }
557

558 1
        if (has2This(this))
559
        {
560 1
            assert(p1);
561 1
            auto outer = toParent();
562 1
            while (outer)
563
            {
564 1
                auto ti = outer.isTemplateInstance();
565 1
                if (!ti)
566 1
                    break;
567 1
                foreach (oarg; *ti.tiargs)
568
                {
569 1
                    auto sa = getDsymbol(oarg);
570 1
                    if (!sa)
571 0
                        continue;
572 1
                    sa = sa.toAlias().toParent2();
573 1
                    if (!sa)
574 0
                        continue;
575 1
                    if (sa == p1)
576 1
                        return true;
577 1
                    else if (p2 && sa == p2)
578 1
                        return true;
579
                }
580 1
                outer = ti.tempdecl.toParent();
581
            }
582 1
            return false;
583
        }
584 1
        return false;
585
    }
586

587
    // Check if this function is a member of a template which has only been
588
    // instantiated speculatively, eg from inside is(typeof()).
589
    // Return the speculative template instance it is part of,
590
    // or NULL if not speculative.
591
    final inout(TemplateInstance) isSpeculative() inout
592
    {
593 1
        if (!parent)
594 0
            return null;
595 1
        auto ti = parent.isTemplateInstance();
596 1
        if (ti && ti.gagged)
597 1
            return ti;
598 1
        if (!parent.toParent())
599 1
            return null;
600 1
        return parent.isSpeculative();
601
    }
602

603
    final Ungag ungagSpeculative() const
604
    {
605 1
        uint oldgag = global.gag;
606 1
        if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
607 1
            global.gag = 0;
608 1
        return Ungag(oldgag);
609
    }
610

611
    // kludge for template.isSymbol()
612
    override final DYNCAST dyncast() const
613
    {
614 1
        return DYNCAST.dsymbol;
615
    }
616

617
    /*************************************
618
     * Do syntax copy of an array of Dsymbol's.
619
     */
620
    extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a)
621
    {
622 1
        Dsymbols* b = null;
623 1
        if (a)
624
        {
625 1
            b = a.copy();
626 1
            for (size_t i = 0; i < b.dim; i++)
627
            {
628 1
                (*b)[i] = (*b)[i].syntaxCopy(null);
629
            }
630
        }
631 1
        return b;
632
    }
633

634
    Identifier getIdent()
635
    {
636 1
        return ident;
637
    }
638

639
    const(char)* toPrettyChars(bool QualifyTypes = false)
640
    {
641 1
        if (prettystring && !QualifyTypes)
642 1
            return prettystring;
643

644
        //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
645 1
        if (!parent)
646
        {
647 1
            auto s = toChars();
648 1
            if (!QualifyTypes)
649 1
                prettystring = s;
650 1
            return s;
651
        }
652

653
        // Computer number of components
654 1
        size_t complength = 0;
655 1
        for (Dsymbol p = this; p; p = p.parent)
656 1
            ++complength;
657

658
        // Allocate temporary array comp[]
659
        alias T = const(char)[];
660 1
        auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
661 1
        auto comp = compptr[0 .. complength];
662

663
        // Fill in comp[] and compute length of final result
664 1
        size_t length = 0;
665 1
        int i;
666 1
        for (Dsymbol p = this; p; p = p.parent)
667
        {
668 1
            const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
669 1
            const len = strlen(s);
670 1
            comp[i] = s[0 .. len];
671 1
            ++i;
672 1
            length += len + 1;
673
        }
674

675 1
        auto s = cast(char*)mem.xmalloc_noscan(length);
676 1
        auto q = s + length - 1;
677 1
        *q = 0;
678 1
        foreach (j; 0 .. complength)
679
        {
680 1
            const t = comp[j].ptr;
681 1
            const len = comp[j].length;
682 1
            q -= len;
683 1
            memcpy(q, t, len);
684 1
            if (q == s)
685 1
                break;
686 1
            *--q = '.';
687
        }
688 1
        free(comp.ptr);
689 1
        if (!QualifyTypes)
690 1
            prettystring = s;
691 1
        return s;
692
    }
693

694
    const(char)* kind() const pure nothrow @nogc @safe
695
    {
696 0
        return "symbol";
697
    }
698

699
    /*********************************
700
     * If this symbol is really an alias for another,
701
     * return that other.
702
     * If needed, semantic() is invoked due to resolve forward reference.
703
     */
704
    Dsymbol toAlias()
705
    {
706 1
        return this;
707
    }
708

709
    /*********************************
710
     * Resolve recursive tuple expansion in eponymous template.
711
     */
712
    Dsymbol toAlias2()
713
    {
714 1
        return toAlias();
715
    }
716

717
    void addMember(Scope* sc, ScopeDsymbol sds)
718
    {
719
        //printf("Dsymbol::addMember('%s')\n", toChars());
720
        //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
721
        //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
722 1
        parent = sds;
723 1
        if (isAnonymous()) // no name, so can't add it to symbol table
724 1
            return;
725

726 1
        if (!sds.symtabInsert(this)) // if name is already defined
727
        {
728 1
            if (isAliasDeclaration() && !_scope)
729 1
                setScope(sc);
730 1
            Dsymbol s2 = sds.symtabLookup(this,ident);
731 1
            if (!s2.overloadInsert(this))
732
            {
733 1
                sds.multiplyDefined(Loc.initial, this, s2);
734 1
                errors = true;
735
            }
736
        }
737 1
        if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
738
        {
739 1
            if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
740
            {
741 0
                error("`.%s` property cannot be redefined", ident.toChars());
742 0
                errors = true;
743
            }
744
        }
745
    }
746

747
    /*************************************
748
     * Set scope for future semantic analysis so we can
749
     * deal better with forward references.
750
     */
751
    void setScope(Scope* sc)
752
    {
753
        //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
754 1
        if (!sc.nofree)
755 1
            sc.setNoFree(); // may need it even after semantic() finishes
756 1
        _scope = sc;
757 1
        if (sc.depdecl)
758 1
            depdecl = sc.depdecl;
759 1
        if (!userAttribDecl)
760 1
            userAttribDecl = sc.userAttribDecl;
761
    }
762

763
    void importAll(Scope* sc)
764
    {
765
    }
766

767
    /*********************************************
768
     * Search for ident as member of s.
769
     * Params:
770
     *  loc = location to print for error messages
771
     *  ident = identifier to search for
772
     *  flags = IgnoreXXXX
773
     * Returns:
774
     *  null if not found
775
     */
776
    Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
777
    {
778
        //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
779 1
        return null;
780
    }
781

782
    extern (D) final Dsymbol search_correct(Identifier ident)
783
    {
784
        /***************************************************
785
         * Search for symbol with correct spelling.
786
         */
787
        extern (D) Dsymbol symbol_search_fp(const(char)[] seed, ref int cost)
788
        {
789
            /* If not in the lexer's string table, it certainly isn't in the symbol table.
790
             * Doing this first is a lot faster.
791
             */
792 1
            if (!seed.length)
793 0
                return null;
794 1
            Identifier id = Identifier.lookup(seed);
795 1
            if (!id)
796 1
                return null;
797 1
            cost = 0;
798 1
            Dsymbol s = this;
799 1
            Module.clearCache();
800 1
            return s.search(Loc.initial, id, IgnoreErrors);
801
        }
802

803 1
        if (global.gag)
804 1
            return null; // don't do it for speculative compiles; too time consuming
805
        // search for exact name first
806 1
        if (auto s = search(Loc.initial, ident, IgnoreErrors))
807 1
            return s;
808 1
        return speller!symbol_search_fp(ident.toString());
809
    }
810

811
    /***************************************
812
     * Search for identifier id as a member of `this`.
813
     * `id` may be a template instance.
814
     *
815
     * Params:
816
     *  loc = location to print the error messages
817
     *  sc = the scope where the symbol is located
818
     *  id = the id of the symbol
819
     *  flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
820
     *
821
     * Returns:
822
     *      symbol found, NULL if not
823
     */
824
    extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
825
    {
826
        //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
827 1
        Dsymbol s = toAlias();
828 1
        Dsymbol sm;
829 1
        if (Declaration d = s.isDeclaration())
830
        {
831 1
            if (d.inuse)
832
            {
833 1
                .error(loc, "circular reference to `%s`", d.toPrettyChars());
834 1
                return null;
835
            }
836
        }
837 1
        switch (id.dyncast())
838
        {
839 1
        case DYNCAST.identifier:
840 1
            sm = s.search(loc, cast(Identifier)id, flags);
841 1
            break;
842 1
        case DYNCAST.dsymbol:
843
            {
844
                // It's a template instance
845
                //printf("\ttemplate instance id\n");
846 1
                Dsymbol st = cast(Dsymbol)id;
847 1
                TemplateInstance ti = st.isTemplateInstance();
848 1
                sm = s.search(loc, ti.name);
849 1
                if (!sm)
850
                {
851 1
                    sm = s.search_correct(ti.name);
852 1
                    if (sm)
853 1
                        .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());
854
                    else
855 1
                        .error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars());
856 1
                    return null;
857
                }
858 1
                sm = sm.toAlias();
859 1
                TemplateDeclaration td = sm.isTemplateDeclaration();
860 1
                if (!td)
861
                {
862 1
                    .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
863 1
                    return null;
864
                }
865 1
                ti.tempdecl = td;
866 1
                if (!ti.semanticRun)
867 1
                    ti.dsymbolSemantic(sc);
868 1
                sm = ti.toAlias();
869 1
                break;
870
            }
871 0
        case DYNCAST.type:
872 0
        case DYNCAST.expression:
873 0
        default:
874 0
            assert(0);
875
        }
876 1
        return sm;
877
    }
878

879
    bool overloadInsert(Dsymbol s)
880
    {
881
        //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
882 1
        return false;
883
    }
884

885
    /*********************************
886
     * Returns:
887
     *  SIZE_INVALID when the size cannot be determined
888
     */
889
    d_uns64 size(const ref Loc loc)
890
    {
891 0
        error("Dsymbol `%s` has no size", toChars());
892 0
        return SIZE_INVALID;
893
    }
894

895
    bool isforwardRef()
896
    {
897 0
        return false;
898
    }
899

900
    // is a 'this' required to access the member
901
    inout(AggregateDeclaration) isThis() inout
902
    {
903 1
        return null;
904
    }
905

906
    // is Dsymbol exported?
907
    bool isExport() const
908
    {
909 0
        return false;
910
    }
911

912
    // is Dsymbol imported?
913
    bool isImportedSymbol() const
914
    {
915 1
        return false;
916
    }
917

918
    // is Dsymbol deprecated?
919
    bool isDeprecated() const
920
    {
921 1
        return false;
922
    }
923

924
    bool isOverloadable() const
925
    {
926 1
        return false;
927
    }
928

929
    // is this a LabelDsymbol()?
930
    LabelDsymbol isLabel()
931
    {
932 1
        return null;
933
    }
934

935
    /// Returns an AggregateDeclaration when toParent() is that.
936
    final inout(AggregateDeclaration) isMember() inout
937
    {
938
        //printf("Dsymbol::isMember() %s\n", toChars());
939 1
        auto p = toParent();
940
        //printf("parent is %s %s\n", p.kind(), p.toChars());
941 1
        return p ? p.isAggregateDeclaration() : null;
942
    }
943

944
    /// Returns an AggregateDeclaration when toParent2() is that.
945
    final inout(AggregateDeclaration) isMember2() inout
946
    {
947
        //printf("Dsymbol::isMember2() '%s'\n", toChars());
948 1
        auto p = toParent2();
949
        //printf("parent is %s %s\n", p.kind(), p.toChars());
950 1
        return p ? p.isAggregateDeclaration() : null;
951
    }
952

953
    /// Returns an AggregateDeclaration when toParentDecl() is that.
954
    final inout(AggregateDeclaration) isMemberDecl() inout
955
    {
956
        //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
957 1
        auto p = toParentDecl();
958
        //printf("parent is %s %s\n", p.kind(), p.toChars());
959 1
        return p ? p.isAggregateDeclaration() : null;
960
    }
961

962
    /// Returns an AggregateDeclaration when toParentLocal() is that.
963
    final inout(AggregateDeclaration) isMemberLocal() inout
964
    {
965
        //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
966 1
        auto p = toParentLocal();
967
        //printf("parent is %s %s\n", p.kind(), p.toChars());
968 1
        return p ? p.isAggregateDeclaration() : null;
969
    }
970

971
    // is this a member of a ClassDeclaration?
972
    final ClassDeclaration isClassMember()
973
    {
974 1
        auto ad = isMember();
975 1
        return ad ? ad.isClassDeclaration() : null;
976
    }
977

978
    // is this a type?
979
    Type getType()
980
    {
981 1
        return null;
982
    }
983

984
    // need a 'this' pointer?
985
    bool needThis()
986
    {
987 1
        return false;
988
    }
989

990
    /*************************************
991
     */
992
    Prot prot() pure nothrow @nogc @safe
993
    {
994 1
        return Prot(Prot.Kind.public_);
995
    }
996

997
    /**************************************
998
     * Copy the syntax.
999
     * Used for template instantiations.
1000
     * If s is NULL, allocate the new object, otherwise fill it in.
1001
     */
1002
    Dsymbol syntaxCopy(Dsymbol s)
1003
    {
1004 0
        printf("%s %s\n", kind(), toChars());
1005 0
        assert(0);
1006
    }
1007

1008
    /**************************************
1009
     * Determine if this symbol is only one.
1010
     * Returns:
1011
     *      false, *ps = NULL: There are 2 or more symbols
1012
     *      true,  *ps = NULL: There are zero symbols
1013
     *      true,  *ps = symbol: The one and only one symbol
1014
     */
1015
    bool oneMember(Dsymbol* ps, Identifier ident)
1016
    {
1017
        //printf("Dsymbol::oneMember()\n");
1018 1
        *ps = this;
1019 1
        return true;
1020
    }
1021

1022
    /*****************************************
1023
     * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
1024
     */
1025
    extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
1026
    {
1027
        //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
1028 1
        Dsymbol s = null;
1029 1
        if (!members)
1030
        {
1031 1
            *ps = null;
1032 1
            return true;
1033
        }
1034

1035 1
        for (size_t i = 0; i < members.dim; i++)
1036
        {
1037 1
            Dsymbol sx = (*members)[i];
1038 1
            bool x = sx.oneMember(ps, ident);
1039
            //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
1040 1
            if (!x)
1041
            {
1042
                //printf("\tfalse 1\n");
1043 1
                assert(*ps is null);
1044 1
                return false;
1045
            }
1046 1
            if (*ps)
1047
            {
1048 1
                assert(ident);
1049 1
                if (!(*ps).ident || !(*ps).ident.equals(ident))
1050 1
                    continue;
1051 1
                if (!s)
1052 1
                    s = *ps;
1053 1
                else if (s.isOverloadable() && (*ps).isOverloadable())
1054
                {
1055
                    // keep head of overload set
1056 1
                    FuncDeclaration f1 = s.isFuncDeclaration();
1057 1
                    FuncDeclaration f2 = (*ps).isFuncDeclaration();
1058 1
                    if (f1 && f2)
1059
                    {
1060 1
                        assert(!f1.isFuncAliasDeclaration());
1061 1
                        assert(!f2.isFuncAliasDeclaration());
1062 1
                        for (; f1 != f2; f1 = f1.overnext0)
1063
                        {
1064 1
                            if (f1.overnext0 is null)
1065
                            {
1066 1
                                f1.overnext0 = f2;
1067 1
                                break;
1068
                            }
1069
                        }
1070
                    }
1071
                }
1072
                else // more than one symbol
1073
                {
1074 0
                    *ps = null;
1075
                    //printf("\tfalse 2\n");
1076 0
                    return false;
1077
                }
1078
            }
1079
        }
1080 1
        *ps = s; // s is the one symbol, null if none
1081
        //printf("\ttrue\n");
1082 1
        return true;
1083
    }
1084

1085
    void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion)
1086
    {
1087
    }
1088

1089
    /*****************************************
1090
     * Is Dsymbol a variable that contains pointers?
1091
     */
1092
    bool hasPointers()
1093
    {
1094
        //printf("Dsymbol::hasPointers() %s\n", toChars());
1095 1
        return false;
1096
    }
1097

1098
    bool hasStaticCtorOrDtor()
1099
    {
1100
        //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
1101 1
        return false;
1102
    }
1103

1104
    void addLocalClass(ClassDeclarations*)
1105
    {
1106
    }
1107

1108
    void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
1109
    {
1110
    }
1111

1112
    void checkCtorConstInit()
1113
    {
1114
    }
1115

1116
    /****************************************
1117
     * Add documentation comment to Dsymbol.
1118
     * Ignore NULL comments.
1119
     */
1120
    void addComment(const(char)* comment)
1121
    {
1122
        //if (comment)
1123
        //    printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
1124 1
        if (!this.comment)
1125 1
            this.comment = comment;
1126 1
        else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
1127
        {
1128
            // Concatenate the two
1129 1
            this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true);
1130
        }
1131
    }
1132

1133
    /****************************************
1134
     * Returns true if this symbol is defined in a non-root module without instantiation.
1135
     */
1136
    final bool inNonRoot()
1137
    {
1138 1
        Dsymbol s = parent;
1139 1
        for (; s; s = s.toParent())
1140
        {
1141 1
            if (auto ti = s.isTemplateInstance())
1142
            {
1143 1
                return false;
1144
            }
1145 1
            if (auto m = s.isModule())
1146
            {
1147 1
                if (!m.isRoot())
1148 1
                    return true;
1149 1
                break;
1150
            }
1151
        }
1152 1
        return false;
1153
    }
1154

1155
    /************
1156
     */
1157
    override void accept(Visitor v)
1158
    {
1159 0
        v.visit(this);
1160
    }
1161

1162
  pure nothrow @safe @nogc:
1163

1164
    // Eliminate need for dynamic_cast
1165 1
    inout(Package)                     isPackage()                     inout { return null; }
1166 1
    inout(Module)                      isModule()                      inout { return null; }
1167 1
    inout(EnumMember)                  isEnumMember()                  inout { return null; }
1168 1
    inout(TemplateDeclaration)         isTemplateDeclaration()         inout { return null; }
1169 1
    inout(TemplateInstance)            isTemplateInstance()            inout { return null; }
1170 1
    inout(TemplateMixin)               isTemplateMixin()               inout { return null; }
1171 1
    inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
1172 1
    inout(Nspace)                      isNspace()                      inout { return null; }
1173 1
    inout(Declaration)                 isDeclaration()                 inout { return null; }
1174 1
    inout(StorageClassDeclaration)     isStorageClassDeclaration()     inout { return null; }
1175 1
    inout(ExpressionDsymbol)           isExpressionDsymbol()           inout { return null; }
1176 1
    inout(ThisDeclaration)             isThisDeclaration()             inout { return null; }
1177 1
    inout(TypeInfoDeclaration)         isTypeInfoDeclaration()         inout { return null; }
1178 1
    inout(TupleDeclaration)            isTupleDeclaration()            inout { return null; }
1179 1
    inout(AliasDeclaration)            isAliasDeclaration()            inout { return null; }
1180 1
    inout(AggregateDeclaration)        isAggregateDeclaration()        inout { return null; }
1181 1
    inout(FuncDeclaration)             isFuncDeclaration()             inout { return null; }
1182 1
    inout(FuncAliasDeclaration)        isFuncAliasDeclaration()        inout { return null; }
1183 1
    inout(OverDeclaration)             isOverDeclaration()             inout { return null; }
1184 1
    inout(FuncLiteralDeclaration)      isFuncLiteralDeclaration()      inout { return null; }
1185 1
    inout(CtorDeclaration)             isCtorDeclaration()             inout { return null; }
1186 1
    inout(PostBlitDeclaration)         isPostBlitDeclaration()         inout { return null; }
1187 1
    inout(DtorDeclaration)             isDtorDeclaration()             inout { return null; }
1188 1
    inout(StaticCtorDeclaration)       isStaticCtorDeclaration()       inout { return null; }
1189 1
    inout(StaticDtorDeclaration)       isStaticDtorDeclaration()       inout { return null; }
1190 1
    inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
1191 1
    inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
1192 1
    inout(InvariantDeclaration)        isInvariantDeclaration()        inout { return null; }
1193 1
    inout(UnitTestDeclaration)         isUnitTestDeclaration()         inout { return null; }
1194 1
    inout(NewDeclaration)              isNewDeclaration()              inout { return null; }
1195 1
    inout(VarDeclaration)              isVarDeclaration()              inout { return null; }
1196 1
    inout(VersionSymbol)               isVersionSymbol()               inout { return null; }
1197 1
    inout(DebugSymbol)                 isDebugSymbol()                 inout { return null; }
1198 1
    inout(ClassDeclaration)            isClassDeclaration()            inout { return null; }
1199 1
    inout(StructDeclaration)           isStructDeclaration()           inout { return null; }
1200 1
    inout(UnionDeclaration)            isUnionDeclaration()            inout { return null; }
1201 1
    inout(InterfaceDeclaration)        isInterfaceDeclaration()        inout { return null; }
1202 1
    inout(ScopeDsymbol)                isScopeDsymbol()                inout { return null; }
1203 1
    inout(ForwardingScopeDsymbol)      isForwardingScopeDsymbol()      inout { return null; }
1204 1
    inout(WithScopeSymbol)             isWithScopeSymbol()             inout { return null; }
1205 1
    inout(ArrayScopeSymbol)            isArrayScopeSymbol()            inout { return null; }
1206 1
    inout(Import)                      isImport()                      inout { return null; }
1207 1
    inout(EnumDeclaration)             isEnumDeclaration()             inout { return null; }
1208 0
    inout(SymbolDeclaration)           isSymbolDeclaration()           inout { return null; }
1209 1
    inout(AttribDeclaration)           isAttribDeclaration()           inout { return null; }
1210 1
    inout(AnonDeclaration)             isAnonDeclaration()             inout { return null; }
1211 1
    inout(CPPNamespaceDeclaration)     isCPPNamespaceDeclaration()     inout { return null; }
1212 1
    inout(ProtDeclaration)             isProtDeclaration()             inout { return null; }
1213 1
    inout(OverloadSet)                 isOverloadSet()                 inout { return null; }
1214 1
    inout(CompileDeclaration)          isCompileDeclaration()          inout { return null; }
1215
}
1216

1217
/***********************************************************
1218
 * Dsymbol that generates a scope
1219
 */
1220
extern (C++) class ScopeDsymbol : Dsymbol
1221
{
1222
    Dsymbols* members;          // all Dsymbol's in this scope
1223
    DsymbolTable symtab;        // members[] sorted into table
1224
    uint endlinnum;             // the linnumber of the statement after the scope (0 if unknown)
1225

1226
private:
1227
    /// symbols whose members have been imported, i.e. imported modules and template mixins
1228
    Dsymbols* importedScopes;
1229
    Prot.Kind* prots;            // array of Prot.Kind, one for each import
1230

1231
    import dmd.root.bitarray;
1232
    BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
1233

1234
public:
1235 1
    final extern (D) this()
1236
    {
1237
    }
1238

1239 1
    final extern (D) this(Identifier ident)
1240
    {
1241 1
        super(ident);
1242
    }
1243

1244 1
    final extern (D) this(const ref Loc loc, Identifier ident)
1245
    {
1246 1
        super(loc, ident);
1247
    }
1248

1249
    override Dsymbol syntaxCopy(Dsymbol s)
1250
    {
1251
        //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
1252 1
        ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
1253 1
        sds.comment = comment;
1254 1
        sds.members = arraySyntaxCopy(members);
1255 1
        sds.endlinnum = endlinnum;
1256 1
        return sds;
1257
    }
1258

1259
    /*****************************************
1260
     * This function is #1 on the list of functions that eat cpu time.
1261
     * Be very, very careful about slowing it down.
1262
     */
1263
    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1264
    {
1265
        //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
1266
        //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
1267

1268
        // Look in symbols declared in this module
1269 1
        if (symtab && !(flags & SearchImportsOnly))
1270
        {
1271
            //printf(" look in locals\n");
1272 1
            auto s1 = symtab.lookup(ident);
1273 1
            if (s1)
1274
            {
1275
                //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
1276 1
                return s1;
1277
            }
1278
        }
1279
        //printf(" not found in locals\n");
1280

1281
        // Look in imported scopes
1282 1
        if (!importedScopes)
1283 1
            return null;
1284

1285
        //printf(" look in imports\n");
1286 1
        Dsymbol s = null;
1287 1
        OverloadSet a = null;
1288
        // Look in imported modules
1289 1
        for (size_t i = 0; i < importedScopes.dim; i++)
1290
        {
1291
            // If private import, don't search it
1292 1
            if ((flags & IgnorePrivateImports) && prots[i] == Prot.Kind.private_)
1293 1
                continue;
1294 1
            int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
1295 1
            Dsymbol ss = (*importedScopes)[i];
1296
            //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss.toChars(), prots[i], ss.isModule(), ss.isImport());
1297

1298 1
            if (ss.isModule())
1299
            {
1300 1
                if (flags & SearchLocalsOnly)
1301 1
                    continue;
1302
            }
1303
            else // mixin template
1304
            {
1305 1
                if (flags & SearchImportsOnly)
1306 1
                    continue;
1307

1308 1
                sflags |= SearchLocalsOnly;
1309
            }
1310

1311
            /* Don't find private members if ss is a module
1312
             */
1313 1
            Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
1314
            import dmd.access : symbolIsVisible;
1315 1
            if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
1316 1
                continue;
1317 1
            if (!s)
1318
            {
1319 1
                s = s2;
1320 1
                if (s && s.isOverloadSet())
1321 1
                    a = mergeOverloadSet(ident, a, s);
1322
            }
1323 1
            else if (s2 && s != s2)
1324
            {
1325 1
                if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
1326
                {
1327
                    /* After following aliases, we found the same
1328
                     * symbol, so it's not an ambiguity.  But if one
1329
                     * alias is deprecated or less accessible, prefer
1330
                     * the other.
1331
                     */
1332 1
                    if (s.isDeprecated() || s.prot().isMoreRestrictiveThan(s2.prot()) && s2.prot().kind != Prot.Kind.none)
1333 1
                        s = s2;
1334
                }
1335
                else
1336
                {
1337
                    /* Two imports of the same module should be regarded as
1338
                     * the same.
1339
                     */
1340 1
                    Import i1 = s.isImport();
1341 1
                    Import i2 = s2.isImport();
1342 1
                    if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
1343
                    {
1344
                        /* https://issues.dlang.org/show_bug.cgi?id=8668
1345
                         * Public selective import adds AliasDeclaration in module.
1346
                         * To make an overload set, resolve aliases in here and
1347
                         * get actual overload roots which accessible via s and s2.
1348
                         */
1349 1
                        s = s.toAlias();
1350 1
                        s2 = s2.toAlias();
1351
                        /* If both s2 and s are overloadable (though we only
1352
                         * need to check s once)
1353
                         */
1354

1355 1
                        auto so2 = s2.isOverloadSet();
1356 1
                        if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
1357
                        {
1358 1
                            if (symbolIsVisible(this, s2))
1359
                            {
1360 1
                                a = mergeOverloadSet(ident, a, s2);
1361
                            }
1362 1
                            if (!symbolIsVisible(this, s))
1363 0
                                s = s2;
1364 1
                            continue;
1365
                        }
1366

1367
                        /* Two different overflow sets can have the same members
1368
                         * https://issues.dlang.org/show_bug.cgi?id=16709
1369
                         */
1370 1
                        auto so = s.isOverloadSet();
1371 1
                        if (so && so2)
1372
                        {
1373 1
                            if (so.a.length == so2.a.length)
1374
                            {
1375 1
                                foreach (j; 0 .. so.a.length)
1376
                                {
1377 1
                                    if (so.a[j] !is so2.a[j])
1378 0
                                        goto L1;
1379
                                }
1380 1
                                continue;  // the same
1381
                              L1:
1382
                                {   } // different
1383
                            }
1384
                        }
1385

1386 1
                        if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
1387 0
                            return null;
1388 1
                        if (!(flags & IgnoreErrors))
1389 1
                            ScopeDsymbol.multiplyDefined(loc, s, s2);
1390 1
                        break;
1391
                    }
1392
                }
1393
            }
1394
        }
1395 1
        if (s)
1396
        {
1397
            /* Build special symbol if we had multiple finds
1398
             */
1399 1
            if (a)
1400
            {
1401 1
                if (!s.isOverloadSet())
1402 1
                    a = mergeOverloadSet(ident, a, s);
1403 1
                s = a;
1404
            }
1405
            //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
1406 1
            return s;
1407
        }
1408
        //printf(" not found in imports\n");
1409 1
        return null;
1410
    }
1411

1412
    extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
1413
    {
1414 1
        if (!os)
1415
        {
1416 1
            os = new OverloadSet(ident);
1417 1
            os.parent = this;
1418
        }
1419 1
        if (OverloadSet os2 = s.isOverloadSet())
1420
        {
1421
            // Merge the cross-module overload set 'os2' into 'os'
1422 1
            if (os.a.dim == 0)
1423
            {
1424 1
                os.a.setDim(os2.a.dim);
1425 1
                memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
1426
            }
1427
            else
1428
            {
1429 1
                for (size_t i = 0; i < os2.a.dim; i++)
1430
                {
1431 1
                    os = mergeOverloadSet(ident, os, os2.a[i]);
1432
                }
1433
            }
1434
        }
1435
        else
1436
        {
1437 1
            assert(s.isOverloadable());
1438
            /* Don't add to os[] if s is alias of previous sym
1439
             */
1440 1
            for (size_t j = 0; j < os.a.dim; j++)
1441
            {
1442 1
                Dsymbol s2 = os.a[j];
1443 1
                if (s.toAlias() == s2.toAlias())
1444
                {
1445 1
                    if (s2.isDeprecated() || (s2.prot().isMoreRestrictiveThan(s.prot()) && s.prot().kind != Prot.Kind.none))
1446
                    {
1447 0
                        os.a[j] = s;
1448
                    }
1449 1
                    goto Lcontinue;
1450
                }
1451
            }
1452 1
            os.push(s);
1453
        Lcontinue:
1454
        }
1455 1
        return os;
1456
    }
1457

1458
    void importScope(Dsymbol s, Prot protection)
1459
    {
1460
        //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), protection);
1461
        // No circular or redundant import's
1462 1
        if (s != this)
1463
        {
1464 1
            if (!importedScopes)
1465 1
                importedScopes = new Dsymbols();
1466
            else
1467
            {
1468 1
                for (size_t i = 0; i < importedScopes.dim; i++)
1469
                {
1470 1
                    Dsymbol ss = (*importedScopes)[i];
1471 1
                    if (ss == s) // if already imported
1472
                    {
1473 1
                        if (protection.kind > prots[i])
1474 0
                            prots[i] = protection.kind; // upgrade access
1475 1
                        return;
1476
                    }
1477
                }
1478
            }
1479 1
            importedScopes.push(s);
1480 1
            prots = cast(Prot.Kind*)mem.xrealloc(prots, importedScopes.dim * (prots[0]).sizeof);
1481 1
            prots[importedScopes.dim - 1] = protection.kind;
1482
        }
1483
    }
1484

1485
    extern (D) final void addAccessiblePackage(Package p, Prot protection)
1486
    {
1487 1
        auto pary = protection.kind == Prot.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
1488 1
        if (pary.length <= p.tag)
1489 1
            pary.length = p.tag + 1;
1490 1
        (*pary)[p.tag] = true;
1491
    }
1492

1493
    bool isPackageAccessible(Package p, Prot protection, int flags = 0)
1494
    {
1495 1
        if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
1496 1
            protection.kind == Prot.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
1497 1
            return true;
1498 1
        foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
1499
        {
1500
            // only search visible scopes && imported modules should ignore private imports
1501 1
            if (protection.kind <= prots[i] &&
1502 1
                ss.isScopeDsymbol.isPackageAccessible(p, protection, IgnorePrivateImports))
1503 1
                return true;
1504
        }
1505 1
        return false;
1506
    }
1507

1508
    override final bool isforwardRef()
1509
    {
1510 1
        return (members is null);
1511
    }
1512

1513
    static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
1514
    {
1515
        version (none)
1516
        {
1517
            printf("ScopeDsymbol::multiplyDefined()\n");
1518
            printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
1519
            printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
1520
        }
1521 1
        if (loc.isValid())
1522
        {
1523 1
            .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s",
1524
                s1.kind(), s1.toPrettyChars(), s1.locToChars(),
1525
                s2.kind(), s2.toPrettyChars(), s2.locToChars());
1526

1527
            static if (0)
1528
            {
1529
                if (auto so = s1.isOverloadSet())
1530
                {
1531
                    printf("first %p:\n", so);
1532
                    foreach (s; so.a[])
1533
                    {
1534
                        printf("  %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1535
                    }
1536
                }
1537
                if (auto so = s2.isOverloadSet())
1538
                {
1539
                    printf("second %p:\n", so);
1540
                    foreach (s; so.a[])
1541
                    {
1542
                        printf("  %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
1543
                    }
1544
                }
1545
            }
1546
        }
1547
        else
1548
        {
1549 1
            s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
1550
        }
1551
    }
1552

1553
    override const(char)* kind() const
1554
    {
1555 0
        return "ScopeDsymbol";
1556
    }
1557

1558
    /*******************************************
1559
     * Look for member of the form:
1560
     *      const(MemberInfo)[] getMembers(string);
1561
     * Returns NULL if not found
1562
     */
1563
    final FuncDeclaration findGetMembers()
1564
    {
1565 1
        Dsymbol s = search_function(this, Id.getmembers);
1566 1
        FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
1567
        version (none)
1568
        {
1569
            // Finish
1570
            __gshared TypeFunction tfgetmembers;
1571
            if (!tfgetmembers)
1572
            {
1573
                Scope sc;
1574
                auto parameters = new Parameters();
1575
                Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
1576
                parameters.push(p);
1577
                Type tret = null;
1578
                tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
1579
                tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
1580
            }
1581
            if (fdx)
1582
                fdx = fdx.overloadExactMatch(tfgetmembers);
1583
        }
1584 1
        if (fdx && fdx.isVirtual())
1585 0
            fdx = null;
1586 1
        return fdx;
1587
    }
1588

1589
    Dsymbol symtabInsert(Dsymbol s)
1590
    {
1591 1
        return symtab.insert(s);
1592
    }
1593

1594
    /****************************************
1595
     * Look up identifier in symbol table.
1596
     */
1597

1598
    Dsymbol symtabLookup(Dsymbol s, Identifier id)
1599
    {
1600 1
        return symtab.lookup(id);
1601
    }
1602

1603
    /****************************************
1604
     * Return true if any of the members are static ctors or static dtors, or if
1605
     * any members have members that are.
1606
     */
1607
    override bool hasStaticCtorOrDtor()
1608
    {
1609 1
        if (members)
1610
        {
1611 1
            for (size_t i = 0; i < members.dim; i++)
1612
            {
1613 1
                Dsymbol member = (*members)[i];
1614 1
                if (member.hasStaticCtorOrDtor())
1615 0
                    return true;
1616
            }
1617
        }
1618 1
        return false;
1619
    }
1620

1621
    extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
1622

1623
    /***************************************
1624
     * Expands attribute declarations in members in depth first
1625
     * order. Calls dg(size_t symidx, Dsymbol *sym) for each
1626
     * member.
1627
     * If dg returns !=0, stops and returns that value else returns 0.
1628
     * Use this function to avoid the O(N + N^2/2) complexity of
1629
     * calculating dim and calling N times getNth.
1630
     * Returns:
1631
     *  last value returned by dg()
1632
     */
1633
    extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
1634
    {
1635 1
        assert(dg);
1636 1
        if (!members)
1637 1
            return 0;
1638 1
        size_t n = pn ? *pn : 0; // take over index
1639 1
        int result = 0;
1640 1
        foreach (size_t i; 0 .. members.dim)
1641
        {
1642 1
            Dsymbol s = (*members)[i];
1643 1
            if (AttribDeclaration a = s.isAttribDeclaration())
1644 1
                result = _foreach(sc, a.include(sc), dg, &n);
1645 1
            else if (TemplateMixin tm = s.isTemplateMixin())
1646 1
                result = _foreach(sc, tm.members, dg, &n);
1647 1
            else if (s.isTemplateInstance())
1648
            {
1649
            }
1650 1
            else if (s.isUnitTestDeclaration())
1651
            {
1652
            }
1653
            else
1654 1
                result = dg(n++, s);
1655 1
            if (result)
1656 0
                break;
1657
        }
1658 1
        if (pn)
1659 1
            *pn = n; // update index
1660 1
        return result;
1661
    }
1662

1663
    override final inout(ScopeDsymbol) isScopeDsymbol() inout
1664
    {
1665 1
        return this;
1666
    }
1667

1668
    override void accept(Visitor v)
1669
    {
1670 0
        v.visit(this);
1671
    }
1672
}
1673

1674
/***********************************************************
1675
 * With statement scope
1676
 */
1677
extern (C++) final class WithScopeSymbol : ScopeDsymbol
1678
{
1679
    WithStatement withstate;
1680

1681 1
    extern (D) this(WithStatement withstate)
1682
    {
1683 1
        this.withstate = withstate;
1684
    }
1685

1686
    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
1687
    {
1688
        //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
1689 1
        if (flags & SearchImportsOnly)
1690 1
            return null;
1691
        // Acts as proxy to the with class declaration
1692 1
        Dsymbol s = null;
1693 1
        Expression eold = null;
1694 1
        for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e))
1695
        {
1696 1
            if (e.op == TOK.scope_)
1697
            {
1698 1
                s = (cast(ScopeExp)e).sds;
1699
            }
1700 1
            else if (e.op == TOK.type)
1701
            {
1702 1
                s = e.type.toDsymbol(null);
1703
            }
1704
            else
1705
            {
1706 1
                Type t = e.type.toBasetype();
1707 1
                s = t.toDsymbol(null);
1708
            }
1709 1
            if (s)
1710
            {
1711 1
                s = s.search(loc, ident, flags);
1712 1
                if (s)
1713 1
                    return s;
1714
            }
1715 1
            eold = e;
1716
        }
1717 1
        return null;
1718
    }
1719

1720
    override inout(WithScopeSymbol) isWithScopeSymbol() inout
1721
    {
1722 1
        return this;
1723
    }
1724

1725
    override void accept(Visitor v)
1726
    {
1727 0
        v.visit(this);
1728
    }
1729
}
1730

1731
/***********************************************************
1732
 * Array Index/Slice scope
1733
 */
1734
extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
1735
{
1736
    // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
1737
    // Discriminated using DYNCAST and, for expressions, also TOK
1738
    private RootObject arrayContent;
1739
    Scope* sc;
1740

1741 1
    extern (D) this(Scope* sc, Expression exp)
1742
    {
1743 1
        super(exp.loc, null);
1744 1
        assert(exp.op == TOK.index || exp.op == TOK.slice || exp.op == TOK.array);
1745 1
        this.sc = sc;
1746 1
        this.arrayContent = exp;
1747
    }
1748

1749 1
    extern (D) this(Scope* sc, TypeTuple type)
1750
    {
1751 1
        this.sc = sc;
1752 1
        this.arrayContent = type;
1753
    }
1754

1755 1
    extern (D) this(Scope* sc, TupleDeclaration td)
1756
    {
1757 1
        this.sc = sc;
1758 1
        this.arrayContent = td;
1759
    }
1760

1761
    /// This override is used to solve `$`
1762
    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
1763
    {
1764
        //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
1765 1
        if (ident != Id.dollar)
1766 1
            return null;
1767

1768 1
        VarDeclaration* pvar;
1769 1
        Expression ce;
1770

1771
        static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
1772
        {
1773

1774
            /* $ gives the number of type entries in the type tuple
1775
             */
1776 1
            auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1777 1
            Expression e = new IntegerExp(Loc.initial, tt.arguments.dim, Type.tsize_t);
1778 1
            v._init = new ExpInitializer(Loc.initial, e);
1779 1
            v.storage_class |= STC.temp | STC.static_ | STC.const_;
1780 1
            v.dsymbolSemantic(sc);
1781 1
            return v;
1782
        }
1783

1784 1
        const DYNCAST kind = arrayContent.dyncast();
1785 1
        if (kind == DYNCAST.dsymbol)
1786
        {
1787 1
            TupleDeclaration td = cast(TupleDeclaration) arrayContent;
1788
            /* $ gives the number of elements in the tuple
1789
             */
1790 1
            auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
1791 1
            Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t);
1792 1
            v._init = new ExpInitializer(Loc.initial, e);
1793 1
            v.storage_class |= STC.temp | STC.static_ | STC.const_;
1794 1
            v.dsymbolSemantic(sc);
1795 1
            return v;
1796
        }
1797 1
        if (kind == DYNCAST.type)
1798
        {
1799 1
            return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
1800
        }
1801 1
        Expression exp = cast(Expression) arrayContent;
1802 1
        if (auto ie = exp.isIndexExp())
1803
        {
1804
            /* array[index] where index is some function of $
1805
             */
1806 1
            pvar = &ie.lengthVar;
1807 1
            ce = ie.e1;
1808
        }
1809 1
        else if (auto se = exp.isSliceExp())
1810
        {
1811
            /* array[lwr .. upr] where lwr or upr is some function of $
1812
             */
1813 1
            pvar = &se.lengthVar;
1814 1
            ce = se.e1;
1815
        }
1816 1
        else if (auto ae = exp.isArrayExp())
1817
        {
1818
            /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
1819
             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
1820
             */
1821 1
            pvar = &ae.lengthVar;
1822 1
            ce = ae.e1;
1823
        }
1824
        else
1825
        {
1826
            /* Didn't find $, look in enclosing scope(s).
1827
             */
1828 0
            return null;
1829
        }
1830 1
        ce = ce.lastComma();
1831
        /* If we are indexing into an array that is really a type
1832
         * tuple, rewrite this as an index into a type tuple and
1833
         * try again.
1834
         */
1835 1
        if (auto te = ce.isTypeExp())
1836
        {
1837 1
            if (auto ttp = te.type.isTypeTuple())
1838 1
                return dollarFromTypeTuple(loc, ttp, sc);
1839
        }
1840
        /* *pvar is lazily initialized, so if we refer to $
1841
         * multiple times, it gets set only once.
1842
         */
1843 1
        if (!*pvar) // if not already initialized
1844
        {
1845
            /* Create variable v and set it to the value of $
1846
             */
1847 1
            VarDeclaration v;
1848 1
            Type t;
1849 1
            if (auto tupexp = ce.isTupleExp())
1850
            {
1851
                /* It is for an expression tuple, so the
1852
                 * length will be a const.
1853
                 */
1854 1
                Expression e = new IntegerExp(Loc.initial, tupexp.exps.dim, Type.tsize_t);
1855 1
                v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
1856 1
                v.storage_class |= STC.temp | STC.static_ | STC.const_;
1857
            }
1858 1
            else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
1859
            {
1860
                // Look for opDollar
1861 1
                assert(exp.op == TOK.array || exp.op == TOK.slice);
1862 1
                AggregateDeclaration ad = isAggregate(t);
1863 1
                assert(ad);
1864 1
                Dsymbol s = ad.search(loc, Id.opDollar);
1865 1
                if (!s) // no dollar exists -- search in higher scope
1866 1
                    return null;
1867 1
                s = s.toAlias();
1868 1
                Expression e = null;
1869
                // Check for multi-dimensional opDollar(dim) template.
1870 1
                if (TemplateDeclaration td = s.isTemplateDeclaration())
1871
                {
1872 1
                    dinteger_t dim = 0;
1873 1
                    if (exp.op == TOK.array)
1874
                    {
1875 1
                        dim = (cast(ArrayExp)exp).currentDimension;
1876
                    }
1877 0
                    else if (exp.op == TOK.slice)
1878
                    {
1879 0
                        dim = 0; // slices are currently always one-dimensional
1880
                    }
1881
                    else
1882
                    {
1883 0
                        assert(0);
1884
                    }
1885 1
                    auto tiargs = new Objects();
1886 1
                    Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
1887 1
                    edim = edim.expressionSemantic(sc);
1888 1
                    tiargs.push(edim);
1889 1
                    e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
1890
                }
1891
                else
1892
                {
1893
                    /* opDollar exists, but it's not a template.
1894
                     * This is acceptable ONLY for single-dimension indexing.
1895
                     * Note that it's impossible to have both template & function opDollar,
1896
                     * because both take no arguments.
1897
                     */
1898 1
                    if (exp.op == TOK.array && (cast(ArrayExp)exp).arguments.dim != 1)
1899
                    {
1900 1
                        exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
1901 1
                        return null;
1902
                    }
1903 1
                    Declaration d = s.isDeclaration();
1904 1
                    assert(d);
1905 1
                    e = new DotVarExp(loc, ce, d);
1906
                }
1907 1
                e = e.expressionSemantic(sc);
1908 1
                if (!e.type)
1909 0
                    exp.error("`%s` has no value", e.toChars());
1910 1
                t = e.type.toBasetype();
1911 1
                if (t && t.ty == Tfunction)
1912 1
                    e = new CallExp(e.loc, e);
1913 1
                v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
1914 1
                v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
1915
            }
1916
            else
1917
            {
1918
                /* For arrays, $ will either be a compile-time constant
1919
                 * (in which case its value in set during constant-folding),
1920
                 * or a variable (in which case an expression is created in
1921
                 * toir.c).
1922
                 */
1923 1
                auto e = new VoidInitializer(Loc.initial);
1924 1
                e.type = Type.tsize_t;
1925 1
                v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
1926 1
                v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
1927
            }
1928 1
            *pvar = v;
1929
        }
1930 1
        (*pvar).dsymbolSemantic(sc);
1931 1
        return (*pvar);
1932
    }
1933

1934
    override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
1935
    {
1936 0
        return this;
1937
    }
1938

1939
    override void accept(Visitor v)
1940
    {
1941 0
        v.visit(this);
1942
    }
1943
}
1944

1945
/***********************************************************
1946
 * Overload Sets
1947
 */
1948
extern (C++) final class OverloadSet : Dsymbol
1949
{
1950
    Dsymbols a;     // array of Dsymbols
1951

1952 1
    extern (D) this(Identifier ident, OverloadSet os = null)
1953
    {
1954 1
        super(ident);
1955 1
        if (os)
1956
        {
1957 1
            a.pushSlice(os.a[]);
1958
        }
1959
    }
1960

1961
    void push(Dsymbol s)
1962
    {
1963 1
        a.push(s);
1964
    }
1965

1966
    override inout(OverloadSet) isOverloadSet() inout
1967
    {
1968 1
        return this;
1969
    }
1970

1971
    override const(char)* kind() const
1972
    {
1973 1
        return "overloadset";
1974
    }
1975

1976
    override void accept(Visitor v)
1977
    {
1978 1
        v.visit(this);
1979
    }
1980
}
1981

1982
/***********************************************************
1983
 * Forwarding ScopeDsymbol.  Used by ForwardingAttribDeclaration and
1984
 * ForwardingScopeDeclaration to forward symbol insertions to another
1985
 * scope.  See `dmd.attrib.ForwardingAttribDeclaration` for more
1986
 * details.
1987
 */
1988
extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
1989
{
1990
    /*************************
1991
     * Symbol to forward insertions to.
1992
     * Can be `null` before being lazily initialized.
1993
     */
1994
    ScopeDsymbol forward;
1995 1
    extern (D) this(ScopeDsymbol forward)
1996
    {
1997 1
        super(null);
1998 1
        this.forward = forward;
1999
    }
2000
    override Dsymbol symtabInsert(Dsymbol s)
2001
    {
2002 1
        assert(forward);
2003 1
        if (auto d = s.isDeclaration())
2004
        {
2005 1
            if (d.storage_class & STC.local)
2006
            {
2007
                // Symbols with storage class STC.local are not
2008
                // forwarded, but stored in the local symbol
2009
                // table. (Those are the `static foreach` variables.)
2010 1
                if (!symtab)
2011
                {
2012 0
                    symtab = new DsymbolTable();
2013
                }
2014 1
                return super.symtabInsert(s); // insert locally
2015
            }
2016
        }
2017 1
        if (!forward.symtab)
2018
        {
2019 1
            forward.symtab = new DsymbolTable();
2020
        }
2021
        // Non-STC.local symbols are forwarded to `forward`.
2022 1
        return forward.symtabInsert(s);
2023
    }
2024

2025
    /************************
2026
     * This override handles the following two cases:
2027
     *     static foreach (i, i; [0]) { ... }
2028
     * and
2029
     *     static foreach (i; [0]) { enum i = 2; }
2030
     */
2031
    override Dsymbol symtabLookup(Dsymbol s, Identifier id)
2032
    {
2033 1
        assert(forward);
2034
        // correctly diagnose clashing foreach loop variables.
2035 1
        if (auto d = s.isDeclaration())
2036
        {
2037 1
            if (d.storage_class & STC.local)
2038
            {
2039 1
                if (!symtab)
2040
                {
2041 0
                    symtab = new DsymbolTable();
2042
                }
2043 1
                return super.symtabLookup(s,id);
2044
            }
2045
        }
2046
        // Declarations within `static foreach` do not clash with
2047
        // `static foreach` loop variables.
2048 1
        if (!forward.symtab)
2049
        {
2050 0
            forward.symtab = new DsymbolTable();
2051
        }
2052 1
        return forward.symtabLookup(s,id);
2053
    }
2054

2055
    override void importScope(Dsymbol s, Prot protection)
2056
    {
2057 1
        forward.importScope(s, protection);
2058
    }
2059

2060 0
    override const(char)* kind()const{ return "local scope"; }
2061

2062
    override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout
2063
    {
2064 1
        return this;
2065
    }
2066

2067
}
2068

2069
/**
2070
 * Class that holds an expression in a Dsymbol wraper.
2071
 * This is not an AST node, but a class used to pass
2072
 * an expression as a function parameter of type Dsymbol.
2073
 */
2074
extern (C++) final class ExpressionDsymbol : Dsymbol
2075
{
2076
    Expression exp;
2077 1
    this(Expression exp)
2078
    {
2079 1
        super();
2080 1
        this.exp = exp;
2081
    }
2082

2083
    override inout(ExpressionDsymbol) isExpressionDsymbol() inout
2084
    {
2085 1
        return this;
2086
    }
2087
}
2088

2089

2090
/***********************************************************
2091
 * Table of Dsymbol's
2092
 */
2093 1
extern (C++) final class DsymbolTable : RootObject
2094
{
2095
    AssocArray!(Identifier, Dsymbol) tab;
2096

2097
    // Look up Identifier. Return Dsymbol if found, NULL if not.
2098
    Dsymbol lookup(const Identifier ident)
2099
    {
2100
        //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
2101 1
        return tab[ident];
2102
    }
2103

2104
    // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
2105
    Dsymbol update(Dsymbol s)
2106
    {
2107 1
        const ident = s.ident;
2108 1
        Dsymbol* ps = tab.getLvalue(ident);
2109 1
        *ps = s;
2110 1
        return s;
2111
    }
2112

2113
    // Insert Dsymbol in table. Return NULL if already there.
2114
    Dsymbol insert(Dsymbol s)
2115
    {
2116
        //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s.ident.toChars());
2117 1
        return insert(s.ident, s);
2118
    }
2119

2120
    // when ident and s are not the same
2121
    Dsymbol insert(const Identifier ident, Dsymbol s)
2122
    {
2123
        //printf("DsymbolTable::insert()\n");
2124 1
        Dsymbol* ps = tab.getLvalue(ident);
2125 1
        if (*ps)
2126 1
            return null; // already in table
2127 1
        *ps = s;
2128 1
        return s;
2129
    }
2130

2131
    /*****
2132
     * Returns:
2133
     *  number of symbols in symbol table
2134
     */
2135
    size_t length() const pure
2136
    {
2137 1
        return tab.length;
2138
    }
2139
}

Read our documentation on viewing source code .

Loading