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