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