1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Template implementation. 6 * 7 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 8 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 9 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 10 * Source: $(DMDSRC _dtemplate.d) 11 */ 12 13 module ddmd.dtemplate; 14 15 import core.stdc.stdio; 16 import core.stdc..string; 17 import ddmd.aggregate; 18 import ddmd.aliasthis; 19 import ddmd.arraytypes; 20 import ddmd.attrib; 21 import ddmd.dcast; 22 import ddmd.dclass; 23 import ddmd.declaration; 24 import ddmd.dmangle; 25 import ddmd.dmodule; 26 import ddmd.dscope; 27 import ddmd.dsymbol; 28 import ddmd.errors; 29 import ddmd.expression; 30 import ddmd.func; 31 import ddmd.globals; 32 import ddmd.hdrgen; 33 import ddmd.id; 34 import ddmd.identifier; 35 import ddmd.init; 36 import ddmd.mtype; 37 import ddmd.opover; 38 import ddmd.root.aav; 39 import ddmd.root.outbuffer; 40 import ddmd.root.rootobject; 41 import ddmd.tokens; 42 import ddmd.visitor; 43 44 private enum LOG = false; 45 46 enum IDX_NOTFOUND = 0x12345678; 47 48 /******************************************** 49 * These functions substitute for dynamic_cast. dynamic_cast does not work 50 * on earlier versions of gcc. 51 */ 52 extern (C++) Expression isExpression(RootObject o) 53 { 54 //return dynamic_cast<Expression *>(o); 55 if (!o || o.dyncast() != DYNCAST_EXPRESSION) 56 return null; 57 return cast(Expression)o; 58 } 59 60 extern (C++) Dsymbol isDsymbol(RootObject o) 61 { 62 //return dynamic_cast<Dsymbol *>(o); 63 if (!o || o.dyncast() != DYNCAST_DSYMBOL) 64 return null; 65 return cast(Dsymbol)o; 66 } 67 68 extern (C++) Type isType(RootObject o) 69 { 70 //return dynamic_cast<Type *>(o); 71 if (!o || o.dyncast() != DYNCAST_TYPE) 72 return null; 73 return cast(Type)o; 74 } 75 76 extern (C++) Tuple isTuple(RootObject o) 77 { 78 //return dynamic_cast<Tuple *>(o); 79 if (!o || o.dyncast() != DYNCAST_TUPLE) 80 return null; 81 return cast(Tuple)o; 82 } 83 84 extern (C++) Parameter isParameter(RootObject o) 85 { 86 //return dynamic_cast<Parameter *>(o); 87 if (!o || o.dyncast() != DYNCAST_PARAMETER) 88 return null; 89 return cast(Parameter)o; 90 } 91 92 /************************************** 93 * Is this Object an error? 94 */ 95 extern (C++) bool isError(RootObject o) 96 { 97 Type t = isType(o); 98 if (t) 99 return (t.ty == Terror); 100 Expression e = isExpression(o); 101 if (e) 102 return (e.op == TOKerror || !e.type || e.type.ty == Terror); 103 Tuple v = isTuple(o); 104 if (v) 105 return arrayObjectIsError(&v.objects); 106 Dsymbol s = isDsymbol(o); 107 assert(s); 108 if (s.errors) 109 return true; 110 return s.parent ? isError(s.parent) : false; 111 } 112 113 /************************************** 114 * Are any of the Objects an error? 115 */ 116 extern (C++) bool arrayObjectIsError(Objects* args) 117 { 118 for (size_t i = 0; i < args.dim; i++) 119 { 120 RootObject o = (*args)[i]; 121 if (isError(o)) 122 return true; 123 } 124 return false; 125 } 126 127 /*********************** 128 * Try to get arg as a type. 129 */ 130 extern (C++) Type getType(RootObject o) 131 { 132 Type t = isType(o); 133 if (!t) 134 { 135 Expression e = isExpression(o); 136 if (e) 137 t = e.type; 138 } 139 return t; 140 } 141 142 extern (C++) Dsymbol getDsymbol(RootObject oarg) 143 { 144 //printf("getDsymbol()\n"); 145 //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg)); 146 Dsymbol sa; 147 Expression ea = isExpression(oarg); 148 if (ea) 149 { 150 // Try to convert Expression to symbol 151 if (ea.op == TOKvar) 152 sa = (cast(VarExp)ea).var; 153 else if (ea.op == TOKfunction) 154 { 155 if ((cast(FuncExp)ea).td) 156 sa = (cast(FuncExp)ea).td; 157 else 158 sa = (cast(FuncExp)ea).fd; 159 } 160 else if (ea.op == TOKtemplate) 161 sa = (cast(TemplateExp)ea).td; 162 else 163 sa = null; 164 } 165 else 166 { 167 // Try to convert Type to symbol 168 Type ta = isType(oarg); 169 if (ta) 170 sa = ta.toDsymbol(null); 171 else 172 sa = isDsymbol(oarg); // if already a symbol 173 } 174 return sa; 175 } 176 177 private Expression getValue(ref Dsymbol s) 178 { 179 Expression e = null; 180 if (s) 181 { 182 VarDeclaration v = s.isVarDeclaration(); 183 if (v && v.storage_class & STCmanifest) 184 { 185 e = v.getConstInitializer(); 186 } 187 } 188 return e; 189 } 190 191 /*********************** 192 * Try to get value from manifest constant 193 */ 194 private Expression getValue(Expression e) 195 { 196 if (e && e.op == TOKvar) 197 { 198 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); 199 if (v && v.storage_class & STCmanifest) 200 { 201 e = v.getConstInitializer(); 202 } 203 } 204 return e; 205 } 206 207 /****************************** 208 * If o1 matches o2, return true. 209 * Else, return false. 210 */ 211 private bool match(RootObject o1, RootObject o2) 212 { 213 static Expression getExpression(RootObject o) 214 { 215 auto s = isDsymbol(o); 216 return s ? .getValue(s) : .getValue(isExpression(o)); 217 } 218 219 enum debugPrint = 0; 220 221 static if (debugPrint) 222 { 223 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n", 224 o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast()); 225 } 226 227 /* A proper implementation of the various equals() overrides 228 * should make it possible to just do o1.equals(o2), but 229 * we'll do that another day. 230 */ 231 /* Manifest constants should be compared by their values, 232 * at least in template arguments. 233 */ 234 235 if (auto t1 = isType(o1)) 236 { 237 auto t2 = isType(o2); 238 if (!t2) 239 goto Lnomatch; 240 241 static if (debugPrint) 242 { 243 printf("\tt1 = %s\n", t1.toChars()); 244 printf("\tt2 = %s\n", t2.toChars()); 245 } 246 if (!t1.equals(t2)) 247 goto Lnomatch; 248 249 goto Lmatch; 250 } 251 if (auto e1 = getExpression(o1)) 252 { 253 auto e2 = getExpression(o2); 254 if (!e2) 255 goto Lnomatch; 256 257 static if (debugPrint) 258 { 259 printf("\te1 = %s '%s' %s\n", e1.type.toChars(), Token.toChars(e1.op), e1.toChars()); 260 printf("\te2 = %s '%s' %s\n", e2.type.toChars(), Token.toChars(e2.op), e2.toChars()); 261 } 262 if (!e1.equals(e2)) 263 goto Lnomatch; 264 265 goto Lmatch; 266 } 267 if (auto s1 = isDsymbol(o1)) 268 { 269 auto s2 = isDsymbol(o2); 270 if (!s2) 271 goto Lnomatch; 272 273 static if (debugPrint) 274 { 275 printf("\ts1 = %s \n", s1.kind(), s1.toChars()); 276 printf("\ts2 = %s \n", s2.kind(), s2.toChars()); 277 } 278 if (!s1.equals(s2)) 279 goto Lnomatch; 280 if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration()) 281 goto Lnomatch; 282 283 goto Lmatch; 284 } 285 if (auto u1 = isTuple(o1)) 286 { 287 auto u2 = isTuple(o2); 288 if (!u2) 289 goto Lnomatch; 290 291 static if (debugPrint) 292 { 293 printf("\tu1 = %s\n", u1.toChars()); 294 printf("\tu2 = %s\n", u2.toChars()); 295 } 296 if (!arrayObjectMatch(&u1.objects, &u2.objects)) 297 goto Lnomatch; 298 299 goto Lmatch; 300 } 301 Lmatch: 302 static if (debugPrint) 303 printf("\t-> match\n"); 304 return true; 305 306 Lnomatch: 307 static if (debugPrint) 308 printf("\t-> nomatch\n"); 309 return false; 310 } 311 312 /************************************ 313 * Match an array of them. 314 */ 315 private int arrayObjectMatch(Objects* oa1, Objects* oa2) 316 { 317 if (oa1 == oa2) 318 return 1; 319 if (oa1.dim != oa2.dim) 320 return 0; 321 for (size_t j = 0; j < oa1.dim; j++) 322 { 323 RootObject o1 = (*oa1)[j]; 324 RootObject o2 = (*oa2)[j]; 325 if (!match(o1, o2)) 326 { 327 return 0; 328 } 329 } 330 return 1; 331 } 332 333 /************************************ 334 * Return hash of Objects. 335 */ 336 private hash_t arrayObjectHash(Objects* oa1) 337 { 338 hash_t hash = 0; 339 for (size_t j = 0; j < oa1.dim; j++) 340 { 341 /* Must follow the logic of match() 342 */ 343 RootObject o1 = (*oa1)[j]; 344 if (Type t1 = isType(o1)) 345 hash += cast(size_t)t1.deco; 346 else 347 { 348 Dsymbol s1 = isDsymbol(o1); 349 Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); 350 if (e1) 351 { 352 if (e1.op == TOKint64) 353 { 354 IntegerExp ne = cast(IntegerExp)e1; 355 hash += cast(size_t)ne.getInteger(); 356 } 357 } 358 else if (s1) 359 { 360 FuncAliasDeclaration fa1 = s1.isFuncAliasDeclaration(); 361 if (fa1) 362 s1 = fa1.toAliasFunc(); 363 hash += cast(size_t)cast(void*)s1.getIdent() + cast(size_t)cast(void*)s1.parent; 364 } 365 else if (Tuple u1 = isTuple(o1)) 366 hash += arrayObjectHash(&u1.objects); 367 } 368 } 369 return hash; 370 } 371 372 RootObject objectSyntaxCopy(RootObject o) 373 { 374 if (!o) 375 return null; 376 if (Type t = isType(o)) 377 return t.syntaxCopy(); 378 if (Expression e = isExpression(o)) 379 return e.syntaxCopy(); 380 return o; 381 } 382 383 extern (C++) final class Tuple : RootObject 384 { 385 Objects objects; 386 387 // kludge for template.isType() 388 override int dyncast() 389 { 390 return DYNCAST_TUPLE; 391 } 392 393 override const(char)* toChars() 394 { 395 return objects.toChars(); 396 } 397 } 398 399 struct TemplatePrevious 400 { 401 TemplatePrevious* prev; 402 Scope* sc; 403 Objects* dedargs; 404 } 405 406 /*********************************************************** 407 */ 408 extern (C++) final class TemplateDeclaration : ScopeDsymbol 409 { 410 TemplateParameters* parameters; // array of TemplateParameter's 411 TemplateParameters* origParameters; // originals for Ddoc 412 413 Expression constraint; 414 415 // Hash table to look up TemplateInstance's of this TemplateDeclaration 416 TemplateInstance[TemplateInstanceBox] instances; 417 418 TemplateDeclaration overnext; // next overloaded TemplateDeclaration 419 TemplateDeclaration overroot; // first in overnext list 420 FuncDeclaration funcroot; // first function in unified overload list 421 422 Dsymbol onemember; // if !=null then one member of this template 423 424 bool literal; // this template declaration is a literal 425 bool ismixin; // template declaration is only to be used as a mixin 426 bool isstatic; // this is static template declaration 427 Prot protection; 428 429 // threaded list of previous instantiation attempts on stack 430 TemplatePrevious* previous; 431 432 extern (D) this(Loc loc, Identifier id, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) 433 { 434 super(id); 435 static if (LOG) 436 { 437 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id.toChars()); 438 } 439 version (none) 440 { 441 if (parameters) 442 for (int i = 0; i < parameters.dim; i++) 443 { 444 TemplateParameter tp = (*parameters)[i]; 445 //printf("\tparameter[%d] = %p\n", i, tp); 446 TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); 447 if (ttp) 448 { 449 printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); 450 } 451 } 452 } 453 this.loc = loc; 454 this.parameters = parameters; 455 this.origParameters = parameters; 456 this.constraint = constraint; 457 this.members = decldefs; 458 this.literal = literal; 459 this.ismixin = ismixin; 460 this.isstatic = true; 461 this.protection = Prot(PROTundefined); 462 463 // Compute in advance for Ddoc's use 464 // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails. 465 if (members && ident) 466 { 467 Dsymbol s; 468 if (Dsymbol.oneMembers(members, &s, ident) && s) 469 { 470 onemember = s; 471 s.parent = this; 472 } 473 } 474 } 475 476 override Dsymbol syntaxCopy(Dsymbol) 477 { 478 //printf("TemplateDeclaration.syntaxCopy()\n"); 479 TemplateParameters* p = null; 480 if (parameters) 481 { 482 p = new TemplateParameters(); 483 p.setDim(parameters.dim); 484 for (size_t i = 0; i < p.dim; i++) 485 (*p)[i] = (*parameters)[i].syntaxCopy(); 486 } 487 return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal); 488 } 489 490 override void semantic(Scope* sc) 491 { 492 static if (LOG) 493 { 494 printf("TemplateDeclaration.semantic(this = %p, id = '%s')\n", this, ident.toChars()); 495 printf("sc.stc = %llx\n", sc.stc); 496 printf("sc.module = %s\n", sc._module.toChars()); 497 } 498 if (semanticRun != PASSinit) 499 return; // semantic() already run 500 semanticRun = PASSsemantic; 501 502 // Remember templates defined in module object that we need to know about 503 if (sc._module && sc._module.ident == Id.object) 504 { 505 if (ident == Id.RTInfo) 506 Type.rtinfo = this; 507 } 508 509 /* Remember Scope for later instantiations, but make 510 * a copy since attributes can change. 511 */ 512 if (!this._scope) 513 { 514 this._scope = sc.copy(); 515 this._scope.setNoFree(); 516 } 517 518 parent = sc.parent; 519 protection = sc.protection; 520 isstatic = toParent().isModule() || (_scope.stc & STCstatic); 521 522 if (!isstatic) 523 { 524 if (auto ad = parent.pastMixin().isAggregateDeclaration()) 525 ad.makeNested(); 526 } 527 528 // Set up scope for parameters 529 auto paramsym = new ScopeDsymbol(); 530 paramsym.parent = parent; 531 Scope* paramscope = sc.push(paramsym); 532 paramscope.stc = 0; 533 534 if (global.params.doDocComments) 535 { 536 origParameters = new TemplateParameters(); 537 origParameters.setDim(parameters.dim); 538 for (size_t i = 0; i < parameters.dim; i++) 539 { 540 TemplateParameter tp = (*parameters)[i]; 541 (*origParameters)[i] = tp.syntaxCopy(); 542 } 543 } 544 545 for (size_t i = 0; i < parameters.dim; i++) 546 { 547 TemplateParameter tp = (*parameters)[i]; 548 if (!tp.declareParameter(paramscope)) 549 { 550 error(tp.loc, "parameter '%s' multiply defined", tp.ident.toChars()); 551 errors = true; 552 } 553 if (!tp.semantic(paramscope, parameters)) 554 { 555 errors = true; 556 } 557 if (i + 1 != parameters.dim && tp.isTemplateTupleParameter()) 558 { 559 error("template tuple parameter must be last one"); 560 errors = true; 561 } 562 } 563 564 /* Calculate TemplateParameter.dependent 565 */ 566 TemplateParameters tparams; 567 tparams.setDim(1); 568 for (size_t i = 0; i < parameters.dim; i++) 569 { 570 TemplateParameter tp = (*parameters)[i]; 571 tparams[0] = tp; 572 573 for (size_t j = 0; j < parameters.dim; j++) 574 { 575 // Skip cases like: X(T : T) 576 if (i == j) 577 continue; 578 579 if (TemplateTypeParameter ttp = (*parameters)[j].isTemplateTypeParameter()) 580 { 581 if (reliesOnTident(ttp.specType, &tparams)) 582 tp.dependent = true; 583 } 584 else if (TemplateAliasParameter tap = (*parameters)[j].isTemplateAliasParameter()) 585 { 586 if (reliesOnTident(tap.specType, &tparams) || 587 reliesOnTident(isType(tap.specAlias), &tparams)) 588 { 589 tp.dependent = true; 590 } 591 } 592 } 593 } 594 595 paramscope.pop(); 596 597 // Compute again 598 onemember = null; 599 if (members) 600 { 601 Dsymbol s; 602 if (Dsymbol.oneMembers(members, &s, ident) && s) 603 { 604 onemember = s; 605 s.parent = this; 606 } 607 } 608 609 /* BUG: should check: 610 * o no virtual functions or non-static data members of classes 611 */ 612 } 613 614 /********************************** 615 * Overload existing TemplateDeclaration 'this' with the new one 's'. 616 * Return true if successful; i.e. no conflict. 617 */ 618 override bool overloadInsert(Dsymbol s) 619 { 620 static if (LOG) 621 { 622 printf("TemplateDeclaration.overloadInsert('%s')\n", s.toChars()); 623 } 624 FuncDeclaration fd = s.isFuncDeclaration(); 625 if (fd) 626 { 627 if (funcroot) 628 return funcroot.overloadInsert(fd); 629 funcroot = fd; 630 return funcroot.overloadInsert(this); 631 } 632 633 TemplateDeclaration td = s.isTemplateDeclaration(); 634 if (!td) 635 return false; 636 637 TemplateDeclaration pthis = this; 638 TemplateDeclaration* ptd; 639 for (ptd = &pthis; *ptd; ptd = &(*ptd).overnext) 640 { 641 } 642 643 td.overroot = this; 644 *ptd = td; 645 static if (LOG) 646 { 647 printf("\ttrue: no conflict\n"); 648 } 649 return true; 650 } 651 652 override bool hasStaticCtorOrDtor() 653 { 654 return false; // don't scan uninstantiated templates 655 } 656 657 override const(char)* kind() const 658 { 659 return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template"; 660 } 661 662 override const(char)* toChars() 663 { 664 if (literal) 665 return Dsymbol.toChars(); 666 667 OutBuffer buf; 668 HdrGenState hgs; 669 670 buf.writestring(ident.toChars()); 671 buf.writeByte('('); 672 for (size_t i = 0; i < parameters.dim; i++) 673 { 674 TemplateParameter tp = (*parameters)[i]; 675 if (i) 676 buf.writestring(", "); 677 .toCBuffer(tp, &buf, &hgs); 678 } 679 buf.writeByte(')'); 680 681 if (onemember) 682 { 683 FuncDeclaration fd = onemember.isFuncDeclaration(); 684 if (fd && fd.type) 685 { 686 TypeFunction tf = cast(TypeFunction)fd.type; 687 buf.writestring(parametersTypeToChars(tf.parameters, tf.varargs)); 688 } 689 } 690 691 if (constraint) 692 { 693 buf.writestring(" if ("); 694 .toCBuffer(constraint, &buf, &hgs); 695 buf.writeByte(')'); 696 } 697 return buf.extractString(); 698 } 699 700 override Prot prot() 701 { 702 return protection; 703 } 704 705 /**************************** 706 * Check to see if constraint is satisfied. 707 */ 708 bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) 709 { 710 /* Detect recursive attempts to instantiate this template declaration, 711 * https://issues.dlang.org/show_bug.cgi?id=4072 712 * void foo(T)(T x) if (is(typeof(foo(x)))) { } 713 * static assert(!is(typeof(foo(7)))); 714 * Recursive attempts are regarded as a constraint failure. 715 */ 716 /* There's a chicken-and-egg problem here. We don't know yet if this template 717 * instantiation will be a local one (enclosing is set), and we won't know until 718 * after selecting the correct template. Thus, function we're nesting inside 719 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). 720 * Workaround the problem by setting a flag to relax the checking on frame errors. 721 */ 722 723 for (TemplatePrevious* p = previous; p; p = p.prev) 724 { 725 if (arrayObjectMatch(p.dedargs, dedargs)) 726 { 727 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); 728 /* It must be a subscope of p.sc, other scope chains are not recursive 729 * instantiations. 730 */ 731 for (Scope* scx = sc; scx; scx = scx.enclosing) 732 { 733 if (scx == p.sc) 734 return false; 735 } 736 } 737 /* BUG: should also check for ref param differences 738 */ 739 } 740 741 TemplatePrevious pr; 742 pr.prev = previous; 743 pr.sc = paramscope; 744 pr.dedargs = dedargs; 745 previous = ≺ // add this to threaded list 746 747 uint nerrors = global.errors; 748 749 Scope* scx = paramscope.push(ti); 750 scx.parent = ti; 751 scx.tinst = null; 752 scx.minst = null; 753 754 assert(!ti.symtab); 755 if (fd) 756 { 757 /* Declare all the function parameters as variables and add them to the scope 758 * Making parameters is similar to FuncDeclaration.semantic3 759 */ 760 TypeFunction tf = cast(TypeFunction)fd.type; 761 assert(tf.ty == Tfunction); 762 763 scx.parent = fd; 764 765 Parameters* fparameters = tf.parameters; 766 int fvarargs = tf.varargs; 767 size_t nfparams = Parameter.dim(fparameters); 768 for (size_t i = 0; i < nfparams; i++) 769 { 770 Parameter fparam = Parameter.getNth(fparameters, i); 771 fparam.storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); 772 fparam.storageClass |= STCparameter; 773 if (fvarargs == 2 && i + 1 == nfparams) 774 fparam.storageClass |= STCvariadic; 775 } 776 for (size_t i = 0; i < fparameters.dim; i++) 777 { 778 Parameter fparam = (*fparameters)[i]; 779 if (!fparam.ident) 780 continue; 781 // don't add it, if it has no name 782 auto v = new VarDeclaration(loc, fparam.type, fparam.ident, null); 783 v.storage_class = fparam.storageClass; 784 v.semantic(scx); 785 if (!ti.symtab) 786 ti.symtab = new DsymbolTable(); 787 if (!scx.insert(v)) 788 error("parameter %s.%s is already defined", toChars(), v.toChars()); 789 else 790 v.parent = fd; 791 } 792 if (isstatic) 793 fd.storage_class |= STCstatic; 794 fd.vthis = fd.declareThis(scx, fd.isThis()); 795 } 796 797 Expression e = constraint.syntaxCopy(); 798 799 scx = scx.startCTFE(); 800 scx.flags |= SCOPEcondition | SCOPEconstraint; 801 assert(ti.inst is null); 802 ti.inst = ti; // temporary instantiation to enable genIdent() 803 804 //printf("\tscx.parent = %s %s\n", scx.parent.kind(), scx.parent.toPrettyChars()); 805 e = e.semantic(scx); 806 e = resolveProperties(scx, e); 807 808 ti.inst = null; 809 ti.symtab = null; 810 scx = scx.endCTFE(); 811 812 scx = scx.pop(); 813 previous = pr.prev; // unlink from threaded list 814 815 if (nerrors != global.errors) // if any errors from evaluating the constraint, no match 816 return false; 817 if (e.op == TOKerror) 818 return false; 819 820 e = e.ctfeInterpret(); 821 if (e.isBool(true)) 822 { 823 } 824 else if (e.isBool(false)) 825 return false; 826 else 827 { 828 e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); 829 } 830 return true; 831 } 832 833 /*************************************** 834 * Given that ti is an instance of this TemplateDeclaration, 835 * deduce the types of the parameters to this, and store 836 * those deduced types in dedtypes[]. 837 * Input: 838 * flag 1: don't do semantic() because of dummy types 839 * 2: don't change types in matchArg() 840 * Output: 841 * dedtypes deduced arguments 842 * Return match level. 843 */ 844 MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag) 845 { 846 enum LOGM = 0; 847 static if (LOGM) 848 { 849 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); 850 } 851 version (none) 852 { 853 printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes.dim, parameters.dim); 854 if (ti.tiargs.dim) 855 printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, (*ti.tiargs)[0]); 856 } 857 MATCH m; 858 size_t dedtypes_dim = dedtypes.dim; 859 860 dedtypes.zero(); 861 862 if (errors) 863 return MATCHnomatch; 864 865 size_t parameters_dim = parameters.dim; 866 int variadic = isVariadic() !is null; 867 868 // If more arguments than parameters, no match 869 if (ti.tiargs.dim > parameters_dim && !variadic) 870 { 871 static if (LOGM) 872 { 873 printf(" no match: more arguments than parameters\n"); 874 } 875 return MATCHnomatch; 876 } 877 878 assert(dedtypes_dim == parameters_dim); 879 assert(dedtypes_dim >= ti.tiargs.dim || variadic); 880 881 assert(_scope); 882 883 // Set up scope for template parameters 884 auto paramsym = new ScopeDsymbol(); 885 paramsym.parent = _scope.parent; 886 Scope* paramscope = _scope.push(paramsym); 887 paramscope.tinst = ti; 888 paramscope.minst = sc.minst; 889 paramscope.callsc = sc; 890 paramscope.stc = 0; 891 892 // Attempt type deduction 893 m = MATCHexact; 894 for (size_t i = 0; i < dedtypes_dim; i++) 895 { 896 MATCH m2; 897 TemplateParameter tp = (*parameters)[i]; 898 Declaration sparam; 899 900 //printf("\targument [%d]\n", i); 901 static if (LOGM) 902 { 903 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); 904 TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); 905 if (ttp) 906 printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); 907 } 908 909 m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); 910 //printf("\tm2 = %d\n", m2); 911 if (m2 == MATCHnomatch) 912 { 913 version (none) 914 { 915 printf("\tmatchArg() for parameter %i failed\n", i); 916 } 917 goto Lnomatch; 918 } 919 920 if (m2 < m) 921 m = m2; 922 923 if (!flag) 924 sparam.semantic(paramscope); 925 if (!paramscope.insert(sparam)) // TODO: This check can make more early 926 { 927 // in TemplateDeclaration.semantic, and 928 // then we don't need to make sparam if flags == 0 929 goto Lnomatch; 930 } 931 } 932 933 if (!flag) 934 { 935 /* Any parameter left without a type gets the type of 936 * its corresponding arg 937 */ 938 for (size_t i = 0; i < dedtypes_dim; i++) 939 { 940 if (!(*dedtypes)[i]) 941 { 942 assert(i < ti.tiargs.dim); 943 (*dedtypes)[i] = cast(Type)(*ti.tiargs)[i]; 944 } 945 } 946 } 947 948 if (m > MATCHnomatch && constraint && !flag) 949 { 950 if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error 951 ti.parent = ti.enclosing; 952 else 953 ti.parent = this.parent; 954 955 // Similar to doHeaderInstantiation 956 FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null; 957 if (fd) 958 { 959 assert(fd.type.ty == Tfunction); 960 TypeFunction tf = cast(TypeFunction)fd.type.syntaxCopy(); 961 962 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); 963 fd.parent = ti; 964 fd.inferRetType = true; 965 966 // Shouldn't run semantic on default arguments and return type. 967 for (size_t i = 0; i < tf.parameters.dim; i++) 968 (*tf.parameters)[i].defaultArg = null; 969 tf.next = null; 970 971 // Resolve parameter types and 'auto ref's. 972 tf.fargs = fargs; 973 uint olderrors = global.startGagging(); 974 fd.type = tf.semantic(loc, paramscope); 975 if (global.endGagging(olderrors)) 976 { 977 assert(fd.type.ty != Tfunction); 978 goto Lnomatch; 979 } 980 assert(fd.type.ty == Tfunction); 981 fd.originalType = fd.type; // for mangling 982 } 983 984 // TODO: dedtypes => ti.tiargs ? 985 if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd)) 986 goto Lnomatch; 987 } 988 989 static if (LOGM) 990 { 991 // Print out the results 992 printf("--------------------------\n"); 993 printf("template %s\n", toChars()); 994 printf("instance %s\n", ti.toChars()); 995 if (m > MATCHnomatch) 996 { 997 for (size_t i = 0; i < dedtypes_dim; i++) 998 { 999 TemplateParameter tp = (*parameters)[i]; 1000 RootObject oarg; 1001 printf(" [%d]", i); 1002 if (i < ti.tiargs.dim) 1003 oarg = (*ti.tiargs)[i]; 1004 else 1005 oarg = null; 1006 tp.print(oarg, (*dedtypes)[i]); 1007 } 1008 } 1009 else 1010 goto Lnomatch; 1011 } 1012 static if (LOGM) 1013 { 1014 printf(" match = %d\n", m); 1015 } 1016 goto Lret; 1017 1018 Lnomatch: 1019 static if (LOGM) 1020 { 1021 printf(" no match\n"); 1022 } 1023 m = MATCHnomatch; 1024 1025 Lret: 1026 paramscope.pop(); 1027 static if (LOGM) 1028 { 1029 printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); 1030 } 1031 return m; 1032 } 1033 1034 /******************************************** 1035 * Determine partial specialization order of 'this' vs td2. 1036 * Returns: 1037 * match this is at least as specialized as td2 1038 * 0 td2 is more specialized than this 1039 */ 1040 MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs) 1041 { 1042 enum LOG_LEASTAS = 0; 1043 static if (LOG_LEASTAS) 1044 { 1045 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); 1046 } 1047 1048 /* This works by taking the template parameters to this template 1049 * declaration and feeding them to td2 as if it were a template 1050 * instance. 1051 * If it works, then this template is at least as specialized 1052 * as td2. 1053 */ 1054 1055 // Set type arguments to dummy template instance to be types 1056 // generated from the parameters to this template declaration 1057 auto tiargs = new Objects(); 1058 tiargs.reserve(parameters.dim); 1059 for (size_t i = 0; i < parameters.dim; i++) 1060 { 1061 TemplateParameter tp = (*parameters)[i]; 1062 if (tp.dependent) 1063 break; 1064 RootObject p = cast(RootObject)tp.dummyArg(); 1065 if (!p) 1066 break; 1067 1068 tiargs.push(p); 1069 } 1070 scope TemplateInstance ti = new TemplateInstance(Loc(), ident, tiargs); // create dummy template instance 1071 1072 // Temporary Array to hold deduced types 1073 Objects dedtypes; 1074 dedtypes.setDim(td2.parameters.dim); 1075 1076 // Attempt a type deduction 1077 MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1); 1078 if (m > MATCHnomatch) 1079 { 1080 /* A non-variadic template is more specialized than a 1081 * variadic one. 1082 */ 1083 TemplateTupleParameter tp = isVariadic(); 1084 if (tp && !tp.dependent && !td2.isVariadic()) 1085 goto L1; 1086 1087 static if (LOG_LEASTAS) 1088 { 1089 printf(" matches %d, so is least as specialized\n", m); 1090 } 1091 return m; 1092 } 1093 L1: 1094 static if (LOG_LEASTAS) 1095 { 1096 printf(" doesn't match, so is not as specialized\n"); 1097 } 1098 return MATCHnomatch; 1099 } 1100 1101 /************************************************* 1102 * Match function arguments against a specific template function. 1103 * Input: 1104 * ti 1105 * sc instantiation scope 1106 * fd 1107 * tthis 'this' argument if !NULL 1108 * fargs arguments to function 1109 * Output: 1110 * fd Partially instantiated function declaration 1111 * ti.tdtypes Expression/Type deduced template arguments 1112 * Returns: 1113 * match level 1114 * bit 0-3 Match template parameters by inferred template arguments 1115 * bit 4-7 Match template parameters by initial template arguments 1116 */ 1117 MATCH deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs) 1118 { 1119 size_t nfparams; 1120 size_t nfargs; 1121 size_t ntargs; // array size of tiargs 1122 size_t fptupindex = IDX_NOTFOUND; 1123 MATCH match = MATCHexact; 1124 MATCH matchTiargs = MATCHexact; 1125 Parameters* fparameters; // function parameter list 1126 int fvarargs; // function varargs 1127 uint wildmatch = 0; 1128 size_t inferStart = 0; 1129 1130 Loc instLoc = ti.loc; 1131 Objects* tiargs = ti.tiargs; 1132 auto dedargs = new Objects(); 1133 Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T 1134 1135 version (none) 1136 { 1137 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); 1138 for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++) 1139 { 1140 Expression e = (*fargs)[i]; 1141 printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars()); 1142 } 1143 printf("fd = %s\n", fd.toChars()); 1144 printf("fd.type = %s\n", fd.type.toChars()); 1145 if (tthis) 1146 printf("tthis = %s\n", tthis.toChars()); 1147 } 1148 1149 assert(_scope); 1150 1151 dedargs.setDim(parameters.dim); 1152 dedargs.zero(); 1153 1154 dedtypes.setDim(parameters.dim); 1155 dedtypes.zero(); 1156 1157 if (errors || fd.errors) 1158 return MATCHnomatch; 1159 1160 // Set up scope for parameters 1161 auto paramsym = new ScopeDsymbol(); 1162 paramsym.parent = _scope.parent; // should use hasnestedArgs and enclosing? 1163 Scope* paramscope = _scope.push(paramsym); 1164 paramscope.tinst = ti; 1165 paramscope.minst = sc.minst; 1166 paramscope.callsc = sc; 1167 paramscope.stc = 0; 1168 1169 TemplateTupleParameter tp = isVariadic(); 1170 Tuple declaredTuple = null; 1171 1172 version (none) 1173 { 1174 for (size_t i = 0; i < dedargs.dim; i++) 1175 { 1176 printf("\tdedarg[%d] = ", i); 1177 RootObject oarg = (*dedargs)[i]; 1178 if (oarg) 1179 printf("%s", oarg.toChars()); 1180 printf("\n"); 1181 } 1182 } 1183 1184 ntargs = 0; 1185 if (tiargs) 1186 { 1187 // Set initial template arguments 1188 ntargs = tiargs.dim; 1189 size_t n = parameters.dim; 1190 if (tp) 1191 n--; 1192 if (ntargs > n) 1193 { 1194 if (!tp) 1195 goto Lnomatch; 1196 1197 /* The extra initial template arguments 1198 * now form the tuple argument. 1199 */ 1200 auto t = new Tuple(); 1201 assert(parameters.dim); 1202 (*dedargs)[parameters.dim - 1] = t; 1203 1204 t.objects.setDim(ntargs - n); 1205 for (size_t i = 0; i < t.objects.dim; i++) 1206 { 1207 t.objects[i] = (*tiargs)[n + i]; 1208 } 1209 declareParameter(paramscope, tp, t); 1210 declaredTuple = t; 1211 } 1212 else 1213 n = ntargs; 1214 1215 memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); 1216 1217 for (size_t i = 0; i < n; i++) 1218 { 1219 assert(i < parameters.dim); 1220 Declaration sparam = null; 1221 MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam); 1222 //printf("\tdeduceType m = %d\n", m); 1223 if (m <= MATCHnomatch) 1224 goto Lnomatch; 1225 if (m < matchTiargs) 1226 matchTiargs = m; 1227 1228 sparam.semantic(paramscope); 1229 if (!paramscope.insert(sparam)) 1230 goto Lnomatch; 1231 } 1232 if (n < parameters.dim && !declaredTuple) 1233 { 1234 inferStart = n; 1235 } 1236 else 1237 inferStart = parameters.dim; 1238 //printf("tiargs matchTiargs = %d\n", matchTiargs); 1239 } 1240 version (none) 1241 { 1242 for (size_t i = 0; i < dedargs.dim; i++) 1243 { 1244 printf("\tdedarg[%d] = ", i); 1245 RootObject oarg = (*dedargs)[i]; 1246 if (oarg) 1247 printf("%s", oarg.toChars()); 1248 printf("\n"); 1249 } 1250 } 1251 1252 fparameters = fd.getParameters(&fvarargs); 1253 nfparams = Parameter.dim(fparameters); // number of function parameters 1254 nfargs = fargs ? fargs.dim : 0; // number of function arguments 1255 1256 /* Check for match of function arguments with variadic template 1257 * parameter, such as: 1258 * 1259 * void foo(T, A...)(T t, A a); 1260 * void main() { foo(1,2,3); } 1261 */ 1262 if (tp) // if variadic 1263 { 1264 // TemplateTupleParameter always makes most lesser matching. 1265 matchTiargs = MATCHconvert; 1266 1267 if (nfparams == 0 && nfargs != 0) // if no function parameters 1268 { 1269 if (!declaredTuple) 1270 { 1271 auto t = new Tuple(); 1272 //printf("t = %p\n", t); 1273 (*dedargs)[parameters.dim - 1] = t; 1274 declareParameter(paramscope, tp, t); 1275 declaredTuple = t; 1276 } 1277 } 1278 else 1279 { 1280 /* Figure out which of the function parameters matches 1281 * the tuple template parameter. Do this by matching 1282 * type identifiers. 1283 * Set the index of this function parameter to fptupindex. 1284 */ 1285 for (fptupindex = 0; fptupindex < nfparams; fptupindex++) 1286 { 1287 Parameter fparam = (*fparameters)[fptupindex]; 1288 if (fparam.type.ty != Tident) 1289 continue; 1290 TypeIdentifier tid = cast(TypeIdentifier)fparam.type; 1291 if (!tp.ident.equals(tid.ident) || tid.idents.dim) 1292 continue; 1293 1294 if (fvarargs) // variadic function doesn't 1295 goto Lnomatch; // go with variadic template 1296 1297 goto L1; 1298 } 1299 fptupindex = IDX_NOTFOUND; 1300 L1: 1301 } 1302 } 1303 1304 if (toParent().isModule() || (_scope.stc & STCstatic)) 1305 tthis = null; 1306 if (tthis) 1307 { 1308 bool hasttp = false; 1309 1310 // Match 'tthis' to any TemplateThisParameter's 1311 for (size_t i = 0; i < parameters.dim; i++) 1312 { 1313 TemplateThisParameter ttp = (*parameters)[i].isTemplateThisParameter(); 1314 if (ttp) 1315 { 1316 hasttp = true; 1317 1318 Type t = new TypeIdentifier(Loc(), ttp.ident); 1319 MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes); 1320 if (m <= MATCHnomatch) 1321 goto Lnomatch; 1322 if (m < match) 1323 match = m; // pick worst match 1324 } 1325 } 1326 1327 // Match attributes of tthis against attributes of fd 1328 if (fd.type && !fd.isCtorDeclaration()) 1329 { 1330 StorageClass stc = _scope.stc | fd.storage_class2; 1331 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 1332 Dsymbol p = parent; 1333 while (p.isTemplateDeclaration() || p.isTemplateInstance()) 1334 p = p.parent; 1335 AggregateDeclaration ad = p.isAggregateDeclaration(); 1336 if (ad) 1337 stc |= ad.storage_class; 1338 1339 ubyte mod = fd.type.mod; 1340 if (stc & STCimmutable) 1341 mod = MODimmutable; 1342 else 1343 { 1344 if (stc & (STCshared | STCsynchronized)) 1345 mod |= MODshared; 1346 if (stc & STCconst) 1347 mod |= MODconst; 1348 if (stc & STCwild) 1349 mod |= MODwild; 1350 } 1351 1352 ubyte thismod = tthis.mod; 1353 if (hasttp) 1354 mod = MODmerge(thismod, mod); 1355 MATCH m = MODmethodConv(thismod, mod); 1356 if (m <= MATCHnomatch) 1357 goto Lnomatch; 1358 if (m < match) 1359 match = m; 1360 } 1361 } 1362 1363 // Loop through the function parameters 1364 { 1365 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.dim : 0); 1366 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); 1367 size_t argi = 0; 1368 size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs 1369 for (size_t parami = 0; parami < nfparams; parami++) 1370 { 1371 Parameter fparam = Parameter.getNth(fparameters, parami); 1372 1373 // Apply function parameter storage classes to parameter types 1374 Type prmtype = fparam.type.addStorageClass(fparam.storageClass); 1375 1376 Expression farg; 1377 1378 /* See function parameters which wound up 1379 * as part of a template tuple parameter. 1380 */ 1381 if (fptupindex != IDX_NOTFOUND && parami == fptupindex) 1382 { 1383 assert(prmtype.ty == Tident); 1384 TypeIdentifier tid = cast(TypeIdentifier)prmtype; 1385 if (!declaredTuple) 1386 { 1387 /* The types of the function arguments 1388 * now form the tuple argument. 1389 */ 1390 declaredTuple = new Tuple(); 1391 (*dedargs)[parameters.dim - 1] = declaredTuple; 1392 1393 /* Count function parameters following a tuple parameter. 1394 * void foo(U, T...)(int y, T, U, int) {} // rem == 2 (U, int) 1395 */ 1396 size_t rem = 0; 1397 for (size_t j = parami + 1; j < nfparams; j++) 1398 { 1399 Parameter p = Parameter.getNth(fparameters, j); 1400 if (!reliesOnTident(p.type, parameters, inferStart)) 1401 { 1402 Type pt = p.type.syntaxCopy().semantic(fd.loc, paramscope); 1403 rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.dim : 1; 1404 } 1405 else 1406 { 1407 ++rem; 1408 } 1409 } 1410 1411 if (nfargs2 - argi < rem) 1412 goto Lnomatch; 1413 declaredTuple.objects.setDim(nfargs2 - argi - rem); 1414 for (size_t i = 0; i < declaredTuple.objects.dim; i++) 1415 { 1416 farg = (*fargs)[argi + i]; 1417 1418 // Check invalid arguments to detect errors early. 1419 if (farg.op == TOKerror || farg.type.ty == Terror) 1420 goto Lnomatch; 1421 1422 if (!(fparam.storageClass & STClazy) && farg.type.ty == Tvoid) 1423 goto Lnomatch; 1424 1425 Type tt; 1426 MATCH m; 1427 if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) 1428 { 1429 wildmatch |= wm; 1430 m = MATCHconst; 1431 } 1432 else 1433 { 1434 m = deduceTypeHelper(farg.type, &tt, tid); 1435 } 1436 if (m <= MATCHnomatch) 1437 goto Lnomatch; 1438 if (m < match) 1439 match = m; 1440 1441 /* Remove top const for dynamic array types and pointer types 1442 */ 1443 if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STCref) || (fparam.storageClass & STCauto) && !farg.isLvalue())) 1444 { 1445 tt = tt.mutableOf(); 1446 } 1447 declaredTuple.objects[i] = tt; 1448 } 1449 declareParameter(paramscope, tp, declaredTuple); 1450 } 1451 else 1452 { 1453 // https://issues.dlang.org/show_bug.cgi?id=6810 1454 // If declared tuple is not a type tuple, 1455 // it cannot be function parameter types. 1456 for (size_t i = 0; i < declaredTuple.objects.dim; i++) 1457 { 1458 if (!isType(declaredTuple.objects[i])) 1459 goto Lnomatch; 1460 } 1461 } 1462 assert(declaredTuple); 1463 argi += declaredTuple.objects.dim; 1464 continue; 1465 } 1466 1467 // If parameter type doesn't depend on inferred template parameters, 1468 // semantic it to get actual type. 1469 if (!reliesOnTident(prmtype, parameters, inferStart)) 1470 { 1471 // should copy prmtype to avoid affecting semantic result 1472 prmtype = prmtype.syntaxCopy().semantic(fd.loc, paramscope); 1473 1474 if (prmtype.ty == Ttuple) 1475 { 1476 TypeTuple tt = cast(TypeTuple)prmtype; 1477 size_t tt_dim = tt.arguments.dim; 1478 for (size_t j = 0; j < tt_dim; j++, ++argi) 1479 { 1480 Parameter p = (*tt.arguments)[j]; 1481 if (j == tt_dim - 1 && fvarargs == 2 && parami + 1 == nfparams && argi < nfargs) 1482 { 1483 prmtype = p.type; 1484 goto Lvarargs; 1485 } 1486 if (argi >= nfargs) 1487 { 1488 if (p.defaultArg) 1489 continue; 1490 goto Lnomatch; 1491 } 1492 farg = (*fargs)[argi]; 1493 if (!farg.implicitConvTo(p.type)) 1494 goto Lnomatch; 1495 } 1496 continue; 1497 } 1498 } 1499 1500 if (argi >= nfargs) // if not enough arguments 1501 { 1502 if (!fparam.defaultArg) 1503 goto Lvarargs; 1504 1505 /* https://issues.dlang.org/show_bug.cgi?id=2803 1506 * Before the starting of type deduction from the function 1507 * default arguments, set the already deduced parameters into paramscope. 1508 * It's necessary to avoid breaking existing acceptable code. Cases: 1509 * 1510 * 1. Already deduced template parameters can appear in fparam.defaultArg: 1511 * auto foo(A, B)(A a, B b = A.stringof); 1512 * foo(1); 1513 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' 1514 * 1515 * 2. If prmtype depends on default-specified template parameter, the 1516 * default type should be preferred. 1517 * auto foo(N = size_t, R)(R r, N start = 0) 1518 * foo([1,2,3]); 1519 * // at fparam `N start = 0`, N should be 'size_t' before 1520 * // the deduction result from fparam.defaultArg. 1521 */ 1522 if (argi == nfargs) 1523 { 1524 for (size_t i = 0; i < dedtypes.dim; i++) 1525 { 1526 Type at = isType((*dedtypes)[i]); 1527 if (at && at.ty == Tnone) 1528 { 1529 TypeDeduced xt = cast(TypeDeduced)at; 1530 (*dedtypes)[i] = xt.tded; // 'unbox' 1531 } 1532 } 1533 for (size_t i = ntargs; i < dedargs.dim; i++) 1534 { 1535 TemplateParameter tparam = (*parameters)[i]; 1536 1537 RootObject oarg = (*dedargs)[i]; 1538 RootObject oded = (*dedtypes)[i]; 1539 if (!oarg) 1540 { 1541 if (oded) 1542 { 1543 if (tparam.specialization() || !tparam.isTemplateTypeParameter()) 1544 { 1545 /* The specialization can work as long as afterwards 1546 * the oded == oarg 1547 */ 1548 (*dedargs)[i] = oded; 1549 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); 1550 //printf("m2 = %d\n", m2); 1551 if (m2 <= MATCHnomatch) 1552 goto Lnomatch; 1553 if (m2 < matchTiargs) 1554 matchTiargs = m2; // pick worst match 1555 if (!(*dedtypes)[i].equals(oded)) 1556 error("specialization not allowed for deduced parameter %s", tparam.ident.toChars()); 1557 } 1558 else 1559 { 1560 if (MATCHconvert < matchTiargs) 1561 matchTiargs = MATCHconvert; 1562 } 1563 (*dedargs)[i] = declareParameter(paramscope, tparam, oded); 1564 } 1565 else 1566 { 1567 oded = tparam.defaultArg(instLoc, paramscope); 1568 if (oded) 1569 (*dedargs)[i] = declareParameter(paramscope, tparam, oded); 1570 } 1571 } 1572 } 1573 } 1574 nfargs2 = argi + 1; 1575 1576 /* If prmtype does not depend on any template parameters: 1577 * 1578 * auto foo(T)(T v, double x = 0); 1579 * foo("str"); 1580 * // at fparam == 'double x = 0' 1581 * 1582 * or, if all template parameters in the prmtype are already deduced: 1583 * 1584 * auto foo(R)(R range, ElementType!R sum = 0); 1585 * foo([1,2,3]); 1586 * // at fparam == 'ElementType!R sum = 0' 1587 * 1588 * Deducing prmtype from fparam.defaultArg is not necessary. 1589 */ 1590 if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope)) 1591 { 1592 ++argi; 1593 continue; 1594 } 1595 1596 // Deduce prmtype from the defaultArg. 1597 farg = fparam.defaultArg.syntaxCopy(); 1598 farg = farg.semantic(paramscope); 1599 farg = resolveProperties(paramscope, farg); 1600 } 1601 else 1602 { 1603 farg = (*fargs)[argi]; 1604 } 1605 { 1606 // Check invalid arguments to detect errors early. 1607 if (farg.op == TOKerror || farg.type.ty == Terror) 1608 goto Lnomatch; 1609 1610 Type att = null; 1611 Lretry: 1612 version (none) 1613 { 1614 printf("\tfarg.type = %s\n", farg.type.toChars()); 1615 printf("\tfparam.type = %s\n", prmtype.toChars()); 1616 } 1617 Type argtype = farg.type; 1618 1619 if (!(fparam.storageClass & STClazy) && argtype.ty == Tvoid && farg.op != TOKfunction) 1620 goto Lnomatch; 1621 1622 // https://issues.dlang.org/show_bug.cgi?id=12876 1623 // Optimize argument to allow CT-known length matching 1624 farg = farg.optimize(WANTvalue, (fparam.storageClass & (STCref | STCout)) != 0); 1625 //printf("farg = %s %s\n", farg.type.toChars(), fargtoChars()); 1626 1627 RootObject oarg = farg; 1628 if ((fparam.storageClass & STCref) && (!(fparam.storageClass & STCauto) || farg.isLvalue())) 1629 { 1630 /* Allow expressions that have CT-known boundaries and type [] to match with [dim] 1631 */ 1632 Type taai; 1633 if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) 1634 { 1635 if (farg.op == TOKstring) 1636 { 1637 StringExp se = cast(StringExp)farg; 1638 argtype = se.type.nextOf().sarrayOf(se.len); 1639 } 1640 else if (farg.op == TOKarrayliteral) 1641 { 1642 ArrayLiteralExp ae = cast(ArrayLiteralExp)farg; 1643 argtype = ae.type.nextOf().sarrayOf(ae.elements.dim); 1644 } 1645 else if (farg.op == TOKslice) 1646 { 1647 SliceExp se = cast(SliceExp)farg; 1648 if (Type tsa = toStaticArrayType(se)) 1649 argtype = tsa; 1650 } 1651 } 1652 1653 oarg = argtype; 1654 } 1655 else if ((fparam.storageClass & STCout) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.dim == 0) 1656 { 1657 /* The farg passing to the prmtype always make a copy. Therefore, 1658 * we can shrink the set of the deduced type arguments for prmtype 1659 * by adjusting top-qualifier of the argtype. 1660 * 1661 * prmtype argtype ta 1662 * T <- const(E)[] const(E)[] 1663 * T <- const(E[]) const(E)[] 1664 * qualifier(T) <- const(E)[] const(E[]) 1665 * qualifier(T) <- const(E[]) const(E[]) 1666 */ 1667 Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); 1668 if (ta != argtype) 1669 { 1670 Expression ea = farg.copy(); 1671 ea.type = ta; 1672 oarg = ea; 1673 } 1674 } 1675 1676 if (fvarargs == 2 && parami + 1 == nfparams && argi + 1 < nfargs) 1677 goto Lvarargs; 1678 1679 uint wm = 0; 1680 MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart); 1681 //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch); 1682 wildmatch |= wm; 1683 1684 /* If no match, see if the argument can be matched by using 1685 * implicit conversions. 1686 */ 1687 if (m == MATCHnomatch && prmtype.deco) 1688 m = farg.implicitConvTo(prmtype); 1689 1690 if (m == MATCHnomatch) 1691 { 1692 AggregateDeclaration ad = isAggregate(farg.type); 1693 if (ad && ad.aliasthis && argtype != att) 1694 { 1695 if (!att && argtype.checkAliasThisRec()) // https://issues.dlang.org/show_bug.cgi?id=12537 1696 att = argtype; 1697 /* If a semantic error occurs while doing alias this, 1698 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), 1699 * just regard it as not a match. 1700 */ 1701 if (auto e = resolveAliasThis(sc, farg, true)) 1702 { 1703 farg = e; 1704 goto Lretry; 1705 } 1706 } 1707 } 1708 1709 if (m > MATCHnomatch && (fparam.storageClass & (STCref | STCauto)) == STCref) 1710 { 1711 if (!farg.isLvalue()) 1712 { 1713 if ((farg.op == TOKstring || farg.op == TOKslice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) 1714 { 1715 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] 1716 } 1717 else 1718 goto Lnomatch; 1719 } 1720 } 1721 if (m > MATCHnomatch && (fparam.storageClass & STCout)) 1722 { 1723 if (!farg.isLvalue()) 1724 goto Lnomatch; 1725 if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 1726 goto Lnomatch; 1727 } 1728 if (m == MATCHnomatch && (fparam.storageClass & STClazy) && prmtype.ty == Tvoid && farg.type.ty != Tvoid) 1729 m = MATCHconvert; 1730 if (m != MATCHnomatch) 1731 { 1732 if (m < match) 1733 match = m; // pick worst match 1734 argi++; 1735 continue; 1736 } 1737 } 1738 1739 Lvarargs: 1740 /* The following code for variadic arguments closely 1741 * matches TypeFunction.callMatch() 1742 */ 1743 if (!(fvarargs == 2 && parami + 1 == nfparams)) 1744 goto Lnomatch; 1745 1746 /* Check for match with function parameter T... 1747 */ 1748 Type tb = prmtype.toBasetype(); 1749 switch (tb.ty) 1750 { 1751 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). 1752 case Tsarray: 1753 case Taarray: 1754 { 1755 // Perhaps we can do better with this, see TypeFunction.callMatch() 1756 if (tb.ty == Tsarray) 1757 { 1758 TypeSArray tsa = cast(TypeSArray)tb; 1759 dinteger_t sz = tsa.dim.toInteger(); 1760 if (sz != nfargs - argi) 1761 goto Lnomatch; 1762 } 1763 else if (tb.ty == Taarray) 1764 { 1765 TypeAArray taa = cast(TypeAArray)tb; 1766 Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t); 1767 1768 size_t i = templateParameterLookup(taa.index, parameters); 1769 if (i == IDX_NOTFOUND) 1770 { 1771 Expression e; 1772 Type t; 1773 Dsymbol s; 1774 taa.index.resolve(instLoc, sc, &e, &t, &s); 1775 if (!e) 1776 goto Lnomatch; 1777 e = e.ctfeInterpret(); 1778 e = e.implicitCastTo(sc, Type.tsize_t); 1779 e = e.optimize(WANTvalue); 1780 if (!dim.equals(e)) 1781 goto Lnomatch; 1782 } 1783 else 1784 { 1785 // This code matches code in TypeInstance.deduceType() 1786 TemplateParameter tprm = (*parameters)[i]; 1787 TemplateValueParameter tvp = tprm.isTemplateValueParameter(); 1788 if (!tvp) 1789 goto Lnomatch; 1790 Expression e = cast(Expression)(*dedtypes)[i]; 1791 if (e) 1792 { 1793 if (!dim.equals(e)) 1794 goto Lnomatch; 1795 } 1796 else 1797 { 1798 Type vt = tvp.valType.semantic(Loc(), sc); 1799 MATCH m = dim.implicitConvTo(vt); 1800 if (m <= MATCHnomatch) 1801 goto Lnomatch; 1802 (*dedtypes)[i] = dim; 1803 } 1804 } 1805 } 1806 goto case Tarray; 1807 } 1808 case Tarray: 1809 { 1810 TypeArray ta = cast(TypeArray)tb; 1811 Type tret = fparam.isLazyArray(); 1812 for (; argi < nfargs; argi++) 1813 { 1814 Expression arg = (*fargs)[argi]; 1815 assert(arg); 1816 1817 MATCH m; 1818 /* If lazy array of delegates, 1819 * convert arg(s) to delegate(s) 1820 */ 1821 if (tret) 1822 { 1823 if (ta.next.equals(arg.type)) 1824 { 1825 m = MATCHexact; 1826 } 1827 else 1828 { 1829 m = arg.implicitConvTo(tret); 1830 if (m == MATCHnomatch) 1831 { 1832 if (tret.toBasetype().ty == Tvoid) 1833 m = MATCHconvert; 1834 } 1835 } 1836 } 1837 else 1838 { 1839 uint wm = 0; 1840 m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart); 1841 wildmatch |= wm; 1842 } 1843 if (m == MATCHnomatch) 1844 goto Lnomatch; 1845 if (m < match) 1846 match = m; 1847 } 1848 goto Lmatch; 1849 } 1850 case Tclass: 1851 case Tident: 1852 goto Lmatch; 1853 1854 default: 1855 goto Lnomatch; 1856 } 1857 assert(0); 1858 } 1859 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); 1860 if (argi != nfargs2 && !fvarargs) 1861 goto Lnomatch; 1862 } 1863 1864 Lmatch: 1865 for (size_t i = 0; i < dedtypes.dim; i++) 1866 { 1867 Type at = isType((*dedtypes)[i]); 1868 if (at) 1869 { 1870 if (at.ty == Tnone) 1871 { 1872 TypeDeduced xt = cast(TypeDeduced)at; 1873 at = xt.tded; // 'unbox' 1874 } 1875 (*dedtypes)[i] = at.merge2(); 1876 } 1877 } 1878 for (size_t i = ntargs; i < dedargs.dim; i++) 1879 { 1880 TemplateParameter tparam = (*parameters)[i]; 1881 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); 1882 1883 /* For T:T*, the dedargs is the T*, dedtypes is the T 1884 * But for function templates, we really need them to match 1885 */ 1886 RootObject oarg = (*dedargs)[i]; 1887 RootObject oded = (*dedtypes)[i]; 1888 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); 1889 //if (oarg) printf("oarg: %s\n", oarg.toChars()); 1890 //if (oded) printf("oded: %s\n", oded.toChars()); 1891 if (!oarg) 1892 { 1893 if (oded) 1894 { 1895 if (tparam.specialization() || !tparam.isTemplateTypeParameter()) 1896 { 1897 /* The specialization can work as long as afterwards 1898 * the oded == oarg 1899 */ 1900 (*dedargs)[i] = oded; 1901 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); 1902 //printf("m2 = %d\n", m2); 1903 if (m2 <= MATCHnomatch) 1904 goto Lnomatch; 1905 if (m2 < matchTiargs) 1906 matchTiargs = m2; // pick worst match 1907 if (!(*dedtypes)[i].equals(oded)) 1908 error("specialization not allowed for deduced parameter %s", tparam.ident.toChars()); 1909 } 1910 else 1911 { 1912 if (MATCHconvert < matchTiargs) 1913 matchTiargs = MATCHconvert; 1914 } 1915 } 1916 else 1917 { 1918 oded = tparam.defaultArg(instLoc, paramscope); 1919 if (!oded) 1920 { 1921 // if tuple parameter and 1922 // tuple parameter was not in function parameter list and 1923 // we're one or more arguments short (i.e. no tuple argument) 1924 if (tparam == tp && 1925 fptupindex == IDX_NOTFOUND && 1926 ntargs <= dedargs.dim - 1) 1927 { 1928 // make tuple argument an empty tuple 1929 oded = cast(RootObject)new Tuple(); 1930 } 1931 else 1932 goto Lnomatch; 1933 } 1934 if (isError(oded)) 1935 goto Lerror; 1936 ntargs++; 1937 1938 /* At the template parameter T, the picked default template argument 1939 * X!int should be matched to T in order to deduce dependent 1940 * template parameter A. 1941 * auto foo(T : X!A = X!int, A...)() { ... } 1942 * foo(); // T <-- X!int, A <-- (int) 1943 */ 1944 if (tparam.specialization()) 1945 { 1946 (*dedargs)[i] = oded; 1947 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null); 1948 //printf("m2 = %d\n", m2); 1949 if (m2 <= MATCHnomatch) 1950 goto Lnomatch; 1951 if (m2 < matchTiargs) 1952 matchTiargs = m2; // pick worst match 1953 if (!(*dedtypes)[i].equals(oded)) 1954 error("specialization not allowed for deduced parameter %s", tparam.ident.toChars()); 1955 } 1956 } 1957 oded = declareParameter(paramscope, tparam, oded); 1958 (*dedargs)[i] = oded; 1959 } 1960 } 1961 1962 /* https://issues.dlang.org/show_bug.cgi?id=7469 1963 * As same as the code for 7469 in findBestMatch, 1964 * expand a Tuple in dedargs to normalize template arguments. 1965 */ 1966 if (auto d = dedargs.dim) 1967 { 1968 if (auto va = isTuple((*dedargs)[d - 1])) 1969 { 1970 dedargs.setDim(d - 1); 1971 dedargs.insert(d - 1, &va.objects); 1972 } 1973 } 1974 ti.tiargs = dedargs; // update to the normalized template arguments. 1975 1976 // Partially instantiate function for constraint and fd.leastAsSpecialized() 1977 { 1978 assert(paramsym); 1979 Scope* sc2 = _scope; 1980 sc2 = sc2.push(paramsym); 1981 sc2 = sc2.push(ti); 1982 sc2.parent = ti; 1983 sc2.tinst = ti; 1984 sc2.minst = sc.minst; 1985 1986 fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); 1987 1988 sc2 = sc2.pop(); 1989 sc2 = sc2.pop(); 1990 1991 if (!fd) 1992 goto Lnomatch; 1993 } 1994 1995 if (constraint) 1996 { 1997 if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) 1998 goto Lnomatch; 1999 } 2000 2001 version (none) 2002 { 2003 for (size_t i = 0; i < dedargs.dim; i++) 2004 { 2005 RootObject o = (*dedargs)[i]; 2006 printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); 2007 } 2008 } 2009 2010 paramscope.pop(); 2011 //printf("\tmatch %d\n", match); 2012 return cast(MATCH)(match | (matchTiargs << 4)); 2013 2014 Lnomatch: 2015 paramscope.pop(); 2016 //printf("\tnomatch\n"); 2017 return MATCHnomatch; 2018 2019 Lerror: 2020 // todo: for the future improvement 2021 paramscope.pop(); 2022 //printf("\terror\n"); 2023 return MATCHnomatch; 2024 } 2025 2026 /************************************************** 2027 * Declare template parameter tp with value o, and install it in the scope sc. 2028 */ 2029 RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o) 2030 { 2031 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); 2032 Type ta = isType(o); 2033 Expression ea = isExpression(o); 2034 Dsymbol sa = isDsymbol(o); 2035 Tuple va = isTuple(o); 2036 2037 Declaration d; 2038 VarDeclaration v = null; 2039 2040 if (ea && ea.op == TOKtype) 2041 ta = ea.type; 2042 else if (ea && ea.op == TOKscope) 2043 sa = (cast(ScopeExp)ea).sds; 2044 else if (ea && (ea.op == TOKthis || ea.op == TOKsuper)) 2045 sa = (cast(ThisExp)ea).var; 2046 else if (ea && ea.op == TOKfunction) 2047 { 2048 if ((cast(FuncExp)ea).td) 2049 sa = (cast(FuncExp)ea).td; 2050 else 2051 sa = (cast(FuncExp)ea).fd; 2052 } 2053 2054 if (ta) 2055 { 2056 //printf("type %s\n", ta.toChars()); 2057 d = new AliasDeclaration(Loc(), tp.ident, ta); 2058 } 2059 else if (sa) 2060 { 2061 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); 2062 d = new AliasDeclaration(Loc(), tp.ident, sa); 2063 } 2064 else if (ea) 2065 { 2066 // tdtypes.data[i] always matches ea here 2067 Initializer _init = new ExpInitializer(loc, ea); 2068 TemplateValueParameter tvp = tp.isTemplateValueParameter(); 2069 Type t = tvp ? tvp.valType : null; 2070 v = new VarDeclaration(loc, t, tp.ident, _init); 2071 v.storage_class = STCmanifest | STCtemplateparameter; 2072 d = v; 2073 } 2074 else if (va) 2075 { 2076 //printf("\ttuple\n"); 2077 d = new TupleDeclaration(loc, tp.ident, &va.objects); 2078 } 2079 else 2080 { 2081 debug 2082 { 2083 o.print(); 2084 } 2085 assert(0); 2086 } 2087 d.storage_class |= STCtemplateparameter; 2088 2089 if (ta) 2090 { 2091 Type t = ta; 2092 // consistent with Type.checkDeprecated() 2093 while (t.ty != Tenum) 2094 { 2095 if (!t.nextOf()) 2096 break; 2097 t = (cast(TypeNext)t).next; 2098 } 2099 if (Dsymbol s = t.toDsymbol(sc)) 2100 { 2101 if (s.isDeprecated()) 2102 d.storage_class |= STCdeprecated; 2103 } 2104 } 2105 else if (sa) 2106 { 2107 if (sa.isDeprecated()) 2108 d.storage_class |= STCdeprecated; 2109 } 2110 2111 if (!sc.insert(d)) 2112 error("declaration %s is already defined", tp.ident.toChars()); 2113 d.semantic(sc); 2114 /* So the caller's o gets updated with the result of semantic() being run on o 2115 */ 2116 if (v) 2117 o = v._init.toExpression(); 2118 return o; 2119 } 2120 2121 /************************************************* 2122 * Limited function template instantiation for using fd.leastAsSpecialized() 2123 */ 2124 FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs) 2125 { 2126 assert(fd); 2127 version (none) 2128 { 2129 printf("doHeaderInstantiation this = %s\n", toChars()); 2130 } 2131 2132 // function body and contracts are not need 2133 if (fd.isCtorDeclaration()) 2134 fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy()); 2135 else 2136 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy()); 2137 fd.parent = ti; 2138 2139 assert(fd.type.ty == Tfunction); 2140 TypeFunction tf = cast(TypeFunction)fd.type; 2141 tf.fargs = fargs; 2142 2143 if (tthis) 2144 { 2145 // Match 'tthis' to any TemplateThisParameter's 2146 bool hasttp = false; 2147 for (size_t i = 0; i < parameters.dim; i++) 2148 { 2149 TemplateParameter tp = (*parameters)[i]; 2150 TemplateThisParameter ttp = tp.isTemplateThisParameter(); 2151 if (ttp) 2152 hasttp = true; 2153 } 2154 if (hasttp) 2155 { 2156 tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod)); 2157 assert(!tf.deco); 2158 } 2159 } 2160 2161 Scope* scx = sc2.push(); 2162 2163 // Shouldn't run semantic on default arguments and return type. 2164 for (size_t i = 0; i < tf.parameters.dim; i++) 2165 (*tf.parameters)[i].defaultArg = null; 2166 if (fd.isCtorDeclaration()) 2167 { 2168 // For constructors, emitting return type is necessary for 2169 // isolateReturn() in functionResolve. 2170 scx.flags |= SCOPEctor; 2171 2172 Dsymbol parent = toParent2(); 2173 Type tret; 2174 AggregateDeclaration ad = parent.isAggregateDeclaration(); 2175 if (!ad || parent.isUnionDeclaration()) 2176 { 2177 tret = Type.tvoid; 2178 } 2179 else 2180 { 2181 tret = ad.handleType(); 2182 assert(tret); 2183 tret = tret.addStorageClass(fd.storage_class | scx.stc); 2184 tret = tret.addMod(tf.mod); 2185 } 2186 tf.next = tret; 2187 if (ad && ad.isStructDeclaration()) 2188 tf.isref = 1; 2189 //printf("tf = %s\n", tf.toChars()); 2190 } 2191 else 2192 tf.next = null; 2193 fd.type = tf; 2194 fd.type = fd.type.addSTC(scx.stc); 2195 fd.type = fd.type.semantic(fd.loc, scx); 2196 scx = scx.pop(); 2197 2198 if (fd.type.ty != Tfunction) 2199 return null; 2200 2201 fd.originalType = fd.type; // for mangling 2202 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod); 2203 //printf("fd.needThis() = %d\n", fd.needThis()); 2204 2205 return fd; 2206 } 2207 2208 /**************************************************** 2209 * Given a new instance tithis of this TemplateDeclaration, 2210 * see if there already exists an instance. 2211 * If so, return that existing instance. 2212 */ 2213 TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs) 2214 { 2215 //printf("findExistingInstance(%p)\n", tithis); 2216 tithis.fargs = fargs; 2217 auto tibox = TemplateInstanceBox(tithis); 2218 auto p = tibox in instances; 2219 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n"); 2220 return p ? *p : null; 2221 } 2222 2223 /******************************************** 2224 * Add instance ti to TemplateDeclaration's table of instances. 2225 * Return a handle we can use to later remove it if it fails instantiation. 2226 */ 2227 TemplateInstance addInstance(TemplateInstance ti) 2228 { 2229 //printf("addInstance() %p %p\n", instances, ti); 2230 auto tibox = TemplateInstanceBox(ti); 2231 instances[tibox] = ti; 2232 return ti; 2233 } 2234 2235 /******************************************* 2236 * Remove TemplateInstance from table of instances. 2237 * Input: 2238 * handle returned by addInstance() 2239 */ 2240 void removeInstance(TemplateInstance ti) 2241 { 2242 //printf("removeInstance()\n"); 2243 auto tibox = TemplateInstanceBox(ti); 2244 instances.remove(tibox); 2245 } 2246 2247 override inout(TemplateDeclaration) isTemplateDeclaration() inout 2248 { 2249 return this; 2250 } 2251 2252 /** 2253 * Check if the last template parameter is a tuple one, 2254 * and returns it if so, else returns `null`. 2255 * 2256 * Returns: 2257 * The last template parameter if it's a `TemplateTupleParameter` 2258 */ 2259 TemplateTupleParameter isVariadic() 2260 { 2261 size_t dim = parameters.dim; 2262 if (dim == 0) 2263 return null; 2264 return (*parameters)[dim - 1].isTemplateTupleParameter(); 2265 } 2266 2267 /*********************************** 2268 * We can overload templates. 2269 */ 2270 override bool isOverloadable() 2271 { 2272 return true; 2273 } 2274 2275 override void accept(Visitor v) 2276 { 2277 v.visit(this); 2278 } 2279 } 2280 2281 extern (C++) final class TypeDeduced : Type 2282 { 2283 Type tded; 2284 Expressions argexps; // corresponding expressions 2285 Types tparams; // tparams[i].mod 2286 2287 extern (D) this(Type tt, Expression e, Type tparam) 2288 { 2289 super(Tnone); 2290 tded = tt; 2291 argexps.push(e); 2292 tparams.push(tparam); 2293 } 2294 2295 void update(Expression e, Type tparam) 2296 { 2297 argexps.push(e); 2298 tparams.push(tparam); 2299 } 2300 2301 void update(Type tt, Expression e, Type tparam) 2302 { 2303 tded = tt; 2304 argexps.push(e); 2305 tparams.push(tparam); 2306 } 2307 2308 MATCH matchAll(Type tt) 2309 { 2310 MATCH match = MATCHexact; 2311 for (size_t j = 0; j < argexps.dim; j++) 2312 { 2313 Expression e = argexps[j]; 2314 assert(e); 2315 if (e == emptyArrayElement) 2316 continue; 2317 2318 Type t = tt.addMod(tparams[j].mod).substWildTo(MODconst); 2319 2320 MATCH m = e.implicitConvTo(t); 2321 if (match > m) 2322 match = m; 2323 if (match <= MATCHnomatch) 2324 break; 2325 } 2326 return match; 2327 } 2328 } 2329 2330 2331 /************************************************* 2332 * Given function arguments, figure out which template function 2333 * to expand, and return matching result. 2334 * Input: 2335 * m matching result 2336 * dstart the root of overloaded function templates 2337 * loc instantiation location 2338 * sc instantiation scope 2339 * tiargs initial list of template arguments 2340 * tthis if !NULL, the 'this' pointer argument 2341 * fargs arguments to function 2342 */ 2343 void functionResolve(Match* m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, Type tthis, Expressions* fargs) 2344 { 2345 version (none) 2346 { 2347 printf("functionResolve() dstart = %s\n", dstart.toChars()); 2348 printf(" tiargs:\n"); 2349 if (tiargs) 2350 { 2351 for (size_t i = 0; i < tiargs.dim; i++) 2352 { 2353 RootObject arg = (*tiargs)[i]; 2354 printf("\t%s\n", arg.toChars()); 2355 } 2356 } 2357 printf(" fargs:\n"); 2358 for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++) 2359 { 2360 Expression arg = (*fargs)[i]; 2361 printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); 2362 //printf("\tty = %d\n", arg.type.ty); 2363 } 2364 //printf("stc = %llx\n", dstart.scope.stc); 2365 //printf("match:t/f = %d/%d\n", ta_last, m.last); 2366 } 2367 2368 // results 2369 int property = 0; // 0: unintialized 2370 // 1: seen @property 2371 // 2: not @property 2372 size_t ov_index = 0; 2373 TemplateDeclaration td_best; 2374 TemplateInstance ti_best; 2375 MATCH ta_last = m.last != MATCHnomatch ? MATCHexact : MATCHnomatch; 2376 Type tthis_best; 2377 2378 int applyFunction(FuncDeclaration fd) 2379 { 2380 // skip duplicates 2381 if (fd == m.lastf) 2382 return 0; 2383 // explicitly specified tiargs never match to non template function 2384 if (tiargs && tiargs.dim > 0) 2385 return 0; 2386 2387 if (fd.semanticRun == PASSinit && fd._scope) 2388 { 2389 Ungag ungag = fd.ungagSpeculative(); 2390 fd.semantic(fd._scope); 2391 } 2392 if (fd.semanticRun == PASSinit) 2393 { 2394 .error(loc, "forward reference to template %s", fd.toChars()); 2395 return 1; 2396 } 2397 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars()); 2398 m.anyf = fd; 2399 auto tf = cast(TypeFunction)fd.type; 2400 2401 int prop = tf.isproperty ? 1 : 2; 2402 if (property == 0) 2403 property = prop; 2404 else if (property != prop) 2405 error(fd.loc, "cannot overload both property and non-property functions"); 2406 2407 /* For constructors, qualifier check will be opposite direction. 2408 * Qualified constructor always makes qualified object, then will be checked 2409 * that it is implicitly convertible to tthis. 2410 */ 2411 Type tthis_fd = fd.needThis() ? tthis : null; 2412 bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); 2413 if (isCtorCall) 2414 { 2415 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(), 2416 // tf.mod, tthis_fd.mod, fd.isolateReturn()); 2417 if (MODimplicitConv(tf.mod, tthis_fd.mod) || 2418 tf.isWild() && tf.isShared() == tthis_fd.isShared() || 2419 fd.isolateReturn()) 2420 { 2421 /* && tf.isShared() == tthis_fd.isShared()*/ 2422 // Uniquely constructed object can ignore shared qualifier. 2423 // TODO: Is this appropriate? 2424 tthis_fd = null; 2425 } 2426 else 2427 return 0; // MATCHnomatch 2428 } 2429 MATCH mfa = tf.callMatch(tthis_fd, fargs); 2430 //printf("test1: mfa = %d\n", mfa); 2431 if (mfa > MATCHnomatch) 2432 { 2433 if (mfa > m.last) goto LfIsBetter; 2434 if (mfa < m.last) goto LlastIsBetter; 2435 2436 /* See if one of the matches overrides the other. 2437 */ 2438 assert(m.lastf); 2439 if (m.lastf.overrides(fd)) goto LlastIsBetter; 2440 if (fd.overrides(m.lastf)) goto LfIsBetter; 2441 2442 /* Try to disambiguate using template-style partial ordering rules. 2443 * In essence, if f() and g() are ambiguous, if f() can call g(), 2444 * but g() cannot call f(), then pick f(). 2445 * This is because f() is "more specialized." 2446 */ 2447 { 2448 MATCH c1 = fd.leastAsSpecialized(m.lastf); 2449 MATCH c2 = m.lastf.leastAsSpecialized(fd); 2450 //printf("c1 = %d, c2 = %d\n", c1, c2); 2451 if (c1 > c2) goto LfIsBetter; 2452 if (c1 < c2) goto LlastIsBetter; 2453 } 2454 2455 /* If the two functions are the same function, like: 2456 * int foo(int); 2457 * int foo(int x) { ... } 2458 * then pick the one with the body. 2459 */ 2460 if (tf.equals(m.lastf.type) && 2461 fd.storage_class == m.lastf.storage_class && 2462 fd.parent == m.lastf.parent && 2463 fd.protection == m.lastf.protection && 2464 fd.linkage == m.lastf.linkage) 2465 { 2466 if (fd.fbody && !m.lastf.fbody) goto LfIsBetter; 2467 if (!fd.fbody && m.lastf.fbody) goto LlastIsBetter; 2468 } 2469 2470 // Bugzilla 14450: Prefer exact qualified constructor for the creating object type 2471 if (isCtorCall && tf.mod != m.lastf.type.mod) 2472 { 2473 if (tthis.mod == tf.mod) goto LfIsBetter; 2474 if (tthis.mod == m.lastf.type.mod) goto LlastIsBetter; 2475 } 2476 2477 m.nextf = fd; 2478 m.count++; 2479 return 0; 2480 2481 LlastIsBetter: 2482 return 0; 2483 2484 LfIsBetter: 2485 td_best = null; 2486 ti_best = null; 2487 ta_last = MATCHexact; 2488 m.last = mfa; 2489 m.lastf = fd; 2490 tthis_best = tthis_fd; 2491 ov_index = 0; 2492 m.count = 1; 2493 return 0; 2494 } 2495 return 0; 2496 } 2497 2498 int applyTemplate(TemplateDeclaration td) 2499 { 2500 // skip duplicates 2501 if (td == td_best) 2502 return 0; 2503 2504 if (!sc) 2505 sc = td._scope; // workaround for Type.aliasthisOf 2506 2507 if (td.semanticRun == PASSinit && td._scope) 2508 { 2509 // Try to fix forward reference. Ungag errors while doing so. 2510 Ungag ungag = td.ungagSpeculative(); 2511 td.semantic(td._scope); 2512 } 2513 if (td.semanticRun == PASSinit) 2514 { 2515 .error(loc, "forward reference to template %s", td.toChars()); 2516 Lerror: 2517 m.lastf = null; 2518 m.count = 0; 2519 m.last = MATCHnomatch; 2520 return 1; 2521 } 2522 //printf("td = %s\n", td.toChars()); 2523 2524 auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; 2525 if (!f) 2526 { 2527 if (!tiargs) 2528 tiargs = new Objects(); 2529 auto ti = new TemplateInstance(loc, td, tiargs); 2530 Objects dedtypes; 2531 dedtypes.setDim(td.parameters.dim); 2532 assert(td.semanticRun != PASSinit); 2533 MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0); 2534 //printf("matchWithInstance = %d\n", mta); 2535 if (mta <= MATCHnomatch || mta < ta_last) // no match or less match 2536 return 0; 2537 2538 ti.semantic(sc, fargs); 2539 if (!ti.inst) // if template failed to expand 2540 return 0; 2541 2542 Dsymbol s = ti.inst.toAlias(); 2543 FuncDeclaration fd; 2544 if (auto tdx = s.isTemplateDeclaration()) 2545 { 2546 Objects dedtypesX; // empty tiargs 2547 2548 // https://issues.dlang.org/show_bug.cgi?id=11553 2549 // Check for recursive instantiation of tdx. 2550 for (TemplatePrevious* p = tdx.previous; p; p = p.prev) 2551 { 2552 if (arrayObjectMatch(p.dedargs, &dedtypesX)) 2553 { 2554 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); 2555 /* It must be a subscope of p.sc, other scope chains are not recursive 2556 * instantiations. 2557 */ 2558 for (Scope* scx = sc; scx; scx = scx.enclosing) 2559 { 2560 if (scx == p.sc) 2561 { 2562 error(loc, "recursive template expansion while looking for %s.%s", ti.toChars(), tdx.toChars()); 2563 goto Lerror; 2564 } 2565 } 2566 } 2567 /* BUG: should also check for ref param differences 2568 */ 2569 } 2570 2571 TemplatePrevious pr; 2572 pr.prev = tdx.previous; 2573 pr.sc = sc; 2574 pr.dedargs = &dedtypesX; 2575 tdx.previous = ≺ // add this to threaded list 2576 2577 fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, 1); 2578 2579 tdx.previous = pr.prev; // unlink from threaded list 2580 } 2581 else if (s.isFuncDeclaration()) 2582 { 2583 fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, 1); 2584 } 2585 else 2586 goto Lerror; 2587 2588 if (!fd) 2589 return 0; 2590 2591 if (fd.type.ty != Tfunction) 2592 { 2593 m.lastf = fd; // to propagate "error match" 2594 m.count = 1; 2595 m.last = MATCHnomatch; 2596 return 1; 2597 } 2598 2599 Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; 2600 2601 auto tf = cast(TypeFunction)fd.type; 2602 MATCH mfa = tf.callMatch(tthis_fd, fargs); 2603 if (mfa < m.last) 2604 return 0; 2605 2606 if (mta < ta_last) goto Ltd_best2; 2607 if (mta > ta_last) goto Ltd2; 2608 2609 if (mfa < m.last) goto Ltd_best2; 2610 if (mfa > m.last) goto Ltd2; 2611 2612 Lambig2: // td_best and td are ambiguous 2613 //printf("Lambig2\n"); 2614 m.nextf = fd; 2615 m.count++; 2616 return 0; 2617 2618 Ltd_best2: 2619 return 0; 2620 2621 Ltd2: 2622 // td is the new best match 2623 assert(td._scope); 2624 td_best = td; 2625 ti_best = null; 2626 property = 0; // (backward compatibility) 2627 ta_last = mta; 2628 m.last = mfa; 2629 m.lastf = fd; 2630 tthis_best = tthis_fd; 2631 ov_index = 0; 2632 m.nextf = null; 2633 m.count = 1; 2634 return 0; 2635 } 2636 2637 //printf("td = %s\n", td.toChars()); 2638 for (size_t ovi = 0; f; f = f.overnext0, ovi++) 2639 { 2640 if (f.type.ty != Tfunction || f.errors) 2641 goto Lerror; 2642 2643 /* This is a 'dummy' instance to evaluate constraint properly. 2644 */ 2645 auto ti = new TemplateInstance(loc, td, tiargs); 2646 ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. 2647 2648 auto fd = f; 2649 int x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs); 2650 MATCH mta = cast(MATCH)(x >> 4); 2651 MATCH mfa = cast(MATCH)(x & 0xF); 2652 //printf("match:t/f = %d/%d\n", mta, mfa); 2653 if (!fd || mfa == MATCHnomatch) 2654 continue; 2655 2656 Type tthis_fd = fd.needThis() ? tthis : null; 2657 2658 bool isCtorCall = tthis_fd && fd.isCtorDeclaration(); 2659 if (isCtorCall) 2660 { 2661 // Constructor call requires additional check. 2662 2663 auto tf = cast(TypeFunction)fd.type; 2664 assert(tf.next); 2665 if (MODimplicitConv(tf.mod, tthis_fd.mod) || 2666 tf.isWild() && tf.isShared() == tthis_fd.isShared() || 2667 fd.isolateReturn()) 2668 { 2669 tthis_fd = null; 2670 } 2671 else 2672 continue; // MATCHnomatch 2673 } 2674 2675 if (mta < ta_last) goto Ltd_best; 2676 if (mta > ta_last) goto Ltd; 2677 2678 if (mfa < m.last) goto Ltd_best; 2679 if (mfa > m.last) goto Ltd; 2680 2681 if (td_best) 2682 { 2683 // Disambiguate by picking the most specialized TemplateDeclaration 2684 MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs); 2685 MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs); 2686 //printf("1: c1 = %d, c2 = %d\n", c1, c2); 2687 if (c1 > c2) goto Ltd; 2688 if (c1 < c2) goto Ltd_best; 2689 } 2690 assert(fd && m.lastf); 2691 { 2692 // Disambiguate by tf.callMatch 2693 auto tf1 = cast(TypeFunction)fd.type; 2694 assert(tf1.ty == Tfunction); 2695 auto tf2 = cast(TypeFunction)m.lastf.type; 2696 assert(tf2.ty == Tfunction); 2697 MATCH c1 = tf1.callMatch(tthis_fd, fargs); 2698 MATCH c2 = tf2.callMatch(tthis_best, fargs); 2699 //printf("2: c1 = %d, c2 = %d\n", c1, c2); 2700 if (c1 > c2) goto Ltd; 2701 if (c1 < c2) goto Ltd_best; 2702 } 2703 { 2704 // Disambiguate by picking the most specialized FunctionDeclaration 2705 MATCH c1 = fd.leastAsSpecialized(m.lastf); 2706 MATCH c2 = m.lastf.leastAsSpecialized(fd); 2707 //printf("3: c1 = %d, c2 = %d\n", c1, c2); 2708 if (c1 > c2) goto Ltd; 2709 if (c1 < c2) goto Ltd_best; 2710 } 2711 2712 // Bugzilla 14450: Prefer exact qualified constructor for the creating object type 2713 if (isCtorCall && fd.type.mod != m.lastf.type.mod) 2714 { 2715 if (tthis.mod == fd.type.mod) goto Ltd; 2716 if (tthis.mod == m.lastf.type.mod) goto Ltd_best; 2717 } 2718 2719 m.nextf = fd; 2720 m.count++; 2721 continue; 2722 2723 Ltd_best: // td_best is the best match so far 2724 //printf("Ltd_best\n"); 2725 continue; 2726 2727 Ltd: // td is the new best match 2728 //printf("Ltd\n"); 2729 assert(td._scope); 2730 td_best = td; 2731 ti_best = ti; 2732 property = 0; // (backward compatibility) 2733 ta_last = mta; 2734 m.last = mfa; 2735 m.lastf = fd; 2736 tthis_best = tthis_fd; 2737 ov_index = ovi; 2738 m.nextf = null; 2739 m.count = 1; 2740 continue; 2741 } 2742 return 0; 2743 } 2744 2745 auto td = dstart.isTemplateDeclaration(); 2746 if (td && td.funcroot) 2747 dstart = td.funcroot; 2748 overloadApply(dstart, (Dsymbol s) 2749 { 2750 if (s.errors) 2751 return 0; 2752 if (auto fd = s.isFuncDeclaration()) 2753 return applyFunction(fd); 2754 if (auto td = s.isTemplateDeclaration()) 2755 return applyTemplate(td); 2756 return 0; 2757 }); 2758 2759 //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf); 2760 if (td_best && ti_best && m.count == 1) 2761 { 2762 // Matches to template function 2763 assert(td_best.onemember && td_best.onemember.isFuncDeclaration()); 2764 /* The best match is td_best with arguments tdargs. 2765 * Now instantiate the template. 2766 */ 2767 assert(td_best._scope); 2768 if (!sc) 2769 sc = td_best._scope; // workaround for Type.aliasthisOf 2770 2771 auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); 2772 ti.semantic(sc, fargs); 2773 2774 m.lastf = ti.toAlias().isFuncDeclaration(); 2775 if (!m.lastf) 2776 goto Lnomatch; 2777 if (ti.errors) 2778 { 2779 Lerror: 2780 m.count = 1; 2781 assert(m.lastf); 2782 m.last = MATCHnomatch; 2783 return; 2784 } 2785 2786 // look forward instantiated overload function 2787 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic. 2788 // it has filled overnext0d 2789 while (ov_index--) 2790 { 2791 m.lastf = m.lastf.overnext0; 2792 assert(m.lastf); 2793 } 2794 2795 tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null; 2796 2797 auto tf = cast(TypeFunction)m.lastf.type; 2798 if (tf.ty == Terror) 2799 goto Lerror; 2800 assert(tf.ty == Tfunction); 2801 if (!tf.callMatch(tthis_best, fargs)) 2802 goto Lnomatch; 2803 2804 /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, 2805 * a template instance can be matched while instantiating 2806 * that same template. Thus, the function type can be incomplete. Complete it. 2807 * 2808 * https://issues.dlang.org/show_bug.cgi?id=9208 2809 * For auto function, completion should be deferred to the end of 2810 * its semantic3. Should not complete it in here. 2811 */ 2812 if (tf.next && !m.lastf.inferRetType) 2813 { 2814 m.lastf.type = tf.semantic(loc, sc); 2815 } 2816 } 2817 else if (m.lastf) 2818 { 2819 // Matches to non template function, 2820 // or found matches were ambiguous. 2821 assert(m.count >= 1); 2822 } 2823 else 2824 { 2825 Lnomatch: 2826 m.count = 0; 2827 m.lastf = null; 2828 m.last = MATCHnomatch; 2829 } 2830 } 2831 2832 /* ======================== Type ============================================ */ 2833 2834 /**** 2835 * Given an identifier, figure out which TemplateParameter it is. 2836 * Return IDX_NOTFOUND if not found. 2837 */ 2838 private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters) 2839 { 2840 for (size_t i = 0; i < parameters.dim; i++) 2841 { 2842 TemplateParameter tp = (*parameters)[i]; 2843 if (tp.ident.equals(id)) 2844 return i; 2845 } 2846 return IDX_NOTFOUND; 2847 } 2848 2849 private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) 2850 { 2851 if (tparam.ty == Tident) 2852 { 2853 TypeIdentifier tident = cast(TypeIdentifier)tparam; 2854 //printf("\ttident = '%s'\n", tident.toChars()); 2855 return templateIdentifierLookup(tident.ident, parameters); 2856 } 2857 return IDX_NOTFOUND; 2858 } 2859 2860 private ubyte deduceWildHelper(Type t, Type* at, Type tparam) 2861 { 2862 if ((tparam.mod & MODwild) == 0) 2863 return 0; 2864 2865 *at = null; 2866 2867 auto X(T, U)(T U, U T) 2868 { 2869 return (U << 4) | T; 2870 } 2871 2872 switch (X(tparam.mod, t.mod)) 2873 { 2874 case X(MODwild, 0): 2875 case X(MODwild, MODconst): 2876 case X(MODwild, MODshared): 2877 case X(MODwild, MODshared | MODconst): 2878 case X(MODwild, MODimmutable): 2879 case X(MODwildconst, 0): 2880 case X(MODwildconst, MODconst): 2881 case X(MODwildconst, MODshared): 2882 case X(MODwildconst, MODshared | MODconst): 2883 case X(MODwildconst, MODimmutable): 2884 case X(MODshared | MODwild, MODshared): 2885 case X(MODshared | MODwild, MODshared | MODconst): 2886 case X(MODshared | MODwild, MODimmutable): 2887 case X(MODshared | MODwildconst, MODshared): 2888 case X(MODshared | MODwildconst, MODshared | MODconst): 2889 case X(MODshared | MODwildconst, MODimmutable): 2890 { 2891 ubyte wm = (t.mod & ~MODshared); 2892 if (wm == 0) 2893 wm = MODmutable; 2894 ubyte m = (t.mod & (MODconst | MODimmutable)) | (tparam.mod & t.mod & MODshared); 2895 *at = t.unqualify(m); 2896 return wm; 2897 } 2898 case X(MODwild, MODwild): 2899 case X(MODwild, MODwildconst): 2900 case X(MODwild, MODshared | MODwild): 2901 case X(MODwild, MODshared | MODwildconst): 2902 case X(MODwildconst, MODwild): 2903 case X(MODwildconst, MODwildconst): 2904 case X(MODwildconst, MODshared | MODwild): 2905 case X(MODwildconst, MODshared | MODwildconst): 2906 case X(MODshared | MODwild, MODshared | MODwild): 2907 case X(MODshared | MODwild, MODshared | MODwildconst): 2908 case X(MODshared | MODwildconst, MODshared | MODwild): 2909 case X(MODshared | MODwildconst, MODshared | MODwildconst): 2910 { 2911 *at = t.unqualify(tparam.mod & t.mod); 2912 return MODwild; 2913 } 2914 default: 2915 return 0; 2916 } 2917 } 2918 2919 private MATCH deduceTypeHelper(Type t, Type* at, Type tparam) 2920 { 2921 // 9*9 == 81 cases 2922 2923 auto X(T, U)(T U, U T) 2924 { 2925 return (U << 4) | T; 2926 } 2927 2928 switch (X(tparam.mod, t.mod)) 2929 { 2930 case X(0, 0): 2931 case X(0, MODconst): 2932 case X(0, MODwild): 2933 case X(0, MODwildconst): 2934 case X(0, MODshared): 2935 case X(0, MODshared | MODconst): 2936 case X(0, MODshared | MODwild): 2937 case X(0, MODshared | MODwildconst): 2938 case X(0, MODimmutable): 2939 // foo(U) T => T 2940 // foo(U) const(T) => const(T) 2941 // foo(U) inout(T) => inout(T) 2942 // foo(U) inout(const(T)) => inout(const(T)) 2943 // foo(U) shared(T) => shared(T) 2944 // foo(U) shared(const(T)) => shared(const(T)) 2945 // foo(U) shared(inout(T)) => shared(inout(T)) 2946 // foo(U) shared(inout(const(T))) => shared(inout(const(T))) 2947 // foo(U) immutable(T) => immutable(T) 2948 { 2949 *at = t; 2950 return MATCHexact; 2951 } 2952 case X(MODconst, MODconst): 2953 case X(MODwild, MODwild): 2954 case X(MODwildconst, MODwildconst): 2955 case X(MODshared, MODshared): 2956 case X(MODshared | MODconst, MODshared | MODconst): 2957 case X(MODshared | MODwild, MODshared | MODwild): 2958 case X(MODshared | MODwildconst, MODshared | MODwildconst): 2959 case X(MODimmutable, MODimmutable): 2960 // foo(const(U)) const(T) => T 2961 // foo(inout(U)) inout(T) => T 2962 // foo(inout(const(U))) inout(const(T)) => T 2963 // foo(shared(U)) shared(T) => T 2964 // foo(shared(const(U))) shared(const(T)) => T 2965 // foo(shared(inout(U))) shared(inout(T)) => T 2966 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T 2967 // foo(immutable(U)) immutable(T) => T 2968 { 2969 *at = t.mutableOf().unSharedOf(); 2970 return MATCHexact; 2971 } 2972 case X(MODconst, 0): 2973 case X(MODconst, MODwild): 2974 case X(MODconst, MODwildconst): 2975 case X(MODconst, MODshared | MODconst): 2976 case X(MODconst, MODshared | MODwild): 2977 case X(MODconst, MODshared | MODwildconst): 2978 case X(MODconst, MODimmutable): 2979 case X(MODwild, MODshared | MODwild): 2980 case X(MODwildconst, MODshared | MODwildconst): 2981 case X(MODshared | MODconst, MODimmutable): 2982 // foo(const(U)) T => T 2983 // foo(const(U)) inout(T) => T 2984 // foo(const(U)) inout(const(T)) => T 2985 // foo(const(U)) shared(const(T)) => shared(T) 2986 // foo(const(U)) shared(inout(T)) => shared(T) 2987 // foo(const(U)) shared(inout(const(T))) => shared(T) 2988 // foo(const(U)) immutable(T) => T 2989 // foo(inout(U)) shared(inout(T)) => shared(T) 2990 // foo(inout(const(U))) shared(inout(const(T))) => shared(T) 2991 // foo(shared(const(U))) immutable(T) => T 2992 { 2993 *at = t.mutableOf(); 2994 return MATCHconst; 2995 } 2996 case X(MODconst, MODshared): 2997 // foo(const(U)) shared(T) => shared(T) 2998 { 2999 *at = t; 3000 return MATCHconst; 3001 } 3002 case X(MODshared, MODshared | MODconst): 3003 case X(MODshared, MODshared | MODwild): 3004 case X(MODshared, MODshared | MODwildconst): 3005 case X(MODshared | MODconst, MODshared): 3006 // foo(shared(U)) shared(const(T)) => const(T) 3007 // foo(shared(U)) shared(inout(T)) => inout(T) 3008 // foo(shared(U)) shared(inout(const(T))) => inout(const(T)) 3009 // foo(shared(const(U))) shared(T) => T 3010 { 3011 *at = t.unSharedOf(); 3012 return MATCHconst; 3013 } 3014 case X(MODwildconst, MODimmutable): 3015 case X(MODshared | MODconst, MODshared | MODwildconst): 3016 case X(MODshared | MODwildconst, MODimmutable): 3017 case X(MODshared | MODwildconst, MODshared | MODwild): 3018 // foo(inout(const(U))) immutable(T) => T 3019 // foo(shared(const(U))) shared(inout(const(T))) => T 3020 // foo(shared(inout(const(U)))) immutable(T) => T 3021 // foo(shared(inout(const(U)))) shared(inout(T)) => T 3022 { 3023 *at = t.unSharedOf().mutableOf(); 3024 return MATCHconst; 3025 } 3026 case X(MODshared | MODconst, MODshared | MODwild): 3027 // foo(shared(const(U))) shared(inout(T)) => T 3028 { 3029 *at = t.unSharedOf().mutableOf(); 3030 return MATCHconst; 3031 } 3032 case X(MODwild, 0): 3033 case X(MODwild, MODconst): 3034 case X(MODwild, MODwildconst): 3035 case X(MODwild, MODimmutable): 3036 case X(MODwild, MODshared): 3037 case X(MODwild, MODshared | MODconst): 3038 case X(MODwild, MODshared | MODwildconst): 3039 case X(MODwildconst, 0): 3040 case X(MODwildconst, MODconst): 3041 case X(MODwildconst, MODwild): 3042 case X(MODwildconst, MODshared): 3043 case X(MODwildconst, MODshared | MODconst): 3044 case X(MODwildconst, MODshared | MODwild): 3045 case X(MODshared, 0): 3046 case X(MODshared, MODconst): 3047 case X(MODshared, MODwild): 3048 case X(MODshared, MODwildconst): 3049 case X(MODshared, MODimmutable): 3050 case X(MODshared | MODconst, 0): 3051 case X(MODshared | MODconst, MODconst): 3052 case X(MODshared | MODconst, MODwild): 3053 case X(MODshared | MODconst, MODwildconst): 3054 case X(MODshared | MODwild, 0): 3055 case X(MODshared | MODwild, MODconst): 3056 case X(MODshared | MODwild, MODwild): 3057 case X(MODshared | MODwild, MODwildconst): 3058 case X(MODshared | MODwild, MODimmutable): 3059 case X(MODshared | MODwild, MODshared): 3060 case X(MODshared | MODwild, MODshared | MODconst): 3061 case X(MODshared | MODwild, MODshared | MODwildconst): 3062 case X(MODshared | MODwildconst, 0): 3063 case X(MODshared | MODwildconst, MODconst): 3064 case X(MODshared | MODwildconst, MODwild): 3065 case X(MODshared | MODwildconst, MODwildconst): 3066 case X(MODshared | MODwildconst, MODshared): 3067 case X(MODshared | MODwildconst, MODshared | MODconst): 3068 case X(MODimmutable, 0): 3069 case X(MODimmutable, MODconst): 3070 case X(MODimmutable, MODwild): 3071 case X(MODimmutable, MODwildconst): 3072 case X(MODimmutable, MODshared): 3073 case X(MODimmutable, MODshared | MODconst): 3074 case X(MODimmutable, MODshared | MODwild): 3075 case X(MODimmutable, MODshared | MODwildconst): 3076 // foo(inout(U)) T => nomatch 3077 // foo(inout(U)) const(T) => nomatch 3078 // foo(inout(U)) inout(const(T)) => nomatch 3079 // foo(inout(U)) immutable(T) => nomatch 3080 // foo(inout(U)) shared(T) => nomatch 3081 // foo(inout(U)) shared(const(T)) => nomatch 3082 // foo(inout(U)) shared(inout(const(T))) => nomatch 3083 // foo(inout(const(U))) T => nomatch 3084 // foo(inout(const(U))) const(T) => nomatch 3085 // foo(inout(const(U))) inout(T) => nomatch 3086 // foo(inout(const(U))) shared(T) => nomatch 3087 // foo(inout(const(U))) shared(const(T)) => nomatch 3088 // foo(inout(const(U))) shared(inout(T)) => nomatch 3089 // foo(shared(U)) T => nomatch 3090 // foo(shared(U)) const(T) => nomatch 3091 // foo(shared(U)) inout(T) => nomatch 3092 // foo(shared(U)) inout(const(T)) => nomatch 3093 // foo(shared(U)) immutable(T) => nomatch 3094 // foo(shared(const(U))) T => nomatch 3095 // foo(shared(const(U))) const(T) => nomatch 3096 // foo(shared(const(U))) inout(T) => nomatch 3097 // foo(shared(const(U))) inout(const(T)) => nomatch 3098 // foo(shared(inout(U))) T => nomatch 3099 // foo(shared(inout(U))) const(T) => nomatch 3100 // foo(shared(inout(U))) inout(T) => nomatch 3101 // foo(shared(inout(U))) inout(const(T)) => nomatch 3102 // foo(shared(inout(U))) immutable(T) => nomatch 3103 // foo(shared(inout(U))) shared(T) => nomatch 3104 // foo(shared(inout(U))) shared(const(T)) => nomatch 3105 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch 3106 // foo(shared(inout(const(U)))) T => nomatch 3107 // foo(shared(inout(const(U)))) const(T) => nomatch 3108 // foo(shared(inout(const(U)))) inout(T) => nomatch 3109 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch 3110 // foo(shared(inout(const(U)))) shared(T) => nomatch 3111 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch 3112 // foo(immutable(U)) T => nomatch 3113 // foo(immutable(U)) const(T) => nomatch 3114 // foo(immutable(U)) inout(T) => nomatch 3115 // foo(immutable(U)) inout(const(T)) => nomatch 3116 // foo(immutable(U)) shared(T) => nomatch 3117 // foo(immutable(U)) shared(const(T)) => nomatch 3118 // foo(immutable(U)) shared(inout(T)) => nomatch 3119 // foo(immutable(U)) shared(inout(const(T))) => nomatch 3120 return MATCHnomatch; 3121 3122 default: 3123 assert(0); 3124 } 3125 } 3126 3127 __gshared Expression emptyArrayElement = null; 3128 3129 /* These form the heart of template argument deduction. 3130 * Given 'this' being the type argument to the template instance, 3131 * it is matched against the template declaration parameter specialization 3132 * 'tparam' to determine the type to be used for the parameter. 3133 * Example: 3134 * template Foo(T:T*) // template declaration 3135 * Foo!(int*) // template instantiation 3136 * Input: 3137 * this = int* 3138 * tparam = T* 3139 * parameters = [ T:T* ] // Array of TemplateParameter's 3140 * Output: 3141 * dedtypes = [ int ] // Array of Expression/Type's 3142 */ 3143 MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0) 3144 { 3145 extern (C++) final class DeduceType : Visitor 3146 { 3147 alias visit = super.visit; 3148 public: 3149 Scope* sc; 3150 Type tparam; 3151 TemplateParameters* parameters; 3152 Objects* dedtypes; 3153 uint* wm; 3154 size_t inferStart; 3155 MATCH result; 3156 3157 extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart) 3158 { 3159 this.sc = sc; 3160 this.tparam = tparam; 3161 this.parameters = parameters; 3162 this.dedtypes = dedtypes; 3163 this.wm = wm; 3164 this.inferStart = inferStart; 3165 result = MATCHnomatch; 3166 } 3167 3168 override void visit(Type t) 3169 { 3170 version (none) 3171 { 3172 printf("Type.deduceType()\n"); 3173 printf("\tthis = %d, ", t.ty); 3174 t.print(); 3175 printf("\ttparam = %d, ", tparam.ty); 3176 tparam.print(); 3177 } 3178 if (!tparam) 3179 goto Lnomatch; 3180 3181 if (t == tparam) 3182 goto Lexact; 3183 3184 if (tparam.ty == Tident) 3185 { 3186 // Determine which parameter tparam is 3187 size_t i = templateParameterLookup(tparam, parameters); 3188 if (i == IDX_NOTFOUND) 3189 { 3190 if (!sc) 3191 goto Lnomatch; 3192 3193 /* Need a loc to go with the semantic routine. 3194 */ 3195 Loc loc; 3196 if (parameters.dim) 3197 { 3198 TemplateParameter tp = (*parameters)[0]; 3199 loc = tp.loc; 3200 } 3201 3202 /* BUG: what if tparam is a template instance, that 3203 * has as an argument another Tident? 3204 */ 3205 tparam = tparam.semantic(loc, sc); 3206 assert(tparam.ty != Tident); 3207 result = deduceType(t, sc, tparam, parameters, dedtypes, wm); 3208 return; 3209 } 3210 3211 TemplateParameter tp = (*parameters)[i]; 3212 3213 TypeIdentifier tident = cast(TypeIdentifier)tparam; 3214 if (tident.idents.dim > 0) 3215 { 3216 //printf("matching %s to %s\n", tparam.toChars(), t.toChars()); 3217 Dsymbol s = t.toDsymbol(sc); 3218 for (size_t j = tident.idents.dim; j-- > 0;) 3219 { 3220 RootObject id = tident.idents[j]; 3221 if (id.dyncast() == DYNCAST_IDENTIFIER) 3222 { 3223 if (!s || !s.parent) 3224 goto Lnomatch; 3225 Dsymbol s2 = s.parent.search(Loc(), cast(Identifier)id); 3226 if (!s2) 3227 goto Lnomatch; 3228 s2 = s2.toAlias(); 3229 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars()); 3230 if (s != s2) 3231 { 3232 if (Type tx = s2.getType()) 3233 { 3234 if (s != tx.toDsymbol(sc)) 3235 goto Lnomatch; 3236 } 3237 else 3238 goto Lnomatch; 3239 } 3240 s = s.parent; 3241 } 3242 else 3243 goto Lnomatch; 3244 } 3245 //printf("[e] s = %s\n", s?s.toChars():"(null)"); 3246 if (tp.isTemplateTypeParameter()) 3247 { 3248 Type tt = s.getType(); 3249 if (!tt) 3250 goto Lnomatch; 3251 Type at = cast(Type)(*dedtypes)[i]; 3252 if (at && at.ty == Tnone) 3253 at = (cast(TypeDeduced)at).tded; 3254 if (!at || tt.equals(at)) 3255 { 3256 (*dedtypes)[i] = tt; 3257 goto Lexact; 3258 } 3259 } 3260 if (tp.isTemplateAliasParameter()) 3261 { 3262 Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i]; 3263 if (!s2 || s == s2) 3264 { 3265 (*dedtypes)[i] = s; 3266 goto Lexact; 3267 } 3268 } 3269 goto Lnomatch; 3270 } 3271 3272 // Found the corresponding parameter tp 3273 if (!tp.isTemplateTypeParameter()) 3274 goto Lnomatch; 3275 3276 Type at = cast(Type)(*dedtypes)[i]; 3277 Type tt; 3278 if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0) 3279 { 3280 // type vs (none) 3281 if (!at) 3282 { 3283 (*dedtypes)[i] = tt; 3284 *wm |= wx; 3285 result = MATCHconst; 3286 return; 3287 } 3288 3289 // type vs expressions 3290 if (at.ty == Tnone) 3291 { 3292 TypeDeduced xt = cast(TypeDeduced)at; 3293 result = xt.matchAll(tt); 3294 if (result > MATCHnomatch) 3295 { 3296 (*dedtypes)[i] = tt; 3297 if (result > MATCHconst) 3298 result = MATCHconst; // limit level for inout matches 3299 } 3300 return; 3301 } 3302 3303 // type vs type 3304 if (tt.equals(at)) 3305 { 3306 (*dedtypes)[i] = tt; // Prefer current type match 3307 goto Lconst; 3308 } 3309 if (tt.implicitConvTo(at.constOf())) 3310 { 3311 (*dedtypes)[i] = at.constOf().mutableOf(); 3312 *wm |= MODconst; 3313 goto Lconst; 3314 } 3315 if (at.implicitConvTo(tt.constOf())) 3316 { 3317 (*dedtypes)[i] = tt.constOf().mutableOf(); 3318 *wm |= MODconst; 3319 goto Lconst; 3320 } 3321 goto Lnomatch; 3322 } 3323 else if (MATCH m = deduceTypeHelper(t, &tt, tparam)) 3324 { 3325 // type vs (none) 3326 if (!at) 3327 { 3328 (*dedtypes)[i] = tt; 3329 result = m; 3330 return; 3331 } 3332 3333 // type vs expressions 3334 if (at.ty == Tnone) 3335 { 3336 TypeDeduced xt = cast(TypeDeduced)at; 3337 result = xt.matchAll(tt); 3338 if (result > MATCHnomatch) 3339 { 3340 (*dedtypes)[i] = tt; 3341 } 3342 return; 3343 } 3344 3345 // type vs type 3346 if (tt.equals(at)) 3347 { 3348 goto Lexact; 3349 } 3350 if (tt.ty == Tclass && at.ty == Tclass) 3351 { 3352 result = tt.implicitConvTo(at); 3353 return; 3354 } 3355 if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCHconst) 3356 { 3357 goto Lexact; 3358 } 3359 } 3360 goto Lnomatch; 3361 } 3362 3363 if (tparam.ty == Ttypeof) 3364 { 3365 /* Need a loc to go with the semantic routine. 3366 */ 3367 Loc loc; 3368 if (parameters.dim) 3369 { 3370 TemplateParameter tp = (*parameters)[0]; 3371 loc = tp.loc; 3372 } 3373 3374 tparam = tparam.semantic(loc, sc); 3375 } 3376 if (t.ty != tparam.ty) 3377 { 3378 if (Dsymbol sym = t.toDsymbol(sc)) 3379 { 3380 if (sym.isforwardRef() && !tparam.deco) 3381 goto Lnomatch; 3382 } 3383 3384 MATCH m = t.implicitConvTo(tparam); 3385 if (m == MATCHnomatch) 3386 { 3387 if (t.ty == Tclass) 3388 { 3389 TypeClass tc = cast(TypeClass)t; 3390 if (tc.sym.aliasthis && !(tc.att & RECtracingDT)) 3391 { 3392 tc.att = cast(AliasThisRec)(tc.att | RECtracingDT); 3393 m = deduceType(t.aliasthisOf(), sc, tparam, parameters, dedtypes, wm); 3394 tc.att = cast(AliasThisRec)(tc.att & ~RECtracingDT); 3395 } 3396 } 3397 else if (t.ty == Tstruct) 3398 { 3399 TypeStruct ts = cast(TypeStruct)t; 3400 if (ts.sym.aliasthis && !(ts.att & RECtracingDT)) 3401 { 3402 ts.att = cast(AliasThisRec)(ts.att | RECtracingDT); 3403 m = deduceType(t.aliasthisOf(), sc, tparam, parameters, dedtypes, wm); 3404 ts.att = cast(AliasThisRec)(ts.att & ~RECtracingDT); 3405 } 3406 } 3407 } 3408 result = m; 3409 return; 3410 } 3411 3412 if (t.nextOf()) 3413 { 3414 if (tparam.deco && !tparam.hasWild()) 3415 { 3416 result = t.implicitConvTo(tparam); 3417 return; 3418 } 3419 3420 Type tpn = tparam.nextOf(); 3421 if (wm && t.ty == Taarray && tparam.isWild()) 3422 { 3423 // https://issues.dlang.org/show_bug.cgi?id=12403 3424 // In IFTI, stop inout matching on transitive part of AA types. 3425 tpn = tpn.substWildTo(MODmutable); 3426 } 3427 3428 result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm); 3429 return; 3430 } 3431 3432 Lexact: 3433 result = MATCHexact; 3434 return; 3435 3436 Lnomatch: 3437 result = MATCHnomatch; 3438 return; 3439 3440 Lconst: 3441 result = MATCHconst; 3442 } 3443 3444 override void visit(TypeVector t) 3445 { 3446 version (none) 3447 { 3448 printf("TypeVector.deduceType()\n"); 3449 printf("\tthis = %d, ", t.ty); 3450 t.print(); 3451 printf("\ttparam = %d, ", tparam.ty); 3452 tparam.print(); 3453 } 3454 if (tparam.ty == Tvector) 3455 { 3456 TypeVector tp = cast(TypeVector)tparam; 3457 result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm); 3458 return; 3459 } 3460 visit(cast(Type)t); 3461 } 3462 3463 override void visit(TypeDArray t) 3464 { 3465 version (none) 3466 { 3467 printf("TypeDArray.deduceType()\n"); 3468 printf("\tthis = %d, ", t.ty); 3469 t.print(); 3470 printf("\ttparam = %d, ", tparam.ty); 3471 tparam.print(); 3472 } 3473 visit(cast(Type)t); 3474 } 3475 3476 override void visit(TypeSArray t) 3477 { 3478 version (none) 3479 { 3480 printf("TypeSArray.deduceType()\n"); 3481 printf("\tthis = %d, ", t.ty); 3482 t.print(); 3483 printf("\ttparam = %d, ", tparam.ty); 3484 tparam.print(); 3485 } 3486 3487 // Extra check that array dimensions must match 3488 if (tparam) 3489 { 3490 if (tparam.ty == Tarray) 3491 { 3492 MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); 3493 result = (m >= MATCHconst) ? MATCHconvert : MATCHnomatch; 3494 return; 3495 } 3496 3497 TemplateParameter tp = null; 3498 Expression edim = null; 3499 size_t i; 3500 if (tparam.ty == Tsarray) 3501 { 3502 TypeSArray tsa = cast(TypeSArray)tparam; 3503 if (tsa.dim.op == TOKvar && (cast(VarExp)tsa.dim).var.storage_class & STCtemplateparameter) 3504 { 3505 Identifier id = (cast(VarExp)tsa.dim).var.ident; 3506 i = templateIdentifierLookup(id, parameters); 3507 assert(i != IDX_NOTFOUND); 3508 tp = (*parameters)[i]; 3509 } 3510 else 3511 edim = tsa.dim; 3512 } 3513 else if (tparam.ty == Taarray) 3514 { 3515 TypeAArray taa = cast(TypeAArray)tparam; 3516 i = templateParameterLookup(taa.index, parameters); 3517 if (i != IDX_NOTFOUND) 3518 tp = (*parameters)[i]; 3519 else 3520 { 3521 Expression e; 3522 Type tx; 3523 Dsymbol s; 3524 taa.index.resolve(Loc(), sc, &e, &tx, &s); 3525 edim = s ? getValue(s) : getValue(e); 3526 } 3527 } 3528 if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) 3529 { 3530 result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); 3531 return; 3532 } 3533 } 3534 visit(cast(Type)t); 3535 } 3536 3537 override void visit(TypeAArray t) 3538 { 3539 version (none) 3540 { 3541 printf("TypeAArray.deduceType()\n"); 3542 printf("\tthis = %d, ", t.ty); 3543 t.print(); 3544 printf("\ttparam = %d, ", tparam.ty); 3545 tparam.print(); 3546 } 3547 3548 // Extra check that index type must match 3549 if (tparam && tparam.ty == Taarray) 3550 { 3551 TypeAArray tp = cast(TypeAArray)tparam; 3552 if (!deduceType(t.index, sc, tp.index, parameters, dedtypes)) 3553 { 3554 result = MATCHnomatch; 3555 return; 3556 } 3557 } 3558 visit(cast(Type)t); 3559 } 3560 3561 override void visit(TypeFunction t) 3562 { 3563 //printf("TypeFunction.deduceType()\n"); 3564 //printf("\tthis = %d, ", t.ty); t.print(); 3565 //printf("\ttparam = %d, ", tparam.ty); tparam.print(); 3566 3567 // Extra check that function characteristics must match 3568 if (tparam && tparam.ty == Tfunction) 3569 { 3570 TypeFunction tp = cast(TypeFunction)tparam; 3571 if (t.varargs != tp.varargs || t.linkage != tp.linkage) 3572 { 3573 result = MATCHnomatch; 3574 return; 3575 } 3576 3577 size_t nfargs = Parameter.dim(t.parameters); 3578 size_t nfparams = Parameter.dim(tp.parameters); 3579 3580 // https://issues.dlang.org/show_bug.cgi?id=2579 3581 // Apply function parameter storage classes to parameter types 3582 for (size_t i = 0; i < nfparams; i++) 3583 { 3584 Parameter fparam = Parameter.getNth(tp.parameters, i); 3585 fparam.type = fparam.type.addStorageClass(fparam.storageClass); 3586 fparam.storageClass &= ~(STC_TYPECTOR | STCin); 3587 } 3588 //printf("\t. this = %d, ", t.ty); t.print(); 3589 //printf("\t. tparam = %d, ", tparam.ty); tparam.print(); 3590 3591 /* See if tuple match 3592 */ 3593 if (nfparams > 0 && nfargs >= nfparams - 1) 3594 { 3595 /* See if 'A' of the template parameter matches 'A' 3596 * of the type of the last function parameter. 3597 */ 3598 Parameter fparam = Parameter.getNth(tp.parameters, nfparams - 1); 3599 assert(fparam); 3600 assert(fparam.type); 3601 if (fparam.type.ty != Tident) 3602 goto L1; 3603 TypeIdentifier tid = cast(TypeIdentifier)fparam.type; 3604 if (tid.idents.dim) 3605 goto L1; 3606 3607 /* Look through parameters to find tuple matching tid.ident 3608 */ 3609 size_t tupi = 0; 3610 for (; 1; tupi++) 3611 { 3612 if (tupi == parameters.dim) 3613 goto L1; 3614 TemplateParameter tx = (*parameters)[tupi]; 3615 TemplateTupleParameter tup = tx.isTemplateTupleParameter(); 3616 if (tup && tup.ident.equals(tid.ident)) 3617 break; 3618 } 3619 3620 /* The types of the function arguments [nfparams - 1 .. nfargs] 3621 * now form the tuple argument. 3622 */ 3623 size_t tuple_dim = nfargs - (nfparams - 1); 3624 3625 /* See if existing tuple, and whether it matches or not 3626 */ 3627 RootObject o = (*dedtypes)[tupi]; 3628 if (o) 3629 { 3630 // Existing deduced argument must be a tuple, and must match 3631 Tuple tup = isTuple(o); 3632 if (!tup || tup.objects.dim != tuple_dim) 3633 { 3634 result = MATCHnomatch; 3635 return; 3636 } 3637 for (size_t i = 0; i < tuple_dim; i++) 3638 { 3639 Parameter arg = Parameter.getNth(t.parameters, nfparams - 1 + i); 3640 if (!arg.type.equals(tup.objects[i])) 3641 { 3642 result = MATCHnomatch; 3643 return; 3644 } 3645 } 3646 } 3647 else 3648 { 3649 // Create new tuple 3650 auto tup = new Tuple(); 3651 tup.objects.setDim(tuple_dim); 3652 for (size_t i = 0; i < tuple_dim; i++) 3653 { 3654 Parameter arg = Parameter.getNth(t.parameters, nfparams - 1 + i); 3655 tup.objects[i] = arg.type; 3656 } 3657 (*dedtypes)[tupi] = tup; 3658 } 3659 nfparams--; // don't consider the last parameter for type deduction 3660 goto L2; 3661 } 3662 3663 L1: 3664 if (nfargs != nfparams) 3665 { 3666 result = MATCHnomatch; 3667 return; 3668 } 3669 L2: 3670 for (size_t i = 0; i < nfparams; i++) 3671 { 3672 Parameter a = Parameter.getNth(t.parameters, i); 3673 Parameter ap = Parameter.getNth(tp.parameters, i); 3674 if (a.storageClass != ap.storageClass || !deduceType(a.type, sc, ap.type, parameters, dedtypes)) 3675 { 3676 result = MATCHnomatch; 3677 return; 3678 } 3679 } 3680 } 3681 visit(cast(Type)t); 3682 } 3683 3684 override void visit(TypeIdentifier t) 3685 { 3686 // Extra check 3687 if (tparam && tparam.ty == Tident) 3688 { 3689 TypeIdentifier tp = cast(TypeIdentifier)tparam; 3690 for (size_t i = 0; i < t.idents.dim; i++) 3691 { 3692 RootObject id1 = t.idents[i]; 3693 RootObject id2 = tp.idents[i]; 3694 if (!id1.equals(id2)) 3695 { 3696 result = MATCHnomatch; 3697 return; 3698 } 3699 } 3700 } 3701 visit(cast(Type)t); 3702 } 3703 3704 override void visit(TypeInstance t) 3705 { 3706 version (none) 3707 { 3708 printf("TypeInstance.deduceType()\n"); 3709 printf("\tthis = %d, ", t.ty); 3710 t.print(); 3711 printf("\ttparam = %d, ", tparam.ty); 3712 tparam.print(); 3713 } 3714 // Extra check 3715 if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl) 3716 { 3717 TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration(); 3718 assert(tempdecl); 3719 3720 TypeInstance tp = cast(TypeInstance)tparam; 3721 3722 //printf("tempinst.tempdecl = %p\n", tempdecl); 3723 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl); 3724 if (!tp.tempinst.tempdecl) 3725 { 3726 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars()); 3727 3728 /* Handle case of: 3729 * template Foo(T : sa!(T), alias sa) 3730 */ 3731 size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); 3732 if (i == IDX_NOTFOUND) 3733 { 3734 /* Didn't find it as a parameter identifier. Try looking 3735 * it up and seeing if is an alias. 3736 * https://issues.dlang.org/show_bug.cgi?id=1454 3737 */ 3738 auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name); 3739 Type tx; 3740 Expression e; 3741 Dsymbol s; 3742 tid.resolve(tp.loc, sc, &e, &tx, &s); 3743 if (tx) 3744 { 3745 s = tx.toDsymbol(sc); 3746 if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null) 3747 { 3748 // https://issues.dlang.org/show_bug.cgi?id=14290 3749 // Try to match with ti.tempecl, 3750 // only when ti is an enclosing instance. 3751 Dsymbol p = sc.parent; 3752 while (p && p != ti) 3753 p = p.parent; 3754 if (p) 3755 s = ti.tempdecl; 3756 } 3757 } 3758 if (s) 3759 { 3760 s = s.toAlias(); 3761 TemplateDeclaration td = s.isTemplateDeclaration(); 3762 if (td) 3763 { 3764 if (td.overroot) 3765 td = td.overroot; 3766 for (; td; td = td.overnext) 3767 { 3768 if (td == tempdecl) 3769 goto L2; 3770 } 3771 } 3772 } 3773 goto Lnomatch; 3774 } 3775 TemplateParameter tpx = (*parameters)[i]; 3776 if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null)) 3777 goto Lnomatch; 3778 } 3779 else if (tempdecl != tp.tempinst.tempdecl) 3780 goto Lnomatch; 3781 3782 L2: 3783 for (size_t i = 0; 1; i++) 3784 { 3785 //printf("\ttest: tempinst.tiargs[%d]\n", i); 3786 RootObject o1 = null; 3787 if (i < t.tempinst.tiargs.dim) 3788 o1 = (*t.tempinst.tiargs)[i]; 3789 else if (i < t.tempinst.tdtypes.dim && i < tp.tempinst.tiargs.dim) 3790 { 3791 // Pick up default arg 3792 o1 = t.tempinst.tdtypes[i]; 3793 } 3794 else if (i >= tp.tempinst.tiargs.dim) 3795 break; 3796 3797 if (i >= tp.tempinst.tiargs.dim) 3798 { 3799 size_t dim = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0); 3800 while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg())) 3801 { 3802 i++; 3803 } 3804 if (i >= dim) 3805 break; // match if all remained parameters are dependent 3806 goto Lnomatch; 3807 } 3808 3809 RootObject o2 = (*tp.tempinst.tiargs)[i]; 3810 Type t2 = isType(o2); 3811 3812 size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.dim - 1) 3813 ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND; 3814 if (j != IDX_NOTFOUND && j == parameters.dim - 1 && 3815 (*parameters)[j].isTemplateTupleParameter()) 3816 { 3817 /* Given: 3818 * struct A(B...) {} 3819 * alias A!(int, float) X; 3820 * static if (is(X Y == A!(Z), Z...)) {} 3821 * deduce that Z is a tuple(int, float) 3822 */ 3823 3824 /* Create tuple from remaining args 3825 */ 3826 auto vt = new Tuple(); 3827 size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.dim : t.tempinst.tdtypes.dim) - i; 3828 vt.objects.setDim(vtdim); 3829 for (size_t k = 0; k < vtdim; k++) 3830 { 3831 RootObject o; 3832 if (k < t.tempinst.tiargs.dim) 3833 o = (*t.tempinst.tiargs)[i + k]; 3834 else // Pick up default arg 3835 o = t.tempinst.tdtypes[i + k]; 3836 vt.objects[k] = o; 3837 } 3838 3839 Tuple v = cast(Tuple)(*dedtypes)[j]; 3840 if (v) 3841 { 3842 if (!match(v, vt)) 3843 goto Lnomatch; 3844 } 3845 else 3846 (*dedtypes)[j] = vt; 3847 break; 3848 } 3849 else if (!o1) 3850 break; 3851 3852 Type t1 = isType(o1); 3853 Dsymbol s1 = isDsymbol(o1); 3854 Dsymbol s2 = isDsymbol(o2); 3855 Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1)); 3856 Expression e2 = isExpression(o2); 3857 version (none) 3858 { 3859 Tuple v1 = isTuple(o1); 3860 Tuple v2 = isTuple(o2); 3861 if (t1) 3862 printf("t1 = %s\n", t1.toChars()); 3863 if (t2) 3864 printf("t2 = %s\n", t2.toChars()); 3865 if (e1) 3866 printf("e1 = %s\n", e1.toChars()); 3867 if (e2) 3868 printf("e2 = %s\n", e2.toChars()); 3869 if (s1) 3870 printf("s1 = %s\n", s1.toChars()); 3871 if (s2) 3872 printf("s2 = %s\n", s2.toChars()); 3873 if (v1) 3874 printf("v1 = %s\n", v1.toChars()); 3875 if (v2) 3876 printf("v2 = %s\n", v2.toChars()); 3877 } 3878 3879 if (t1 && t2) 3880 { 3881 if (!deduceType(t1, sc, t2, parameters, dedtypes)) 3882 goto Lnomatch; 3883 } 3884 else if (e1 && e2) 3885 { 3886 Le: 3887 e1 = e1.ctfeInterpret(); 3888 3889 /* If it is one of the template parameters for this template, 3890 * we should not attempt to interpret it. It already has a value. 3891 */ 3892 if (e2.op == TOKvar && ((cast(VarExp)e2).var.storage_class & STCtemplateparameter)) 3893 { 3894 /* 3895 * (T:Number!(e2), int e2) 3896 */ 3897 j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters); 3898 if (j != IDX_NOTFOUND) 3899 goto L1; 3900 // The template parameter was not from this template 3901 // (it may be from a parent template, for example) 3902 } 3903 3904 e2 = e2.semantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417 3905 e2 = e2.ctfeInterpret(); 3906 3907 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty); 3908 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty); 3909 if (!e1.equals(e2)) 3910 { 3911 if (!e2.implicitConvTo(e1.type)) 3912 goto Lnomatch; 3913 3914 e2 = e2.implicitCastTo(sc, e1.type); 3915 e2 = e2.ctfeInterpret(); 3916 if (!e1.equals(e2)) 3917 goto Lnomatch; 3918 } 3919 } 3920 else if (e1 && t2 && t2.ty == Tident) 3921 { 3922 j = templateParameterLookup(t2, parameters); 3923 L1: 3924 if (j == IDX_NOTFOUND) 3925 { 3926 t2.resolve((cast(TypeIdentifier)t2).loc, sc, &e2, &t2, &s2); 3927 if (e2) 3928 goto Le; 3929 goto Lnomatch; 3930 } 3931 if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null)) 3932 goto Lnomatch; 3933 } 3934 else if (s1 && s2) 3935 { 3936 Ls: 3937 if (!s1.equals(s2)) 3938 goto Lnomatch; 3939 } 3940 else if (s1 && t2 && t2.ty == Tident) 3941 { 3942 j = templateParameterLookup(t2, parameters); 3943 if (j == IDX_NOTFOUND) 3944 { 3945 t2.resolve((cast(TypeIdentifier)t2).loc, sc, &e2, &t2, &s2); 3946 if (s2) 3947 goto Ls; 3948 goto Lnomatch; 3949 } 3950 if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null)) 3951 goto Lnomatch; 3952 } 3953 else 3954 goto Lnomatch; 3955 } 3956 } 3957 visit(cast(Type)t); 3958 return; 3959 3960 Lnomatch: 3961 //printf("no match\n"); 3962 result = MATCHnomatch; 3963 } 3964 3965 override void visit(TypeStruct t) 3966 { 3967 version (none) 3968 { 3969 printf("TypeStruct.deduceType()\n"); 3970 printf("\tthis.parent = %s, ", t.sym.parent.toChars()); 3971 t.print(); 3972 printf("\ttparam = %d, ", tparam.ty); 3973 tparam.print(); 3974 } 3975 3976 /* If this struct is a template struct, and we're matching 3977 * it against a template instance, convert the struct type 3978 * to a template instance, too, and try again. 3979 */ 3980 TemplateInstance ti = t.sym.parent.isTemplateInstance(); 3981 3982 if (tparam && tparam.ty == Tinstance) 3983 { 3984 if (ti && ti.toAlias() == t.sym) 3985 { 3986 auto tx = new TypeInstance(Loc(), ti); 3987 result = deduceType(tx, sc, tparam, parameters, dedtypes, wm); 3988 return; 3989 } 3990 3991 /* Match things like: 3992 * S!(T).foo 3993 */ 3994 TypeInstance tpi = cast(TypeInstance)tparam; 3995 if (tpi.idents.dim) 3996 { 3997 RootObject id = tpi.idents[tpi.idents.dim - 1]; 3998 if (id.dyncast() == DYNCAST_IDENTIFIER && t.sym.ident.equals(cast(Identifier)id)) 3999 { 4000 Type tparent = t.sym.parent.getType(); 4001 if (tparent) 4002 { 4003 /* Slice off the .foo in S!(T).foo 4004 */ 4005 tpi.idents.dim--; 4006 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm); 4007 tpi.idents.dim++; 4008 return; 4009 } 4010 } 4011 } 4012 } 4013 4014 // Extra check 4015 if (tparam && tparam.ty == Tstruct) 4016 { 4017 TypeStruct tp = cast(TypeStruct)tparam; 4018 4019 //printf("\t%d\n", (MATCH) t.implicitConvTo(tp)); 4020 if (wm && t.deduceWild(tparam, false)) 4021 { 4022 result = MATCHconst; 4023 return; 4024 } 4025 result = t.implicitConvTo(tp); 4026 return; 4027 } 4028 visit(cast(Type)t); 4029 } 4030 4031 override void visit(TypeEnum t) 4032 { 4033 // Extra check 4034 if (tparam && tparam.ty == Tenum) 4035 { 4036 TypeEnum tp = cast(TypeEnum)tparam; 4037 if (t.sym == tp.sym) 4038 visit(cast(Type)t); 4039 else 4040 result = MATCHnomatch; 4041 return; 4042 } 4043 Type tb = t.toBasetype(); 4044 if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray) 4045 { 4046 result = deduceType(tb, sc, tparam, parameters, dedtypes, wm); 4047 return; 4048 } 4049 visit(cast(Type)t); 4050 } 4051 4052 /* Helper for TypeClass.deduceType(). 4053 * Classes can match with implicit conversion to a base class or interface. 4054 * This is complicated, because there may be more than one base class which 4055 * matches. In such cases, one or more parameters remain ambiguous. 4056 * For example, 4057 * 4058 * interface I(X, Y) {} 4059 * class C : I(uint, double), I(char, double) {} 4060 * C x; 4061 * foo(T, U)( I!(T, U) x) 4062 * 4063 * deduces that U is double, but T remains ambiguous (could be char or uint). 4064 * 4065 * Given a baseclass b, and initial deduced types 'dedtypes', this function 4066 * tries to match tparam with b, and also tries all base interfaces of b. 4067 * If a match occurs, numBaseClassMatches is incremented, and the new deduced 4068 * types are ANDed with the current 'best' estimate for dedtypes. 4069 */ 4070 static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches) 4071 { 4072 TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null; 4073 if (parti) 4074 { 4075 // Make a temporary copy of dedtypes so we don't destroy it 4076 auto tmpdedtypes = new Objects(); 4077 tmpdedtypes.setDim(dedtypes.dim); 4078 memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.dim * (void*).sizeof); 4079 4080 auto t = new TypeInstance(Loc(), parti); 4081 MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes); 4082 if (m > MATCHnomatch) 4083 { 4084 // If this is the first ever match, it becomes our best estimate 4085 if (numBaseClassMatches == 0) 4086 memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.dim * (void*).sizeof); 4087 else 4088 for (size_t k = 0; k < tmpdedtypes.dim; ++k) 4089 { 4090 // If we've found more than one possible type for a parameter, 4091 // mark it as unknown. 4092 if ((*tmpdedtypes)[k] != (*best)[k]) 4093 (*best)[k] = (*dedtypes)[k]; 4094 } 4095 ++numBaseClassMatches; 4096 } 4097 } 4098 4099 // Now recursively test the inherited interfaces 4100 foreach (ref bi; b.baseInterfaces) 4101 { 4102 deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); 4103 } 4104 } 4105 4106 override void visit(TypeClass t) 4107 { 4108 //printf("TypeClass.deduceType(this = %s)\n", t.toChars()); 4109 4110 /* If this class is a template class, and we're matching 4111 * it against a template instance, convert the class type 4112 * to a template instance, too, and try again. 4113 */ 4114 TemplateInstance ti = t.sym.parent.isTemplateInstance(); 4115 4116 if (tparam && tparam.ty == Tinstance) 4117 { 4118 if (ti && ti.toAlias() == t.sym) 4119 { 4120 auto tx = new TypeInstance(Loc(), ti); 4121 MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm); 4122 // Even if the match fails, there is still a chance it could match 4123 // a base class. 4124 if (m != MATCHnomatch) 4125 { 4126 result = m; 4127 return; 4128 } 4129 } 4130 4131 /* Match things like: 4132 * S!(T).foo 4133 */ 4134 TypeInstance tpi = cast(TypeInstance)tparam; 4135 if (tpi.idents.dim) 4136 { 4137 RootObject id = tpi.idents[tpi.idents.dim - 1]; 4138 if (id.dyncast() == DYNCAST_IDENTIFIER && t.sym.ident.equals(cast(Identifier)id)) 4139 { 4140 Type tparent = t.sym.parent.getType(); 4141 if (tparent) 4142 { 4143 /* Slice off the .foo in S!(T).foo 4144 */ 4145 tpi.idents.dim--; 4146 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm); 4147 tpi.idents.dim++; 4148 return; 4149 } 4150 } 4151 } 4152 4153 // If it matches exactly or via implicit conversion, we're done 4154 visit(cast(Type)t); 4155 if (result != MATCHnomatch) 4156 return; 4157 4158 /* There is still a chance to match via implicit conversion to 4159 * a base class or interface. Because there could be more than one such 4160 * match, we need to check them all. 4161 */ 4162 4163 int numBaseClassMatches = 0; // Have we found an interface match? 4164 4165 // Our best guess at dedtypes 4166 auto best = new Objects(); 4167 best.setDim(dedtypes.dim); 4168 4169 ClassDeclaration s = t.sym; 4170 while (s && s.baseclasses.dim > 0) 4171 { 4172 // Test the base class 4173 deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches); 4174 4175 // Test the interfaces inherited by the base class 4176 foreach (b; s.interfaces) 4177 { 4178 deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches); 4179 } 4180 s = (*s.baseclasses)[0].sym; 4181 } 4182 4183 if (numBaseClassMatches == 0) 4184 { 4185 result = MATCHnomatch; 4186 return; 4187 } 4188 4189 // If we got at least one match, copy the known types into dedtypes 4190 memcpy(dedtypes.tdata(), best.tdata(), best.dim * (void*).sizeof); 4191 result = MATCHconvert; 4192 return; 4193 } 4194 4195 // Extra check 4196 if (tparam && tparam.ty == Tclass) 4197 { 4198 TypeClass tp = cast(TypeClass)tparam; 4199 4200 //printf("\t%d\n", (MATCH) t.implicitConvTo(tp)); 4201 if (wm && t.deduceWild(tparam, false)) 4202 { 4203 result = MATCHconst; 4204 return; 4205 } 4206 result = t.implicitConvTo(tp); 4207 return; 4208 } 4209 visit(cast(Type)t); 4210 } 4211 4212 override void visit(Expression e) 4213 { 4214 //printf("Expression.deduceType(e = %s)\n", e.toChars()); 4215 size_t i = templateParameterLookup(tparam, parameters); 4216 if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.dim > 0) 4217 { 4218 if (e == emptyArrayElement && tparam.ty == Tarray) 4219 { 4220 Type tn = (cast(TypeNext)tparam).next; 4221 result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm); 4222 return; 4223 } 4224 e.type.accept(this); 4225 return; 4226 } 4227 4228 TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter(); 4229 if (!tp) 4230 return; // nomatch 4231 4232 if (e == emptyArrayElement) 4233 { 4234 if ((*dedtypes)[i]) 4235 { 4236 result = MATCHexact; 4237 return; 4238 } 4239 if (tp.defaultType) 4240 { 4241 tp.defaultType.accept(this); 4242 return; 4243 } 4244 } 4245 4246 Type at = cast(Type)(*dedtypes)[i]; 4247 Type tt; 4248 if (ubyte wx = deduceWildHelper(e.type, &tt, tparam)) 4249 { 4250 *wm |= wx; 4251 result = MATCHconst; 4252 } 4253 else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam)) 4254 { 4255 result = m; 4256 } 4257 else 4258 return; // nomatch 4259 4260 // expression vs (none) 4261 if (!at) 4262 { 4263 (*dedtypes)[i] = new TypeDeduced(tt, e, tparam); 4264 return; 4265 } 4266 4267 TypeDeduced xt = null; 4268 if (at.ty == Tnone) 4269 { 4270 xt = cast(TypeDeduced)at; 4271 at = xt.tded; 4272 } 4273 4274 // From previous matched expressions to current deduced type 4275 MATCH match1 = xt ? xt.matchAll(tt) : MATCHnomatch; 4276 4277 // From current expresssion to previous deduced type 4278 Type pt = at.addMod(tparam.mod); 4279 if (*wm) 4280 pt = pt.substWildTo(*wm); 4281 MATCH match2 = e.implicitConvTo(pt); 4282 4283 if (match1 > MATCHnomatch && match2 > MATCHnomatch) 4284 { 4285 if (at.implicitConvTo(tt) <= MATCHnomatch) 4286 match1 = MATCHnomatch; // Prefer at 4287 else if (tt.implicitConvTo(at) <= MATCHnomatch) 4288 match2 = MATCHnomatch; // Prefer tt 4289 else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod) 4290 { 4291 if (!tt.isMutable() && !at.isMutable()) 4292 tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod)); 4293 else if (tt.isMutable()) 4294 { 4295 if (at.mod == 0) // Prefer unshared 4296 match1 = MATCHnomatch; 4297 else 4298 match2 = MATCHnomatch; 4299 } 4300 else if (at.isMutable()) 4301 { 4302 if (tt.mod == 0) // Prefer unshared 4303 match2 = MATCHnomatch; 4304 else 4305 match1 = MATCHnomatch; 4306 } 4307 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars()); 4308 } 4309 else 4310 { 4311 match1 = MATCHnomatch; 4312 match2 = MATCHnomatch; 4313 } 4314 } 4315 if (match1 > MATCHnomatch) 4316 { 4317 // Prefer current match: tt 4318 if (xt) 4319 xt.update(tt, e, tparam); 4320 else 4321 (*dedtypes)[i] = tt; 4322 result = match1; 4323 return; 4324 } 4325 if (match2 > MATCHnomatch) 4326 { 4327 // Prefer previous match: (*dedtypes)[i] 4328 if (xt) 4329 xt.update(e, tparam); 4330 result = match2; 4331 return; 4332 } 4333 4334 /* Deduce common type 4335 */ 4336 if (Type t = rawTypeMerge(at, tt)) 4337 { 4338 if (xt) 4339 xt.update(t, e, tparam); 4340 else 4341 (*dedtypes)[i] = t; 4342 4343 pt = tt.addMod(tparam.mod); 4344 if (*wm) 4345 pt = pt.substWildTo(*wm); 4346 result = e.implicitConvTo(pt); 4347 return; 4348 } 4349 4350 result = MATCHnomatch; 4351 } 4352 4353 MATCH deduceEmptyArrayElement() 4354 { 4355 if (!emptyArrayElement) 4356 { 4357 emptyArrayElement = new IdentifierExp(Loc(), Id.p); // dummy 4358 emptyArrayElement.type = Type.tvoid; 4359 } 4360 assert(tparam.ty == Tarray); 4361 4362 Type tn = (cast(TypeNext)tparam).next; 4363 return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm); 4364 } 4365 4366 override void visit(NullExp e) 4367 { 4368 if (tparam.ty == Tarray && e.type.ty == Tnull) 4369 { 4370 // tparam:T[] <- e:null (void[]) 4371 result = deduceEmptyArrayElement(); 4372 return; 4373 } 4374 visit(cast(Expression)e); 4375 } 4376 4377 override void visit(StringExp e) 4378 { 4379 Type taai; 4380 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) 4381 { 4382 // Consider compile-time known boundaries 4383 e.type.nextOf().sarrayOf(e.len).accept(this); 4384 return; 4385 } 4386 visit(cast(Expression)e); 4387 } 4388 4389 override void visit(ArrayLiteralExp e) 4390 { 4391 if ((!e.elements || !e.elements.dim) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray) 4392 { 4393 // tparam:T[] <- e:[] (void[]) 4394 result = deduceEmptyArrayElement(); 4395 return; 4396 } 4397 4398 if (tparam.ty == Tarray && e.elements && e.elements.dim) 4399 { 4400 Type tn = (cast(TypeDArray)tparam).next; 4401 result = MATCHexact; 4402 if (e.basis) 4403 { 4404 MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm); 4405 if (m < result) 4406 result = m; 4407 } 4408 for (size_t i = 0; i < e.elements.dim; i++) 4409 { 4410 if (result <= MATCHnomatch) 4411 break; 4412 auto el = (*e.elements)[i]; 4413 if (!el) 4414 continue; 4415 MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm); 4416 if (m < result) 4417 result = m; 4418 } 4419 return; 4420 } 4421 4422 Type taai; 4423 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) 4424 { 4425 // Consider compile-time known boundaries 4426 e.type.nextOf().sarrayOf(e.elements.dim).accept(this); 4427 return; 4428 } 4429 visit(cast(Expression)e); 4430 } 4431 4432 override void visit(AssocArrayLiteralExp e) 4433 { 4434 if (tparam.ty == Taarray && e.keys && e.keys.dim) 4435 { 4436 TypeAArray taa = cast(TypeAArray)tparam; 4437 result = MATCHexact; 4438 for (size_t i = 0; i < e.keys.dim; i++) 4439 { 4440 MATCH m1 = deduceType((*e.keys)[i], sc, taa.index, parameters, dedtypes, wm); 4441 if (m1 < result) 4442 result = m1; 4443 if (result <= MATCHnomatch) 4444 break; 4445 MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm); 4446 if (m2 < result) 4447 result = m2; 4448 if (result <= MATCHnomatch) 4449 break; 4450 } 4451 return; 4452 } 4453 visit(cast(Expression)e); 4454 } 4455 4456 override void visit(FuncExp e) 4457 { 4458 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars()); 4459 if (e.td) 4460 { 4461 Type to = tparam; 4462 if (!to.nextOf() || to.nextOf().ty != Tfunction) 4463 return; 4464 TypeFunction tof = cast(TypeFunction)to.nextOf(); 4465 4466 // Parameter types inference from 'tof' 4467 assert(e.td._scope); 4468 TypeFunction tf = cast(TypeFunction)e.fd.type; 4469 //printf("\ttof = %s\n", tof.toChars()); 4470 //printf("\ttf = %s\n", tf.toChars()); 4471 size_t dim = Parameter.dim(tf.parameters); 4472 4473 if (Parameter.dim(tof.parameters) != dim || tof.varargs != tf.varargs) 4474 return; 4475 4476 auto tiargs = new Objects(); 4477 tiargs.reserve(e.td.parameters.dim); 4478 4479 for (size_t i = 0; i < e.td.parameters.dim; i++) 4480 { 4481 TemplateParameter tp = (*e.td.parameters)[i]; 4482 size_t u = 0; 4483 for (; u < dim; u++) 4484 { 4485 Parameter p = Parameter.getNth(tf.parameters, u); 4486 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) 4487 { 4488 break; 4489 } 4490 } 4491 assert(u < dim); 4492 Parameter pto = Parameter.getNth(tof.parameters, u); 4493 if (!pto) 4494 break; 4495 Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774 4496 if (reliesOnTident(t, parameters, inferStart)) 4497 return; 4498 t = t.semantic(e.loc, sc); 4499 if (t.ty == Terror) 4500 return; 4501 tiargs.push(t); 4502 } 4503 4504 // Set target of return type inference 4505 if (!tf.next && tof.next) 4506 e.fd.treq = tparam; 4507 4508 auto ti = new TemplateInstance(e.loc, e.td, tiargs); 4509 Expression ex = (new ScopeExp(e.loc, ti)).semantic(e.td._scope); 4510 4511 // Reset inference target for the later re-semantic 4512 e.fd.treq = null; 4513 4514 if (ex.op == TOKerror) 4515 return; 4516 if (ex.op != TOKfunction) 4517 return; 4518 visit(ex.type); 4519 return; 4520 } 4521 4522 Type t = e.type; 4523 4524 if (t.ty == Tdelegate && tparam.ty == Tpointer) 4525 return; 4526 4527 // Allow conversion from implicit function pointer to delegate 4528 if (e.tok == TOKreserved && t.ty == Tpointer && tparam.ty == Tdelegate) 4529 { 4530 TypeFunction tf = cast(TypeFunction)t.nextOf(); 4531 t = (new TypeDelegate(tf)).merge(); 4532 } 4533 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars()); 4534 visit(t); 4535 } 4536 4537 override void visit(SliceExp e) 4538 { 4539 Type taai; 4540 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0)) 4541 { 4542 // Consider compile-time known boundaries 4543 if (Type tsa = toStaticArrayType(e)) 4544 { 4545 tsa.accept(this); 4546 return; 4547 } 4548 } 4549 visit(cast(Expression)e); 4550 } 4551 4552 override void visit(CommaExp e) 4553 { 4554 e.e2.accept(this); 4555 } 4556 } 4557 4558 scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart); 4559 if (Type t = isType(o)) 4560 t.accept(v); 4561 else 4562 { 4563 assert(isExpression(o) && wm); 4564 (cast(Expression)o).accept(v); 4565 } 4566 return v.result; 4567 } 4568 4569 /*********************************************************** 4570 * Check whether the type t representation relies on one or more the template parameters. 4571 * Params: 4572 * t = Tested type, if null, returns false. 4573 * tparams = Template parameters. 4574 * iStart = Start index of tparams to limit the tested parameters. If it's 4575 * nonzero, tparams[0..iStart] will be excluded from the test target. 4576 */ 4577 private bool reliesOnTident(Type t, TemplateParameters* tparams = null, size_t iStart = 0) 4578 { 4579 extern (C++) final class ReliesOnTident : Visitor 4580 { 4581 alias visit = super.visit; 4582 public: 4583 TemplateParameters* tparams; 4584 size_t iStart; 4585 bool result; 4586 4587 extern (D) this(TemplateParameters* tparams, size_t iStart) 4588 { 4589 this.tparams = tparams; 4590 this.iStart = iStart; 4591 } 4592 4593 override void visit(Type t) 4594 { 4595 } 4596 4597 override void visit(TypeNext t) 4598 { 4599 t.next.accept(this); 4600 } 4601 4602 override void visit(TypeVector t) 4603 { 4604 t.basetype.accept(this); 4605 } 4606 4607 override void visit(TypeAArray t) 4608 { 4609 visit(cast(TypeNext)t); 4610 if (!result) 4611 t.index.accept(this); 4612 } 4613 4614 override void visit(TypeFunction t) 4615 { 4616 size_t dim = Parameter.dim(t.parameters); 4617 for (size_t i = 0; i < dim; i++) 4618 { 4619 Parameter fparam = Parameter.getNth(t.parameters, i); 4620 fparam.type.accept(this); 4621 if (result) 4622 return; 4623 } 4624 if (t.next) 4625 t.next.accept(this); 4626 } 4627 4628 override void visit(TypeIdentifier t) 4629 { 4630 for (size_t i = iStart; i < tparams.dim; i++) 4631 { 4632 TemplateParameter tp = (*tparams)[i]; 4633 if (tp.ident.equals(t.ident)) 4634 { 4635 result = true; 4636 return; 4637 } 4638 } 4639 } 4640 4641 override void visit(TypeInstance t) 4642 { 4643 for (size_t i = iStart; i < tparams.dim; i++) 4644 { 4645 TemplateParameter tp = (*tparams)[i]; 4646 if (t.tempinst.name == tp.ident) 4647 { 4648 result = true; 4649 return; 4650 } 4651 } 4652 if (!t.tempinst.tiargs) 4653 return; 4654 for (size_t i = 0; i < t.tempinst.tiargs.dim; i++) 4655 { 4656 Type ta = isType((*t.tempinst.tiargs)[i]); 4657 if (ta) 4658 { 4659 ta.accept(this); 4660 if (result) 4661 return; 4662 } 4663 } 4664 } 4665 4666 override void visit(TypeTypeof t) 4667 { 4668 //printf("TypeTypeof.reliesOnTident('%s')\n", t.toChars()); 4669 t.exp.accept(this); 4670 } 4671 4672 override void visit(TypeTuple t) 4673 { 4674 if (t.arguments) 4675 { 4676 for (size_t i = 0; i < t.arguments.dim; i++) 4677 { 4678 Parameter arg = (*t.arguments)[i]; 4679 arg.type.accept(this); 4680 if (result) 4681 return; 4682 } 4683 } 4684 } 4685 4686 override void visit(Expression e) 4687 { 4688 //printf("Expression.reliesOnTident('%s')\n", e.toChars()); 4689 } 4690 4691 override void visit(IdentifierExp e) 4692 { 4693 //printf("IdentifierExp.reliesOnTident('%s')\n", e.toChars()); 4694 for (size_t i = iStart; i < tparams.dim; i++) 4695 { 4696 auto tp = (*tparams)[i]; 4697 if (e.ident == tp.ident) 4698 { 4699 result = true; 4700 return; 4701 } 4702 } 4703 } 4704 4705 override void visit(TupleExp e) 4706 { 4707 //printf("TupleExp.reliesOnTident('%s')\n", e.toChars()); 4708 if (e.exps) 4709 { 4710 foreach (ea; *e.exps) 4711 { 4712 ea.accept(this); 4713 if (result) 4714 return; 4715 } 4716 } 4717 } 4718 4719 override void visit(ArrayLiteralExp e) 4720 { 4721 //printf("ArrayLiteralExp.reliesOnTident('%s')\n", e.toChars()); 4722 if (e.elements) 4723 { 4724 foreach (el; *e.elements) 4725 { 4726 el.accept(this); 4727 if (result) 4728 return; 4729 } 4730 } 4731 } 4732 4733 override void visit(AssocArrayLiteralExp e) 4734 { 4735 //printf("AssocArrayLiteralExp.reliesOnTident('%s')\n", e.toChars()); 4736 foreach (ek; *e.keys) 4737 { 4738 ek.accept(this); 4739 if (result) 4740 return; 4741 } 4742 foreach (ev; *e.values) 4743 { 4744 ev.accept(this); 4745 if (result) 4746 return; 4747 } 4748 } 4749 4750 override void visit(StructLiteralExp e) 4751 { 4752 //printf("StructLiteralExp.reliesOnTident('%s')\n", e.toChars()); 4753 if (e.elements) 4754 { 4755 foreach (ea; *e.elements) 4756 { 4757 ea.accept(this); 4758 if (result) 4759 return; 4760 } 4761 } 4762 } 4763 4764 override void visit(TypeExp e) 4765 { 4766 //printf("TypeExp.reliesOnTident('%s')\n", e.toChars()); 4767 e.type.accept(this); 4768 } 4769 4770 override void visit(NewExp e) 4771 { 4772 //printf("NewExp.reliesOnTident('%s')\n", e.toChars()); 4773 if (e.thisexp) 4774 e.thisexp.accept(this); 4775 if (!result && e.newargs) 4776 { 4777 foreach (ea; *e.newargs) 4778 { 4779 ea.accept(this); 4780 if (result) 4781 return; 4782 } 4783 } 4784 e.newtype.accept(this); 4785 if (!result && e.arguments) 4786 { 4787 foreach (ea; *e.arguments) 4788 { 4789 ea.accept(this); 4790 if (result) 4791 return; 4792 } 4793 } 4794 } 4795 4796 override void visit(NewAnonClassExp e) 4797 { 4798 //printf("NewAnonClassExp.reliesOnTident('%s')\n", e.toChars()); 4799 result = true; 4800 } 4801 4802 override void visit(FuncExp e) 4803 { 4804 //printf("FuncExp.reliesOnTident('%s')\n", e.toChars()); 4805 result = true; 4806 } 4807 4808 override void visit(TypeidExp e) 4809 { 4810 //printf("TypeidExp.reliesOnTident('%s')\n", e.toChars()); 4811 if (auto ea = isExpression(e.obj)) 4812 ea.accept(this); 4813 else if (auto ta = isType(e.obj)) 4814 ta.accept(this); 4815 } 4816 4817 override void visit(TraitsExp e) 4818 { 4819 //printf("TraitsExp.reliesOnTident('%s')\n", e.toChars()); 4820 if (e.args) 4821 { 4822 foreach (oa; *e.args) 4823 { 4824 if (auto ea = isExpression(oa)) 4825 ea.accept(this); 4826 else if (auto ta = isType(oa)) 4827 ta.accept(this); 4828 if (result) 4829 return; 4830 } 4831 } 4832 } 4833 4834 override void visit(IsExp e) 4835 { 4836 //printf("IsExp.reliesOnTident('%s')\n", e.toChars()); 4837 e.targ.accept(this); 4838 } 4839 4840 override void visit(UnaExp e) 4841 { 4842 //printf("UnaExp.reliesOnTident('%s')\n", e.toChars()); 4843 e.e1.accept(this); 4844 } 4845 4846 override void visit(DotTemplateInstanceExp e) 4847 { 4848 //printf("DotTemplateInstanceExp.reliesOnTident('%s')\n", e.toChars()); 4849 visit(cast(UnaExp)e); 4850 if (!result && e.ti.tiargs) 4851 { 4852 foreach (oa; *e.ti.tiargs) 4853 { 4854 if (auto ea = isExpression(oa)) 4855 ea.accept(this); 4856 else if (auto ta = isType(oa)) 4857 ta.accept(this); 4858 if (result) 4859 return; 4860 } 4861 } 4862 } 4863 4864 override void visit(CallExp e) 4865 { 4866 //printf("CallExp.reliesOnTident('%s')\n", e.toChars()); 4867 visit(cast(UnaExp)e); 4868 if (!result && e.arguments) 4869 { 4870 foreach (ea; *e.arguments) 4871 { 4872 ea.accept(this); 4873 if (result) 4874 return; 4875 } 4876 } 4877 } 4878 4879 override void visit(CastExp e) 4880 { 4881 //printf("CallExp.reliesOnTident('%s')\n", e.toChars()); 4882 visit(cast(UnaExp)e); 4883 if (!result) 4884 e.to.accept(this); 4885 } 4886 4887 override void visit(SliceExp e) 4888 { 4889 //printf("SliceExp.reliesOnTident('%s')\n", e.toChars()); 4890 visit(cast(UnaExp)e); 4891 if (!result && e.lwr) 4892 e.lwr.accept(this); 4893 if (!result && e.upr) 4894 e.upr.accept(this); 4895 } 4896 4897 override void visit(IntervalExp e) 4898 { 4899 //printf("IntervalExp.reliesOnTident('%s')\n", e.toChars()); 4900 e.lwr.accept(this); 4901 if (!result) 4902 e.upr.accept(this); 4903 } 4904 4905 override void visit(ArrayExp e) 4906 { 4907 //printf("ArrayExp.reliesOnTident('%s')\n", e.toChars()); 4908 visit(cast(UnaExp)e); 4909 if (!result && e.arguments) 4910 { 4911 foreach (ea; *e.arguments) 4912 ea.accept(this); 4913 } 4914 } 4915 4916 override void visit(BinExp e) 4917 { 4918 //printf("BinExp.reliesOnTident('%s')\n", e.toChars()); 4919 e.e1.accept(this); 4920 if (!result) 4921 e.e2.accept(this); 4922 } 4923 4924 override void visit(CondExp e) 4925 { 4926 //printf("BinExp.reliesOnTident('%s')\n", e.toChars()); 4927 e.econd.accept(this); 4928 if (!result) 4929 visit(cast(BinExp)e); 4930 } 4931 } 4932 4933 if (!t) 4934 return false; 4935 4936 assert(tparams); 4937 scope ReliesOnTident v = new ReliesOnTident(tparams, iStart); 4938 t.accept(v); 4939 return v.result; 4940 } 4941 4942 /*********************************************************** 4943 */ 4944 extern (C++) class TemplateParameter 4945 { 4946 Loc loc; 4947 Identifier ident; 4948 4949 /* True if this is a part of precedent parameter specialization pattern. 4950 * 4951 * template A(T : X!TL, alias X, TL...) {} 4952 * // X and TL are dependent template parameter 4953 * 4954 * A dependent template parameter should return MATCHexact in matchArg() 4955 * to respect the match level of the corresponding precedent parameter. 4956 */ 4957 bool dependent; 4958 4959 /* ======================== TemplateParameter =============================== */ 4960 final extern (D) this(Loc loc, Identifier ident) 4961 { 4962 this.loc = loc; 4963 this.ident = ident; 4964 } 4965 4966 TemplateTypeParameter isTemplateTypeParameter() 4967 { 4968 return null; 4969 } 4970 4971 TemplateValueParameter isTemplateValueParameter() 4972 { 4973 return null; 4974 } 4975 4976 TemplateAliasParameter isTemplateAliasParameter() 4977 { 4978 return null; 4979 } 4980 4981 TemplateThisParameter isTemplateThisParameter() 4982 { 4983 return null; 4984 } 4985 4986 TemplateTupleParameter isTemplateTupleParameter() 4987 { 4988 return null; 4989 } 4990 4991 abstract TemplateParameter syntaxCopy(); 4992 4993 abstract bool declareParameter(Scope* sc); 4994 4995 abstract bool semantic(Scope* sc, TemplateParameters* parameters); 4996 4997 abstract void print(RootObject oarg, RootObject oded); 4998 4999 abstract RootObject specialization(); 5000 5001 abstract RootObject defaultArg(Loc instLoc, Scope* sc); 5002 5003 abstract bool hasDefaultArg(); 5004 5005 /******************************************* 5006 * Match to a particular TemplateParameter. 5007 * Input: 5008 * instLoc location that the template is instantiated. 5009 * tiargs[] actual arguments to template instance 5010 * i i'th argument 5011 * parameters[] template parameters 5012 * dedtypes[] deduced arguments to template instance 5013 * *psparam set to symbol declared and initialized to dedtypes[i] 5014 */ 5015 MATCH matchArg(Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) 5016 { 5017 RootObject oarg; 5018 5019 if (i < tiargs.dim) 5020 oarg = (*tiargs)[i]; 5021 else 5022 { 5023 // Get default argument instead 5024 oarg = defaultArg(instLoc, sc); 5025 if (!oarg) 5026 { 5027 assert(i < dedtypes.dim); 5028 // It might have already been deduced 5029 oarg = (*dedtypes)[i]; 5030 if (!oarg) 5031 goto Lnomatch; 5032 } 5033 } 5034 return matchArg(sc, oarg, i, parameters, dedtypes, psparam); 5035 5036 Lnomatch: 5037 if (psparam) 5038 *psparam = null; 5039 return MATCHnomatch; 5040 } 5041 5042 abstract MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam); 5043 5044 /* Create dummy argument based on parameter. 5045 */ 5046 abstract void* dummyArg(); 5047 5048 void accept(Visitor v) 5049 { 5050 v.visit(this); 5051 } 5052 } 5053 5054 /*********************************************************** 5055 * Syntax: 5056 * ident : specType = defaultType 5057 */ 5058 extern (C++) class TemplateTypeParameter : TemplateParameter 5059 { 5060 Type specType; // if !=null, this is the type specialization 5061 Type defaultType; 5062 5063 extern (C++) static __gshared Type tdummy = null; 5064 5065 final extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) 5066 { 5067 super(loc, ident); 5068 this.ident = ident; 5069 this.specType = specType; 5070 this.defaultType = defaultType; 5071 } 5072 5073 override final TemplateTypeParameter isTemplateTypeParameter() 5074 { 5075 return this; 5076 } 5077 5078 override TemplateParameter syntaxCopy() 5079 { 5080 return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null); 5081 } 5082 5083 override final bool declareParameter(Scope* sc) 5084 { 5085 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars()); 5086 auto ti = new TypeIdentifier(loc, ident); 5087 Declaration ad = new AliasDeclaration(loc, ident, ti); 5088 return sc.insert(ad) !is null; 5089 } 5090 5091 override final bool semantic(Scope* sc, TemplateParameters* parameters) 5092 { 5093 //printf("TemplateTypeParameter.semantic('%s')\n", ident.toChars()); 5094 if (specType && !reliesOnTident(specType, parameters)) 5095 { 5096 specType = specType.semantic(loc, sc); 5097 } 5098 version (none) 5099 { 5100 // Don't do semantic() until instantiation 5101 if (defaultType) 5102 { 5103 defaultType = defaultType.semantic(loc, sc); 5104 } 5105 } 5106 return !(specType && isError(specType)); 5107 } 5108 5109 override final void print(RootObject oarg, RootObject oded) 5110 { 5111 printf(" %s\n", ident.toChars()); 5112 5113 Type t = isType(oarg); 5114 Type ta = isType(oded); 5115 assert(ta); 5116 5117 if (specType) 5118 printf("\tSpecialization: %s\n", specType.toChars()); 5119 if (defaultType) 5120 printf("\tDefault: %s\n", defaultType.toChars()); 5121 printf("\tParameter: %s\n", t ? t.toChars() : "NULL"); 5122 printf("\tDeduced Type: %s\n", ta.toChars()); 5123 } 5124 5125 override final RootObject specialization() 5126 { 5127 return specType; 5128 } 5129 5130 override final RootObject defaultArg(Loc instLoc, Scope* sc) 5131 { 5132 Type t = defaultType; 5133 if (t) 5134 { 5135 t = t.syntaxCopy(); 5136 t = t.semantic(loc, sc); // use the parameter loc 5137 } 5138 return t; 5139 } 5140 5141 override final bool hasDefaultArg() 5142 { 5143 return defaultType !is null; 5144 } 5145 5146 override final MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) 5147 { 5148 //printf("TemplateTypeParameter.matchArg('%s')\n", ident.toChars()); 5149 MATCH m = MATCHexact; 5150 Type ta = isType(oarg); 5151 if (!ta) 5152 { 5153 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); 5154 goto Lnomatch; 5155 } 5156 //printf("ta is %s\n", ta.toChars()); 5157 5158 if (specType) 5159 { 5160 if (!ta || ta == tdummy) 5161 goto Lnomatch; 5162 5163 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), specType.toChars()); 5164 MATCH m2 = deduceType(ta, sc, specType, parameters, dedtypes); 5165 if (m2 <= MATCHnomatch) 5166 { 5167 //printf("\tfailed deduceType\n"); 5168 goto Lnomatch; 5169 } 5170 5171 if (m2 < m) 5172 m = m2; 5173 if ((*dedtypes)[i]) 5174 { 5175 Type t = cast(Type)(*dedtypes)[i]; 5176 5177 if (dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357 5178 goto Lnomatch; 5179 5180 /* This is a self-dependent parameter. For example: 5181 * template X(T : T*) {} 5182 * template X(T : S!T, alias S) {} 5183 */ 5184 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars()); 5185 ta = t; 5186 } 5187 } 5188 else 5189 { 5190 if ((*dedtypes)[i]) 5191 { 5192 // Must match already deduced type 5193 Type t = cast(Type)(*dedtypes)[i]; 5194 5195 if (!t.equals(ta)) 5196 { 5197 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars()); 5198 goto Lnomatch; 5199 } 5200 } 5201 else 5202 { 5203 // So that matches with specializations are better 5204 m = MATCHconvert; 5205 } 5206 } 5207 (*dedtypes)[i] = ta; 5208 5209 if (psparam) 5210 *psparam = new AliasDeclaration(loc, ident, ta); 5211 //printf("\tm = %d\n", m); 5212 return dependent ? MATCHexact : m; 5213 5214 Lnomatch: 5215 if (psparam) 5216 *psparam = null; 5217 //printf("\tm = %d\n", MATCHnomatch); 5218 return MATCHnomatch; 5219 } 5220 5221 override final void* dummyArg() 5222 { 5223 Type t = specType; 5224 if (!t) 5225 { 5226 // Use this for alias-parameter's too (?) 5227 if (!tdummy) 5228 tdummy = new TypeIdentifier(loc, ident); 5229 t = tdummy; 5230 } 5231 return cast(void*)t; 5232 } 5233 5234 override void accept(Visitor v) 5235 { 5236 v.visit(this); 5237 } 5238 } 5239 5240 /*********************************************************** 5241 * Syntax: 5242 * this ident : specType = defaultType 5243 */ 5244 extern (C++) final class TemplateThisParameter : TemplateTypeParameter 5245 { 5246 extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) 5247 { 5248 super(loc, ident, specType, defaultType); 5249 } 5250 5251 override TemplateThisParameter isTemplateThisParameter() 5252 { 5253 return this; 5254 } 5255 5256 override TemplateParameter syntaxCopy() 5257 { 5258 return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null); 5259 } 5260 5261 override void accept(Visitor v) 5262 { 5263 v.visit(this); 5264 } 5265 } 5266 5267 /*********************************************************** 5268 * Syntax: 5269 * valType ident : specValue = defaultValue 5270 */ 5271 extern (C++) final class TemplateValueParameter : TemplateParameter 5272 { 5273 Type valType; 5274 Expression specValue; 5275 Expression defaultValue; 5276 5277 extern (C++) static __gshared AA* edummies = null; 5278 5279 extern (D) this(Loc loc, Identifier ident, Type valType, 5280 Expression specValue, Expression defaultValue) 5281 { 5282 super(loc, ident); 5283 this.ident = ident; 5284 this.valType = valType; 5285 this.specValue = specValue; 5286 this.defaultValue = defaultValue; 5287 } 5288 5289 override TemplateValueParameter isTemplateValueParameter() 5290 { 5291 return this; 5292 } 5293 5294 override TemplateParameter syntaxCopy() 5295 { 5296 return new TemplateValueParameter(loc, ident, 5297 valType.syntaxCopy(), 5298 specValue ? specValue.syntaxCopy() : null, 5299 defaultValue ? defaultValue.syntaxCopy() : null); 5300 } 5301 5302 override bool declareParameter(Scope* sc) 5303 { 5304 auto v = new VarDeclaration(loc, valType, ident, null); 5305 v.storage_class = STCtemplateparameter; 5306 return sc.insert(v) !is null; 5307 } 5308 5309 override bool semantic(Scope* sc, TemplateParameters* parameters) 5310 { 5311 valType = valType.semantic(loc, sc); 5312 version (none) 5313 { 5314 // defer semantic analysis to arg match 5315 if (specValue) 5316 { 5317 Expression e = specValue; 5318 sc = sc.startCTFE(); 5319 e = e.semantic(sc); 5320 sc = sc.endCTFE(); 5321 e = e.implicitCastTo(sc, valType); 5322 e = e.ctfeInterpret(); 5323 if (e.op == TOKint64 || e.op == TOKfloat64 || 5324 e.op == TOKcomplex80 || e.op == TOKnull || e.op == TOKstring) 5325 specValue = e; 5326 } 5327 5328 if (defaultValue) 5329 { 5330 Expression e = defaultValue; 5331 sc = sc.startCTFE(); 5332 e = e.semantic(sc); 5333 sc = sc.endCTFE(); 5334 e = e.implicitCastTo(sc, valType); 5335 e = e.ctfeInterpret(); 5336 if (e.op == TOKint64) 5337 defaultValue = e; 5338 } 5339 } 5340 return !isError(valType); 5341 } 5342 5343 override void print(RootObject oarg, RootObject oded) 5344 { 5345 printf(" %s\n", ident.toChars()); 5346 Expression ea = isExpression(oded); 5347 if (specValue) 5348 printf("\tSpecialization: %s\n", specValue.toChars()); 5349 printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL"); 5350 } 5351 5352 override RootObject specialization() 5353 { 5354 return specValue; 5355 } 5356 5357 override RootObject defaultArg(Loc instLoc, Scope* sc) 5358 { 5359 Expression e = defaultValue; 5360 if (e) 5361 { 5362 e = e.syntaxCopy(); 5363 e = e.semantic(sc); 5364 e = resolveProperties(sc, e); 5365 e = e.resolveLoc(instLoc, sc); // use the instantiated loc 5366 e = e.optimize(WANTvalue); 5367 } 5368 return e; 5369 } 5370 5371 override bool hasDefaultArg() 5372 { 5373 return defaultValue !is null; 5374 } 5375 5376 override MATCH matchArg(Scope* sc, RootObject oarg, 5377 size_t i, TemplateParameters* parameters, Objects* dedtypes, 5378 Declaration* psparam) 5379 { 5380 //printf("TemplateValueParameter.matchArg('%s')\n", ident.toChars()); 5381 5382 MATCH m = MATCHexact; 5383 5384 Expression ei = isExpression(oarg); 5385 Type vt; 5386 5387 if (!ei && oarg) 5388 { 5389 Dsymbol si = isDsymbol(oarg); 5390 FuncDeclaration f = si ? si.isFuncDeclaration() : null; 5391 if (!f || !f.fbody || f.needThis()) 5392 goto Lnomatch; 5393 5394 ei = new VarExp(loc, f); 5395 ei = ei.semantic(sc); 5396 5397 /* If a function is really property-like, and then 5398 * it's CTFEable, ei will be a literal expression. 5399 */ 5400 uint olderrors = global.startGagging(); 5401 ei = resolveProperties(sc, ei); 5402 ei = ei.ctfeInterpret(); 5403 if (global.endGagging(olderrors) || ei.op == TOKerror) 5404 goto Lnomatch; 5405 5406 /* https://issues.dlang.org/show_bug.cgi?id=14520 5407 * A property-like function can match to both 5408 * TemplateAlias and ValueParameter. But for template overloads, 5409 * it should always prefer alias parameter to be consistent 5410 * template match result. 5411 * 5412 * template X(alias f) { enum X = 1; } 5413 * template X(int val) { enum X = 2; } 5414 * int f1() { return 0; } // CTFEable 5415 * int f2(); // body-less function is not CTFEable 5416 * enum x1 = X!f1; // should be 1 5417 * enum x2 = X!f2; // should be 1 5418 * 5419 * e.g. The x1 value must be same even if the f1 definition will be moved 5420 * into di while stripping body code. 5421 */ 5422 m = MATCHconvert; 5423 } 5424 5425 if (ei && ei.op == TOKvar) 5426 { 5427 // Resolve const variables that we had skipped earlier 5428 ei = ei.ctfeInterpret(); 5429 } 5430 5431 //printf("\tvalType: %s, ty = %d\n", valType.toChars(), valType.ty); 5432 vt = valType.semantic(loc, sc); 5433 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars()); 5434 //printf("vt = %s\n", vt.toChars()); 5435 5436 if (ei.type) 5437 { 5438 MATCH m2 = ei.implicitConvTo(vt); 5439 //printf("m: %d\n", m); 5440 if (m2 < m) 5441 m = m2; 5442 if (m <= MATCHnomatch) 5443 goto Lnomatch; 5444 ei = ei.implicitCastTo(sc, vt); 5445 ei = ei.ctfeInterpret(); 5446 } 5447 5448 if (specValue) 5449 { 5450 if (!ei || cast(Expression)dmd_aaGetRvalue(edummies, cast(void*)ei.type) == ei) 5451 goto Lnomatch; 5452 5453 Expression e = specValue; 5454 5455 sc = sc.startCTFE(); 5456 e = e.semantic(sc); 5457 e = resolveProperties(sc, e); 5458 sc = sc.endCTFE(); 5459 e = e.implicitCastTo(sc, vt); 5460 e = e.ctfeInterpret(); 5461 5462 ei = ei.syntaxCopy(); 5463 sc = sc.startCTFE(); 5464 ei = ei.semantic(sc); 5465 sc = sc.endCTFE(); 5466 ei = ei.implicitCastTo(sc, vt); 5467 ei = ei.ctfeInterpret(); 5468 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars()); 5469 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars()); 5470 if (!ei.equals(e)) 5471 goto Lnomatch; 5472 } 5473 else 5474 { 5475 if ((*dedtypes)[i]) 5476 { 5477 // Must match already deduced value 5478 Expression e = cast(Expression)(*dedtypes)[i]; 5479 if (!ei || !ei.equals(e)) 5480 goto Lnomatch; 5481 } 5482 } 5483 (*dedtypes)[i] = ei; 5484 5485 if (psparam) 5486 { 5487 Initializer _init = new ExpInitializer(loc, ei); 5488 Declaration sparam = new VarDeclaration(loc, vt, ident, _init); 5489 sparam.storage_class = STCmanifest; 5490 *psparam = sparam; 5491 } 5492 return dependent ? MATCHexact : m; 5493 5494 Lnomatch: 5495 //printf("\tno match\n"); 5496 if (psparam) 5497 *psparam = null; 5498 return MATCHnomatch; 5499 } 5500 5501 override void* dummyArg() 5502 { 5503 Expression e = specValue; 5504 if (!e) 5505 { 5506 // Create a dummy value 5507 Expression* pe = cast(Expression*)dmd_aaGet(&edummies, cast(void*)valType); 5508 if (!*pe) 5509 *pe = valType.defaultInit(); 5510 e = *pe; 5511 } 5512 return cast(void*)e; 5513 } 5514 5515 override void accept(Visitor v) 5516 { 5517 v.visit(this); 5518 } 5519 } 5520 5521 private RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplateParameters* parameters) 5522 { 5523 if (o) 5524 { 5525 Expression ea = isExpression(o); 5526 Type ta = isType(o); 5527 if (ta && (!parameters || !reliesOnTident(ta, parameters))) 5528 { 5529 Dsymbol s = ta.toDsymbol(sc); 5530 if (s) 5531 o = s; 5532 else 5533 o = ta.semantic(loc, sc); 5534 } 5535 else if (ea) 5536 { 5537 sc = sc.startCTFE(); 5538 ea = ea.semantic(sc); 5539 sc = sc.endCTFE(); 5540 o = ea.ctfeInterpret(); 5541 } 5542 } 5543 return o; 5544 } 5545 5546 /*********************************************************** 5547 * Syntax: 5548 * specType ident : specAlias = defaultAlias 5549 */ 5550 extern (C++) final class TemplateAliasParameter : TemplateParameter 5551 { 5552 Type specType; 5553 RootObject specAlias; 5554 RootObject defaultAlias; 5555 5556 extern (C++) static __gshared Dsymbol sdummy = null; 5557 5558 extern (D) this(Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) 5559 { 5560 super(loc, ident); 5561 this.ident = ident; 5562 this.specType = specType; 5563 this.specAlias = specAlias; 5564 this.defaultAlias = defaultAlias; 5565 } 5566 5567 override TemplateAliasParameter isTemplateAliasParameter() 5568 { 5569 return this; 5570 } 5571 5572 override TemplateParameter syntaxCopy() 5573 { 5574 return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias)); 5575 } 5576 5577 override bool declareParameter(Scope* sc) 5578 { 5579 auto ti = new TypeIdentifier(loc, ident); 5580 Declaration ad = new AliasDeclaration(loc, ident, ti); 5581 return sc.insert(ad) !is null; 5582 } 5583 5584 override bool semantic(Scope* sc, TemplateParameters* parameters) 5585 { 5586 if (specType && !reliesOnTident(specType, parameters)) 5587 { 5588 specType = specType.semantic(loc, sc); 5589 } 5590 specAlias = aliasParameterSemantic(loc, sc, specAlias, parameters); 5591 version (none) 5592 { 5593 // Don't do semantic() until instantiation 5594 if (defaultAlias) 5595 defaultAlias = defaultAlias.semantic(loc, sc); 5596 } 5597 return !(specType && isError(specType)) && !(specAlias && isError(specAlias)); 5598 } 5599 5600 override void print(RootObject oarg, RootObject oded) 5601 { 5602 printf(" %s\n", ident.toChars()); 5603 Dsymbol sa = isDsymbol(oded); 5604 assert(sa); 5605 printf("\tParameter alias: %s\n", sa.toChars()); 5606 } 5607 5608 override RootObject specialization() 5609 { 5610 return specAlias; 5611 } 5612 5613 override RootObject defaultArg(Loc instLoc, Scope* sc) 5614 { 5615 RootObject da = defaultAlias; 5616 Type ta = isType(defaultAlias); 5617 if (ta) 5618 { 5619 if (ta.ty == Tinstance) 5620 { 5621 // If the default arg is a template, instantiate for each type 5622 da = ta.syntaxCopy(); 5623 } 5624 } 5625 5626 RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc 5627 return o; 5628 } 5629 5630 override bool hasDefaultArg() 5631 { 5632 return defaultAlias !is null; 5633 } 5634 5635 override MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) 5636 { 5637 //printf("TemplateAliasParameter.matchArg('%s')\n", ident.toChars()); 5638 MATCH m = MATCHexact; 5639 Type ta = isType(oarg); 5640 RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg); 5641 Expression ea = isExpression(oarg); 5642 if (ea && (ea.op == TOKthis || ea.op == TOKsuper)) 5643 sa = (cast(ThisExp)ea).var; 5644 else if (ea && ea.op == TOKscope) 5645 sa = (cast(ScopeExp)ea).sds; 5646 if (sa) 5647 { 5648 if ((cast(Dsymbol)sa).isAggregateDeclaration()) 5649 m = MATCHconvert; 5650 5651 /* specType means the alias must be a declaration with a type 5652 * that matches specType. 5653 */ 5654 if (specType) 5655 { 5656 Declaration d = (cast(Dsymbol)sa).isDeclaration(); 5657 if (!d) 5658 goto Lnomatch; 5659 if (!d.type.equals(specType)) 5660 goto Lnomatch; 5661 } 5662 } 5663 else 5664 { 5665 sa = oarg; 5666 if (ea) 5667 { 5668 if (specType) 5669 { 5670 if (!ea.type.equals(specType)) 5671 goto Lnomatch; 5672 } 5673 } 5674 else if (ta && ta.ty == Tinstance && !specAlias) 5675 { 5676 /* Specialized parameter should be preferred 5677 * match to the template type parameter. 5678 * template X(alias a) {} // a == this 5679 * template X(alias a : B!A, alias B, A...) {} // B!A => ta 5680 */ 5681 } 5682 else if (sa && sa == TemplateTypeParameter.tdummy) 5683 { 5684 /* https://issues.dlang.org/show_bug.cgi?id=2025 5685 * Aggregate Types should preferentially 5686 * match to the template type parameter. 5687 * template X(alias a) {} // a == this 5688 * template X(T) {} // T => sa 5689 */ 5690 } 5691 else 5692 goto Lnomatch; 5693 } 5694 5695 if (specAlias) 5696 { 5697 if (sa == sdummy) 5698 goto Lnomatch; 5699 Dsymbol sx = isDsymbol(sa); 5700 if (sa != specAlias && sx) 5701 { 5702 Type talias = isType(specAlias); 5703 if (!talias) 5704 goto Lnomatch; 5705 5706 TemplateInstance ti = sx.isTemplateInstance(); 5707 if (!ti && sx.parent) 5708 { 5709 ti = sx.parent.isTemplateInstance(); 5710 if (ti && ti.name != sx.ident) 5711 goto Lnomatch; 5712 } 5713 if (!ti) 5714 goto Lnomatch; 5715 5716 Type t = new TypeInstance(Loc(), ti); 5717 MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes); 5718 if (m2 <= MATCHnomatch) 5719 goto Lnomatch; 5720 } 5721 } 5722 else if ((*dedtypes)[i]) 5723 { 5724 // Must match already deduced symbol 5725 RootObject si = (*dedtypes)[i]; 5726 if (!sa || si != sa) 5727 goto Lnomatch; 5728 } 5729 (*dedtypes)[i] = sa; 5730 5731 if (psparam) 5732 { 5733 if (Dsymbol s = isDsymbol(sa)) 5734 { 5735 *psparam = new AliasDeclaration(loc, ident, s); 5736 } 5737 else if (Type t = isType(sa)) 5738 { 5739 *psparam = new AliasDeclaration(loc, ident, t); 5740 } 5741 else 5742 { 5743 assert(ea); 5744 5745 // Declare manifest constant 5746 Initializer _init = new ExpInitializer(loc, ea); 5747 auto v = new VarDeclaration(loc, null, ident, _init); 5748 v.storage_class = STCmanifest; 5749 v.semantic(sc); 5750 *psparam = v; 5751 } 5752 } 5753 return dependent ? MATCHexact : m; 5754 5755 Lnomatch: 5756 if (psparam) 5757 *psparam = null; 5758 //printf("\tm = %d\n", MATCHnomatch); 5759 return MATCHnomatch; 5760 } 5761 5762 override void* dummyArg() 5763 { 5764 RootObject s = specAlias; 5765 if (!s) 5766 { 5767 if (!sdummy) 5768 sdummy = new Dsymbol(); 5769 s = sdummy; 5770 } 5771 return cast(void*)s; 5772 } 5773 5774 override void accept(Visitor v) 5775 { 5776 v.visit(this); 5777 } 5778 } 5779 5780 /*********************************************************** 5781 * Syntax: 5782 * ident ... 5783 */ 5784 extern (C++) final class TemplateTupleParameter : TemplateParameter 5785 { 5786 extern (D) this(Loc loc, Identifier ident) 5787 { 5788 super(loc, ident); 5789 this.ident = ident; 5790 } 5791 5792 override TemplateTupleParameter isTemplateTupleParameter() 5793 { 5794 return this; 5795 } 5796 5797 override TemplateParameter syntaxCopy() 5798 { 5799 return new TemplateTupleParameter(loc, ident); 5800 } 5801 5802 override bool declareParameter(Scope* sc) 5803 { 5804 auto ti = new TypeIdentifier(loc, ident); 5805 Declaration ad = new AliasDeclaration(loc, ident, ti); 5806 return sc.insert(ad) !is null; 5807 } 5808 5809 override bool semantic(Scope* sc, TemplateParameters* parameters) 5810 { 5811 return true; 5812 } 5813 5814 override void print(RootObject oarg, RootObject oded) 5815 { 5816 printf(" %s... [", ident.toChars()); 5817 Tuple v = isTuple(oded); 5818 assert(v); 5819 5820 //printf("|%d| ", v.objects.dim); 5821 for (size_t i = 0; i < v.objects.dim; i++) 5822 { 5823 if (i) 5824 printf(", "); 5825 5826 RootObject o = v.objects[i]; 5827 Dsymbol sa = isDsymbol(o); 5828 if (sa) 5829 printf("alias: %s", sa.toChars()); 5830 Type ta = isType(o); 5831 if (ta) 5832 printf("type: %s", ta.toChars()); 5833 Expression ea = isExpression(o); 5834 if (ea) 5835 printf("exp: %s", ea.toChars()); 5836 5837 assert(!isTuple(o)); // no nested Tuple arguments 5838 } 5839 printf("]\n"); 5840 } 5841 5842 override RootObject specialization() 5843 { 5844 return null; 5845 } 5846 5847 override RootObject defaultArg(Loc instLoc, Scope* sc) 5848 { 5849 return null; 5850 } 5851 5852 override bool hasDefaultArg() 5853 { 5854 return false; 5855 } 5856 5857 override MATCH matchArg(Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) 5858 { 5859 /* The rest of the actual arguments (tiargs[]) form the match 5860 * for the variadic parameter. 5861 */ 5862 assert(i + 1 == dedtypes.dim); // must be the last one 5863 Tuple ovar; 5864 5865 if (Tuple u = isTuple((*dedtypes)[i])) 5866 { 5867 // It has already been deduced 5868 ovar = u; 5869 } 5870 else if (i + 1 == tiargs.dim && isTuple((*tiargs)[i])) 5871 ovar = isTuple((*tiargs)[i]); 5872 else 5873 { 5874 ovar = new Tuple(); 5875 //printf("ovar = %p\n", ovar); 5876 if (i < tiargs.dim) 5877 { 5878 //printf("i = %d, tiargs.dim = %d\n", i, tiargs.dim); 5879 ovar.objects.setDim(tiargs.dim - i); 5880 for (size_t j = 0; j < ovar.objects.dim; j++) 5881 ovar.objects[j] = (*tiargs)[i + j]; 5882 } 5883 } 5884 return matchArg(sc, ovar, i, parameters, dedtypes, psparam); 5885 } 5886 5887 override MATCH matchArg(Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam) 5888 { 5889 //printf("TemplateTupleParameter.matchArg('%s')\n", ident.toChars()); 5890 Tuple ovar = isTuple(oarg); 5891 if (!ovar) 5892 return MATCHnomatch; 5893 if ((*dedtypes)[i]) 5894 { 5895 Tuple tup = isTuple((*dedtypes)[i]); 5896 if (!tup) 5897 return MATCHnomatch; 5898 if (!match(tup, ovar)) 5899 return MATCHnomatch; 5900 } 5901 (*dedtypes)[i] = ovar; 5902 5903 if (psparam) 5904 *psparam = new TupleDeclaration(loc, ident, &ovar.objects); 5905 return dependent ? MATCHexact : MATCHconvert; 5906 } 5907 5908 override void* dummyArg() 5909 { 5910 return null; 5911 } 5912 5913 override void accept(Visitor v) 5914 { 5915 v.visit(this); 5916 } 5917 } 5918 5919 /*********************************************************** 5920 * Given: 5921 * foo!(args) => 5922 * name = foo 5923 * tiargs = args 5924 */ 5925 extern (C++) class TemplateInstance : ScopeDsymbol 5926 { 5927 Identifier name; 5928 5929 // Array of Types/Expressions of template 5930 // instance arguments [int*, char, 10*10] 5931 Objects* tiargs; 5932 5933 // Array of Types/Expressions corresponding 5934 // to TemplateDeclaration.parameters 5935 // [int, char, 100] 5936 Objects tdtypes; 5937 5938 Dsymbol tempdecl; // referenced by foo.bar.abc 5939 Dsymbol enclosing; // if referencing local symbols, this is the context 5940 Dsymbol aliasdecl; // !=null if instance is an alias for its sole member 5941 TemplateInstance inst; // refer to existing instance 5942 ScopeDsymbol argsym; // argument symbol table 5943 int inuse; // for recursive expansion detection 5944 int nest; // for recursive pretty printing detection 5945 bool semantictiargsdone; // has semanticTiargs() been done? 5946 bool havetempdecl; // if used second constructor 5947 bool gagged; // if the instantiation is done with error gagging 5948 hash_t hash; // cached result of toHash() 5949 Expressions* fargs; // for function template, these are the function arguments 5950 5951 TemplateInstances* deferred; 5952 5953 Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[] 5954 5955 // Used to determine the instance needs code generation. 5956 // Note that these are inaccurate until semantic analysis phase completed. 5957 TemplateInstance tinst; // enclosing template instance 5958 TemplateInstance tnext; // non-first instantiated instances 5959 Module minst; // the top module that instantiated this instance 5960 5961 final extern (D) this(Loc loc, Identifier ident, Objects* tiargs) 5962 { 5963 super(null); 5964 static if (LOG) 5965 { 5966 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null"); 5967 } 5968 this.loc = loc; 5969 this.name = ident; 5970 this.tiargs = tiargs; 5971 } 5972 5973 /***************** 5974 * This constructor is only called when we figured out which function 5975 * template to instantiate. 5976 */ 5977 final extern (D) this(Loc loc, TemplateDeclaration td, Objects* tiargs) 5978 { 5979 super(null); 5980 static if (LOG) 5981 { 5982 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars()); 5983 } 5984 this.loc = loc; 5985 this.name = td.ident; 5986 this.tiargs = tiargs; 5987 this.tempdecl = td; 5988 this.semantictiargsdone = true; 5989 this.havetempdecl = true; 5990 assert(tempdecl._scope); 5991 } 5992 5993 static Objects* arraySyntaxCopy(Objects* objs) 5994 { 5995 Objects* a = null; 5996 if (objs) 5997 { 5998 a = new Objects(); 5999 a.setDim(objs.dim); 6000 for (size_t i = 0; i < objs.dim; i++) 6001 (*a)[i] = objectSyntaxCopy((*objs)[i]); 6002 } 6003 return a; 6004 } 6005 6006 override Dsymbol syntaxCopy(Dsymbol s) 6007 { 6008 TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null); 6009 ti.tiargs = arraySyntaxCopy(tiargs); 6010 TemplateDeclaration td; 6011 if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null) 6012 td.ScopeDsymbol.syntaxCopy(ti); 6013 else 6014 ScopeDsymbol.syntaxCopy(ti); 6015 return ti; 6016 } 6017 6018 void semantic(Scope* sc, Expressions* fargs) 6019 { 6020 //printf("[%s] TemplateInstance.semantic('%s', this=%p, gag = %d, sc = %p)\n", loc.toChars(), toChars(), this, global.gag, sc); 6021 version (none) 6022 { 6023 for (Dsymbol s = this; s; s = s.parent) 6024 { 6025 printf("\t%s\n", s.toChars()); 6026 } 6027 printf("Scope\n"); 6028 for (Scope* scx = sc; scx; scx = scx.enclosing) 6029 { 6030 printf("\t%s parent %s\n", scx._module ? scx._module.toChars() : "null", scx.parent ? scx.parent.toChars() : "null"); 6031 } 6032 } 6033 6034 static if (LOG) 6035 { 6036 printf("\n+TemplateInstance.semantic('%s', this=%p)\n", toChars(), this); 6037 } 6038 if (inst) // if semantic() was already run 6039 { 6040 static if (LOG) 6041 { 6042 printf("-TemplateInstance.semantic('%s', this=%p) already run\n", inst.toChars(), inst); 6043 } 6044 return; 6045 } 6046 if (semanticRun != PASSinit) 6047 { 6048 static if (LOG) 6049 { 6050 printf("Recursive template expansion\n"); 6051 } 6052 auto ungag = Ungag(global.gag); 6053 if (!gagged) 6054 global.gag = 0; 6055 error(loc, "recursive template expansion"); 6056 if (gagged) 6057 semanticRun = PASSinit; 6058 else 6059 inst = this; 6060 errors = true; 6061 return; 6062 } 6063 6064 // Get the enclosing template instance from the scope tinst 6065 tinst = sc.tinst; 6066 6067 // Get the instantiating module from the scope minst 6068 minst = sc.minst; 6069 // https://issues.dlang.org/show_bug.cgi?id=10920 6070 // If the enclosing function is non-root symbol, 6071 // this instance should be speculative. 6072 if (!tinst && sc.func && sc.func.inNonRoot()) 6073 { 6074 minst = null; 6075 } 6076 6077 gagged = (global.gag > 0); 6078 6079 semanticRun = PASSsemantic; 6080 6081 static if (LOG) 6082 { 6083 printf("\tdo semantic\n"); 6084 } 6085 /* Find template declaration first, 6086 * then run semantic on each argument (place results in tiargs[]), 6087 * last find most specialized template from overload list/set. 6088 */ 6089 if (!findTempDecl(sc, null) || !semanticTiargs(sc) || !findBestMatch(sc, fargs)) 6090 { 6091 Lerror: 6092 if (gagged) 6093 { 6094 // https://issues.dlang.org/show_bug.cgi?id=13220 6095 // Roll back status for later semantic re-running 6096 semanticRun = PASSinit; 6097 } 6098 else 6099 inst = this; 6100 errors = true; 6101 return; 6102 } 6103 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); 6104 assert(tempdecl); 6105 6106 // If tempdecl is a mixin, disallow it 6107 if (tempdecl.ismixin) 6108 { 6109 error("mixin templates are not regular templates"); 6110 goto Lerror; 6111 } 6112 6113 hasNestedArgs(tiargs, tempdecl.isstatic); 6114 if (errors) 6115 goto Lerror; 6116 6117 /* See if there is an existing TemplateInstantiation that already 6118 * implements the typeargs. If so, just refer to that one instead. 6119 */ 6120 inst = tempdecl.findExistingInstance(this, fargs); 6121 TemplateInstance errinst = null; 6122 if (!inst) 6123 { 6124 // So, we need to implement 'this' instance. 6125 } 6126 else if (inst.gagged && !gagged && inst.errors) 6127 { 6128 // If the first instantiation had failed, re-run semantic, 6129 // so that error messages are shown. 6130 errinst = inst; 6131 } 6132 else 6133 { 6134 // It's a match 6135 parent = inst.parent; 6136 errors = inst.errors; 6137 6138 // If both this and the previous instantiation were gagged, 6139 // use the number of errors that happened last time. 6140 global.errors += errors; 6141 global.gaggedErrors += errors; 6142 6143 // If the first instantiation was gagged, but this is not: 6144 if (inst.gagged) 6145 { 6146 // It had succeeded, mark it is a non-gagged instantiation, 6147 // and reuse it. 6148 inst.gagged = gagged; 6149 } 6150 6151 this.tnext = inst.tnext; 6152 inst.tnext = this; 6153 6154 /* A module can have explicit template instance and its alias 6155 * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`). 6156 * If the first instantiation 'inst' had happened in non-root module, 6157 * compiler can assume that its instantiated code would be included 6158 * in the separately compiled obj/lib file (e.g. phobos.lib). 6159 * 6160 * However, if 'this' second instantiation happened in root module, 6161 * compiler might need to invoke its codegen 6162 * (https://issues.dlang.org/show_bug.cgi?id=2500 & https://issues.dlang.org/show_bug.cgi?id=2644). 6163 * But whole import graph is not determined until all semantic pass finished, 6164 * so 'inst' should conservatively finish the semantic3 pass for the codegen. 6165 */ 6166 if (minst && minst.isRoot() && !(inst.minst && inst.minst.isRoot())) 6167 { 6168 /* Swap the position of 'inst' and 'this' in the instantiation graph. 6169 * Then, the primary instance `inst` will be changed to a root instance. 6170 * 6171 * Before: 6172 * non-root -> A!() -> B!()[inst] -> C!() 6173 * | 6174 * root -> D!() -> B!()[this] 6175 * 6176 * After: 6177 * non-root -> A!() -> B!()[this] 6178 * | 6179 * root -> D!() -> B!()[inst] -> C!() 6180 */ 6181 Module mi = minst; 6182 TemplateInstance ti = tinst; 6183 minst = inst.minst; 6184 tinst = inst.tinst; 6185 inst.minst = mi; 6186 inst.tinst = ti; 6187 6188 if (minst) // if inst was not speculative 6189 { 6190 /* Add 'inst' once again to the root module members[], then the 6191 * instance members will get codegen chances. 6192 */ 6193 inst.appendToModuleMember(); 6194 } 6195 } 6196 static if (LOG) 6197 { 6198 printf("\tit's a match with instance %p, %d\n", inst, inst.semanticRun); 6199 } 6200 return; 6201 } 6202 static if (LOG) 6203 { 6204 printf("\timplement template instance %s '%s'\n", tempdecl.parent.toChars(), toChars()); 6205 printf("\ttempdecl %s\n", tempdecl.toChars()); 6206 } 6207 uint errorsave = global.errors; 6208 6209 inst = this; 6210 parent = enclosing ? enclosing : tempdecl.parent; 6211 //printf("parent = '%s'\n", parent.kind()); 6212 6213 TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(this); 6214 6215 //getIdent(); 6216 6217 // Store the place we added it to in target_symbol_list(_idx) so we can 6218 // remove it later if we encounter an error. 6219 Dsymbols* target_symbol_list = appendToModuleMember(); 6220 size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list.dim - 1 : 0; 6221 6222 // Copy the syntax trees from the TemplateDeclaration 6223 members = Dsymbol.arraySyntaxCopy(tempdecl.members); 6224 6225 // resolve TemplateThisParameter 6226 for (size_t i = 0; i < tempdecl.parameters.dim; i++) 6227 { 6228 if ((*tempdecl.parameters)[i].isTemplateThisParameter() is null) 6229 continue; 6230 Type t = isType((*tiargs)[i]); 6231 assert(t); 6232 if (StorageClass stc = ModToStc(t.mod)) 6233 { 6234 //printf("t = %s, stc = x%llx\n", t.toChars(), stc); 6235 auto s = new Dsymbols(); 6236 s.push(new StorageClassDeclaration(stc, members)); 6237 members = s; 6238 } 6239 break; 6240 } 6241 6242 // Create our own scope for the template parameters 6243 Scope* _scope = tempdecl._scope; 6244 if (tempdecl.semanticRun == PASSinit) 6245 { 6246 error("template instantiation %s forward references template declaration %s", toChars(), tempdecl.toChars()); 6247 return; 6248 } 6249 6250 static if (LOG) 6251 { 6252 printf("\tcreate scope for template parameters '%s'\n", toChars()); 6253 } 6254 argsym = new ScopeDsymbol(); 6255 argsym.parent = _scope.parent; 6256 _scope = _scope.push(argsym); 6257 _scope.tinst = this; 6258 _scope.minst = minst; 6259 //scope.stc = 0; 6260 6261 // Declare each template parameter as an alias for the argument type 6262 Scope* paramscope = _scope.push(); 6263 paramscope.stc = 0; 6264 paramscope.protection = Prot(PROTpublic); // https://issues.dlang.org/show_bug.cgi?id=14169 6265 // template parameters should be public 6266 declareParameters(paramscope); 6267 paramscope.pop(); 6268 6269 // Add members of template instance to template instance symbol table 6270 //parent = scope.scopesym; 6271 symtab = new DsymbolTable(); 6272 for (size_t i = 0; i < members.dim; i++) 6273 { 6274 Dsymbol s = (*members)[i]; 6275 static if (LOG) 6276 { 6277 printf("\t[%d] adding member '%s' %p kind %s to '%s'\n", i, s.toChars(), s, s.kind(), this.toChars()); 6278 } 6279 s.addMember(_scope, this); 6280 } 6281 static if (LOG) 6282 { 6283 printf("adding members done\n"); 6284 } 6285 6286 /* See if there is only one member of template instance, and that 6287 * member has the same name as the template instance. 6288 * If so, this template instance becomes an alias for that member. 6289 */ 6290 //printf("members.dim = %d\n", members.dim); 6291 if (members.dim) 6292 { 6293 Dsymbol s; 6294 if (Dsymbol.oneMembers(members, &s, tempdecl.ident) && s) 6295 { 6296 //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); 6297 //printf("setting aliasdecl\n"); 6298 aliasdecl = s; 6299 } 6300 } 6301 6302 /* If function template declaration 6303 */ 6304 if (fargs && aliasdecl) 6305 { 6306 FuncDeclaration fd = aliasdecl.isFuncDeclaration(); 6307 if (fd) 6308 { 6309 /* Transmit fargs to type so that TypeFunction.semantic() can 6310 * resolve any "auto ref" storage classes. 6311 */ 6312 TypeFunction tf = cast(TypeFunction)fd.type; 6313 if (tf && tf.ty == Tfunction) 6314 tf.fargs = fargs; 6315 } 6316 } 6317 6318 // Do semantic() analysis on template instance members 6319 static if (LOG) 6320 { 6321 printf("\tdo semantic() on template instance members '%s'\n", toChars()); 6322 } 6323 Scope* sc2; 6324 sc2 = _scope.push(this); 6325 //printf("enclosing = %d, sc.parent = %s\n", enclosing, sc.parent.toChars()); 6326 sc2.parent = this; 6327 sc2.tinst = this; 6328 sc2.minst = minst; 6329 6330 tryExpandMembers(sc2); 6331 6332 semanticRun = PASSsemanticdone; 6333 6334 /* ConditionalDeclaration may introduce eponymous declaration, 6335 * so we should find it once again after semantic. 6336 */ 6337 if (members.dim) 6338 { 6339 Dsymbol s; 6340 if (Dsymbol.oneMembers(members, &s, tempdecl.ident) && s) 6341 { 6342 if (!aliasdecl || aliasdecl != s) 6343 { 6344 //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); 6345 //printf("setting aliasdecl 2\n"); 6346 aliasdecl = s; 6347 } 6348 } 6349 } 6350 6351 if (global.errors != errorsave) 6352 goto Laftersemantic; 6353 6354 /* If any of the instantiation members didn't get semantic() run 6355 * on them due to forward references, we cannot run semantic2() 6356 * or semantic3() yet. 6357 */ 6358 { 6359 bool found_deferred_ad = false; 6360 for (size_t i = 0; i < Module.deferred.dim; i++) 6361 { 6362 Dsymbol sd = Module.deferred[i]; 6363 AggregateDeclaration ad = sd.isAggregateDeclaration(); 6364 if (ad && ad.parent && ad.parent.isTemplateInstance()) 6365 { 6366 //printf("deferred template aggregate: %s %s\n", 6367 // sd.parent.toChars(), sd.toChars()); 6368 found_deferred_ad = true; 6369 if (ad.parent == this) 6370 { 6371 ad.deferred = this; 6372 break; 6373 } 6374 } 6375 } 6376 if (found_deferred_ad || Module.deferred.dim) 6377 goto Laftersemantic; 6378 } 6379 6380 /* The problem is when to parse the initializer for a variable. 6381 * Perhaps VarDeclaration.semantic() should do it like it does 6382 * for initializers inside a function. 6383 */ 6384 //if (sc.parent.isFuncDeclaration()) 6385 { 6386 /* https://issues.dlang.org/show_bug.cgi?id=782 6387 * this has problems if the classes this depends on 6388 * are forward referenced. Find a way to defer semantic() 6389 * on this template. 6390 */ 6391 semantic2(sc2); 6392 } 6393 if (global.errors != errorsave) 6394 goto Laftersemantic; 6395 6396 if ((sc.func || (sc.flags & SCOPEfullinst)) && !tinst) 6397 { 6398 /* If a template is instantiated inside function, the whole instantiation 6399 * should be done at that position. But, immediate running semantic3 of 6400 * dependent templates may cause unresolved forward reference. 6401 * https://issues.dlang.org/show_bug.cgi?id=9050 6402 * To avoid the issue, don't run semantic3 until semantic and semantic2 done. 6403 */ 6404 TemplateInstances deferred; 6405 this.deferred = &deferred; 6406 6407 //printf("Run semantic3 on %s\n", toChars()); 6408 trySemantic3(sc2); 6409 6410 for (size_t i = 0; i < deferred.dim; i++) 6411 { 6412 //printf("+ run deferred semantic3 on %s\n", deferred[i].toChars()); 6413 deferred[i].semantic3(null); 6414 } 6415 6416 this.deferred = null; 6417 } 6418 else if (tinst) 6419 { 6420 bool doSemantic3 = false; 6421 if (sc.func && aliasdecl && aliasdecl.toAlias().isFuncDeclaration()) 6422 { 6423 /* Template function instantiation should run semantic3 immediately 6424 * for attribute inference. 6425 */ 6426 doSemantic3 = true; 6427 } 6428 else if (sc.func) 6429 { 6430 /* A lambda function in template arguments might capture the 6431 * instantiated scope context. For the correct context inference, 6432 * all instantiated functions should run the semantic3 immediately. 6433 * See also compilable/test14973.d 6434 */ 6435 foreach (oarg; tdtypes) 6436 { 6437 auto s = getDsymbol(oarg); 6438 if (!s) 6439 continue; 6440 6441 if (auto td = s.isTemplateDeclaration()) 6442 { 6443 if (!td.literal) 6444 continue; 6445 assert(td.members && td.members.dim == 1); 6446 s = (*td.members)[0]; 6447 } 6448 if (auto fld = s.isFuncLiteralDeclaration()) 6449 { 6450 if (fld.tok == TOKreserved) 6451 { 6452 doSemantic3 = true; 6453 break; 6454 } 6455 } 6456 } 6457 //printf("[%s] %s doSemantic3 = %d\n", loc.toChars(), toChars(), doSemantic3); 6458 } 6459 if (doSemantic3) 6460 trySemantic3(sc2); 6461 6462 TemplateInstance ti = tinst; 6463 int nest = 0; 6464 while (ti && !ti.deferred && ti.tinst) 6465 { 6466 ti = ti.tinst; 6467 if (++nest > 500) 6468 { 6469 global.gag = 0; // ensure error message gets printed 6470 error("recursive expansion"); 6471 fatal(); 6472 } 6473 } 6474 if (ti && ti.deferred) 6475 { 6476 //printf("deferred semantic3 of %p %s, ti = %s, ti.deferred = %p\n", this, toChars(), ti.toChars()); 6477 for (size_t i = 0;; i++) 6478 { 6479 if (i == ti.deferred.dim) 6480 { 6481 ti.deferred.push(this); 6482 break; 6483 } 6484 if ((*ti.deferred)[i] == this) 6485 break; 6486 } 6487 } 6488 } 6489 6490 if (aliasdecl) 6491 { 6492 /* https://issues.dlang.org/show_bug.cgi?id=13816 6493 * AliasDeclaration tries to resolve forward reference 6494 * twice (See inuse check in AliasDeclaration.toAlias()). It's 6495 * necessary to resolve mutual references of instantiated symbols, but 6496 * it will left a true recursive alias in tuple declaration - an 6497 * AliasDeclaration A refers TupleDeclaration B, and B contains A 6498 * in its elements. To correctly make it an error, we strictly need to 6499 * resolve the alias of eponymous member. 6500 */ 6501 aliasdecl = aliasdecl.toAlias2(); 6502 } 6503 6504 Laftersemantic: 6505 sc2.pop(); 6506 _scope.pop(); 6507 6508 // Give additional context info if error occurred during instantiation 6509 if (global.errors != errorsave) 6510 { 6511 if (!errors) 6512 { 6513 if (!tempdecl.literal) 6514 error(loc, "error instantiating"); 6515 if (tinst) 6516 tinst.printInstantiationTrace(); 6517 } 6518 errors = true; 6519 if (gagged) 6520 { 6521 // Errors are gagged, so remove the template instance from the 6522 // instance/symbol lists we added it to and reset our state to 6523 // finish clean and so we can try to instantiate it again later 6524 // (see https://issues.dlang.org/show_bug.cgi?id=4302 and https://issues.dlang.org/show_bug.cgi?id=6602). 6525 tempdecl.removeInstance(tempdecl_instance_idx); 6526 if (target_symbol_list) 6527 { 6528 // Because we added 'this' in the last position above, we 6529 // should be able to remove it without messing other indices up. 6530 assert((*target_symbol_list)[target_symbol_list_idx] == this); 6531 target_symbol_list.remove(target_symbol_list_idx); 6532 memberOf = null; // no longer a member 6533 } 6534 semanticRun = PASSinit; 6535 inst = null; 6536 symtab = null; 6537 } 6538 } 6539 else if (errinst) 6540 { 6541 /* https://issues.dlang.org/show_bug.cgi?id=14541 6542 * If the previous gagged instance had failed by 6543 * circular references, currrent "error reproduction instantiation" 6544 * might succeed, because of the difference of instantiated context. 6545 * On such case, the cached error instance needs to be overridden by the 6546 * succeeded instance. 6547 */ 6548 //printf("replaceInstance()\n"); 6549 assert(errinst.errors); 6550 auto ti1 = TemplateInstanceBox(errinst); 6551 tempdecl.instances.remove(ti1); 6552 6553 auto ti2 = TemplateInstanceBox(this); 6554 tempdecl.instances[ti2] = this; 6555 } 6556 6557 static if (LOG) 6558 { 6559 printf("-TemplateInstance.semantic('%s', this=%p)\n", toChars(), this); 6560 } 6561 } 6562 6563 override void semantic(Scope* sc) 6564 { 6565 semantic(sc, null); 6566 } 6567 6568 override void semantic2(Scope* sc) 6569 { 6570 if (semanticRun >= PASSsemantic2) 6571 return; 6572 semanticRun = PASSsemantic2; 6573 static if (LOG) 6574 { 6575 printf("+TemplateInstance.semantic2('%s')\n", toChars()); 6576 } 6577 if (!errors && members) 6578 { 6579 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); 6580 assert(tempdecl); 6581 6582 sc = tempdecl._scope; 6583 assert(sc); 6584 sc = sc.push(argsym); 6585 sc = sc.push(this); 6586 sc.tinst = this; 6587 sc.minst = minst; 6588 6589 int needGagging = (gagged && !global.gag); 6590 uint olderrors = global.errors; 6591 int oldGaggedErrors = -1; // dead-store to prevent spurious warning 6592 if (needGagging) 6593 oldGaggedErrors = global.startGagging(); 6594 6595 for (size_t i = 0; i < members.dim; i++) 6596 { 6597 Dsymbol s = (*members)[i]; 6598 static if (LOG) 6599 { 6600 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); 6601 } 6602 s.semantic2(sc); 6603 if (gagged && global.errors != olderrors) 6604 break; 6605 } 6606 6607 if (global.errors != olderrors) 6608 { 6609 if (!errors) 6610 { 6611 if (!tempdecl.literal) 6612 error(loc, "error instantiating"); 6613 if (tinst) 6614 tinst.printInstantiationTrace(); 6615 } 6616 errors = true; 6617 } 6618 if (needGagging) 6619 global.endGagging(oldGaggedErrors); 6620 6621 sc = sc.pop(); 6622 sc.pop(); 6623 } 6624 static if (LOG) 6625 { 6626 printf("-TemplateInstance.semantic2('%s')\n", toChars()); 6627 } 6628 } 6629 6630 override void semantic3(Scope* sc) 6631 { 6632 static if (LOG) 6633 { 6634 printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun); 6635 } 6636 //if (toChars()[0] == 'D') *(char*)0=0; 6637 if (semanticRun >= PASSsemantic3) 6638 return; 6639 semanticRun = PASSsemantic3; 6640 if (!errors && members) 6641 { 6642 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); 6643 assert(tempdecl); 6644 6645 sc = tempdecl._scope; 6646 sc = sc.push(argsym); 6647 sc = sc.push(this); 6648 sc.tinst = this; 6649 sc.minst = minst; 6650 6651 int needGagging = (gagged && !global.gag); 6652 uint olderrors = global.errors; 6653 int oldGaggedErrors = -1; // dead-store to prevent spurious warning 6654 /* If this is a gagged instantiation, gag errors. 6655 * Future optimisation: If the results are actually needed, errors 6656 * would already be gagged, so we don't really need to run semantic 6657 * on the members. 6658 */ 6659 if (needGagging) 6660 oldGaggedErrors = global.startGagging(); 6661 6662 for (size_t i = 0; i < members.dim; i++) 6663 { 6664 Dsymbol s = (*members)[i]; 6665 s.semantic3(sc); 6666 if (gagged && global.errors != olderrors) 6667 break; 6668 } 6669 6670 if (global.errors != olderrors) 6671 { 6672 if (!errors) 6673 { 6674 if (!tempdecl.literal) 6675 error(loc, "error instantiating"); 6676 if (tinst) 6677 tinst.printInstantiationTrace(); 6678 } 6679 errors = true; 6680 } 6681 if (needGagging) 6682 global.endGagging(oldGaggedErrors); 6683 6684 sc = sc.pop(); 6685 sc.pop(); 6686 } 6687 } 6688 6689 // resolve real symbol 6690 override final Dsymbol toAlias() 6691 { 6692 static if (LOG) 6693 { 6694 printf("TemplateInstance.toAlias()\n"); 6695 } 6696 if (!inst) 6697 { 6698 // Maybe we can resolve it 6699 if (_scope) 6700 { 6701 semantic(_scope); 6702 } 6703 if (!inst) 6704 { 6705 error("cannot resolve forward reference"); 6706 errors = true; 6707 return this; 6708 } 6709 } 6710 6711 if (inst != this) 6712 return inst.toAlias(); 6713 6714 if (aliasdecl) 6715 { 6716 return aliasdecl.toAlias(); 6717 } 6718 6719 return inst; 6720 } 6721 6722 override const(char)* kind() const 6723 { 6724 return "template instance"; 6725 } 6726 6727 override bool oneMember(Dsymbol* ps, Identifier ident) 6728 { 6729 *ps = null; 6730 return true; 6731 } 6732 6733 override const(char)* toChars() 6734 { 6735 OutBuffer buf; 6736 toCBufferInstance(this, &buf); 6737 return buf.extractString(); 6738 } 6739 6740 override final char* toPrettyCharsHelper() 6741 { 6742 OutBuffer buf; 6743 toCBufferInstance(this, &buf, true); 6744 return buf.extractString(); 6745 } 6746 6747 /************************************** 6748 * Given an error instantiating the TemplateInstance, 6749 * give the nested TemplateInstance instantiations that got 6750 * us here. Those are a list threaded into the nested scopes. 6751 */ 6752 final void printInstantiationTrace() 6753 { 6754 if (global.gag) 6755 return; 6756 6757 const(uint) max_shown = 6; 6758 const(char)* format = "instantiated from here: %s"; 6759 6760 // determine instantiation depth and number of recursive instantiations 6761 int n_instantiations = 1; 6762 int n_totalrecursions = 0; 6763 for (TemplateInstance cur = this; cur; cur = cur.tinst) 6764 { 6765 ++n_instantiations; 6766 // If two instantiations use the same declaration, they are recursive. 6767 // (this works even if they are instantiated from different places in the 6768 // same template). 6769 // In principle, we could also check for multiple-template recursion, but it's 6770 // probably not worthwhile. 6771 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc)) 6772 ++n_totalrecursions; 6773 } 6774 6775 // show full trace only if it's short or verbose is on 6776 if (n_instantiations <= max_shown || global.params.verbose) 6777 { 6778 for (TemplateInstance cur = this; cur; cur = cur.tinst) 6779 { 6780 cur.errors = true; 6781 errorSupplemental(cur.loc, format, cur.toChars()); 6782 } 6783 } 6784 else if (n_instantiations - n_totalrecursions <= max_shown) 6785 { 6786 // By collapsing recursive instantiations into a single line, 6787 // we can stay under the limit. 6788 int recursionDepth = 0; 6789 for (TemplateInstance cur = this; cur; cur = cur.tinst) 6790 { 6791 cur.errors = true; 6792 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc)) 6793 { 6794 ++recursionDepth; 6795 } 6796 else 6797 { 6798 if (recursionDepth) 6799 errorSupplemental(cur.loc, "%d recursive instantiations from here: %s", recursionDepth + 2, cur.toChars()); 6800 else 6801 errorSupplemental(cur.loc, format, cur.toChars()); 6802 recursionDepth = 0; 6803 } 6804 } 6805 } 6806 else 6807 { 6808 // Even after collapsing the recursions, the depth is too deep. 6809 // Just display the first few and last few instantiations. 6810 uint i = 0; 6811 for (TemplateInstance cur = this; cur; cur = cur.tinst) 6812 { 6813 cur.errors = true; 6814 6815 if (i == max_shown / 2) 6816 errorSupplemental(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); 6817 6818 if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2) 6819 errorSupplemental(cur.loc, format, cur.toChars()); 6820 ++i; 6821 } 6822 } 6823 } 6824 6825 /************************************* 6826 * Lazily generate identifier for template instance. 6827 * This is because 75% of the ident's are never needed. 6828 */ 6829 override final Identifier getIdent() 6830 { 6831 if (!ident && inst && !errors) 6832 ident = genIdent(tiargs); // need an identifier for name mangling purposes. 6833 return ident; 6834 } 6835 6836 /************************************* 6837 * Compare proposed template instantiation with existing template instantiation. 6838 * Note that this is not commutative because of the auto ref check. 6839 * Params: 6840 * this = proposed template instantiation 6841 * o = existing template instantiation 6842 * Returns: 6843 * 0 for match, 1 for no match 6844 */ 6845 override final int compare(RootObject o) 6846 { 6847 TemplateInstance ti = cast(TemplateInstance)o; 6848 6849 //printf("this = %p, ti = %p\n", this, ti); 6850 assert(tdtypes.dim == ti.tdtypes.dim); 6851 6852 // Nesting must match 6853 if (enclosing != ti.enclosing) 6854 { 6855 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : ""); 6856 goto Lnotequals; 6857 } 6858 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars()); 6859 6860 if (!arrayObjectMatch(&tdtypes, &ti.tdtypes)) 6861 goto Lnotequals; 6862 6863 /* Template functions may have different instantiations based on 6864 * "auto ref" parameters. 6865 */ 6866 if (auto fd = ti.toAlias().isFuncDeclaration()) 6867 { 6868 if (!fd.errors) 6869 { 6870 auto fparameters = fd.getParameters(null); 6871 size_t nfparams = Parameter.dim(fparameters); // Num function parameters 6872 for (size_t j = 0; j < nfparams; j++) 6873 { 6874 Parameter fparam = Parameter.getNth(fparameters, j); 6875 if (fparam.storageClass & STCautoref) // if "auto ref" 6876 { 6877 if (!fargs) 6878 goto Lnotequals; 6879 if (fargs.dim <= j) 6880 break; 6881 Expression farg = (*fargs)[j]; 6882 if (farg.isLvalue()) 6883 { 6884 if (!(fparam.storageClass & STCref)) 6885 goto Lnotequals; // auto ref's don't match 6886 } 6887 else 6888 { 6889 if (fparam.storageClass & STCref) 6890 goto Lnotequals; // auto ref's don't match 6891 } 6892 } 6893 } 6894 } 6895 } 6896 return 0; 6897 6898 Lnotequals: 6899 return 1; 6900 } 6901 6902 final hash_t toHash() 6903 { 6904 if (!hash) 6905 { 6906 hash = cast(size_t)cast(void*)enclosing; 6907 hash += arrayObjectHash(&tdtypes); 6908 hash += hash == 0; 6909 } 6910 return hash; 6911 } 6912 6913 /*********************************************** 6914 * Returns true if this is not instantiated in non-root module, and 6915 * is a part of non-speculative instantiatiation. 6916 * 6917 * Note: minst does not stabilize until semantic analysis is completed, 6918 * so don't call this function during semantic analysis to return precise result. 6919 */ 6920 final bool needsCodegen() 6921 { 6922 // Now -allInst is just for the backward compatibility. 6923 if (global.params.allInst) 6924 { 6925 //printf("%s minst = %s, enclosing (%s).isNonRoot = %d\n", 6926 // toPrettyChars(), minst ? minst.toChars() : NULL, 6927 // enclosing ? enclosing.toPrettyChars() : NULL, enclosing && enclosing.inNonRoot()); 6928 if (enclosing) 6929 { 6930 /* https://issues.dlang.org/show_bug.cgi?id=14588 6931 * If the captured context is not a function 6932 * (e.g. class), the instance layout determination is guaranteed, 6933 * because the semantic/semantic2 pass will be executed 6934 * even for non-root instances. 6935 */ 6936 if (!enclosing.isFuncDeclaration()) 6937 return true; 6938 6939 /* https://issues.dlang.org/show_bug.cgi?id=14834 6940 * If the captured context is a function, 6941 * this excessive instantiation may cause ODR violation, because 6942 * -allInst and others doesn't guarantee the semantic3 execution 6943 * for that function. 6944 * 6945 * If the enclosing is also an instantiated function, 6946 * we have to rely on the ancestor's needsCodegen() result. 6947 */ 6948 if (TemplateInstance ti = enclosing.isInstantiated()) 6949 return ti.needsCodegen(); 6950 6951 /* https://issues.dlang.org/show_bug.cgi?id=13415 6952 * If and only if the enclosing scope needs codegen, 6953 * this nested templates would also need code generation. 6954 */ 6955 return !enclosing.inNonRoot(); 6956 } 6957 return true; 6958 } 6959 6960 if (!minst) 6961 { 6962 // If this is a speculative instantiation, 6963 // 1. do codegen if ancestors really needs codegen. 6964 // 2. become non-speculative if siblings are not speculative 6965 6966 TemplateInstance tnext = this.tnext; 6967 TemplateInstance tinst = this.tinst; 6968 // At first, disconnect chain first to prevent infinite recursion. 6969 this.tnext = null; 6970 this.tinst = null; 6971 6972 // Determine necessity of tinst before tnext. 6973 if (tinst && tinst.needsCodegen()) 6974 { 6975 minst = tinst.minst; // cache result 6976 assert(minst); 6977 assert(minst.isRoot() || minst.rootImports()); 6978 return true; 6979 } 6980 if (tnext && (tnext.needsCodegen() || tnext.minst)) 6981 { 6982 minst = tnext.minst; // cache result 6983 assert(minst); 6984 return minst.isRoot() || minst.rootImports(); 6985 } 6986 6987 // Elide codegen because this is really speculative. 6988 return false; 6989 } 6990 6991 /* Even when this is reached to the codegen pass, 6992 * a non-root nested template should not generate code, 6993 * due to avoid ODR violation. 6994 */ 6995 if (enclosing && enclosing.inNonRoot()) 6996 { 6997 if (tinst) 6998 { 6999 auto r = tinst.needsCodegen(); 7000 minst = tinst.minst; // cache result 7001 return r; 7002 } 7003 if (tnext) 7004 { 7005 auto r = tnext.needsCodegen(); 7006 minst = tnext.minst; // cache result 7007 return r; 7008 } 7009 return false; 7010 } 7011 7012 /* The issue is that if the importee is compiled with a different -debug 7013 * setting than the importer, the importer may believe it exists 7014 * in the compiled importee when it does not, when the instantiation 7015 * is behind a conditional debug declaration. 7016 */ 7017 // workaround for https://issues.dlang.org/show_bug.cgi?id=11239 7018 if (global.params.useUnitTests || 7019 global.params.debuglevel) 7020 { 7021 // Prefer instantiations from root modules, to maximize link-ability. 7022 if (minst.isRoot()) 7023 return true; 7024 7025 TemplateInstance tnext = this.tnext; 7026 TemplateInstance tinst = this.tinst; 7027 this.tnext = null; 7028 this.tinst = null; 7029 7030 if (tinst && tinst.needsCodegen()) 7031 { 7032 minst = tinst.minst; // cache result 7033 assert(minst); 7034 assert(minst.isRoot() || minst.rootImports()); 7035 return true; 7036 } 7037 if (tnext && tnext.needsCodegen()) 7038 { 7039 minst = tnext.minst; // cache result 7040 assert(minst); 7041 assert(minst.isRoot() || minst.rootImports()); 7042 return true; 7043 } 7044 7045 // https://issues.dlang.org/show_bug.cgi?id=2500 case 7046 if (minst.rootImports()) 7047 return true; 7048 7049 // Elide codegen because this is not included in root instances. 7050 return false; 7051 } 7052 else 7053 { 7054 // Prefer instantiations from non-root module, to minimize object code size. 7055 7056 /* If a TemplateInstance is ever instantiated by non-root modules, 7057 * we do not have to generate code for it, 7058 * because it will be generated when the non-root module is compiled. 7059 * 7060 * But, if the non-root 'minst' imports any root modules, it might still need codegen. 7061 * 7062 * The problem is if A imports B, and B imports A, and both A 7063 * and B instantiate the same template, does the compilation of A 7064 * or the compilation of B do the actual instantiation? 7065 * 7066 * See https://issues.dlang.org/show_bug.cgi?id=2500. 7067 */ 7068 if (!minst.isRoot() && !minst.rootImports()) 7069 return false; 7070 7071 TemplateInstance tnext = this.tnext; 7072 this.tnext = null; 7073 7074 if (tnext && !tnext.needsCodegen() && tnext.minst) 7075 { 7076 minst = tnext.minst; // cache result 7077 assert(!minst.isRoot()); 7078 return false; 7079 } 7080 7081 // Do codegen because this is not included in non-root instances. 7082 return true; 7083 } 7084 } 7085 7086 /********************************************** 7087 * Find template declaration corresponding to template instance. 7088 * 7089 * Returns: 7090 * false if finding fails. 7091 * Note: 7092 * This function is reentrant against error occurrence. If returns false, 7093 * any members of this object won't be modified, and repetition call will 7094 * reproduce same error. 7095 */ 7096 final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym) 7097 { 7098 if (pwithsym) 7099 *pwithsym = null; 7100 7101 if (havetempdecl) 7102 return true; 7103 7104 //printf("TemplateInstance.findTempDecl() %s\n", toChars()); 7105 if (!tempdecl) 7106 { 7107 /* Given: 7108 * foo!( ... ) 7109 * figure out which TemplateDeclaration foo refers to. 7110 */ 7111 Identifier id = name; 7112 Dsymbol scopesym; 7113 Dsymbol s = sc.search(loc, id, &scopesym); 7114 if (!s) 7115 { 7116 s = sc.search_correct(id); 7117 if (s) 7118 error("template '%s' is not defined, did you mean %s?", id.toChars(), s.toChars()); 7119 else 7120 error("template '%s' is not defined", id.toChars()); 7121 return false; 7122 } 7123 static if (LOG) 7124 { 7125 printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind()); 7126 if (s.parent) 7127 printf("s.parent = '%s'\n", s.parent.toChars()); 7128 } 7129 if (pwithsym) 7130 *pwithsym = scopesym.isWithScopeSymbol(); 7131 7132 /* We might have found an alias within a template when 7133 * we really want the template. 7134 */ 7135 TemplateInstance ti; 7136 if (s.parent && (ti = s.parent.isTemplateInstance()) !is null) 7137 { 7138 if (ti.tempdecl && ti.tempdecl.ident == id) 7139 { 7140 /* This is so that one can refer to the enclosing 7141 * template, even if it has the same name as a member 7142 * of the template, if it has a !(arguments) 7143 */ 7144 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 7145 assert(td); 7146 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 7147 td = td.overroot; // then get the start 7148 s = td; 7149 } 7150 } 7151 7152 if (!updateTempDecl(sc, s)) 7153 { 7154 return false; 7155 } 7156 } 7157 assert(tempdecl); 7158 7159 // Look for forward references 7160 auto tovers = tempdecl.isOverloadSet(); 7161 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) 7162 { 7163 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; 7164 int r = overloadApply(dstart, (Dsymbol s) 7165 { 7166 auto td = s.isTemplateDeclaration(); 7167 if (!td) 7168 return 0; 7169 7170 if (td.semanticRun == PASSinit) 7171 { 7172 if (td._scope) 7173 { 7174 // Try to fix forward reference. Ungag errors while doing so. 7175 Ungag ungag = td.ungagSpeculative(); 7176 td.semantic(td._scope); 7177 } 7178 if (td.semanticRun == PASSinit) 7179 { 7180 error("%s forward references template declaration %s", 7181 toChars(), td.toChars()); 7182 return 1; 7183 } 7184 } 7185 return 0; 7186 }); 7187 if (r) 7188 return false; 7189 } 7190 return true; 7191 } 7192 7193 /********************************************** 7194 * Confirm s is a valid template, then store it. 7195 * Input: 7196 * sc 7197 * s candidate symbol of template. It may be: 7198 * TemplateDeclaration 7199 * FuncDeclaration with findTemplateDeclRoot() != NULL 7200 * OverloadSet which contains candidates 7201 * Returns: 7202 * true if updating succeeds. 7203 */ 7204 final bool updateTempDecl(Scope* sc, Dsymbol s) 7205 { 7206 if (s) 7207 { 7208 Identifier id = name; 7209 s = s.toAlias(); 7210 7211 /* If an OverloadSet, look for a unique member that is a template declaration 7212 */ 7213 OverloadSet os = s.isOverloadSet(); 7214 if (os) 7215 { 7216 s = null; 7217 for (size_t i = 0; i < os.a.dim; i++) 7218 { 7219 Dsymbol s2 = os.a[i]; 7220 if (FuncDeclaration f = s2.isFuncDeclaration()) 7221 s2 = f.findTemplateDeclRoot(); 7222 else 7223 s2 = s2.isTemplateDeclaration(); 7224 if (s2) 7225 { 7226 if (s) 7227 { 7228 tempdecl = os; 7229 return true; 7230 } 7231 s = s2; 7232 } 7233 } 7234 if (!s) 7235 { 7236 error("template '%s' is not defined", id.toChars()); 7237 return false; 7238 } 7239 } 7240 7241 OverDeclaration od = s.isOverDeclaration(); 7242 if (od) 7243 { 7244 tempdecl = od; // TODO: more strict check 7245 return true; 7246 } 7247 7248 /* It should be a TemplateDeclaration, not some other symbol 7249 */ 7250 if (FuncDeclaration f = s.isFuncDeclaration()) 7251 tempdecl = f.findTemplateDeclRoot(); 7252 else 7253 tempdecl = s.isTemplateDeclaration(); 7254 if (!tempdecl) 7255 { 7256 if (!s.parent && global.errors) 7257 return false; 7258 if (!s.parent && s.getType()) 7259 { 7260 Dsymbol s2 = s.getType().toDsymbol(sc); 7261 if (!s2) 7262 { 7263 error("%s is not a template declaration, it is a %s", id.toChars(), s.kind()); 7264 return false; 7265 } 7266 s = s2; 7267 } 7268 debug 7269 { 7270 //if (!s.parent) printf("s = %s %s\n", s.kind(), s.toChars()); 7271 } 7272 //assert(s.parent); 7273 TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null; 7274 if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl) 7275 { 7276 /* This is so that one can refer to the enclosing 7277 * template, even if it has the same name as a member 7278 * of the template, if it has a !(arguments) 7279 */ 7280 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 7281 assert(td); 7282 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 7283 td = td.overroot; // then get the start 7284 tempdecl = td; 7285 } 7286 else 7287 { 7288 error("%s is not a template declaration, it is a %s", id.toChars(), s.kind()); 7289 return false; 7290 } 7291 } 7292 } 7293 return (tempdecl !is null); 7294 } 7295 7296 /********************************** 7297 * Run semantic of tiargs as arguments of template. 7298 * Input: 7299 * loc 7300 * sc 7301 * tiargs array of template arguments 7302 * flags 1: replace const variables with their initializers 7303 * 2: don't devolve Parameter to Type 7304 * Returns: 7305 * false if one or more arguments have errors. 7306 */ 7307 static bool semanticTiargs(Loc loc, Scope* sc, Objects* tiargs, int flags) 7308 { 7309 // Run semantic on each argument, place results in tiargs[] 7310 //printf("+TemplateInstance.semanticTiargs()\n"); 7311 if (!tiargs) 7312 return true; 7313 bool err = false; 7314 for (size_t j = 0; j < tiargs.dim; j++) 7315 { 7316 RootObject o = (*tiargs)[j]; 7317 Type ta = isType(o); 7318 Expression ea = isExpression(o); 7319 Dsymbol sa = isDsymbol(o); 7320 7321 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); 7322 if (ta) 7323 { 7324 //printf("type %s\n", ta.toChars()); 7325 // It might really be an Expression or an Alias 7326 ta.resolve(loc, sc, &ea, &ta, &sa); 7327 if (ea) 7328 goto Lexpr; 7329 if (sa) 7330 goto Ldsym; 7331 if (ta is null) 7332 { 7333 assert(global.errors); 7334 ta = Type.terror; 7335 } 7336 7337 Ltype: 7338 if (ta.ty == Ttuple) 7339 { 7340 // Expand tuple 7341 TypeTuple tt = cast(TypeTuple)ta; 7342 size_t dim = tt.arguments.dim; 7343 tiargs.remove(j); 7344 if (dim) 7345 { 7346 tiargs.reserve(dim); 7347 for (size_t i = 0; i < dim; i++) 7348 { 7349 Parameter arg = (*tt.arguments)[i]; 7350 if (flags & 2 && arg.ident) 7351 tiargs.insert(j + i, arg); 7352 else 7353 tiargs.insert(j + i, arg.type); 7354 } 7355 } 7356 j--; 7357 continue; 7358 } 7359 if (ta.ty == Terror) 7360 { 7361 err = true; 7362 continue; 7363 } 7364 (*tiargs)[j] = ta.merge2(); 7365 } 7366 else if (ea) 7367 { 7368 Lexpr: 7369 //printf("+[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars()); 7370 if (flags & 1) // only used by __traits 7371 { 7372 ea = ea.semantic(sc); 7373 7374 // must not interpret the args, excepting template parameters 7375 if (ea.op != TOKvar || ((cast(VarExp)ea).var.storage_class & STCtemplateparameter)) 7376 { 7377 ea = ea.optimize(WANTvalue); 7378 } 7379 } 7380 else 7381 { 7382 sc = sc.startCTFE(); 7383 ea = ea.semantic(sc); 7384 sc = sc.endCTFE(); 7385 7386 if (ea.op == TOKvar) 7387 { 7388 /* This test is to skip substituting a const var with 7389 * its initializer. The problem is the initializer won't 7390 * match with an 'alias' parameter. Instead, do the 7391 * const substitution in TemplateValueParameter.matchArg(). 7392 */ 7393 } 7394 else if (definitelyValueParameter(ea)) 7395 { 7396 if (ea.checkValue()) // check void expression 7397 ea = new ErrorExp(); 7398 uint olderrs = global.errors; 7399 ea = ea.ctfeInterpret(); 7400 if (global.errors != olderrs) 7401 ea = new ErrorExp(); 7402 } 7403 } 7404 //printf("-[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars()); 7405 if (ea.op == TOKtuple) 7406 { 7407 // Expand tuple 7408 TupleExp te = cast(TupleExp)ea; 7409 size_t dim = te.exps.dim; 7410 tiargs.remove(j); 7411 if (dim) 7412 { 7413 tiargs.reserve(dim); 7414 for (size_t i = 0; i < dim; i++) 7415 tiargs.insert(j + i, (*te.exps)[i]); 7416 } 7417 j--; 7418 continue; 7419 } 7420 if (ea.op == TOKerror) 7421 { 7422 err = true; 7423 continue; 7424 } 7425 (*tiargs)[j] = ea; 7426 7427 if (ea.op == TOKtype) 7428 { 7429 ta = ea.type; 7430 goto Ltype; 7431 } 7432 if (ea.op == TOKscope) 7433 { 7434 sa = (cast(ScopeExp)ea).sds; 7435 goto Ldsym; 7436 } 7437 if (ea.op == TOKfunction) 7438 { 7439 FuncExp fe = cast(FuncExp)ea; 7440 /* A function literal, that is passed to template and 7441 * already semanticed as function pointer, never requires 7442 * outer frame. So convert it to global function is valid. 7443 */ 7444 if (fe.fd.tok == TOKreserved && fe.type.ty == Tpointer) 7445 { 7446 // change to non-nested 7447 fe.fd.tok = TOKfunction; 7448 fe.fd.vthis = null; 7449 } 7450 else if (fe.td) 7451 { 7452 /* If template argument is a template lambda, 7453 * get template declaration itself. */ 7454 //sa = fe.td; 7455 //goto Ldsym; 7456 } 7457 } 7458 if (ea.op == TOKdotvar) 7459 { 7460 // translate expression to dsymbol. 7461 sa = (cast(DotVarExp)ea).var; 7462 goto Ldsym; 7463 } 7464 if (ea.op == TOKtemplate) 7465 { 7466 sa = (cast(TemplateExp)ea).td; 7467 goto Ldsym; 7468 } 7469 if (ea.op == TOKdottd) 7470 { 7471 // translate expression to dsymbol. 7472 sa = (cast(DotTemplateExp)ea).td; 7473 goto Ldsym; 7474 } 7475 } 7476 else if (sa) 7477 { 7478 Ldsym: 7479 //printf("dsym %s %s\n", sa.kind(), sa.toChars()); 7480 if (sa.errors) 7481 { 7482 err = true; 7483 continue; 7484 } 7485 7486 TupleDeclaration d = sa.toAlias().isTupleDeclaration(); 7487 if (d) 7488 { 7489 // Expand tuple 7490 tiargs.remove(j); 7491 tiargs.insert(j, d.objects); 7492 j--; 7493 continue; 7494 } 7495 if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration()) 7496 { 7497 FuncDeclaration f = fa.toAliasFunc(); 7498 if (!fa.hasOverloads && f.isUnique()) 7499 { 7500 // Strip FuncAlias only when the aliased function 7501 // does not have any overloads. 7502 sa = f; 7503 } 7504 } 7505 (*tiargs)[j] = sa; 7506 7507 TemplateDeclaration td = sa.isTemplateDeclaration(); 7508 if (td && td.semanticRun == PASSinit && td.literal) 7509 { 7510 td.semantic(sc); 7511 } 7512 FuncDeclaration fd = sa.isFuncDeclaration(); 7513 if (fd) 7514 fd.functionSemantic(); 7515 } 7516 else if (isParameter(o)) 7517 { 7518 } 7519 else 7520 { 7521 assert(0); 7522 } 7523 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]); 7524 } 7525 version (none) 7526 { 7527 printf("-TemplateInstance.semanticTiargs()\n"); 7528 for (size_t j = 0; j < tiargs.dim; j++) 7529 { 7530 RootObject o = (*tiargs)[j]; 7531 Type ta = isType(o); 7532 Expression ea = isExpression(o); 7533 Dsymbol sa = isDsymbol(o); 7534 Tuple va = isTuple(o); 7535 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); 7536 } 7537 } 7538 return !err; 7539 } 7540 7541 /********************************** 7542 * Run semantic on the elements of tiargs. 7543 * Input: 7544 * sc 7545 * Returns: 7546 * false if one or more arguments have errors. 7547 * Note: 7548 * This function is reentrant against error occurrence. If returns false, 7549 * all elements of tiargs won't be modified. 7550 */ 7551 final bool semanticTiargs(Scope* sc) 7552 { 7553 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars()); 7554 if (semantictiargsdone) 7555 return true; 7556 if (semanticTiargs(loc, sc, tiargs, 0)) 7557 { 7558 // cache the result iff semantic analysis succeeded entirely 7559 semantictiargsdone = 1; 7560 return true; 7561 } 7562 return false; 7563 } 7564 7565 final bool findBestMatch(Scope* sc, Expressions* fargs) 7566 { 7567 if (havetempdecl) 7568 { 7569 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); 7570 assert(tempdecl); 7571 assert(tempdecl._scope); 7572 // Deduce tdtypes 7573 tdtypes.setDim(tempdecl.parameters.dim); 7574 if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2)) 7575 { 7576 error("incompatible arguments for template instantiation"); 7577 return false; 7578 } 7579 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary? 7580 return true; 7581 } 7582 7583 static if (LOG) 7584 { 7585 printf("TemplateInstance.findBestMatch()\n"); 7586 } 7587 7588 uint errs = global.errors; 7589 TemplateDeclaration td_last = null; 7590 Objects dedtypes; 7591 7592 /* Since there can be multiple TemplateDeclaration's with the same 7593 * name, look for the best match. 7594 */ 7595 auto tovers = tempdecl.isOverloadSet(); 7596 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) 7597 { 7598 TemplateDeclaration td_best; 7599 TemplateDeclaration td_ambig; 7600 MATCH m_best = MATCHnomatch; 7601 7602 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; 7603 overloadApply(dstart, (Dsymbol s) 7604 { 7605 auto td = s.isTemplateDeclaration(); 7606 if (!td || td == td_best) // skip duplicates 7607 return 0; 7608 7609 //printf("td = %s\n", td.toPrettyChars()); 7610 // If more arguments than parameters, 7611 // then this is no match. 7612 if (td.parameters.dim < tiargs.dim) 7613 { 7614 if (!td.isVariadic()) 7615 return 0; 7616 } 7617 7618 dedtypes.setDim(td.parameters.dim); 7619 dedtypes.zero(); 7620 assert(td.semanticRun != PASSinit); 7621 7622 MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0); 7623 //printf("matchWithInstance = %d\n", m); 7624 if (m <= MATCHnomatch) // no match at all 7625 return 0; 7626 if (m < m_best) goto Ltd_best; 7627 if (m > m_best) goto Ltd; 7628 7629 // Disambiguate by picking the most specialized TemplateDeclaration 7630 { 7631 MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs); 7632 MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs); 7633 //printf("c1 = %d, c2 = %d\n", c1, c2); 7634 if (c1 > c2) goto Ltd; 7635 if (c1 < c2) goto Ltd_best; 7636 } 7637 7638 td_ambig = td; 7639 return 0; 7640 7641 Ltd_best: 7642 // td_best is the best match so far 7643 td_ambig = null; 7644 return 0; 7645 7646 Ltd: 7647 // td is the new best match 7648 td_ambig = null; 7649 td_best = td; 7650 m_best = m; 7651 tdtypes.setDim(dedtypes.dim); 7652 memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * (void*).sizeof); 7653 return 0; 7654 }); 7655 7656 if (td_ambig) 7657 { 7658 .error(loc, "%s %s.%s matches more than one template declaration:\n%s: %s\nand\n%s: %s", 7659 td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(), 7660 td_best.loc.toChars(), td_best.toChars(), 7661 td_ambig.loc.toChars(), td_ambig.toChars()); 7662 return false; 7663 } 7664 if (td_best) 7665 { 7666 if (!td_last) 7667 td_last = td_best; 7668 else if (td_last != td_best) 7669 { 7670 ScopeDsymbol.multiplyDefined(loc, td_last, td_best); 7671 return false; 7672 } 7673 } 7674 } 7675 7676 if (td_last) 7677 { 7678 /* https://issues.dlang.org/show_bug.cgi?id=7469 7679 * Normalize tiargs by using corresponding deduced 7680 * template value parameters and tuples for the correct mangling. 7681 * 7682 * By doing this before hasNestedArgs, CTFEable local variable will be 7683 * accepted as a value parameter. For example: 7684 * 7685 * void foo() { 7686 * struct S(int n) {} // non-global template 7687 * const int num = 1; // CTFEable local variable 7688 * S!num s; // S!1 is instantiated, not S!num 7689 * } 7690 */ 7691 size_t dim = td_last.parameters.dim - (td_last.isVariadic() ? 1 : 0); 7692 for (size_t i = 0; i < dim; i++) 7693 { 7694 if (tiargs.dim <= i) 7695 tiargs.push(tdtypes[i]); 7696 assert(i < tiargs.dim); 7697 7698 auto tvp = (*td_last.parameters)[i].isTemplateValueParameter(); 7699 if (!tvp) 7700 continue; 7701 assert(tdtypes[i]); 7702 // tdtypes[i] is already normalized to the required type in matchArg 7703 7704 (*tiargs)[i] = tdtypes[i]; 7705 } 7706 if (td_last.isVariadic() && tiargs.dim == dim && tdtypes[dim]) 7707 { 7708 Tuple va = isTuple(tdtypes[dim]); 7709 assert(va); 7710 for (size_t i = 0; i < va.objects.dim; i++) 7711 tiargs.push(va.objects[i]); 7712 } 7713 } 7714 else if (errors && inst) 7715 { 7716 // instantiation was failed with error reporting 7717 assert(global.errors); 7718 return false; 7719 } 7720 else 7721 { 7722 auto tdecl = tempdecl.isTemplateDeclaration(); 7723 7724 if (errs != global.errors) 7725 errorSupplemental(loc, "while looking for match for %s", toChars()); 7726 else if (tdecl && !tdecl.overnext) 7727 { 7728 // Only one template, so we can give better error message 7729 error("does not match template declaration %s", tdecl.toChars()); 7730 } 7731 else 7732 .error(loc, "%s %s.%s does not match any template declaration", tempdecl.kind(), tempdecl.parent.toPrettyChars(), tempdecl.ident.toChars()); 7733 return false; 7734 } 7735 7736 /* The best match is td_last 7737 */ 7738 tempdecl = td_last; 7739 7740 static if (LOG) 7741 { 7742 printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars()); 7743 } 7744 return (errs == global.errors); 7745 } 7746 7747 /***************************************************** 7748 * Determine if template instance is really a template function, 7749 * and that template function needs to infer types from the function 7750 * arguments. 7751 * 7752 * Like findBestMatch, iterate possible template candidates, 7753 * but just looks only the necessity of type inference. 7754 */ 7755 final bool needsTypeInference(Scope* sc, int flag = 0) 7756 { 7757 //printf("TemplateInstance.needsTypeInference() %s\n", toChars()); 7758 if (semanticRun != PASSinit) 7759 return false; 7760 7761 uint olderrs = global.errors; 7762 Objects dedtypes; 7763 size_t count = 0; 7764 7765 auto tovers = tempdecl.isOverloadSet(); 7766 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) 7767 { 7768 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; 7769 int r = overloadApply(dstart, (Dsymbol s) 7770 { 7771 auto td = s.isTemplateDeclaration(); 7772 if (!td) 7773 return 0; 7774 7775 /* If any of the overloaded template declarations need inference, 7776 * then return true 7777 */ 7778 if (!td.onemember) 7779 return 0; 7780 if (auto td2 = td.onemember.isTemplateDeclaration()) 7781 { 7782 if (!td2.onemember || !td2.onemember.isFuncDeclaration()) 7783 return 0; 7784 if (tiargs.dim >= td.parameters.dim - (td.isVariadic() ? 1 : 0)) 7785 return 0; 7786 return 1; 7787 } 7788 auto fd = td.onemember.isFuncDeclaration(); 7789 if (!fd || fd.type.ty != Tfunction) 7790 return 0; 7791 7792 foreach (tp; *td.parameters) 7793 { 7794 if (tp.isTemplateThisParameter()) 7795 return 1; 7796 } 7797 7798 /* Determine if the instance arguments, tiargs, are all that is necessary 7799 * to instantiate the template. 7800 */ 7801 //printf("tp = %p, td.parameters.dim = %d, tiargs.dim = %d\n", tp, td.parameters.dim, tiargs.dim); 7802 auto tf = cast(TypeFunction)fd.type; 7803 if (size_t dim = Parameter.dim(tf.parameters)) 7804 { 7805 auto tp = td.isVariadic(); 7806 if (tp && td.parameters.dim > 1) 7807 return 1; 7808 7809 if (!tp && tiargs.dim < td.parameters.dim) 7810 { 7811 // Can remain tiargs be filled by default arguments? 7812 foreach (size_t i; tiargs.dim .. td.parameters.dim) 7813 { 7814 if (!(*td.parameters)[i].hasDefaultArg()) 7815 return 1; 7816 } 7817 } 7818 7819 foreach (size_t i; 0 .. dim) 7820 { 7821 // 'auto ref' needs inference. 7822 if (Parameter.getNth(tf.parameters, i).storageClass & STCauto) 7823 return 1; 7824 } 7825 } 7826 7827 if (!flag) 7828 { 7829 /* Calculate the need for overload resolution. 7830 * When only one template can match with tiargs, inference is not necessary. 7831 */ 7832 dedtypes.setDim(td.parameters.dim); 7833 dedtypes.zero(); 7834 if (td.semanticRun == PASSinit) 7835 { 7836 if (td._scope) 7837 { 7838 // Try to fix forward reference. Ungag errors while doing so. 7839 Ungag ungag = td.ungagSpeculative(); 7840 td.semantic(td._scope); 7841 } 7842 if (td.semanticRun == PASSinit) 7843 { 7844 error("%s forward references template declaration %s", toChars(), td.toChars()); 7845 return 1; 7846 } 7847 } 7848 MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0); 7849 if (m <= MATCHnomatch) 7850 return 0; 7851 } 7852 7853 /* If there is more than one function template which matches, we may 7854 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430) 7855 */ 7856 return ++count > 1 ? 1 : 0; 7857 }); 7858 if (r) 7859 return true; 7860 } 7861 7862 if (olderrs != global.errors) 7863 { 7864 if (!global.gag) 7865 { 7866 errorSupplemental(loc, "while looking for match for %s", toChars()); 7867 semanticRun = PASSsemanticdone; 7868 inst = this; 7869 } 7870 errors = true; 7871 } 7872 //printf("false\n"); 7873 return false; 7874 } 7875 7876 /***************************************** 7877 * Determines if a TemplateInstance will need a nested 7878 * generation of the TemplateDeclaration. 7879 * Sets enclosing property if so, and returns != 0; 7880 */ 7881 final bool hasNestedArgs(Objects* args, bool isstatic) 7882 { 7883 int nested = 0; 7884 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars()); 7885 7886 version (none) 7887 { 7888 if (!enclosing) 7889 { 7890 if (TemplateInstance ti = tempdecl.isInstantiated()) 7891 enclosing = ti.enclosing; 7892 } 7893 } 7894 7895 /* A nested instance happens when an argument references a local 7896 * symbol that is on the stack. 7897 */ 7898 for (size_t i = 0; i < args.dim; i++) 7899 { 7900 RootObject o = (*args)[i]; 7901 Expression ea = isExpression(o); 7902 Dsymbol sa = isDsymbol(o); 7903 Tuple va = isTuple(o); 7904 if (ea) 7905 { 7906 if (ea.op == TOKvar) 7907 { 7908 sa = (cast(VarExp)ea).var; 7909 goto Lsa; 7910 } 7911 if (ea.op == TOKthis) 7912 { 7913 sa = (cast(ThisExp)ea).var; 7914 goto Lsa; 7915 } 7916 if (ea.op == TOKfunction) 7917 { 7918 if ((cast(FuncExp)ea).td) 7919 sa = (cast(FuncExp)ea).td; 7920 else 7921 sa = (cast(FuncExp)ea).fd; 7922 goto Lsa; 7923 } 7924 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent. 7925 if (ea.op != TOKint64 && ea.op != TOKfloat64 && ea.op != TOKcomplex80 && ea.op != TOKnull && ea.op != TOKstring && ea.op != TOKarrayliteral && ea.op != TOKassocarrayliteral && ea.op != TOKstructliteral) 7926 { 7927 ea.error("expression %s is not a valid template value argument", ea.toChars()); 7928 errors = true; 7929 } 7930 } 7931 else if (sa) 7932 { 7933 Lsa: 7934 sa = sa.toAlias(); 7935 TemplateDeclaration td = sa.isTemplateDeclaration(); 7936 if (td) 7937 { 7938 TemplateInstance ti = sa.toParent().isTemplateInstance(); 7939 if (ti && ti.enclosing) 7940 sa = ti; 7941 } 7942 TemplateInstance ti = sa.isTemplateInstance(); 7943 Declaration d = sa.isDeclaration(); 7944 if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STCmanifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin())) 7945 { 7946 // if module level template 7947 if (isstatic) 7948 { 7949 Dsymbol dparent = sa.toParent2(); 7950 if (!enclosing) 7951 enclosing = dparent; 7952 else if (enclosing != dparent) 7953 { 7954 /* Select the more deeply nested of the two. 7955 * Error if one is not nested inside the other. 7956 */ 7957 for (Dsymbol p = enclosing; p; p = p.parent) 7958 { 7959 if (p == dparent) 7960 goto L1; // enclosing is most nested 7961 } 7962 for (Dsymbol p = dparent; p; p = p.parent) 7963 { 7964 if (p == enclosing) 7965 { 7966 enclosing = dparent; 7967 goto L1; // dparent is most nested 7968 } 7969 } 7970 error("%s is nested in both %s and %s", toChars(), enclosing.toChars(), dparent.toChars()); 7971 errors = true; 7972 } 7973 L1: 7974 //printf("\tnested inside %s\n", enclosing.toChars()); 7975 nested |= 1; 7976 } 7977 else 7978 { 7979 error("cannot use local '%s' as parameter to non-global template %s", sa.toChars(), tempdecl.toChars()); 7980 errors = true; 7981 } 7982 } 7983 } 7984 else if (va) 7985 { 7986 nested |= cast(int)hasNestedArgs(&va.objects, isstatic); 7987 } 7988 } 7989 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested); 7990 return nested != 0; 7991 } 7992 7993 /***************************************** 7994 * Append 'this' to the specific module members[] 7995 */ 7996 final Dsymbols* appendToModuleMember() 7997 { 7998 Module mi = minst; // instantiated . inserted module 7999 8000 if (global.params.useUnitTests || global.params.debuglevel) 8001 { 8002 // Turn all non-root instances to speculative 8003 if (mi && !mi.isRoot()) 8004 mi = null; 8005 } 8006 8007 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n", 8008 // toPrettyChars(), 8009 // enclosing ? enclosing.toPrettyChars() : null, 8010 // mi ? mi.toPrettyChars() : null); 8011 if (!mi || mi.isRoot()) 8012 { 8013 /* If the instantiated module is speculative or root, insert to the 8014 * member of a root module. Then: 8015 * - semantic3 pass will get called on the instance members. 8016 * - codegen pass will get a selection chance to do/skip it. 8017 */ 8018 static Dsymbol getStrictEnclosing(TemplateInstance ti) 8019 { 8020 do 8021 { 8022 if (ti.enclosing) 8023 return ti.enclosing; 8024 ti = ti.tempdecl.isInstantiated(); 8025 } while (ti); 8026 return null; 8027 } 8028 8029 Dsymbol enc = getStrictEnclosing(this); 8030 // insert target is made stable by using the module 8031 // where tempdecl is declared. 8032 mi = (enc ? enc : tempdecl).getModule(); 8033 if (!mi.isRoot()) 8034 mi = mi.importedFrom; 8035 assert(mi.isRoot()); 8036 } 8037 else 8038 { 8039 /* If the instantiated module is non-root, insert to the member of the 8040 * non-root module. Then: 8041 * - semantic3 pass won't be called on the instance. 8042 * - codegen pass won't reach to the instance. 8043 */ 8044 } 8045 //printf("\t-. mi = %s\n", mi.toPrettyChars()); 8046 8047 if (memberOf is mi) // already a member 8048 { 8049 debug // make sure it really is a member 8050 { 8051 auto a = mi.members; 8052 for (size_t i = 0; 1; ++i) 8053 { 8054 assert(i != a.dim); 8055 if (this == (*a)[i]) 8056 break; 8057 } 8058 } 8059 return null; 8060 } 8061 8062 Dsymbols* a = mi.members; 8063 a.push(this); 8064 memberOf = mi; 8065 if (mi.semanticRun >= PASSsemantic2done && mi.isRoot()) 8066 Module.addDeferredSemantic2(this); 8067 if (mi.semanticRun >= PASSsemantic3done && mi.isRoot()) 8068 Module.addDeferredSemantic3(this); 8069 return a; 8070 } 8071 8072 /**************************************************** 8073 * Declare parameters of template instance, initialize them with the 8074 * template instance arguments. 8075 */ 8076 final void declareParameters(Scope* sc) 8077 { 8078 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); 8079 assert(tempdecl); 8080 8081 //printf("TemplateInstance.declareParameters()\n"); 8082 for (size_t i = 0; i < tdtypes.dim; i++) 8083 { 8084 TemplateParameter tp = (*tempdecl.parameters)[i]; 8085 //RootObject *o = (*tiargs)[i]; 8086 RootObject o = tdtypes[i]; // initializer for tp 8087 8088 //printf("\ttdtypes[%d] = %p\n", i, o); 8089 tempdecl.declareParameter(sc, tp, o); 8090 } 8091 } 8092 8093 /**************************************** 8094 * This instance needs an identifier for name mangling purposes. 8095 * Create one by taking the template declaration name and adding 8096 * the type signature for it. 8097 */ 8098 final Identifier genIdent(Objects* args) 8099 { 8100 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); 8101 assert(tempdecl); 8102 8103 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars()); 8104 OutBuffer buf; 8105 8106 const id = tempdecl.ident.toString(); 8107 // Use "__U" for the symbols declared inside template constraint. 8108 const char T = members ? 'T' : 'U'; 8109 buf.printf("__%c%u%.*s", T, cast(int)id.length, cast(int)id.length, id.ptr); 8110 8111 size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0); 8112 for (size_t i = 0; i < args.dim; i++) 8113 { 8114 RootObject o = (*args)[i]; 8115 Type ta = isType(o); 8116 Expression ea = isExpression(o); 8117 Dsymbol sa = isDsymbol(o); 8118 Tuple va = isTuple(o); 8119 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); 8120 if (i < nparams && (*tempdecl.parameters)[i].specialization()) 8121 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574 8122 if (ta) 8123 { 8124 buf.writeByte('T'); 8125 if (ta.deco) 8126 buf.writestring(ta.deco); 8127 else 8128 { 8129 debug 8130 { 8131 if (!global.errors) 8132 printf("ta = %d, %s\n", ta.ty, ta.toChars()); 8133 } 8134 assert(global.errors); 8135 } 8136 } 8137 else if (ea) 8138 { 8139 // Don't interpret it yet, it might actually be an alias 8140 ea = ea.optimize(WANTvalue); 8141 if (ea.op == TOKvar) 8142 { 8143 sa = (cast(VarExp)ea).var; 8144 ea = null; 8145 goto Lsa; 8146 } 8147 if (ea.op == TOKthis) 8148 { 8149 sa = (cast(ThisExp)ea).var; 8150 ea = null; 8151 goto Lsa; 8152 } 8153 if (ea.op == TOKfunction) 8154 { 8155 if ((cast(FuncExp)ea).td) 8156 sa = (cast(FuncExp)ea).td; 8157 else 8158 sa = (cast(FuncExp)ea).fd; 8159 ea = null; 8160 goto Lsa; 8161 } 8162 buf.writeByte('V'); 8163 if (ea.op == TOKtuple) 8164 { 8165 ea.error("tuple is not a valid template value argument"); 8166 continue; 8167 } 8168 // Now that we know it is not an alias, we MUST obtain a value 8169 uint olderr = global.errors; 8170 ea = ea.ctfeInterpret(); 8171 if (ea.op == TOKerror || olderr != global.errors) 8172 continue; 8173 8174 /* Use deco that matches what it would be for a function parameter 8175 */ 8176 buf.writestring(ea.type.deco); 8177 mangleToBuffer(ea, &buf); 8178 } 8179 else if (sa) 8180 { 8181 Lsa: 8182 buf.writeByte('S'); 8183 sa = sa.toAlias(); 8184 Declaration d = sa.isDeclaration(); 8185 if (d && (!d.type || !d.type.deco)) 8186 { 8187 error("forward reference of %s %s", d.kind(), d.toChars()); 8188 continue; 8189 } 8190 8191 OutBuffer bufsa; 8192 mangleToBuffer(sa, &bufsa); 8193 auto s = bufsa.peekSlice(); 8194 8195 /* https://issues.dlang.org/show_bug.cgi?id=3043 8196 * If the first character of p is a digit this 8197 * causes ambiguity issues because the digits of the two numbers are adjacent. 8198 * Current demanglers resolve this by trying various places to separate the 8199 * numbers until one gets a successful demangle. 8200 * Unfortunately, fixing this ambiguity will break existing binary 8201 * compatibility and the demanglers, so we'll leave it as is. 8202 */ 8203 buf.printf("%u%.*s", cast(uint)s.length, cast(int)s.length, s.ptr); 8204 } 8205 else if (va) 8206 { 8207 assert(i + 1 == args.dim); // must be last one 8208 args = &va.objects; 8209 i = -cast(size_t)1; 8210 } 8211 else 8212 assert(0); 8213 } 8214 buf.writeByte('Z'); 8215 //printf("\tgenIdent = %s\n", buf.peekString()); 8216 return Identifier.idPool(buf.peekSlice()); 8217 } 8218 8219 final void expandMembers(Scope* sc2) 8220 { 8221 for (size_t i = 0; i < members.dim; i++) 8222 { 8223 Dsymbol s = (*members)[i]; 8224 s.setScope(sc2); 8225 } 8226 8227 for (size_t i = 0; i < members.dim; i++) 8228 { 8229 Dsymbol s = (*members)[i]; 8230 s.importAll(sc2); 8231 } 8232 8233 for (size_t i = 0; i < members.dim; i++) 8234 { 8235 Dsymbol s = (*members)[i]; 8236 //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s.toChars(), s, s.kind(), this.toChars()); 8237 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars()); 8238 //if (enclosing) 8239 // s.parent = sc.parent; 8240 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars()); 8241 s.semantic(sc2); 8242 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars()); 8243 Module.runDeferredSemantic(); 8244 } 8245 } 8246 8247 final void tryExpandMembers(Scope* sc2) 8248 { 8249 static __gshared int nest; 8250 // extracted to a function to allow windows SEH to work without destructors in the same function 8251 //printf("%d\n", nest); 8252 if (++nest > 500) 8253 { 8254 global.gag = 0; // ensure error message gets printed 8255 error("recursive expansion"); 8256 fatal(); 8257 } 8258 8259 expandMembers(sc2); 8260 8261 nest--; 8262 } 8263 8264 final void trySemantic3(Scope* sc2) 8265 { 8266 // extracted to a function to allow windows SEH to work without destructors in the same function 8267 static __gshared int nest; 8268 //printf("%d\n", nest); 8269 if (++nest > 300) 8270 { 8271 global.gag = 0; // ensure error message gets printed 8272 error("recursive expansion"); 8273 fatal(); 8274 } 8275 8276 semantic3(sc2); 8277 8278 --nest; 8279 } 8280 8281 override final inout(TemplateInstance) isTemplateInstance() inout 8282 { 8283 return this; 8284 } 8285 8286 override void accept(Visitor v) 8287 { 8288 v.visit(this); 8289 } 8290 } 8291 8292 /************************************** 8293 * IsExpression can evaluate the specified type speculatively, and even if 8294 * it instantiates any symbols, they are normally unnecessary for the 8295 * final executable. 8296 * However, if those symbols leak to the actual code, compiler should remark 8297 * them as non-speculative to generate their code and link to the final executable. 8298 */ 8299 void unSpeculative(Scope* sc, RootObject o) 8300 { 8301 if (!o) 8302 return; 8303 8304 if (Tuple tup = isTuple(o)) 8305 { 8306 for (size_t i = 0; i < tup.objects.dim; i++) 8307 { 8308 unSpeculative(sc, tup.objects[i]); 8309 } 8310 return; 8311 } 8312 8313 Dsymbol s = getDsymbol(o); 8314 if (!s) 8315 return; 8316 8317 Declaration d = s.isDeclaration(); 8318 if (d) 8319 { 8320 if (VarDeclaration vd = d.isVarDeclaration()) 8321 o = vd.type; 8322 else if (AliasDeclaration ad = d.isAliasDeclaration()) 8323 { 8324 o = ad.getType(); 8325 if (!o) 8326 o = ad.toAlias(); 8327 } 8328 else 8329 o = d.toAlias(); 8330 8331 s = getDsymbol(o); 8332 if (!s) 8333 return; 8334 } 8335 8336 if (TemplateInstance ti = s.isTemplateInstance()) 8337 { 8338 // If the instance is already non-speculative, 8339 // or it is leaked to the speculative scope. 8340 if (ti.minst !is null || sc.minst is null) 8341 return; 8342 8343 // Remark as non-speculative instance. 8344 ti.minst = sc.minst; 8345 if (!ti.tinst) 8346 ti.tinst = sc.tinst; 8347 8348 unSpeculative(sc, ti.tempdecl); 8349 } 8350 8351 if (TemplateInstance ti = s.isInstantiated()) 8352 unSpeculative(sc, ti); 8353 } 8354 8355 /********************************** 8356 * Return true if e could be valid only as a template value parameter. 8357 * Return false if it might be an alias or tuple. 8358 * (Note that even in this case, it could still turn out to be a value). 8359 */ 8360 bool definitelyValueParameter(Expression e) 8361 { 8362 // None of these can be value parameters 8363 if (e.op == TOKtuple || e.op == TOKscope || 8364 e.op == TOKtype || e.op == TOKdottype || 8365 e.op == TOKtemplate || e.op == TOKdottd || 8366 e.op == TOKfunction || e.op == TOKerror || 8367 e.op == TOKthis || e.op == TOKsuper) 8368 return false; 8369 8370 if (e.op != TOKdotvar) 8371 return true; 8372 8373 /* Template instantiations involving a DotVar expression are difficult. 8374 * In most cases, they should be treated as a value parameter, and interpreted. 8375 * But they might also just be a fully qualified name, which should be treated 8376 * as an alias. 8377 */ 8378 8379 // x.y.f cannot be a value 8380 FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration(); 8381 if (f) 8382 return false; 8383 8384 while (e.op == TOKdotvar) 8385 { 8386 e = (cast(DotVarExp)e).e1; 8387 } 8388 // this.x.y and super.x.y couldn't possibly be valid values. 8389 if (e.op == TOKthis || e.op == TOKsuper) 8390 return false; 8391 8392 // e.type.x could be an alias 8393 if (e.op == TOKdottype) 8394 return false; 8395 8396 // var.x.y is the only other possible form of alias 8397 if (e.op != TOKvar) 8398 return true; 8399 8400 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); 8401 // func.x.y is not an alias 8402 if (!v) 8403 return true; 8404 8405 // TODO: Should we force CTFE if it is a global constant? 8406 return false; 8407 } 8408 8409 /*********************************************************** 8410 */ 8411 extern (C++) final class TemplateMixin : TemplateInstance 8412 { 8413 TypeQualified tqual; 8414 8415 extern (D) this(Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs) 8416 { 8417 super(loc, 8418 tqual.idents.dim ? cast(Identifier)tqual.idents[tqual.idents.dim - 1] : (cast(TypeIdentifier)tqual).ident, 8419 tiargs ? tiargs : new Objects()); 8420 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : ""); 8421 this.ident = ident; 8422 this.tqual = tqual; 8423 } 8424 8425 override Dsymbol syntaxCopy(Dsymbol s) 8426 { 8427 auto tm = new TemplateMixin(loc, ident, cast(TypeQualified)tqual.syntaxCopy(), tiargs); 8428 return TemplateInstance.syntaxCopy(tm); 8429 } 8430 8431 override void semantic(Scope* sc) 8432 { 8433 static if (LOG) 8434 { 8435 printf("+TemplateMixin.semantic('%s', this=%p)\n", toChars(), this); 8436 fflush(stdout); 8437 } 8438 if (semanticRun != PASSinit) 8439 { 8440 // When a class/struct contains mixin members, and is done over 8441 // because of forward references, never reach here so semanticRun 8442 // has been reset to PASSinit. 8443 static if (LOG) 8444 { 8445 printf("\tsemantic done\n"); 8446 } 8447 return; 8448 } 8449 semanticRun = PASSsemantic; 8450 static if (LOG) 8451 { 8452 printf("\tdo semantic\n"); 8453 } 8454 8455 Scope* scx = null; 8456 if (_scope) 8457 { 8458 sc = _scope; 8459 scx = _scope; // save so we don't make redundant copies 8460 _scope = null; 8461 } 8462 8463 /* Run semantic on each argument, place results in tiargs[], 8464 * then find best match template with tiargs 8465 */ 8466 if (!findTempDecl(sc) || !semanticTiargs(sc) || !findBestMatch(sc, null)) 8467 { 8468 if (semanticRun == PASSinit) // forward reference had occured 8469 { 8470 //printf("forward reference - deferring\n"); 8471 _scope = scx ? scx : sc.copy(); 8472 _scope.setNoFree(); 8473 _scope._module.addDeferredSemantic(this); 8474 return; 8475 } 8476 8477 inst = this; 8478 errors = true; 8479 return; // error recovery 8480 } 8481 8482 auto tempdecl = this.tempdecl.isTemplateDeclaration(); 8483 assert(tempdecl); 8484 8485 if (!ident) 8486 { 8487 /* Assign scope local unique identifier, as same as lambdas. 8488 */ 8489 const(char)* s = "__mixin"; 8490 8491 DsymbolTable symtab; 8492 if (FuncDeclaration func = sc.parent.isFuncDeclaration()) 8493 { 8494 symtab = func.localsymtab; 8495 if (symtab) 8496 { 8497 // Inside template constraint, symtab is not set yet. 8498 goto L1; 8499 } 8500 } 8501 else 8502 { 8503 symtab = sc.parent.isScopeDsymbol().symtab; 8504 L1: 8505 assert(symtab); 8506 ident = Identifier.generateId(s, symtab.len + 1); 8507 symtab.insert(this); 8508 } 8509 } 8510 8511 inst = this; 8512 parent = sc.parent; 8513 8514 /* Detect recursive mixin instantiations. 8515 */ 8516 for (Dsymbol s = parent; s; s = s.parent) 8517 { 8518 //printf("\ts = '%s'\n", s.toChars()); 8519 TemplateMixin tm = s.isTemplateMixin(); 8520 if (!tm || tempdecl != tm.tempdecl) 8521 continue; 8522 8523 /* Different argument list lengths happen with variadic args 8524 */ 8525 if (tiargs.dim != tm.tiargs.dim) 8526 continue; 8527 8528 for (size_t i = 0; i < tiargs.dim; i++) 8529 { 8530 RootObject o = (*tiargs)[i]; 8531 Type ta = isType(o); 8532 Expression ea = isExpression(o); 8533 Dsymbol sa = isDsymbol(o); 8534 RootObject tmo = (*tm.tiargs)[i]; 8535 if (ta) 8536 { 8537 Type tmta = isType(tmo); 8538 if (!tmta) 8539 goto Lcontinue; 8540 if (!ta.equals(tmta)) 8541 goto Lcontinue; 8542 } 8543 else if (ea) 8544 { 8545 Expression tme = isExpression(tmo); 8546 if (!tme || !ea.equals(tme)) 8547 goto Lcontinue; 8548 } 8549 else if (sa) 8550 { 8551 Dsymbol tmsa = isDsymbol(tmo); 8552 if (sa != tmsa) 8553 goto Lcontinue; 8554 } 8555 else 8556 assert(0); 8557 } 8558 error("recursive mixin instantiation"); 8559 return; 8560 8561 Lcontinue: 8562 continue; 8563 } 8564 8565 // Copy the syntax trees from the TemplateDeclaration 8566 members = Dsymbol.arraySyntaxCopy(tempdecl.members); 8567 if (!members) 8568 return; 8569 8570 symtab = new DsymbolTable(); 8571 8572 for (Scope* sce = sc; 1; sce = sce.enclosing) 8573 { 8574 ScopeDsymbol sds = sce.scopesym; 8575 if (sds) 8576 { 8577 sds.importScope(this, Prot(PROTpublic)); 8578 break; 8579 } 8580 } 8581 8582 static if (LOG) 8583 { 8584 printf("\tcreate scope for template parameters '%s'\n", toChars()); 8585 } 8586 Scope* scy = sc.push(this); 8587 scy.parent = this; 8588 8589 argsym = new ScopeDsymbol(); 8590 argsym.parent = scy.parent; 8591 Scope* argscope = scy.push(argsym); 8592 8593 uint errorsave = global.errors; 8594 8595 // Declare each template parameter as an alias for the argument type 8596 declareParameters(argscope); 8597 8598 // Add members to enclosing scope, as well as this scope 8599 for (size_t i = 0; i < members.dim; i++) 8600 { 8601 Dsymbol s = (*members)[i]; 8602 s.addMember(argscope, this); 8603 //printf("sc.parent = %p, sc.scopesym = %p\n", sc.parent, sc.scopesym); 8604 //printf("s.parent = %s\n", s.parent.toChars()); 8605 } 8606 8607 // Do semantic() analysis on template instance members 8608 static if (LOG) 8609 { 8610 printf("\tdo semantic() on template instance members '%s'\n", toChars()); 8611 } 8612 Scope* sc2 = argscope.push(this); 8613 //size_t deferred_dim = Module.deferred.dim; 8614 8615 static __gshared int nest; 8616 //printf("%d\n", nest); 8617 if (++nest > 500) 8618 { 8619 global.gag = 0; // ensure error message gets printed 8620 error("recursive expansion"); 8621 fatal(); 8622 } 8623 8624 for (size_t i = 0; i < members.dim; i++) 8625 { 8626 Dsymbol s = (*members)[i]; 8627 s.setScope(sc2); 8628 } 8629 8630 for (size_t i = 0; i < members.dim; i++) 8631 { 8632 Dsymbol s = (*members)[i]; 8633 s.importAll(sc2); 8634 } 8635 8636 for (size_t i = 0; i < members.dim; i++) 8637 { 8638 Dsymbol s = (*members)[i]; 8639 s.semantic(sc2); 8640 } 8641 8642 nest--; 8643 8644 /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols. 8645 * Because the members would already call Module.addDeferredSemantic() for themselves. 8646 * See Struct, Class, Interface, and EnumDeclaration.semantic(). 8647 */ 8648 //if (!sc.func && Module.deferred.dim > deferred_dim) {} 8649 8650 AggregateDeclaration ad = toParent().isAggregateDeclaration(); 8651 if (sc.func && !ad) 8652 { 8653 semantic2(sc2); 8654 semantic3(sc2); 8655 } 8656 8657 // Give additional context info if error occurred during instantiation 8658 if (global.errors != errorsave) 8659 { 8660 error("error instantiating"); 8661 errors = true; 8662 } 8663 8664 sc2.pop(); 8665 argscope.pop(); 8666 scy.pop(); 8667 8668 static if (LOG) 8669 { 8670 printf("-TemplateMixin.semantic('%s', this=%p)\n", toChars(), this); 8671 } 8672 } 8673 8674 override void semantic2(Scope* sc) 8675 { 8676 if (semanticRun >= PASSsemantic2) 8677 return; 8678 semanticRun = PASSsemantic2; 8679 static if (LOG) 8680 { 8681 printf("+TemplateMixin.semantic2('%s')\n", toChars()); 8682 } 8683 if (members) 8684 { 8685 assert(sc); 8686 sc = sc.push(argsym); 8687 sc = sc.push(this); 8688 for (size_t i = 0; i < members.dim; i++) 8689 { 8690 Dsymbol s = (*members)[i]; 8691 static if (LOG) 8692 { 8693 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); 8694 } 8695 s.semantic2(sc); 8696 } 8697 sc = sc.pop(); 8698 sc.pop(); 8699 } 8700 static if (LOG) 8701 { 8702 printf("-TemplateMixin.semantic2('%s')\n", toChars()); 8703 } 8704 } 8705 8706 override void semantic3(Scope* sc) 8707 { 8708 if (semanticRun >= PASSsemantic3) 8709 return; 8710 semanticRun = PASSsemantic3; 8711 static if (LOG) 8712 { 8713 printf("TemplateMixin.semantic3('%s')\n", toChars()); 8714 } 8715 if (members) 8716 { 8717 sc = sc.push(argsym); 8718 sc = sc.push(this); 8719 for (size_t i = 0; i < members.dim; i++) 8720 { 8721 Dsymbol s = (*members)[i]; 8722 s.semantic3(sc); 8723 } 8724 sc = sc.pop(); 8725 sc.pop(); 8726 } 8727 } 8728 8729 override const(char)* kind() const 8730 { 8731 return "mixin"; 8732 } 8733 8734 override bool oneMember(Dsymbol* ps, Identifier ident) 8735 { 8736 return Dsymbol.oneMember(ps, ident); 8737 } 8738 8739 override int apply(Dsymbol_apply_ft_t fp, void* param) 8740 { 8741 if (_scope) // if fwd reference 8742 semantic(null); // try to resolve it 8743 if (members) 8744 { 8745 for (size_t i = 0; i < members.dim; i++) 8746 { 8747 Dsymbol s = (*members)[i]; 8748 if (s) 8749 { 8750 if (s.apply(fp, param)) 8751 return 1; 8752 } 8753 } 8754 } 8755 return 0; 8756 } 8757 8758 override bool hasPointers() 8759 { 8760 //printf("TemplateMixin.hasPointers() %s\n", toChars()); 8761 if (members) 8762 { 8763 for (size_t i = 0; i < members.dim; i++) 8764 { 8765 Dsymbol s = (*members)[i]; 8766 //printf(" s = %s %s\n", s.kind(), s.toChars()); 8767 if (s.hasPointers()) 8768 { 8769 return true; 8770 } 8771 } 8772 } 8773 return false; 8774 } 8775 8776 override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion) 8777 { 8778 //printf("TemplateMixin.setFieldOffset() %s\n", toChars()); 8779 if (_scope) // if fwd reference 8780 semantic(null); // try to resolve it 8781 if (members) 8782 { 8783 for (size_t i = 0; i < members.dim; i++) 8784 { 8785 Dsymbol s = (*members)[i]; 8786 //printf("\t%s\n", s.toChars()); 8787 s.setFieldOffset(ad, poffset, isunion); 8788 } 8789 } 8790 } 8791 8792 override const(char)* toChars() 8793 { 8794 OutBuffer buf; 8795 toCBufferInstance(this, &buf); 8796 return buf.extractString(); 8797 } 8798 8799 bool findTempDecl(Scope* sc) 8800 { 8801 // Follow qualifications to find the TemplateDeclaration 8802 if (!tempdecl) 8803 { 8804 Expression e; 8805 Type t; 8806 Dsymbol s; 8807 tqual.resolve(loc, sc, &e, &t, &s); 8808 if (!s) 8809 { 8810 error("is not defined"); 8811 return false; 8812 } 8813 s = s.toAlias(); 8814 tempdecl = s.isTemplateDeclaration(); 8815 OverloadSet os = s.isOverloadSet(); 8816 8817 /* If an OverloadSet, look for a unique member that is a template declaration 8818 */ 8819 if (os) 8820 { 8821 Dsymbol ds = null; 8822 for (size_t i = 0; i < os.a.dim; i++) 8823 { 8824 Dsymbol s2 = os.a[i].isTemplateDeclaration(); 8825 if (s2) 8826 { 8827 if (ds) 8828 { 8829 tempdecl = os; 8830 break; 8831 } 8832 ds = s2; 8833 } 8834 } 8835 } 8836 if (!tempdecl) 8837 { 8838 error("%s isn't a template", s.toChars()); 8839 return false; 8840 } 8841 } 8842 assert(tempdecl); 8843 8844 // Look for forward references 8845 auto tovers = tempdecl.isOverloadSet(); 8846 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) 8847 { 8848 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl; 8849 int r = overloadApply(dstart, (Dsymbol s) 8850 { 8851 auto td = s.isTemplateDeclaration(); 8852 if (!td) 8853 return 0; 8854 8855 if (td.semanticRun == PASSinit) 8856 { 8857 if (td._scope) 8858 td.semantic(td._scope); 8859 else 8860 { 8861 semanticRun = PASSinit; 8862 return 1; 8863 } 8864 } 8865 return 0; 8866 }); 8867 if (r) 8868 return false; 8869 } 8870 return true; 8871 } 8872 8873 override inout(TemplateMixin) isTemplateMixin() inout 8874 { 8875 return this; 8876 } 8877 8878 override void accept(Visitor v) 8879 { 8880 v.visit(this); 8881 } 8882 } 8883 8884 /************************************ 8885 * This struct is needed for TemplateInstance to be the key in an associative array. 8886 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and 8887 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary. 8888 */ 8889 struct TemplateInstanceBox 8890 { 8891 TemplateInstance ti; 8892 8893 this(TemplateInstance ti) 8894 { 8895 this.ti = ti; 8896 this.ti.toHash(); 8897 assert(this.ti.hash); 8898 } 8899 8900 size_t toHash() const @trusted pure nothrow 8901 { 8902 assert(ti.hash); 8903 return ti.hash; 8904 } 8905 8906 bool opEquals(ref const TemplateInstanceBox s) @trusted const 8907 { 8908 if (ti.inst && s.ti.inst) 8909 /* This clause is only used when an instance with errors 8910 * is replaced with a correct instance. 8911 */ 8912 return ti is s.ti; 8913 else 8914 /* Used when a proposed instance is used to see if there's 8915 * an existing instance. 8916 */ 8917 return (cast()s.ti).compare(cast()ti) == 0; 8918 } 8919 }