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