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