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