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