d: Merge upstream dmd 4d1bfcf14, druntime 9ba9a6ae, phobos c0cc5e917.
[official-gcc.git] / gcc / d / dmd / dtemplate.d
blobfb41e2bd05f5c4e224d6f4c118862d18ab5e579a
1 /**
2 * Defines `TemplateDeclaration`, `TemplateInstance` and a few utilities
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.
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`
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`.
31 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
32 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
33 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
34 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d)
35 * Documentation: https://dlang.org/phobos/dmd_dtemplate.html
36 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d
39 module dmd.dtemplate;
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.common.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;
78 import dmd.templateparamsem;
80 //debug = FindExistingInstance; // print debug stats of findExistingInstance
81 private enum LOG = false;
83 enum IDX_NOTFOUND = 0x12345678;
85 pure nothrow @nogc
88 /********************************************
89 * These functions substitute for dynamic_cast. dynamic_cast does not work
90 * on earlier versions of gcc.
92 extern (C++) inout(Expression) isExpression(inout RootObject o)
94 //return dynamic_cast<Expression *>(o);
95 if (!o || o.dyncast() != DYNCAST.expression)
96 return null;
97 return cast(inout(Expression))o;
100 extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o)
102 //return dynamic_cast<Dsymbol *>(o);
103 if (!o || o.dyncast() != DYNCAST.dsymbol)
104 return null;
105 return cast(inout(Dsymbol))o;
108 extern (C++) inout(Type) isType(inout RootObject o)
110 //return dynamic_cast<Type *>(o);
111 if (!o || o.dyncast() != DYNCAST.type)
112 return null;
113 return cast(inout(Type))o;
116 extern (C++) inout(Tuple) isTuple(inout RootObject o)
118 //return dynamic_cast<Tuple *>(o);
119 if (!o || o.dyncast() != DYNCAST.tuple)
120 return null;
121 return cast(inout(Tuple))o;
124 extern (C++) inout(Parameter) isParameter(inout RootObject o)
126 //return dynamic_cast<Parameter *>(o);
127 if (!o || o.dyncast() != DYNCAST.parameter)
128 return null;
129 return cast(inout(Parameter))o;
132 extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o)
134 if (!o || o.dyncast() != DYNCAST.templateparameter)
135 return null;
136 return cast(inout(TemplateParameter))o;
139 /**************************************
140 * Is this Object an error?
142 extern (C++) bool isError(const RootObject o)
144 if (const t = isType(o))
145 return (t.ty == Terror);
146 if (const e = isExpression(o))
147 return (e.op == EXP.error || !e.type || e.type.ty == Terror);
148 if (const v = isTuple(o))
149 return arrayObjectIsError(&v.objects);
150 const s = isDsymbol(o);
151 assert(s);
152 if (s.errors)
153 return true;
154 return s.parent ? isError(s.parent) : false;
157 /**************************************
158 * Are any of the Objects an error?
160 bool arrayObjectIsError(const Objects* args)
162 foreach (const o; *args)
164 if (isError(o))
165 return true;
167 return false;
170 /***********************
171 * Try to get arg as a type.
173 inout(Type) getType(inout RootObject o)
175 inout t = isType(o);
176 if (!t)
178 if (inout e = isExpression(o))
179 return e.type;
181 return t;
186 Dsymbol getDsymbol(RootObject oarg)
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))
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;
204 else
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
215 private Expression getValue(ref Dsymbol s)
217 if (s)
219 if (VarDeclaration v = s.isVarDeclaration())
221 if (v.storage_class & STC.manifest)
222 return v.getConstInitializer();
225 return null;
228 /***********************
229 * Try to get value from manifest constant
231 private Expression getValue(Expression e)
233 if (!e)
234 return null;
235 if (auto ve = e.isVarExp())
237 if (auto v = ve.var.isVarDeclaration())
239 if (v.storage_class & STC.manifest)
241 e = v.getConstInitializer();
245 return e;
248 private Expression getExpression(RootObject o)
250 auto s = isDsymbol(o);
251 return s ? .getValue(s) : .getValue(isExpression(o));
254 /******************************
255 * If o1 matches o2, return true.
256 * Else, return false.
258 private bool match(RootObject o1, RootObject o2)
260 enum log = false;
262 static if (log)
264 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
265 o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
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.
272 /* Manifest constants should be compared by their values,
273 * at least in template arguments.
276 if (auto t1 = isType(o1))
278 auto t2 = isType(o2);
279 if (!t2)
280 goto Lnomatch;
282 static if (log)
284 printf("\tt1 = %s\n", t1.toChars());
285 printf("\tt2 = %s\n", t2.toChars());
287 if (!t1.equals(t2))
288 goto Lnomatch;
290 goto Lmatch;
292 if (auto e1 = getExpression(o1))
294 auto e2 = getExpression(o2);
295 if (!e2)
296 goto Lnomatch;
298 static if (log)
300 printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars());
301 printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars());
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;
311 goto Lmatch;
313 if (auto s1 = isDsymbol(o1))
315 auto s2 = isDsymbol(o2);
316 if (!s2)
317 goto Lnomatch;
319 static if (log)
321 printf("\ts1 = %s \n", s1.kind(), s1.toChars());
322 printf("\ts2 = %s \n", s2.kind(), s2.toChars());
324 if (!s1.equals(s2))
325 goto Lnomatch;
326 if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
327 goto Lnomatch;
329 goto Lmatch;
331 if (auto u1 = isTuple(o1))
333 auto u2 = isTuple(o2);
334 if (!u2)
335 goto Lnomatch;
337 static if (log)
339 printf("\tu1 = %s\n", u1.toChars());
340 printf("\tu2 = %s\n", u2.toChars());
342 if (!arrayObjectMatch(&u1.objects, &u2.objects))
343 goto Lnomatch;
345 goto Lmatch;
347 Lmatch:
348 static if (log)
349 printf("\t. match\n");
350 return true;
352 Lnomatch:
353 static if (log)
354 printf("\t. nomatch\n");
355 return false;
358 /************************************
359 * Match an array of them.
361 private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
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)
372 RootObject o1 = oa1d[j];
373 RootObject o2 = oa2d[j];
374 if (!match(o1, o2))
376 return false;
379 return true;
382 /************************************
383 * Return hash of Objects.
385 private size_t arrayObjectHash(Objects* oa1)
387 import dmd.root.hash : mixHash;
389 size_t hash = 0;
390 foreach (o1; *oa1)
392 /* Must follow the logic of match()
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))
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));
405 else if (auto u1 = isTuple(o1))
406 hash = mixHash(hash, arrayObjectHash(&u1.objects));
408 return hash;
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).
417 private size_t expressionHash(Expression e)
419 import dmd.root.ctfloat : CTFloat;
420 import dmd.root.hash : calcHash, mixHash;
422 switch (e.op)
424 case EXP.int64:
425 return cast(size_t) e.isIntegerExp().getInteger();
427 case EXP.float64:
428 return CTFloat.hash(e.isRealExp().value);
430 case EXP.complex80:
431 auto ce = e.isComplexExp();
432 return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary));
434 case EXP.identifier:
435 return cast(size_t)cast(void*) e.isIdentifierExp().ident;
437 case EXP.null_:
438 return cast(size_t)cast(void*) e.isNullExp().type;
440 case EXP.string_:
441 return calcHash(e.isStringExp.peekData());
443 case EXP.tuple:
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;
453 case EXP.arrayLiteral:
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;
462 case EXP.assocArrayLiteral:
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;
472 case EXP.structLiteral:
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;
481 case EXP.variable:
482 return cast(size_t)cast(void*) e.isVarExp().var;
484 case EXP.function_:
485 return cast(size_t)cast(void*) e.isFuncExp().fd;
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;
495 RootObject objectSyntaxCopy(RootObject o)
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;
506 extern (C++) final class Tuple : RootObject
508 Objects objects;
510 extern (D) this() {}
513 Params:
514 numObjects = The initial number of objects.
516 extern (D) this(size_t numObjects)
518 objects.setDim(numObjects);
521 // kludge for template.isType()
522 override DYNCAST dyncast() const
524 return DYNCAST.tuple;
527 override const(char)* toChars() const
529 return objects.toChars();
533 struct TemplatePrevious
535 TemplatePrevious* prev;
536 Scope* sc;
537 Objects* dedargs;
540 /***********************************************************
541 * [mixin] template Identifier (parameters) [Constraint]
542 * https://dlang.org/spec/template.html
543 * https://dlang.org/spec/template-mixin.html
545 extern (C++) final class TemplateDeclaration : ScopeDsymbol
547 import dmd.root.array : Array;
549 TemplateParameters* parameters; // array of TemplateParameter's
550 TemplateParameters* origParameters; // originals for Ddoc
552 Expression constraint;
554 // Hash table to look up TemplateInstance's of this TemplateDeclaration
555 TemplateInstance[TemplateInstanceBox] instances;
557 TemplateDeclaration overnext; // next overloaded TemplateDeclaration
558 TemplateDeclaration overroot; // first in overnext list
559 FuncDeclaration funcroot; // first function in unified overload list
561 Dsymbol onemember; // if !=null then one member of this template
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
572 // threaded list of previous instantiation attempts on stack
573 TemplatePrevious* previous;
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`
579 extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
581 super(loc, ident);
582 static if (LOG)
584 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident.toChars());
586 version (none)
588 if (parameters)
589 for (int i = 0; i < parameters.dim; i++)
591 TemplateParameter tp = (*parameters)[i];
592 //printf("\tparameter[%d] = %p\n", i, tp);
593 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
594 if (ttp)
596 printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
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);
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;
614 Dsymbol s;
615 if (!Dsymbol.oneMembers(members, &s, ident) || !s)
616 return;
618 onemember = s;
619 s.parent = this;
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); }
626 if (!(parameters && parameters.length == 1))
627 return;
629 auto ad = s.isAliasDeclaration();
630 if (!ad || !ad.type)
631 return;
633 auto ti = ad.type.isTypeIdentifier();
635 if (!ti || ti.idents.length != 0)
636 return;
638 if (auto ttp = (*parameters)[0].isTemplateTupleParameter())
640 if (ti.ident is ttp.ident &&
641 ti.mod == 0)
643 //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
644 isTrivialAliasSeq = true;
647 else if (auto ttp = (*parameters)[0].isTemplateTypeParameter())
649 if (ti.ident is ttp.ident)
651 //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
652 isTrivialAlias = true;
657 override TemplateDeclaration syntaxCopy(Dsymbol)
659 //printf("TemplateDeclaration.syntaxCopy()\n");
660 TemplateParameters* p = null;
661 if (parameters)
663 p = new TemplateParameters(parameters.dim);
664 foreach (i, ref param; *p)
665 param = (*parameters)[i].syntaxCopy();
667 return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal);
670 /**********************************
671 * Overload existing TemplateDeclaration 'this' with the new one 's'.
672 * Return true if successful; i.e. no conflict.
674 override bool overloadInsert(Dsymbol s)
676 static if (LOG)
678 printf("TemplateDeclaration.overloadInsert('%s')\n", s.toChars());
680 FuncDeclaration fd = s.isFuncDeclaration();
681 if (fd)
683 if (funcroot)
684 return funcroot.overloadInsert(fd);
685 funcroot = fd;
686 return funcroot.overloadInsert(this);
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())
694 if (s._scope)
695 aliasSemantic(ad, s._scope);
696 if (ad.aliassym && ad.aliassym is this)
697 return false;
699 TemplateDeclaration td = s.toAlias().isTemplateDeclaration();
700 if (!td)
701 return false;
703 TemplateDeclaration pthis = this;
704 TemplateDeclaration* ptd;
705 for (ptd = &pthis; *ptd; ptd = &(*ptd).overnext)
709 td.overroot = this;
710 *ptd = td;
711 static if (LOG)
713 printf("\ttrue: no conflict\n");
715 return true;
718 override bool hasStaticCtorOrDtor()
720 return false; // don't scan uninstantiated templates
723 override const(char)* kind() const
725 return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template";
728 override const(char)* toChars() const
730 return toCharsMaybeConstraints(true);
733 /****************************
734 * Similar to `toChars`, but does not print the template constraints
736 const(char)* toCharsNoConstraints() const
738 return toCharsMaybeConstraints(false);
741 const(char)* toCharsMaybeConstraints(bool includeConstraints) const
743 if (literal)
744 return Dsymbol.toChars();
746 OutBuffer buf;
747 HdrGenState hgs;
749 buf.writestring(ident.toString());
750 buf.writeByte('(');
751 foreach (i, const tp; *parameters)
753 if (i)
754 buf.writestring(", ");
755 .toCBuffer(tp, &buf, &hgs);
757 buf.writeByte(')');
759 if (onemember)
761 const FuncDeclaration fd = onemember.isFuncDeclaration();
762 if (fd && fd.type)
764 TypeFunction tf = cast(TypeFunction)fd.type;
765 buf.writestring(parametersTypeToChars(tf.parameterList));
769 if (includeConstraints &&
770 constraint)
772 buf.writestring(" if (");
773 .toCBuffer(constraint, &buf, &hgs);
774 buf.writeByte(')');
777 return buf.extractChars();
780 override Visibility visible() pure nothrow @nogc @safe
782 return visibility;
785 /****************************
786 * Check to see if constraint is satisfied.
788 extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
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.
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.
803 for (TemplatePrevious* p = previous; p; p = p.prev)
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
814 for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
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;
821 /* BUG: should also check for ref param differences
825 TemplatePrevious pr;
826 pr.prev = previous;
827 pr.sc = paramscope.callsc;
828 pr.dedargs = dedargs;
829 previous = &pr; // add this to threaded list
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;
841 assert(!ti.symtab);
842 if (fd)
844 /* Declare all the function parameters as variables and add them to the scope
845 * Making parameters is similar to FuncDeclaration.semantic3
847 auto tf = fd.type.isTypeFunction();
849 scx.parent = fd;
851 Parameters* fparameters = tf.parameterList.parameters;
852 const nfparams = tf.parameterList.length;
853 foreach (i, fparam; tf.parameterList)
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)
859 fparam.storageClass |= STC.variadic;
860 /* Don't need to set STC.scope_ because this will only
861 * be evaluated at compile time
865 foreach (fparam; *fparameters)
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;
881 if (isstatic)
882 fd.storage_class |= STC.static_;
883 fd.declareThis(scx);
886 lastConstraint = constraint.syntaxCopy();
887 lastConstraintTiargs = ti.tiargs;
888 lastConstraintNegs.setDim(0);
890 import dmd.staticcond;
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)
898 lastConstraint = null;
899 lastConstraintTiargs = null;
900 lastConstraintNegs.setDim(0);
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;
911 /****************************
912 * Destructively get the error message from the last constraint evaluation
913 * Params:
914 * tip = tip to show after printing all overloads
916 const(char)* getConstraintEvalError(ref const(char)* tip)
918 import dmd.staticcond;
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)
926 lastConstraint = null;
927 lastConstraintTiargs = null;
928 lastConstraintNegs.setDim(0);
930 if (!msg)
931 return null;
933 OutBuffer buf;
935 assert(parameters && lastConstraintTiargs);
936 if (parameters.length > 0)
938 formatParamsWithTiargs(*lastConstraintTiargs, buf);
939 buf.writenl();
941 if (!full)
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('`');
954 else
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 `>`";
968 return buf.extractChars();
971 private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf)
973 buf.writestring(" with `");
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++)
982 if (i > 0)
984 buf.writeByte(',');
985 buf.writenl();
986 buf.writestring(" ");
988 write(buf, (*parameters)[i]);
989 buf.writestring(" = ");
990 write(buf, tiargs[i]);
992 // write remaining variadic arguments on the last line
993 if (variadic)
995 if (i > 0)
997 buf.writeByte(',');
998 buf.writenl();
999 buf.writestring(" ");
1001 write(buf, (*parameters)[end]);
1002 buf.writestring(" = ");
1003 buf.writeByte('(');
1004 if (cast(int)tiargs.length - end > 0)
1006 write(buf, tiargs[end]);
1007 foreach (j; parameters.length .. tiargs.length)
1009 buf.writestring(", ");
1010 write(buf, tiargs[j]);
1013 buf.writeByte(')');
1015 buf.writeByte('`');
1018 /******************************
1019 * Create a scope for the parameters of the TemplateInstance
1020 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
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
1030 Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc)
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;
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.
1053 extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag)
1055 enum LOGM = 0;
1056 static if (LOGM)
1058 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag);
1060 version (none)
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]);
1066 MATCH nomatch()
1068 static if (LOGM)
1070 printf(" no match\n");
1072 return MATCH.nomatch;
1074 MATCH m;
1075 size_t dedtypes_dim = dedtypes.dim;
1077 dedtypes.zero();
1079 if (errors)
1080 return MATCH.nomatch;
1082 size_t parameters_dim = parameters.dim;
1083 int variadic = isVariadic() !is null;
1085 // If more arguments than parameters, no match
1086 if (ti.tiargs.dim > parameters_dim && !variadic)
1088 static if (LOGM)
1090 printf(" no match: more arguments than parameters\n");
1092 return MATCH.nomatch;
1095 assert(dedtypes_dim == parameters_dim);
1096 assert(dedtypes_dim >= ti.tiargs.dim || variadic);
1098 assert(_scope);
1100 // Set up scope for template parameters
1101 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1103 // Attempt type deduction
1104 m = MATCH.exact;
1105 for (size_t i = 0; i < dedtypes_dim; i++)
1107 MATCH m2;
1108 TemplateParameter tp = (*parameters)[i];
1109 Declaration sparam;
1111 //printf("\targument [%d]\n", i);
1112 static if (LOGM)
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() : "");
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)
1126 version (none)
1128 printf("\tmatchArg() for parameter %i failed\n", i);
1130 return nomatch();
1133 if (m2 < m)
1134 m = m2;
1136 if (!flag)
1137 sparam.dsymbolSemantic(paramscope);
1138 if (!paramscope.insert(sparam)) // TODO: This check can make more early
1140 // in TemplateDeclaration.semantic, and
1141 // then we don't need to make sparam if flags == 0
1142 return nomatch();
1146 if (!flag)
1148 /* Any parameter left without a type gets the type of
1149 * its corresponding arg
1151 foreach (i, ref dedtype; *dedtypes)
1153 if (!dedtype)
1155 assert(i < ti.tiargs.dim);
1156 dedtype = cast(Type)(*ti.tiargs)[i];
1161 if (m > MATCH.nomatch && constraint && !flag)
1163 if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error
1164 ti.parent = ti.enclosing;
1165 else
1166 ti.parent = this.parent;
1168 // Similar to doHeaderInstantiation
1169 FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null;
1170 if (fd)
1172 TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
1174 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
1175 fd.parent = ti;
1176 fd.flags |= FUNCFLAG.inferRetType;
1178 // Shouldn't run semantic on default arguments and return type.
1179 foreach (ref param; *tf.parameterList.parameters)
1180 param.defaultArg = null;
1182 tf.next = null;
1183 tf.incomplete = true;
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
1195 // TODO: dedtypes => ti.tiargs ?
1196 if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
1197 return nomatch();
1200 static if (LOGM)
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)
1208 for (size_t i = 0; i < dedtypes_dim; i++)
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]);
1220 else
1221 return nomatch();
1223 static if (LOGM)
1225 printf(" match = %d\n", m);
1228 paramscope.pop();
1229 static if (LOGM)
1231 printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
1233 return m;
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
1242 MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs)
1244 enum LOG_LEASTAS = 0;
1245 static if (LOG_LEASTAS)
1247 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
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.
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)
1263 if (tp.dependent)
1264 break;
1265 RootObject p = tp.dummyArg();
1266 if (!p) //TemplateTupleParameter
1267 break;
1269 tiargs.push(p);
1271 scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance
1273 // Temporary Array to hold deduced types
1274 Objects dedtypes = Objects(td2.parameters.dim);
1276 // Attempt a type deduction
1277 MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1);
1278 if (m > MATCH.nomatch)
1280 /* A non-variadic template is more specialized than a
1281 * variadic one.
1283 TemplateTupleParameter tp = isVariadic();
1284 if (tp && !tp.dependent && !td2.isVariadic())
1285 goto L1;
1287 static if (LOG_LEASTAS)
1289 printf(" matches %d, so is least as specialized\n", m);
1291 return m;
1294 static if (LOG_LEASTAS)
1296 printf(" doesn't match, so is not as specialized\n");
1298 return MATCH.nomatch;
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
1315 extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs)
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;
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
1333 version (none)
1335 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
1336 for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++)
1338 Expression e = (*fargs)[i];
1339 printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars());
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());
1347 assert(_scope);
1349 dedargs.setDim(parameters.dim);
1350 dedargs.zero();
1352 dedtypes.setDim(parameters.dim);
1353 dedtypes.zero();
1355 if (errors || fd.errors)
1356 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1358 // Set up scope for parameters
1359 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1361 MATCHpair nomatch()
1363 paramscope.pop();
1364 //printf("\tnomatch\n");
1365 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1368 MATCHpair matcherror()
1370 // todo: for the future improvement
1371 paramscope.pop();
1372 //printf("\terror\n");
1373 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
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_;
1380 TemplateTupleParameter tp = isVariadic();
1381 Tuple declaredTuple = null;
1383 version (none)
1385 for (size_t i = 0; i < dedargs.dim; i++)
1387 printf("\tdedarg[%d] = ", i);
1388 RootObject oarg = (*dedargs)[i];
1389 if (oarg)
1390 printf("%s", oarg.toChars());
1391 printf("\n");
1395 ntargs = 0;
1396 if (tiargs)
1398 // Set initial template arguments
1399 ntargs = tiargs.dim;
1400 size_t n = parameters.dim;
1401 if (tp)
1402 n--;
1403 if (ntargs > n)
1405 if (!tp)
1406 return nomatch();
1408 /* The extra initial template arguments
1409 * now form the tuple argument.
1411 auto t = new Tuple(ntargs - n);
1412 assert(parameters.dim);
1413 (*dedargs)[parameters.dim - 1] = t;
1415 for (size_t i = 0; i < t.objects.dim; i++)
1417 t.objects[i] = (*tiargs)[n + i];
1419 declareParameter(paramscope, tp, t);
1420 declaredTuple = t;
1422 else
1423 n = ntargs;
1425 memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
1427 for (size_t i = 0; i < n; i++)
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;
1438 sparam.dsymbolSemantic(paramscope);
1439 if (!paramscope.insert(sparam))
1440 return nomatch();
1442 if (n < parameters.dim && !declaredTuple)
1444 inferStart = n;
1446 else
1447 inferStart = parameters.dim;
1448 //printf("tiargs matchTiargs = %d\n", matchTiargs);
1450 version (none)
1452 for (size_t i = 0; i < dedargs.dim; i++)
1454 printf("\tdedarg[%d] = ", i);
1455 RootObject oarg = (*dedargs)[i];
1456 if (oarg)
1457 printf("%s", oarg.toChars());
1458 printf("\n");
1462 fparameters = fd.getParameterList();
1463 nfparams = fparameters.length; // number of function parameters
1464 nfargs = fargs ? fargs.dim : 0; // number of function arguments
1466 /* Check for match of function arguments with variadic template
1467 * parameter, such as:
1469 * void foo(T, A...)(T t, A a);
1470 * void main() { foo(1,2,3); }
1472 if (tp) // if variadic
1474 // TemplateTupleParameter always makes most lesser matching.
1475 matchTiargs = MATCH.convert;
1477 if (nfparams == 0 && nfargs != 0) // if no function parameters
1479 if (!declaredTuple)
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;
1488 else
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.
1495 for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
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;
1504 if (fparameters.varargs != VarArg.none) // variadic function doesn't
1505 return nomatch(); // go with variadic template
1507 goto L1;
1509 fptupindex = IDX_NOTFOUND;
1514 if (toParent().isModule() || (_scope.stc & STC.static_))
1515 tthis = null;
1516 if (tthis)
1518 bool hasttp = false;
1520 // Match 'tthis' to any TemplateThisParameter's
1521 foreach (param; *parameters)
1523 if (auto ttp = param.isTemplateThisParameter())
1525 hasttp = true;
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
1536 // Match attributes of tthis against attributes of fd
1537 if (fd.type && !fd.isCtorDeclaration())
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;
1548 ubyte mod = fd.type.mod;
1549 if (stc & STC.immutable_)
1550 mod = MODFlags.immutable_;
1551 else
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;
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;
1572 // Loop through the function parameters
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++)
1580 Parameter fparam = fparameters[parami];
1582 // Apply function parameter storage classes to parameter types
1583 Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
1585 Expression farg;
1587 /* See function parameters which wound up
1588 * as part of a template tuple parameter.
1590 if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
1592 assert(prmtype.ty == Tident);
1593 TypeIdentifier tid = cast(TypeIdentifier)prmtype;
1594 if (!declaredTuple)
1596 /* The types of the function arguments
1597 * now form the tuple argument.
1599 declaredTuple = new Tuple();
1600 (*dedargs)[parameters.dim - 1] = declaredTuple;
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)
1605 size_t rem = 0;
1606 for (size_t j = parami + 1; j < nfparams; j++)
1608 Parameter p = fparameters[j];
1609 if (p.defaultArg)
1611 break;
1613 if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.dim]))
1615 Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
1616 rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.dim : 1;
1618 else
1620 ++rem;
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++)
1629 farg = (*fargs)[argi + i];
1631 // Check invalid arguments to detect errors early.
1632 if (farg.op == EXP.error || farg.type.ty == Terror)
1633 return nomatch();
1635 if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid)
1636 return nomatch();
1638 Type tt;
1639 MATCH m;
1640 if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
1642 wildmatch |= wm;
1643 m = MATCH.constant;
1645 else
1647 m = deduceTypeHelper(farg.type, &tt, tid);
1649 if (m == MATCH.nomatch)
1650 return nomatch();
1651 if (m < match)
1652 match = m;
1654 /* Remove top const for dynamic array types and pointer types
1656 if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
1658 tt = tt.mutableOf();
1660 declaredTuple.objects[i] = tt;
1662 declareParameter(paramscope, tp, declaredTuple);
1664 else
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++)
1671 if (!isType(declaredTuple.objects[i]))
1672 return nomatch();
1675 assert(declaredTuple);
1676 argi += declaredTuple.objects.dim;
1677 continue;
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]))
1684 // should copy prmtype to avoid affecting semantic result
1685 prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
1687 if (prmtype.ty == Ttuple)
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)
1693 Parameter p = (*tt.arguments)[j];
1694 if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
1695 parami + 1 == nfparams && argi < nfargs)
1697 prmtype = p.type;
1698 goto Lvarargs;
1700 if (argi >= nfargs)
1702 if (p.defaultArg)
1703 continue;
1705 // https://issues.dlang.org/show_bug.cgi?id=19888
1706 if (fparam.defaultArg)
1707 break;
1709 return nomatch();
1711 farg = (*fargs)[argi];
1712 if (!farg.implicitConvTo(p.type))
1713 return nomatch();
1715 continue;
1719 if (argi >= nfargs) // if not enough arguments
1721 if (!fparam.defaultArg)
1722 goto Lvarargs;
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:
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'
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.
1741 if (argi == nfargs)
1743 foreach (ref dedtype; *dedtypes)
1745 Type at = isType(dedtype);
1746 if (at && at.ty == Tnone)
1748 TypeDeduced xt = cast(TypeDeduced)at;
1749 dedtype = xt.tded; // 'unbox'
1752 for (size_t i = ntargs; i < dedargs.dim; i++)
1754 TemplateParameter tparam = (*parameters)[i];
1756 RootObject oarg = (*dedargs)[i];
1757 RootObject oded = (*dedtypes)[i];
1758 if (oarg)
1759 continue;
1761 if (oded)
1763 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
1765 /* The specialization can work as long as afterwards
1766 * the oded == oarg
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());
1778 else
1780 if (MATCH.convert < matchTiargs)
1781 matchTiargs = MATCH.convert;
1783 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1785 else
1787 inuse++;
1788 oded = tparam.defaultArg(instLoc, paramscope);
1789 inuse--;
1790 if (oded)
1791 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1795 nfargs2 = argi + 1;
1797 /* If prmtype does not depend on any template parameters:
1799 * auto foo(T)(T v, double x = 0);
1800 * foo("str");
1801 * // at fparam == 'double x = 0'
1803 * or, if all template parameters in the prmtype are already deduced:
1805 * auto foo(R)(R range, ElementType!R sum = 0);
1806 * foo([1,2,3]);
1807 * // at fparam == 'ElementType!R sum = 0'
1809 * Deducing prmtype from fparam.defaultArg is not necessary.
1811 if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope))
1813 ++argi;
1814 continue;
1817 // Deduce prmtype from the defaultArg.
1818 farg = fparam.defaultArg.syntaxCopy();
1819 farg = farg.expressionSemantic(paramscope);
1820 farg = resolveProperties(paramscope, farg);
1822 else
1824 farg = (*fargs)[argi];
1827 // Check invalid arguments to detect errors early.
1828 if (farg.op == EXP.error || farg.type.ty == Terror)
1829 return nomatch();
1831 Type att = null;
1832 Lretry:
1833 version (none)
1835 printf("\tfarg.type = %s\n", farg.type.toChars());
1836 printf("\tfparam.type = %s\n", prmtype.toChars());
1838 Type argtype = farg.type;
1840 if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != EXP.function_)
1841 return nomatch();
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());
1848 RootObject oarg = farg;
1849 if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
1851 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
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))
1856 if (farg.op == EXP.string_)
1858 StringExp se = cast(StringExp)farg;
1859 argtype = se.type.nextOf().sarrayOf(se.len);
1861 else if (farg.op == EXP.arrayLiteral)
1863 ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
1864 argtype = ae.type.nextOf().sarrayOf(ae.elements.dim);
1866 else if (farg.op == EXP.slice)
1868 SliceExp se = cast(SliceExp)farg;
1869 if (Type tsa = toStaticArrayType(se))
1870 argtype = tsa;
1874 oarg = argtype;
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)
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.
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[])
1888 Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
1889 if (ta != argtype)
1891 Expression ea = farg.copy();
1892 ea.type = ta;
1893 oarg = ea;
1897 if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
1898 goto Lvarargs;
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;
1905 /* If no match, see if the argument can be matched by using
1906 * implicit conversions.
1908 if (m == MATCH.nomatch && prmtype.deco)
1909 m = farg.implicitConvTo(prmtype);
1911 if (m == MATCH.nomatch)
1913 AggregateDeclaration ad = isAggregate(farg.type);
1914 if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
1916 // https://issues.dlang.org/show_bug.cgi?id=12537
1917 // The isRecursiveAliasThis() call above
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.
1923 * We also save/restore sc.func.flags to avoid messing up
1924 * attribute inference in the evaluation.
1926 const oldflags = sc.func ? sc.func.flags : 0;
1927 auto e = resolveAliasThis(sc, farg, true);
1928 if (sc.func)
1929 sc.func.flags = oldflags;
1930 if (e)
1932 farg = e;
1933 goto Lretry;
1938 if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
1940 if (!farg.isLvalue())
1942 if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
1944 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1946 else if (global.params.rvalueRefParam == FeatureState.enabled)
1948 // Allow implicit conversion to ref
1950 else
1951 return nomatch();
1954 if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
1956 if (!farg.isLvalue())
1957 return nomatch();
1958 if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1959 return nomatch();
1961 if (m == MATCH.nomatch && (fparam.storageClass & STC.lazy_) && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
1962 m = MATCH.convert;
1963 if (m != MATCH.nomatch)
1965 if (m < match)
1966 match = m; // pick worst match
1967 argi++;
1968 continue;
1972 Lvarargs:
1973 /* The following code for variadic arguments closely
1974 * matches TypeFunction.callMatch()
1976 if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
1977 return nomatch();
1979 /* Check for match with function parameter T...
1981 Type tb = prmtype.toBasetype();
1982 switch (tb.ty)
1984 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1985 case Tsarray:
1986 case Taarray:
1988 // Perhaps we can do better with this, see TypeFunction.callMatch()
1989 if (tb.ty == Tsarray)
1991 TypeSArray tsa = cast(TypeSArray)tb;
1992 dinteger_t sz = tsa.dim.toInteger();
1993 if (sz != nfargs - argi)
1994 return nomatch();
1996 else if (tb.ty == Taarray)
1998 TypeAArray taa = cast(TypeAArray)tb;
1999 Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
2001 size_t i = templateParameterLookup(taa.index, parameters);
2002 if (i == IDX_NOTFOUND)
2004 Expression e;
2005 Type t;
2006 Dsymbol s;
2007 Scope *sco;
2009 uint errors = global.startGagging();
2010 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
2011 * The parameter isn't part of the template
2012 * ones, let's try to find it in the
2013 * instantiation scope 'sc' and the one
2014 * belonging to the template itself. */
2015 sco = sc;
2016 taa.index.resolve(instLoc, sco, e, t, s);
2017 if (!e)
2019 sco = paramscope;
2020 taa.index.resolve(instLoc, sco, e, t, s);
2022 global.endGagging(errors);
2024 if (!e)
2025 return nomatch();
2027 e = e.ctfeInterpret();
2028 e = e.implicitCastTo(sco, Type.tsize_t);
2029 e = e.optimize(WANTvalue);
2030 if (!dim.equals(e))
2031 return nomatch();
2033 else
2035 // This code matches code in TypeInstance.deduceType()
2036 TemplateParameter tprm = (*parameters)[i];
2037 TemplateValueParameter tvp = tprm.isTemplateValueParameter();
2038 if (!tvp)
2039 return nomatch();
2040 Expression e = cast(Expression)(*dedtypes)[i];
2041 if (e)
2043 if (!dim.equals(e))
2044 return nomatch();
2046 else
2048 Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
2049 MATCH m = dim.implicitConvTo(vt);
2050 if (m == MATCH.nomatch)
2051 return nomatch();
2052 (*dedtypes)[i] = dim;
2056 goto case Tarray;
2058 case Tarray:
2060 TypeArray ta = cast(TypeArray)tb;
2061 Type tret = fparam.isLazyArray();
2062 for (; argi < nfargs; argi++)
2064 Expression arg = (*fargs)[argi];
2065 assert(arg);
2067 MATCH m;
2068 /* If lazy array of delegates,
2069 * convert arg(s) to delegate(s)
2071 if (tret)
2073 if (ta.next.equals(arg.type))
2075 m = MATCH.exact;
2077 else
2079 m = arg.implicitConvTo(tret);
2080 if (m == MATCH.nomatch)
2082 if (tret.toBasetype().ty == Tvoid)
2083 m = MATCH.convert;
2087 else
2089 uint wm = 0;
2090 m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
2091 wildmatch |= wm;
2093 if (m == MATCH.nomatch)
2094 return nomatch();
2095 if (m < match)
2096 match = m;
2098 goto Lmatch;
2100 case Tclass:
2101 case Tident:
2102 goto Lmatch;
2104 default:
2105 return nomatch();
2107 assert(0);
2109 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
2110 if (argi != nfargs2 && fparameters.varargs == VarArg.none)
2111 return nomatch();
2114 Lmatch:
2115 foreach (ref dedtype; *dedtypes)
2117 Type at = isType(dedtype);
2118 if (at)
2120 if (at.ty == Tnone)
2122 TypeDeduced xt = cast(TypeDeduced)at;
2123 at = xt.tded; // 'unbox'
2125 dedtype = at.merge2();
2128 for (size_t i = ntargs; i < dedargs.dim; i++)
2130 TemplateParameter tparam = (*parameters)[i];
2131 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
2133 /* For T:T*, the dedargs is the T*, dedtypes is the T
2134 * But for function templates, we really need them to match
2136 RootObject oarg = (*dedargs)[i];
2137 RootObject oded = (*dedtypes)[i];
2138 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
2139 //if (oarg) printf("oarg: %s\n", oarg.toChars());
2140 //if (oded) printf("oded: %s\n", oded.toChars());
2141 if (oarg)
2142 continue;
2144 if (oded)
2146 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
2148 /* The specialization can work as long as afterwards
2149 * the oded == oarg
2151 (*dedargs)[i] = oded;
2152 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2153 //printf("m2 = %d\n", m2);
2154 if (m2 == MATCH.nomatch)
2155 return nomatch();
2156 if (m2 < matchTiargs)
2157 matchTiargs = m2; // pick worst match
2158 if (!(*dedtypes)[i].equals(oded))
2159 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
2161 else
2163 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
2164 if (MATCH.convert < matchTiargs)
2165 matchTiargs = MATCH.convert;
2168 else
2170 inuse++;
2171 oded = tparam.defaultArg(instLoc, paramscope);
2172 inuse--;
2173 if (!oded)
2175 // if tuple parameter and
2176 // tuple parameter was not in function parameter list and
2177 // we're one or more arguments short (i.e. no tuple argument)
2178 if (tparam == tp &&
2179 fptupindex == IDX_NOTFOUND &&
2180 ntargs <= dedargs.dim - 1)
2182 // make tuple argument an empty tuple
2183 oded = new Tuple();
2185 else
2186 return nomatch();
2188 if (isError(oded))
2189 return matcherror();
2190 ntargs++;
2192 /* At the template parameter T, the picked default template argument
2193 * X!int should be matched to T in order to deduce dependent
2194 * template parameter A.
2195 * auto foo(T : X!A = X!int, A...)() { ... }
2196 * foo(); // T <-- X!int, A <-- (int)
2198 if (tparam.specialization())
2200 (*dedargs)[i] = oded;
2201 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2202 //printf("m2 = %d\n", m2);
2203 if (m2 == MATCH.nomatch)
2204 return nomatch();
2205 if (m2 < matchTiargs)
2206 matchTiargs = m2; // pick worst match
2207 if (!(*dedtypes)[i].equals(oded))
2208 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
2211 oded = declareParameter(paramscope, tparam, oded);
2212 (*dedargs)[i] = oded;
2215 /* https://issues.dlang.org/show_bug.cgi?id=7469
2216 * As same as the code for 7469 in findBestMatch,
2217 * expand a Tuple in dedargs to normalize template arguments.
2219 if (auto d = dedargs.dim)
2221 if (auto va = isTuple((*dedargs)[d - 1]))
2223 dedargs.setDim(d - 1);
2224 dedargs.insert(d - 1, &va.objects);
2227 ti.tiargs = dedargs; // update to the normalized template arguments.
2229 // Partially instantiate function for constraint and fd.leastAsSpecialized()
2231 assert(paramscope.scopesym);
2232 Scope* sc2 = _scope;
2233 sc2 = sc2.push(paramscope.scopesym);
2234 sc2 = sc2.push(ti);
2235 sc2.parent = ti;
2236 sc2.tinst = ti;
2237 sc2.minst = sc.minst;
2238 sc2.stc |= fd.storage_class & STC.deprecated_;
2240 fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
2242 sc2 = sc2.pop();
2243 sc2 = sc2.pop();
2245 if (!fd)
2246 return nomatch();
2249 if (constraint)
2251 if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
2252 return nomatch();
2255 version (none)
2257 for (size_t i = 0; i < dedargs.dim; i++)
2259 RootObject o = (*dedargs)[i];
2260 printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
2264 paramscope.pop();
2265 //printf("\tmatch %d\n", match);
2266 return MATCHpair(matchTiargs, match);
2269 /**************************************************
2270 * Declare template parameter tp with value o, and install it in the scope sc.
2272 RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o)
2274 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
2275 Type ta = isType(o);
2276 Expression ea = isExpression(o);
2277 Dsymbol sa = isDsymbol(o);
2278 Tuple va = isTuple(o);
2280 Declaration d;
2281 VarDeclaration v = null;
2283 if (ea && ea.op == EXP.type)
2284 ta = ea.type;
2285 else if (ea && ea.op == EXP.scope_)
2286 sa = (cast(ScopeExp)ea).sds;
2287 else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
2288 sa = (cast(ThisExp)ea).var;
2289 else if (ea && ea.op == EXP.function_)
2291 if ((cast(FuncExp)ea).td)
2292 sa = (cast(FuncExp)ea).td;
2293 else
2294 sa = (cast(FuncExp)ea).fd;
2297 if (ta)
2299 //printf("type %s\n", ta.toChars());
2300 auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta);
2301 ad.storage_class |= STC.templateparameter;
2302 d = ad;
2304 else if (sa)
2306 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
2307 auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa);
2308 ad.storage_class |= STC.templateparameter;
2309 d = ad;
2311 else if (ea)
2313 // tdtypes.data[i] always matches ea here
2314 Initializer _init = new ExpInitializer(loc, ea);
2315 TemplateValueParameter tvp = tp.isTemplateValueParameter();
2316 Type t = tvp ? tvp.valType : null;
2317 v = new VarDeclaration(loc, t, tp.ident, _init);
2318 v.storage_class = STC.manifest | STC.templateparameter;
2319 d = v;
2321 else if (va)
2323 //printf("\ttuple\n");
2324 d = new TupleDeclaration(loc, tp.ident, &va.objects);
2326 else
2328 assert(0);
2330 d.storage_class |= STC.templateparameter;
2332 if (ta)
2334 Type t = ta;
2335 // consistent with Type.checkDeprecated()
2336 while (t.ty != Tenum)
2338 if (!t.nextOf())
2339 break;
2340 t = (cast(TypeNext)t).next;
2342 if (Dsymbol s = t.toDsymbol(sc))
2344 if (s.isDeprecated())
2345 d.storage_class |= STC.deprecated_;
2348 else if (sa)
2350 if (sa.isDeprecated())
2351 d.storage_class |= STC.deprecated_;
2354 if (!sc.insert(d))
2355 error("declaration `%s` is already defined", tp.ident.toChars());
2356 d.dsymbolSemantic(sc);
2357 /* So the caller's o gets updated with the result of semantic() being run on o
2359 if (v)
2360 o = v._init.initializerToExpression();
2361 return o;
2364 /*************************************************
2365 * Limited function template instantiation for using fd.leastAsSpecialized()
2367 extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs)
2369 assert(fd);
2370 version (none)
2372 printf("doHeaderInstantiation this = %s\n", toChars());
2375 // function body and contracts are not need
2376 if (fd.isCtorDeclaration())
2377 fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy());
2378 else
2379 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy());
2380 fd.parent = ti;
2382 assert(fd.type.ty == Tfunction);
2383 auto tf = fd.type.isTypeFunction();
2384 tf.fargs = fargs;
2386 if (tthis)
2388 // Match 'tthis' to any TemplateThisParameter's
2389 bool hasttp = false;
2390 foreach (tp; *parameters)
2392 TemplateThisParameter ttp = tp.isTemplateThisParameter();
2393 if (ttp)
2394 hasttp = true;
2396 if (hasttp)
2398 tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
2399 assert(!tf.deco);
2403 Scope* scx = sc2.push();
2405 // Shouldn't run semantic on default arguments and return type.
2406 foreach (ref params; *tf.parameterList.parameters)
2407 params.defaultArg = null;
2408 tf.incomplete = true;
2410 if (fd.isCtorDeclaration())
2412 // For constructors, emitting return type is necessary for
2413 // isReturnIsolated() in functionResolve.
2414 tf.isctor = true;
2416 Dsymbol parent = toParentDecl();
2417 Type tret;
2418 AggregateDeclaration ad = parent.isAggregateDeclaration();
2419 if (!ad || parent.isUnionDeclaration())
2421 tret = Type.tvoid;
2423 else
2425 tret = ad.handleType();
2426 assert(tret);
2427 tret = tret.addStorageClass(fd.storage_class | scx.stc);
2428 tret = tret.addMod(tf.mod);
2430 tf.next = tret;
2431 if (ad && ad.isStructDeclaration())
2432 tf.isref = 1;
2433 //printf("tf = %s\n", tf.toChars());
2435 else
2436 tf.next = null;
2437 fd.type = tf;
2438 fd.type = fd.type.addSTC(scx.stc);
2439 fd.type = fd.type.typeSemantic(fd.loc, scx);
2440 scx = scx.pop();
2442 if (fd.type.ty != Tfunction)
2443 return null;
2445 fd.originalType = fd.type; // for mangling
2446 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
2447 //printf("fd.needThis() = %d\n", fd.needThis());
2449 return fd;
2452 debug (FindExistingInstance)
2454 __gshared uint nFound, nNotFound, nAdded, nRemoved;
2456 shared static ~this()
2458 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
2459 nFound, nNotFound, nAdded, nRemoved);
2463 /****************************************************
2464 * Given a new instance tithis of this TemplateDeclaration,
2465 * see if there already exists an instance.
2466 * If so, return that existing instance.
2468 extern (D) TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs)
2470 //printf("findExistingInstance() %s\n", tithis.toChars());
2471 tithis.fargs = fargs;
2472 auto tibox = TemplateInstanceBox(tithis);
2473 auto p = tibox in instances;
2474 debug (FindExistingInstance) ++(p ? nFound : nNotFound);
2475 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
2476 return p ? *p : null;
2479 /********************************************
2480 * Add instance ti to TemplateDeclaration's table of instances.
2481 * Return a handle we can use to later remove it if it fails instantiation.
2483 extern (D) TemplateInstance addInstance(TemplateInstance ti)
2485 //printf("addInstance() %p %s\n", instances, ti.toChars());
2486 auto tibox = TemplateInstanceBox(ti);
2487 instances[tibox] = ti;
2488 debug (FindExistingInstance) ++nAdded;
2489 return ti;
2492 /*******************************************
2493 * Remove TemplateInstance from table of instances.
2494 * Input:
2495 * handle returned by addInstance()
2497 extern (D) void removeInstance(TemplateInstance ti)
2499 //printf("removeInstance() %s\n", ti.toChars());
2500 auto tibox = TemplateInstanceBox(ti);
2501 debug (FindExistingInstance) ++nRemoved;
2502 instances.remove(tibox);
2505 override inout(TemplateDeclaration) isTemplateDeclaration() inout
2507 return this;
2511 * Check if the last template parameter is a tuple one,
2512 * and returns it if so, else returns `null`.
2514 * Returns:
2515 * The last template parameter if it's a `TemplateTupleParameter`
2517 TemplateTupleParameter isVariadic()
2519 size_t dim = parameters.dim;
2520 if (dim == 0)
2521 return null;
2522 return (*parameters)[dim - 1].isTemplateTupleParameter();
2525 extern(C++) override bool isDeprecated() const
2527 return this.deprecated_;
2530 /***********************************
2531 * We can overload templates.
2533 override bool isOverloadable() const
2535 return true;
2538 override void accept(Visitor v)
2540 v.visit(this);
2544 extern (C++) final class TypeDeduced : Type
2546 Type tded;
2547 Expressions argexps; // corresponding expressions
2548 Types tparams; // tparams[i].mod
2550 extern (D) this(Type tt, Expression e, Type tparam)
2552 super(Tnone);
2553 tded = tt;
2554 argexps.push(e);
2555 tparams.push(tparam);
2558 void update(Expression e, Type tparam)
2560 argexps.push(e);
2561 tparams.push(tparam);
2564 void update(Type tt, Expression e, Type tparam)
2566 tded = tt;
2567 argexps.push(e);
2568 tparams.push(tparam);
2571 MATCH matchAll(Type tt)
2573 MATCH match = MATCH.exact;
2574 foreach (j, e; argexps)
2576 assert(e);
2577 if (e == emptyArrayElement)
2578 continue;
2580 Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_);
2582 MATCH m = e.implicitConvTo(t);
2583 if (match > m)
2584 match = m;
2585 if (match == MATCH.nomatch)
2586 break;
2588 return match;
2593 /*************************************************
2594 * Given function arguments, figure out which template function
2595 * to expand, and return matching result.
2596 * Params:
2597 * m = matching result
2598 * dstart = the root of overloaded function templates
2599 * loc = instantiation location
2600 * sc = instantiation scope
2601 * tiargs = initial list of template arguments
2602 * tthis = if !NULL, the 'this' pointer argument
2603 * fargs = arguments to function
2604 * pMessage = address to store error message, or null
2606 void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
2607 Type tthis, Expressions* fargs, const(char)** pMessage = null)
2609 Expression[] fargs_ = fargs.peekSlice();
2610 version (none)
2612 printf("functionResolve() dstart = %s\n", dstart.toChars());
2613 printf(" tiargs:\n");
2614 if (tiargs)
2616 for (size_t i = 0; i < tiargs.dim; i++)
2618 RootObject arg = (*tiargs)[i];
2619 printf("\t%s\n", arg.toChars());
2622 printf(" fargs:\n");
2623 for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++)
2625 Expression arg = (*fargs)[i];
2626 printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
2627 //printf("\tty = %d\n", arg.type.ty);
2629 //printf("stc = %llx\n", dstart._scope.stc);
2630 //printf("match:t/f = %d/%d\n", ta_last, m.last);
2633 // results
2634 int property = 0; // 0: uninitialized
2635 // 1: seen @property
2636 // 2: not @property
2637 size_t ov_index = 0;
2638 TemplateDeclaration td_best;
2639 TemplateInstance ti_best;
2640 MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch;
2641 Type tthis_best;
2643 int applyFunction(FuncDeclaration fd)
2645 // skip duplicates
2646 if (fd == m.lastf)
2647 return 0;
2648 // explicitly specified tiargs never match to non template function
2649 if (tiargs && tiargs.dim > 0)
2650 return 0;
2652 // constructors need a valid scope in order to detect semantic errors
2653 if (!fd.isCtorDeclaration &&
2654 fd.semanticRun < PASS.semanticdone)
2656 Ungag ungag = fd.ungagSpeculative();
2657 fd.dsymbolSemantic(null);
2659 if (fd.semanticRun < PASS.semanticdone)
2661 .error(loc, "forward reference to template `%s`", fd.toChars());
2662 return 1;
2664 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
2665 auto tf = cast(TypeFunction)fd.type;
2667 int prop = tf.isproperty ? 1 : 2;
2668 if (property == 0)
2669 property = prop;
2670 else if (property != prop)
2671 error(fd.loc, "cannot overload both property and non-property functions");
2673 /* For constructors, qualifier check will be opposite direction.
2674 * Qualified constructor always makes qualified object, then will be checked
2675 * that it is implicitly convertible to tthis.
2677 Type tthis_fd = fd.needThis() ? tthis : null;
2678 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2679 if (isCtorCall)
2681 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
2682 // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
2683 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2684 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2685 fd.isReturnIsolated())
2687 /* && tf.isShared() == tthis_fd.isShared()*/
2688 // Uniquely constructed object can ignore shared qualifier.
2689 // TODO: Is this appropriate?
2690 tthis_fd = null;
2692 else
2693 return 0; // MATCH.nomatch
2695 /* Fix Issue 17970:
2696 If a struct is declared as shared the dtor is automatically
2697 considered to be shared, but when the struct is instantiated
2698 the instance is no longer considered to be shared when the
2699 function call matching is done. The fix makes it so that if a
2700 struct declaration is shared, when the destructor is called,
2701 the instantiated struct is also considered shared.
2703 if (auto dt = fd.isDtorDeclaration())
2705 auto dtmod = dt.type.toTypeFunction();
2706 auto shared_dtor = dtmod.mod & MODFlags.shared_;
2707 auto shared_this = tthis_fd !is null ?
2708 tthis_fd.mod & MODFlags.shared_ : 0;
2709 if (shared_dtor && !shared_this)
2710 tthis_fd = dtmod;
2711 else if (shared_this && !shared_dtor && tthis_fd !is null)
2712 tf.mod = tthis_fd.mod;
2714 MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, pMessage, sc);
2715 //printf("test1: mfa = %d\n", mfa);
2716 if (mfa == MATCH.nomatch)
2717 return 0;
2719 if (mfa > m.last) goto LfIsBetter;
2720 if (mfa < m.last) goto LlastIsBetter;
2722 /* See if one of the matches overrides the other.
2724 assert(m.lastf);
2725 if (m.lastf.overrides(fd)) goto LlastIsBetter;
2726 if (fd.overrides(m.lastf)) goto LfIsBetter;
2728 /* Try to disambiguate using template-style partial ordering rules.
2729 * In essence, if f() and g() are ambiguous, if f() can call g(),
2730 * but g() cannot call f(), then pick f().
2731 * This is because f() is "more specialized."
2734 MATCH c1 = fd.leastAsSpecialized(m.lastf);
2735 MATCH c2 = m.lastf.leastAsSpecialized(fd);
2736 //printf("c1 = %d, c2 = %d\n", c1, c2);
2737 if (c1 > c2) goto LfIsBetter;
2738 if (c1 < c2) goto LlastIsBetter;
2741 /* The 'overrides' check above does covariant checking only
2742 * for virtual member functions. It should do it for all functions,
2743 * but in order to not risk breaking code we put it after
2744 * the 'leastAsSpecialized' check.
2745 * In the future try moving it before.
2746 * I.e. a not-the-same-but-covariant match is preferred,
2747 * as it is more restrictive.
2749 if (!m.lastf.type.equals(fd.type))
2751 //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
2752 const lastCovariant = m.lastf.type.covariant(fd.type);
2753 const firstCovariant = fd.type.covariant(m.lastf.type);
2755 if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no)
2757 if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no)
2759 goto LlastIsBetter;
2762 else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no)
2764 goto LfIsBetter;
2768 /* If the two functions are the same function, like:
2769 * int foo(int);
2770 * int foo(int x) { ... }
2771 * then pick the one with the body.
2773 * If none has a body then don't care because the same
2774 * real function would be linked to the decl (e.g from object file)
2776 if (tf.equals(m.lastf.type) &&
2777 fd.storage_class == m.lastf.storage_class &&
2778 fd.parent == m.lastf.parent &&
2779 fd.visibility == m.lastf.visibility &&
2780 fd.linkage == m.lastf.linkage)
2782 if (fd.fbody && !m.lastf.fbody)
2783 goto LfIsBetter;
2784 if (!fd.fbody)
2785 goto LlastIsBetter;
2788 // https://issues.dlang.org/show_bug.cgi?id=14450
2789 // Prefer exact qualified constructor for the creating object type
2790 if (isCtorCall && tf.mod != m.lastf.type.mod)
2792 if (tthis.mod == tf.mod) goto LfIsBetter;
2793 if (tthis.mod == m.lastf.type.mod) goto LlastIsBetter;
2796 m.nextf = fd;
2797 m.count++;
2798 return 0;
2800 LlastIsBetter:
2801 return 0;
2803 LfIsBetter:
2804 td_best = null;
2805 ti_best = null;
2806 ta_last = MATCH.exact;
2807 m.last = mfa;
2808 m.lastf = fd;
2809 tthis_best = tthis_fd;
2810 ov_index = 0;
2811 m.count = 1;
2812 return 0;
2816 int applyTemplate(TemplateDeclaration td)
2818 //printf("applyTemplate()\n");
2819 if (td.inuse)
2821 td.error(loc, "recursive template expansion");
2822 return 1;
2824 if (td == td_best) // skip duplicates
2825 return 0;
2827 if (!sc)
2828 sc = td._scope; // workaround for Type.aliasthisOf
2830 if (td.semanticRun == PASS.initial && td._scope)
2832 // Try to fix forward reference. Ungag errors while doing so.
2833 Ungag ungag = td.ungagSpeculative();
2834 td.dsymbolSemantic(td._scope);
2836 if (td.semanticRun == PASS.initial)
2838 .error(loc, "forward reference to template `%s`", td.toChars());
2839 Lerror:
2840 m.lastf = null;
2841 m.count = 0;
2842 m.last = MATCH.nomatch;
2843 return 1;
2845 //printf("td = %s\n", td.toChars());
2847 auto f = td.onemember ? td.onemember.isFuncDeclaration() : null;
2848 if (!f)
2850 if (!tiargs)
2851 tiargs = new Objects();
2852 auto ti = new TemplateInstance(loc, td, tiargs);
2853 Objects dedtypes = Objects(td.parameters.dim);
2854 assert(td.semanticRun != PASS.initial);
2855 MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0);
2856 //printf("matchWithInstance = %d\n", mta);
2857 if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
2858 return 0;
2860 ti.templateInstanceSemantic(sc, fargs);
2861 if (!ti.inst) // if template failed to expand
2862 return 0;
2864 Dsymbol s = ti.inst.toAlias();
2865 FuncDeclaration fd;
2866 if (auto tdx = s.isTemplateDeclaration())
2868 Objects dedtypesX; // empty tiargs
2870 // https://issues.dlang.org/show_bug.cgi?id=11553
2871 // Check for recursive instantiation of tdx.
2872 for (TemplatePrevious* p = tdx.previous; p; p = p.prev)
2874 if (arrayObjectMatch(p.dedargs, &dedtypesX))
2876 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
2877 /* It must be a subscope of p.sc, other scope chains are not recursive
2878 * instantiations.
2880 for (Scope* scx = sc; scx; scx = scx.enclosing)
2882 if (scx == p.sc)
2884 error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars());
2885 goto Lerror;
2889 /* BUG: should also check for ref param differences
2893 TemplatePrevious pr;
2894 pr.prev = tdx.previous;
2895 pr.sc = sc;
2896 pr.dedargs = &dedtypesX;
2897 tdx.previous = &pr; // add this to threaded list
2899 fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
2901 tdx.previous = pr.prev; // unlink from threaded list
2903 else if (s.isFuncDeclaration())
2905 fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
2907 else
2908 goto Lerror;
2910 if (!fd)
2911 return 0;
2913 if (fd.type.ty != Tfunction)
2915 m.lastf = fd; // to propagate "error match"
2916 m.count = 1;
2917 m.last = MATCH.nomatch;
2918 return 1;
2921 Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
2923 auto tf = cast(TypeFunction)fd.type;
2924 MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, null, sc);
2925 if (mfa < m.last)
2926 return 0;
2928 if (mta < ta_last) goto Ltd_best2;
2929 if (mta > ta_last) goto Ltd2;
2931 if (mfa < m.last) goto Ltd_best2;
2932 if (mfa > m.last) goto Ltd2;
2934 // td_best and td are ambiguous
2935 //printf("Lambig2\n");
2936 m.nextf = fd;
2937 m.count++;
2938 return 0;
2940 Ltd_best2:
2941 return 0;
2943 Ltd2:
2944 // td is the new best match
2945 assert(td._scope);
2946 td_best = td;
2947 ti_best = null;
2948 property = 0; // (backward compatibility)
2949 ta_last = mta;
2950 m.last = mfa;
2951 m.lastf = fd;
2952 tthis_best = tthis_fd;
2953 ov_index = 0;
2954 m.nextf = null;
2955 m.count = 1;
2956 return 0;
2959 //printf("td = %s\n", td.toChars());
2960 for (size_t ovi = 0; f; f = f.overnext0, ovi++)
2962 if (f.type.ty != Tfunction || f.errors)
2963 goto Lerror;
2965 /* This is a 'dummy' instance to evaluate constraint properly.
2967 auto ti = new TemplateInstance(loc, td, tiargs);
2968 ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary.
2970 auto fd = f;
2971 MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
2972 MATCH mta = x.mta;
2973 MATCH mfa = x.mfa;
2974 //printf("match:t/f = %d/%d\n", mta, mfa);
2975 if (!fd || mfa == MATCH.nomatch)
2976 continue;
2978 Type tthis_fd = fd.needThis() ? tthis : null;
2980 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2981 if (isCtorCall)
2983 // Constructor call requires additional check.
2985 auto tf = cast(TypeFunction)fd.type;
2986 assert(tf.next);
2987 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2988 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2989 fd.isReturnIsolated())
2991 tthis_fd = null;
2993 else
2994 continue; // MATCH.nomatch
2997 if (mta < ta_last) goto Ltd_best;
2998 if (mta > ta_last) goto Ltd;
3000 if (mfa < m.last) goto Ltd_best;
3001 if (mfa > m.last) goto Ltd;
3003 if (td_best)
3005 // Disambiguate by picking the most specialized TemplateDeclaration
3006 MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
3007 MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
3008 //printf("1: c1 = %d, c2 = %d\n", c1, c2);
3009 if (c1 > c2) goto Ltd;
3010 if (c1 < c2) goto Ltd_best;
3012 assert(fd && m.lastf);
3014 // Disambiguate by tf.callMatch
3015 auto tf1 = fd.type.isTypeFunction();
3016 auto tf2 = m.lastf.type.isTypeFunction();
3017 MATCH c1 = tf1.callMatch(tthis_fd, fargs_, 0, null, sc);
3018 MATCH c2 = tf2.callMatch(tthis_best, fargs_, 0, null, sc);
3019 //printf("2: c1 = %d, c2 = %d\n", c1, c2);
3020 if (c1 > c2) goto Ltd;
3021 if (c1 < c2) goto Ltd_best;
3024 // Disambiguate by picking the most specialized FunctionDeclaration
3025 MATCH c1 = fd.leastAsSpecialized(m.lastf);
3026 MATCH c2 = m.lastf.leastAsSpecialized(fd);
3027 //printf("3: c1 = %d, c2 = %d\n", c1, c2);
3028 if (c1 > c2) goto Ltd;
3029 if (c1 < c2) goto Ltd_best;
3032 // https://issues.dlang.org/show_bug.cgi?id=14450
3033 // Prefer exact qualified constructor for the creating object type
3034 if (isCtorCall && fd.type.mod != m.lastf.type.mod)
3036 if (tthis.mod == fd.type.mod) goto Ltd;
3037 if (tthis.mod == m.lastf.type.mod) goto Ltd_best;
3040 m.nextf = fd;
3041 m.count++;
3042 continue;
3044 Ltd_best: // td_best is the best match so far
3045 //printf("Ltd_best\n");
3046 continue;
3048 Ltd: // td is the new best match
3049 //printf("Ltd\n");
3050 assert(td._scope);
3051 td_best = td;
3052 ti_best = ti;
3053 property = 0; // (backward compatibility)
3054 ta_last = mta;
3055 m.last = mfa;
3056 m.lastf = fd;
3057 tthis_best = tthis_fd;
3058 ov_index = ovi;
3059 m.nextf = null;
3060 m.count = 1;
3061 continue;
3063 return 0;
3066 auto td = dstart.isTemplateDeclaration();
3067 if (td && td.funcroot)
3068 dstart = td.funcroot;
3069 overloadApply(dstart, (Dsymbol s)
3071 if (s.errors)
3072 return 0;
3073 if (auto fd = s.isFuncDeclaration())
3074 return applyFunction(fd);
3075 if (auto td = s.isTemplateDeclaration())
3076 return applyTemplate(td);
3077 return 0;
3078 }, sc);
3080 //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf);
3081 if (td_best && ti_best && m.count == 1)
3083 // Matches to template function
3084 assert(td_best.onemember && td_best.onemember.isFuncDeclaration());
3085 /* The best match is td_best with arguments tdargs.
3086 * Now instantiate the template.
3088 assert(td_best._scope);
3089 if (!sc)
3090 sc = td_best._scope; // workaround for Type.aliasthisOf
3092 auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs);
3093 ti.templateInstanceSemantic(sc, fargs);
3095 m.lastf = ti.toAlias().isFuncDeclaration();
3096 if (!m.lastf)
3097 goto Lnomatch;
3098 if (ti.errors)
3100 Lerror:
3101 m.count = 1;
3102 assert(m.lastf);
3103 m.last = MATCH.nomatch;
3104 return;
3107 // look forward instantiated overload function
3108 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
3109 // it has filled overnext0d
3110 while (ov_index--)
3112 m.lastf = m.lastf.overnext0;
3113 assert(m.lastf);
3116 tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null;
3118 if (m.lastf.type.ty == Terror)
3119 goto Lerror;
3120 auto tf = m.lastf.type.isTypeFunction();
3121 if (!tf.callMatch(tthis_best, fargs_, 0, null, sc))
3122 goto Lnomatch;
3124 /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
3125 * a template instance can be matched while instantiating
3126 * that same template. Thus, the function type can be incomplete. Complete it.
3128 * https://issues.dlang.org/show_bug.cgi?id=9208
3129 * For auto function, completion should be deferred to the end of
3130 * its semantic3. Should not complete it in here.
3132 if (tf.next && !m.lastf.inferRetType)
3134 m.lastf.type = tf.typeSemantic(loc, sc);
3137 else if (m.lastf)
3139 // Matches to non template function,
3140 // or found matches were ambiguous.
3141 assert(m.count >= 1);
3143 else
3145 Lnomatch:
3146 m.count = 0;
3147 m.lastf = null;
3148 m.last = MATCH.nomatch;
3152 /* ======================== Type ============================================ */
3154 /****
3155 * Given an identifier, figure out which TemplateParameter it is.
3156 * Return IDX_NOTFOUND if not found.
3158 private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters)
3160 for (size_t i = 0; i < parameters.dim; i++)
3162 TemplateParameter tp = (*parameters)[i];
3163 if (tp.ident.equals(id))
3164 return i;
3166 return IDX_NOTFOUND;
3169 private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
3171 if (tparam.ty == Tident)
3173 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3174 //printf("\ttident = '%s'\n", tident.toChars());
3175 return templateIdentifierLookup(tident.ident, parameters);
3177 return IDX_NOTFOUND;
3180 private ubyte deduceWildHelper(Type t, Type* at, Type tparam)
3182 if ((tparam.mod & MODFlags.wild) == 0)
3183 return 0;
3185 *at = null;
3187 auto X(T, U)(T U, U T)
3189 return (U << 4) | T;
3192 switch (X(tparam.mod, t.mod))
3194 case X(MODFlags.wild, 0):
3195 case X(MODFlags.wild, MODFlags.const_):
3196 case X(MODFlags.wild, MODFlags.shared_):
3197 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3198 case X(MODFlags.wild, MODFlags.immutable_):
3199 case X(MODFlags.wildconst, 0):
3200 case X(MODFlags.wildconst, MODFlags.const_):
3201 case X(MODFlags.wildconst, MODFlags.shared_):
3202 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3203 case X(MODFlags.wildconst, MODFlags.immutable_):
3204 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
3205 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3206 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
3207 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
3208 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3209 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
3211 ubyte wm = (t.mod & ~MODFlags.shared_);
3212 if (wm == 0)
3213 wm = MODFlags.mutable;
3214 ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_);
3215 *at = t.unqualify(m);
3216 return wm;
3218 case X(MODFlags.wild, MODFlags.wild):
3219 case X(MODFlags.wild, MODFlags.wildconst):
3220 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3221 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3222 case X(MODFlags.wildconst, MODFlags.wild):
3223 case X(MODFlags.wildconst, MODFlags.wildconst):
3224 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3225 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3226 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3227 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3228 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3229 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3231 *at = t.unqualify(tparam.mod & t.mod);
3232 return MODFlags.wild;
3234 default:
3235 return 0;
3240 * Returns the common type of the 2 types.
3242 private Type rawTypeMerge(Type t1, Type t2)
3244 if (t1.equals(t2))
3245 return t1;
3246 if (t1.equivalent(t2))
3247 return t1.castMod(MODmerge(t1.mod, t2.mod));
3249 auto t1b = t1.toBasetype();
3250 auto t2b = t2.toBasetype();
3251 if (t1b.equals(t2b))
3252 return t1b;
3253 if (t1b.equivalent(t2b))
3254 return t1b.castMod(MODmerge(t1b.mod, t2b.mod));
3256 auto ty = implicitConvCommonTy(t1b.ty, t2b.ty);
3257 if (ty != Terror)
3258 return Type.basic[ty];
3260 return null;
3263 private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
3265 // 9*9 == 81 cases
3267 auto X(T, U)(T U, U T)
3269 return (U << 4) | T;
3272 switch (X(tparam.mod, t.mod))
3274 case X(0, 0):
3275 case X(0, MODFlags.const_):
3276 case X(0, MODFlags.wild):
3277 case X(0, MODFlags.wildconst):
3278 case X(0, MODFlags.shared_):
3279 case X(0, MODFlags.shared_ | MODFlags.const_):
3280 case X(0, MODFlags.shared_ | MODFlags.wild):
3281 case X(0, MODFlags.shared_ | MODFlags.wildconst):
3282 case X(0, MODFlags.immutable_):
3283 // foo(U) T => T
3284 // foo(U) const(T) => const(T)
3285 // foo(U) inout(T) => inout(T)
3286 // foo(U) inout(const(T)) => inout(const(T))
3287 // foo(U) shared(T) => shared(T)
3288 // foo(U) shared(const(T)) => shared(const(T))
3289 // foo(U) shared(inout(T)) => shared(inout(T))
3290 // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
3291 // foo(U) immutable(T) => immutable(T)
3293 *at = t;
3294 return MATCH.exact;
3296 case X(MODFlags.const_, MODFlags.const_):
3297 case X(MODFlags.wild, MODFlags.wild):
3298 case X(MODFlags.wildconst, MODFlags.wildconst):
3299 case X(MODFlags.shared_, MODFlags.shared_):
3300 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
3301 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3302 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3303 case X(MODFlags.immutable_, MODFlags.immutable_):
3304 // foo(const(U)) const(T) => T
3305 // foo(inout(U)) inout(T) => T
3306 // foo(inout(const(U))) inout(const(T)) => T
3307 // foo(shared(U)) shared(T) => T
3308 // foo(shared(const(U))) shared(const(T)) => T
3309 // foo(shared(inout(U))) shared(inout(T)) => T
3310 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
3311 // foo(immutable(U)) immutable(T) => T
3313 *at = t.mutableOf().unSharedOf();
3314 return MATCH.exact;
3316 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
3317 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3318 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3319 // foo(const(U)) shared(const(T)) => shared(T)
3320 // foo(inout(U)) shared(inout(T)) => shared(T)
3321 // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
3323 *at = t.mutableOf();
3324 return MATCH.exact;
3326 case X(MODFlags.const_, 0):
3327 case X(MODFlags.const_, MODFlags.wild):
3328 case X(MODFlags.const_, MODFlags.wildconst):
3329 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
3330 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
3331 case X(MODFlags.const_, MODFlags.immutable_):
3332 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.immutable_):
3333 // foo(const(U)) T => T
3334 // foo(const(U)) inout(T) => T
3335 // foo(const(U)) inout(const(T)) => T
3336 // foo(const(U)) shared(inout(T)) => shared(T)
3337 // foo(const(U)) shared(inout(const(T))) => shared(T)
3338 // foo(const(U)) immutable(T) => T
3339 // foo(shared(const(U))) immutable(T) => T
3341 *at = t.mutableOf();
3342 return MATCH.constant;
3344 case X(MODFlags.const_, MODFlags.shared_):
3345 // foo(const(U)) shared(T) => shared(T)
3347 *at = t;
3348 return MATCH.constant;
3350 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
3351 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
3352 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wildconst):
3353 // foo(shared(U)) shared(const(T)) => const(T)
3354 // foo(shared(U)) shared(inout(T)) => inout(T)
3355 // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
3357 *at = t.unSharedOf();
3358 return MATCH.exact;
3360 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
3361 // foo(shared(const(U))) shared(T) => T
3363 *at = t.unSharedOf();
3364 return MATCH.constant;
3366 case X(MODFlags.wildconst, MODFlags.immutable_):
3367 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
3368 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
3369 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3370 // foo(inout(const(U))) immutable(T) => T
3371 // foo(shared(const(U))) shared(inout(const(T))) => T
3372 // foo(shared(inout(const(U)))) immutable(T) => T
3373 // foo(shared(inout(const(U)))) shared(inout(T)) => T
3375 *at = t.unSharedOf().mutableOf();
3376 return MATCH.constant;
3378 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
3379 // foo(shared(const(U))) shared(inout(T)) => T
3381 *at = t.unSharedOf().mutableOf();
3382 return MATCH.constant;
3384 case X(MODFlags.wild, 0):
3385 case X(MODFlags.wild, MODFlags.const_):
3386 case X(MODFlags.wild, MODFlags.wildconst):
3387 case X(MODFlags.wild, MODFlags.immutable_):
3388 case X(MODFlags.wild, MODFlags.shared_):
3389 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3390 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3391 case X(MODFlags.wildconst, 0):
3392 case X(MODFlags.wildconst, MODFlags.const_):
3393 case X(MODFlags.wildconst, MODFlags.wild):
3394 case X(MODFlags.wildconst, MODFlags.shared_):
3395 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3396 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3397 case X(MODFlags.shared_, 0):
3398 case X(MODFlags.shared_, MODFlags.const_):
3399 case X(MODFlags.shared_, MODFlags.wild):
3400 case X(MODFlags.shared_, MODFlags.wildconst):
3401 case X(MODFlags.shared_, MODFlags.immutable_):
3402 case X(MODFlags.shared_ | MODFlags.const_, 0):
3403 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.const_):
3404 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wild):
3405 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wildconst):
3406 case X(MODFlags.shared_ | MODFlags.wild, 0):
3407 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.const_):
3408 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wild):
3409 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wildconst):
3410 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
3411 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
3412 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3413 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3414 case X(MODFlags.shared_ | MODFlags.wildconst, 0):
3415 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.const_):
3416 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wild):
3417 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wildconst):
3418 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
3419 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3420 case X(MODFlags.immutable_, 0):
3421 case X(MODFlags.immutable_, MODFlags.const_):
3422 case X(MODFlags.immutable_, MODFlags.wild):
3423 case X(MODFlags.immutable_, MODFlags.wildconst):
3424 case X(MODFlags.immutable_, MODFlags.shared_):
3425 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.const_):
3426 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
3427 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wildconst):
3428 // foo(inout(U)) T => nomatch
3429 // foo(inout(U)) const(T) => nomatch
3430 // foo(inout(U)) inout(const(T)) => nomatch
3431 // foo(inout(U)) immutable(T) => nomatch
3432 // foo(inout(U)) shared(T) => nomatch
3433 // foo(inout(U)) shared(const(T)) => nomatch
3434 // foo(inout(U)) shared(inout(const(T))) => nomatch
3435 // foo(inout(const(U))) T => nomatch
3436 // foo(inout(const(U))) const(T) => nomatch
3437 // foo(inout(const(U))) inout(T) => nomatch
3438 // foo(inout(const(U))) shared(T) => nomatch
3439 // foo(inout(const(U))) shared(const(T)) => nomatch
3440 // foo(inout(const(U))) shared(inout(T)) => nomatch
3441 // foo(shared(U)) T => nomatch
3442 // foo(shared(U)) const(T) => nomatch
3443 // foo(shared(U)) inout(T) => nomatch
3444 // foo(shared(U)) inout(const(T)) => nomatch
3445 // foo(shared(U)) immutable(T) => nomatch
3446 // foo(shared(const(U))) T => nomatch
3447 // foo(shared(const(U))) const(T) => nomatch
3448 // foo(shared(const(U))) inout(T) => nomatch
3449 // foo(shared(const(U))) inout(const(T)) => nomatch
3450 // foo(shared(inout(U))) T => nomatch
3451 // foo(shared(inout(U))) const(T) => nomatch
3452 // foo(shared(inout(U))) inout(T) => nomatch
3453 // foo(shared(inout(U))) inout(const(T)) => nomatch
3454 // foo(shared(inout(U))) immutable(T) => nomatch
3455 // foo(shared(inout(U))) shared(T) => nomatch
3456 // foo(shared(inout(U))) shared(const(T)) => nomatch
3457 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
3458 // foo(shared(inout(const(U)))) T => nomatch
3459 // foo(shared(inout(const(U)))) const(T) => nomatch
3460 // foo(shared(inout(const(U)))) inout(T) => nomatch
3461 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
3462 // foo(shared(inout(const(U)))) shared(T) => nomatch
3463 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
3464 // foo(immutable(U)) T => nomatch
3465 // foo(immutable(U)) const(T) => nomatch
3466 // foo(immutable(U)) inout(T) => nomatch
3467 // foo(immutable(U)) inout(const(T)) => nomatch
3468 // foo(immutable(U)) shared(T) => nomatch
3469 // foo(immutable(U)) shared(const(T)) => nomatch
3470 // foo(immutable(U)) shared(inout(T)) => nomatch
3471 // foo(immutable(U)) shared(inout(const(T))) => nomatch
3472 return MATCH.nomatch;
3474 default:
3475 assert(0);
3479 __gshared Expression emptyArrayElement = null;
3481 /* These form the heart of template argument deduction.
3482 * Given 'this' being the type argument to the template instance,
3483 * it is matched against the template declaration parameter specialization
3484 * 'tparam' to determine the type to be used for the parameter.
3485 * Example:
3486 * template Foo(T:T*) // template declaration
3487 * Foo!(int*) // template instantiation
3488 * Input:
3489 * this = int*
3490 * tparam = T*
3491 * parameters = [ T:T* ] // Array of TemplateParameter's
3492 * Output:
3493 * dedtypes = [ int ] // Array of Expression/Type's
3495 MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
3497 extern (C++) final class DeduceType : Visitor
3499 alias visit = Visitor.visit;
3500 public:
3501 Scope* sc;
3502 Type tparam;
3503 TemplateParameters* parameters;
3504 Objects* dedtypes;
3505 uint* wm;
3506 size_t inferStart;
3507 bool ignoreAliasThis;
3508 MATCH result;
3510 extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis)
3512 this.sc = sc;
3513 this.tparam = tparam;
3514 this.parameters = parameters;
3515 this.dedtypes = dedtypes;
3516 this.wm = wm;
3517 this.inferStart = inferStart;
3518 this.ignoreAliasThis = ignoreAliasThis;
3519 result = MATCH.nomatch;
3522 override void visit(Type t)
3524 if (!tparam)
3525 goto Lnomatch;
3527 if (t == tparam)
3528 goto Lexact;
3530 if (tparam.ty == Tident)
3532 // Determine which parameter tparam is
3533 size_t i = templateParameterLookup(tparam, parameters);
3534 if (i == IDX_NOTFOUND)
3536 if (!sc)
3537 goto Lnomatch;
3539 /* Need a loc to go with the semantic routine.
3541 Loc loc;
3542 if (parameters.dim)
3544 TemplateParameter tp = (*parameters)[0];
3545 loc = tp.loc;
3548 /* BUG: what if tparam is a template instance, that
3549 * has as an argument another Tident?
3551 tparam = tparam.typeSemantic(loc, sc);
3552 assert(tparam.ty != Tident);
3553 result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
3554 return;
3557 TemplateParameter tp = (*parameters)[i];
3559 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3560 if (tident.idents.dim > 0)
3562 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
3563 Dsymbol s = t.toDsymbol(sc);
3564 for (size_t j = tident.idents.dim; j-- > 0;)
3566 RootObject id = tident.idents[j];
3567 if (id.dyncast() == DYNCAST.identifier)
3569 if (!s || !s.parent)
3570 goto Lnomatch;
3571 Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id);
3572 if (!s2)
3573 goto Lnomatch;
3574 s2 = s2.toAlias();
3575 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
3576 if (s != s2)
3578 if (Type tx = s2.getType())
3580 if (s != tx.toDsymbol(sc))
3581 goto Lnomatch;
3583 else
3584 goto Lnomatch;
3586 s = s.parent;
3588 else
3589 goto Lnomatch;
3591 //printf("[e] s = %s\n", s?s.toChars():"(null)");
3592 if (tp.isTemplateTypeParameter())
3594 Type tt = s.getType();
3595 if (!tt)
3596 goto Lnomatch;
3597 Type at = cast(Type)(*dedtypes)[i];
3598 if (at && at.ty == Tnone)
3599 at = (cast(TypeDeduced)at).tded;
3600 if (!at || tt.equals(at))
3602 (*dedtypes)[i] = tt;
3603 goto Lexact;
3606 if (tp.isTemplateAliasParameter())
3608 Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
3609 if (!s2 || s == s2)
3611 (*dedtypes)[i] = s;
3612 goto Lexact;
3615 goto Lnomatch;
3618 // Found the corresponding parameter tp
3619 if (!tp.isTemplateTypeParameter())
3620 goto Lnomatch;
3621 Type at = cast(Type)(*dedtypes)[i];
3622 Type tt;
3623 if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
3625 // type vs (none)
3626 if (!at)
3628 (*dedtypes)[i] = tt;
3629 *wm |= wx;
3630 result = MATCH.constant;
3631 return;
3634 // type vs expressions
3635 if (at.ty == Tnone)
3637 TypeDeduced xt = cast(TypeDeduced)at;
3638 result = xt.matchAll(tt);
3639 if (result > MATCH.nomatch)
3641 (*dedtypes)[i] = tt;
3642 if (result > MATCH.constant)
3643 result = MATCH.constant; // limit level for inout matches
3645 return;
3648 // type vs type
3649 if (tt.equals(at))
3651 (*dedtypes)[i] = tt; // Prefer current type match
3652 goto Lconst;
3654 if (tt.implicitConvTo(at.constOf()))
3656 (*dedtypes)[i] = at.constOf().mutableOf();
3657 *wm |= MODFlags.const_;
3658 goto Lconst;
3660 if (at.implicitConvTo(tt.constOf()))
3662 (*dedtypes)[i] = tt.constOf().mutableOf();
3663 *wm |= MODFlags.const_;
3664 goto Lconst;
3666 goto Lnomatch;
3668 else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
3670 // type vs (none)
3671 if (!at)
3673 (*dedtypes)[i] = tt;
3674 result = m;
3675 return;
3678 // type vs expressions
3679 if (at.ty == Tnone)
3681 TypeDeduced xt = cast(TypeDeduced)at;
3682 result = xt.matchAll(tt);
3683 if (result > MATCH.nomatch)
3685 (*dedtypes)[i] = tt;
3687 return;
3690 // type vs type
3691 if (tt.equals(at))
3693 goto Lexact;
3695 if (tt.ty == Tclass && at.ty == Tclass)
3697 result = tt.implicitConvTo(at);
3698 return;
3700 if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant)
3702 goto Lexact;
3705 goto Lnomatch;
3708 if (tparam.ty == Ttypeof)
3710 /* Need a loc to go with the semantic routine.
3712 Loc loc;
3713 if (parameters.dim)
3715 TemplateParameter tp = (*parameters)[0];
3716 loc = tp.loc;
3719 tparam = tparam.typeSemantic(loc, sc);
3721 if (t.ty != tparam.ty)
3723 if (Dsymbol sym = t.toDsymbol(sc))
3725 if (sym.isforwardRef() && !tparam.deco)
3726 goto Lnomatch;
3729 MATCH m = t.implicitConvTo(tparam);
3730 if (m == MATCH.nomatch && !ignoreAliasThis)
3732 if (t.ty == Tclass)
3734 TypeClass tc = cast(TypeClass)t;
3735 if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
3737 if (auto ato = t.aliasthisOf())
3739 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT);
3740 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3741 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT);
3745 else if (t.ty == Tstruct)
3747 TypeStruct ts = cast(TypeStruct)t;
3748 if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
3750 if (auto ato = t.aliasthisOf())
3752 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT);
3753 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3754 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT);
3759 result = m;
3760 return;
3763 if (t.nextOf())
3765 if (tparam.deco && !tparam.hasWild())
3767 result = t.implicitConvTo(tparam);
3768 return;
3771 Type tpn = tparam.nextOf();
3772 if (wm && t.ty == Taarray && tparam.isWild())
3774 // https://issues.dlang.org/show_bug.cgi?id=12403
3775 // In IFTI, stop inout matching on transitive part of AA types.
3776 tpn = tpn.substWildTo(MODFlags.mutable);
3779 result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm);
3780 return;
3783 Lexact:
3784 result = MATCH.exact;
3785 return;
3787 Lnomatch:
3788 result = MATCH.nomatch;
3789 return;
3791 Lconst:
3792 result = MATCH.constant;
3795 override void visit(TypeVector t)
3797 if (tparam.ty == Tvector)
3799 TypeVector tp = cast(TypeVector)tparam;
3800 result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
3801 return;
3803 visit(cast(Type)t);
3806 override void visit(TypeDArray t)
3808 visit(cast(Type)t);
3811 override void visit(TypeSArray t)
3813 // Extra check that array dimensions must match
3814 if (tparam)
3816 if (tparam.ty == Tarray)
3818 MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3819 result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
3820 return;
3823 TemplateParameter tp = null;
3824 Expression edim = null;
3825 size_t i;
3826 if (tparam.ty == Tsarray)
3828 TypeSArray tsa = cast(TypeSArray)tparam;
3829 if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
3831 Identifier id = (cast(VarExp)tsa.dim).var.ident;
3832 i = templateIdentifierLookup(id, parameters);
3833 assert(i != IDX_NOTFOUND);
3834 tp = (*parameters)[i];
3836 else
3837 edim = tsa.dim;
3839 else if (tparam.ty == Taarray)
3841 TypeAArray taa = cast(TypeAArray)tparam;
3842 i = templateParameterLookup(taa.index, parameters);
3843 if (i != IDX_NOTFOUND)
3844 tp = (*parameters)[i];
3845 else
3847 Expression e;
3848 Type tx;
3849 Dsymbol s;
3850 taa.index.resolve(Loc.initial, sc, e, tx, s);
3851 edim = s ? getValue(s) : getValue(e);
3854 if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
3856 result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3857 return;
3860 visit(cast(Type)t);
3863 override void visit(TypeAArray t)
3865 // Extra check that index type must match
3866 if (tparam && tparam.ty == Taarray)
3868 TypeAArray tp = cast(TypeAArray)tparam;
3869 if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
3871 result = MATCH.nomatch;
3872 return;
3875 visit(cast(Type)t);
3878 override void visit(TypeFunction t)
3880 // Extra check that function characteristics must match
3881 if (!tparam)
3882 return visit(cast(Type)t);
3884 if (auto tp = tparam.isTypeFunction())
3886 if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
3888 result = MATCH.nomatch;
3889 return;
3892 foreach (fparam; *tp.parameterList.parameters)
3894 // https://issues.dlang.org/show_bug.cgi?id=2579
3895 // Apply function parameter storage classes to parameter types
3896 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
3897 fparam.storageClass &= ~(STC.TYPECTOR | STC.in_);
3899 // https://issues.dlang.org/show_bug.cgi?id=15243
3900 // Resolve parameter type if it's not related with template parameters
3901 if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.dim]))
3903 auto tx = fparam.type.typeSemantic(Loc.initial, sc);
3904 if (tx.ty == Terror)
3906 result = MATCH.nomatch;
3907 return;
3909 fparam.type = tx;
3913 size_t nfargs = t.parameterList.length;
3914 size_t nfparams = tp.parameterList.length;
3916 /* See if tuple match
3918 if (nfparams > 0 && nfargs >= nfparams - 1)
3920 /* See if 'A' of the template parameter matches 'A'
3921 * of the type of the last function parameter.
3923 Parameter fparam = tp.parameterList[nfparams - 1];
3924 assert(fparam);
3925 assert(fparam.type);
3926 if (fparam.type.ty != Tident)
3927 goto L1;
3928 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
3929 if (tid.idents.dim)
3930 goto L1;
3932 /* Look through parameters to find tuple matching tid.ident
3934 size_t tupi = 0;
3935 for (; 1; tupi++)
3937 if (tupi == parameters.dim)
3938 goto L1;
3939 TemplateParameter tx = (*parameters)[tupi];
3940 TemplateTupleParameter tup = tx.isTemplateTupleParameter();
3941 if (tup && tup.ident.equals(tid.ident))
3942 break;
3945 /* The types of the function arguments [nfparams - 1 .. nfargs]
3946 * now form the tuple argument.
3948 size_t tuple_dim = nfargs - (nfparams - 1);
3950 /* See if existing tuple, and whether it matches or not
3952 RootObject o = (*dedtypes)[tupi];
3953 if (o)
3955 // Existing deduced argument must be a tuple, and must match
3956 Tuple tup = isTuple(o);
3957 if (!tup || tup.objects.dim != tuple_dim)
3959 result = MATCH.nomatch;
3960 return;
3962 for (size_t i = 0; i < tuple_dim; i++)
3964 Parameter arg = t.parameterList[nfparams - 1 + i];
3965 if (!arg.type.equals(tup.objects[i]))
3967 result = MATCH.nomatch;
3968 return;
3972 else
3974 // Create new tuple
3975 auto tup = new Tuple(tuple_dim);
3976 for (size_t i = 0; i < tuple_dim; i++)
3978 Parameter arg = t.parameterList[nfparams - 1 + i];
3979 tup.objects[i] = arg.type;
3981 (*dedtypes)[tupi] = tup;
3983 nfparams--; // don't consider the last parameter for type deduction
3984 goto L2;
3988 if (nfargs != nfparams)
3990 result = MATCH.nomatch;
3991 return;
3994 assert(nfparams <= tp.parameterList.length);
3995 foreach (i, ap; tp.parameterList)
3997 if (i == nfparams)
3998 break;
4000 Parameter a = t.parameterList[i];
4002 if (!a.isCovariant(t.isref, ap) ||
4003 !deduceType(a.type, sc, ap.type, parameters, dedtypes))
4005 result = MATCH.nomatch;
4006 return;
4010 visit(cast(Type)t);
4013 override void visit(TypeIdentifier t)
4015 // Extra check
4016 if (tparam && tparam.ty == Tident)
4018 TypeIdentifier tp = cast(TypeIdentifier)tparam;
4019 for (size_t i = 0; i < t.idents.dim; i++)
4021 RootObject id1 = t.idents[i];
4022 RootObject id2 = tp.idents[i];
4023 if (!id1.equals(id2))
4025 result = MATCH.nomatch;
4026 return;
4030 visit(cast(Type)t);
4033 override void visit(TypeInstance t)
4035 // Extra check
4036 if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl)
4038 TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
4039 assert(tempdecl);
4041 TypeInstance tp = cast(TypeInstance)tparam;
4043 //printf("tempinst.tempdecl = %p\n", tempdecl);
4044 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
4045 if (!tp.tempinst.tempdecl)
4047 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
4049 /* Handle case of:
4050 * template Foo(T : sa!(T), alias sa)
4052 size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
4053 if (i == IDX_NOTFOUND)
4055 /* Didn't find it as a parameter identifier. Try looking
4056 * it up and seeing if is an alias.
4057 * https://issues.dlang.org/show_bug.cgi?id=1454
4059 auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name);
4060 Type tx;
4061 Expression e;
4062 Dsymbol s;
4063 tid.resolve(tp.loc, sc, e, tx, s);
4064 if (tx)
4066 s = tx.toDsymbol(sc);
4067 if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null)
4069 // https://issues.dlang.org/show_bug.cgi?id=14290
4070 // Try to match with ti.tempecl,
4071 // only when ti is an enclosing instance.
4072 Dsymbol p = sc.parent;
4073 while (p && p != ti)
4074 p = p.parent;
4075 if (p)
4076 s = ti.tempdecl;
4079 if (s)
4081 s = s.toAlias();
4082 TemplateDeclaration td = s.isTemplateDeclaration();
4083 if (td)
4085 if (td.overroot)
4086 td = td.overroot;
4087 for (; td; td = td.overnext)
4089 if (td == tempdecl)
4090 goto L2;
4094 goto Lnomatch;
4096 TemplateParameter tpx = (*parameters)[i];
4097 if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
4098 goto Lnomatch;
4100 else if (tempdecl != tp.tempinst.tempdecl)
4101 goto Lnomatch;
4104 for (size_t i = 0; 1; i++)
4106 //printf("\ttest: tempinst.tiargs[%d]\n", i);
4107 RootObject o1 = null;
4108 if (i < t.tempinst.tiargs.dim)
4109 o1 = (*t.tempinst.tiargs)[i];
4110 else if (i < t.tempinst.tdtypes.dim && i < tp.tempinst.tiargs.dim)
4112 // Pick up default arg
4113 o1 = t.tempinst.tdtypes[i];
4115 else if (i >= tp.tempinst.tiargs.dim)
4116 break;
4118 if (i >= tp.tempinst.tiargs.dim)
4120 size_t dim = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
4121 while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
4123 i++;
4125 if (i >= dim)
4126 break; // match if all remained parameters are dependent
4127 goto Lnomatch;
4130 RootObject o2 = (*tp.tempinst.tiargs)[i];
4131 Type t2 = isType(o2);
4133 size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.dim - 1)
4134 ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
4135 if (j != IDX_NOTFOUND && j == parameters.dim - 1 &&
4136 (*parameters)[j].isTemplateTupleParameter())
4138 /* Given:
4139 * struct A(B...) {}
4140 * alias A!(int, float) X;
4141 * static if (is(X Y == A!(Z), Z...)) {}
4142 * deduce that Z is a tuple(int, float)
4145 /* Create tuple from remaining args
4147 size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.dim : t.tempinst.tdtypes.dim) - i;
4148 auto vt = new Tuple(vtdim);
4149 for (size_t k = 0; k < vtdim; k++)
4151 RootObject o;
4152 if (k < t.tempinst.tiargs.dim)
4153 o = (*t.tempinst.tiargs)[i + k];
4154 else // Pick up default arg
4155 o = t.tempinst.tdtypes[i + k];
4156 vt.objects[k] = o;
4159 Tuple v = cast(Tuple)(*dedtypes)[j];
4160 if (v)
4162 if (!match(v, vt))
4163 goto Lnomatch;
4165 else
4166 (*dedtypes)[j] = vt;
4167 break;
4169 else if (!o1)
4170 break;
4172 Type t1 = isType(o1);
4173 Dsymbol s1 = isDsymbol(o1);
4174 Dsymbol s2 = isDsymbol(o2);
4175 Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
4176 Expression e2 = isExpression(o2);
4177 version (none)
4179 Tuple v1 = isTuple(o1);
4180 Tuple v2 = isTuple(o2);
4181 if (t1)
4182 printf("t1 = %s\n", t1.toChars());
4183 if (t2)
4184 printf("t2 = %s\n", t2.toChars());
4185 if (e1)
4186 printf("e1 = %s\n", e1.toChars());
4187 if (e2)
4188 printf("e2 = %s\n", e2.toChars());
4189 if (s1)
4190 printf("s1 = %s\n", s1.toChars());
4191 if (s2)
4192 printf("s2 = %s\n", s2.toChars());
4193 if (v1)
4194 printf("v1 = %s\n", v1.toChars());
4195 if (v2)
4196 printf("v2 = %s\n", v2.toChars());
4199 if (t1 && t2)
4201 if (!deduceType(t1, sc, t2, parameters, dedtypes))
4202 goto Lnomatch;
4204 else if (e1 && e2)
4207 e1 = e1.ctfeInterpret();
4209 /* If it is one of the template parameters for this template,
4210 * we should not attempt to interpret it. It already has a value.
4212 if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
4215 * (T:Number!(e2), int e2)
4217 j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters);
4218 if (j != IDX_NOTFOUND)
4219 goto L1;
4220 // The template parameter was not from this template
4221 // (it may be from a parent template, for example)
4224 e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
4225 e2 = e2.ctfeInterpret();
4227 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
4228 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
4229 if (!e1.equals(e2))
4231 if (!e2.implicitConvTo(e1.type))
4232 goto Lnomatch;
4234 e2 = e2.implicitCastTo(sc, e1.type);
4235 e2 = e2.ctfeInterpret();
4236 if (!e1.equals(e2))
4237 goto Lnomatch;
4240 else if (e1 && t2 && t2.ty == Tident)
4242 j = templateParameterLookup(t2, parameters);
4244 if (j == IDX_NOTFOUND)
4246 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4247 if (e2)
4248 goto Le;
4249 goto Lnomatch;
4251 if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
4252 goto Lnomatch;
4254 else if (s1 && s2)
4257 if (!s1.equals(s2))
4258 goto Lnomatch;
4260 else if (s1 && t2 && t2.ty == Tident)
4262 j = templateParameterLookup(t2, parameters);
4263 if (j == IDX_NOTFOUND)
4265 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4266 if (s2)
4267 goto Ls;
4268 goto Lnomatch;
4270 if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
4271 goto Lnomatch;
4273 else
4274 goto Lnomatch;
4277 visit(cast(Type)t);
4278 return;
4280 Lnomatch:
4281 //printf("no match\n");
4282 result = MATCH.nomatch;
4285 override void visit(TypeStruct t)
4287 /* If this struct is a template struct, and we're matching
4288 * it against a template instance, convert the struct type
4289 * to a template instance, too, and try again.
4291 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4293 if (tparam && tparam.ty == Tinstance)
4295 if (ti && ti.toAlias() == t.sym)
4297 auto tx = new TypeInstance(Loc.initial, ti);
4298 auto m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4299 // if we have a no match we still need to check alias this
4300 if (m != MATCH.nomatch)
4302 result = m;
4303 return;
4307 /* Match things like:
4308 * S!(T).foo
4310 TypeInstance tpi = cast(TypeInstance)tparam;
4311 if (tpi.idents.dim)
4313 RootObject id = tpi.idents[tpi.idents.dim - 1];
4314 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4316 Type tparent = t.sym.parent.getType();
4317 if (tparent)
4319 /* Slice off the .foo in S!(T).foo
4321 tpi.idents.dim--;
4322 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4323 tpi.idents.dim++;
4324 return;
4330 // Extra check
4331 if (tparam && tparam.ty == Tstruct)
4333 TypeStruct tp = cast(TypeStruct)tparam;
4335 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4336 if (wm && t.deduceWild(tparam, false))
4338 result = MATCH.constant;
4339 return;
4341 result = t.implicitConvTo(tp);
4342 return;
4344 visit(cast(Type)t);
4347 override void visit(TypeEnum t)
4349 // Extra check
4350 if (tparam && tparam.ty == Tenum)
4352 TypeEnum tp = cast(TypeEnum)tparam;
4353 if (t.sym == tp.sym)
4354 visit(cast(Type)t);
4355 else
4356 result = MATCH.nomatch;
4357 return;
4359 Type tb = t.toBasetype();
4360 if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray)
4362 result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
4363 if (result == MATCH.exact)
4364 result = MATCH.convert;
4365 return;
4367 visit(cast(Type)t);
4370 /* Helper for TypeClass.deduceType().
4371 * Classes can match with implicit conversion to a base class or interface.
4372 * This is complicated, because there may be more than one base class which
4373 * matches. In such cases, one or more parameters remain ambiguous.
4374 * For example,
4376 * interface I(X, Y) {}
4377 * class C : I(uint, double), I(char, double) {}
4378 * C x;
4379 * foo(T, U)( I!(T, U) x)
4381 * deduces that U is double, but T remains ambiguous (could be char or uint).
4383 * Given a baseclass b, and initial deduced types 'dedtypes', this function
4384 * tries to match tparam with b, and also tries all base interfaces of b.
4385 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
4386 * types are ANDed with the current 'best' estimate for dedtypes.
4388 static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
4390 TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
4391 if (parti)
4393 // Make a temporary copy of dedtypes so we don't destroy it
4394 auto tmpdedtypes = new Objects(dedtypes.dim);
4395 memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.dim * (void*).sizeof);
4397 auto t = new TypeInstance(Loc.initial, parti);
4398 MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
4399 if (m > MATCH.nomatch)
4401 // If this is the first ever match, it becomes our best estimate
4402 if (numBaseClassMatches == 0)
4403 memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.dim * (void*).sizeof);
4404 else
4405 for (size_t k = 0; k < tmpdedtypes.dim; ++k)
4407 // If we've found more than one possible type for a parameter,
4408 // mark it as unknown.
4409 if ((*tmpdedtypes)[k] != (*best)[k])
4410 (*best)[k] = (*dedtypes)[k];
4412 ++numBaseClassMatches;
4416 // Now recursively test the inherited interfaces
4417 foreach (ref bi; b.baseInterfaces)
4419 deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4423 override void visit(TypeClass t)
4425 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
4427 /* If this class is a template class, and we're matching
4428 * it against a template instance, convert the class type
4429 * to a template instance, too, and try again.
4431 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4433 if (tparam && tparam.ty == Tinstance)
4435 if (ti && ti.toAlias() == t.sym)
4437 auto tx = new TypeInstance(Loc.initial, ti);
4438 MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4439 // Even if the match fails, there is still a chance it could match
4440 // a base class.
4441 if (m != MATCH.nomatch)
4443 result = m;
4444 return;
4448 /* Match things like:
4449 * S!(T).foo
4451 TypeInstance tpi = cast(TypeInstance)tparam;
4452 if (tpi.idents.dim)
4454 RootObject id = tpi.idents[tpi.idents.dim - 1];
4455 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4457 Type tparent = t.sym.parent.getType();
4458 if (tparent)
4460 /* Slice off the .foo in S!(T).foo
4462 tpi.idents.dim--;
4463 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4464 tpi.idents.dim++;
4465 return;
4470 // If it matches exactly or via implicit conversion, we're done
4471 visit(cast(Type)t);
4472 if (result != MATCH.nomatch)
4473 return;
4475 /* There is still a chance to match via implicit conversion to
4476 * a base class or interface. Because there could be more than one such
4477 * match, we need to check them all.
4480 int numBaseClassMatches = 0; // Have we found an interface match?
4482 // Our best guess at dedtypes
4483 auto best = new Objects(dedtypes.dim);
4485 ClassDeclaration s = t.sym;
4486 while (s && s.baseclasses.dim > 0)
4488 // Test the base class
4489 deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4491 // Test the interfaces inherited by the base class
4492 foreach (b; s.interfaces)
4494 deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4496 s = (*s.baseclasses)[0].sym;
4499 if (numBaseClassMatches == 0)
4501 result = MATCH.nomatch;
4502 return;
4505 // If we got at least one match, copy the known types into dedtypes
4506 memcpy(dedtypes.tdata(), best.tdata(), best.dim * (void*).sizeof);
4507 result = MATCH.convert;
4508 return;
4511 // Extra check
4512 if (tparam && tparam.ty == Tclass)
4514 TypeClass tp = cast(TypeClass)tparam;
4516 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4517 if (wm && t.deduceWild(tparam, false))
4519 result = MATCH.constant;
4520 return;
4522 result = t.implicitConvTo(tp);
4523 return;
4525 visit(cast(Type)t);
4528 override void visit(Expression e)
4530 //printf("Expression.deduceType(e = %s)\n", e.toChars());
4531 size_t i = templateParameterLookup(tparam, parameters);
4532 if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.dim > 0)
4534 if (e == emptyArrayElement && tparam.ty == Tarray)
4536 Type tn = (cast(TypeNext)tparam).next;
4537 result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4538 return;
4540 e.type.accept(this);
4541 return;
4544 TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
4545 if (!tp)
4546 return; // nomatch
4548 if (e == emptyArrayElement)
4550 if ((*dedtypes)[i])
4552 result = MATCH.exact;
4553 return;
4555 if (tp.defaultType)
4557 tp.defaultType.accept(this);
4558 return;
4562 /* Returns `true` if `t` is a reference type, or an array of reference types
4564 bool isTopRef(Type t)
4566 auto tb = t.baseElemOf();
4567 return tb.ty == Tclass ||
4568 tb.ty == Taarray ||
4569 tb.ty == Tstruct && tb.hasPointers();
4572 Type at = cast(Type)(*dedtypes)[i];
4573 Type tt;
4574 if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
4576 *wm |= wx;
4577 result = MATCH.constant;
4579 else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
4581 result = m;
4583 else if (!isTopRef(e.type))
4585 /* https://issues.dlang.org/show_bug.cgi?id=15653
4586 * In IFTI, recognize top-qualifier conversions
4587 * through the value copy, e.g.
4588 * int --> immutable(int)
4589 * immutable(string[]) --> immutable(string)[]
4591 tt = e.type.mutableOf();
4592 result = MATCH.convert;
4594 else
4595 return; // nomatch
4597 // expression vs (none)
4598 if (!at)
4600 (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
4601 return;
4604 TypeDeduced xt = null;
4605 if (at.ty == Tnone)
4607 xt = cast(TypeDeduced)at;
4608 at = xt.tded;
4611 // From previous matched expressions to current deduced type
4612 MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch;
4614 // From current expressions to previous deduced type
4615 Type pt = at.addMod(tparam.mod);
4616 if (*wm)
4617 pt = pt.substWildTo(*wm);
4618 MATCH match2 = e.implicitConvTo(pt);
4620 if (match1 > MATCH.nomatch && match2 > MATCH.nomatch)
4622 if (at.implicitConvTo(tt) == MATCH.nomatch)
4623 match1 = MATCH.nomatch; // Prefer at
4624 else if (tt.implicitConvTo(at) == MATCH.nomatch)
4625 match2 = MATCH.nomatch; // Prefer tt
4626 else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod)
4628 if (!tt.isMutable() && !at.isMutable())
4629 tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod));
4630 else if (tt.isMutable())
4632 if (at.mod == 0) // Prefer unshared
4633 match1 = MATCH.nomatch;
4634 else
4635 match2 = MATCH.nomatch;
4637 else if (at.isMutable())
4639 if (tt.mod == 0) // Prefer unshared
4640 match2 = MATCH.nomatch;
4641 else
4642 match1 = MATCH.nomatch;
4644 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
4646 else
4648 match1 = MATCH.nomatch;
4649 match2 = MATCH.nomatch;
4652 if (match1 > MATCH.nomatch)
4654 // Prefer current match: tt
4655 if (xt)
4656 xt.update(tt, e, tparam);
4657 else
4658 (*dedtypes)[i] = tt;
4659 result = match1;
4660 return;
4662 if (match2 > MATCH.nomatch)
4664 // Prefer previous match: (*dedtypes)[i]
4665 if (xt)
4666 xt.update(e, tparam);
4667 result = match2;
4668 return;
4671 /* Deduce common type
4673 if (Type t = rawTypeMerge(at, tt))
4675 if (xt)
4676 xt.update(t, e, tparam);
4677 else
4678 (*dedtypes)[i] = t;
4680 pt = tt.addMod(tparam.mod);
4681 if (*wm)
4682 pt = pt.substWildTo(*wm);
4683 result = e.implicitConvTo(pt);
4684 return;
4687 result = MATCH.nomatch;
4690 MATCH deduceEmptyArrayElement()
4692 if (!emptyArrayElement)
4694 emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy
4695 emptyArrayElement.type = Type.tvoid;
4697 assert(tparam.ty == Tarray);
4699 Type tn = (cast(TypeNext)tparam).next;
4700 return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4703 override void visit(NullExp e)
4705 if (tparam.ty == Tarray && e.type.ty == Tnull)
4707 // tparam:T[] <- e:null (void[])
4708 result = deduceEmptyArrayElement();
4709 return;
4711 visit(cast(Expression)e);
4714 override void visit(StringExp e)
4716 Type taai;
4717 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
4719 // Consider compile-time known boundaries
4720 e.type.nextOf().sarrayOf(e.len).accept(this);
4721 return;
4723 visit(cast(Expression)e);
4726 override void visit(ArrayLiteralExp e)
4728 // https://issues.dlang.org/show_bug.cgi?id=20092
4729 if (e.elements && e.elements.dim && e.type.toBasetype().nextOf().ty == Tvoid)
4731 result = deduceEmptyArrayElement();
4732 return;
4734 if ((!e.elements || !e.elements.dim) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray)
4736 // tparam:T[] <- e:[] (void[])
4737 result = deduceEmptyArrayElement();
4738 return;
4741 if (tparam.ty == Tarray && e.elements && e.elements.dim)
4743 Type tn = (cast(TypeDArray)tparam).next;
4744 result = MATCH.exact;
4745 if (e.basis)
4747 MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm);
4748 if (m < result)
4749 result = m;
4751 foreach (el; *e.elements)
4753 if (result == MATCH.nomatch)
4754 break;
4755 if (!el)
4756 continue;
4757 MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
4758 if (m < result)
4759 result = m;
4761 return;
4764 Type taai;
4765 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
4767 // Consider compile-time known boundaries
4768 e.type.nextOf().sarrayOf(e.elements.dim).accept(this);
4769 return;
4771 visit(cast(Expression)e);
4774 override void visit(AssocArrayLiteralExp e)
4776 if (tparam.ty == Taarray && e.keys && e.keys.dim)
4778 TypeAArray taa = cast(TypeAArray)tparam;
4779 result = MATCH.exact;
4780 foreach (i, key; *e.keys)
4782 MATCH m1 = deduceType(key, sc, taa.index, parameters, dedtypes, wm);
4783 if (m1 < result)
4784 result = m1;
4785 if (result == MATCH.nomatch)
4786 break;
4787 MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm);
4788 if (m2 < result)
4789 result = m2;
4790 if (result == MATCH.nomatch)
4791 break;
4793 return;
4795 visit(cast(Expression)e);
4798 override void visit(FuncExp e)
4800 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
4801 if (e.td)
4803 Type to = tparam;
4804 if (!to.nextOf())
4805 return;
4806 auto tof = to.nextOf().isTypeFunction();
4807 if (!tof)
4808 return;
4810 // Parameter types inference from 'tof'
4811 assert(e.td._scope);
4812 TypeFunction tf = cast(TypeFunction)e.fd.type;
4813 //printf("\ttof = %s\n", tof.toChars());
4814 //printf("\ttf = %s\n", tf.toChars());
4815 const dim = tf.parameterList.length;
4817 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
4818 return;
4820 auto tiargs = new Objects();
4821 tiargs.reserve(e.td.parameters.dim);
4823 foreach (tp; *e.td.parameters)
4825 size_t u = 0;
4826 foreach (i, p; tf.parameterList)
4828 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4829 break;
4830 ++u;
4832 assert(u < dim);
4833 Parameter pto = tof.parameterList[u];
4834 if (!pto)
4835 break;
4836 Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
4837 if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.dim]))
4838 return;
4839 t = t.typeSemantic(e.loc, sc);
4840 if (t.ty == Terror)
4841 return;
4842 tiargs.push(t);
4845 // Set target of return type inference
4846 if (!tf.next && tof.next)
4847 e.fd.treq = tparam;
4849 auto ti = new TemplateInstance(e.loc, e.td, tiargs);
4850 Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope);
4852 // Reset inference target for the later re-semantic
4853 e.fd.treq = null;
4855 if (ex.op == EXP.error)
4856 return;
4857 if (ex.op != EXP.function_)
4858 return;
4859 visit(ex.type);
4860 return;
4863 Type t = e.type;
4865 if (t.ty == Tdelegate && tparam.ty == Tpointer)
4866 return;
4868 // Allow conversion from implicit function pointer to delegate
4869 if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
4871 TypeFunction tf = cast(TypeFunction)t.nextOf();
4872 t = (new TypeDelegate(tf)).merge();
4874 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
4875 visit(t);
4878 override void visit(SliceExp e)
4880 Type taai;
4881 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
4883 // Consider compile-time known boundaries
4884 if (Type tsa = toStaticArrayType(e))
4886 tsa.accept(this);
4887 if (result > MATCH.convert)
4888 result = MATCH.convert; // match with implicit conversion at most
4889 return;
4892 visit(cast(Expression)e);
4895 override void visit(CommaExp e)
4897 e.e2.accept(this);
4901 scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
4902 if (Type t = isType(o))
4903 t.accept(v);
4904 else if (Expression e = isExpression(o))
4906 assert(wm);
4907 e.accept(v);
4909 else
4910 assert(0);
4911 return v.result;
4914 /***********************************************************
4915 * Check whether the type t representation relies on one or more the template parameters.
4916 * Params:
4917 * t = Tested type, if null, returns false.
4918 * tparams = Template parameters.
4919 * iStart = Start index of tparams to limit the tested parameters. If it's
4920 * nonzero, tparams[0..iStart] will be excluded from the test target.
4922 bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
4924 return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.dim]);
4927 /***********************************************************
4928 * Check whether the type t representation relies on one or more the template parameters.
4929 * Params:
4930 * t = Tested type, if null, returns false.
4931 * tparams = Template parameters.
4933 private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
4935 bool visitVector(TypeVector t)
4937 return t.basetype.reliesOnTemplateParameters(tparams);
4940 bool visitAArray(TypeAArray t)
4942 return t.next.reliesOnTemplateParameters(tparams) ||
4943 t.index.reliesOnTemplateParameters(tparams);
4946 bool visitFunction(TypeFunction t)
4948 foreach (i, fparam; t.parameterList)
4950 if (fparam.type.reliesOnTemplateParameters(tparams))
4951 return true;
4953 return t.next.reliesOnTemplateParameters(tparams);
4956 bool visitIdentifier(TypeIdentifier t)
4958 foreach (tp; tparams)
4960 if (tp.ident.equals(t.ident))
4961 return true;
4963 return false;
4966 bool visitInstance(TypeInstance t)
4968 foreach (tp; tparams)
4970 if (t.tempinst.name == tp.ident)
4971 return true;
4974 if (t.tempinst.tiargs)
4975 foreach (arg; *t.tempinst.tiargs)
4977 if (Type ta = isType(arg))
4979 if (ta.reliesOnTemplateParameters(tparams))
4980 return true;
4984 return false;
4987 bool visitTypeof(TypeTypeof t)
4989 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
4990 return t.exp.reliesOnTemplateParameters(tparams);
4993 bool visitTuple(TypeTuple t)
4995 if (t.arguments)
4996 foreach (arg; *t.arguments)
4998 if (arg.type.reliesOnTemplateParameters(tparams))
4999 return true;
5002 return false;
5005 if (!t)
5006 return false;
5008 Type tb = t.toBasetype();
5009 switch (tb.ty)
5011 case Tvector: return visitVector(tb.isTypeVector());
5012 case Taarray: return visitAArray(tb.isTypeAArray());
5013 case Tfunction: return visitFunction(tb.isTypeFunction());
5014 case Tident: return visitIdentifier(tb.isTypeIdentifier());
5015 case Tinstance: return visitInstance(tb.isTypeInstance());
5016 case Ttypeof: return visitTypeof(tb.isTypeTypeof());
5017 case Ttuple: return visitTuple(tb.isTypeTuple());
5018 case Tenum: return false;
5019 default: return tb.nextOf().reliesOnTemplateParameters(tparams);
5023 /***********************************************************
5024 * Check whether the expression representation relies on one or more the template parameters.
5025 * Params:
5026 * e = expression to test
5027 * tparams = Template parameters.
5028 * Returns:
5029 * true if it does
5031 private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
5033 extern (C++) final class ReliesOnTemplateParameters : Visitor
5035 alias visit = Visitor.visit;
5036 public:
5037 TemplateParameter[] tparams;
5038 bool result;
5040 extern (D) this(TemplateParameter[] tparams)
5042 this.tparams = tparams;
5045 override void visit(Expression e)
5047 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
5050 override void visit(IdentifierExp e)
5052 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5053 foreach (tp; tparams)
5055 if (e.ident == tp.ident)
5057 result = true;
5058 return;
5063 override void visit(TupleExp e)
5065 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5066 if (e.exps)
5068 foreach (ea; *e.exps)
5070 ea.accept(this);
5071 if (result)
5072 return;
5077 override void visit(ArrayLiteralExp e)
5079 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5080 if (e.elements)
5082 foreach (el; *e.elements)
5084 el.accept(this);
5085 if (result)
5086 return;
5091 override void visit(AssocArrayLiteralExp e)
5093 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5094 foreach (ek; *e.keys)
5096 ek.accept(this);
5097 if (result)
5098 return;
5100 foreach (ev; *e.values)
5102 ev.accept(this);
5103 if (result)
5104 return;
5108 override void visit(StructLiteralExp e)
5110 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5111 if (e.elements)
5113 foreach (ea; *e.elements)
5115 ea.accept(this);
5116 if (result)
5117 return;
5122 override void visit(TypeExp e)
5124 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5125 result = e.type.reliesOnTemplateParameters(tparams);
5128 override void visit(NewExp e)
5130 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5131 if (e.thisexp)
5132 e.thisexp.accept(this);
5133 result = e.newtype.reliesOnTemplateParameters(tparams);
5134 if (!result && e.arguments)
5136 foreach (ea; *e.arguments)
5138 ea.accept(this);
5139 if (result)
5140 return;
5145 override void visit(NewAnonClassExp e)
5147 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5148 result = true;
5151 override void visit(FuncExp e)
5153 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5154 result = true;
5157 override void visit(TypeidExp e)
5159 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5160 if (auto ea = isExpression(e.obj))
5161 ea.accept(this);
5162 else if (auto ta = isType(e.obj))
5163 result = ta.reliesOnTemplateParameters(tparams);
5166 override void visit(TraitsExp e)
5168 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5169 if (e.args)
5171 foreach (oa; *e.args)
5173 if (auto ea = isExpression(oa))
5174 ea.accept(this);
5175 else if (auto ta = isType(oa))
5176 result = ta.reliesOnTemplateParameters(tparams);
5177 if (result)
5178 return;
5183 override void visit(IsExp e)
5185 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5186 result = e.targ.reliesOnTemplateParameters(tparams);
5189 override void visit(UnaExp e)
5191 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5192 e.e1.accept(this);
5195 override void visit(DotTemplateInstanceExp e)
5197 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5198 visit(cast(UnaExp)e);
5199 if (!result && e.ti.tiargs)
5201 foreach (oa; *e.ti.tiargs)
5203 if (auto ea = isExpression(oa))
5204 ea.accept(this);
5205 else if (auto ta = isType(oa))
5206 result = ta.reliesOnTemplateParameters(tparams);
5207 if (result)
5208 return;
5213 override void visit(CallExp e)
5215 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5216 visit(cast(UnaExp)e);
5217 if (!result && e.arguments)
5219 foreach (ea; *e.arguments)
5221 ea.accept(this);
5222 if (result)
5223 return;
5228 override void visit(CastExp e)
5230 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5231 visit(cast(UnaExp)e);
5232 // e.to can be null for cast() with no type
5233 if (!result && e.to)
5234 result = e.to.reliesOnTemplateParameters(tparams);
5237 override void visit(SliceExp e)
5239 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5240 visit(cast(UnaExp)e);
5241 if (!result && e.lwr)
5242 e.lwr.accept(this);
5243 if (!result && e.upr)
5244 e.upr.accept(this);
5247 override void visit(IntervalExp e)
5249 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5250 e.lwr.accept(this);
5251 if (!result)
5252 e.upr.accept(this);
5255 override void visit(ArrayExp e)
5257 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5258 visit(cast(UnaExp)e);
5259 if (!result && e.arguments)
5261 foreach (ea; *e.arguments)
5262 ea.accept(this);
5266 override void visit(BinExp e)
5268 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5269 e.e1.accept(this);
5270 if (!result)
5271 e.e2.accept(this);
5274 override void visit(CondExp e)
5276 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5277 e.econd.accept(this);
5278 if (!result)
5279 visit(cast(BinExp)e);
5283 scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
5284 e.accept(v);
5285 return v.result;
5288 /***********************************************************
5289 * https://dlang.org/spec/template.html#TemplateParameter
5291 extern (C++) class TemplateParameter : ASTNode
5293 Loc loc;
5294 Identifier ident;
5296 /* True if this is a part of precedent parameter specialization pattern.
5298 * template A(T : X!TL, alias X, TL...) {}
5299 * // X and TL are dependent template parameter
5301 * A dependent template parameter should return MATCH.exact in matchArg()
5302 * to respect the match level of the corresponding precedent parameter.
5304 bool dependent;
5306 /* ======================== TemplateParameter =============================== */
5307 extern (D) this(const ref Loc loc, Identifier ident)
5309 this.loc = loc;
5310 this.ident = ident;
5313 TemplateTypeParameter isTemplateTypeParameter()
5315 return null;
5318 TemplateValueParameter isTemplateValueParameter()
5320 return null;
5323 TemplateAliasParameter isTemplateAliasParameter()
5325 return null;
5328 TemplateThisParameter isTemplateThisParameter()
5330 return null;
5333 TemplateTupleParameter isTemplateTupleParameter()
5335 return null;
5338 abstract TemplateParameter syntaxCopy();
5340 abstract bool declareParameter(Scope* sc);
5342 abstract void print(RootObject oarg, RootObject oded);
5344 abstract RootObject specialization();
5346 abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
5348 abstract bool hasDefaultArg();
5350 override const(char)* toChars() const
5352 return this.ident.toChars();
5355 override DYNCAST dyncast() const pure @nogc nothrow @safe
5357 return DYNCAST.templateparameter;
5360 /* Create dummy argument based on parameter.
5362 abstract RootObject dummyArg();
5364 override void accept(Visitor v)
5366 v.visit(this);
5370 /***********************************************************
5371 * https://dlang.org/spec/template.html#TemplateTypeParameter
5372 * Syntax:
5373 * ident : specType = defaultType
5375 extern (C++) class TemplateTypeParameter : TemplateParameter
5377 Type specType; // if !=null, this is the type specialization
5378 Type defaultType;
5380 extern (D) __gshared Type tdummy = null;
5382 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
5384 super(loc, ident);
5385 this.specType = specType;
5386 this.defaultType = defaultType;
5389 override final TemplateTypeParameter isTemplateTypeParameter()
5391 return this;
5394 override TemplateTypeParameter syntaxCopy()
5396 return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5399 override final bool declareParameter(Scope* sc)
5401 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
5402 auto ti = new TypeIdentifier(loc, ident);
5403 Declaration ad = new AliasDeclaration(loc, ident, ti);
5404 return sc.insert(ad) !is null;
5407 override final void print(RootObject oarg, RootObject oded)
5409 printf(" %s\n", ident.toChars());
5411 Type t = isType(oarg);
5412 Type ta = isType(oded);
5413 assert(ta);
5415 if (specType)
5416 printf("\tSpecialization: %s\n", specType.toChars());
5417 if (defaultType)
5418 printf("\tDefault: %s\n", defaultType.toChars());
5419 printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
5420 printf("\tDeduced Type: %s\n", ta.toChars());
5423 override final RootObject specialization()
5425 return specType;
5428 override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5430 Type t = defaultType;
5431 if (t)
5433 t = t.syntaxCopy();
5434 t = t.typeSemantic(loc, sc); // use the parameter loc
5436 return t;
5439 override final bool hasDefaultArg()
5441 return defaultType !is null;
5444 override final RootObject dummyArg()
5446 Type t = specType;
5447 if (!t)
5449 // Use this for alias-parameter's too (?)
5450 if (!tdummy)
5451 tdummy = new TypeIdentifier(loc, ident);
5452 t = tdummy;
5454 return t;
5457 override void accept(Visitor v)
5459 v.visit(this);
5463 /***********************************************************
5464 * https://dlang.org/spec/template.html#TemplateThisParameter
5465 * Syntax:
5466 * this ident : specType = defaultType
5468 extern (C++) final class TemplateThisParameter : TemplateTypeParameter
5470 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
5472 super(loc, ident, specType, defaultType);
5475 override TemplateThisParameter isTemplateThisParameter()
5477 return this;
5480 override TemplateThisParameter syntaxCopy()
5482 return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5485 override void accept(Visitor v)
5487 v.visit(this);
5491 /***********************************************************
5492 * https://dlang.org/spec/template.html#TemplateValueParameter
5493 * Syntax:
5494 * valType ident : specValue = defaultValue
5496 extern (C++) final class TemplateValueParameter : TemplateParameter
5498 Type valType;
5499 Expression specValue;
5500 Expression defaultValue;
5502 extern (D) __gshared Expression[void*] edummies;
5504 extern (D) this(const ref Loc loc, Identifier ident, Type valType,
5505 Expression specValue, Expression defaultValue)
5507 super(loc, ident);
5508 this.valType = valType;
5509 this.specValue = specValue;
5510 this.defaultValue = defaultValue;
5513 override TemplateValueParameter isTemplateValueParameter()
5515 return this;
5518 override TemplateValueParameter syntaxCopy()
5520 return new TemplateValueParameter(loc, ident,
5521 valType.syntaxCopy(),
5522 specValue ? specValue.syntaxCopy() : null,
5523 defaultValue ? defaultValue.syntaxCopy() : null);
5526 override bool declareParameter(Scope* sc)
5529 Do type semantic earlier.
5531 This means for certain erroneous value parameters
5532 their "type" can be known earlier and thus a better
5533 error message given.
5535 For example:
5536 `template test(x* x) {}`
5537 now yields "undefined identifier" rather than the opaque
5538 "variable `x` is used as a type".
5540 if (valType)
5541 valType = valType.typeSemantic(loc, sc);
5542 auto v = new VarDeclaration(loc, valType, ident, null);
5543 v.storage_class = STC.templateparameter;
5544 return sc.insert(v) !is null;
5547 override void print(RootObject oarg, RootObject oded)
5549 printf(" %s\n", ident.toChars());
5550 Expression ea = isExpression(oded);
5551 if (specValue)
5552 printf("\tSpecialization: %s\n", specValue.toChars());
5553 printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
5556 override RootObject specialization()
5558 return specValue;
5561 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5563 Expression e = defaultValue;
5564 if (e)
5566 e = e.syntaxCopy();
5567 uint olderrs = global.errors;
5568 if ((e = e.expressionSemantic(sc)) is null)
5569 return null;
5570 if ((e = resolveProperties(sc, e)) is null)
5571 return null;
5572 e = e.resolveLoc(instLoc, sc); // use the instantiated loc
5573 e = e.optimize(WANTvalue);
5574 if (global.errors != olderrs)
5575 e = ErrorExp.get();
5577 return e;
5580 override bool hasDefaultArg()
5582 return defaultValue !is null;
5585 override RootObject dummyArg()
5587 Expression e = specValue;
5588 if (!e)
5590 // Create a dummy value
5591 auto pe = cast(void*)valType in edummies;
5592 if (!pe)
5594 e = valType.defaultInit(Loc.initial);
5595 edummies[cast(void*)valType] = e;
5597 else
5598 e = *pe;
5600 return e;
5603 override void accept(Visitor v)
5605 v.visit(this);
5609 /***********************************************************
5610 * https://dlang.org/spec/template.html#TemplateAliasParameter
5611 * Syntax:
5612 * specType ident : specAlias = defaultAlias
5614 extern (C++) final class TemplateAliasParameter : TemplateParameter
5616 Type specType;
5617 RootObject specAlias;
5618 RootObject defaultAlias;
5620 extern (D) __gshared Dsymbol sdummy = null;
5622 extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias)
5624 super(loc, ident);
5625 this.specType = specType;
5626 this.specAlias = specAlias;
5627 this.defaultAlias = defaultAlias;
5630 override TemplateAliasParameter isTemplateAliasParameter()
5632 return this;
5635 override TemplateAliasParameter syntaxCopy()
5637 return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
5640 override bool declareParameter(Scope* sc)
5642 auto ti = new TypeIdentifier(loc, ident);
5643 Declaration ad = new AliasDeclaration(loc, ident, ti);
5644 return sc.insert(ad) !is null;
5647 override void print(RootObject oarg, RootObject oded)
5649 printf(" %s\n", ident.toChars());
5650 Dsymbol sa = isDsymbol(oded);
5651 assert(sa);
5652 printf("\tParameter alias: %s\n", sa.toChars());
5655 override RootObject specialization()
5657 return specAlias;
5660 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5662 RootObject da = defaultAlias;
5663 Type ta = isType(defaultAlias);
5664 if (ta)
5666 if (ta.ty == Tinstance)
5668 // If the default arg is a template, instantiate for each type
5669 da = ta.syntaxCopy();
5673 RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc
5674 return o;
5677 override bool hasDefaultArg()
5679 return defaultAlias !is null;
5682 override RootObject dummyArg()
5684 RootObject s = specAlias;
5685 if (!s)
5687 if (!sdummy)
5688 sdummy = new Dsymbol();
5689 s = sdummy;
5691 return s;
5694 override void accept(Visitor v)
5696 v.visit(this);
5700 /***********************************************************
5701 * https://dlang.org/spec/template.html#TemplateSequenceParameter
5702 * Syntax:
5703 * ident ...
5705 extern (C++) final class TemplateTupleParameter : TemplateParameter
5707 extern (D) this(const ref Loc loc, Identifier ident)
5709 super(loc, ident);
5712 override TemplateTupleParameter isTemplateTupleParameter()
5714 return this;
5717 override TemplateTupleParameter syntaxCopy()
5719 return new TemplateTupleParameter(loc, ident);
5722 override bool declareParameter(Scope* sc)
5724 auto ti = new TypeIdentifier(loc, ident);
5725 Declaration ad = new AliasDeclaration(loc, ident, ti);
5726 return sc.insert(ad) !is null;
5729 override void print(RootObject oarg, RootObject oded)
5731 printf(" %s... [", ident.toChars());
5732 Tuple v = isTuple(oded);
5733 assert(v);
5735 //printf("|%d| ", v.objects.dim);
5736 foreach (i, o; v.objects)
5738 if (i)
5739 printf(", ");
5741 Dsymbol sa = isDsymbol(o);
5742 if (sa)
5743 printf("alias: %s", sa.toChars());
5744 Type ta = isType(o);
5745 if (ta)
5746 printf("type: %s", ta.toChars());
5747 Expression ea = isExpression(o);
5748 if (ea)
5749 printf("exp: %s", ea.toChars());
5751 assert(!isTuple(o)); // no nested Tuple arguments
5753 printf("]\n");
5756 override RootObject specialization()
5758 return null;
5761 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5763 return null;
5766 override bool hasDefaultArg()
5768 return false;
5771 override RootObject dummyArg()
5773 return null;
5776 override void accept(Visitor v)
5778 v.visit(this);
5782 /***********************************************************
5783 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
5784 * Given:
5785 * foo!(args) =>
5786 * name = foo
5787 * tiargs = args
5789 extern (C++) class TemplateInstance : ScopeDsymbol
5791 Identifier name;
5793 // Array of Types/Expressions of template
5794 // instance arguments [int*, char, 10*10]
5795 Objects* tiargs;
5797 // Array of Types/Expressions corresponding
5798 // to TemplateDeclaration.parameters
5799 // [int, char, 100]
5800 Objects tdtypes;
5802 // Modules imported by this template instance
5803 Modules importedModules;
5805 Dsymbol tempdecl; // referenced by foo.bar.abc
5806 Dsymbol enclosing; // if referencing local symbols, this is the context
5807 Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
5808 TemplateInstance inst; // refer to existing instance
5809 ScopeDsymbol argsym; // argument symbol table
5810 size_t hash; // cached result of toHash()
5811 Expressions* fargs; // for function template, these are the function arguments
5813 TemplateInstances* deferred;
5815 Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
5817 // Used to determine the instance needs code generation.
5818 // Note that these are inaccurate until semantic analysis phase completed.
5819 TemplateInstance tinst; // enclosing template instance
5820 TemplateInstance tnext; // non-first instantiated instances
5821 Module minst; // the top module that instantiated this instance
5823 private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
5824 ubyte inuse; // for recursive expansion detection
5826 private enum Flag : uint
5828 semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
5829 havetempdecl = semantictiargsdone >> 1,
5830 gagged = semantictiargsdone >> 2,
5831 available = gagged - 1 // always last flag minus one, 1s for all available bits
5834 extern(D) final @safe @property pure nothrow @nogc
5836 ushort nest() const { return _nest & Flag.available; }
5837 void nestUp() { assert(nest() < Flag.available); ++_nest; }
5838 void nestDown() { assert(nest() > 0); --_nest; }
5839 /// has semanticTiargs() been done?
5840 bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
5841 void semantictiargsdone(bool x)
5843 if (x) _nest |= Flag.semantictiargsdone;
5844 else _nest &= ~Flag.semantictiargsdone;
5846 /// if used second constructor
5847 bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
5848 void havetempdecl(bool x)
5850 if (x) _nest |= Flag.havetempdecl;
5851 else _nest &= ~Flag.havetempdecl;
5853 /// if the instantiation is done with error gagging
5854 bool gagged() const { return (_nest & Flag.gagged) != 0; }
5855 void gagged(bool x)
5857 if (x) _nest |= Flag.gagged;
5858 else _nest &= ~Flag.gagged;
5862 extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs)
5864 super(loc, null);
5865 static if (LOG)
5867 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
5869 this.name = ident;
5870 this.tiargs = tiargs;
5873 /*****************
5874 * This constructor is only called when we figured out which function
5875 * template to instantiate.
5877 extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs)
5879 super(loc, null);
5880 static if (LOG)
5882 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
5884 this.name = td.ident;
5885 this.tiargs = tiargs;
5886 this.tempdecl = td;
5887 this.semantictiargsdone = true;
5888 this.havetempdecl = true;
5889 assert(tempdecl._scope);
5892 extern (D) static Objects* arraySyntaxCopy(Objects* objs)
5894 Objects* a = null;
5895 if (objs)
5897 a = new Objects(objs.dim);
5898 foreach (i, o; *objs)
5899 (*a)[i] = objectSyntaxCopy(o);
5901 return a;
5904 override TemplateInstance syntaxCopy(Dsymbol s)
5906 TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
5907 ti.tiargs = arraySyntaxCopy(tiargs);
5908 TemplateDeclaration td;
5909 if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
5910 td.ScopeDsymbol.syntaxCopy(ti);
5911 else
5912 ScopeDsymbol.syntaxCopy(ti);
5913 return ti;
5916 // resolve real symbol
5917 override final Dsymbol toAlias()
5919 static if (LOG)
5921 printf("TemplateInstance.toAlias()\n");
5923 if (!inst)
5925 // Maybe we can resolve it
5926 if (_scope)
5928 dsymbolSemantic(this, _scope);
5930 if (!inst)
5932 error("cannot resolve forward reference");
5933 errors = true;
5934 return this;
5938 if (inst != this)
5939 return inst.toAlias();
5941 if (aliasdecl)
5943 return aliasdecl.toAlias();
5946 return inst;
5949 override const(char)* kind() const
5951 return "template instance";
5954 override bool oneMember(Dsymbol* ps, Identifier ident)
5956 *ps = null;
5957 return true;
5960 override const(char)* toChars() const
5962 OutBuffer buf;
5963 toCBufferInstance(this, &buf);
5964 return buf.extractChars();
5967 override final const(char)* toPrettyCharsHelper()
5969 OutBuffer buf;
5970 toCBufferInstance(this, &buf, true);
5971 return buf.extractChars();
5974 /**************************************
5975 * Given an error instantiating the TemplateInstance,
5976 * give the nested TemplateInstance instantiations that got
5977 * us here. Those are a list threaded into the nested scopes.
5979 extern(D) final void printInstantiationTrace(Classification cl = Classification.error)
5981 if (global.gag)
5982 return;
5984 // Print full trace for verbose mode, otherwise only short traces
5985 const(uint) max_shown = !global.params.verbose ? 6 : uint.max;
5986 const(char)* format = "instantiated from here: `%s`";
5988 // This returns a function pointer
5989 scope printFn = () {
5990 final switch (cl)
5992 case Classification.error:
5993 return &errorSupplemental;
5994 case Classification.warning:
5995 return &warningSupplemental;
5996 case Classification.deprecation:
5997 return &deprecationSupplemental;
5998 case Classification.gagged, Classification.tip:
5999 assert(0);
6001 }();
6003 // determine instantiation depth and number of recursive instantiations
6004 int n_instantiations = 1;
6005 int n_totalrecursions = 0;
6006 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6008 ++n_instantiations;
6009 // Set error here as we don't want it to depend on the number of
6010 // entries that are being printed.
6011 if (cl == Classification.error ||
6012 (cl == Classification.warning && global.params.warnings == DiagnosticReporting.error) ||
6013 (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
6014 cur.errors = true;
6016 // If two instantiations use the same declaration, they are recursive.
6017 // (this works even if they are instantiated from different places in the
6018 // same template).
6019 // In principle, we could also check for multiple-template recursion, but it's
6020 // probably not worthwhile.
6021 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6022 ++n_totalrecursions;
6025 if (n_instantiations <= max_shown)
6027 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6028 printFn(cur.loc, format, cur.toChars());
6030 else if (n_instantiations - n_totalrecursions <= max_shown)
6032 // By collapsing recursive instantiations into a single line,
6033 // we can stay under the limit.
6034 int recursionDepth = 0;
6035 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6037 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6039 ++recursionDepth;
6041 else
6043 if (recursionDepth)
6044 printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
6045 else
6046 printFn(cur.loc, format, cur.toChars());
6047 recursionDepth = 0;
6051 else
6053 // Even after collapsing the recursions, the depth is too deep.
6054 // Just display the first few and last few instantiations.
6055 uint i = 0;
6056 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6058 if (i == max_shown / 2)
6059 printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
6061 if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
6062 printFn(cur.loc, format, cur.toChars());
6063 ++i;
6068 /*************************************
6069 * Lazily generate identifier for template instance.
6070 * This is because 75% of the ident's are never needed.
6072 override final Identifier getIdent()
6074 if (!ident && inst && !errors)
6075 ident = genIdent(tiargs); // need an identifier for name mangling purposes.
6076 return ident;
6079 /*************************************
6080 * Compare proposed template instantiation with existing template instantiation.
6081 * Note that this is not commutative because of the auto ref check.
6082 * Params:
6083 * ti = existing template instantiation
6084 * Returns:
6085 * true for match
6087 final bool equalsx(TemplateInstance ti)
6089 //printf("this = %p, ti = %p\n", this, ti);
6090 assert(tdtypes.dim == ti.tdtypes.dim);
6092 // Nesting must match
6093 if (enclosing != ti.enclosing)
6095 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
6096 goto Lnotequals;
6098 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
6100 if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
6101 goto Lnotequals;
6103 /* Template functions may have different instantiations based on
6104 * "auto ref" parameters.
6106 if (auto fd = ti.toAlias().isFuncDeclaration())
6108 if (!fd.errors)
6110 auto fparameters = fd.getParameterList();
6111 size_t nfparams = fparameters.length; // Num function parameters
6112 for (size_t j = 0; j < nfparams; j++)
6114 Parameter fparam = fparameters[j];
6115 if (fparam.storageClass & STC.autoref) // if "auto ref"
6117 Expression farg = fargs && j < fargs.dim ? (*fargs)[j] : fparam.defaultArg;
6118 if (!farg)
6119 goto Lnotequals;
6120 if (farg.isLvalue())
6122 if (!(fparam.storageClass & STC.ref_))
6123 goto Lnotequals; // auto ref's don't match
6125 else
6127 if (fparam.storageClass & STC.ref_)
6128 goto Lnotequals; // auto ref's don't match
6134 return true;
6136 Lnotequals:
6137 return false;
6140 final size_t toHash()
6142 if (!hash)
6144 hash = cast(size_t)cast(void*)enclosing;
6145 hash += arrayObjectHash(&tdtypes);
6146 hash += hash == 0;
6148 return hash;
6152 Returns: true if the instances' innards are discardable.
6154 The idea of this function is to see if the template instantiation
6155 can be 100% replaced with its eponymous member. All other members
6156 can be discarded, even in the compiler to free memory (for example,
6157 the template could be expanded in a region allocator, deemed trivial,
6158 the end result copied back out independently and the entire region freed),
6159 and can be elided entirely from the binary.
6161 The current implementation affects code that generally looks like:
6164 template foo(args...) {
6165 some_basic_type_or_string helper() { .... }
6166 enum foo = helper();
6170 since it was the easiest starting point of implementation but it can and
6171 should be expanded more later.
6173 final bool isDiscardable()
6175 if (aliasdecl is null)
6176 return false;
6178 auto v = aliasdecl.isVarDeclaration();
6179 if (v is null)
6180 return false;
6182 if (!(v.storage_class & STC.manifest))
6183 return false;
6185 // Currently only doing basic types here because it is the easiest proof-of-concept
6186 // implementation with minimal risk of side effects, but it could likely be
6187 // expanded to any type that already exists outside this particular instance.
6188 if (!(v.type.equals(Type.tstring) || (v.type.isTypeBasic() !is null)))
6189 return false;
6191 // Static ctors and dtors, even in an eponymous enum template, are still run,
6192 // so if any of them are in here, we'd better not assume it is trivial lest
6193 // we break useful code
6194 foreach(member; *members)
6196 if(member.hasStaticCtorOrDtor())
6197 return false;
6198 if(member.isStaticDtorDeclaration())
6199 return false;
6200 if(member.isStaticCtorDeclaration())
6201 return false;
6204 // but if it passes through this gauntlet... it should be fine. D code will
6205 // see only the eponymous member, outside stuff can never access it, even through
6206 // reflection; the outside world ought to be none the wiser. Even dmd should be
6207 // able to simply free the memory of everything except the final result.
6209 return true;
6213 /***********************************************
6214 * Returns true if this is not instantiated in non-root module, and
6215 * is a part of non-speculative instantiatiation.
6217 * Note: minst does not stabilize until semantic analysis is completed,
6218 * so don't call this function during semantic analysis to return precise result.
6220 final bool needsCodegen()
6222 // minst is finalized after the 1st invocation.
6223 // tnext and tinst are only needed for the 1st invocation and
6224 // cleared for further invocations.
6225 TemplateInstance tnext = this.tnext;
6226 TemplateInstance tinst = this.tinst;
6227 this.tnext = null;
6228 this.tinst = null;
6230 if (errors || (inst && inst.isDiscardable()))
6232 minst = null; // mark as speculative
6233 return false;
6236 if (global.params.allInst)
6238 // Do codegen if there is an instantiation from a root module, to maximize link-ability.
6240 // Do codegen if `this` is instantiated from a root module.
6241 if (minst && minst.isRoot())
6242 return true;
6244 // Do codegen if the ancestor needs it.
6245 if (tinst && tinst.needsCodegen())
6247 minst = tinst.minst; // cache result
6248 assert(minst);
6249 assert(minst.isRoot());
6250 return true;
6253 // Do codegen if a sibling needs it.
6254 if (tnext)
6256 if (tnext.needsCodegen())
6258 minst = tnext.minst; // cache result
6259 assert(minst);
6260 assert(minst.isRoot());
6261 return true;
6263 else if (!minst && tnext.minst)
6265 minst = tnext.minst; // cache result from non-speculative sibling
6266 return false;
6270 // Elide codegen because there's no instantiation from any root modules.
6271 return false;
6273 else
6275 // Prefer instantiations from non-root modules, to minimize object code size.
6277 /* If a TemplateInstance is ever instantiated from a non-root module,
6278 * we do not have to generate code for it,
6279 * because it will be generated when the non-root module is compiled.
6281 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
6283 * The problem is if A imports B, and B imports A, and both A
6284 * and B instantiate the same template, does the compilation of A
6285 * or the compilation of B do the actual instantiation?
6287 * See https://issues.dlang.org/show_bug.cgi?id=2500.
6289 * => Elide codegen if there is at least one instantiation from a non-root module
6290 * which doesn't import any root modules.
6293 // If the ancestor isn't speculative,
6294 // 1. do codegen if the ancestor needs it
6295 // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
6296 if (tinst)
6298 const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
6299 if (tinst.minst) // not speculative
6301 minst = tinst.minst; // cache result
6302 return needsCodegen;
6306 // Elide codegen if `this` doesn't need it.
6307 if (minst && !minst.isRoot() && !minst.rootImports())
6308 return false;
6310 // Elide codegen if a (non-speculative) sibling doesn't need it.
6311 if (tnext)
6313 const needsCodegen = tnext.needsCodegen(); // sets tnext.minst
6314 if (tnext.minst) // not speculative
6316 if (!needsCodegen)
6318 minst = tnext.minst; // cache result
6319 assert(!minst.isRoot() && !minst.rootImports());
6320 return false;
6322 else if (!minst)
6324 minst = tnext.minst; // cache result from non-speculative sibling
6325 return true;
6330 // Unless `this` is still speculative (=> all further siblings speculative too),
6331 // do codegen because we found no guaranteed-codegen'd non-root instantiation.
6332 return minst !is null;
6336 /**********************************************
6337 * Find template declaration corresponding to template instance.
6339 * Returns:
6340 * false if finding fails.
6341 * Note:
6342 * This function is reentrant against error occurrence. If returns false,
6343 * any members of this object won't be modified, and repetition call will
6344 * reproduce same error.
6346 extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym)
6348 if (pwithsym)
6349 *pwithsym = null;
6351 if (havetempdecl)
6352 return true;
6354 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
6355 if (!tempdecl)
6357 /* Given:
6358 * foo!( ... )
6359 * figure out which TemplateDeclaration foo refers to.
6361 Identifier id = name;
6362 Dsymbol scopesym;
6363 Dsymbol s = sc.search(loc, id, &scopesym);
6364 if (!s)
6366 s = sc.search_correct(id);
6367 if (s)
6368 error("template `%s` is not defined, did you mean %s?", id.toChars(), s.toChars());
6369 else
6370 error("template `%s` is not defined", id.toChars());
6371 return false;
6373 static if (LOG)
6375 printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
6376 if (s.parent)
6377 printf("s.parent = '%s'\n", s.parent.toChars());
6379 if (pwithsym)
6380 *pwithsym = scopesym.isWithScopeSymbol();
6382 /* We might have found an alias within a template when
6383 * we really want the template.
6385 TemplateInstance ti;
6386 if (s.parent && (ti = s.parent.isTemplateInstance()) !is null)
6388 if (ti.tempdecl && ti.tempdecl.ident == id)
6390 /* This is so that one can refer to the enclosing
6391 * template, even if it has the same name as a member
6392 * of the template, if it has a !(arguments)
6394 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6395 assert(td);
6396 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6397 td = td.overroot; // then get the start
6398 s = td;
6402 // The template might originate from a selective import which implies that
6403 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
6404 // This is the last place where we see the deprecated alias because it is
6405 // stripped below, so check if the selective import was deprecated.
6406 // See https://issues.dlang.org/show_bug.cgi?id=20840.
6407 if (s.isAliasDeclaration())
6408 s.checkDeprecated(this.loc, sc);
6410 if (!updateTempDecl(sc, s))
6412 return false;
6415 assert(tempdecl);
6417 // Look for forward references
6418 auto tovers = tempdecl.isOverloadSet();
6419 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
6421 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6422 int r = overloadApply(dstart, (Dsymbol s)
6424 auto td = s.isTemplateDeclaration();
6425 if (!td)
6426 return 0;
6428 if (td.semanticRun == PASS.initial)
6430 if (td._scope)
6432 // Try to fix forward reference. Ungag errors while doing so.
6433 Ungag ungag = td.ungagSpeculative();
6434 td.dsymbolSemantic(td._scope);
6436 if (td.semanticRun == PASS.initial)
6438 error("`%s` forward references template declaration `%s`",
6439 toChars(), td.toChars());
6440 return 1;
6443 return 0;
6445 if (r)
6446 return false;
6448 return true;
6451 /**********************************************
6452 * Confirm s is a valid template, then store it.
6453 * Input:
6454 * sc
6455 * s candidate symbol of template. It may be:
6456 * TemplateDeclaration
6457 * FuncDeclaration with findTemplateDeclRoot() != NULL
6458 * OverloadSet which contains candidates
6459 * Returns:
6460 * true if updating succeeds.
6462 extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s)
6464 if (!s)
6465 return tempdecl !is null;
6467 Identifier id = name;
6468 s = s.toAlias();
6470 /* If an OverloadSet, look for a unique member that is a template declaration
6472 if (OverloadSet os = s.isOverloadSet())
6474 s = null;
6475 foreach (s2; os.a)
6477 if (FuncDeclaration f = s2.isFuncDeclaration())
6478 s2 = f.findTemplateDeclRoot();
6479 else
6480 s2 = s2.isTemplateDeclaration();
6481 if (s2)
6483 if (s)
6485 tempdecl = os;
6486 return true;
6488 s = s2;
6491 if (!s)
6493 error("template `%s` is not defined", id.toChars());
6494 return false;
6498 if (OverDeclaration od = s.isOverDeclaration())
6500 tempdecl = od; // TODO: more strict check
6501 return true;
6504 /* It should be a TemplateDeclaration, not some other symbol
6506 if (FuncDeclaration f = s.isFuncDeclaration())
6507 tempdecl = f.findTemplateDeclRoot();
6508 else
6509 tempdecl = s.isTemplateDeclaration();
6511 // We're done
6512 if (tempdecl)
6513 return true;
6515 // Error already issued, just return `false`
6516 if (!s.parent && global.errors)
6517 return false;
6519 if (!s.parent && s.getType())
6521 Dsymbol s2 = s.getType().toDsymbol(sc);
6522 if (!s2)
6524 .error(loc, "`%s` is not a valid template instance, because `%s` is not a template declaration but a type (`%s == %s`)", toChars(), id.toChars(), id.toChars(), s.getType.kind());
6525 return false;
6527 // because s can be the alias created for a TemplateParameter
6528 const AliasDeclaration ad = s.isAliasDeclaration();
6529 version (none)
6531 if (ad && ad.isAliasedTemplateParameter())
6532 printf("`%s` is an alias created from a template parameter\n", s.toChars());
6534 if (!ad || !ad.isAliasedTemplateParameter())
6535 s = s2;
6538 TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
6539 if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl)
6541 /* This is so that one can refer to the enclosing
6542 * template, even if it has the same name as a member
6543 * of the template, if it has a !(arguments)
6545 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6546 assert(td);
6547 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6548 td = td.overroot; // then get the start
6549 tempdecl = td;
6550 return true;
6552 else
6554 error("`%s` is not a template declaration, it is a %s", id.toChars(), s.kind());
6555 return false;
6559 /**********************************
6560 * Run semantic of tiargs as arguments of template.
6561 * Input:
6562 * loc
6563 * sc
6564 * tiargs array of template arguments
6565 * flags 1: replace const variables with their initializers
6566 * 2: don't devolve Parameter to Type
6567 * Returns:
6568 * false if one or more arguments have errors.
6570 extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags)
6572 // Run semantic on each argument, place results in tiargs[]
6573 //printf("+TemplateInstance.semanticTiargs()\n");
6574 if (!tiargs)
6575 return true;
6576 bool err = false;
6577 for (size_t j = 0; j < tiargs.dim; j++)
6579 RootObject o = (*tiargs)[j];
6580 Type ta = isType(o);
6581 Expression ea = isExpression(o);
6582 Dsymbol sa = isDsymbol(o);
6584 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
6585 if (ta)
6587 //printf("type %s\n", ta.toChars());
6589 // It might really be an Expression or an Alias
6590 ta.resolve(loc, sc, ea, ta, sa, (flags & 1) != 0);
6591 if (ea)
6592 goto Lexpr;
6593 if (sa)
6594 goto Ldsym;
6595 if (ta is null)
6597 assert(global.errors);
6598 ta = Type.terror;
6601 Ltype:
6602 if (ta.ty == Ttuple)
6604 // Expand tuple
6605 TypeTuple tt = cast(TypeTuple)ta;
6606 size_t dim = tt.arguments.dim;
6607 tiargs.remove(j);
6608 if (dim)
6610 tiargs.reserve(dim);
6611 foreach (i, arg; *tt.arguments)
6613 if (flags & 2 && (arg.storageClass & STC.parameter))
6614 tiargs.insert(j + i, arg);
6615 else
6616 tiargs.insert(j + i, arg.type);
6619 j--;
6620 continue;
6622 if (ta.ty == Terror)
6624 err = true;
6625 continue;
6627 (*tiargs)[j] = ta.merge2();
6629 else if (ea)
6631 Lexpr:
6632 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6633 if (flags & 1) // only used by __traits
6635 ea = ea.expressionSemantic(sc);
6637 // must not interpret the args, excepting template parameters
6638 if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
6640 ea = ea.optimize(WANTvalue);
6643 else
6645 sc = sc.startCTFE();
6646 ea = ea.expressionSemantic(sc);
6647 sc = sc.endCTFE();
6649 if (ea.op == EXP.variable)
6651 /* If the parameter is a function that is not called
6652 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
6653 * then it is a dsymbol, not the return value of `func()`
6655 Declaration vd = (cast(VarExp)ea).var;
6656 if (auto fd = vd.isFuncDeclaration())
6658 sa = fd;
6659 goto Ldsym;
6661 /* Otherwise skip substituting a const var with
6662 * its initializer. The problem is the initializer won't
6663 * match with an 'alias' parameter. Instead, do the
6664 * const substitution in TemplateValueParameter.matchArg().
6667 else if (definitelyValueParameter(ea))
6669 if (ea.checkValue()) // check void expression
6670 ea = ErrorExp.get();
6671 uint olderrs = global.errors;
6672 ea = ea.ctfeInterpret();
6673 if (global.errors != olderrs)
6674 ea = ErrorExp.get();
6677 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6678 if (ea.op == EXP.tuple)
6680 // Expand tuple
6681 TupleExp te = cast(TupleExp)ea;
6682 size_t dim = te.exps.dim;
6683 tiargs.remove(j);
6684 if (dim)
6686 tiargs.reserve(dim);
6687 foreach (i, exp; *te.exps)
6688 tiargs.insert(j + i, exp);
6690 j--;
6691 continue;
6693 if (ea.op == EXP.error)
6695 err = true;
6696 continue;
6698 (*tiargs)[j] = ea;
6700 if (ea.op == EXP.type)
6702 ta = ea.type;
6703 goto Ltype;
6705 if (ea.op == EXP.scope_)
6707 sa = (cast(ScopeExp)ea).sds;
6708 goto Ldsym;
6710 if (ea.op == EXP.function_)
6712 FuncExp fe = cast(FuncExp)ea;
6713 /* A function literal, that is passed to template and
6714 * already semanticed as function pointer, never requires
6715 * outer frame. So convert it to global function is valid.
6717 if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer)
6719 // change to non-nested
6720 fe.fd.tok = TOK.function_;
6721 fe.fd.vthis = null;
6723 else if (fe.td)
6725 /* If template argument is a template lambda,
6726 * get template declaration itself. */
6727 //sa = fe.td;
6728 //goto Ldsym;
6731 if (ea.op == EXP.dotVariable && !(flags & 1))
6733 // translate expression to dsymbol.
6734 sa = (cast(DotVarExp)ea).var;
6735 goto Ldsym;
6737 if (ea.op == EXP.template_)
6739 sa = (cast(TemplateExp)ea).td;
6740 goto Ldsym;
6742 if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
6744 // translate expression to dsymbol.
6745 sa = (cast(DotTemplateExp)ea).td;
6746 goto Ldsym;
6748 if (ea.op == EXP.dot)
6750 if (auto se = (cast(DotExp)ea).e2.isScopeExp())
6752 sa = se.sds;
6753 goto Ldsym;
6757 else if (sa)
6759 Ldsym:
6760 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
6761 if (sa.errors)
6763 err = true;
6764 continue;
6767 TupleDeclaration d = sa.toAlias().isTupleDeclaration();
6768 if (d)
6770 // Expand tuple
6771 tiargs.remove(j);
6772 tiargs.insert(j, d.objects);
6773 j--;
6774 continue;
6776 if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration())
6778 FuncDeclaration f = fa.toAliasFunc();
6779 if (!fa.hasOverloads && f.isUnique())
6781 // Strip FuncAlias only when the aliased function
6782 // does not have any overloads.
6783 sa = f;
6786 (*tiargs)[j] = sa;
6788 TemplateDeclaration td = sa.isTemplateDeclaration();
6789 if (td && td.semanticRun == PASS.initial && td.literal)
6791 td.dsymbolSemantic(sc);
6793 FuncDeclaration fd = sa.isFuncDeclaration();
6794 if (fd)
6795 fd.functionSemantic();
6797 else if (isParameter(o))
6800 else
6802 assert(0);
6804 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
6806 version (none)
6808 printf("-TemplateInstance.semanticTiargs()\n");
6809 for (size_t j = 0; j < tiargs.dim; j++)
6811 RootObject o = (*tiargs)[j];
6812 Type ta = isType(o);
6813 Expression ea = isExpression(o);
6814 Dsymbol sa = isDsymbol(o);
6815 Tuple va = isTuple(o);
6816 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
6819 return !err;
6822 /**********************************
6823 * Run semantic on the elements of tiargs.
6824 * Input:
6825 * sc
6826 * Returns:
6827 * false if one or more arguments have errors.
6828 * Note:
6829 * This function is reentrant against error occurrence. If returns false,
6830 * all elements of tiargs won't be modified.
6832 extern (D) final bool semanticTiargs(Scope* sc)
6834 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
6835 if (semantictiargsdone)
6836 return true;
6837 if (semanticTiargs(loc, sc, tiargs, 0))
6839 // cache the result iff semantic analysis succeeded entirely
6840 semantictiargsdone = 1;
6841 return true;
6843 return false;
6846 /**********************************
6847 * Find the TemplateDeclaration that matches this TemplateInstance best.
6849 * Params:
6850 * sc = the scope this TemplateInstance resides in
6851 * fargs = function arguments in case of a template function, null otherwise
6853 * Returns:
6854 * `true` if a match was found, `false` otherwise
6856 extern (D) final bool findBestMatch(Scope* sc, Expressions* fargs)
6858 if (havetempdecl)
6860 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
6861 assert(tempdecl);
6862 assert(tempdecl._scope);
6863 // Deduce tdtypes
6864 tdtypes.setDim(tempdecl.parameters.dim);
6865 if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2))
6867 error("incompatible arguments for template instantiation");
6868 return false;
6870 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
6871 return true;
6874 static if (LOG)
6876 printf("TemplateInstance.findBestMatch()\n");
6879 uint errs = global.errors;
6880 TemplateDeclaration td_last = null;
6881 Objects dedtypes;
6883 /* Since there can be multiple TemplateDeclaration's with the same
6884 * name, look for the best match.
6886 auto tovers = tempdecl.isOverloadSet();
6887 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
6889 TemplateDeclaration td_best;
6890 TemplateDeclaration td_ambig;
6891 MATCH m_best = MATCH.nomatch;
6893 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6894 overloadApply(dstart, (Dsymbol s)
6896 auto td = s.isTemplateDeclaration();
6897 if (!td)
6898 return 0;
6899 if (td.inuse)
6901 td.error(loc, "recursive template expansion");
6902 return 1;
6904 if (td == td_best) // skip duplicates
6905 return 0;
6907 //printf("td = %s\n", td.toPrettyChars());
6908 // If more arguments than parameters,
6909 // then this is no match.
6910 if (td.parameters.dim < tiargs.dim)
6912 if (!td.isVariadic())
6913 return 0;
6916 dedtypes.setDim(td.parameters.dim);
6917 dedtypes.zero();
6918 assert(td.semanticRun != PASS.initial);
6920 MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
6921 //printf("matchWithInstance = %d\n", m);
6922 if (m == MATCH.nomatch) // no match at all
6923 return 0;
6924 if (m < m_best) goto Ltd_best;
6925 if (m > m_best) goto Ltd;
6927 // Disambiguate by picking the most specialized TemplateDeclaration
6929 MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
6930 MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
6931 //printf("c1 = %d, c2 = %d\n", c1, c2);
6932 if (c1 > c2) goto Ltd;
6933 if (c1 < c2) goto Ltd_best;
6936 td_ambig = td;
6937 return 0;
6939 Ltd_best:
6940 // td_best is the best match so far
6941 td_ambig = null;
6942 return 0;
6944 Ltd:
6945 // td is the new best match
6946 td_ambig = null;
6947 td_best = td;
6948 m_best = m;
6949 tdtypes.setDim(dedtypes.dim);
6950 memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * (void*).sizeof);
6951 return 0;
6954 if (td_ambig)
6956 .error(loc, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`",
6957 td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(),
6958 td_best.loc.toChars(), td_best.toChars(),
6959 td_ambig.loc.toChars(), td_ambig.toChars());
6960 return false;
6962 if (td_best)
6964 if (!td_last)
6965 td_last = td_best;
6966 else if (td_last != td_best)
6968 ScopeDsymbol.multiplyDefined(loc, td_last, td_best);
6969 return false;
6974 if (td_last)
6976 /* https://issues.dlang.org/show_bug.cgi?id=7469
6977 * Normalize tiargs by using corresponding deduced
6978 * template value parameters and tuples for the correct mangling.
6980 * By doing this before hasNestedArgs, CTFEable local variable will be
6981 * accepted as a value parameter. For example:
6983 * void foo() {
6984 * struct S(int n) {} // non-global template
6985 * const int num = 1; // CTFEable local variable
6986 * S!num s; // S!1 is instantiated, not S!num
6989 size_t dim = td_last.parameters.dim - (td_last.isVariadic() ? 1 : 0);
6990 for (size_t i = 0; i < dim; i++)
6992 if (tiargs.dim <= i)
6993 tiargs.push(tdtypes[i]);
6994 assert(i < tiargs.dim);
6996 auto tvp = (*td_last.parameters)[i].isTemplateValueParameter();
6997 if (!tvp)
6998 continue;
6999 assert(tdtypes[i]);
7000 // tdtypes[i] is already normalized to the required type in matchArg
7002 (*tiargs)[i] = tdtypes[i];
7004 if (td_last.isVariadic() && tiargs.dim == dim && tdtypes[dim])
7006 Tuple va = isTuple(tdtypes[dim]);
7007 assert(va);
7008 tiargs.pushSlice(va.objects[]);
7011 else if (errors && inst)
7013 // instantiation was failed with error reporting
7014 assert(global.errors);
7015 return false;
7017 else
7019 auto tdecl = tempdecl.isTemplateDeclaration();
7021 if (errs != global.errors)
7022 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7023 else if (tdecl && !tdecl.overnext)
7025 // Only one template, so we can give better error message
7026 const(char)* msg = "does not match template declaration";
7027 const(char)* tip;
7028 const tmsg = tdecl.toCharsNoConstraints();
7029 const cmsg = tdecl.getConstraintEvalError(tip);
7030 if (cmsg)
7032 error("%s `%s`\n%s", msg, tmsg, cmsg);
7033 if (tip)
7034 .tip(tip);
7036 else
7038 error("%s `%s`", msg, tmsg);
7040 if (tdecl.parameters.dim == tiargs.dim)
7042 // https://issues.dlang.org/show_bug.cgi?id=7352
7043 // print additional information, e.g. `foo` is not a type
7044 foreach (i, param; *tdecl.parameters)
7046 MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
7047 auto arg = (*tiargs)[i];
7048 auto sym = arg.isDsymbol;
7049 auto exp = arg.isExpression;
7051 if (exp)
7052 exp = exp.optimize(WANTvalue);
7054 if (match == MATCH.nomatch &&
7055 ((sym && sym.isFuncDeclaration) ||
7056 (exp && exp.isVarExp)))
7058 if (param.isTemplateTypeParameter)
7059 errorSupplemental(loc, "`%s` is not a type", arg.toChars);
7060 else if (auto tvp = param.isTemplateValueParameter)
7061 errorSupplemental(loc, "`%s` is not of a value of type `%s`",
7062 arg.toChars, tvp.valType.toChars);
7069 else
7070 .error(loc, "%s `%s.%s` does not match any template declaration", tempdecl.kind(), tempdecl.parent.toPrettyChars(), tempdecl.ident.toChars());
7071 return false;
7074 /* The best match is td_last
7076 tempdecl = td_last;
7078 static if (LOG)
7080 printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
7082 return (errs == global.errors);
7085 /*****************************************************
7086 * Determine if template instance is really a template function,
7087 * and that template function needs to infer types from the function
7088 * arguments.
7090 * Like findBestMatch, iterate possible template candidates,
7091 * but just looks only the necessity of type inference.
7093 extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
7095 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
7096 if (semanticRun != PASS.initial)
7097 return false;
7099 uint olderrs = global.errors;
7100 Objects dedtypes;
7101 size_t count = 0;
7103 auto tovers = tempdecl.isOverloadSet();
7104 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
7106 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7107 int r = overloadApply(dstart, (Dsymbol s)
7109 auto td = s.isTemplateDeclaration();
7110 if (!td)
7111 return 0;
7112 if (td.inuse)
7114 td.error(loc, "recursive template expansion");
7115 return 1;
7118 /* If any of the overloaded template declarations need inference,
7119 * then return true
7121 if (!td.onemember)
7122 return 0;
7123 if (auto td2 = td.onemember.isTemplateDeclaration())
7125 if (!td2.onemember || !td2.onemember.isFuncDeclaration())
7126 return 0;
7127 if (tiargs.dim >= td.parameters.dim - (td.isVariadic() ? 1 : 0))
7128 return 0;
7129 return 1;
7131 auto fd = td.onemember.isFuncDeclaration();
7132 if (!fd || fd.type.ty != Tfunction)
7133 return 0;
7135 foreach (tp; *td.parameters)
7137 if (tp.isTemplateThisParameter())
7138 return 1;
7141 /* Determine if the instance arguments, tiargs, are all that is necessary
7142 * to instantiate the template.
7144 //printf("tp = %p, td.parameters.dim = %d, tiargs.dim = %d\n", tp, td.parameters.dim, tiargs.dim);
7145 auto tf = cast(TypeFunction)fd.type;
7146 if (tf.parameterList.length)
7148 auto tp = td.isVariadic();
7149 if (tp && td.parameters.dim > 1)
7150 return 1;
7152 if (!tp && tiargs.dim < td.parameters.dim)
7154 // Can remain tiargs be filled by default arguments?
7155 foreach (size_t i; tiargs.dim .. td.parameters.dim)
7157 if (!(*td.parameters)[i].hasDefaultArg())
7158 return 1;
7162 foreach (i, fparam; tf.parameterList)
7164 // 'auto ref' needs inference.
7165 if (fparam.storageClass & STC.auto_)
7166 return 1;
7170 if (!flag)
7172 /* Calculate the need for overload resolution.
7173 * When only one template can match with tiargs, inference is not necessary.
7175 dedtypes.setDim(td.parameters.dim);
7176 dedtypes.zero();
7177 if (td.semanticRun == PASS.initial)
7179 if (td._scope)
7181 // Try to fix forward reference. Ungag errors while doing so.
7182 Ungag ungag = td.ungagSpeculative();
7183 td.dsymbolSemantic(td._scope);
7185 if (td.semanticRun == PASS.initial)
7187 error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
7188 return 1;
7191 MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0);
7192 if (m == MATCH.nomatch)
7193 return 0;
7196 /* If there is more than one function template which matches, we may
7197 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
7199 return ++count > 1 ? 1 : 0;
7201 if (r)
7202 return true;
7205 if (olderrs != global.errors)
7207 if (!global.gag)
7209 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7210 semanticRun = PASS.semanticdone;
7211 inst = this;
7213 errors = true;
7215 //printf("false\n");
7216 return false;
7219 /*****************************************
7220 * Determines if a TemplateInstance will need a nested
7221 * generation of the TemplateDeclaration.
7222 * Sets enclosing property if so, and returns != 0;
7224 extern (D) final bool hasNestedArgs(Objects* args, bool isstatic)
7226 int nested = 0;
7227 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
7229 // arguments from parent instances are also accessible
7230 if (!enclosing)
7232 if (TemplateInstance ti = tempdecl.toParent().isTemplateInstance())
7233 enclosing = ti.enclosing;
7236 /* A nested instance happens when an argument references a local
7237 * symbol that is on the stack.
7239 foreach (o; *args)
7241 Expression ea = isExpression(o);
7242 Dsymbol sa = isDsymbol(o);
7243 Tuple va = isTuple(o);
7244 if (ea)
7246 if (ea.op == EXP.variable)
7248 sa = (cast(VarExp)ea).var;
7249 goto Lsa;
7251 if (ea.op == EXP.this_)
7253 sa = (cast(ThisExp)ea).var;
7254 goto Lsa;
7256 if (ea.op == EXP.function_)
7258 if ((cast(FuncExp)ea).td)
7259 sa = (cast(FuncExp)ea).td;
7260 else
7261 sa = (cast(FuncExp)ea).fd;
7262 goto Lsa;
7264 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
7265 if (ea.op != EXP.int64 && ea.op != EXP.float64 && ea.op != EXP.complex80 && ea.op != EXP.null_ && ea.op != EXP.string_ && ea.op != EXP.arrayLiteral && ea.op != EXP.assocArrayLiteral && ea.op != EXP.structLiteral)
7267 ea.error("expression `%s` is not a valid template value argument", ea.toChars());
7268 errors = true;
7271 else if (sa)
7273 Lsa:
7274 sa = sa.toAlias();
7275 TemplateDeclaration td = sa.isTemplateDeclaration();
7276 if (td)
7278 TemplateInstance ti = sa.toParent().isTemplateInstance();
7279 if (ti && ti.enclosing)
7280 sa = ti;
7282 TemplateInstance ti = sa.isTemplateInstance();
7283 Declaration d = sa.isDeclaration();
7284 if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin()))
7286 Dsymbol dparent = sa.toParent2();
7287 if (!dparent || dparent.isModule)
7288 goto L1;
7289 else if (!enclosing)
7290 enclosing = dparent;
7291 else if (enclosing != dparent)
7293 /* Select the more deeply nested of the two.
7294 * Error if one is not nested inside the other.
7296 for (Dsymbol p = enclosing; p; p = p.parent)
7298 if (p == dparent)
7299 goto L1; // enclosing is most nested
7301 for (Dsymbol p = dparent; p; p = p.parent)
7303 if (p == enclosing)
7305 enclosing = dparent;
7306 goto L1; // dparent is most nested
7309 //https://issues.dlang.org/show_bug.cgi?id=17870
7310 if (dparent.isClassDeclaration() && enclosing.isClassDeclaration())
7312 auto pc = dparent.isClassDeclaration();
7313 auto ec = enclosing.isClassDeclaration();
7314 if (pc.isBaseOf(ec, null))
7315 goto L1;
7316 else if (ec.isBaseOf(pc, null))
7318 enclosing = dparent;
7319 goto L1;
7322 error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars());
7323 errors = true;
7326 //printf("\tnested inside %s\n", enclosing.toChars());
7327 nested |= 1;
7330 else if (va)
7332 nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
7335 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
7336 return nested != 0;
7339 /*****************************************
7340 * Append 'this' to the specific module members[]
7342 extern (D) final Dsymbols* appendToModuleMember()
7344 Module mi = minst; // instantiated . inserted module
7346 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
7347 // toPrettyChars(),
7348 // enclosing ? enclosing.toPrettyChars() : null,
7349 // mi ? mi.toPrettyChars() : null);
7350 if (global.params.allInst || !mi || mi.isRoot())
7352 /* If the instantiated module is speculative or root, insert to the
7353 * member of a root module. Then:
7354 * - semantic3 pass will get called on the instance members.
7355 * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
7357 static Dsymbol getStrictEnclosing(TemplateInstance ti)
7361 if (ti.enclosing)
7362 return ti.enclosing;
7363 ti = ti.tempdecl.isInstantiated();
7364 } while (ti);
7365 return null;
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())
7374 if (mi.importedFrom)
7376 mi = mi.importedFrom;
7377 assert(mi.isRoot());
7379 else
7381 // This can happen when using the frontend as a library.
7382 // Append it to the non-root module.
7386 else
7388 /* If the instantiated module is non-root, insert to the member of the
7389 * non-root module. Then:
7390 * - semantic3 pass won't be called on the instance.
7391 * - codegen pass won't reach to the instance.
7392 * Unless it is re-appended to a root module later (with changed minst).
7395 //printf("\t-. mi = %s\n", mi.toPrettyChars());
7397 assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module");
7399 Dsymbols* a = mi.members;
7400 a.push(this);
7401 memberOf = mi;
7402 if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
7403 Module.addDeferredSemantic2(this);
7404 if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
7405 Module.addDeferredSemantic3(this);
7406 return a;
7409 /****************************************************
7410 * Declare parameters of template instance, initialize them with the
7411 * template instance arguments.
7413 extern (D) final void declareParameters(Scope* sc)
7415 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
7416 assert(tempdecl);
7418 //printf("TemplateInstance.declareParameters()\n");
7419 foreach (i, o; tdtypes) // initializer for tp
7421 TemplateParameter tp = (*tempdecl.parameters)[i];
7422 //printf("\ttdtypes[%d] = %p\n", i, o);
7423 tempdecl.declareParameter(sc, tp, o);
7427 /****************************************
7428 * This instance needs an identifier for name mangling purposes.
7429 * Create one by taking the template declaration name and adding
7430 * the type signature for it.
7432 extern (D) final Identifier genIdent(Objects* args)
7434 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
7435 assert(args is tiargs);
7436 OutBuffer buf;
7437 mangleToBuffer(this, &buf);
7438 //printf("\tgenIdent = %s\n", buf.peekChars());
7439 return Identifier.idPool(buf[]);
7442 extern (D) final void expandMembers(Scope* sc2)
7444 members.foreachDsymbol( (s) { s.setScope (sc2); } );
7446 members.foreachDsymbol( (s) { s.importAll(sc2); } );
7448 void symbolDg(Dsymbol s)
7450 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
7451 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
7452 //if (enclosing)
7453 // s.parent = sc.parent;
7454 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7455 s.dsymbolSemantic(sc2);
7456 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7457 Module.runDeferredSemantic();
7460 members.foreachDsymbol(&symbolDg);
7463 extern (D) final void tryExpandMembers(Scope* sc2)
7465 __gshared int nest;
7466 // extracted to a function to allow windows SEH to work without destructors in the same function
7467 //printf("%d\n", nest);
7468 if (++nest > global.recursionLimit)
7470 global.gag = 0; // ensure error message gets printed
7471 error("recursive expansion exceeded allowed nesting limit");
7472 fatal();
7475 expandMembers(sc2);
7477 nest--;
7480 extern (D) final void trySemantic3(Scope* sc2)
7482 // extracted to a function to allow windows SEH to work without destructors in the same function
7483 __gshared int nest;
7484 //printf("%d\n", nest);
7485 if (++nest > global.recursionLimit)
7487 global.gag = 0; // ensure error message gets printed
7488 error("recursive expansion exceeded allowed nesting limit");
7489 fatal();
7492 semantic3(this, sc2);
7494 --nest;
7497 override final inout(TemplateInstance) isTemplateInstance() inout
7499 return this;
7502 override void accept(Visitor v)
7504 v.visit(this);
7508 /**************************************
7509 * IsExpression can evaluate the specified type speculatively, and even if
7510 * it instantiates any symbols, they are normally unnecessary for the
7511 * final executable.
7512 * However, if those symbols leak to the actual code, compiler should remark
7513 * them as non-speculative to generate their code and link to the final executable.
7515 void unSpeculative(Scope* sc, RootObject o)
7517 if (!o)
7518 return;
7520 if (Tuple tup = isTuple(o))
7522 foreach (obj; tup.objects)
7524 unSpeculative(sc, obj);
7526 return;
7529 Dsymbol s = getDsymbol(o);
7530 if (!s)
7531 return;
7533 if (Declaration d = s.isDeclaration())
7535 if (VarDeclaration vd = d.isVarDeclaration())
7536 o = vd.type;
7537 else if (AliasDeclaration ad = d.isAliasDeclaration())
7539 o = ad.getType();
7540 if (!o)
7541 o = ad.toAlias();
7543 else
7544 o = d.toAlias();
7546 s = getDsymbol(o);
7547 if (!s)
7548 return;
7551 if (TemplateInstance ti = s.isTemplateInstance())
7553 // If the instance is already non-speculative,
7554 // or it is leaked to the speculative scope.
7555 if (ti.minst !is null || sc.minst is null)
7556 return;
7558 // Remark as non-speculative instance.
7559 ti.minst = sc.minst;
7560 if (!ti.tinst)
7561 ti.tinst = sc.tinst;
7563 unSpeculative(sc, ti.tempdecl);
7566 if (TemplateInstance ti = s.isInstantiated())
7567 unSpeculative(sc, ti);
7570 /**********************************
7571 * Return true if e could be valid only as a template value parameter.
7572 * Return false if it might be an alias or tuple.
7573 * (Note that even in this case, it could still turn out to be a value).
7575 bool definitelyValueParameter(Expression e)
7577 // None of these can be value parameters
7578 if (e.op == EXP.tuple || e.op == EXP.scope_ ||
7579 e.op == EXP.type || e.op == EXP.dotType ||
7580 e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration ||
7581 e.op == EXP.function_ || e.op == EXP.error ||
7582 e.op == EXP.this_ || e.op == EXP.super_ ||
7583 e.op == EXP.dot)
7584 return false;
7586 if (e.op != EXP.dotVariable)
7587 return true;
7589 /* Template instantiations involving a DotVar expression are difficult.
7590 * In most cases, they should be treated as a value parameter, and interpreted.
7591 * But they might also just be a fully qualified name, which should be treated
7592 * as an alias.
7595 // x.y.f cannot be a value
7596 FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration();
7597 if (f)
7598 return false;
7600 while (e.op == EXP.dotVariable)
7602 e = (cast(DotVarExp)e).e1;
7604 // this.x.y and super.x.y couldn't possibly be valid values.
7605 if (e.op == EXP.this_ || e.op == EXP.super_)
7606 return false;
7608 // e.type.x could be an alias
7609 if (e.op == EXP.dotType)
7610 return false;
7612 // var.x.y is the only other possible form of alias
7613 if (e.op != EXP.variable)
7614 return true;
7616 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
7617 // func.x.y is not an alias
7618 if (!v)
7619 return true;
7621 // https://issues.dlang.org/show_bug.cgi?id=16685
7622 // var.x.y where var is a constant available at compile time
7623 if (v.storage_class & STC.manifest)
7624 return true;
7626 // TODO: Should we force CTFE if it is a global constant?
7627 return false;
7630 /***********************************************************
7631 * https://dlang.org/spec/template-mixin.html
7632 * Syntax:
7633 * mixin MixinTemplateName [TemplateArguments] [Identifier];
7635 extern (C++) final class TemplateMixin : TemplateInstance
7637 TypeQualified tqual;
7639 extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
7641 super(loc,
7642 tqual.idents.dim ? cast(Identifier)tqual.idents[tqual.idents.dim - 1] : (cast(TypeIdentifier)tqual).ident,
7643 tiargs ? tiargs : new Objects());
7644 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
7645 this.ident = ident;
7646 this.tqual = tqual;
7649 override TemplateInstance syntaxCopy(Dsymbol s)
7651 auto tm = new TemplateMixin(loc, ident, tqual.syntaxCopy(), tiargs);
7652 return TemplateInstance.syntaxCopy(tm);
7655 override const(char)* kind() const
7657 return "mixin";
7660 override bool oneMember(Dsymbol* ps, Identifier ident)
7662 return Dsymbol.oneMember(ps, ident);
7665 override bool hasPointers()
7667 //printf("TemplateMixin.hasPointers() %s\n", toChars());
7668 return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
7671 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
7673 //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
7674 if (_scope) // if fwd reference
7675 dsymbolSemantic(this, null); // try to resolve it
7677 members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
7680 override const(char)* toChars() const
7682 OutBuffer buf;
7683 toCBufferInstance(this, &buf);
7684 return buf.extractChars();
7687 extern (D) bool findTempDecl(Scope* sc)
7689 // Follow qualifications to find the TemplateDeclaration
7690 if (!tempdecl)
7692 Expression e;
7693 Type t;
7694 Dsymbol s;
7695 tqual.resolve(loc, sc, e, t, s);
7696 if (!s)
7698 error("is not defined");
7699 return false;
7701 s = s.toAlias();
7702 tempdecl = s.isTemplateDeclaration();
7703 OverloadSet os = s.isOverloadSet();
7705 /* If an OverloadSet, look for a unique member that is a template declaration
7707 if (os)
7709 Dsymbol ds = null;
7710 foreach (i, sym; os.a)
7712 Dsymbol s2 = sym.isTemplateDeclaration();
7713 if (s2)
7715 if (ds)
7717 tempdecl = os;
7718 break;
7720 ds = s2;
7724 if (!tempdecl)
7726 error("`%s` isn't a template", s.toChars());
7727 return false;
7730 assert(tempdecl);
7732 // Look for forward references
7733 auto tovers = tempdecl.isOverloadSet();
7734 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
7736 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7737 int r = overloadApply(dstart, (Dsymbol s)
7739 auto td = s.isTemplateDeclaration();
7740 if (!td)
7741 return 0;
7743 if (td.semanticRun == PASS.initial)
7745 if (td._scope)
7746 td.dsymbolSemantic(td._scope);
7747 else
7749 semanticRun = PASS.initial;
7750 return 1;
7753 return 0;
7755 if (r)
7756 return false;
7758 return true;
7761 override inout(TemplateMixin) isTemplateMixin() inout
7763 return this;
7766 override void accept(Visitor v)
7768 v.visit(this);
7772 /************************************
7773 * This struct is needed for TemplateInstance to be the key in an associative array.
7774 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
7775 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
7777 struct TemplateInstanceBox
7779 TemplateInstance ti;
7781 this(TemplateInstance ti)
7783 this.ti = ti;
7784 this.ti.toHash();
7785 assert(this.ti.hash);
7788 size_t toHash() const @trusted pure nothrow
7790 assert(ti.hash);
7791 return ti.hash;
7794 bool opEquals(ref const TemplateInstanceBox s) @trusted const
7796 bool res = void;
7797 if (ti.inst && s.ti.inst)
7799 /* This clause is only used when an instance with errors
7800 * is replaced with a correct instance.
7802 res = ti is s.ti;
7804 else
7806 /* Used when a proposed instance is used to see if there's
7807 * an existing instance.
7809 static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
7810 res = (cast()s.ti).equalsx(cast()ti);
7811 else
7812 res = (cast()ti).equalsx(cast()s.ti);
7815 debug (FindExistingInstance) ++(res ? nHits : nCollisions);
7816 return res;
7819 debug (FindExistingInstance)
7821 __gshared uint nHits, nCollisions;
7823 shared static ~this()
7825 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
7826 nHits, nCollisions);
7831 /*******************************************
7832 * Match to a particular TemplateParameter.
7833 * Input:
7834 * instLoc location that the template is instantiated.
7835 * tiargs[] actual arguments to template instance
7836 * i i'th argument
7837 * parameters[] template parameters
7838 * dedtypes[] deduced arguments to template instance
7839 * *psparam set to symbol declared and initialized to dedtypes[i]
7841 MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
7843 MATCH matchArgNoMatch()
7845 if (psparam)
7846 *psparam = null;
7847 return MATCH.nomatch;
7850 MATCH matchArgParameter()
7852 RootObject oarg;
7854 if (i < tiargs.dim)
7855 oarg = (*tiargs)[i];
7856 else
7858 // Get default argument instead
7859 oarg = tp.defaultArg(instLoc, sc);
7860 if (!oarg)
7862 assert(i < dedtypes.dim);
7863 // It might have already been deduced
7864 oarg = (*dedtypes)[i];
7865 if (!oarg)
7866 return matchArgNoMatch();
7869 return tp.matchArg(sc, oarg, i, parameters, dedtypes, psparam);
7872 MATCH matchArgTuple(TemplateTupleParameter ttp)
7874 /* The rest of the actual arguments (tiargs[]) form the match
7875 * for the variadic parameter.
7877 assert(i + 1 == dedtypes.dim); // must be the last one
7878 Tuple ovar;
7880 if (Tuple u = isTuple((*dedtypes)[i]))
7882 // It has already been deduced
7883 ovar = u;
7885 else if (i + 1 == tiargs.dim && isTuple((*tiargs)[i]))
7886 ovar = isTuple((*tiargs)[i]);
7887 else
7889 ovar = new Tuple();
7890 //printf("ovar = %p\n", ovar);
7891 if (i < tiargs.dim)
7893 //printf("i = %d, tiargs.dim = %d\n", i, tiargs.dim);
7894 ovar.objects.setDim(tiargs.dim - i);
7895 foreach (j, ref obj; ovar.objects)
7896 obj = (*tiargs)[i + j];
7899 return ttp.matchArg(sc, ovar, i, parameters, dedtypes, psparam);
7902 if (auto ttp = tp.isTemplateTupleParameter())
7903 return matchArgTuple(ttp);
7904 else
7905 return matchArgParameter();
7908 MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
7910 MATCH matchArgNoMatch()
7912 //printf("\tm = %d\n", MATCH.nomatch);
7913 if (psparam)
7914 *psparam = null;
7915 return MATCH.nomatch;
7918 MATCH matchArgType(TemplateTypeParameter ttp)
7920 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
7921 MATCH m = MATCH.exact;
7922 Type ta = isType(oarg);
7923 if (!ta)
7925 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
7926 return matchArgNoMatch();
7928 //printf("ta is %s\n", ta.toChars());
7930 if (ttp.specType)
7932 if (!ta || ta == TemplateTypeParameter.tdummy)
7933 return matchArgNoMatch();
7935 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
7936 MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
7937 if (m2 == MATCH.nomatch)
7939 //printf("\tfailed deduceType\n");
7940 return matchArgNoMatch();
7943 if (m2 < m)
7944 m = m2;
7945 if ((*dedtypes)[i])
7947 Type t = cast(Type)(*dedtypes)[i];
7949 if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
7950 return matchArgNoMatch();
7952 /* This is a self-dependent parameter. For example:
7953 * template X(T : T*) {}
7954 * template X(T : S!T, alias S) {}
7956 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
7957 ta = t;
7960 else
7962 if ((*dedtypes)[i])
7964 // Must match already deduced type
7965 Type t = cast(Type)(*dedtypes)[i];
7967 if (!t.equals(ta))
7969 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
7970 return matchArgNoMatch();
7973 else
7975 // So that matches with specializations are better
7976 m = MATCH.convert;
7979 (*dedtypes)[i] = ta;
7981 if (psparam)
7982 *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
7983 //printf("\tm = %d\n", m);
7984 return ttp.dependent ? MATCH.exact : m;
7987 MATCH matchArgValue(TemplateValueParameter tvp)
7989 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
7990 MATCH m = MATCH.exact;
7992 Expression ei = isExpression(oarg);
7993 Type vt;
7995 if (!ei && oarg)
7997 Dsymbol si = isDsymbol(oarg);
7998 FuncDeclaration f = si ? si.isFuncDeclaration() : null;
7999 if (!f || !f.fbody || f.needThis())
8000 return matchArgNoMatch();
8002 ei = new VarExp(tvp.loc, f);
8003 ei = ei.expressionSemantic(sc);
8005 /* If a function is really property-like, and then
8006 * it's CTFEable, ei will be a literal expression.
8008 uint olderrors = global.startGagging();
8009 ei = resolveProperties(sc, ei);
8010 ei = ei.ctfeInterpret();
8011 if (global.endGagging(olderrors) || ei.op == EXP.error)
8012 return matchArgNoMatch();
8014 /* https://issues.dlang.org/show_bug.cgi?id=14520
8015 * A property-like function can match to both
8016 * TemplateAlias and ValueParameter. But for template overloads,
8017 * it should always prefer alias parameter to be consistent
8018 * template match result.
8020 * template X(alias f) { enum X = 1; }
8021 * template X(int val) { enum X = 2; }
8022 * int f1() { return 0; } // CTFEable
8023 * int f2(); // body-less function is not CTFEable
8024 * enum x1 = X!f1; // should be 1
8025 * enum x2 = X!f2; // should be 1
8027 * e.g. The x1 value must be same even if the f1 definition will be moved
8028 * into di while stripping body code.
8030 m = MATCH.convert;
8033 if (ei && ei.op == EXP.variable)
8035 // Resolve const variables that we had skipped earlier
8036 ei = ei.ctfeInterpret();
8039 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
8040 vt = tvp.valType.typeSemantic(tvp.loc, sc);
8041 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
8042 //printf("vt = %s\n", vt.toChars());
8044 if (ei.type)
8046 MATCH m2 = ei.implicitConvTo(vt);
8047 //printf("m: %d\n", m);
8048 if (m2 < m)
8049 m = m2;
8050 if (m == MATCH.nomatch)
8051 return matchArgNoMatch();
8052 ei = ei.implicitCastTo(sc, vt);
8053 ei = ei.ctfeInterpret();
8056 if (tvp.specValue)
8058 if (ei is null || (cast(void*)ei.type in TemplateValueParameter.edummies &&
8059 TemplateValueParameter.edummies[cast(void*)ei.type] == ei))
8060 return matchArgNoMatch();
8062 Expression e = tvp.specValue;
8064 sc = sc.startCTFE();
8065 e = e.expressionSemantic(sc);
8066 e = resolveProperties(sc, e);
8067 sc = sc.endCTFE();
8068 e = e.implicitCastTo(sc, vt);
8069 e = e.ctfeInterpret();
8071 ei = ei.syntaxCopy();
8072 sc = sc.startCTFE();
8073 ei = ei.expressionSemantic(sc);
8074 sc = sc.endCTFE();
8075 ei = ei.implicitCastTo(sc, vt);
8076 ei = ei.ctfeInterpret();
8077 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
8078 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
8079 if (!ei.equals(e))
8080 return matchArgNoMatch();
8082 else
8084 if ((*dedtypes)[i])
8086 // Must match already deduced value
8087 Expression e = cast(Expression)(*dedtypes)[i];
8088 if (!ei || !ei.equals(e))
8089 return matchArgNoMatch();
8092 (*dedtypes)[i] = ei;
8094 if (psparam)
8096 Initializer _init = new ExpInitializer(tvp.loc, ei);
8097 Declaration sparam = new VarDeclaration(tvp.loc, vt, tvp.ident, _init);
8098 sparam.storage_class = STC.manifest;
8099 *psparam = sparam;
8101 return tvp.dependent ? MATCH.exact : m;
8104 MATCH matchArgAlias(TemplateAliasParameter tap)
8106 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
8107 MATCH m = MATCH.exact;
8108 Type ta = isType(oarg);
8109 RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
8110 Expression ea = isExpression(oarg);
8111 if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
8112 sa = (cast(ThisExp)ea).var;
8113 else if (ea && ea.op == EXP.scope_)
8114 sa = (cast(ScopeExp)ea).sds;
8115 if (sa)
8117 if ((cast(Dsymbol)sa).isAggregateDeclaration())
8118 m = MATCH.convert;
8120 /* specType means the alias must be a declaration with a type
8121 * that matches specType.
8123 if (tap.specType)
8125 Declaration d = (cast(Dsymbol)sa).isDeclaration();
8126 if (!d)
8127 return matchArgNoMatch();
8128 if (!d.type.equals(tap.specType))
8129 return matchArgNoMatch();
8132 else
8134 sa = oarg;
8135 if (ea)
8137 if (tap.specType)
8139 if (!ea.type.equals(tap.specType))
8140 return matchArgNoMatch();
8143 else if (ta && ta.ty == Tinstance && !tap.specAlias)
8145 /* Specialized parameter should be preferred
8146 * match to the template type parameter.
8147 * template X(alias a) {} // a == this
8148 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
8151 else if (sa && sa == TemplateTypeParameter.tdummy)
8153 /* https://issues.dlang.org/show_bug.cgi?id=2025
8154 * Aggregate Types should preferentially
8155 * match to the template type parameter.
8156 * template X(alias a) {} // a == this
8157 * template X(T) {} // T => sa
8160 else if (ta && ta.ty != Tident)
8162 /* Match any type that's not a TypeIdentifier to alias parameters,
8163 * but prefer type parameter.
8164 * template X(alias a) { } // a == ta
8166 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
8168 m = MATCH.convert;
8170 else
8171 return matchArgNoMatch();
8174 if (tap.specAlias)
8176 if (sa == TemplateAliasParameter.sdummy)
8177 return matchArgNoMatch();
8178 // check specialization if template arg is a symbol
8179 Dsymbol sx = isDsymbol(sa);
8180 if (sa != tap.specAlias && sx)
8182 Type talias = isType(tap.specAlias);
8183 if (!talias)
8184 return matchArgNoMatch();
8186 TemplateInstance ti = sx.isTemplateInstance();
8187 if (!ti && sx.parent)
8189 ti = sx.parent.isTemplateInstance();
8190 if (ti && ti.name != sx.ident)
8191 return matchArgNoMatch();
8193 if (!ti)
8194 return matchArgNoMatch();
8196 Type t = new TypeInstance(Loc.initial, ti);
8197 MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
8198 if (m2 == MATCH.nomatch)
8199 return matchArgNoMatch();
8201 // check specialization if template arg is a type
8202 else if (ta)
8204 if (Type tspec = isType(tap.specAlias))
8206 MATCH m2 = ta.implicitConvTo(tspec);
8207 if (m2 == MATCH.nomatch)
8208 return matchArgNoMatch();
8210 else
8212 error(tap.loc, "template parameter specialization for a type must be a type and not `%s`",
8213 tap.specAlias.toChars());
8214 return matchArgNoMatch();
8218 else if ((*dedtypes)[i])
8220 // Must match already deduced symbol
8221 RootObject si = (*dedtypes)[i];
8222 if (!sa || si != sa)
8223 return matchArgNoMatch();
8225 (*dedtypes)[i] = sa;
8227 if (psparam)
8229 if (Dsymbol s = isDsymbol(sa))
8231 *psparam = new AliasDeclaration(tap.loc, tap.ident, s);
8233 else if (Type t = isType(sa))
8235 *psparam = new AliasDeclaration(tap.loc, tap.ident, t);
8237 else
8239 assert(ea);
8241 // Declare manifest constant
8242 Initializer _init = new ExpInitializer(tap.loc, ea);
8243 auto v = new VarDeclaration(tap.loc, null, tap.ident, _init);
8244 v.storage_class = STC.manifest;
8245 v.dsymbolSemantic(sc);
8246 *psparam = v;
8249 return tap.dependent ? MATCH.exact : m;
8252 MATCH matchArgTuple(TemplateTupleParameter ttp)
8254 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
8255 Tuple ovar = isTuple(oarg);
8256 if (!ovar)
8257 return MATCH.nomatch;
8258 if ((*dedtypes)[i])
8260 Tuple tup = isTuple((*dedtypes)[i]);
8261 if (!tup)
8262 return MATCH.nomatch;
8263 if (!match(tup, ovar))
8264 return MATCH.nomatch;
8266 (*dedtypes)[i] = ovar;
8268 if (psparam)
8269 *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
8270 return ttp.dependent ? MATCH.exact : MATCH.convert;
8273 if (auto ttp = tp.isTemplateTypeParameter())
8274 return matchArgType(ttp);
8275 else if (auto tvp = tp.isTemplateValueParameter())
8276 return matchArgValue(tvp);
8277 else if (auto tap = tp.isTemplateAliasParameter())
8278 return matchArgAlias(tap);
8279 else if (auto ttp = tp.isTemplateTupleParameter())
8280 return matchArgTuple(ttp);
8281 else
8282 assert(0);
8286 /***********************************************
8287 * Collect and print statistics on template instantiations.
8289 struct TemplateStats
8291 __gshared TemplateStats[const void*] stats;
8293 uint numInstantiations; // number of instantiations of the template
8294 uint uniqueInstantiations; // number of unique instantiations of the template
8296 TemplateInstances* allInstances;
8298 /*******************************
8299 * Add this instance
8301 static void incInstance(const TemplateDeclaration td,
8302 const TemplateInstance ti)
8304 void log(ref TemplateStats ts)
8306 if (ts.allInstances is null)
8307 ts.allInstances = new TemplateInstances();
8308 if (global.params.vtemplatesListInstances)
8309 ts.allInstances.push(cast() ti);
8312 // message(ti.loc, "incInstance %p %p", td, ti);
8313 if (!global.params.vtemplates)
8314 return;
8315 if (!td)
8316 return;
8317 assert(ti);
8318 if (auto ts = cast(const void*) td in stats)
8320 log(*ts);
8321 ++ts.numInstantiations;
8323 else
8325 stats[cast(const void*) td] = TemplateStats(1, 0);
8326 log(stats[cast(const void*) td]);
8330 /*******************************
8331 * Add this unique instance
8333 static void incUnique(const TemplateDeclaration td,
8334 const TemplateInstance ti)
8336 // message(ti.loc, "incUnique %p %p", td, ti);
8337 if (!global.params.vtemplates)
8338 return;
8339 if (!td)
8340 return;
8341 assert(ti);
8342 if (auto ts = cast(const void*) td in stats)
8343 ++ts.uniqueInstantiations;
8344 else
8345 stats[cast(const void*) td] = TemplateStats(0, 1);
8349 extern (C++) void printTemplateStats()
8351 static struct TemplateDeclarationStats
8353 TemplateDeclaration td;
8354 TemplateStats ts;
8355 static int compare(scope const TemplateDeclarationStats* a,
8356 scope const TemplateDeclarationStats* b) @safe nothrow @nogc pure
8358 auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations;
8359 if (diff)
8360 return diff;
8361 else
8362 return b.ts.numInstantiations - a.ts.numInstantiations;
8366 if (!global.params.vtemplates)
8367 return;
8369 Array!(TemplateDeclarationStats) sortedStats;
8370 sortedStats.reserve(TemplateStats.stats.length);
8371 foreach (td_, ref ts; TemplateStats.stats)
8373 sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
8376 sortedStats.sort!(TemplateDeclarationStats.compare);
8378 foreach (const ref ss; sortedStats[])
8380 if (global.params.vtemplatesListInstances &&
8381 ss.ts.allInstances)
8383 message(ss.td.loc,
8384 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
8385 ss.ts.numInstantiations,
8386 ss.ts.uniqueInstantiations,
8387 ss.td.toCharsNoConstraints());
8388 foreach (const ti; (*ss.ts.allInstances)[])
8390 if (ti.tinst) // if has enclosing instance
8391 message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
8392 else
8393 message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
8396 else
8398 message(ss.td.loc,
8399 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
8400 ss.ts.numInstantiations,
8401 ss.ts.uniqueInstantiations,
8402 ss.td.toCharsNoConstraints());
8407 /// Pair of MATCHes
8408 private struct MATCHpair
8410 MATCH mta; /// match template parameters by initial template arguments
8411 MATCH mfa; /// match template parameters by inferred template arguments
8413 debug this(MATCH mta, MATCH mfa)
8415 assert(MATCH.min <= mta && mta <= MATCH.max);
8416 assert(MATCH.min <= mfa && mfa <= MATCH.max);
8417 this.mta = mta;
8418 this.mfa = mfa;
8422 private void write(ref OutBuffer buf, RootObject obj)
8424 if (obj)
8426 buf.writestring(obj.toChars());