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