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