1 // This file is part of Visual D 2 // 3 // Visual D integrates the D programming language into Visual Studio 4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved 5 // 6 // Distributed under the Boost Software License, Version 1.0. 7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 8 9 module vdc.ast.decl; 10 11 import vdc.util; 12 import vdc.lexer; 13 import vdc.semantic; 14 import vdc.logger; 15 import vdc.interpret; 16 17 import vdc.ast.node; 18 import vdc.ast.expr; 19 import vdc.ast.misc; 20 import vdc.ast.aggr; 21 import vdc.ast.tmpl; 22 import vdc.ast.stmt; 23 import vdc.ast.type; 24 import vdc.ast.mod; 25 import vdc.ast.writer; 26 27 import std.conv; 28 import stdext.util; 29 30 version(obsolete) 31 { 32 //Declaration: 33 // alias Decl 34 // Decl 35 class Declaration : Node 36 { 37 mixin ForwardCtor!(); 38 } 39 } 40 41 // AliasDeclaration: 42 // [Decl] 43 class AliasDeclaration : Node 44 { 45 mixin ForwardCtor!(); 46 47 override void toD(CodeWriter writer) 48 { 49 if(writer.writeDeclarations) 50 writer("alias ", getMember(0)); 51 } 52 override void addSymbols(Scope sc) 53 { 54 getMember(0).addSymbols(sc); 55 } 56 } 57 58 //Decl: 59 // attributes annotations [Type Declarators FunctionBody_opt] 60 class Decl : Node 61 { 62 mixin ForwardCtor!(); 63 64 bool hasSemi; 65 bool isAlias; 66 67 Type getType() { return getMember!Type(0); } 68 Declarators getDeclarators() { return getMember!Declarators(1); } 69 FunctionBody getFunctionBody() { return getMember!FunctionBody(2); } 70 71 override Decl clone() 72 { 73 Decl n = static_cast!Decl(super.clone()); 74 n.hasSemi = hasSemi; 75 n.isAlias = isAlias; 76 return n; 77 } 78 79 override bool compare(const(Node) n) const 80 { 81 if(!super.compare(n)) 82 return false; 83 84 auto tn = static_cast!(typeof(this))(n); 85 return tn.hasSemi == hasSemi 86 && tn.isAlias == isAlias; 87 } 88 89 override void toD(CodeWriter writer) 90 { 91 if(isAlias) 92 writer(TOK_alias, " "); 93 writer.writeAttributesAndAnnotations(attr, annotation); 94 95 writer(getType(), " ", getDeclarators()); 96 bool semi = true; 97 if(auto fn = getFunctionBody()) 98 { 99 if(writer.writeImplementations) 100 { 101 writer.nl; 102 writer(fn); 103 semi = hasSemi; 104 } 105 } 106 if(semi) 107 { 108 writer(";"); 109 writer.nl(); 110 } 111 } 112 113 override void toC(CodeWriter writer) 114 { 115 bool addExtern = false; 116 if(!isAlias && writer.writeDeclarations && !(attr & Attr_ExternC)) 117 { 118 Node p = parent; 119 while(p && !cast(Aggregate) p && !cast(TemplateDeclaration) p && !cast(Statement) p) 120 p = p.parent; 121 122 if(!p) 123 addExtern = true; 124 } 125 if(auto fn = getFunctionBody()) 126 { 127 if(writer.writeReferencedOnly && getDeclarators().getDeclarator(0).semanticSearches == 0) 128 return; 129 130 writer.nl; 131 if(isAlias) 132 writer(TOK_alias, " "); 133 writer.writeAttributesAndAnnotations(attr | (addExtern ? Attr_Extern : 0), annotation); 134 135 bool semi = true; 136 writer(getType(), " ", getDeclarators()); 137 if(writer.writeImplementations) 138 { 139 writer.nl; 140 writer(fn); 141 semi = hasSemi; 142 } 143 if(semi) 144 { 145 writer(";"); 146 writer.nl(); 147 } 148 } 149 else 150 { 151 foreach(i, d; getDeclarators().members) 152 { 153 if(writer.writeReferencedOnly && getDeclarators().getDeclarator(i).semanticSearches == 0) 154 continue; 155 156 if(isAlias) 157 writer(TOK_alias, " "); 158 writer.writeAttributesAndAnnotations(attr | (addExtern ? Attr_Extern : 0), annotation); 159 160 writer(getType(), " ", d, ";"); 161 writer.nl(); 162 } 163 } 164 } 165 166 override Type calcType() 167 { 168 return getType().calcType(); 169 } 170 171 override void addSymbols(Scope sc) 172 { 173 getDeclarators().addSymbols(sc); 174 } 175 176 override void _semantic(Scope sc) 177 { 178 bool isTemplate = false; 179 if(auto fn = getFunctionBody()) 180 { 181 // if it is a function declaration, create a new scope including function parameters 182 scop = sc.push(scop); 183 scop.node = this; 184 if(auto decls = getDeclarators()) 185 if(auto decl = decls.getDeclarator(0)) 186 { 187 foreach(m; decl.members) // template parameters and function parameters and constraint 188 { 189 if(cast(TemplateParameterList) m) 190 { 191 // it does not make sense to add symbols for unexpanded templates 192 isTemplate = decl._isTemplate = true; 193 break; 194 } 195 m.addSymbols(scop); 196 } 197 } 198 199 if(!isTemplate) 200 super._semantic(scop); 201 //fn.semantic(scop); 202 sc = scop.pop(); 203 } 204 else 205 super._semantic(sc); 206 } 207 } 208 209 //Declarators: 210 // [DeclaratorInitializer|Declarator...] 211 class Declarators : Node 212 { 213 mixin ForwardCtor!(); 214 215 Declarator getDeclarator(size_t n) 216 { 217 if(auto decl = cast(Declarator) getMember(n)) 218 return decl; 219 220 return getMember!DeclaratorInitializer(n).getDeclarator(); 221 } 222 223 override void toD(CodeWriter writer) 224 { 225 writer(getMember(0)); 226 foreach(decl; members[1..$]) 227 writer(", ", decl); 228 } 229 override void addSymbols(Scope sc) 230 { 231 foreach(decl; members) 232 decl.addSymbols(sc); 233 } 234 } 235 236 //DeclaratorInitializer: 237 // [Declarator Initializer_opt] 238 class DeclaratorInitializer : Node 239 { 240 mixin ForwardCtor!(); 241 242 Declarator getDeclarator() { return getMember!Declarator(0); } 243 Expression getInitializer() { return getMember!Expression(1); } 244 245 override void toD(CodeWriter writer) 246 { 247 writer(getMember(0)); 248 if(Expression expr = getInitializer()) 249 { 250 if(expr.getPrecedence() <= PREC.assign) 251 writer(" = (", expr, ")"); 252 else 253 writer(" = ", getMember(1)); 254 } 255 } 256 257 override Type calcType() 258 { 259 return getInitializer().calcType(); 260 } 261 262 override void addSymbols(Scope sc) 263 { 264 getDeclarator().addSymbols(sc); 265 } 266 } 267 268 // unused 269 class DeclaratorIdentifierList : Node 270 { 271 mixin ForwardCtor!(); 272 273 override void toD(CodeWriter writer) 274 { 275 assert(false); 276 } 277 } 278 279 // unused 280 class DeclaratorIdentifier : Node 281 { 282 mixin ForwardCtor!(); 283 284 override void toD(CodeWriter writer) 285 { 286 assert(false); 287 } 288 } 289 290 class Initializer : Expression 291 { 292 mixin ForwardCtor!(); 293 } 294 295 //Declarator: 296 // Identifier [DeclaratorSuffixes...] 297 class Declarator : Identifier, CallableNode 298 { 299 mixin ForwardCtorTok!(); 300 301 Type type; 302 Value value; 303 Node aliasTo; 304 ParameterList parameterList; 305 bool isAlias; 306 bool isRef; 307 bool needsContext; 308 bool _isTemplate; 309 bool _inReinit; 310 TemplateInstantiation[] tmpl; 311 312 override Declarator clone() 313 { 314 Declarator n = static_cast!Declarator(super.clone()); 315 n.type = type; 316 return n; 317 } 318 319 final Declarator cloneDeclaratorShallow() 320 { 321 auto decl = static_cast!Declarator(_cloneShallow()); 322 decl.ident = ident; 323 if(parameterList) 324 decl.addMember(parameterList.clone()); 325 // copy info from applySuffixes 326 return decl; 327 } 328 329 Expression getInitializer() 330 { 331 if(auto di = cast(DeclaratorInitializer) parent) 332 return di.getInitializer(); 333 return null; 334 } 335 336 override void toD(CodeWriter writer) 337 { 338 super.toD(writer); 339 foreach(m; members) // template parameters and function parameters and constraint 340 writer(m); 341 } 342 343 bool _isAlias() 344 { 345 for(Node p = parent; p; p = p.parent) 346 if(auto decl = cast(Decl) p) 347 return decl.isAlias; 348 else if(auto pdecl = cast(ParameterDeclarator) p) 349 break; 350 return false; 351 } 352 // returns 0 for never, 1 for non-static statement declaration, 2 for yes 353 bool _needsContext() 354 { 355 for(Node p = parent; p; p = p.parent) 356 if(auto decl = cast(Decl) p) 357 { 358 if(!decl.parent || cast(Module)decl.parent) 359 return false; 360 if (decl.attr & (Attr_Static | Attr_Shared | Attr_Gshared)) 361 return false; 362 return true; 363 } 364 else if(auto pdecl = cast(ParameterDeclarator) p) 365 return true; 366 367 return false; 368 } 369 370 override bool isTemplate() 371 { 372 return _isTemplate; 373 } 374 375 override Node expandTemplate(Scope sc, TemplateArgumentList args) 376 { 377 assert(_isTemplate); 378 379 calcType(); // ensure suffixes applied 380 TemplateParameterList tpl = getTemplateParameterList(); 381 382 ArgMatch[] vargs = matchTemplateArgs(ident, sc, args, tpl); 383 if(vargs is null) 384 return this; 385 386 if(auto impl = getTemplateInstantiation(vargs)) 387 return impl.getDeclarator(); 388 389 // new instantiation has template parameters as parameterlist and contains 390 // a copy of the function declaration without template arguments 391 auto tmpl = new TemplateInstantiation(this, vargs); 392 addMember(tmpl); // add as suffix 393 tmpl.semantic(getScope()); 394 return tmpl.getDeclarator(); 395 } 396 397 TemplateInstantiation getTemplateInstantiation(ArgMatch[] args) 398 { 399 return null; 400 } 401 402 TemplateParameterList getTemplateParameterList() 403 { 404 for(int m = 0; m < members.length; m++) 405 { 406 auto member = members[0]; 407 if(auto tpl = cast(TemplateParameterList) member) 408 return tpl; 409 } 410 return null; 411 } 412 413 override void addSymbols(Scope sc) 414 { 415 sc.addSymbol(ident, this); 416 } 417 418 Type applySuffixes(Type t) 419 { 420 // assumed to be only called once by calcType 421 isAlias = _isAlias(); 422 needsContext = _needsContext(); 423 424 // template parameters and function parameters and constraint 425 size_t mlen = members.length; 426 for(int m = 0; m < members.length; m++) 427 { 428 auto member = members[m]; 429 if(auto pl = cast(ParameterList) member) 430 { 431 auto tf = needsContext ? new TypeDelegate(pl.id, pl.span) : new TypeFunction(pl.id, pl.span); 432 tf.funcDecl = this; 433 tf.returnType = t; // need clones? 434 tf.paramList = pl; 435 tf.scop = getScope(); // not fully added to node tree 436 t = tf; 437 parameterList = pl; 438 } 439 else if(auto sa = cast(SuffixArray) member) 440 { 441 auto idx = sa.getMember(0); 442 if(auto tidx = cast(Type) idx) // TODO: need to resolve identifiers? 443 { 444 auto taa = new TypeAssocArray(sa.id, sa.span); 445 taa.setNextType(t); // need clones? 446 taa.keyType = tidx; 447 t = taa; 448 } 449 else 450 { 451 auto tsa = new TypeStaticArray(sa.id, sa.span); 452 tsa.setNextType(t); // need clones? 453 tsa.dimExpr = static_cast!Expression(idx); 454 t = tsa; 455 } 456 t.scop = getScope(); // not fully added to node tree 457 } 458 else if(auto sda = cast(SuffixDynamicArray) member) 459 { 460 auto tda = new TypeDynamicArray(sda.id, sda.span); 461 tda.addMember(t.clone()); 462 t = tda; 463 tda.scop = getScope(); // not fully added to node tree 464 } 465 // TODO: slice suffix? template parameters, constraint 466 } 467 468 //// after removal, limit span to remaining members 469 //if(mlen > members.length) 470 //{ 471 // fulspan = span; 472 // foreach(m; members) 473 // extendSpan(m.fulspan); 474 //} 475 return t; 476 } 477 478 override Node resolve() 479 { 480 return this; 481 } 482 483 override Type calcType() 484 { 485 if(type) 486 return type; 487 if(aliasTo) 488 return aliasTo.calcType(); 489 490 for(Node p = parent; p; p = p.parent) 491 { 492 if(auto decl = cast(Decl) p) 493 { 494 type = decl.getType(); 495 if(cast(AutoType)type) 496 { 497 if(auto expr = getInitializer()) 498 type = expr.calcType(); 499 } 500 if(type) 501 { 502 type = applySuffixes(type); 503 type = type.calcType(); 504 } 505 return type; 506 } 507 else if(auto pdecl = cast(ParameterDeclarator) p) 508 { 509 type = pdecl.getType(); 510 if(type) 511 { 512 type = applySuffixes(type); 513 type = type.calcType(); 514 } 515 return type; 516 } 517 } 518 type = semanticErrorType("cannot find Declarator type"); 519 return type; 520 } 521 522 override Value interpret(Context sc) 523 { 524 if(value) 525 return value; 526 if(aliasTo) 527 return aliasTo.interpret(sc); // TODO: alias not restricted to types 528 Type type = calcType(); 529 if(isAlias) 530 return type.interpret(sc); // TODO: alias not restricted to types 531 else if(needsContext) 532 { 533 if(!sc) 534 return semanticErrorValue("evaluating ", ident, " needs context pointer"); 535 if(auto v = sc.getValue(this)) 536 return v; 537 } 538 return interpretReinit(sc); 539 } 540 541 Value interpretReinit(Context sc) 542 { 543 if(_inReinit) 544 return semanticErrorValue("initializing ", ident, " refers to itself"); 545 _inReinit = true; 546 scope(exit) _inReinit = false; 547 548 if(aliasTo) 549 return aliasTo.interpret(sc); // TODO: alias not restricted to types 550 Type type = calcType(); 551 if(isAlias) 552 return type.interpret(sc); // TODO: alias not restricted to types 553 else if(needsContext) 554 { 555 if(!sc) 556 return semanticErrorValue("evaluating ", ident, " needs context pointer"); 557 Value v; 558 if(auto expr = getInitializer()) 559 { 560 v = expr.interpret(sc); 561 if(!v.getType().compare(type)) 562 type.createValue(sc, v); 563 } 564 else 565 v = type.createValue(sc, null); 566 debug v.ident = ident; 567 sc.setValue(this, v); 568 return v; 569 } 570 else if(auto expr = getInitializer()) 571 value = type.createValue(sc, expr.interpret(sc)); 572 else 573 value = type.createValue(sc, null); 574 debug value.ident = ident; 575 return value; 576 } 577 578 override ParameterList getParameterList() 579 { 580 calcType(); 581 return parameterList; 582 } 583 584 override FunctionBody getFunctionBody() 585 { 586 for(Node p = parent; p; p = p.parent) 587 if(auto decl = cast(Decl) p) 588 if(auto fbody = decl.getFunctionBody()) 589 return fbody; 590 return null; 591 } 592 593 override Value interpretCall(Context sc) 594 { 595 logInfo("calling %s", ident); 596 597 if(auto fbody = getFunctionBody()) 598 return fbody.interpret(sc); 599 600 return semanticErrorValue(ident, " is not an interpretable function"); 601 } 602 } 603 604 //TemplateInstantiation: 605 // [ParameterList Decl] 606 class TemplateInstantiation : Node 607 { 608 ArgMatch[] args; 609 Declarator dec; 610 611 override ParameterList getParameterList() { return getMember!ParameterList(0); } 612 Declarator getDeclarator() { return dec; } 613 614 this(Declarator ddec, ArgMatch[] vargs) 615 { 616 Decl decl = new Decl; 617 dec = ddec.cloneDeclaratorShallow(); 618 args = vargs; 619 620 for(Node p = ddec.parent; p; p = p.parent) 621 if(auto ddecl = cast(Decl) p) 622 { 623 if(auto type = ddecl.getType()) 624 decl.addMember(type.clone()); 625 Declarators decs = new Declarators; 626 decs.addMember(dec); 627 decl.addMember(decs); 628 if(auto fbody = ddecl.getFunctionBody()) 629 decl.addMember(fbody.clone()); 630 break; 631 } 632 assert(decl.members.length > 0); 633 634 if(auto tpl = ddec.getTemplateParameterList()) 635 addMember(createTemplateParameterList(vargs)); 636 else 637 addMember(new ParameterList); 638 addMember(decl); 639 logInfo("created template instance of ", dec.ident, " with args ", vargs); 640 } 641 642 override void toD(CodeWriter writer) 643 { 644 // suppress output (add a flag to the writer to enable output of expanded template?) 645 } 646 647 override void addSymbols(Scope sc) 648 { 649 getParameterList().addSymbols(sc); 650 } 651 652 override bool createsScope() const { return true; } 653 654 override void _semantic(Scope sc) 655 { 656 sc = enterScope(sc); 657 super._semantic(sc); 658 sc = scop.pop(); 659 } 660 } 661 662 //IdentifierList: 663 // [IdentifierOrTemplateInstance...] 664 class IdentifierList : Node 665 { 666 mixin ForwardCtor!(); 667 668 bool global; 669 670 // semantic data 671 Node resolved; 672 673 override IdentifierList clone() 674 { 675 IdentifierList n = static_cast!IdentifierList(super.clone()); 676 n.global = global; 677 return n; 678 } 679 680 override bool compare(const(Node) n) const 681 { 682 if(!super.compare(n)) 683 return false; 684 685 auto tn = static_cast!(typeof(this))(n); 686 return tn.global == global; 687 } 688 689 Node doResolve(bool isMixin) 690 { 691 // TODO: does not work for package qualified symbols 692 Scope sc; 693 if(global) 694 sc = getModule().scop; 695 else if(auto bc = cast(BaseClass) parent) 696 if(auto clss = bc.parent) 697 if(auto p = clss.parent) 698 sc = p.getScope(); 699 if(!sc) 700 sc = getScope(); 701 702 Node res; 703 for(int m = 0; sc && m < members.length; m++) 704 { 705 auto id = getMember!Identifier(m); 706 res = sc.resolveWithTemplate(id.ident, sc, id); 707 sc = (res ? res.getScope() : null); 708 } 709 if(!sc && !isMixin) 710 res = semanticErrorType("cannot resolve ", writeD(this)); 711 return res; 712 } 713 714 override Node resolve() 715 { 716 if(resolved) 717 return resolved; 718 719 resolved = doResolve(false); 720 return resolved; 721 } 722 723 override Type calcType() 724 { 725 if(Node n = resolve()) 726 return n.calcType(); 727 return semanticErrorType("cannot resolve type of ", writeD(this)); 728 } 729 730 override Value interpret(Context sc) 731 { 732 if(Node n = resolve()) 733 return n.interpret(sc); 734 return semanticErrorValue("cannot resolve ", writeD(this)); 735 } 736 737 override void _semantic(Scope sc) 738 { 739 resolve(); 740 } 741 742 override void toD(CodeWriter writer) 743 { 744 if(global) 745 writer("."); 746 writer.writeArray(members, "."); 747 } 748 } 749 750 class Identifier : Node 751 { 752 string ident; 753 754 this() {} // default constructor needed for clone() 755 756 this(Token tok) 757 { 758 super(tok); 759 ident = tok.txt; 760 } 761 762 override Identifier clone() 763 { 764 Identifier n = static_cast!Identifier(super.clone()); 765 n.ident = ident; 766 return n; 767 } 768 769 override bool compare(const(Node) n) const 770 { 771 if(!super.compare(n)) 772 return false; 773 774 auto tn = static_cast!(typeof(this))(n); 775 return tn.ident == ident; 776 } 777 778 override void toD(CodeWriter writer) 779 { 780 writer.writeIdentifier(ident); 781 } 782 783 override ArgumentList getFunctionArguments() 784 { 785 if(parent) 786 return parent.getFunctionArguments(); 787 return null; 788 } 789 790 override Node resolve() 791 { 792 if(parent) 793 return parent.resolve(); 794 return super.resolve(); 795 } 796 797 override Type calcType() 798 { 799 if(auto p = cast(IdentifierList) parent) 800 return p.calcType(); 801 if(auto p = cast(IdentifierExpression) parent) 802 return p.calcType(); 803 if(auto p = cast(DotExpression) parent) 804 return p.calcType(); 805 if(auto p = cast(ModuleFullyQualifiedName) parent) 806 { 807 } 808 if(auto p = cast(ForeachType) parent) 809 return parent.calcType(); 810 return super.calcType(); 811 } 812 813 override Value interpret(Context ctx) 814 { 815 if(auto p = cast(IdentifierList) parent) 816 return p.interpret(ctx); 817 if(auto p = cast(IdentifierExpression) parent) 818 return p.interpret(ctx); 819 if(auto p = cast(DotExpression) parent) 820 return p.interpret(ctx); 821 if(auto p = cast(ModuleFullyQualifiedName) parent) 822 { 823 } 824 if(auto p = cast(ForeachType) parent) 825 return parent.interpret(ctx); 826 return super.interpret(ctx); 827 } 828 } 829 830 //ParameterList: 831 // [Parameter...] attributes 832 class ParameterList : Node 833 { 834 mixin ForwardCtor!(); 835 836 Parameter getParameter(size_t i) { return getMember!Parameter(i); } 837 838 bool varargs; 839 bool anonymous_varargs; 840 841 override ParameterList clone() 842 { 843 ParameterList n = static_cast!ParameterList(super.clone()); 844 n.varargs = varargs; 845 n.anonymous_varargs = anonymous_varargs; 846 return n; 847 } 848 849 override bool compare(const(Node) n) const 850 { 851 if(!super.compare(n)) 852 return false; 853 854 auto tn = static_cast!(typeof(this))(n); 855 return tn.varargs == varargs && tn.anonymous_varargs == anonymous_varargs; 856 } 857 858 override void toD(CodeWriter writer) 859 { 860 writer("("); 861 writer.writeArray(members); 862 if(anonymous_varargs) 863 writer(", ..."); 864 else if(varargs) 865 writer("..."); 866 writer(")"); 867 if(attr) 868 { 869 writer.writeAttributesAndAnnotations(attr, annotation, true); 870 } 871 } 872 873 override void addSymbols(Scope sc) 874 { 875 foreach(m; members) 876 m.addSymbols(sc); 877 } 878 } 879 880 //Parameter: 881 // io [ParameterDeclarator Expression_opt] 882 class Parameter : Node 883 { 884 mixin ForwardCtor!(); 885 886 TokenId io; 887 888 ParameterDeclarator getParameterDeclarator() { return getMember!ParameterDeclarator(0); } 889 Expression getInitializer() { return getMember!Expression(1); } 890 891 override Parameter clone() 892 { 893 Parameter n = static_cast!Parameter(super.clone()); 894 n.io = io; 895 return n; 896 } 897 898 override bool compare(const(Node) n) const 899 { 900 if(!super.compare(n)) 901 return false; 902 903 auto tn = static_cast!(typeof(this))(n); 904 return tn.io == io; 905 } 906 907 override void toD(CodeWriter writer) 908 { 909 if(io) 910 writer(io, " "); 911 writer(getMember(0)); 912 if(members.length > 1) 913 writer(" = ", getMember(1)); 914 } 915 916 override void addSymbols(Scope sc) 917 { 918 getParameterDeclarator().addSymbols(sc); 919 } 920 921 override Type calcType() 922 { 923 return getParameterDeclarator().calcType(); 924 } 925 } 926 927 //ParameterDeclarator: 928 // attributes [Type Declarator] 929 class ParameterDeclarator : Node 930 { 931 mixin ForwardCtor!(); 932 933 Type getType() { return getMember!Type(0); } 934 Declarator getDeclarator() { return members.length > 1 ? getMember!Declarator(1) : null; } 935 936 override void toD(CodeWriter writer) 937 { 938 writer.writeAttributesAndAnnotations(attr, annotation); 939 writer(getType()); 940 if(auto decl = getDeclarator()) 941 writer(" ", decl); 942 } 943 944 override void addSymbols(Scope sc) 945 { 946 if (auto decl = getDeclarator()) 947 decl.addSymbols(sc); 948 } 949 950 override Type calcType() 951 { 952 if (auto decl = getDeclarator()) 953 return decl.calcType(); 954 return getType().calcType(); 955 } 956 }