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