d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[official-gcc.git] / gcc / d / dmd / dtemplate.d
blobad3a6d4dd54f9e9af4904691d87ad341e5f438a7
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-2023 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.attrib;
49 import dmd.dcast;
50 import dmd.dclass;
51 import dmd.declaration;
52 import dmd.dmangle;
53 import dmd.dmodule;
54 import dmd.dscope;
55 import dmd.dsymbol;
56 import dmd.dsymbolsem;
57 import dmd.errors;
58 import dmd.expression;
59 import dmd.expressionsem;
60 import dmd.func;
61 import dmd.globals;
62 import dmd.hdrgen;
63 import dmd.id;
64 import dmd.identifier;
65 import dmd.impcnvtab;
66 import dmd.init;
67 import dmd.initsem;
68 import dmd.location;
69 import dmd.mtype;
70 import dmd.opover;
71 import dmd.root.array;
72 import dmd.common.outbuffer;
73 import dmd.root.rootobject;
74 import dmd.semantic2;
75 import dmd.semantic3;
76 import dmd.tokens;
77 import dmd.typesem;
78 import dmd.visitor;
80 import dmd.templateparamsem;
82 //debug = FindExistingInstance; // print debug stats of findExistingInstance
83 private enum LOG = false;
85 enum IDX_NOTFOUND = 0x12345678;
87 pure nothrow @nogc
90 /********************************************
91 * These functions substitute for dynamic_cast. dynamic_cast does not work
92 * on earlier versions of gcc.
94 extern (C++) inout(Expression) isExpression(inout RootObject o)
96 //return dynamic_cast<Expression *>(o);
97 if (!o || o.dyncast() != DYNCAST.expression)
98 return null;
99 return cast(inout(Expression))o;
102 extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o)
104 //return dynamic_cast<Dsymbol *>(o);
105 if (!o || o.dyncast() != DYNCAST.dsymbol)
106 return null;
107 return cast(inout(Dsymbol))o;
110 extern (C++) inout(Type) isType(inout RootObject o)
112 //return dynamic_cast<Type *>(o);
113 if (!o || o.dyncast() != DYNCAST.type)
114 return null;
115 return cast(inout(Type))o;
118 extern (C++) inout(Tuple) isTuple(inout RootObject o)
120 //return dynamic_cast<Tuple *>(o);
121 if (!o || o.dyncast() != DYNCAST.tuple)
122 return null;
123 return cast(inout(Tuple))o;
126 extern (C++) inout(Parameter) isParameter(inout RootObject o)
128 //return dynamic_cast<Parameter *>(o);
129 if (!o || o.dyncast() != DYNCAST.parameter)
130 return null;
131 return cast(inout(Parameter))o;
134 extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o)
136 if (!o || o.dyncast() != DYNCAST.templateparameter)
137 return null;
138 return cast(inout(TemplateParameter))o;
141 /**************************************
142 * Is this Object an error?
144 extern (C++) bool isError(const RootObject o)
146 if (const t = isType(o))
147 return (t.ty == Terror);
148 if (const e = isExpression(o))
149 return (e.op == EXP.error || !e.type || e.type.ty == Terror);
150 if (const v = isTuple(o))
151 return arrayObjectIsError(&v.objects);
152 const s = isDsymbol(o);
153 assert(s);
154 if (s.errors)
155 return true;
156 return s.parent ? isError(s.parent) : false;
159 /**************************************
160 * Are any of the Objects an error?
162 bool arrayObjectIsError(const Objects* args)
164 foreach (const o; *args)
166 if (isError(o))
167 return true;
169 return false;
172 /***********************
173 * Try to get arg as a type.
175 inout(Type) getType(inout RootObject o)
177 inout t = isType(o);
178 if (!t)
180 if (inout e = isExpression(o))
181 return e.type;
183 return t;
188 Dsymbol getDsymbol(RootObject oarg)
190 //printf("getDsymbol()\n");
191 //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
192 if (auto ea = isExpression(oarg))
194 // Try to convert Expression to symbol
195 if (auto ve = ea.isVarExp())
196 return ve.var;
197 else if (auto fe = ea.isFuncExp())
198 return fe.td ? fe.td : fe.fd;
199 else if (auto te = ea.isTemplateExp())
200 return te.td;
201 else if (auto te = ea.isScopeExp())
202 return te.sds;
203 else
204 return null;
206 else
208 // Try to convert Type to symbol
209 if (auto ta = isType(oarg))
210 return ta.toDsymbol(null);
211 else
212 return isDsymbol(oarg); // if already a symbol
217 private Expression getValue(ref Dsymbol s)
219 if (s)
221 if (VarDeclaration v = s.isVarDeclaration())
223 if (v.storage_class & STC.manifest)
224 return v.getConstInitializer();
227 return null;
230 /***********************
231 * Try to get value from manifest constant
233 private Expression getValue(Expression e)
235 if (!e)
236 return null;
237 if (auto ve = e.isVarExp())
239 if (auto v = ve.var.isVarDeclaration())
241 if (v.storage_class & STC.manifest)
243 e = v.getConstInitializer();
247 return e;
250 private Expression getExpression(RootObject o)
252 auto s = isDsymbol(o);
253 return s ? .getValue(s) : .getValue(isExpression(o));
256 /******************************
257 * If o1 matches o2, return true.
258 * Else, return false.
260 private bool match(RootObject o1, RootObject o2)
262 enum log = false;
264 static if (log)
266 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
267 o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
270 /* A proper implementation of the various equals() overrides
271 * should make it possible to just do o1.equals(o2), but
272 * we'll do that another day.
274 /* Manifest constants should be compared by their values,
275 * at least in template arguments.
278 if (auto t1 = isType(o1))
280 auto t2 = isType(o2);
281 if (!t2)
282 goto Lnomatch;
284 static if (log)
286 printf("\tt1 = %s\n", t1.toChars());
287 printf("\tt2 = %s\n", t2.toChars());
289 if (!t1.equals(t2))
290 goto Lnomatch;
292 goto Lmatch;
294 if (auto e1 = getExpression(o1))
296 auto e2 = getExpression(o2);
297 if (!e2)
298 goto Lnomatch;
300 static if (log)
302 printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars());
303 printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars());
306 // two expressions can be equal although they do not have the same
307 // type; that happens when they have the same value. So check type
308 // as well as expression equality to ensure templates are properly
309 // matched.
310 if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2))
311 goto Lnomatch;
313 goto Lmatch;
315 if (auto s1 = isDsymbol(o1))
317 auto s2 = isDsymbol(o2);
318 if (!s2)
319 goto Lnomatch;
321 static if (log)
323 printf("\ts1 = %s \n", s1.kind(), s1.toChars());
324 printf("\ts2 = %s \n", s2.kind(), s2.toChars());
326 if (!s1.equals(s2))
327 goto Lnomatch;
328 if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
329 goto Lnomatch;
331 goto Lmatch;
333 if (auto u1 = isTuple(o1))
335 auto u2 = isTuple(o2);
336 if (!u2)
337 goto Lnomatch;
339 static if (log)
341 printf("\tu1 = %s\n", u1.toChars());
342 printf("\tu2 = %s\n", u2.toChars());
344 if (!arrayObjectMatch(&u1.objects, &u2.objects))
345 goto Lnomatch;
347 goto Lmatch;
349 Lmatch:
350 static if (log)
351 printf("\t. match\n");
352 return true;
354 Lnomatch:
355 static if (log)
356 printf("\t. nomatch\n");
357 return false;
360 /************************************
361 * Match an array of them.
363 private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
365 if (oa1 == oa2)
366 return true;
367 if (oa1.length != oa2.length)
368 return false;
369 immutable oa1dim = oa1.length;
370 auto oa1d = (*oa1)[].ptr;
371 auto oa2d = (*oa2)[].ptr;
372 foreach (j; 0 .. oa1dim)
374 RootObject o1 = oa1d[j];
375 RootObject o2 = oa2d[j];
376 if (!match(o1, o2))
378 return false;
381 return true;
384 /************************************
385 * Return hash of Objects.
387 private size_t arrayObjectHash(Objects* oa1)
389 import dmd.root.hash : mixHash;
391 size_t hash = 0;
392 foreach (o1; *oa1)
394 /* Must follow the logic of match()
396 if (auto t1 = isType(o1))
397 hash = mixHash(hash, cast(size_t)t1.deco);
398 else if (auto e1 = getExpression(o1))
399 hash = mixHash(hash, expressionHash(e1));
400 else if (auto s1 = isDsymbol(o1))
402 auto fa1 = s1.isFuncAliasDeclaration();
403 if (fa1)
404 s1 = fa1.toAliasFunc();
405 hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
407 else if (auto u1 = isTuple(o1))
408 hash = mixHash(hash, arrayObjectHash(&u1.objects));
410 return hash;
414 /************************************
415 * Computes hash of expression.
416 * Handles all Expression classes and MUST match their equals method,
417 * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2).
419 private size_t expressionHash(Expression e)
421 import dmd.root.ctfloat : CTFloat;
422 import dmd.root.hash : calcHash, mixHash;
424 switch (e.op)
426 case EXP.int64:
427 return cast(size_t) e.isIntegerExp().getInteger();
429 case EXP.float64:
430 return CTFloat.hash(e.isRealExp().value);
432 case EXP.complex80:
433 auto ce = e.isComplexExp();
434 return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary));
436 case EXP.identifier:
437 return cast(size_t)cast(void*) e.isIdentifierExp().ident;
439 case EXP.null_:
440 return cast(size_t)cast(void*) e.isNullExp().type;
442 case EXP.string_:
443 return calcHash(e.isStringExp.peekData());
445 case EXP.tuple:
447 auto te = e.isTupleExp();
448 size_t hash = 0;
449 hash += te.e0 ? expressionHash(te.e0) : 0;
450 foreach (elem; *te.exps)
451 hash = mixHash(hash, expressionHash(elem));
452 return hash;
455 case EXP.arrayLiteral:
457 auto ae = e.isArrayLiteralExp();
458 size_t hash;
459 foreach (i; 0 .. ae.elements.length)
460 hash = mixHash(hash, expressionHash(ae[i]));
461 return hash;
464 case EXP.assocArrayLiteral:
466 auto ae = e.isAssocArrayLiteralExp();
467 size_t hash;
468 foreach (i; 0 .. ae.keys.length)
469 // reduction needs associative op as keys are unsorted (use XOR)
470 hash ^= mixHash(expressionHash((*ae.keys)[i]), expressionHash((*ae.values)[i]));
471 return hash;
474 case EXP.structLiteral:
476 auto se = e.isStructLiteralExp();
477 size_t hash;
478 foreach (elem; *se.elements)
479 hash = mixHash(hash, elem ? expressionHash(elem) : 0);
480 return hash;
483 case EXP.variable:
484 return cast(size_t)cast(void*) e.isVarExp().var;
486 case EXP.function_:
487 return cast(size_t)cast(void*) e.isFuncExp().fd;
489 default:
490 // no custom equals for this expression
491 assert((&e.equals).funcptr is &RootObject.equals);
492 // equals based on identity
493 return cast(size_t)cast(void*) e;
497 RootObject objectSyntaxCopy(RootObject o)
499 if (!o)
500 return null;
501 if (Type t = isType(o))
502 return t.syntaxCopy();
503 if (Expression e = isExpression(o))
504 return e.syntaxCopy();
505 return o;
508 extern (C++) final class Tuple : RootObject
510 Objects objects;
512 extern (D) this() {}
515 Params:
516 numObjects = The initial number of objects.
518 extern (D) this(size_t numObjects)
520 objects.setDim(numObjects);
523 // kludge for template.isType()
524 override DYNCAST dyncast() const
526 return DYNCAST.tuple;
529 override const(char)* toChars() const
531 return objects.toChars();
535 struct TemplatePrevious
537 TemplatePrevious* prev;
538 Scope* sc;
539 Objects* dedargs;
542 /***********************************************************
543 * [mixin] template Identifier (parameters) [Constraint]
544 * https://dlang.org/spec/template.html
545 * https://dlang.org/spec/template-mixin.html
547 extern (C++) final class TemplateDeclaration : ScopeDsymbol
549 import dmd.root.array : Array;
551 TemplateParameters* parameters; // array of TemplateParameter's
552 TemplateParameters* origParameters; // originals for Ddoc
554 Expression constraint;
556 // Hash table to look up TemplateInstance's of this TemplateDeclaration
557 TemplateInstance[TemplateInstanceBox] instances;
559 TemplateDeclaration overnext; // next overloaded TemplateDeclaration
560 TemplateDeclaration overroot; // first in overnext list
561 FuncDeclaration funcroot; // first function in unified overload list
563 Dsymbol onemember; // if !=null then one member of this template
565 bool literal; // this template declaration is a literal
566 bool ismixin; // this is a mixin template declaration
567 bool isstatic; // this is static template declaration
568 bool isTrivialAliasSeq; /// matches pattern `template AliasSeq(T...) { alias AliasSeq = T; }`
569 bool isTrivialAlias; /// matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
570 bool deprecated_; /// this template declaration is deprecated
571 Visibility visibility;
573 // threaded list of previous instantiation attempts on stack
574 TemplatePrevious* previous;
576 private Expression lastConstraint; /// the constraint after the last failed evaluation
577 private Array!Expression lastConstraintNegs; /// its negative parts
578 private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
580 extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
582 super(loc, ident);
583 static if (LOG)
585 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident.toChars());
587 version (none)
589 if (parameters)
590 for (int i = 0; i < parameters.length; i++)
592 TemplateParameter tp = (*parameters)[i];
593 //printf("\tparameter[%d] = %p\n", i, tp);
594 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
595 if (ttp)
597 printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
601 this.parameters = parameters;
602 this.origParameters = parameters;
603 this.constraint = constraint;
604 this.members = decldefs;
605 this.literal = literal;
606 this.ismixin = ismixin;
607 this.isstatic = true;
608 this.visibility = Visibility(Visibility.Kind.undefined);
610 // Compute in advance for Ddoc's use
611 // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails.
612 if (!members || !ident)
613 return;
615 Dsymbol s;
616 if (!Dsymbol.oneMembers(members, &s, ident) || !s)
617 return;
619 onemember = s;
620 s.parent = this;
622 /* Set isTrivialAliasSeq if this fits the pattern:
623 * template AliasSeq(T...) { alias AliasSeq = T; }
624 * or set isTrivialAlias if this fits the pattern:
625 * template Alias(T) { alias Alias = qualifiers(T); }
627 if (!(parameters && parameters.length == 1))
628 return;
630 auto ad = s.isAliasDeclaration();
631 if (!ad || !ad.type)
632 return;
634 auto ti = ad.type.isTypeIdentifier();
636 if (!ti || ti.idents.length != 0)
637 return;
639 if (auto ttp = (*parameters)[0].isTemplateTupleParameter())
641 if (ti.ident is ttp.ident &&
642 ti.mod == 0)
644 //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
645 isTrivialAliasSeq = true;
648 else if (auto ttp = (*parameters)[0].isTemplateTypeParameter())
650 if (ti.ident is ttp.ident)
652 //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
653 isTrivialAlias = true;
658 override TemplateDeclaration syntaxCopy(Dsymbol)
660 //printf("TemplateDeclaration.syntaxCopy()\n");
661 TemplateParameters* p = null;
662 if (parameters)
664 p = new TemplateParameters(parameters.length);
665 foreach (i, ref param; *p)
666 param = (*parameters)[i].syntaxCopy();
668 return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal);
671 /**********************************
672 * Overload existing TemplateDeclaration 'this' with the new one 's'.
673 * Return true if successful; i.e. no conflict.
675 override bool overloadInsert(Dsymbol s)
677 static if (LOG)
679 printf("TemplateDeclaration.overloadInsert('%s')\n", s.toChars());
681 FuncDeclaration fd = s.isFuncDeclaration();
682 if (fd)
684 if (funcroot)
685 return funcroot.overloadInsert(fd);
686 funcroot = fd;
687 return funcroot.overloadInsert(this);
690 // https://issues.dlang.org/show_bug.cgi?id=15795
691 // if candidate is an alias and its sema is not run then
692 // insertion can fail because the thing it alias is not known
693 if (AliasDeclaration ad = s.isAliasDeclaration())
695 if (s._scope)
696 aliasSemantic(ad, s._scope);
697 if (ad.aliassym && ad.aliassym is this)
698 return false;
700 TemplateDeclaration td = s.toAlias().isTemplateDeclaration();
701 if (!td)
702 return false;
704 TemplateDeclaration pthis = this;
705 TemplateDeclaration* ptd;
706 for (ptd = &pthis; *ptd; ptd = &(*ptd).overnext)
710 td.overroot = this;
711 *ptd = td;
712 static if (LOG)
714 printf("\ttrue: no conflict\n");
716 return true;
719 override bool hasStaticCtorOrDtor()
721 return false; // don't scan uninstantiated templates
724 override const(char)* kind() const
726 return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template";
729 override const(char)* toChars() const
731 return toCharsMaybeConstraints(true);
734 /****************************
735 * Similar to `toChars`, but does not print the template constraints
737 const(char)* toCharsNoConstraints() const
739 return toCharsMaybeConstraints(false);
742 const(char)* toCharsMaybeConstraints(bool includeConstraints) const
744 if (literal)
745 return Dsymbol.toChars();
747 OutBuffer buf;
748 HdrGenState hgs;
750 buf.writestring(ident.toString());
751 buf.writeByte('(');
752 foreach (i, const tp; *parameters)
754 if (i)
755 buf.writestring(", ");
756 .toCBuffer(tp, &buf, &hgs);
758 buf.writeByte(')');
760 if (onemember)
762 const FuncDeclaration fd = onemember.isFuncDeclaration();
763 if (fd && fd.type)
765 TypeFunction tf = cast(TypeFunction)fd.type;
766 buf.writestring(parametersTypeToChars(tf.parameterList));
770 if (includeConstraints &&
771 constraint)
773 buf.writestring(" if (");
774 .toCBuffer(constraint, &buf, &hgs);
775 buf.writeByte(')');
778 return buf.extractChars();
781 override Visibility visible() pure nothrow @nogc @safe
783 return visibility;
786 /****************************
787 * Check to see if constraint is satisfied.
789 extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
791 /* Detect recursive attempts to instantiate this template declaration,
792 * https://issues.dlang.org/show_bug.cgi?id=4072
793 * void foo(T)(T x) if (is(typeof(foo(x)))) { }
794 * static assert(!is(typeof(foo(7))));
795 * Recursive attempts are regarded as a constraint failure.
797 /* There's a chicken-and-egg problem here. We don't know yet if this template
798 * instantiation will be a local one (enclosing is set), and we won't know until
799 * after selecting the correct template. Thus, function we're nesting inside
800 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
801 * Workaround the problem by setting a flag to relax the checking on frame errors.
804 for (TemplatePrevious* p = previous; p; p = p.prev)
806 if (!arrayObjectMatch(p.dedargs, dedargs))
807 continue;
808 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
809 /* It must be a subscope of p.sc, other scope chains are not recursive
810 * instantiations.
811 * the chain of enclosing scopes is broken by paramscope (its enclosing
812 * scope is _scope, but paramscope.callsc is the instantiating scope). So
813 * it's good enough to check the chain of callsc
815 for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
817 // The first scx might be identical for nested eponymeous templates, e.g.
818 // template foo() { void foo()() {...} }
819 if (scx == p.sc && scx !is paramscope.callsc)
820 return false;
822 /* BUG: should also check for ref param differences
826 TemplatePrevious pr;
827 pr.prev = previous;
828 pr.sc = paramscope.callsc;
829 pr.dedargs = dedargs;
830 previous = &pr; // add this to threaded list
832 Scope* scx = paramscope.push(ti);
833 scx.parent = ti;
834 scx.tinst = null;
835 scx.minst = null;
836 // Set SCOPE.constraint before declaring function parameters for the static condition
837 // (previously, this was immediately before calling evalStaticCondition), so the
838 // semantic pass knows not to issue deprecation warnings for these throw-away decls.
839 // https://issues.dlang.org/show_bug.cgi?id=21831
840 scx.flags |= SCOPE.constraint;
842 assert(!ti.symtab);
843 if (fd)
845 /* Declare all the function parameters as variables and add them to the scope
846 * Making parameters is similar to FuncDeclaration.semantic3
848 auto tf = fd.type.isTypeFunction();
850 scx.parent = fd;
852 Parameters* fparameters = tf.parameterList.parameters;
853 const nfparams = tf.parameterList.length;
854 foreach (i, fparam; tf.parameterList)
856 fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
857 fparam.storageClass |= STC.parameter;
858 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams)
860 fparam.storageClass |= STC.variadic;
861 /* Don't need to set STC.scope_ because this will only
862 * be evaluated at compile time
866 foreach (fparam; *fparameters)
868 if (!fparam.ident)
869 continue;
870 // don't add it, if it has no name
871 auto v = new VarDeclaration(loc, fparam.type, fparam.ident, null);
872 fparam.storageClass |= STC.parameter;
873 v.storage_class = fparam.storageClass;
874 v.dsymbolSemantic(scx);
875 if (!ti.symtab)
876 ti.symtab = new DsymbolTable();
877 if (!scx.insert(v))
878 error("parameter `%s.%s` is already defined", toChars(), v.toChars());
879 else
880 v.parent = fd;
882 if (isstatic)
883 fd.storage_class |= STC.static_;
884 fd.declareThis(scx);
887 lastConstraint = constraint.syntaxCopy();
888 lastConstraintTiargs = ti.tiargs;
889 lastConstraintNegs.setDim(0);
891 import dmd.staticcond;
893 assert(ti.inst is null);
894 ti.inst = ti; // temporary instantiation to enable genIdent()
895 bool errors;
896 const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs);
897 if (result || errors)
899 lastConstraint = null;
900 lastConstraintTiargs = null;
901 lastConstraintNegs.setDim(0);
903 ti.inst = null;
904 ti.symtab = null;
905 scx = scx.pop();
906 previous = pr.prev; // unlink from threaded list
907 if (errors)
908 return false;
909 return result;
912 /****************************
913 * Destructively get the error message from the last constraint evaluation
914 * Params:
915 * tip = tip to show after printing all overloads
917 const(char)* getConstraintEvalError(ref const(char)* tip)
919 import dmd.staticcond;
921 // there will be a full tree view in verbose mode, and more compact list in the usual
922 const full = global.params.verbose;
923 uint count;
924 const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count);
925 scope (exit)
927 lastConstraint = null;
928 lastConstraintTiargs = null;
929 lastConstraintNegs.setDim(0);
931 if (!msg)
932 return null;
934 OutBuffer buf;
936 assert(parameters && lastConstraintTiargs);
937 if (parameters.length > 0)
939 formatParamsWithTiargs(*lastConstraintTiargs, buf);
940 buf.writenl();
942 if (!full)
944 // choosing singular/plural
945 const s = (count == 1) ?
946 " must satisfy the following constraint:" :
947 " must satisfy one of the following constraints:";
948 buf.writestring(s);
949 buf.writenl();
950 // the constraints
951 buf.writeByte('`');
952 buf.writestring(msg);
953 buf.writeByte('`');
955 else
957 buf.writestring(" whose parameters have the following constraints:");
958 buf.writenl();
959 const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
960 buf.writestring(sep);
961 buf.writenl();
962 // the constraints
963 buf.writeByte('`');
964 buf.writestring(msg);
965 buf.writeByte('`');
966 buf.writestring(sep);
967 tip = "not satisfied constraints are marked with `>`";
969 return buf.extractChars();
972 private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf)
974 buf.writestring(" with `");
976 // write usual arguments line-by-line
977 // skips trailing default ones - they are not present in `tiargs`
978 const bool variadic = isVariadic() !is null;
979 const end = cast(int)parameters.length - (variadic ? 1 : 0);
980 uint i;
981 for (; i < tiargs.length && i < end; i++)
983 if (i > 0)
985 buf.writeByte(',');
986 buf.writenl();
987 buf.writestring(" ");
989 write(buf, (*parameters)[i]);
990 buf.writestring(" = ");
991 write(buf, tiargs[i]);
993 // write remaining variadic arguments on the last line
994 if (variadic)
996 if (i > 0)
998 buf.writeByte(',');
999 buf.writenl();
1000 buf.writestring(" ");
1002 write(buf, (*parameters)[end]);
1003 buf.writestring(" = ");
1004 buf.writeByte('(');
1005 if (cast(int)tiargs.length - end > 0)
1007 write(buf, tiargs[end]);
1008 foreach (j; parameters.length .. tiargs.length)
1010 buf.writestring(", ");
1011 write(buf, tiargs[j]);
1014 buf.writeByte(')');
1016 buf.writeByte('`');
1019 /******************************
1020 * Create a scope for the parameters of the TemplateInstance
1021 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
1023 * If paramsym is null a new ScopeDsymbol is used in place of
1024 * paramsym.
1025 * Params:
1026 * ti = the TemplateInstance whose parameters to generate the scope for.
1027 * sc = the parent scope of ti
1028 * Returns:
1029 * a scope for the parameters of ti
1031 Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc)
1033 ScopeDsymbol paramsym = new ScopeDsymbol();
1034 paramsym.parent = _scope.parent;
1035 Scope* paramscope = _scope.push(paramsym);
1036 paramscope.tinst = ti;
1037 paramscope.minst = sc.minst;
1038 paramscope.callsc = sc;
1039 paramscope.stc = 0;
1040 return paramscope;
1043 /***************************************
1044 * Given that ti is an instance of this TemplateDeclaration,
1045 * deduce the types of the parameters to this, and store
1046 * those deduced types in dedtypes[].
1047 * Input:
1048 * flag 1: don't do semantic() because of dummy types
1049 * 2: don't change types in matchArg()
1050 * Output:
1051 * dedtypes deduced arguments
1052 * Return match level.
1054 extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag)
1056 enum LOGM = 0;
1057 static if (LOGM)
1059 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag);
1061 version (none)
1063 printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length);
1064 if (ti.tiargs.length)
1065 printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]);
1067 MATCH nomatch()
1069 static if (LOGM)
1071 printf(" no match\n");
1073 return MATCH.nomatch;
1075 MATCH m;
1076 size_t dedtypes_dim = dedtypes.length;
1078 dedtypes.zero();
1080 if (errors)
1081 return MATCH.nomatch;
1083 size_t parameters_dim = parameters.length;
1084 int variadic = isVariadic() !is null;
1086 // If more arguments than parameters, no match
1087 if (ti.tiargs.length > parameters_dim && !variadic)
1089 static if (LOGM)
1091 printf(" no match: more arguments than parameters\n");
1093 return MATCH.nomatch;
1096 assert(dedtypes_dim == parameters_dim);
1097 assert(dedtypes_dim >= ti.tiargs.length || variadic);
1099 assert(_scope);
1101 // Set up scope for template parameters
1102 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1104 // Attempt type deduction
1105 m = MATCH.exact;
1106 for (size_t i = 0; i < dedtypes_dim; i++)
1108 MATCH m2;
1109 TemplateParameter tp = (*parameters)[i];
1110 Declaration sparam;
1112 //printf("\targument [%d]\n", i);
1113 static if (LOGM)
1115 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
1116 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
1117 if (ttp)
1118 printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
1121 m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam);
1122 //printf("\tm2 = %d\n", m2);
1123 if (m2 == MATCH.nomatch)
1125 version (none)
1127 printf("\tmatchArg() for parameter %i failed\n", i);
1129 return nomatch();
1132 if (m2 < m)
1133 m = m2;
1135 if (!flag)
1136 sparam.dsymbolSemantic(paramscope);
1137 if (!paramscope.insert(sparam)) // TODO: This check can make more early
1139 // in TemplateDeclaration.semantic, and
1140 // then we don't need to make sparam if flags == 0
1141 return nomatch();
1145 if (!flag)
1147 /* Any parameter left without a type gets the type of
1148 * its corresponding arg
1150 foreach (i, ref dedtype; *dedtypes)
1152 if (!dedtype)
1154 assert(i < ti.tiargs.length);
1155 dedtype = cast(Type)(*ti.tiargs)[i];
1160 if (m > MATCH.nomatch && constraint && !flag)
1162 if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error
1163 ti.parent = ti.enclosing;
1164 else
1165 ti.parent = this.parent;
1167 // Similar to doHeaderInstantiation
1168 FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null;
1169 if (fd)
1171 TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
1172 if (argumentList.hasNames)
1173 return nomatch();
1174 Expressions* fargs = argumentList.arguments;
1175 // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
1176 // if (!fargs)
1177 // return nomatch();
1179 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
1180 fd.parent = ti;
1181 fd.inferRetType = true;
1183 // Shouldn't run semantic on default arguments and return type.
1184 foreach (ref param; *tf.parameterList.parameters)
1185 param.defaultArg = null;
1187 tf.next = null;
1188 tf.incomplete = true;
1190 // Resolve parameter types and 'auto ref's.
1191 tf.fargs = fargs;
1192 uint olderrors = global.startGagging();
1193 fd.type = tf.typeSemantic(loc, paramscope);
1194 global.endGagging(olderrors);
1195 if (fd.type.ty != Tfunction)
1196 return nomatch();
1197 fd.originalType = fd.type; // for mangling
1200 // TODO: dedtypes => ti.tiargs ?
1201 if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
1202 return nomatch();
1205 static if (LOGM)
1207 // Print out the results
1208 printf("--------------------------\n");
1209 printf("template %s\n", toChars());
1210 printf("instance %s\n", ti.toChars());
1211 if (m > MATCH.nomatch)
1213 for (size_t i = 0; i < dedtypes_dim; i++)
1215 TemplateParameter tp = (*parameters)[i];
1216 RootObject oarg;
1217 printf(" [%d]", i);
1218 if (i < ti.tiargs.length)
1219 oarg = (*ti.tiargs)[i];
1220 else
1221 oarg = null;
1222 tp.print(oarg, (*dedtypes)[i]);
1225 else
1226 return nomatch();
1228 static if (LOGM)
1230 printf(" match = %d\n", m);
1233 paramscope.pop();
1234 static if (LOGM)
1236 printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m);
1238 return m;
1241 /********************************************
1242 * Determine partial specialization order of 'this' vs td2.
1243 * Returns:
1244 * match this is at least as specialized as td2
1245 * 0 td2 is more specialized than this
1247 MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList)
1249 enum LOG_LEASTAS = 0;
1250 static if (LOG_LEASTAS)
1252 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
1255 /* This works by taking the template parameters to this template
1256 * declaration and feeding them to td2 as if it were a template
1257 * instance.
1258 * If it works, then this template is at least as specialized
1259 * as td2.
1262 // Set type arguments to dummy template instance to be types
1263 // generated from the parameters to this template declaration
1264 auto tiargs = new Objects();
1265 tiargs.reserve(parameters.length);
1266 foreach (tp; *parameters)
1268 if (tp.dependent)
1269 break;
1270 RootObject p = tp.dummyArg();
1271 if (!p) //TemplateTupleParameter
1272 break;
1274 tiargs.push(p);
1276 scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance
1278 // Temporary Array to hold deduced types
1279 Objects dedtypes = Objects(td2.parameters.length);
1281 // Attempt a type deduction
1282 MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1);
1283 if (m > MATCH.nomatch)
1285 /* A non-variadic template is more specialized than a
1286 * variadic one.
1288 TemplateTupleParameter tp = isVariadic();
1289 if (tp && !tp.dependent && !td2.isVariadic())
1290 goto L1;
1292 static if (LOG_LEASTAS)
1294 printf(" matches %d, so is least as specialized\n", m);
1296 return m;
1299 static if (LOG_LEASTAS)
1301 printf(" doesn't match, so is not as specialized\n");
1303 return MATCH.nomatch;
1306 /*************************************************
1307 * Match function arguments against a specific template function.
1308 * Input:
1309 * ti
1310 * sc instantiation scope
1311 * fd
1312 * tthis 'this' argument if !NULL
1313 * argumentList arguments to function
1314 * Output:
1315 * fd Partially instantiated function declaration
1316 * ti.tdtypes Expression/Type deduced template arguments
1317 * Returns:
1318 * match pair of initial and inferred template arguments
1320 extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList)
1322 size_t nfparams;
1323 size_t nfargs;
1324 size_t ntargs; // array size of tiargs
1325 size_t fptupindex = IDX_NOTFOUND;
1326 MATCH match = MATCH.exact;
1327 MATCH matchTiargs = MATCH.exact;
1328 ParameterList fparameters; // function parameter list
1329 VarArg fvarargs; // function varargs
1330 uint wildmatch = 0;
1331 size_t inferStart = 0;
1333 Loc instLoc = ti.loc;
1334 Objects* tiargs = ti.tiargs;
1335 auto dedargs = new Objects(parameters.length);
1336 Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
1338 version (none)
1340 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
1341 for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
1343 Expression e = (*fargs)[i];
1344 printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars());
1346 printf("fd = %s\n", fd.toChars());
1347 printf("fd.type = %s\n", fd.type.toChars());
1348 if (tthis)
1349 printf("tthis = %s\n", tthis.toChars());
1352 assert(_scope);
1354 dedargs.zero();
1356 dedtypes.setDim(parameters.length);
1357 dedtypes.zero();
1359 if (errors || fd.errors)
1360 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1362 // Set up scope for parameters
1363 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1365 MATCHpair nomatch()
1367 paramscope.pop();
1368 //printf("\tnomatch\n");
1369 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1372 MATCHpair matcherror()
1374 // todo: for the future improvement
1375 paramscope.pop();
1376 //printf("\terror\n");
1377 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1379 // Mark the parameter scope as deprecated if the templated
1380 // function is deprecated (since paramscope.enclosing is the
1381 // calling scope already)
1382 paramscope.stc |= fd.storage_class & STC.deprecated_;
1384 TemplateTupleParameter tp = isVariadic();
1385 Tuple declaredTuple = null;
1387 version (none)
1389 for (size_t i = 0; i < dedargs.length; i++)
1391 printf("\tdedarg[%d] = ", i);
1392 RootObject oarg = (*dedargs)[i];
1393 if (oarg)
1394 printf("%s", oarg.toChars());
1395 printf("\n");
1399 ntargs = 0;
1400 if (tiargs)
1402 // Set initial template arguments
1403 ntargs = tiargs.length;
1404 size_t n = parameters.length;
1405 if (tp)
1406 n--;
1407 if (ntargs > n)
1409 if (!tp)
1410 return nomatch();
1412 /* The extra initial template arguments
1413 * now form the tuple argument.
1415 auto t = new Tuple(ntargs - n);
1416 assert(parameters.length);
1417 (*dedargs)[parameters.length - 1] = t;
1419 for (size_t i = 0; i < t.objects.length; i++)
1421 t.objects[i] = (*tiargs)[n + i];
1423 declareParameter(paramscope, tp, t);
1424 declaredTuple = t;
1426 else
1427 n = ntargs;
1429 memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
1431 for (size_t i = 0; i < n; i++)
1433 assert(i < parameters.length);
1434 Declaration sparam = null;
1435 MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
1436 //printf("\tdeduceType m = %d\n", m);
1437 if (m == MATCH.nomatch)
1438 return nomatch();
1439 if (m < matchTiargs)
1440 matchTiargs = m;
1442 sparam.dsymbolSemantic(paramscope);
1443 if (!paramscope.insert(sparam))
1444 return nomatch();
1446 if (n < parameters.length && !declaredTuple)
1448 inferStart = n;
1450 else
1451 inferStart = parameters.length;
1452 //printf("tiargs matchTiargs = %d\n", matchTiargs);
1454 version (none)
1456 for (size_t i = 0; i < dedargs.length; i++)
1458 printf("\tdedarg[%d] = ", i);
1459 RootObject oarg = (*dedargs)[i];
1460 if (oarg)
1461 printf("%s", oarg.toChars());
1462 printf("\n");
1466 fparameters = fd.getParameterList();
1467 nfparams = fparameters.length; // number of function parameters
1468 nfargs = argumentList.length; // number of function arguments
1469 if (argumentList.hasNames)
1470 return matcherror(); // TODO: resolve named args
1471 Expressions* fargs = argumentList.arguments; // TODO: resolve named args
1473 /* Check for match of function arguments with variadic template
1474 * parameter, such as:
1476 * void foo(T, A...)(T t, A a);
1477 * void main() { foo(1,2,3); }
1479 if (tp) // if variadic
1481 // TemplateTupleParameter always makes most lesser matching.
1482 matchTiargs = MATCH.convert;
1484 if (nfparams == 0 && nfargs != 0) // if no function parameters
1486 if (!declaredTuple)
1488 auto t = new Tuple();
1489 //printf("t = %p\n", t);
1490 (*dedargs)[parameters.length - 1] = t;
1491 declareParameter(paramscope, tp, t);
1492 declaredTuple = t;
1495 else
1497 /* Figure out which of the function parameters matches
1498 * the tuple template parameter. Do this by matching
1499 * type identifiers.
1500 * Set the index of this function parameter to fptupindex.
1502 for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
1504 auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
1505 if (fparam.type.ty != Tident)
1506 continue;
1507 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
1508 if (!tp.ident.equals(tid.ident) || tid.idents.length)
1509 continue;
1511 if (fparameters.varargs != VarArg.none) // variadic function doesn't
1512 return nomatch(); // go with variadic template
1514 goto L1;
1516 fptupindex = IDX_NOTFOUND;
1521 if (toParent().isModule())
1522 tthis = null;
1523 if (tthis)
1525 bool hasttp = false;
1527 // Match 'tthis' to any TemplateThisParameter's
1528 foreach (param; *parameters)
1530 if (auto ttp = param.isTemplateThisParameter())
1532 hasttp = true;
1534 Type t = new TypeIdentifier(Loc.initial, ttp.ident);
1535 MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
1536 if (m == MATCH.nomatch)
1537 return nomatch();
1538 if (m < match)
1539 match = m; // pick worst match
1543 // Match attributes of tthis against attributes of fd
1544 if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_))
1546 StorageClass stc = _scope.stc | fd.storage_class2;
1547 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
1548 Dsymbol p = parent;
1549 while (p.isTemplateDeclaration() || p.isTemplateInstance())
1550 p = p.parent;
1551 AggregateDeclaration ad = p.isAggregateDeclaration();
1552 if (ad)
1553 stc |= ad.storage_class;
1555 ubyte mod = fd.type.mod;
1556 if (stc & STC.immutable_)
1557 mod = MODFlags.immutable_;
1558 else
1560 if (stc & (STC.shared_ | STC.synchronized_))
1561 mod |= MODFlags.shared_;
1562 if (stc & STC.const_)
1563 mod |= MODFlags.const_;
1564 if (stc & STC.wild)
1565 mod |= MODFlags.wild;
1568 ubyte thismod = tthis.mod;
1569 if (hasttp)
1570 mod = MODmerge(thismod, mod);
1571 MATCH m = MODmethodConv(thismod, mod);
1572 if (m == MATCH.nomatch)
1573 return nomatch();
1574 if (m < match)
1575 match = m;
1579 // Loop through the function parameters
1581 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
1582 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
1583 size_t argi = 0;
1584 size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
1585 for (size_t parami = 0; parami < nfparams; parami++)
1587 Parameter fparam = fparameters[parami];
1589 // Apply function parameter storage classes to parameter types
1590 Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
1592 Expression farg;
1594 /* See function parameters which wound up
1595 * as part of a template tuple parameter.
1597 if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
1599 assert(prmtype.ty == Tident);
1600 TypeIdentifier tid = cast(TypeIdentifier)prmtype;
1601 if (!declaredTuple)
1603 /* The types of the function arguments
1604 * now form the tuple argument.
1606 declaredTuple = new Tuple();
1607 (*dedargs)[parameters.length - 1] = declaredTuple;
1609 /* Count function parameters with no defaults following a tuple parameter.
1610 * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
1612 size_t rem = 0;
1613 for (size_t j = parami + 1; j < nfparams; j++)
1615 Parameter p = fparameters[j];
1616 if (p.defaultArg)
1618 break;
1620 if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length]))
1622 Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
1623 rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1;
1625 else
1627 ++rem;
1631 if (nfargs2 - argi < rem)
1632 return nomatch();
1633 declaredTuple.objects.setDim(nfargs2 - argi - rem);
1634 for (size_t i = 0; i < declaredTuple.objects.length; i++)
1636 farg = (*fargs)[argi + i];
1638 // Check invalid arguments to detect errors early.
1639 if (farg.op == EXP.error || farg.type.ty == Terror)
1640 return nomatch();
1642 if (!fparam.isLazy() && farg.type.ty == Tvoid)
1643 return nomatch();
1645 Type tt;
1646 MATCH m;
1647 if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
1649 wildmatch |= wm;
1650 m = MATCH.constant;
1652 else
1654 m = deduceTypeHelper(farg.type, &tt, tid);
1656 if (m == MATCH.nomatch)
1657 return nomatch();
1658 if (m < match)
1659 match = m;
1661 /* Remove top const for dynamic array types and pointer types
1663 if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
1665 tt = tt.mutableOf();
1667 declaredTuple.objects[i] = tt;
1669 declareParameter(paramscope, tp, declaredTuple);
1671 else
1673 // https://issues.dlang.org/show_bug.cgi?id=6810
1674 // If declared tuple is not a type tuple,
1675 // it cannot be function parameter types.
1676 for (size_t i = 0; i < declaredTuple.objects.length; i++)
1678 if (!isType(declaredTuple.objects[i]))
1679 return nomatch();
1682 assert(declaredTuple);
1683 argi += declaredTuple.objects.length;
1684 continue;
1687 // If parameter type doesn't depend on inferred template parameters,
1688 // semantic it to get actual type.
1689 if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.length]))
1691 // should copy prmtype to avoid affecting semantic result
1692 prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
1694 if (prmtype.ty == Ttuple)
1696 TypeTuple tt = cast(TypeTuple)prmtype;
1697 size_t tt_dim = tt.arguments.length;
1698 for (size_t j = 0; j < tt_dim; j++, ++argi)
1700 Parameter p = (*tt.arguments)[j];
1701 if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
1702 parami + 1 == nfparams && argi < nfargs)
1704 prmtype = p.type;
1705 goto Lvarargs;
1707 if (argi >= nfargs)
1709 if (p.defaultArg)
1710 continue;
1712 // https://issues.dlang.org/show_bug.cgi?id=19888
1713 if (fparam.defaultArg)
1714 break;
1716 return nomatch();
1718 farg = (*fargs)[argi];
1719 if (!farg.implicitConvTo(p.type))
1720 return nomatch();
1722 continue;
1726 if (argi >= nfargs) // if not enough arguments
1728 if (!fparam.defaultArg)
1729 goto Lvarargs;
1731 /* https://issues.dlang.org/show_bug.cgi?id=2803
1732 * Before the starting of type deduction from the function
1733 * default arguments, set the already deduced parameters into paramscope.
1734 * It's necessary to avoid breaking existing acceptable code. Cases:
1736 * 1. Already deduced template parameters can appear in fparam.defaultArg:
1737 * auto foo(A, B)(A a, B b = A.stringof);
1738 * foo(1);
1739 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
1741 * 2. If prmtype depends on default-specified template parameter, the
1742 * default type should be preferred.
1743 * auto foo(N = size_t, R)(R r, N start = 0)
1744 * foo([1,2,3]);
1745 * // at fparam `N start = 0`, N should be 'size_t' before
1746 * // the deduction result from fparam.defaultArg.
1748 if (argi == nfargs)
1750 foreach (ref dedtype; *dedtypes)
1752 Type at = isType(dedtype);
1753 if (at && at.ty == Tnone)
1755 TypeDeduced xt = cast(TypeDeduced)at;
1756 dedtype = xt.tded; // 'unbox'
1759 for (size_t i = ntargs; i < dedargs.length; i++)
1761 TemplateParameter tparam = (*parameters)[i];
1763 RootObject oarg = (*dedargs)[i];
1764 RootObject oded = (*dedtypes)[i];
1765 if (oarg)
1766 continue;
1768 if (oded)
1770 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
1772 /* The specialization can work as long as afterwards
1773 * the oded == oarg
1775 (*dedargs)[i] = oded;
1776 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
1777 //printf("m2 = %d\n", m2);
1778 if (m2 == MATCH.nomatch)
1779 return nomatch();
1780 if (m2 < matchTiargs)
1781 matchTiargs = m2; // pick worst match
1782 if (!(*dedtypes)[i].equals(oded))
1783 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
1785 else
1787 if (MATCH.convert < matchTiargs)
1788 matchTiargs = MATCH.convert;
1790 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1792 else
1794 oded = tparam.defaultArg(instLoc, paramscope);
1795 if (oded)
1796 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1800 nfargs2 = argi + 1;
1802 /* If prmtype does not depend on any template parameters:
1804 * auto foo(T)(T v, double x = 0);
1805 * foo("str");
1806 * // at fparam == 'double x = 0'
1808 * or, if all template parameters in the prmtype are already deduced:
1810 * auto foo(R)(R range, ElementType!R sum = 0);
1811 * foo([1,2,3]);
1812 * // at fparam == 'ElementType!R sum = 0'
1814 * Deducing prmtype from fparam.defaultArg is not necessary.
1816 if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope))
1818 ++argi;
1819 continue;
1822 // Deduce prmtype from the defaultArg.
1823 farg = fparam.defaultArg.syntaxCopy();
1824 farg = farg.expressionSemantic(paramscope);
1825 farg = resolveProperties(paramscope, farg);
1827 else
1829 farg = (*fargs)[argi];
1832 // Check invalid arguments to detect errors early.
1833 if (farg.op == EXP.error || farg.type.ty == Terror)
1834 return nomatch();
1836 Type att = null;
1837 Lretry:
1838 version (none)
1840 printf("\tfarg.type = %s\n", farg.type.toChars());
1841 printf("\tfparam.type = %s\n", prmtype.toChars());
1843 Type argtype = farg.type;
1845 if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_)
1846 return nomatch();
1848 // https://issues.dlang.org/show_bug.cgi?id=12876
1849 // Optimize argument to allow CT-known length matching
1850 farg = farg.optimize(WANTvalue, fparam.isReference());
1851 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
1853 RootObject oarg = farg;
1854 if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
1856 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
1858 Type taai;
1859 if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
1861 if (farg.op == EXP.string_)
1863 StringExp se = cast(StringExp)farg;
1864 argtype = se.type.nextOf().sarrayOf(se.len);
1866 else if (farg.op == EXP.arrayLiteral)
1868 ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
1869 argtype = ae.type.nextOf().sarrayOf(ae.elements.length);
1871 else if (farg.op == EXP.slice)
1873 SliceExp se = cast(SliceExp)farg;
1874 if (Type tsa = toStaticArrayType(se))
1875 argtype = tsa;
1879 oarg = argtype;
1881 else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0)
1883 /* The farg passing to the prmtype always make a copy. Therefore,
1884 * we can shrink the set of the deduced type arguments for prmtype
1885 * by adjusting top-qualifier of the argtype.
1887 * prmtype argtype ta
1888 * T <- const(E)[] const(E)[]
1889 * T <- const(E[]) const(E)[]
1890 * qualifier(T) <- const(E)[] const(E[])
1891 * qualifier(T) <- const(E[]) const(E[])
1893 Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
1894 if (ta != argtype)
1896 Expression ea = farg.copy();
1897 ea.type = ta;
1898 oarg = ea;
1902 if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
1903 goto Lvarargs;
1905 uint wm = 0;
1906 MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart);
1907 //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
1908 wildmatch |= wm;
1910 /* If no match, see if the argument can be matched by using
1911 * implicit conversions.
1913 if (m == MATCH.nomatch && prmtype.deco)
1914 m = farg.implicitConvTo(prmtype);
1916 if (m == MATCH.nomatch)
1918 AggregateDeclaration ad = isAggregate(farg.type);
1919 if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
1921 // https://issues.dlang.org/show_bug.cgi?id=12537
1922 // The isRecursiveAliasThis() call above
1924 /* If a semantic error occurs while doing alias this,
1925 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
1926 * just regard it as not a match.
1928 * We also save/restore sc.func.flags to avoid messing up
1929 * attribute inference in the evaluation.
1931 const oldflags = sc.func ? sc.func.flags : 0;
1932 auto e = resolveAliasThis(sc, farg, true);
1933 if (sc.func)
1934 sc.func.flags = oldflags;
1935 if (e)
1937 farg = e;
1938 goto Lretry;
1943 if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
1945 if (!farg.isLvalue())
1947 if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
1949 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1951 else if (global.params.rvalueRefParam == FeatureState.enabled)
1953 // Allow implicit conversion to ref
1955 else
1956 return nomatch();
1959 if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
1961 if (!farg.isLvalue())
1962 return nomatch();
1963 if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1964 return nomatch();
1966 if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
1967 m = MATCH.convert;
1968 if (m != MATCH.nomatch)
1970 if (m < match)
1971 match = m; // pick worst match
1972 argi++;
1973 continue;
1977 Lvarargs:
1978 /* The following code for variadic arguments closely
1979 * matches TypeFunction.callMatch()
1981 if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
1982 return nomatch();
1984 /* Check for match with function parameter T...
1986 Type tb = prmtype.toBasetype();
1987 switch (tb.ty)
1989 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1990 case Tsarray:
1991 case Taarray:
1993 // Perhaps we can do better with this, see TypeFunction.callMatch()
1994 if (tb.ty == Tsarray)
1996 TypeSArray tsa = cast(TypeSArray)tb;
1997 dinteger_t sz = tsa.dim.toInteger();
1998 if (sz != nfargs - argi)
1999 return nomatch();
2001 else if (tb.ty == Taarray)
2003 TypeAArray taa = cast(TypeAArray)tb;
2004 Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
2006 size_t i = templateParameterLookup(taa.index, parameters);
2007 if (i == IDX_NOTFOUND)
2009 Expression e;
2010 Type t;
2011 Dsymbol s;
2012 Scope *sco;
2014 uint errors = global.startGagging();
2015 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
2016 * The parameter isn't part of the template
2017 * ones, let's try to find it in the
2018 * instantiation scope 'sc' and the one
2019 * belonging to the template itself. */
2020 sco = sc;
2021 taa.index.resolve(instLoc, sco, e, t, s);
2022 if (!e)
2024 sco = paramscope;
2025 taa.index.resolve(instLoc, sco, e, t, s);
2027 global.endGagging(errors);
2029 if (!e)
2030 return nomatch();
2032 e = e.ctfeInterpret();
2033 e = e.implicitCastTo(sco, Type.tsize_t);
2034 e = e.optimize(WANTvalue);
2035 if (!dim.equals(e))
2036 return nomatch();
2038 else
2040 // This code matches code in TypeInstance.deduceType()
2041 TemplateParameter tprm = (*parameters)[i];
2042 TemplateValueParameter tvp = tprm.isTemplateValueParameter();
2043 if (!tvp)
2044 return nomatch();
2045 Expression e = cast(Expression)(*dedtypes)[i];
2046 if (e)
2048 if (!dim.equals(e))
2049 return nomatch();
2051 else
2053 Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
2054 MATCH m = dim.implicitConvTo(vt);
2055 if (m == MATCH.nomatch)
2056 return nomatch();
2057 (*dedtypes)[i] = dim;
2061 goto case Tarray;
2063 case Tarray:
2065 TypeArray ta = cast(TypeArray)tb;
2066 Type tret = fparam.isLazyArray();
2067 for (; argi < nfargs; argi++)
2069 Expression arg = (*fargs)[argi];
2070 assert(arg);
2072 MATCH m;
2073 /* If lazy array of delegates,
2074 * convert arg(s) to delegate(s)
2076 if (tret)
2078 if (ta.next.equals(arg.type))
2080 m = MATCH.exact;
2082 else
2084 m = arg.implicitConvTo(tret);
2085 if (m == MATCH.nomatch)
2087 if (tret.toBasetype().ty == Tvoid)
2088 m = MATCH.convert;
2092 else
2094 uint wm = 0;
2095 m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
2096 wildmatch |= wm;
2098 if (m == MATCH.nomatch)
2099 return nomatch();
2100 if (m < match)
2101 match = m;
2103 goto Lmatch;
2105 case Tclass:
2106 case Tident:
2107 goto Lmatch;
2109 default:
2110 return nomatch();
2112 assert(0);
2114 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
2115 if (argi != nfargs2 && fparameters.varargs == VarArg.none)
2116 return nomatch();
2119 Lmatch:
2120 foreach (ref dedtype; *dedtypes)
2122 Type at = isType(dedtype);
2123 if (at)
2125 if (at.ty == Tnone)
2127 TypeDeduced xt = cast(TypeDeduced)at;
2128 at = xt.tded; // 'unbox'
2130 dedtype = at.merge2();
2133 for (size_t i = ntargs; i < dedargs.length; i++)
2135 TemplateParameter tparam = (*parameters)[i];
2136 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
2138 /* For T:T*, the dedargs is the T*, dedtypes is the T
2139 * But for function templates, we really need them to match
2141 RootObject oarg = (*dedargs)[i];
2142 RootObject oded = (*dedtypes)[i];
2143 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
2144 //if (oarg) printf("oarg: %s\n", oarg.toChars());
2145 //if (oded) printf("oded: %s\n", oded.toChars());
2146 if (oarg)
2147 continue;
2149 if (oded)
2151 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
2153 /* The specialization can work as long as afterwards
2154 * the oded == oarg
2156 (*dedargs)[i] = oded;
2157 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2158 //printf("m2 = %d\n", m2);
2159 if (m2 == MATCH.nomatch)
2160 return nomatch();
2161 if (m2 < matchTiargs)
2162 matchTiargs = m2; // pick worst match
2163 if (!(*dedtypes)[i].equals(oded))
2164 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
2166 else
2168 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
2169 if (MATCH.convert < matchTiargs)
2170 matchTiargs = MATCH.convert;
2173 else
2175 oded = tparam.defaultArg(instLoc, paramscope);
2176 if (!oded)
2178 // if tuple parameter and
2179 // tuple parameter was not in function parameter list and
2180 // we're one or more arguments short (i.e. no tuple argument)
2181 if (tparam == tp &&
2182 fptupindex == IDX_NOTFOUND &&
2183 ntargs <= dedargs.length - 1)
2185 // make tuple argument an empty tuple
2186 oded = new Tuple();
2188 else
2189 return nomatch();
2191 if (isError(oded))
2192 return matcherror();
2193 ntargs++;
2195 /* At the template parameter T, the picked default template argument
2196 * X!int should be matched to T in order to deduce dependent
2197 * template parameter A.
2198 * auto foo(T : X!A = X!int, A...)() { ... }
2199 * foo(); // T <-- X!int, A <-- (int)
2201 if (tparam.specialization())
2203 (*dedargs)[i] = oded;
2204 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2205 //printf("m2 = %d\n", m2);
2206 if (m2 == MATCH.nomatch)
2207 return nomatch();
2208 if (m2 < matchTiargs)
2209 matchTiargs = m2; // pick worst match
2210 if (!(*dedtypes)[i].equals(oded))
2211 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
2214 oded = declareParameter(paramscope, tparam, oded);
2215 (*dedargs)[i] = oded;
2218 /* https://issues.dlang.org/show_bug.cgi?id=7469
2219 * As same as the code for 7469 in findBestMatch,
2220 * expand a Tuple in dedargs to normalize template arguments.
2222 if (auto d = dedargs.length)
2224 if (auto va = isTuple((*dedargs)[d - 1]))
2226 dedargs.setDim(d - 1);
2227 dedargs.insert(d - 1, &va.objects);
2230 ti.tiargs = dedargs; // update to the normalized template arguments.
2232 // Partially instantiate function for constraint and fd.leastAsSpecialized()
2234 assert(paramscope.scopesym);
2235 Scope* sc2 = _scope;
2236 sc2 = sc2.push(paramscope.scopesym);
2237 sc2 = sc2.push(ti);
2238 sc2.parent = ti;
2239 sc2.tinst = ti;
2240 sc2.minst = sc.minst;
2241 sc2.stc |= fd.storage_class & STC.deprecated_;
2243 fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
2245 sc2 = sc2.pop();
2246 sc2 = sc2.pop();
2248 if (!fd)
2249 return nomatch();
2252 if (constraint)
2254 if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
2255 return nomatch();
2258 version (none)
2260 for (size_t i = 0; i < dedargs.length; i++)
2262 RootObject o = (*dedargs)[i];
2263 printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
2267 paramscope.pop();
2268 //printf("\tmatch %d\n", match);
2269 return MATCHpair(matchTiargs, match);
2272 /**************************************************
2273 * Declare template parameter tp with value o, and install it in the scope sc.
2275 RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o)
2277 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
2278 Type ta = isType(o);
2279 Expression ea = isExpression(o);
2280 Dsymbol sa = isDsymbol(o);
2281 Tuple va = isTuple(o);
2283 Declaration d;
2284 VarDeclaration v = null;
2286 if (ea && ea.op == EXP.type)
2287 ta = ea.type;
2288 else if (ea && ea.op == EXP.scope_)
2289 sa = (cast(ScopeExp)ea).sds;
2290 else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
2291 sa = (cast(ThisExp)ea).var;
2292 else if (ea && ea.op == EXP.function_)
2294 if ((cast(FuncExp)ea).td)
2295 sa = (cast(FuncExp)ea).td;
2296 else
2297 sa = (cast(FuncExp)ea).fd;
2300 if (ta)
2302 //printf("type %s\n", ta.toChars());
2303 auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta);
2304 ad.storage_class |= STC.templateparameter;
2305 d = ad;
2307 else if (sa)
2309 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
2310 auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa);
2311 ad.storage_class |= STC.templateparameter;
2312 d = ad;
2314 else if (ea)
2316 // tdtypes.data[i] always matches ea here
2317 Initializer _init = new ExpInitializer(loc, ea);
2318 TemplateValueParameter tvp = tp.isTemplateValueParameter();
2319 Type t = tvp ? tvp.valType : null;
2320 v = new VarDeclaration(loc, t, tp.ident, _init);
2321 v.storage_class = STC.manifest | STC.templateparameter;
2322 d = v;
2324 else if (va)
2326 //printf("\ttuple\n");
2327 d = new TupleDeclaration(loc, tp.ident, &va.objects);
2329 else
2331 assert(0);
2333 d.storage_class |= STC.templateparameter;
2335 if (ta)
2337 Type t = ta;
2338 // consistent with Type.checkDeprecated()
2339 while (t.ty != Tenum)
2341 if (!t.nextOf())
2342 break;
2343 t = (cast(TypeNext)t).next;
2345 if (Dsymbol s = t.toDsymbol(sc))
2347 if (s.isDeprecated())
2348 d.storage_class |= STC.deprecated_;
2351 else if (sa)
2353 if (sa.isDeprecated())
2354 d.storage_class |= STC.deprecated_;
2357 if (!sc.insert(d))
2358 error("declaration `%s` is already defined", tp.ident.toChars());
2359 d.dsymbolSemantic(sc);
2360 /* So the caller's o gets updated with the result of semantic() being run on o
2362 if (v)
2363 o = v._init.initializerToExpression();
2364 return o;
2367 /*************************************************
2368 * Limited function template instantiation for using fd.leastAsSpecialized()
2370 extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs)
2372 assert(fd);
2373 version (none)
2375 printf("doHeaderInstantiation this = %s\n", toChars());
2378 // function body and contracts are not need
2379 if (fd.isCtorDeclaration())
2380 fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy());
2381 else
2382 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy());
2383 fd.parent = ti;
2385 assert(fd.type.ty == Tfunction);
2386 auto tf = fd.type.isTypeFunction();
2387 tf.fargs = fargs;
2389 if (tthis)
2391 // Match 'tthis' to any TemplateThisParameter's
2392 bool hasttp = false;
2393 foreach (tp; *parameters)
2395 TemplateThisParameter ttp = tp.isTemplateThisParameter();
2396 if (ttp)
2397 hasttp = true;
2399 if (hasttp)
2401 tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
2402 assert(!tf.deco);
2406 Scope* scx = sc2.push();
2408 // Shouldn't run semantic on default arguments and return type.
2409 foreach (ref params; *tf.parameterList.parameters)
2410 params.defaultArg = null;
2411 tf.incomplete = true;
2413 if (fd.isCtorDeclaration())
2415 // For constructors, emitting return type is necessary for
2416 // isReturnIsolated() in functionResolve.
2417 tf.isctor = true;
2419 Dsymbol parent = toParentDecl();
2420 Type tret;
2421 AggregateDeclaration ad = parent.isAggregateDeclaration();
2422 if (!ad || parent.isUnionDeclaration())
2424 tret = Type.tvoid;
2426 else
2428 tret = ad.handleType();
2429 assert(tret);
2430 tret = tret.addStorageClass(fd.storage_class | scx.stc);
2431 tret = tret.addMod(tf.mod);
2433 tf.next = tret;
2434 if (ad && ad.isStructDeclaration())
2435 tf.isref = 1;
2436 //printf("tf = %s\n", tf.toChars());
2438 else
2439 tf.next = null;
2440 fd.type = tf;
2441 fd.type = fd.type.addSTC(scx.stc);
2442 fd.type = fd.type.typeSemantic(fd.loc, scx);
2443 scx = scx.pop();
2445 if (fd.type.ty != Tfunction)
2446 return null;
2448 fd.originalType = fd.type; // for mangling
2449 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
2450 //printf("fd.needThis() = %d\n", fd.needThis());
2452 return fd;
2455 debug (FindExistingInstance)
2457 __gshared uint nFound, nNotFound, nAdded, nRemoved;
2459 shared static ~this()
2461 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
2462 nFound, nNotFound, nAdded, nRemoved);
2466 /****************************************************
2467 * Given a new instance tithis of this TemplateDeclaration,
2468 * see if there already exists an instance.
2469 * If so, return that existing instance.
2471 extern (D) TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs)
2473 //printf("findExistingInstance() %s\n", tithis.toChars());
2474 tithis.fargs = fargs;
2475 auto tibox = TemplateInstanceBox(tithis);
2476 auto p = tibox in instances;
2477 debug (FindExistingInstance) ++(p ? nFound : nNotFound);
2478 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
2479 return p ? *p : null;
2482 /********************************************
2483 * Add instance ti to TemplateDeclaration's table of instances.
2484 * Return a handle we can use to later remove it if it fails instantiation.
2486 extern (D) TemplateInstance addInstance(TemplateInstance ti)
2488 //printf("addInstance() %p %s\n", instances, ti.toChars());
2489 auto tibox = TemplateInstanceBox(ti);
2490 instances[tibox] = ti;
2491 debug (FindExistingInstance) ++nAdded;
2492 return ti;
2495 /*******************************************
2496 * Remove TemplateInstance from table of instances.
2497 * Input:
2498 * handle returned by addInstance()
2500 extern (D) void removeInstance(TemplateInstance ti)
2502 //printf("removeInstance() %s\n", ti.toChars());
2503 auto tibox = TemplateInstanceBox(ti);
2504 debug (FindExistingInstance) ++nRemoved;
2505 instances.remove(tibox);
2508 override inout(TemplateDeclaration) isTemplateDeclaration() inout
2510 return this;
2514 * Check if the last template parameter is a tuple one,
2515 * and returns it if so, else returns `null`.
2517 * Returns:
2518 * The last template parameter if it's a `TemplateTupleParameter`
2520 TemplateTupleParameter isVariadic()
2522 size_t dim = parameters.length;
2523 if (dim == 0)
2524 return null;
2525 return (*parameters)[dim - 1].isTemplateTupleParameter();
2528 extern(C++) override bool isDeprecated() const
2530 return this.deprecated_;
2533 /***********************************
2534 * We can overload templates.
2536 override bool isOverloadable() const
2538 return true;
2541 override void accept(Visitor v)
2543 v.visit(this);
2547 extern (C++) final class TypeDeduced : Type
2549 Type tded;
2550 Expressions argexps; // corresponding expressions
2551 Types tparams; // tparams[i].mod
2553 extern (D) this(Type tt, Expression e, Type tparam)
2555 super(Tnone);
2556 tded = tt;
2557 argexps.push(e);
2558 tparams.push(tparam);
2561 void update(Expression e, Type tparam)
2563 argexps.push(e);
2564 tparams.push(tparam);
2567 void update(Type tt, Expression e, Type tparam)
2569 tded = tt;
2570 argexps.push(e);
2571 tparams.push(tparam);
2574 MATCH matchAll(Type tt)
2576 MATCH match = MATCH.exact;
2577 foreach (j, e; argexps)
2579 assert(e);
2580 if (e == emptyArrayElement)
2581 continue;
2583 Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_);
2585 MATCH m = e.implicitConvTo(t);
2586 if (match > m)
2587 match = m;
2588 if (match == MATCH.nomatch)
2589 break;
2591 return match;
2596 /*************************************************
2597 * Given function arguments, figure out which template function
2598 * to expand, and return matching result.
2599 * Params:
2600 * m = matching result
2601 * dstart = the root of overloaded function templates
2602 * loc = instantiation location
2603 * sc = instantiation scope
2604 * tiargs = initial list of template arguments
2605 * tthis = if !NULL, the 'this' pointer argument
2606 * argumentList= arguments to function
2607 * pMessage = address to store error message, or null
2609 void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
2610 Type tthis, ArgumentList argumentList, const(char)** pMessage = null)
2612 version (none)
2614 printf("functionResolve() dstart = %s\n", dstart.toChars());
2615 printf(" tiargs:\n");
2616 if (tiargs)
2618 for (size_t i = 0; i < tiargs.length; i++)
2620 RootObject arg = (*tiargs)[i];
2621 printf("\t%s\n", arg.toChars());
2624 printf(" fargs:\n");
2625 for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
2627 Expression arg = (*fargs)[i];
2628 printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
2629 //printf("\tty = %d\n", arg.type.ty);
2631 //printf("stc = %llx\n", dstart._scope.stc);
2632 //printf("match:t/f = %d/%d\n", ta_last, m.last);
2635 // results
2636 int property = 0; // 0: uninitialized
2637 // 1: seen @property
2638 // 2: not @property
2639 size_t ov_index = 0;
2640 TemplateDeclaration td_best;
2641 TemplateInstance ti_best;
2642 MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch;
2643 Type tthis_best;
2645 int applyFunction(FuncDeclaration fd)
2647 // skip duplicates
2648 if (fd == m.lastf)
2649 return 0;
2650 // explicitly specified tiargs never match to non template function
2651 if (tiargs && tiargs.length > 0)
2652 return 0;
2654 // constructors need a valid scope in order to detect semantic errors
2655 if (!fd.isCtorDeclaration &&
2656 fd.semanticRun < PASS.semanticdone)
2658 Ungag ungag = fd.ungagSpeculative();
2659 fd.dsymbolSemantic(null);
2661 if (fd.semanticRun < PASS.semanticdone)
2663 .error(loc, "forward reference to template `%s`", fd.toChars());
2664 return 1;
2666 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
2667 auto tf = cast(TypeFunction)fd.type;
2669 int prop = tf.isproperty ? 1 : 2;
2670 if (property == 0)
2671 property = prop;
2672 else if (property != prop)
2673 error(fd.loc, "cannot overload both property and non-property functions");
2675 /* For constructors, qualifier check will be opposite direction.
2676 * Qualified constructor always makes qualified object, then will be checked
2677 * that it is implicitly convertible to tthis.
2679 Type tthis_fd = fd.needThis() ? tthis : null;
2680 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2681 if (isCtorCall)
2683 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
2684 // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
2685 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2686 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2687 fd.isReturnIsolated())
2689 /* && tf.isShared() == tthis_fd.isShared()*/
2690 // Uniquely constructed object can ignore shared qualifier.
2691 // TODO: Is this appropriate?
2692 tthis_fd = null;
2694 else
2695 return 0; // MATCH.nomatch
2697 /* Fix Issue 17970:
2698 If a struct is declared as shared the dtor is automatically
2699 considered to be shared, but when the struct is instantiated
2700 the instance is no longer considered to be shared when the
2701 function call matching is done. The fix makes it so that if a
2702 struct declaration is shared, when the destructor is called,
2703 the instantiated struct is also considered shared.
2705 if (auto dt = fd.isDtorDeclaration())
2707 auto dtmod = dt.type.toTypeFunction();
2708 auto shared_dtor = dtmod.mod & MODFlags.shared_;
2709 auto shared_this = tthis_fd !is null ?
2710 tthis_fd.mod & MODFlags.shared_ : 0;
2711 if (shared_dtor && !shared_this)
2712 tthis_fd = dtmod;
2713 else if (shared_this && !shared_dtor && tthis_fd !is null)
2714 tf.mod = tthis_fd.mod;
2716 MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc);
2717 //printf("test1: mfa = %d\n", mfa);
2718 if (mfa == MATCH.nomatch)
2719 return 0;
2721 int firstIsBetter()
2723 td_best = null;
2724 ti_best = null;
2725 ta_last = MATCH.exact;
2726 m.last = mfa;
2727 m.lastf = fd;
2728 tthis_best = tthis_fd;
2729 ov_index = 0;
2730 m.count = 1;
2731 return 0;
2734 if (mfa > m.last) return firstIsBetter();
2735 if (mfa < m.last) return 0;
2737 /* See if one of the matches overrides the other.
2739 assert(m.lastf);
2740 if (m.lastf.overrides(fd)) return 0;
2741 if (fd.overrides(m.lastf)) return firstIsBetter();
2743 /* Try to disambiguate using template-style partial ordering rules.
2744 * In essence, if f() and g() are ambiguous, if f() can call g(),
2745 * but g() cannot call f(), then pick f().
2746 * This is because f() is "more specialized."
2749 MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
2750 MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
2751 //printf("c1 = %d, c2 = %d\n", c1, c2);
2752 if (c1 > c2) return firstIsBetter();
2753 if (c1 < c2) return 0;
2756 /* The 'overrides' check above does covariant checking only
2757 * for virtual member functions. It should do it for all functions,
2758 * but in order to not risk breaking code we put it after
2759 * the 'leastAsSpecialized' check.
2760 * In the future try moving it before.
2761 * I.e. a not-the-same-but-covariant match is preferred,
2762 * as it is more restrictive.
2764 if (!m.lastf.type.equals(fd.type))
2766 //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
2767 const lastCovariant = m.lastf.type.covariant(fd.type);
2768 const firstCovariant = fd.type.covariant(m.lastf.type);
2770 if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no)
2772 if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no)
2774 return 0;
2777 else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no)
2779 return firstIsBetter();
2783 /* If the two functions are the same function, like:
2784 * int foo(int);
2785 * int foo(int x) { ... }
2786 * then pick the one with the body.
2788 * If none has a body then don't care because the same
2789 * real function would be linked to the decl (e.g from object file)
2791 if (tf.equals(m.lastf.type) &&
2792 fd.storage_class == m.lastf.storage_class &&
2793 fd.parent == m.lastf.parent &&
2794 fd.visibility == m.lastf.visibility &&
2795 fd._linkage == m.lastf._linkage)
2797 if (fd.fbody && !m.lastf.fbody)
2798 return firstIsBetter();
2799 if (!fd.fbody)
2800 return 0;
2803 // https://issues.dlang.org/show_bug.cgi?id=14450
2804 // Prefer exact qualified constructor for the creating object type
2805 if (isCtorCall && tf.mod != m.lastf.type.mod)
2807 if (tthis.mod == tf.mod) return firstIsBetter();
2808 if (tthis.mod == m.lastf.type.mod) return 0;
2811 m.nextf = fd;
2812 m.count++;
2813 return 0;
2816 int applyTemplate(TemplateDeclaration td)
2818 //printf("applyTemplate(): td = %s\n", td.toChars());
2819 if (td == td_best) // skip duplicates
2820 return 0;
2822 if (!sc)
2823 sc = td._scope; // workaround for Type.aliasthisOf
2825 if (td.semanticRun == PASS.initial && td._scope)
2827 // Try to fix forward reference. Ungag errors while doing so.
2828 Ungag ungag = td.ungagSpeculative();
2829 td.dsymbolSemantic(td._scope);
2831 if (td.semanticRun == PASS.initial)
2833 .error(loc, "forward reference to template `%s`", td.toChars());
2834 Lerror:
2835 m.lastf = null;
2836 m.count = 0;
2837 m.last = MATCH.nomatch;
2838 return 1;
2840 //printf("td = %s\n", td.toChars());
2842 if (argumentList.hasNames)
2844 .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet");
2845 goto Lerror;
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.length);
2854 assert(td.semanticRun != PASS.initial);
2855 MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 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, argumentList);
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, argumentList, FuncResolveFlag.quiet);
2901 tdx.previous = pr.prev; // unlink from threaded list
2903 else if (s.isFuncDeclaration())
2905 fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, 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, argumentList, 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, argumentList);
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.
2984 auto tf = cast(TypeFunction)fd.type;
2985 assert(tf.next);
2986 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2987 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2988 fd.isReturnIsolated())
2990 tthis_fd = null;
2992 else
2993 continue; // MATCH.nomatch
2995 // need to check here whether the constructor is the member of a struct
2996 // declaration that defines a copy constructor. This is already checked
2997 // in the semantic of CtorDeclaration, however, when matching functions,
2998 // the template instance is not expanded.
2999 // https://issues.dlang.org/show_bug.cgi?id=21613
3000 auto ad = fd.isThis();
3001 auto sd = ad.isStructDeclaration();
3002 if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti))
3003 continue;
3006 if (mta < ta_last) goto Ltd_best;
3007 if (mta > ta_last) goto Ltd;
3009 if (mfa < m.last) goto Ltd_best;
3010 if (mfa > m.last) goto Ltd;
3012 if (td_best)
3014 // Disambiguate by picking the most specialized TemplateDeclaration
3015 MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
3016 MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
3017 //printf("1: c1 = %d, c2 = %d\n", c1, c2);
3018 if (c1 > c2) goto Ltd;
3019 if (c1 < c2) goto Ltd_best;
3021 assert(fd && m.lastf);
3023 // Disambiguate by tf.callMatch
3024 auto tf1 = fd.type.isTypeFunction();
3025 auto tf2 = m.lastf.type.isTypeFunction();
3026 MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc);
3027 MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc);
3028 //printf("2: c1 = %d, c2 = %d\n", c1, c2);
3029 if (c1 > c2) goto Ltd;
3030 if (c1 < c2) goto Ltd_best;
3033 // Disambiguate by picking the most specialized FunctionDeclaration
3034 MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
3035 MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
3036 //printf("3: c1 = %d, c2 = %d\n", c1, c2);
3037 if (c1 > c2) goto Ltd;
3038 if (c1 < c2) goto Ltd_best;
3041 // https://issues.dlang.org/show_bug.cgi?id=14450
3042 // Prefer exact qualified constructor for the creating object type
3043 if (isCtorCall && fd.type.mod != m.lastf.type.mod)
3045 if (tthis.mod == fd.type.mod) goto Ltd;
3046 if (tthis.mod == m.lastf.type.mod) goto Ltd_best;
3049 m.nextf = fd;
3050 m.count++;
3051 continue;
3053 Ltd_best: // td_best is the best match so far
3054 //printf("Ltd_best\n");
3055 continue;
3057 Ltd: // td is the new best match
3058 //printf("Ltd\n");
3059 assert(td._scope);
3060 td_best = td;
3061 ti_best = ti;
3062 property = 0; // (backward compatibility)
3063 ta_last = mta;
3064 m.last = mfa;
3065 m.lastf = fd;
3066 tthis_best = tthis_fd;
3067 ov_index = ovi;
3068 m.nextf = null;
3069 m.count = 1;
3070 continue;
3072 return 0;
3075 auto td = dstart.isTemplateDeclaration();
3076 if (td && td.funcroot)
3077 dstart = td.funcroot;
3078 overloadApply(dstart, (Dsymbol s)
3080 if (s.errors)
3081 return 0;
3082 if (auto fd = s.isFuncDeclaration())
3083 return applyFunction(fd);
3084 if (auto td = s.isTemplateDeclaration())
3085 return applyTemplate(td);
3086 return 0;
3087 }, sc);
3089 //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf);
3090 if (td_best && ti_best && m.count == 1)
3092 // Matches to template function
3093 assert(td_best.onemember && td_best.onemember.isFuncDeclaration());
3094 /* The best match is td_best with arguments tdargs.
3095 * Now instantiate the template.
3097 assert(td_best._scope);
3098 if (!sc)
3099 sc = td_best._scope; // workaround for Type.aliasthisOf
3101 auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs);
3102 ti.templateInstanceSemantic(sc, argumentList);
3104 m.lastf = ti.toAlias().isFuncDeclaration();
3105 if (!m.lastf)
3106 goto Lnomatch;
3107 if (ti.errors)
3109 Lerror:
3110 m.count = 1;
3111 assert(m.lastf);
3112 m.last = MATCH.nomatch;
3113 return;
3116 // look forward instantiated overload function
3117 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
3118 // it has filled overnext0d
3119 while (ov_index--)
3121 m.lastf = m.lastf.overnext0;
3122 assert(m.lastf);
3125 tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null;
3127 if (m.lastf.type.ty == Terror)
3128 goto Lerror;
3129 auto tf = m.lastf.type.isTypeFunction();
3130 if (!tf.callMatch(tthis_best, argumentList, 0, null, sc))
3131 goto Lnomatch;
3133 /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
3134 * a template instance can be matched while instantiating
3135 * that same template. Thus, the function type can be incomplete. Complete it.
3137 * https://issues.dlang.org/show_bug.cgi?id=9208
3138 * For auto function, completion should be deferred to the end of
3139 * its semantic3. Should not complete it in here.
3141 if (tf.next && !m.lastf.inferRetType)
3143 m.lastf.type = tf.typeSemantic(loc, sc);
3146 else if (m.lastf)
3148 // Matches to non template function,
3149 // or found matches were ambiguous.
3150 assert(m.count >= 1);
3152 else
3154 Lnomatch:
3155 m.count = 0;
3156 m.lastf = null;
3157 m.last = MATCH.nomatch;
3161 /* ======================== Type ============================================ */
3163 /****
3164 * Given an identifier, figure out which TemplateParameter it is.
3165 * Return IDX_NOTFOUND if not found.
3167 private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters)
3169 for (size_t i = 0; i < parameters.length; i++)
3171 TemplateParameter tp = (*parameters)[i];
3172 if (tp.ident.equals(id))
3173 return i;
3175 return IDX_NOTFOUND;
3178 private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
3180 if (tparam.ty == Tident)
3182 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3183 //printf("\ttident = '%s'\n", tident.toChars());
3184 return templateIdentifierLookup(tident.ident, parameters);
3186 return IDX_NOTFOUND;
3189 private ubyte deduceWildHelper(Type t, Type* at, Type tparam)
3191 if ((tparam.mod & MODFlags.wild) == 0)
3192 return 0;
3194 *at = null;
3196 auto X(T, U)(T U, U T)
3198 return (U << 4) | T;
3201 switch (X(tparam.mod, t.mod))
3203 case X(MODFlags.wild, 0):
3204 case X(MODFlags.wild, MODFlags.const_):
3205 case X(MODFlags.wild, MODFlags.shared_):
3206 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3207 case X(MODFlags.wild, MODFlags.immutable_):
3208 case X(MODFlags.wildconst, 0):
3209 case X(MODFlags.wildconst, MODFlags.const_):
3210 case X(MODFlags.wildconst, MODFlags.shared_):
3211 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3212 case X(MODFlags.wildconst, MODFlags.immutable_):
3213 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
3214 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3215 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
3216 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
3217 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3218 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
3220 ubyte wm = (t.mod & ~MODFlags.shared_);
3221 if (wm == 0)
3222 wm = MODFlags.mutable;
3223 ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_);
3224 *at = t.unqualify(m);
3225 return wm;
3227 case X(MODFlags.wild, MODFlags.wild):
3228 case X(MODFlags.wild, MODFlags.wildconst):
3229 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3230 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3231 case X(MODFlags.wildconst, MODFlags.wild):
3232 case X(MODFlags.wildconst, MODFlags.wildconst):
3233 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3234 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3235 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3236 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3237 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3238 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3240 *at = t.unqualify(tparam.mod & t.mod);
3241 return MODFlags.wild;
3243 default:
3244 return 0;
3249 * Returns the common type of the 2 types.
3251 private Type rawTypeMerge(Type t1, Type t2)
3253 if (t1.equals(t2))
3254 return t1;
3255 if (t1.equivalent(t2))
3256 return t1.castMod(MODmerge(t1.mod, t2.mod));
3258 auto t1b = t1.toBasetype();
3259 auto t2b = t2.toBasetype();
3260 if (t1b.equals(t2b))
3261 return t1b;
3262 if (t1b.equivalent(t2b))
3263 return t1b.castMod(MODmerge(t1b.mod, t2b.mod));
3265 auto ty = implicitConvCommonTy(t1b.ty, t2b.ty);
3266 if (ty != Terror)
3267 return Type.basic[ty];
3269 return null;
3272 private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
3274 // 9*9 == 81 cases
3276 auto X(T, U)(T U, U T)
3278 return (U << 4) | T;
3281 switch (X(tparam.mod, t.mod))
3283 case X(0, 0):
3284 case X(0, MODFlags.const_):
3285 case X(0, MODFlags.wild):
3286 case X(0, MODFlags.wildconst):
3287 case X(0, MODFlags.shared_):
3288 case X(0, MODFlags.shared_ | MODFlags.const_):
3289 case X(0, MODFlags.shared_ | MODFlags.wild):
3290 case X(0, MODFlags.shared_ | MODFlags.wildconst):
3291 case X(0, MODFlags.immutable_):
3292 // foo(U) T => T
3293 // foo(U) const(T) => const(T)
3294 // foo(U) inout(T) => inout(T)
3295 // foo(U) inout(const(T)) => inout(const(T))
3296 // foo(U) shared(T) => shared(T)
3297 // foo(U) shared(const(T)) => shared(const(T))
3298 // foo(U) shared(inout(T)) => shared(inout(T))
3299 // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
3300 // foo(U) immutable(T) => immutable(T)
3302 *at = t;
3303 return MATCH.exact;
3305 case X(MODFlags.const_, MODFlags.const_):
3306 case X(MODFlags.wild, MODFlags.wild):
3307 case X(MODFlags.wildconst, MODFlags.wildconst):
3308 case X(MODFlags.shared_, MODFlags.shared_):
3309 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
3310 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3311 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3312 case X(MODFlags.immutable_, MODFlags.immutable_):
3313 // foo(const(U)) const(T) => T
3314 // foo(inout(U)) inout(T) => T
3315 // foo(inout(const(U))) inout(const(T)) => T
3316 // foo(shared(U)) shared(T) => T
3317 // foo(shared(const(U))) shared(const(T)) => T
3318 // foo(shared(inout(U))) shared(inout(T)) => T
3319 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
3320 // foo(immutable(U)) immutable(T) => T
3322 *at = t.mutableOf().unSharedOf();
3323 return MATCH.exact;
3325 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
3326 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3327 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3328 // foo(const(U)) shared(const(T)) => shared(T)
3329 // foo(inout(U)) shared(inout(T)) => shared(T)
3330 // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
3332 *at = t.mutableOf();
3333 return MATCH.exact;
3335 case X(MODFlags.const_, 0):
3336 case X(MODFlags.const_, MODFlags.wild):
3337 case X(MODFlags.const_, MODFlags.wildconst):
3338 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
3339 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
3340 case X(MODFlags.const_, MODFlags.immutable_):
3341 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.immutable_):
3342 // foo(const(U)) T => T
3343 // foo(const(U)) inout(T) => T
3344 // foo(const(U)) inout(const(T)) => T
3345 // foo(const(U)) shared(inout(T)) => shared(T)
3346 // foo(const(U)) shared(inout(const(T))) => shared(T)
3347 // foo(const(U)) immutable(T) => T
3348 // foo(shared(const(U))) immutable(T) => T
3350 *at = t.mutableOf();
3351 return MATCH.constant;
3353 case X(MODFlags.const_, MODFlags.shared_):
3354 // foo(const(U)) shared(T) => shared(T)
3356 *at = t;
3357 return MATCH.constant;
3359 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
3360 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
3361 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wildconst):
3362 // foo(shared(U)) shared(const(T)) => const(T)
3363 // foo(shared(U)) shared(inout(T)) => inout(T)
3364 // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
3366 *at = t.unSharedOf();
3367 return MATCH.exact;
3369 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
3370 // foo(shared(const(U))) shared(T) => T
3372 *at = t.unSharedOf();
3373 return MATCH.constant;
3375 case X(MODFlags.wildconst, MODFlags.immutable_):
3376 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
3377 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
3378 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3379 // foo(inout(const(U))) immutable(T) => T
3380 // foo(shared(const(U))) shared(inout(const(T))) => T
3381 // foo(shared(inout(const(U)))) immutable(T) => T
3382 // foo(shared(inout(const(U)))) shared(inout(T)) => T
3384 *at = t.unSharedOf().mutableOf();
3385 return MATCH.constant;
3387 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
3388 // foo(shared(const(U))) shared(inout(T)) => T
3390 *at = t.unSharedOf().mutableOf();
3391 return MATCH.constant;
3393 case X(MODFlags.wild, 0):
3394 case X(MODFlags.wild, MODFlags.const_):
3395 case X(MODFlags.wild, MODFlags.wildconst):
3396 case X(MODFlags.wild, MODFlags.immutable_):
3397 case X(MODFlags.wild, MODFlags.shared_):
3398 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3399 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3400 case X(MODFlags.wildconst, 0):
3401 case X(MODFlags.wildconst, MODFlags.const_):
3402 case X(MODFlags.wildconst, MODFlags.wild):
3403 case X(MODFlags.wildconst, MODFlags.shared_):
3404 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3405 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3406 case X(MODFlags.shared_, 0):
3407 case X(MODFlags.shared_, MODFlags.const_):
3408 case X(MODFlags.shared_, MODFlags.wild):
3409 case X(MODFlags.shared_, MODFlags.wildconst):
3410 case X(MODFlags.shared_, MODFlags.immutable_):
3411 case X(MODFlags.shared_ | MODFlags.const_, 0):
3412 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.const_):
3413 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wild):
3414 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wildconst):
3415 case X(MODFlags.shared_ | MODFlags.wild, 0):
3416 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.const_):
3417 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wild):
3418 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wildconst):
3419 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
3420 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
3421 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3422 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3423 case X(MODFlags.shared_ | MODFlags.wildconst, 0):
3424 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.const_):
3425 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wild):
3426 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wildconst):
3427 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
3428 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3429 case X(MODFlags.immutable_, 0):
3430 case X(MODFlags.immutable_, MODFlags.const_):
3431 case X(MODFlags.immutable_, MODFlags.wild):
3432 case X(MODFlags.immutable_, MODFlags.wildconst):
3433 case X(MODFlags.immutable_, MODFlags.shared_):
3434 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.const_):
3435 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
3436 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wildconst):
3437 // foo(inout(U)) T => nomatch
3438 // foo(inout(U)) const(T) => nomatch
3439 // foo(inout(U)) inout(const(T)) => nomatch
3440 // foo(inout(U)) immutable(T) => nomatch
3441 // foo(inout(U)) shared(T) => nomatch
3442 // foo(inout(U)) shared(const(T)) => nomatch
3443 // foo(inout(U)) shared(inout(const(T))) => nomatch
3444 // foo(inout(const(U))) T => nomatch
3445 // foo(inout(const(U))) const(T) => nomatch
3446 // foo(inout(const(U))) inout(T) => nomatch
3447 // foo(inout(const(U))) shared(T) => nomatch
3448 // foo(inout(const(U))) shared(const(T)) => nomatch
3449 // foo(inout(const(U))) shared(inout(T)) => nomatch
3450 // foo(shared(U)) T => nomatch
3451 // foo(shared(U)) const(T) => nomatch
3452 // foo(shared(U)) inout(T) => nomatch
3453 // foo(shared(U)) inout(const(T)) => nomatch
3454 // foo(shared(U)) immutable(T) => nomatch
3455 // foo(shared(const(U))) T => nomatch
3456 // foo(shared(const(U))) const(T) => nomatch
3457 // foo(shared(const(U))) inout(T) => nomatch
3458 // foo(shared(const(U))) inout(const(T)) => nomatch
3459 // foo(shared(inout(U))) T => nomatch
3460 // foo(shared(inout(U))) const(T) => nomatch
3461 // foo(shared(inout(U))) inout(T) => nomatch
3462 // foo(shared(inout(U))) inout(const(T)) => nomatch
3463 // foo(shared(inout(U))) immutable(T) => nomatch
3464 // foo(shared(inout(U))) shared(T) => nomatch
3465 // foo(shared(inout(U))) shared(const(T)) => nomatch
3466 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
3467 // foo(shared(inout(const(U)))) T => nomatch
3468 // foo(shared(inout(const(U)))) const(T) => nomatch
3469 // foo(shared(inout(const(U)))) inout(T) => nomatch
3470 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
3471 // foo(shared(inout(const(U)))) shared(T) => nomatch
3472 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
3473 // foo(immutable(U)) T => nomatch
3474 // foo(immutable(U)) const(T) => nomatch
3475 // foo(immutable(U)) inout(T) => nomatch
3476 // foo(immutable(U)) inout(const(T)) => nomatch
3477 // foo(immutable(U)) shared(T) => nomatch
3478 // foo(immutable(U)) shared(const(T)) => nomatch
3479 // foo(immutable(U)) shared(inout(T)) => nomatch
3480 // foo(immutable(U)) shared(inout(const(T))) => nomatch
3481 return MATCH.nomatch;
3483 default:
3484 assert(0);
3488 __gshared Expression emptyArrayElement = null;
3490 /* These form the heart of template argument deduction.
3491 * Given 'this' being the type argument to the template instance,
3492 * it is matched against the template declaration parameter specialization
3493 * 'tparam' to determine the type to be used for the parameter.
3494 * Example:
3495 * template Foo(T:T*) // template declaration
3496 * Foo!(int*) // template instantiation
3497 * Input:
3498 * this = int*
3499 * tparam = T*
3500 * parameters = [ T:T* ] // Array of TemplateParameter's
3501 * Output:
3502 * dedtypes = [ int ] // Array of Expression/Type's
3504 MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
3506 extern (C++) final class DeduceType : Visitor
3508 alias visit = Visitor.visit;
3509 public:
3510 Scope* sc;
3511 Type tparam;
3512 TemplateParameters* parameters;
3513 Objects* dedtypes;
3514 uint* wm;
3515 size_t inferStart;
3516 bool ignoreAliasThis;
3517 MATCH result;
3519 extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis)
3521 this.sc = sc;
3522 this.tparam = tparam;
3523 this.parameters = parameters;
3524 this.dedtypes = dedtypes;
3525 this.wm = wm;
3526 this.inferStart = inferStart;
3527 this.ignoreAliasThis = ignoreAliasThis;
3528 result = MATCH.nomatch;
3531 override void visit(Type t)
3533 if (!tparam)
3534 goto Lnomatch;
3536 if (t == tparam)
3537 goto Lexact;
3539 if (tparam.ty == Tident)
3541 // Determine which parameter tparam is
3542 size_t i = templateParameterLookup(tparam, parameters);
3543 if (i == IDX_NOTFOUND)
3545 if (!sc)
3546 goto Lnomatch;
3548 /* Need a loc to go with the semantic routine.
3550 Loc loc;
3551 if (parameters.length)
3553 TemplateParameter tp = (*parameters)[0];
3554 loc = tp.loc;
3557 /* BUG: what if tparam is a template instance, that
3558 * has as an argument another Tident?
3560 tparam = tparam.typeSemantic(loc, sc);
3561 assert(tparam.ty != Tident);
3562 result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
3563 return;
3566 TemplateParameter tp = (*parameters)[i];
3568 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3569 if (tident.idents.length > 0)
3571 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
3572 Dsymbol s = t.toDsymbol(sc);
3573 for (size_t j = tident.idents.length; j-- > 0;)
3575 RootObject id = tident.idents[j];
3576 if (id.dyncast() == DYNCAST.identifier)
3578 if (!s || !s.parent)
3579 goto Lnomatch;
3580 Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id);
3581 if (!s2)
3582 goto Lnomatch;
3583 s2 = s2.toAlias();
3584 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
3585 if (s != s2)
3587 if (Type tx = s2.getType())
3589 if (s != tx.toDsymbol(sc))
3590 goto Lnomatch;
3592 else
3593 goto Lnomatch;
3595 s = s.parent;
3597 else
3598 goto Lnomatch;
3600 //printf("[e] s = %s\n", s?s.toChars():"(null)");
3601 if (tp.isTemplateTypeParameter())
3603 Type tt = s.getType();
3604 if (!tt)
3605 goto Lnomatch;
3606 Type at = cast(Type)(*dedtypes)[i];
3607 if (at && at.ty == Tnone)
3608 at = (cast(TypeDeduced)at).tded;
3609 if (!at || tt.equals(at))
3611 (*dedtypes)[i] = tt;
3612 goto Lexact;
3615 if (tp.isTemplateAliasParameter())
3617 Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
3618 if (!s2 || s == s2)
3620 (*dedtypes)[i] = s;
3621 goto Lexact;
3624 goto Lnomatch;
3627 // Found the corresponding parameter tp
3629 https://issues.dlang.org/show_bug.cgi?id=23578
3630 To pattern match:
3631 static if (is(S!int == S!av, alias av))
3633 We eventually need to deduce `int` (Tint32 [0]) and `av` (Tident).
3634 Previously this would not get pattern matched at all, but now we check if the
3635 template parameter `av` came from.
3637 This note has been left to serve as a hint for further explorers into
3638 how IsExp matching works.
3640 if (auto ta = tp.isTemplateAliasParameter())
3642 (*dedtypes)[i] = t;
3643 goto Lexact;
3645 // (23578) - ensure previous behaviour for non-alias template params
3646 if (!tp.isTemplateTypeParameter())
3648 goto Lnomatch;
3651 Type at = cast(Type)(*dedtypes)[i];
3652 Type tt;
3653 if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
3655 // type vs (none)
3656 if (!at)
3658 (*dedtypes)[i] = tt;
3659 *wm |= wx;
3660 result = MATCH.constant;
3661 return;
3664 // type vs expressions
3665 if (at.ty == Tnone)
3667 TypeDeduced xt = cast(TypeDeduced)at;
3668 result = xt.matchAll(tt);
3669 if (result > MATCH.nomatch)
3671 (*dedtypes)[i] = tt;
3672 if (result > MATCH.constant)
3673 result = MATCH.constant; // limit level for inout matches
3675 return;
3678 // type vs type
3679 if (tt.equals(at))
3681 (*dedtypes)[i] = tt; // Prefer current type match
3682 goto Lconst;
3684 if (tt.implicitConvTo(at.constOf()))
3686 (*dedtypes)[i] = at.constOf().mutableOf();
3687 *wm |= MODFlags.const_;
3688 goto Lconst;
3690 if (at.implicitConvTo(tt.constOf()))
3692 (*dedtypes)[i] = tt.constOf().mutableOf();
3693 *wm |= MODFlags.const_;
3694 goto Lconst;
3696 goto Lnomatch;
3698 else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
3700 // type vs (none)
3701 if (!at)
3703 (*dedtypes)[i] = tt;
3704 result = m;
3705 return;
3708 // type vs expressions
3709 if (at.ty == Tnone)
3711 TypeDeduced xt = cast(TypeDeduced)at;
3712 result = xt.matchAll(tt);
3713 if (result > MATCH.nomatch)
3715 (*dedtypes)[i] = tt;
3717 return;
3720 // type vs type
3721 if (tt.equals(at))
3723 goto Lexact;
3725 if (tt.ty == Tclass && at.ty == Tclass)
3727 result = tt.implicitConvTo(at);
3728 return;
3730 if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant)
3732 goto Lexact;
3735 goto Lnomatch;
3738 if (tparam.ty == Ttypeof)
3740 /* Need a loc to go with the semantic routine.
3742 Loc loc;
3743 if (parameters.length)
3745 TemplateParameter tp = (*parameters)[0];
3746 loc = tp.loc;
3749 tparam = tparam.typeSemantic(loc, sc);
3751 if (t.ty != tparam.ty)
3753 if (Dsymbol sym = t.toDsymbol(sc))
3755 if (sym.isforwardRef() && !tparam.deco)
3756 goto Lnomatch;
3759 MATCH m = t.implicitConvTo(tparam);
3760 if (m == MATCH.nomatch && !ignoreAliasThis)
3762 if (t.ty == Tclass)
3764 TypeClass tc = cast(TypeClass)t;
3765 if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
3767 if (auto ato = t.aliasthisOf())
3769 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT);
3770 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3771 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT);
3775 else if (t.ty == Tstruct)
3777 TypeStruct ts = cast(TypeStruct)t;
3778 if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
3780 if (auto ato = t.aliasthisOf())
3782 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT);
3783 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3784 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT);
3789 result = m;
3790 return;
3793 if (t.nextOf())
3795 if (tparam.deco && !tparam.hasWild())
3797 result = t.implicitConvTo(tparam);
3798 return;
3801 Type tpn = tparam.nextOf();
3802 if (wm && t.ty == Taarray && tparam.isWild())
3804 // https://issues.dlang.org/show_bug.cgi?id=12403
3805 // In IFTI, stop inout matching on transitive part of AA types.
3806 tpn = tpn.substWildTo(MODFlags.mutable);
3809 result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm);
3810 return;
3813 Lexact:
3814 result = MATCH.exact;
3815 return;
3817 Lnomatch:
3818 result = MATCH.nomatch;
3819 return;
3821 Lconst:
3822 result = MATCH.constant;
3825 override void visit(TypeVector t)
3827 if (tparam.ty == Tvector)
3829 TypeVector tp = cast(TypeVector)tparam;
3830 result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
3831 return;
3833 visit(cast(Type)t);
3836 override void visit(TypeDArray t)
3838 visit(cast(Type)t);
3841 override void visit(TypeSArray t)
3843 // Extra check that array dimensions must match
3844 if (tparam)
3846 if (tparam.ty == Tarray)
3848 MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3849 result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
3850 return;
3853 TemplateParameter tp = null;
3854 Expression edim = null;
3855 size_t i;
3856 if (tparam.ty == Tsarray)
3858 TypeSArray tsa = cast(TypeSArray)tparam;
3859 if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
3861 Identifier id = (cast(VarExp)tsa.dim).var.ident;
3862 i = templateIdentifierLookup(id, parameters);
3863 assert(i != IDX_NOTFOUND);
3864 tp = (*parameters)[i];
3866 else
3867 edim = tsa.dim;
3869 else if (tparam.ty == Taarray)
3871 TypeAArray taa = cast(TypeAArray)tparam;
3872 i = templateParameterLookup(taa.index, parameters);
3873 if (i != IDX_NOTFOUND)
3874 tp = (*parameters)[i];
3875 else
3877 Loc loc;
3878 // The "type" (it hasn't been resolved yet) of the function parameter
3879 // does not have a location but the parameter it is related to does,
3880 // so we use that for the resolution (better error message).
3881 if (inferStart < parameters.length)
3883 TemplateParameter loctp = (*parameters)[inferStart];
3884 loc = loctp.loc;
3887 Expression e;
3888 Type tx;
3889 Dsymbol s;
3890 taa.index.resolve(loc, sc, e, tx, s);
3891 edim = s ? getValue(s) : getValue(e);
3894 if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
3896 result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3897 return;
3900 visit(cast(Type)t);
3903 override void visit(TypeAArray t)
3905 // Extra check that index type must match
3906 if (tparam && tparam.ty == Taarray)
3908 TypeAArray tp = cast(TypeAArray)tparam;
3909 if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
3911 result = MATCH.nomatch;
3912 return;
3915 visit(cast(Type)t);
3918 override void visit(TypeFunction t)
3920 // Extra check that function characteristics must match
3921 if (!tparam)
3922 return visit(cast(Type)t);
3924 if (auto tp = tparam.isTypeFunction())
3926 if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
3928 result = MATCH.nomatch;
3929 return;
3932 foreach (fparam; *tp.parameterList.parameters)
3934 // https://issues.dlang.org/show_bug.cgi?id=2579
3935 // Apply function parameter storage classes to parameter types
3936 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
3937 fparam.storageClass &= ~STC.TYPECTOR;
3939 // https://issues.dlang.org/show_bug.cgi?id=15243
3940 // Resolve parameter type if it's not related with template parameters
3941 if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length]))
3943 auto tx = fparam.type.typeSemantic(Loc.initial, sc);
3944 if (tx.ty == Terror)
3946 result = MATCH.nomatch;
3947 return;
3949 fparam.type = tx;
3953 size_t nfargs = t.parameterList.length;
3954 size_t nfparams = tp.parameterList.length;
3956 /* See if tuple match
3958 if (nfparams > 0 && nfargs >= nfparams - 1)
3960 /* See if 'A' of the template parameter matches 'A'
3961 * of the type of the last function parameter.
3963 Parameter fparam = tp.parameterList[nfparams - 1];
3964 assert(fparam);
3965 assert(fparam.type);
3966 if (fparam.type.ty != Tident)
3967 goto L1;
3968 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
3969 if (tid.idents.length)
3970 goto L1;
3972 /* Look through parameters to find tuple matching tid.ident
3974 size_t tupi = 0;
3975 for (; 1; tupi++)
3977 if (tupi == parameters.length)
3978 goto L1;
3979 TemplateParameter tx = (*parameters)[tupi];
3980 TemplateTupleParameter tup = tx.isTemplateTupleParameter();
3981 if (tup && tup.ident.equals(tid.ident))
3982 break;
3985 /* The types of the function arguments [nfparams - 1 .. nfargs]
3986 * now form the tuple argument.
3988 size_t tuple_dim = nfargs - (nfparams - 1);
3990 /* See if existing tuple, and whether it matches or not
3992 RootObject o = (*dedtypes)[tupi];
3993 if (o)
3995 // Existing deduced argument must be a tuple, and must match
3996 Tuple tup = isTuple(o);
3997 if (!tup || tup.objects.length != tuple_dim)
3999 result = MATCH.nomatch;
4000 return;
4002 for (size_t i = 0; i < tuple_dim; i++)
4004 Parameter arg = t.parameterList[nfparams - 1 + i];
4005 if (!arg.type.equals(tup.objects[i]))
4007 result = MATCH.nomatch;
4008 return;
4012 else
4014 // Create new tuple
4015 auto tup = new Tuple(tuple_dim);
4016 for (size_t i = 0; i < tuple_dim; i++)
4018 Parameter arg = t.parameterList[nfparams - 1 + i];
4019 tup.objects[i] = arg.type;
4021 (*dedtypes)[tupi] = tup;
4023 nfparams--; // don't consider the last parameter for type deduction
4024 goto L2;
4028 if (nfargs != nfparams)
4030 result = MATCH.nomatch;
4031 return;
4034 assert(nfparams <= tp.parameterList.length);
4035 foreach (i, ap; tp.parameterList)
4037 if (i == nfparams)
4038 break;
4040 Parameter a = t.parameterList[i];
4042 if (!a.isCovariant(t.isref, ap) ||
4043 !deduceType(a.type, sc, ap.type, parameters, dedtypes))
4045 result = MATCH.nomatch;
4046 return;
4050 visit(cast(Type)t);
4053 override void visit(TypeIdentifier t)
4055 // Extra check
4056 if (tparam && tparam.ty == Tident)
4058 TypeIdentifier tp = cast(TypeIdentifier)tparam;
4059 for (size_t i = 0; i < t.idents.length; i++)
4061 RootObject id1 = t.idents[i];
4062 RootObject id2 = tp.idents[i];
4063 if (!id1.equals(id2))
4065 result = MATCH.nomatch;
4066 return;
4070 visit(cast(Type)t);
4073 override void visit(TypeInstance t)
4075 // Extra check
4076 if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl)
4078 TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
4079 assert(tempdecl);
4081 TypeInstance tp = cast(TypeInstance)tparam;
4083 //printf("tempinst.tempdecl = %p\n", tempdecl);
4084 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
4085 if (!tp.tempinst.tempdecl)
4087 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
4089 /* Handle case of:
4090 * template Foo(T : sa!(T), alias sa)
4092 size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
4093 if (i == IDX_NOTFOUND)
4095 /* Didn't find it as a parameter identifier. Try looking
4096 * it up and seeing if is an alias.
4097 * https://issues.dlang.org/show_bug.cgi?id=1454
4099 auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name);
4100 Type tx;
4101 Expression e;
4102 Dsymbol s;
4103 tid.resolve(tp.loc, sc, e, tx, s);
4104 if (tx)
4106 s = tx.toDsymbol(sc);
4107 if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null)
4109 // https://issues.dlang.org/show_bug.cgi?id=14290
4110 // Try to match with ti.tempecl,
4111 // only when ti is an enclosing instance.
4112 Dsymbol p = sc.parent;
4113 while (p && p != ti)
4114 p = p.parent;
4115 if (p)
4116 s = ti.tempdecl;
4119 if (s)
4121 s = s.toAlias();
4122 TemplateDeclaration td = s.isTemplateDeclaration();
4123 if (td)
4125 if (td.overroot)
4126 td = td.overroot;
4127 for (; td; td = td.overnext)
4129 if (td == tempdecl)
4130 goto L2;
4134 goto Lnomatch;
4137 TemplateParameter tpx = (*parameters)[i];
4138 if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
4139 goto Lnomatch;
4141 else if (tempdecl != tp.tempinst.tempdecl)
4142 goto Lnomatch;
4145 for (size_t i = 0; 1; i++)
4147 //printf("\ttest: tempinst.tiargs[%zu]\n", i);
4148 RootObject o1 = null;
4149 if (i < t.tempinst.tiargs.length)
4150 o1 = (*t.tempinst.tiargs)[i];
4151 else if (i < t.tempinst.tdtypes.length && i < tp.tempinst.tiargs.length)
4153 // Pick up default arg
4154 o1 = t.tempinst.tdtypes[i];
4156 else if (i >= tp.tempinst.tiargs.length)
4157 break;
4158 //printf("\ttest: o1 = %s\n", o1.toChars());
4159 if (i >= tp.tempinst.tiargs.length)
4161 size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
4162 while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
4164 i++;
4166 if (i >= dim)
4167 break; // match if all remained parameters are dependent
4168 goto Lnomatch;
4171 RootObject o2 = (*tp.tempinst.tiargs)[i];
4172 Type t2 = isType(o2);
4173 //printf("\ttest: o2 = %s\n", o2.toChars());
4174 size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
4175 ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
4176 if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
4177 (*parameters)[j].isTemplateTupleParameter())
4179 /* Given:
4180 * struct A(B...) {}
4181 * alias A!(int, float) X;
4182 * static if (is(X Y == A!(Z), Z...)) {}
4183 * deduce that Z is a tuple(int, float)
4186 /* Create tuple from remaining args
4188 size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.length : t.tempinst.tdtypes.length) - i;
4189 auto vt = new Tuple(vtdim);
4190 for (size_t k = 0; k < vtdim; k++)
4192 RootObject o;
4193 if (k < t.tempinst.tiargs.length)
4194 o = (*t.tempinst.tiargs)[i + k];
4195 else // Pick up default arg
4196 o = t.tempinst.tdtypes[i + k];
4197 vt.objects[k] = o;
4200 Tuple v = cast(Tuple)(*dedtypes)[j];
4201 if (v)
4203 if (!match(v, vt))
4204 goto Lnomatch;
4206 else
4207 (*dedtypes)[j] = vt;
4208 break;
4210 else if (!o1)
4211 break;
4213 Type t1 = isType(o1);
4214 Dsymbol s1 = isDsymbol(o1);
4215 Dsymbol s2 = isDsymbol(o2);
4216 Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
4217 Expression e2 = isExpression(o2);
4218 version (none)
4220 Tuple v1 = isTuple(o1);
4221 Tuple v2 = isTuple(o2);
4222 if (t1)
4223 printf("t1 = %s\n", t1.toChars());
4224 if (t2)
4225 printf("t2 = %s\n", t2.toChars());
4226 if (e1)
4227 printf("e1 = %s\n", e1.toChars());
4228 if (e2)
4229 printf("e2 = %s\n", e2.toChars());
4230 if (s1)
4231 printf("s1 = %s\n", s1.toChars());
4232 if (s2)
4233 printf("s2 = %s\n", s2.toChars());
4234 if (v1)
4235 printf("v1 = %s\n", v1.toChars());
4236 if (v2)
4237 printf("v2 = %s\n", v2.toChars());
4240 if (t1 && t2)
4242 if (!deduceType(t1, sc, t2, parameters, dedtypes))
4243 goto Lnomatch;
4245 else if (e1 && e2)
4248 e1 = e1.ctfeInterpret();
4250 /* If it is one of the template parameters for this template,
4251 * we should not attempt to interpret it. It already has a value.
4253 if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
4256 * (T:Number!(e2), int e2)
4258 j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters);
4259 if (j != IDX_NOTFOUND)
4260 goto L1;
4261 // The template parameter was not from this template
4262 // (it may be from a parent template, for example)
4265 e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
4266 e2 = e2.ctfeInterpret();
4268 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
4269 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
4270 if (!e1.equals(e2))
4272 if (!e2.implicitConvTo(e1.type))
4273 goto Lnomatch;
4275 e2 = e2.implicitCastTo(sc, e1.type);
4276 e2 = e2.ctfeInterpret();
4277 if (!e1.equals(e2))
4278 goto Lnomatch;
4281 else if (e1 && t2 && t2.ty == Tident)
4283 j = templateParameterLookup(t2, parameters);
4285 if (j == IDX_NOTFOUND)
4287 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4288 if (e2)
4289 goto Le;
4290 goto Lnomatch;
4292 if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
4293 goto Lnomatch;
4295 else if (s1 && s2)
4298 if (!s1.equals(s2))
4299 goto Lnomatch;
4301 else if (s1 && t2 && t2.ty == Tident)
4303 j = templateParameterLookup(t2, parameters);
4304 if (j == IDX_NOTFOUND)
4306 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4307 if (s2)
4308 goto Ls;
4309 goto Lnomatch;
4311 if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
4312 goto Lnomatch;
4314 else
4315 goto Lnomatch;
4318 visit(cast(Type)t);
4319 return;
4321 Lnomatch:
4322 //printf("no match\n");
4323 result = MATCH.nomatch;
4326 override void visit(TypeStruct t)
4328 /* If this struct is a template struct, and we're matching
4329 * it against a template instance, convert the struct type
4330 * to a template instance, too, and try again.
4332 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4334 if (tparam && tparam.ty == Tinstance)
4336 if (ti && ti.toAlias() == t.sym)
4338 auto tx = new TypeInstance(Loc.initial, ti);
4339 auto m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4340 // if we have a no match we still need to check alias this
4341 if (m != MATCH.nomatch)
4343 result = m;
4344 return;
4348 /* Match things like:
4349 * S!(T).foo
4351 TypeInstance tpi = cast(TypeInstance)tparam;
4352 if (tpi.idents.length)
4354 RootObject id = tpi.idents[tpi.idents.length - 1];
4355 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4357 Type tparent = t.sym.parent.getType();
4358 if (tparent)
4360 /* Slice off the .foo in S!(T).foo
4362 tpi.idents.length--;
4363 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4364 tpi.idents.length++;
4365 return;
4371 // Extra check
4372 if (tparam && tparam.ty == Tstruct)
4374 TypeStruct tp = cast(TypeStruct)tparam;
4376 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4377 if (wm && t.deduceWild(tparam, false))
4379 result = MATCH.constant;
4380 return;
4382 result = t.implicitConvTo(tp);
4383 return;
4385 visit(cast(Type)t);
4388 override void visit(TypeEnum t)
4390 // Extra check
4391 if (tparam && tparam.ty == Tenum)
4393 TypeEnum tp = cast(TypeEnum)tparam;
4394 if (t.sym == tp.sym)
4395 visit(cast(Type)t);
4396 else
4397 result = MATCH.nomatch;
4398 return;
4400 Type tb = t.toBasetype();
4401 if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray)
4403 result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
4404 if (result == MATCH.exact)
4405 result = MATCH.convert;
4406 return;
4408 visit(cast(Type)t);
4411 /* Helper for TypeClass.deduceType().
4412 * Classes can match with implicit conversion to a base class or interface.
4413 * This is complicated, because there may be more than one base class which
4414 * matches. In such cases, one or more parameters remain ambiguous.
4415 * For example,
4417 * interface I(X, Y) {}
4418 * class C : I(uint, double), I(char, double) {}
4419 * C x;
4420 * foo(T, U)( I!(T, U) x)
4422 * deduces that U is double, but T remains ambiguous (could be char or uint).
4424 * Given a baseclass b, and initial deduced types 'dedtypes', this function
4425 * tries to match tparam with b, and also tries all base interfaces of b.
4426 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
4427 * types are ANDed with the current 'best' estimate for dedtypes.
4429 static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
4431 TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
4432 if (parti)
4434 // Make a temporary copy of dedtypes so we don't destroy it
4435 auto tmpdedtypes = new Objects(dedtypes.length);
4436 memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
4438 auto t = new TypeInstance(Loc.initial, parti);
4439 MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
4440 if (m > MATCH.nomatch)
4442 // If this is the first ever match, it becomes our best estimate
4443 if (numBaseClassMatches == 0)
4444 memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
4445 else
4446 for (size_t k = 0; k < tmpdedtypes.length; ++k)
4448 // If we've found more than one possible type for a parameter,
4449 // mark it as unknown.
4450 if ((*tmpdedtypes)[k] != (*best)[k])
4451 (*best)[k] = (*dedtypes)[k];
4453 ++numBaseClassMatches;
4457 // Now recursively test the inherited interfaces
4458 foreach (ref bi; b.baseInterfaces)
4460 deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4464 override void visit(TypeClass t)
4466 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
4468 /* If this class is a template class, and we're matching
4469 * it against a template instance, convert the class type
4470 * to a template instance, too, and try again.
4472 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4474 if (tparam && tparam.ty == Tinstance)
4476 if (ti && ti.toAlias() == t.sym)
4478 auto tx = new TypeInstance(Loc.initial, ti);
4479 MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4480 // Even if the match fails, there is still a chance it could match
4481 // a base class.
4482 if (m != MATCH.nomatch)
4484 result = m;
4485 return;
4489 /* Match things like:
4490 * S!(T).foo
4492 TypeInstance tpi = cast(TypeInstance)tparam;
4493 if (tpi.idents.length)
4495 RootObject id = tpi.idents[tpi.idents.length - 1];
4496 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4498 Type tparent = t.sym.parent.getType();
4499 if (tparent)
4501 /* Slice off the .foo in S!(T).foo
4503 tpi.idents.length--;
4504 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4505 tpi.idents.length++;
4506 return;
4511 // If it matches exactly or via implicit conversion, we're done
4512 visit(cast(Type)t);
4513 if (result != MATCH.nomatch)
4514 return;
4516 /* There is still a chance to match via implicit conversion to
4517 * a base class or interface. Because there could be more than one such
4518 * match, we need to check them all.
4521 int numBaseClassMatches = 0; // Have we found an interface match?
4523 // Our best guess at dedtypes
4524 auto best = new Objects(dedtypes.length);
4526 ClassDeclaration s = t.sym;
4527 while (s && s.baseclasses.length > 0)
4529 // Test the base class
4530 deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4532 // Test the interfaces inherited by the base class
4533 foreach (b; s.interfaces)
4535 deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4537 s = (*s.baseclasses)[0].sym;
4540 if (numBaseClassMatches == 0)
4542 result = MATCH.nomatch;
4543 return;
4546 // If we got at least one match, copy the known types into dedtypes
4547 memcpy(dedtypes.tdata(), best.tdata(), best.length * (void*).sizeof);
4548 result = MATCH.convert;
4549 return;
4552 // Extra check
4553 if (tparam && tparam.ty == Tclass)
4555 TypeClass tp = cast(TypeClass)tparam;
4557 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4558 if (wm && t.deduceWild(tparam, false))
4560 result = MATCH.constant;
4561 return;
4563 result = t.implicitConvTo(tp);
4564 return;
4566 visit(cast(Type)t);
4569 override void visit(Expression e)
4571 //printf("Expression.deduceType(e = %s)\n", e.toChars());
4572 size_t i = templateParameterLookup(tparam, parameters);
4573 if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0)
4575 if (e == emptyArrayElement && tparam.ty == Tarray)
4577 Type tn = (cast(TypeNext)tparam).next;
4578 result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4579 return;
4581 e.type.accept(this);
4582 return;
4585 TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
4586 if (!tp)
4587 return; // nomatch
4589 if (e == emptyArrayElement)
4591 if ((*dedtypes)[i])
4593 result = MATCH.exact;
4594 return;
4596 if (tp.defaultType)
4598 tp.defaultType.accept(this);
4599 return;
4603 /* Returns `true` if `t` is a reference type, or an array of reference types
4605 bool isTopRef(Type t)
4607 auto tb = t.baseElemOf();
4608 return tb.ty == Tclass ||
4609 tb.ty == Taarray ||
4610 tb.ty == Tstruct && tb.hasPointers();
4613 Type at = cast(Type)(*dedtypes)[i];
4614 Type tt;
4615 if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
4617 *wm |= wx;
4618 result = MATCH.constant;
4620 else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
4622 result = m;
4624 else if (!isTopRef(e.type))
4626 /* https://issues.dlang.org/show_bug.cgi?id=15653
4627 * In IFTI, recognize top-qualifier conversions
4628 * through the value copy, e.g.
4629 * int --> immutable(int)
4630 * immutable(string[]) --> immutable(string)[]
4632 tt = e.type.mutableOf();
4633 result = MATCH.convert;
4635 else
4636 return; // nomatch
4638 // expression vs (none)
4639 if (!at)
4641 (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
4642 return;
4645 TypeDeduced xt = null;
4646 if (at.ty == Tnone)
4648 xt = cast(TypeDeduced)at;
4649 at = xt.tded;
4652 // From previous matched expressions to current deduced type
4653 MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch;
4655 // From current expressions to previous deduced type
4656 Type pt = at.addMod(tparam.mod);
4657 if (*wm)
4658 pt = pt.substWildTo(*wm);
4659 MATCH match2 = e.implicitConvTo(pt);
4661 if (match1 > MATCH.nomatch && match2 > MATCH.nomatch)
4663 if (at.implicitConvTo(tt) == MATCH.nomatch)
4664 match1 = MATCH.nomatch; // Prefer at
4665 else if (tt.implicitConvTo(at) == MATCH.nomatch)
4666 match2 = MATCH.nomatch; // Prefer tt
4667 else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod)
4669 if (!tt.isMutable() && !at.isMutable())
4670 tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod));
4671 else if (tt.isMutable())
4673 if (at.mod == 0) // Prefer unshared
4674 match1 = MATCH.nomatch;
4675 else
4676 match2 = MATCH.nomatch;
4678 else if (at.isMutable())
4680 if (tt.mod == 0) // Prefer unshared
4681 match2 = MATCH.nomatch;
4682 else
4683 match1 = MATCH.nomatch;
4685 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
4687 else
4689 match1 = MATCH.nomatch;
4690 match2 = MATCH.nomatch;
4693 if (match1 > MATCH.nomatch)
4695 // Prefer current match: tt
4696 if (xt)
4697 xt.update(tt, e, tparam);
4698 else
4699 (*dedtypes)[i] = tt;
4700 result = match1;
4701 return;
4703 if (match2 > MATCH.nomatch)
4705 // Prefer previous match: (*dedtypes)[i]
4706 if (xt)
4707 xt.update(e, tparam);
4708 result = match2;
4709 return;
4712 /* Deduce common type
4714 if (Type t = rawTypeMerge(at, tt))
4716 if (xt)
4717 xt.update(t, e, tparam);
4718 else
4719 (*dedtypes)[i] = t;
4721 pt = tt.addMod(tparam.mod);
4722 if (*wm)
4723 pt = pt.substWildTo(*wm);
4724 result = e.implicitConvTo(pt);
4725 return;
4728 result = MATCH.nomatch;
4731 MATCH deduceEmptyArrayElement()
4733 if (!emptyArrayElement)
4735 emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy
4736 emptyArrayElement.type = Type.tvoid;
4738 assert(tparam.ty == Tarray);
4740 Type tn = (cast(TypeNext)tparam).next;
4741 return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4744 override void visit(NullExp e)
4746 if (tparam.ty == Tarray && e.type.ty == Tnull)
4748 // tparam:T[] <- e:null (void[])
4749 result = deduceEmptyArrayElement();
4750 return;
4752 visit(cast(Expression)e);
4755 override void visit(StringExp e)
4757 Type taai;
4758 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
4760 // Consider compile-time known boundaries
4761 e.type.nextOf().sarrayOf(e.len).accept(this);
4762 return;
4764 visit(cast(Expression)e);
4767 override void visit(ArrayLiteralExp e)
4769 // https://issues.dlang.org/show_bug.cgi?id=20092
4770 if (e.elements && e.elements.length && e.type.toBasetype().nextOf().ty == Tvoid)
4772 result = deduceEmptyArrayElement();
4773 return;
4775 if ((!e.elements || !e.elements.length) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray)
4777 // tparam:T[] <- e:[] (void[])
4778 result = deduceEmptyArrayElement();
4779 return;
4782 if (tparam.ty == Tarray && e.elements && e.elements.length)
4784 Type tn = (cast(TypeDArray)tparam).next;
4785 result = MATCH.exact;
4786 if (e.basis)
4788 MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm);
4789 if (m < result)
4790 result = m;
4792 foreach (el; *e.elements)
4794 if (result == MATCH.nomatch)
4795 break;
4796 if (!el)
4797 continue;
4798 MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
4799 if (m < result)
4800 result = m;
4802 return;
4805 Type taai;
4806 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
4808 // Consider compile-time known boundaries
4809 e.type.nextOf().sarrayOf(e.elements.length).accept(this);
4810 return;
4812 visit(cast(Expression)e);
4815 override void visit(AssocArrayLiteralExp e)
4817 if (tparam.ty == Taarray && e.keys && e.keys.length)
4819 TypeAArray taa = cast(TypeAArray)tparam;
4820 result = MATCH.exact;
4821 foreach (i, key; *e.keys)
4823 MATCH m1 = deduceType(key, sc, taa.index, parameters, dedtypes, wm);
4824 if (m1 < result)
4825 result = m1;
4826 if (result == MATCH.nomatch)
4827 break;
4828 MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm);
4829 if (m2 < result)
4830 result = m2;
4831 if (result == MATCH.nomatch)
4832 break;
4834 return;
4836 visit(cast(Expression)e);
4839 override void visit(FuncExp e)
4841 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
4842 if (e.td)
4844 Type to = tparam;
4845 if (!to.nextOf())
4846 return;
4847 auto tof = to.nextOf().isTypeFunction();
4848 if (!tof)
4849 return;
4851 // Parameter types inference from 'tof'
4852 assert(e.td._scope);
4853 TypeFunction tf = cast(TypeFunction)e.fd.type;
4854 //printf("\ttof = %s\n", tof.toChars());
4855 //printf("\ttf = %s\n", tf.toChars());
4856 const dim = tf.parameterList.length;
4858 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
4859 return;
4861 auto tiargs = new Objects();
4862 tiargs.reserve(e.td.parameters.length);
4864 foreach (tp; *e.td.parameters)
4866 size_t u = 0;
4867 foreach (i, p; tf.parameterList)
4869 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4870 break;
4871 ++u;
4873 assert(u < dim);
4874 Parameter pto = tof.parameterList[u];
4875 if (!pto)
4876 break;
4877 Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
4878 if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length]))
4879 return;
4880 t = t.typeSemantic(e.loc, sc);
4881 if (t.ty == Terror)
4882 return;
4883 tiargs.push(t);
4886 // Set target of return type inference
4887 if (!tf.next && tof.next)
4888 e.fd.treq = tparam;
4890 auto ti = new TemplateInstance(e.loc, e.td, tiargs);
4891 Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope);
4893 // Reset inference target for the later re-semantic
4894 e.fd.treq = null;
4896 if (ex.op == EXP.error)
4897 return;
4898 if (ex.op != EXP.function_)
4899 return;
4900 visit(ex.type);
4901 return;
4904 Type t = e.type;
4906 if (t.ty == Tdelegate && tparam.ty == Tpointer)
4907 return;
4909 // Allow conversion from implicit function pointer to delegate
4910 if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
4912 TypeFunction tf = cast(TypeFunction)t.nextOf();
4913 t = (new TypeDelegate(tf)).merge();
4915 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
4916 visit(t);
4919 override void visit(SliceExp e)
4921 Type taai;
4922 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
4924 // Consider compile-time known boundaries
4925 if (Type tsa = toStaticArrayType(e))
4927 tsa.accept(this);
4928 if (result > MATCH.convert)
4929 result = MATCH.convert; // match with implicit conversion at most
4930 return;
4933 visit(cast(Expression)e);
4936 override void visit(CommaExp e)
4938 e.e2.accept(this);
4942 scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
4943 if (Type t = isType(o))
4944 t.accept(v);
4945 else if (Expression e = isExpression(o))
4947 assert(wm);
4948 e.accept(v);
4950 else
4951 assert(0);
4952 return v.result;
4955 /***********************************************************
4956 * Check whether the type t representation relies on one or more the template parameters.
4957 * Params:
4958 * t = Tested type, if null, returns false.
4959 * tparams = Template parameters.
4960 * iStart = Start index of tparams to limit the tested parameters. If it's
4961 * nonzero, tparams[0..iStart] will be excluded from the test target.
4963 bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
4965 return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.length]);
4968 /***********************************************************
4969 * Check whether the type t representation relies on one or more the template parameters.
4970 * Params:
4971 * t = Tested type, if null, returns false.
4972 * tparams = Template parameters.
4974 private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
4976 bool visitVector(TypeVector t)
4978 return t.basetype.reliesOnTemplateParameters(tparams);
4981 bool visitAArray(TypeAArray t)
4983 return t.next.reliesOnTemplateParameters(tparams) ||
4984 t.index.reliesOnTemplateParameters(tparams);
4987 bool visitFunction(TypeFunction t)
4989 foreach (i, fparam; t.parameterList)
4991 if (fparam.type.reliesOnTemplateParameters(tparams))
4992 return true;
4994 return t.next.reliesOnTemplateParameters(tparams);
4997 bool visitIdentifier(TypeIdentifier t)
4999 foreach (tp; tparams)
5001 if (tp.ident.equals(t.ident))
5002 return true;
5004 return false;
5007 bool visitInstance(TypeInstance t)
5009 foreach (tp; tparams)
5011 if (t.tempinst.name == tp.ident)
5012 return true;
5015 if (t.tempinst.tiargs)
5016 foreach (arg; *t.tempinst.tiargs)
5018 if (Type ta = isType(arg))
5020 if (ta.reliesOnTemplateParameters(tparams))
5021 return true;
5025 return false;
5028 bool visitTypeof(TypeTypeof t)
5030 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
5031 return t.exp.reliesOnTemplateParameters(tparams);
5034 bool visitTuple(TypeTuple t)
5036 if (t.arguments)
5037 foreach (arg; *t.arguments)
5039 if (arg.type.reliesOnTemplateParameters(tparams))
5040 return true;
5043 return false;
5046 if (!t)
5047 return false;
5049 Type tb = t.toBasetype();
5050 switch (tb.ty)
5052 case Tvector: return visitVector(tb.isTypeVector());
5053 case Taarray: return visitAArray(tb.isTypeAArray());
5054 case Tfunction: return visitFunction(tb.isTypeFunction());
5055 case Tident: return visitIdentifier(tb.isTypeIdentifier());
5056 case Tinstance: return visitInstance(tb.isTypeInstance());
5057 case Ttypeof: return visitTypeof(tb.isTypeTypeof());
5058 case Ttuple: return visitTuple(tb.isTypeTuple());
5059 case Tenum: return false;
5060 default: return tb.nextOf().reliesOnTemplateParameters(tparams);
5064 /***********************************************************
5065 * Check whether the expression representation relies on one or more the template parameters.
5066 * Params:
5067 * e = expression to test
5068 * tparams = Template parameters.
5069 * Returns:
5070 * true if it does
5072 private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
5074 extern (C++) final class ReliesOnTemplateParameters : Visitor
5076 alias visit = Visitor.visit;
5077 public:
5078 TemplateParameter[] tparams;
5079 bool result;
5081 extern (D) this(TemplateParameter[] tparams)
5083 this.tparams = tparams;
5086 override void visit(Expression e)
5088 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
5091 override void visit(IdentifierExp e)
5093 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5094 foreach (tp; tparams)
5096 if (e.ident == tp.ident)
5098 result = true;
5099 return;
5104 override void visit(TupleExp e)
5106 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5107 if (e.exps)
5109 foreach (ea; *e.exps)
5111 ea.accept(this);
5112 if (result)
5113 return;
5118 override void visit(ArrayLiteralExp e)
5120 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5121 if (e.elements)
5123 foreach (el; *e.elements)
5125 el.accept(this);
5126 if (result)
5127 return;
5132 override void visit(AssocArrayLiteralExp e)
5134 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5135 foreach (ek; *e.keys)
5137 ek.accept(this);
5138 if (result)
5139 return;
5141 foreach (ev; *e.values)
5143 ev.accept(this);
5144 if (result)
5145 return;
5149 override void visit(StructLiteralExp e)
5151 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5152 if (e.elements)
5154 foreach (ea; *e.elements)
5156 ea.accept(this);
5157 if (result)
5158 return;
5163 override void visit(TypeExp e)
5165 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5166 result = e.type.reliesOnTemplateParameters(tparams);
5169 override void visit(NewExp e)
5171 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5172 if (e.thisexp)
5173 e.thisexp.accept(this);
5174 result = e.newtype.reliesOnTemplateParameters(tparams);
5175 if (!result && e.arguments)
5177 foreach (ea; *e.arguments)
5179 ea.accept(this);
5180 if (result)
5181 return;
5186 override void visit(NewAnonClassExp e)
5188 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5189 result = true;
5192 override void visit(FuncExp e)
5194 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5195 result = true;
5198 override void visit(TypeidExp e)
5200 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5201 if (auto ea = isExpression(e.obj))
5202 ea.accept(this);
5203 else if (auto ta = isType(e.obj))
5204 result = ta.reliesOnTemplateParameters(tparams);
5207 override void visit(TraitsExp e)
5209 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5210 if (e.args)
5212 foreach (oa; *e.args)
5214 if (auto ea = isExpression(oa))
5215 ea.accept(this);
5216 else if (auto ta = isType(oa))
5217 result = ta.reliesOnTemplateParameters(tparams);
5218 if (result)
5219 return;
5224 override void visit(IsExp e)
5226 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5227 result = e.targ.reliesOnTemplateParameters(tparams);
5230 override void visit(UnaExp e)
5232 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5233 e.e1.accept(this);
5236 override void visit(DotTemplateInstanceExp e)
5238 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5239 visit(cast(UnaExp)e);
5240 if (!result && e.ti.tiargs)
5242 foreach (oa; *e.ti.tiargs)
5244 if (auto ea = isExpression(oa))
5245 ea.accept(this);
5246 else if (auto ta = isType(oa))
5247 result = ta.reliesOnTemplateParameters(tparams);
5248 if (result)
5249 return;
5254 override void visit(CallExp e)
5256 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5257 visit(cast(UnaExp)e);
5258 if (!result && e.arguments)
5260 foreach (ea; *e.arguments)
5262 ea.accept(this);
5263 if (result)
5264 return;
5269 override void visit(CastExp e)
5271 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5272 visit(cast(UnaExp)e);
5273 // e.to can be null for cast() with no type
5274 if (!result && e.to)
5275 result = e.to.reliesOnTemplateParameters(tparams);
5278 override void visit(SliceExp e)
5280 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5281 visit(cast(UnaExp)e);
5282 if (!result && e.lwr)
5283 e.lwr.accept(this);
5284 if (!result && e.upr)
5285 e.upr.accept(this);
5288 override void visit(IntervalExp e)
5290 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5291 e.lwr.accept(this);
5292 if (!result)
5293 e.upr.accept(this);
5296 override void visit(ArrayExp e)
5298 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5299 visit(cast(UnaExp)e);
5300 if (!result && e.arguments)
5302 foreach (ea; *e.arguments)
5303 ea.accept(this);
5307 override void visit(BinExp e)
5309 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5310 e.e1.accept(this);
5311 if (!result)
5312 e.e2.accept(this);
5315 override void visit(CondExp e)
5317 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5318 e.econd.accept(this);
5319 if (!result)
5320 visit(cast(BinExp)e);
5324 scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
5325 e.accept(v);
5326 return v.result;
5329 /***********************************************************
5330 * https://dlang.org/spec/template.html#TemplateParameter
5332 extern (C++) class TemplateParameter : ASTNode
5334 Loc loc;
5335 Identifier ident;
5337 /* True if this is a part of precedent parameter specialization pattern.
5339 * template A(T : X!TL, alias X, TL...) {}
5340 * // X and TL are dependent template parameter
5342 * A dependent template parameter should return MATCH.exact in matchArg()
5343 * to respect the match level of the corresponding precedent parameter.
5345 bool dependent;
5347 /* ======================== TemplateParameter =============================== */
5348 extern (D) this(const ref Loc loc, Identifier ident)
5350 this.loc = loc;
5351 this.ident = ident;
5354 TemplateTypeParameter isTemplateTypeParameter()
5356 return null;
5359 TemplateValueParameter isTemplateValueParameter()
5361 return null;
5364 TemplateAliasParameter isTemplateAliasParameter()
5366 return null;
5369 TemplateThisParameter isTemplateThisParameter()
5371 return null;
5374 TemplateTupleParameter isTemplateTupleParameter()
5376 return null;
5379 abstract TemplateParameter syntaxCopy();
5381 abstract bool declareParameter(Scope* sc);
5383 abstract void print(RootObject oarg, RootObject oded);
5385 abstract RootObject specialization();
5387 abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
5389 abstract bool hasDefaultArg();
5391 override const(char)* toChars() const
5393 return this.ident.toChars();
5396 override DYNCAST dyncast() const
5398 return DYNCAST.templateparameter;
5401 /* Create dummy argument based on parameter.
5403 abstract RootObject dummyArg();
5405 override void accept(Visitor v)
5407 v.visit(this);
5411 /***********************************************************
5412 * https://dlang.org/spec/template.html#TemplateTypeParameter
5413 * Syntax:
5414 * ident : specType = defaultType
5416 extern (C++) class TemplateTypeParameter : TemplateParameter
5418 Type specType; // if !=null, this is the type specialization
5419 Type defaultType;
5421 extern (D) __gshared Type tdummy = null;
5423 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
5425 super(loc, ident);
5426 this.specType = specType;
5427 this.defaultType = defaultType;
5430 override final TemplateTypeParameter isTemplateTypeParameter()
5432 return this;
5435 override TemplateTypeParameter syntaxCopy()
5437 return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5440 override final bool declareParameter(Scope* sc)
5442 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
5443 auto ti = new TypeIdentifier(loc, ident);
5444 Declaration ad = new AliasDeclaration(loc, ident, ti);
5445 return sc.insert(ad) !is null;
5448 override final void print(RootObject oarg, RootObject oded)
5450 printf(" %s\n", ident.toChars());
5452 Type t = isType(oarg);
5453 Type ta = isType(oded);
5454 assert(ta);
5456 if (specType)
5457 printf("\tSpecialization: %s\n", specType.toChars());
5458 if (defaultType)
5459 printf("\tDefault: %s\n", defaultType.toChars());
5460 printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
5461 printf("\tDeduced Type: %s\n", ta.toChars());
5464 override final RootObject specialization()
5466 return specType;
5469 override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5471 Type t = defaultType;
5472 if (t)
5474 t = t.syntaxCopy();
5475 t = t.typeSemantic(loc, sc); // use the parameter loc
5477 return t;
5480 override final bool hasDefaultArg()
5482 return defaultType !is null;
5485 override final RootObject dummyArg()
5487 Type t = specType;
5488 if (!t)
5490 // Use this for alias-parameter's too (?)
5491 if (!tdummy)
5492 tdummy = new TypeIdentifier(loc, ident);
5493 t = tdummy;
5495 return t;
5498 override void accept(Visitor v)
5500 v.visit(this);
5504 /***********************************************************
5505 * https://dlang.org/spec/template.html#TemplateThisParameter
5506 * Syntax:
5507 * this ident : specType = defaultType
5509 extern (C++) final class TemplateThisParameter : TemplateTypeParameter
5511 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
5513 super(loc, ident, specType, defaultType);
5516 override TemplateThisParameter isTemplateThisParameter()
5518 return this;
5521 override TemplateThisParameter syntaxCopy()
5523 return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5526 override void accept(Visitor v)
5528 v.visit(this);
5532 /***********************************************************
5533 * https://dlang.org/spec/template.html#TemplateValueParameter
5534 * Syntax:
5535 * valType ident : specValue = defaultValue
5537 extern (C++) final class TemplateValueParameter : TemplateParameter
5539 Type valType;
5540 Expression specValue;
5541 Expression defaultValue;
5543 extern (D) __gshared Expression[void*] edummies;
5545 extern (D) this(const ref Loc loc, Identifier ident, Type valType,
5546 Expression specValue, Expression defaultValue)
5548 super(loc, ident);
5549 this.valType = valType;
5550 this.specValue = specValue;
5551 this.defaultValue = defaultValue;
5554 override TemplateValueParameter isTemplateValueParameter()
5556 return this;
5559 override TemplateValueParameter syntaxCopy()
5561 return new TemplateValueParameter(loc, ident,
5562 valType.syntaxCopy(),
5563 specValue ? specValue.syntaxCopy() : null,
5564 defaultValue ? defaultValue.syntaxCopy() : null);
5567 override bool declareParameter(Scope* sc)
5570 Do type semantic earlier.
5572 This means for certain erroneous value parameters
5573 their "type" can be known earlier and thus a better
5574 error message given.
5576 For example:
5577 `template test(x* x) {}`
5578 now yields "undefined identifier" rather than the opaque
5579 "variable `x` is used as a type".
5581 if (valType)
5582 valType = valType.typeSemantic(loc, sc);
5583 auto v = new VarDeclaration(loc, valType, ident, null);
5584 v.storage_class = STC.templateparameter;
5585 return sc.insert(v) !is null;
5588 override void print(RootObject oarg, RootObject oded)
5590 printf(" %s\n", ident.toChars());
5591 Expression ea = isExpression(oded);
5592 if (specValue)
5593 printf("\tSpecialization: %s\n", specValue.toChars());
5594 printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
5597 override RootObject specialization()
5599 return specValue;
5602 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5604 Expression e = defaultValue;
5605 if (e)
5607 e = e.syntaxCopy();
5608 if ((e = e.expressionSemantic(sc)) is null)
5609 return null;
5610 if (auto te = e.isTemplateExp())
5612 assert(sc && sc.tinst);
5613 if (te.td == sc.tinst.tempdecl)
5615 // defaultValue is a reference to its template declaration
5616 // i.e: `template T(int arg = T)`
5617 // Raise error now before calling resolveProperties otherwise we'll
5618 // start looping on the expansion of the template instance.
5619 sc.tinst.tempdecl.error("recursive template expansion");
5620 return ErrorExp.get();
5623 if ((e = resolveProperties(sc, e)) is null)
5624 return null;
5625 e = e.resolveLoc(instLoc, sc); // use the instantiated loc
5626 e = e.optimize(WANTvalue);
5628 return e;
5631 override bool hasDefaultArg()
5633 return defaultValue !is null;
5636 override RootObject dummyArg()
5638 Expression e = specValue;
5639 if (!e)
5641 // Create a dummy value
5642 auto pe = cast(void*)valType in edummies;
5643 if (!pe)
5645 e = valType.defaultInit(Loc.initial);
5646 edummies[cast(void*)valType] = e;
5648 else
5649 e = *pe;
5651 return e;
5654 override void accept(Visitor v)
5656 v.visit(this);
5660 /***********************************************************
5661 * https://dlang.org/spec/template.html#TemplateAliasParameter
5662 * Syntax:
5663 * specType ident : specAlias = defaultAlias
5665 extern (C++) final class TemplateAliasParameter : TemplateParameter
5667 Type specType;
5668 RootObject specAlias;
5669 RootObject defaultAlias;
5671 extern (D) __gshared Dsymbol sdummy = null;
5673 extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias)
5675 super(loc, ident);
5676 this.specType = specType;
5677 this.specAlias = specAlias;
5678 this.defaultAlias = defaultAlias;
5681 override TemplateAliasParameter isTemplateAliasParameter()
5683 return this;
5686 override TemplateAliasParameter syntaxCopy()
5688 return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
5691 override bool declareParameter(Scope* sc)
5693 auto ti = new TypeIdentifier(loc, ident);
5694 Declaration ad = new AliasDeclaration(loc, ident, ti);
5695 return sc.insert(ad) !is null;
5698 override void print(RootObject oarg, RootObject oded)
5700 printf(" %s\n", ident.toChars());
5701 Dsymbol sa = isDsymbol(oded);
5702 assert(sa);
5703 printf("\tParameter alias: %s\n", sa.toChars());
5706 override RootObject specialization()
5708 return specAlias;
5711 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5713 RootObject da = defaultAlias;
5714 Type ta = isType(defaultAlias);
5715 if (ta)
5717 if (ta.ty == Tinstance)
5719 // If the default arg is a template, instantiate for each type
5720 da = ta.syntaxCopy();
5724 RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc
5725 return o;
5728 override bool hasDefaultArg()
5730 return defaultAlias !is null;
5733 override RootObject dummyArg()
5735 RootObject s = specAlias;
5736 if (!s)
5738 if (!sdummy)
5739 sdummy = new Dsymbol();
5740 s = sdummy;
5742 return s;
5745 override void accept(Visitor v)
5747 v.visit(this);
5751 /***********************************************************
5752 * https://dlang.org/spec/template.html#TemplateSequenceParameter
5753 * Syntax:
5754 * ident ...
5756 extern (C++) final class TemplateTupleParameter : TemplateParameter
5758 extern (D) this(const ref Loc loc, Identifier ident)
5760 super(loc, ident);
5763 override TemplateTupleParameter isTemplateTupleParameter()
5765 return this;
5768 override TemplateTupleParameter syntaxCopy()
5770 return new TemplateTupleParameter(loc, ident);
5773 override bool declareParameter(Scope* sc)
5775 auto ti = new TypeIdentifier(loc, ident);
5776 Declaration ad = new AliasDeclaration(loc, ident, ti);
5777 return sc.insert(ad) !is null;
5780 override void print(RootObject oarg, RootObject oded)
5782 printf(" %s... [", ident.toChars());
5783 Tuple v = isTuple(oded);
5784 assert(v);
5786 //printf("|%d| ", v.objects.length);
5787 foreach (i, o; v.objects)
5789 if (i)
5790 printf(", ");
5792 Dsymbol sa = isDsymbol(o);
5793 if (sa)
5794 printf("alias: %s", sa.toChars());
5795 Type ta = isType(o);
5796 if (ta)
5797 printf("type: %s", ta.toChars());
5798 Expression ea = isExpression(o);
5799 if (ea)
5800 printf("exp: %s", ea.toChars());
5802 assert(!isTuple(o)); // no nested Tuple arguments
5804 printf("]\n");
5807 override RootObject specialization()
5809 return null;
5812 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5814 return null;
5817 override bool hasDefaultArg()
5819 return false;
5822 override RootObject dummyArg()
5824 return null;
5827 override void accept(Visitor v)
5829 v.visit(this);
5833 /***********************************************************
5834 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
5835 * Given:
5836 * foo!(args) =>
5837 * name = foo
5838 * tiargs = args
5840 extern (C++) class TemplateInstance : ScopeDsymbol
5842 Identifier name;
5844 // Array of Types/Expressions of template
5845 // instance arguments [int*, char, 10*10]
5846 Objects* tiargs;
5848 // Array of Types/Expressions corresponding
5849 // to TemplateDeclaration.parameters
5850 // [int, char, 100]
5851 Objects tdtypes;
5853 // Modules imported by this template instance
5854 Modules importedModules;
5856 Dsymbol tempdecl; // referenced by foo.bar.abc
5857 Dsymbol enclosing; // if referencing local symbols, this is the context
5858 Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
5859 TemplateInstance inst; // refer to existing instance
5860 ScopeDsymbol argsym; // argument symbol table
5861 size_t hash; // cached result of toHash()
5862 Expressions* fargs; // for function template, these are the function arguments
5864 TemplateInstances* deferred;
5866 Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
5868 // Used to determine the instance needs code generation.
5869 // Note that these are inaccurate until semantic analysis phase completed.
5870 TemplateInstance tinst; // enclosing template instance
5871 TemplateInstance tnext; // non-first instantiated instances
5872 Module minst; // the top module that instantiated this instance
5874 private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
5875 ubyte inuse; // for recursive expansion detection
5877 private enum Flag : uint
5879 semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
5880 havetempdecl = semantictiargsdone >> 1,
5881 gagged = semantictiargsdone >> 2,
5882 available = gagged - 1 // always last flag minus one, 1s for all available bits
5885 extern(D) final @safe @property pure nothrow @nogc
5887 ushort nest() const { return _nest & Flag.available; }
5888 void nestUp() { assert(nest() < Flag.available); ++_nest; }
5889 void nestDown() { assert(nest() > 0); --_nest; }
5890 /// has semanticTiargs() been done?
5891 bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
5892 void semantictiargsdone(bool x)
5894 if (x) _nest |= Flag.semantictiargsdone;
5895 else _nest &= ~Flag.semantictiargsdone;
5897 /// if used second constructor
5898 bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
5899 void havetempdecl(bool x)
5901 if (x) _nest |= Flag.havetempdecl;
5902 else _nest &= ~Flag.havetempdecl;
5904 /// if the instantiation is done with error gagging
5905 bool gagged() const { return (_nest & Flag.gagged) != 0; }
5906 void gagged(bool x)
5908 if (x) _nest |= Flag.gagged;
5909 else _nest &= ~Flag.gagged;
5913 extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) scope
5915 super(loc, null);
5916 static if (LOG)
5918 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
5920 this.name = ident;
5921 this.tiargs = tiargs;
5924 /*****************
5925 * This constructor is only called when we figured out which function
5926 * template to instantiate.
5928 extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) scope
5930 super(loc, null);
5931 static if (LOG)
5933 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
5935 this.name = td.ident;
5936 this.tiargs = tiargs;
5937 this.tempdecl = td;
5938 this.semantictiargsdone = true;
5939 this.havetempdecl = true;
5940 assert(tempdecl._scope);
5943 extern (D) static Objects* arraySyntaxCopy(Objects* objs)
5945 Objects* a = null;
5946 if (objs)
5948 a = new Objects(objs.length);
5949 foreach (i, o; *objs)
5950 (*a)[i] = objectSyntaxCopy(o);
5952 return a;
5955 override TemplateInstance syntaxCopy(Dsymbol s)
5957 TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
5958 ti.tiargs = arraySyntaxCopy(tiargs);
5959 TemplateDeclaration td;
5960 if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
5961 td.ScopeDsymbol.syntaxCopy(ti);
5962 else
5963 ScopeDsymbol.syntaxCopy(ti);
5964 return ti;
5967 // resolve real symbol
5968 override final Dsymbol toAlias()
5970 static if (LOG)
5972 printf("TemplateInstance.toAlias()\n");
5974 if (!inst)
5976 // Maybe we can resolve it
5977 if (_scope)
5979 dsymbolSemantic(this, _scope);
5981 if (!inst)
5983 error("cannot resolve forward reference");
5984 errors = true;
5985 return this;
5989 if (inst != this)
5990 return inst.toAlias();
5992 if (aliasdecl)
5994 return aliasdecl.toAlias();
5997 return inst;
6000 override const(char)* kind() const
6002 return "template instance";
6005 override bool oneMember(Dsymbol* ps, Identifier ident)
6007 *ps = null;
6008 return true;
6011 override const(char)* toChars() const
6013 OutBuffer buf;
6014 toCBufferInstance(this, &buf);
6015 return buf.extractChars();
6018 override final const(char)* toPrettyCharsHelper()
6020 OutBuffer buf;
6021 toCBufferInstance(this, &buf, true);
6022 return buf.extractChars();
6025 /**************************************
6026 * Given an error instantiating the TemplateInstance,
6027 * give the nested TemplateInstance instantiations that got
6028 * us here. Those are a list threaded into the nested scopes.
6030 extern(D) final void printInstantiationTrace(Classification cl = Classification.error)
6032 if (global.gag)
6033 return;
6035 // Print full trace for verbose mode, otherwise only short traces
6036 const(uint) max_shown = !global.params.verbose ?
6037 (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : uint.max)
6038 : uint.max;
6040 const(char)* format = "instantiated from here: `%s`";
6042 // This returns a function pointer
6043 scope printFn = () {
6044 final switch (cl)
6046 case Classification.error:
6047 return &errorSupplemental;
6048 case Classification.warning:
6049 return &warningSupplemental;
6050 case Classification.deprecation:
6051 return &deprecationSupplemental;
6052 case Classification.gagged, Classification.tip:
6053 assert(0);
6055 }();
6057 // determine instantiation depth and number of recursive instantiations
6058 int n_instantiations = 1;
6059 int n_totalrecursions = 0;
6060 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6062 ++n_instantiations;
6063 // Set error here as we don't want it to depend on the number of
6064 // entries that are being printed.
6065 if (cl == Classification.error ||
6066 (cl == Classification.warning && global.params.warnings == DiagnosticReporting.error) ||
6067 (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
6068 cur.errors = true;
6070 // If two instantiations use the same declaration, they are recursive.
6071 // (this works even if they are instantiated from different places in the
6072 // same template).
6073 // In principle, we could also check for multiple-template recursion, but it's
6074 // probably not worthwhile.
6075 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6076 ++n_totalrecursions;
6079 if (n_instantiations <= max_shown)
6081 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6082 printFn(cur.loc, format, cur.toChars());
6084 else if (n_instantiations - n_totalrecursions <= max_shown)
6086 // By collapsing recursive instantiations into a single line,
6087 // we can stay under the limit.
6088 int recursionDepth = 0;
6089 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6091 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6093 ++recursionDepth;
6095 else
6097 if (recursionDepth)
6098 printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
6099 else
6100 printFn(cur.loc, format, cur.toChars());
6101 recursionDepth = 0;
6105 else
6107 // Even after collapsing the recursions, the depth is too deep.
6108 // Just display the first few and last few instantiations.
6109 uint i = 0;
6110 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6112 if (i == max_shown / 2)
6113 printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
6115 if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
6116 printFn(cur.loc, format, cur.toChars());
6117 ++i;
6122 /*************************************
6123 * Lazily generate identifier for template instance.
6124 * This is because 75% of the ident's are never needed.
6126 override final Identifier getIdent()
6128 if (!ident && inst && !errors)
6129 ident = genIdent(tiargs); // need an identifier for name mangling purposes.
6130 return ident;
6133 /*************************************
6134 * Compare proposed template instantiation with existing template instantiation.
6135 * Note that this is not commutative because of the auto ref check.
6136 * Params:
6137 * ti = existing template instantiation
6138 * Returns:
6139 * true for match
6141 final bool equalsx(TemplateInstance ti)
6143 //printf("this = %p, ti = %p\n", this, ti);
6144 assert(tdtypes.length == ti.tdtypes.length);
6146 // Nesting must match
6147 if (enclosing != ti.enclosing)
6149 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
6150 goto Lnotequals;
6152 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
6154 if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
6155 goto Lnotequals;
6157 /* Template functions may have different instantiations based on
6158 * "auto ref" parameters.
6160 if (auto fd = ti.toAlias().isFuncDeclaration())
6162 if (!fd.errors)
6164 auto fparameters = fd.getParameterList();
6165 size_t nfparams = fparameters.length; // Num function parameters
6166 for (size_t j = 0; j < nfparams; j++)
6168 Parameter fparam = fparameters[j];
6169 if (fparam.storageClass & STC.autoref) // if "auto ref"
6171 Expression farg = fargs && j < fargs.length ? (*fargs)[j] : fparam.defaultArg;
6172 if (!farg)
6173 goto Lnotequals;
6174 if (farg.isLvalue())
6176 if (!(fparam.storageClass & STC.ref_))
6177 goto Lnotequals; // auto ref's don't match
6179 else
6181 if (fparam.storageClass & STC.ref_)
6182 goto Lnotequals; // auto ref's don't match
6188 return true;
6190 Lnotequals:
6191 return false;
6194 final size_t toHash()
6196 if (!hash)
6198 hash = cast(size_t)cast(void*)enclosing;
6199 hash += arrayObjectHash(&tdtypes);
6200 hash += hash == 0;
6202 return hash;
6206 Returns: true if the instances' innards are discardable.
6208 The idea of this function is to see if the template instantiation
6209 can be 100% replaced with its eponymous member. All other members
6210 can be discarded, even in the compiler to free memory (for example,
6211 the template could be expanded in a region allocator, deemed trivial,
6212 the end result copied back out independently and the entire region freed),
6213 and can be elided entirely from the binary.
6215 The current implementation affects code that generally looks like:
6218 template foo(args...) {
6219 some_basic_type_or_string helper() { .... }
6220 enum foo = helper();
6224 since it was the easiest starting point of implementation but it can and
6225 should be expanded more later.
6227 final bool isDiscardable()
6229 if (aliasdecl is null)
6230 return false;
6232 auto v = aliasdecl.isVarDeclaration();
6233 if (v is null)
6234 return false;
6236 if (!(v.storage_class & STC.manifest))
6237 return false;
6239 // Currently only doing basic types here because it is the easiest proof-of-concept
6240 // implementation with minimal risk of side effects, but it could likely be
6241 // expanded to any type that already exists outside this particular instance.
6242 if (!(v.type.equals(Type.tstring) || (v.type.isTypeBasic() !is null)))
6243 return false;
6245 // Static ctors and dtors, even in an eponymous enum template, are still run,
6246 // so if any of them are in here, we'd better not assume it is trivial lest
6247 // we break useful code
6248 foreach(member; *members)
6250 if(member.hasStaticCtorOrDtor())
6251 return false;
6252 if(member.isStaticDtorDeclaration())
6253 return false;
6254 if(member.isStaticCtorDeclaration())
6255 return false;
6258 // but if it passes through this gauntlet... it should be fine. D code will
6259 // see only the eponymous member, outside stuff can never access it, even through
6260 // reflection; the outside world ought to be none the wiser. Even dmd should be
6261 // able to simply free the memory of everything except the final result.
6263 return true;
6267 /***********************************************
6268 * Returns true if this is not instantiated in non-root module, and
6269 * is a part of non-speculative instantiatiation.
6271 * Note: minst does not stabilize until semantic analysis is completed,
6272 * so don't call this function during semantic analysis to return precise result.
6274 final bool needsCodegen()
6276 //printf("needsCodegen() %s\n", toChars());
6278 // minst is finalized after the 1st invocation.
6279 // tnext is only needed for the 1st invocation and
6280 // cleared for further invocations.
6281 TemplateInstance tnext = this.tnext;
6282 TemplateInstance tinst = this.tinst;
6283 this.tnext = null;
6285 // Don't do codegen if the instance has errors,
6286 // is a dummy instance (see evaluateConstraint),
6287 // or is determined to be discardable.
6288 if (errors || inst is null || inst.isDiscardable())
6290 minst = null; // mark as speculative
6291 return false;
6294 // This should only be called on the primary instantiation.
6295 assert(this is inst);
6297 if (global.params.allInst)
6299 // Do codegen if there is an instantiation from a root module, to maximize link-ability.
6300 static ThreeState needsCodegenAllInst(TemplateInstance tithis, TemplateInstance tinst)
6302 // Do codegen if `this` is instantiated from a root module.
6303 if (tithis.minst && tithis.minst.isRoot())
6304 return ThreeState.yes;
6306 // Do codegen if the ancestor needs it.
6307 if (tinst && tinst.inst && tinst.inst.needsCodegen())
6309 tithis.minst = tinst.inst.minst; // cache result
6310 assert(tithis.minst);
6311 assert(tithis.minst.isRoot());
6312 return ThreeState.yes;
6314 return ThreeState.none;
6317 if (const needsCodegen = needsCodegenAllInst(this, tinst))
6318 return needsCodegen == ThreeState.yes ? true : false;
6320 // Do codegen if a sibling needs it.
6321 for (; tnext; tnext = tnext.tnext)
6323 const needsCodegen = needsCodegenAllInst(tnext, tnext.tinst);
6324 if (needsCodegen == ThreeState.yes)
6326 minst = tnext.minst; // cache result
6327 assert(minst);
6328 assert(minst.isRoot());
6329 return true;
6331 else if (!minst && tnext.minst)
6333 minst = tnext.minst; // cache result from non-speculative sibling
6334 // continue searching
6336 else if (needsCodegen != ThreeState.none)
6337 break;
6340 // Elide codegen because there's no instantiation from any root modules.
6341 return false;
6343 else
6345 // Prefer instantiations from non-root modules, to minimize object code size.
6347 /* If a TemplateInstance is ever instantiated from a non-root module,
6348 * we do not have to generate code for it,
6349 * because it will be generated when the non-root module is compiled.
6351 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
6353 * The problem is if A imports B, and B imports A, and both A
6354 * and B instantiate the same template, does the compilation of A
6355 * or the compilation of B do the actual instantiation?
6357 * See https://issues.dlang.org/show_bug.cgi?id=2500.
6359 * => Elide codegen if there is at least one instantiation from a non-root module
6360 * which doesn't import any root modules.
6362 static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst)
6364 // If the ancestor isn't speculative,
6365 // 1. do codegen if the ancestor needs it
6366 // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
6367 if (tinst && tinst.inst)
6369 tinst = tinst.inst;
6370 const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
6371 if (tinst.minst) // not speculative
6373 tithis.minst = tinst.minst; // cache result
6374 return needsCodegen ? ThreeState.yes : ThreeState.no;
6378 // Elide codegen if `this` doesn't need it.
6379 if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
6380 return ThreeState.no;
6382 return ThreeState.none;
6385 if (const needsCodegen = needsCodegenRootOnly(this, tinst))
6386 return needsCodegen == ThreeState.yes ? true : false;
6388 // Elide codegen if a (non-speculative) sibling doesn't need it.
6389 for (; tnext; tnext = tnext.tnext)
6391 const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
6392 if (tnext.minst) // not speculative
6394 if (needsCodegen == ThreeState.no)
6396 minst = tnext.minst; // cache result
6397 assert(!minst.isRoot() && !minst.rootImports());
6398 return false;
6400 else if (!minst)
6402 minst = tnext.minst; // cache result from non-speculative sibling
6403 // continue searching
6405 else if (needsCodegen != ThreeState.none)
6406 break;
6410 // Unless `this` is still speculative (=> all further siblings speculative too),
6411 // do codegen because we found no guaranteed-codegen'd non-root instantiation.
6412 return minst !is null;
6416 /**********************************************
6417 * Find template declaration corresponding to template instance.
6419 * Returns:
6420 * false if finding fails.
6421 * Note:
6422 * This function is reentrant against error occurrence. If returns false,
6423 * any members of this object won't be modified, and repetition call will
6424 * reproduce same error.
6426 extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym)
6428 if (pwithsym)
6429 *pwithsym = null;
6431 if (havetempdecl)
6432 return true;
6434 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
6435 if (!tempdecl)
6437 /* Given:
6438 * foo!( ... )
6439 * figure out which TemplateDeclaration foo refers to.
6441 Identifier id = name;
6442 Dsymbol scopesym;
6443 Dsymbol s = sc.search(loc, id, &scopesym);
6444 if (!s)
6446 s = sc.search_correct(id);
6447 if (s)
6448 error("template `%s` is not defined, did you mean %s?", id.toChars(), s.toChars());
6449 else
6450 error("template `%s` is not defined", id.toChars());
6451 return false;
6453 static if (LOG)
6455 printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
6456 if (s.parent)
6457 printf("s.parent = '%s'\n", s.parent.toChars());
6459 if (pwithsym)
6460 *pwithsym = scopesym.isWithScopeSymbol();
6462 /* We might have found an alias within a template when
6463 * we really want the template.
6465 TemplateInstance ti;
6466 if (s.parent && (ti = s.parent.isTemplateInstance()) !is null)
6468 if (ti.tempdecl && ti.tempdecl.ident == id)
6470 /* This is so that one can refer to the enclosing
6471 * template, even if it has the same name as a member
6472 * of the template, if it has a !(arguments)
6474 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6475 assert(td);
6476 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6477 td = td.overroot; // then get the start
6478 s = td;
6482 // The template might originate from a selective import which implies that
6483 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
6484 // This is the last place where we see the deprecated alias because it is
6485 // stripped below, so check if the selective import was deprecated.
6486 // See https://issues.dlang.org/show_bug.cgi?id=20840.
6487 if (s.isAliasDeclaration())
6488 s.checkDeprecated(this.loc, sc);
6490 if (!updateTempDecl(sc, s))
6492 return false;
6495 assert(tempdecl);
6497 // Look for forward references
6498 auto tovers = tempdecl.isOverloadSet();
6499 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
6501 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6502 int r = overloadApply(dstart, (Dsymbol s)
6504 auto td = s.isTemplateDeclaration();
6505 if (!td)
6506 return 0;
6508 if (td.semanticRun == PASS.initial)
6510 if (td._scope)
6512 // Try to fix forward reference. Ungag errors while doing so.
6513 Ungag ungag = td.ungagSpeculative();
6514 td.dsymbolSemantic(td._scope);
6516 if (td.semanticRun == PASS.initial)
6518 error("`%s` forward references template declaration `%s`",
6519 toChars(), td.toChars());
6520 return 1;
6523 return 0;
6525 if (r)
6526 return false;
6528 return true;
6531 /**********************************************
6532 * Confirm s is a valid template, then store it.
6533 * Input:
6534 * sc
6535 * s candidate symbol of template. It may be:
6536 * TemplateDeclaration
6537 * FuncDeclaration with findTemplateDeclRoot() != NULL
6538 * OverloadSet which contains candidates
6539 * Returns:
6540 * true if updating succeeds.
6542 extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s)
6544 if (!s)
6545 return tempdecl !is null;
6547 Identifier id = name;
6548 s = s.toAlias();
6550 /* If an OverloadSet, look for a unique member that is a template declaration
6552 if (OverloadSet os = s.isOverloadSet())
6554 s = null;
6555 foreach (s2; os.a)
6557 if (FuncDeclaration f = s2.isFuncDeclaration())
6558 s2 = f.findTemplateDeclRoot();
6559 else
6560 s2 = s2.isTemplateDeclaration();
6561 if (s2)
6563 if (s)
6565 tempdecl = os;
6566 return true;
6568 s = s2;
6571 if (!s)
6573 error("template `%s` is not defined", id.toChars());
6574 return false;
6578 if (OverDeclaration od = s.isOverDeclaration())
6580 tempdecl = od; // TODO: more strict check
6581 return true;
6584 /* It should be a TemplateDeclaration, not some other symbol
6586 if (FuncDeclaration f = s.isFuncDeclaration())
6587 tempdecl = f.findTemplateDeclRoot();
6588 else
6589 tempdecl = s.isTemplateDeclaration();
6591 // We're done
6592 if (tempdecl)
6593 return true;
6595 // Error already issued, just return `false`
6596 if (!s.parent && global.errors)
6597 return false;
6599 if (!s.parent && s.getType())
6601 Dsymbol s2 = s.getType().toDsymbol(sc);
6602 if (!s2)
6604 .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());
6605 return false;
6607 // because s can be the alias created for a TemplateParameter
6608 const AliasDeclaration ad = s.isAliasDeclaration();
6609 version (none)
6611 if (ad && ad.isAliasedTemplateParameter())
6612 printf("`%s` is an alias created from a template parameter\n", s.toChars());
6614 if (!ad || !ad.isAliasedTemplateParameter())
6615 s = s2;
6618 TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
6620 /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
6622 static bool matchId(TemplateInstance ti, Identifier id)
6624 if (ti.aliasdecl && ti.aliasdecl.isVarDeclaration())
6625 return ti.aliasdecl.isVarDeclaration().ident == id;
6626 return ti.toAlias().ident == id;
6629 if (ti && (ti.name == s.ident || matchId(ti, s.ident)) && ti.tempdecl)
6631 /* This is so that one can refer to the enclosing
6632 * template, even if it has the same name as a member
6633 * of the template, if it has a !(arguments)
6635 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6636 assert(td);
6637 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6638 td = td.overroot; // then get the start
6639 tempdecl = td;
6640 return true;
6642 else
6644 error("`%s` is not a template declaration, it is a %s", id.toChars(), s.kind());
6645 return false;
6649 /**********************************
6650 * Run semantic of tiargs as arguments of template.
6651 * Input:
6652 * loc
6653 * sc
6654 * tiargs array of template arguments
6655 * flags 1: replace const variables with their initializers
6656 * 2: don't devolve Parameter to Type
6657 * atd tuple being optimized. If found, it's not expanded here
6658 * but in AliasAssign semantic.
6659 * Returns:
6660 * false if one or more arguments have errors.
6662 extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null)
6664 // Run semantic on each argument, place results in tiargs[]
6665 //printf("+TemplateInstance.semanticTiargs()\n");
6666 if (!tiargs)
6667 return true;
6668 bool err = false;
6669 for (size_t j = 0; j < tiargs.length; j++)
6671 RootObject o = (*tiargs)[j];
6672 Type ta = isType(o);
6673 Expression ea = isExpression(o);
6674 Dsymbol sa = isDsymbol(o);
6676 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
6677 if (ta)
6679 //printf("type %s\n", ta.toChars());
6681 // It might really be an Expression or an Alias
6682 ta.resolve(loc, sc, ea, ta, sa, (flags & 1) != 0);
6683 if (ea)
6684 goto Lexpr;
6685 if (sa)
6686 goto Ldsym;
6687 if (ta is null)
6689 assert(global.errors);
6690 ta = Type.terror;
6693 Ltype:
6694 if (ta.ty == Ttuple)
6696 // Expand tuple
6697 TypeTuple tt = cast(TypeTuple)ta;
6698 size_t dim = tt.arguments.length;
6699 tiargs.remove(j);
6700 if (dim)
6702 tiargs.reserve(dim);
6703 foreach (i, arg; *tt.arguments)
6705 if (flags & 2 && (arg.storageClass & STC.parameter))
6706 tiargs.insert(j + i, arg);
6707 else
6708 tiargs.insert(j + i, arg.type);
6711 j--;
6712 continue;
6714 if (ta.ty == Terror)
6716 err = true;
6717 continue;
6719 (*tiargs)[j] = ta.merge2();
6721 else if (ea)
6723 Lexpr:
6724 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6725 if (flags & 1) // only used by __traits
6727 ea = ea.expressionSemantic(sc);
6729 // must not interpret the args, excepting template parameters
6730 if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
6732 ea = ea.optimize(WANTvalue);
6735 else
6737 sc = sc.startCTFE();
6738 ea = ea.expressionSemantic(sc);
6739 sc = sc.endCTFE();
6741 if (ea.op == EXP.variable)
6743 /* If the parameter is a function that is not called
6744 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
6745 * then it is a dsymbol, not the return value of `func()`
6747 Declaration vd = (cast(VarExp)ea).var;
6748 if (auto fd = vd.isFuncDeclaration())
6750 sa = fd;
6751 goto Ldsym;
6753 /* Otherwise skip substituting a const var with
6754 * its initializer. The problem is the initializer won't
6755 * match with an 'alias' parameter. Instead, do the
6756 * const substitution in TemplateValueParameter.matchArg().
6759 else if (definitelyValueParameter(ea))
6761 if (ea.checkValue()) // check void expression
6762 ea = ErrorExp.get();
6763 uint olderrs = global.errors;
6764 ea = ea.ctfeInterpret();
6765 if (global.errors != olderrs)
6766 ea = ErrorExp.get();
6769 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6770 if (ea.op == EXP.tuple)
6772 // Expand tuple
6773 TupleExp te = cast(TupleExp)ea;
6774 size_t dim = te.exps.length;
6775 tiargs.remove(j);
6776 if (dim)
6778 tiargs.reserve(dim);
6779 foreach (i, exp; *te.exps)
6780 tiargs.insert(j + i, exp);
6782 j--;
6783 continue;
6785 if (ea.op == EXP.error)
6787 err = true;
6788 continue;
6790 (*tiargs)[j] = ea;
6792 if (ea.op == EXP.type)
6794 ta = ea.type;
6795 goto Ltype;
6797 if (ea.op == EXP.scope_)
6799 sa = (cast(ScopeExp)ea).sds;
6800 goto Ldsym;
6802 if (ea.op == EXP.function_)
6804 FuncExp fe = cast(FuncExp)ea;
6805 /* A function literal, that is passed to template and
6806 * already semanticed as function pointer, never requires
6807 * outer frame. So convert it to global function is valid.
6809 if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer)
6811 // change to non-nested
6812 fe.fd.tok = TOK.function_;
6813 fe.fd.vthis = null;
6815 else if (fe.td)
6817 /* If template argument is a template lambda,
6818 * get template declaration itself. */
6819 //sa = fe.td;
6820 //goto Ldsym;
6823 if (ea.op == EXP.dotVariable && !(flags & 1))
6825 // translate expression to dsymbol.
6826 sa = (cast(DotVarExp)ea).var;
6827 goto Ldsym;
6829 if (ea.op == EXP.template_)
6831 sa = (cast(TemplateExp)ea).td;
6832 goto Ldsym;
6834 if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
6836 // translate expression to dsymbol.
6837 sa = (cast(DotTemplateExp)ea).td;
6838 goto Ldsym;
6840 if (ea.op == EXP.dot)
6842 if (auto se = (cast(DotExp)ea).e2.isScopeExp())
6844 sa = se.sds;
6845 goto Ldsym;
6849 else if (sa)
6851 Ldsym:
6852 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
6853 if (sa.errors)
6855 err = true;
6856 continue;
6859 TupleDeclaration d = sa.toAlias().isTupleDeclaration();
6860 if (d)
6862 if (d is atd)
6864 (*tiargs)[j] = d;
6865 continue;
6867 // Expand tuple
6868 tiargs.remove(j);
6869 tiargs.insert(j, d.objects);
6870 j--;
6871 continue;
6873 if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration())
6875 FuncDeclaration f = fa.toAliasFunc();
6876 if (!fa.hasOverloads && f.isUnique())
6878 // Strip FuncAlias only when the aliased function
6879 // does not have any overloads.
6880 sa = f;
6883 (*tiargs)[j] = sa;
6885 TemplateDeclaration td = sa.isTemplateDeclaration();
6886 if (td && td.semanticRun == PASS.initial && td.literal)
6888 td.dsymbolSemantic(sc);
6890 FuncDeclaration fd = sa.isFuncDeclaration();
6891 if (fd)
6892 fd.functionSemantic();
6894 else if (isParameter(o))
6897 else
6899 assert(0);
6901 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
6903 version (none)
6905 printf("-TemplateInstance.semanticTiargs()\n");
6906 for (size_t j = 0; j < tiargs.length; j++)
6908 RootObject o = (*tiargs)[j];
6909 Type ta = isType(o);
6910 Expression ea = isExpression(o);
6911 Dsymbol sa = isDsymbol(o);
6912 Tuple va = isTuple(o);
6913 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
6916 return !err;
6919 /**********************************
6920 * Run semantic on the elements of tiargs.
6921 * Input:
6922 * sc
6923 * Returns:
6924 * false if one or more arguments have errors.
6925 * Note:
6926 * This function is reentrant against error occurrence. If returns false,
6927 * all elements of tiargs won't be modified.
6929 extern (D) final bool semanticTiargs(Scope* sc)
6931 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
6932 if (semantictiargsdone)
6933 return true;
6934 if (semanticTiargs(loc, sc, tiargs, 0))
6936 // cache the result iff semantic analysis succeeded entirely
6937 semantictiargsdone = 1;
6938 return true;
6940 return false;
6943 /**********************************
6944 * Find the TemplateDeclaration that matches this TemplateInstance best.
6946 * Params:
6947 * sc = the scope this TemplateInstance resides in
6948 * argumentList = function arguments in case of a template function
6950 * Returns:
6951 * `true` if a match was found, `false` otherwise
6953 extern (D) final bool findBestMatch(Scope* sc, ArgumentList argumentList)
6955 if (havetempdecl)
6957 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
6958 assert(tempdecl);
6959 assert(tempdecl._scope);
6960 // Deduce tdtypes
6961 tdtypes.setDim(tempdecl.parameters.length);
6962 if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2))
6964 error("incompatible arguments for template instantiation");
6965 return false;
6967 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
6968 return true;
6971 static if (LOG)
6973 printf("TemplateInstance.findBestMatch()\n");
6976 uint errs = global.errors;
6977 TemplateDeclaration td_last = null;
6978 Objects dedtypes;
6980 /* Since there can be multiple TemplateDeclaration's with the same
6981 * name, look for the best match.
6983 auto tovers = tempdecl.isOverloadSet();
6984 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
6986 TemplateDeclaration td_best;
6987 TemplateDeclaration td_ambig;
6988 MATCH m_best = MATCH.nomatch;
6990 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6991 overloadApply(dstart, (Dsymbol s)
6993 auto td = s.isTemplateDeclaration();
6994 if (!td)
6995 return 0;
6996 if (td == td_best) // skip duplicates
6997 return 0;
6999 //printf("td = %s\n", td.toPrettyChars());
7000 // If more arguments than parameters,
7001 // then this is no match.
7002 if (td.parameters.length < tiargs.length)
7004 if (!td.isVariadic())
7005 return 0;
7008 dedtypes.setDim(td.parameters.length);
7009 dedtypes.zero();
7010 assert(td.semanticRun != PASS.initial);
7012 MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0);
7013 //printf("matchWithInstance = %d\n", m);
7014 if (m == MATCH.nomatch) // no match at all
7015 return 0;
7016 if (m < m_best) goto Ltd_best;
7017 if (m > m_best) goto Ltd;
7019 // Disambiguate by picking the most specialized TemplateDeclaration
7021 MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
7022 MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
7023 //printf("c1 = %d, c2 = %d\n", c1, c2);
7024 if (c1 > c2) goto Ltd;
7025 if (c1 < c2) goto Ltd_best;
7028 td_ambig = td;
7029 return 0;
7031 Ltd_best:
7032 // td_best is the best match so far
7033 td_ambig = null;
7034 return 0;
7036 Ltd:
7037 // td is the new best match
7038 td_ambig = null;
7039 td_best = td;
7040 m_best = m;
7041 tdtypes.setDim(dedtypes.length);
7042 memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.length * (void*).sizeof);
7043 return 0;
7046 if (td_ambig)
7048 .error(loc, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`",
7049 td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(),
7050 td_best.loc.toChars(), td_best.toChars(),
7051 td_ambig.loc.toChars(), td_ambig.toChars());
7052 return false;
7054 if (td_best)
7056 if (!td_last)
7057 td_last = td_best;
7058 else if (td_last != td_best)
7060 ScopeDsymbol.multiplyDefined(loc, td_last, td_best);
7061 return false;
7066 if (td_last)
7068 /* https://issues.dlang.org/show_bug.cgi?id=7469
7069 * Normalize tiargs by using corresponding deduced
7070 * template value parameters and tuples for the correct mangling.
7072 * By doing this before hasNestedArgs, CTFEable local variable will be
7073 * accepted as a value parameter. For example:
7075 * void foo() {
7076 * struct S(int n) {} // non-global template
7077 * const int num = 1; // CTFEable local variable
7078 * S!num s; // S!1 is instantiated, not S!num
7081 size_t dim = td_last.parameters.length - (td_last.isVariadic() ? 1 : 0);
7082 for (size_t i = 0; i < dim; i++)
7084 if (tiargs.length <= i)
7085 tiargs.push(tdtypes[i]);
7086 assert(i < tiargs.length);
7088 auto tvp = (*td_last.parameters)[i].isTemplateValueParameter();
7089 if (!tvp)
7090 continue;
7091 assert(tdtypes[i]);
7092 // tdtypes[i] is already normalized to the required type in matchArg
7094 (*tiargs)[i] = tdtypes[i];
7096 if (td_last.isVariadic() && tiargs.length == dim && tdtypes[dim])
7098 Tuple va = isTuple(tdtypes[dim]);
7099 assert(va);
7100 tiargs.pushSlice(va.objects[]);
7103 else if (errors && inst)
7105 // instantiation was failed with error reporting
7106 assert(global.errors);
7107 return false;
7109 else
7111 auto tdecl = tempdecl.isTemplateDeclaration();
7113 if (errs != global.errors)
7114 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7115 else if (tdecl && !tdecl.overnext)
7117 // Only one template, so we can give better error message
7118 const(char)* msg = "does not match template declaration";
7119 const(char)* tip;
7120 const tmsg = tdecl.toCharsNoConstraints();
7121 const cmsg = tdecl.getConstraintEvalError(tip);
7122 if (cmsg)
7124 error("%s `%s`\n%s", msg, tmsg, cmsg);
7125 if (tip)
7126 .tip(tip);
7128 else
7130 error("%s `%s`", msg, tmsg);
7132 if (tdecl.parameters.length == tiargs.length)
7134 // https://issues.dlang.org/show_bug.cgi?id=7352
7135 // print additional information, e.g. `foo` is not a type
7136 foreach (i, param; *tdecl.parameters)
7138 MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
7139 auto arg = (*tiargs)[i];
7140 auto sym = arg.isDsymbol;
7141 auto exp = arg.isExpression;
7143 if (exp)
7144 exp = exp.optimize(WANTvalue);
7146 if (match == MATCH.nomatch &&
7147 ((sym && sym.isFuncDeclaration) ||
7148 (exp && exp.isVarExp)))
7150 if (param.isTemplateTypeParameter)
7151 errorSupplemental(loc, "`%s` is not a type", arg.toChars);
7152 else if (auto tvp = param.isTemplateValueParameter)
7153 errorSupplemental(loc, "`%s` is not of a value of type `%s`",
7154 arg.toChars, tvp.valType.toChars);
7161 else
7163 .error(loc, "%s `%s` does not match any template declaration", kind(), toPrettyChars());
7164 bool found;
7165 overloadApply(tempdecl, (s){
7166 if (!found)
7167 errorSupplemental(loc, "Candidates are:");
7168 found = true;
7169 errorSupplemental(s.loc, "%s", s.toChars());
7170 return 0;
7173 return false;
7176 /* The best match is td_last
7178 tempdecl = td_last;
7180 static if (LOG)
7182 printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
7184 return (errs == global.errors);
7187 /*****************************************************
7188 * Determine if template instance is really a template function,
7189 * and that template function needs to infer types from the function
7190 * arguments.
7192 * Like findBestMatch, iterate possible template candidates,
7193 * but just looks only the necessity of type inference.
7195 extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
7197 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
7198 if (semanticRun != PASS.initial)
7199 return false;
7201 uint olderrs = global.errors;
7202 Objects dedtypes;
7203 size_t count = 0;
7205 auto tovers = tempdecl.isOverloadSet();
7206 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
7208 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7209 int r = overloadApply(dstart, (Dsymbol s)
7211 auto td = s.isTemplateDeclaration();
7212 if (!td)
7213 return 0;
7215 /* If any of the overloaded template declarations need inference,
7216 * then return true
7218 if (!td.onemember)
7219 return 0;
7220 if (auto td2 = td.onemember.isTemplateDeclaration())
7222 if (!td2.onemember || !td2.onemember.isFuncDeclaration())
7223 return 0;
7224 if (tiargs.length >= td.parameters.length - (td.isVariadic() ? 1 : 0))
7225 return 0;
7226 return 1;
7228 auto fd = td.onemember.isFuncDeclaration();
7229 if (!fd || fd.type.ty != Tfunction)
7230 return 0;
7232 foreach (tp; *td.parameters)
7234 if (tp.isTemplateThisParameter())
7235 return 1;
7238 /* Determine if the instance arguments, tiargs, are all that is necessary
7239 * to instantiate the template.
7241 //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
7242 auto tf = cast(TypeFunction)fd.type;
7243 if (tf.parameterList.length)
7245 auto tp = td.isVariadic();
7246 if (tp && td.parameters.length > 1)
7247 return 1;
7249 if (!tp && tiargs.length < td.parameters.length)
7251 // Can remain tiargs be filled by default arguments?
7252 foreach (size_t i; tiargs.length .. td.parameters.length)
7254 if (!(*td.parameters)[i].hasDefaultArg())
7255 return 1;
7259 foreach (i, fparam; tf.parameterList)
7261 // 'auto ref' needs inference.
7262 if (fparam.storageClass & STC.auto_)
7263 return 1;
7267 if (!flag)
7269 /* Calculate the need for overload resolution.
7270 * When only one template can match with tiargs, inference is not necessary.
7272 dedtypes.setDim(td.parameters.length);
7273 dedtypes.zero();
7274 if (td.semanticRun == PASS.initial)
7276 if (td._scope)
7278 // Try to fix forward reference. Ungag errors while doing so.
7279 Ungag ungag = td.ungagSpeculative();
7280 td.dsymbolSemantic(td._scope);
7282 if (td.semanticRun == PASS.initial)
7284 error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
7285 return 1;
7288 MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0);
7289 if (m == MATCH.nomatch)
7290 return 0;
7293 /* If there is more than one function template which matches, we may
7294 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
7296 return ++count > 1 ? 1 : 0;
7298 if (r)
7299 return true;
7302 if (olderrs != global.errors)
7304 if (!global.gag)
7306 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7307 semanticRun = PASS.semanticdone;
7308 inst = this;
7310 errors = true;
7312 //printf("false\n");
7313 return false;
7316 /*****************************************
7317 * Determines if a TemplateInstance will need a nested
7318 * generation of the TemplateDeclaration.
7319 * Sets enclosing property if so, and returns != 0;
7321 extern (D) final bool hasNestedArgs(Objects* args, bool isstatic)
7323 int nested = 0;
7324 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
7326 // arguments from parent instances are also accessible
7327 if (!enclosing)
7329 if (TemplateInstance ti = tempdecl.toParent().isTemplateInstance())
7330 enclosing = ti.enclosing;
7333 /* A nested instance happens when an argument references a local
7334 * symbol that is on the stack.
7336 foreach (o; *args)
7338 Expression ea = isExpression(o);
7339 Dsymbol sa = isDsymbol(o);
7340 Tuple va = isTuple(o);
7341 if (ea)
7343 if (ea.op == EXP.variable)
7345 sa = (cast(VarExp)ea).var;
7346 goto Lsa;
7348 if (ea.op == EXP.this_)
7350 sa = (cast(ThisExp)ea).var;
7351 goto Lsa;
7353 if (ea.op == EXP.function_)
7355 if ((cast(FuncExp)ea).td)
7356 sa = (cast(FuncExp)ea).td;
7357 else
7358 sa = (cast(FuncExp)ea).fd;
7359 goto Lsa;
7361 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
7362 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)
7364 ea.error("expression `%s` is not a valid template value argument", ea.toChars());
7365 errors = true;
7368 else if (sa)
7370 Lsa:
7371 sa = sa.toAlias();
7372 TemplateDeclaration td = sa.isTemplateDeclaration();
7373 if (td)
7375 TemplateInstance ti = sa.toParent().isTemplateInstance();
7376 if (ti && ti.enclosing)
7377 sa = ti;
7379 TemplateInstance ti = sa.isTemplateInstance();
7380 Declaration d = sa.isDeclaration();
7381 if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin()))
7383 Dsymbol dparent = sa.toParent2();
7384 if (!dparent || dparent.isModule)
7385 goto L1;
7386 else if (!enclosing)
7387 enclosing = dparent;
7388 else if (enclosing != dparent)
7390 /* Select the more deeply nested of the two.
7391 * Error if one is not nested inside the other.
7393 for (Dsymbol p = enclosing; p; p = p.parent)
7395 if (p == dparent)
7396 goto L1; // enclosing is most nested
7398 for (Dsymbol p = dparent; p; p = p.parent)
7400 if (p == enclosing)
7402 enclosing = dparent;
7403 goto L1; // dparent is most nested
7406 //https://issues.dlang.org/show_bug.cgi?id=17870
7407 if (dparent.isClassDeclaration() && enclosing.isClassDeclaration())
7409 auto pc = dparent.isClassDeclaration();
7410 auto ec = enclosing.isClassDeclaration();
7411 if (pc.isBaseOf(ec, null))
7412 goto L1;
7413 else if (ec.isBaseOf(pc, null))
7415 enclosing = dparent;
7416 goto L1;
7419 error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars());
7420 errors = true;
7423 //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
7424 nested |= 1;
7427 else if (va)
7429 nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
7432 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
7433 return nested != 0;
7436 /*****************************************
7437 * Append 'this' to the specific module members[]
7439 extern (D) final Dsymbols* appendToModuleMember()
7441 Module mi = minst; // instantiated . inserted module
7443 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
7444 // toPrettyChars(),
7445 // enclosing ? enclosing.toPrettyChars() : null,
7446 // mi ? mi.toPrettyChars() : null);
7447 if (global.params.allInst || !mi || mi.isRoot())
7449 /* If the instantiated module is speculative or root, insert to the
7450 * member of a root module. Then:
7451 * - semantic3 pass will get called on the instance members.
7452 * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
7454 static Dsymbol getStrictEnclosing(TemplateInstance ti)
7458 if (ti.enclosing)
7459 return ti.enclosing;
7460 ti = ti.tempdecl.isInstantiated();
7461 } while (ti);
7462 return null;
7465 Dsymbol enc = getStrictEnclosing(this);
7466 // insert target is made stable by using the module
7467 // where tempdecl is declared.
7468 mi = (enc ? enc : tempdecl).getModule();
7469 if (!mi.isRoot())
7471 if (mi.importedFrom)
7473 mi = mi.importedFrom;
7474 assert(mi.isRoot());
7476 else
7478 // This can happen when using the frontend as a library.
7479 // Append it to the non-root module.
7483 else
7485 /* If the instantiated module is non-root, insert to the member of the
7486 * non-root module. Then:
7487 * - semantic3 pass won't be called on the instance.
7488 * - codegen pass won't reach to the instance.
7489 * Unless it is re-appended to a root module later (with changed minst).
7492 //printf("\t-. mi = %s\n", mi.toPrettyChars());
7494 assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module");
7496 Dsymbols* a = mi.members;
7497 a.push(this);
7498 memberOf = mi;
7499 if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
7500 Module.addDeferredSemantic2(this);
7501 if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
7502 Module.addDeferredSemantic3(this);
7503 return a;
7506 /****************************************************
7507 * Declare parameters of template instance, initialize them with the
7508 * template instance arguments.
7510 extern (D) final void declareParameters(Scope* sc)
7512 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
7513 assert(tempdecl);
7515 //printf("TemplateInstance.declareParameters()\n");
7516 foreach (i, o; tdtypes) // initializer for tp
7518 TemplateParameter tp = (*tempdecl.parameters)[i];
7519 //printf("\ttdtypes[%d] = %p\n", i, o);
7520 tempdecl.declareParameter(sc, tp, o);
7524 /****************************************
7525 * This instance needs an identifier for name mangling purposes.
7526 * Create one by taking the template declaration name and adding
7527 * the type signature for it.
7529 extern (D) final Identifier genIdent(Objects* args)
7531 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
7532 assert(args is tiargs);
7533 OutBuffer buf;
7534 mangleToBuffer(this, &buf);
7535 //printf("\tgenIdent = %s\n", buf.peekChars());
7536 return Identifier.idPool(buf[]);
7539 extern (D) final void expandMembers(Scope* sc2)
7541 members.foreachDsymbol( (s) { s.setScope (sc2); } );
7543 members.foreachDsymbol( (s) { s.importAll(sc2); } );
7545 if (!aliasdecl)
7547 /* static if's are crucial to evaluating aliasdecl correctly. But
7548 * evaluating the if/else bodies may require aliasdecl.
7549 * So, evaluate the condition for static if's, but not their if/else bodies.
7550 * Then try to set aliasdecl.
7551 * Later do the if/else bodies.
7552 * https://issues.dlang.org/show_bug.cgi?id=23598
7553 * It might be better to do this by attaching a lambda to the StaticIfDeclaration
7554 * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
7556 bool done;
7557 void staticIfDg(Dsymbol s)
7559 if (done || aliasdecl)
7560 return;
7561 //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
7562 if (!s.isStaticIfDeclaration())
7564 //s.dsymbolSemantic(sc2);
7565 done = true;
7566 return;
7568 auto sid = s.isStaticIfDeclaration();
7569 sid.include(sc2);
7570 if (members.length)
7572 Dsymbol sa;
7573 if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa)
7574 aliasdecl = sa;
7576 done = true;
7579 members.foreachDsymbol(&staticIfDg);
7582 void symbolDg(Dsymbol s)
7584 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
7585 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
7586 //if (enclosing)
7587 // s.parent = sc.parent;
7588 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7589 s.dsymbolSemantic(sc2);
7590 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7591 Module.runDeferredSemantic();
7594 members.foreachDsymbol(&symbolDg);
7597 extern (D) final void tryExpandMembers(Scope* sc2)
7599 __gshared int nest;
7600 // extracted to a function to allow windows SEH to work without destructors in the same function
7601 //printf("%d\n", nest);
7602 if (++nest > global.recursionLimit)
7604 global.gag = 0; // ensure error message gets printed
7605 error("recursive expansion exceeded allowed nesting limit");
7606 fatal();
7609 expandMembers(sc2);
7611 nest--;
7614 extern (D) final void trySemantic3(Scope* sc2)
7616 // extracted to a function to allow windows SEH to work without destructors in the same function
7617 __gshared int nest;
7618 //printf("%d\n", nest);
7619 if (++nest > global.recursionLimit)
7621 global.gag = 0; // ensure error message gets printed
7622 error("recursive expansion exceeded allowed nesting limit");
7623 fatal();
7626 semantic3(this, sc2);
7628 --nest;
7631 override final inout(TemplateInstance) isTemplateInstance() inout
7633 return this;
7636 override void accept(Visitor v)
7638 v.visit(this);
7642 /**************************************
7643 * IsExpression can evaluate the specified type speculatively, and even if
7644 * it instantiates any symbols, they are normally unnecessary for the
7645 * final executable.
7646 * However, if those symbols leak to the actual code, compiler should remark
7647 * them as non-speculative to generate their code and link to the final executable.
7649 void unSpeculative(Scope* sc, RootObject o)
7651 if (!o)
7652 return;
7654 if (Tuple tup = isTuple(o))
7656 foreach (obj; tup.objects)
7658 unSpeculative(sc, obj);
7660 return;
7663 Dsymbol s = getDsymbol(o);
7664 if (!s)
7665 return;
7667 if (Declaration d = s.isDeclaration())
7669 if (VarDeclaration vd = d.isVarDeclaration())
7670 o = vd.type;
7671 else if (AliasDeclaration ad = d.isAliasDeclaration())
7673 o = ad.getType();
7674 if (!o)
7675 o = ad.toAlias();
7677 else
7678 o = d.toAlias();
7680 s = getDsymbol(o);
7681 if (!s)
7682 return;
7685 if (TemplateInstance ti = s.isTemplateInstance())
7687 // If the instance is already non-speculative,
7688 // or it is leaked to the speculative scope.
7689 if (ti.minst !is null || sc.minst is null)
7690 return;
7692 // Remark as non-speculative instance.
7693 ti.minst = sc.minst;
7694 if (!ti.tinst)
7695 ti.tinst = sc.tinst;
7697 unSpeculative(sc, ti.tempdecl);
7700 if (TemplateInstance ti = s.isInstantiated())
7701 unSpeculative(sc, ti);
7704 /**********************************
7705 * Return true if e could be valid only as a template value parameter.
7706 * Return false if it might be an alias or tuple.
7707 * (Note that even in this case, it could still turn out to be a value).
7709 bool definitelyValueParameter(Expression e)
7711 // None of these can be value parameters
7712 if (e.op == EXP.tuple || e.op == EXP.scope_ ||
7713 e.op == EXP.type || e.op == EXP.dotType ||
7714 e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration ||
7715 e.op == EXP.function_ || e.op == EXP.error ||
7716 e.op == EXP.this_ || e.op == EXP.super_ ||
7717 e.op == EXP.dot)
7718 return false;
7720 if (e.op != EXP.dotVariable)
7721 return true;
7723 /* Template instantiations involving a DotVar expression are difficult.
7724 * In most cases, they should be treated as a value parameter, and interpreted.
7725 * But they might also just be a fully qualified name, which should be treated
7726 * as an alias.
7729 // x.y.f cannot be a value
7730 FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration();
7731 if (f)
7732 return false;
7734 while (e.op == EXP.dotVariable)
7736 e = (cast(DotVarExp)e).e1;
7738 // this.x.y and super.x.y couldn't possibly be valid values.
7739 if (e.op == EXP.this_ || e.op == EXP.super_)
7740 return false;
7742 // e.type.x could be an alias
7743 if (e.op == EXP.dotType)
7744 return false;
7746 // var.x.y is the only other possible form of alias
7747 if (e.op != EXP.variable)
7748 return true;
7750 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
7751 // func.x.y is not an alias
7752 if (!v)
7753 return true;
7755 // https://issues.dlang.org/show_bug.cgi?id=16685
7756 // var.x.y where var is a constant available at compile time
7757 if (v.storage_class & STC.manifest)
7758 return true;
7760 // TODO: Should we force CTFE if it is a global constant?
7761 return false;
7764 /***********************************************************
7765 * https://dlang.org/spec/template-mixin.html
7766 * Syntax:
7767 * mixin MixinTemplateName [TemplateArguments] [Identifier];
7769 extern (C++) final class TemplateMixin : TemplateInstance
7771 TypeQualified tqual;
7773 extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
7775 super(loc,
7776 tqual.idents.length ? cast(Identifier)tqual.idents[tqual.idents.length - 1] : (cast(TypeIdentifier)tqual).ident,
7777 tiargs ? tiargs : new Objects());
7778 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
7779 this.ident = ident;
7780 this.tqual = tqual;
7783 override TemplateInstance syntaxCopy(Dsymbol s)
7785 auto tm = new TemplateMixin(loc, ident, tqual.syntaxCopy(), tiargs);
7786 return TemplateInstance.syntaxCopy(tm);
7789 override const(char)* kind() const
7791 return "mixin";
7794 override bool oneMember(Dsymbol* ps, Identifier ident)
7796 return Dsymbol.oneMember(ps, ident);
7799 override bool hasPointers()
7801 //printf("TemplateMixin.hasPointers() %s\n", toChars());
7802 return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
7805 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
7807 //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
7808 if (_scope) // if fwd reference
7809 dsymbolSemantic(this, null); // try to resolve it
7811 members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
7814 override const(char)* toChars() const
7816 OutBuffer buf;
7817 toCBufferInstance(this, &buf);
7818 return buf.extractChars();
7821 extern (D) bool findTempDecl(Scope* sc)
7823 // Follow qualifications to find the TemplateDeclaration
7824 if (!tempdecl)
7826 Expression e;
7827 Type t;
7828 Dsymbol s;
7829 tqual.resolve(loc, sc, e, t, s);
7830 if (!s)
7832 error("is not defined");
7833 return false;
7835 s = s.toAlias();
7836 tempdecl = s.isTemplateDeclaration();
7837 OverloadSet os = s.isOverloadSet();
7839 /* If an OverloadSet, look for a unique member that is a template declaration
7841 if (os)
7843 Dsymbol ds = null;
7844 foreach (i, sym; os.a)
7846 Dsymbol s2 = sym.isTemplateDeclaration();
7847 if (s2)
7849 if (ds)
7851 tempdecl = os;
7852 break;
7854 ds = s2;
7858 if (!tempdecl)
7860 error("- `%s` is a %s, not a template", s.toChars(), s.kind());
7861 return false;
7864 assert(tempdecl);
7866 // Look for forward references
7867 auto tovers = tempdecl.isOverloadSet();
7868 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
7870 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7871 int r = overloadApply(dstart, (Dsymbol s)
7873 auto td = s.isTemplateDeclaration();
7874 if (!td)
7875 return 0;
7877 if (td.semanticRun == PASS.initial)
7879 if (td._scope)
7880 td.dsymbolSemantic(td._scope);
7881 else
7883 semanticRun = PASS.initial;
7884 return 1;
7887 return 0;
7889 if (r)
7890 return false;
7892 return true;
7895 override inout(TemplateMixin) isTemplateMixin() inout
7897 return this;
7900 override void accept(Visitor v)
7902 v.visit(this);
7906 /************************************
7907 * This struct is needed for TemplateInstance to be the key in an associative array.
7908 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
7909 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
7911 struct TemplateInstanceBox
7913 TemplateInstance ti;
7915 this(TemplateInstance ti)
7917 this.ti = ti;
7918 this.ti.toHash();
7919 assert(this.ti.hash);
7922 size_t toHash() const @trusted pure nothrow
7924 assert(ti.hash);
7925 return ti.hash;
7928 bool opEquals(ref const TemplateInstanceBox s) @trusted const
7930 bool res = void;
7931 if (ti.inst && s.ti.inst)
7933 /* This clause is only used when an instance with errors
7934 * is replaced with a correct instance.
7936 res = ti is s.ti;
7938 else
7940 /* Used when a proposed instance is used to see if there's
7941 * an existing instance.
7943 static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
7944 res = (cast()s.ti).equalsx(cast()ti);
7945 else
7946 res = (cast()ti).equalsx(cast()s.ti);
7949 debug (FindExistingInstance) ++(res ? nHits : nCollisions);
7950 return res;
7953 debug (FindExistingInstance)
7955 __gshared uint nHits, nCollisions;
7957 shared static ~this()
7959 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
7960 nHits, nCollisions);
7965 /*******************************************
7966 * Match to a particular TemplateParameter.
7967 * Input:
7968 * instLoc location that the template is instantiated.
7969 * tiargs[] actual arguments to template instance
7970 * i i'th argument
7971 * parameters[] template parameters
7972 * dedtypes[] deduced arguments to template instance
7973 * *psparam set to symbol declared and initialized to dedtypes[i]
7975 MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
7977 MATCH matchArgNoMatch()
7979 if (psparam)
7980 *psparam = null;
7981 return MATCH.nomatch;
7984 MATCH matchArgParameter()
7986 RootObject oarg;
7988 if (i < tiargs.length)
7989 oarg = (*tiargs)[i];
7990 else
7992 // Get default argument instead
7993 oarg = tp.defaultArg(instLoc, sc);
7994 if (!oarg)
7996 assert(i < dedtypes.length);
7997 // It might have already been deduced
7998 oarg = (*dedtypes)[i];
7999 if (!oarg)
8000 return matchArgNoMatch();
8003 return tp.matchArg(sc, oarg, i, parameters, dedtypes, psparam);
8006 MATCH matchArgTuple(TemplateTupleParameter ttp)
8008 /* The rest of the actual arguments (tiargs[]) form the match
8009 * for the variadic parameter.
8011 assert(i + 1 == dedtypes.length); // must be the last one
8012 Tuple ovar;
8014 if (Tuple u = isTuple((*dedtypes)[i]))
8016 // It has already been deduced
8017 ovar = u;
8019 else if (i + 1 == tiargs.length && isTuple((*tiargs)[i]))
8020 ovar = isTuple((*tiargs)[i]);
8021 else
8023 ovar = new Tuple();
8024 //printf("ovar = %p\n", ovar);
8025 if (i < tiargs.length)
8027 //printf("i = %d, tiargs.length = %d\n", i, tiargs.length);
8028 ovar.objects.setDim(tiargs.length - i);
8029 foreach (j, ref obj; ovar.objects)
8030 obj = (*tiargs)[i + j];
8033 return ttp.matchArg(sc, ovar, i, parameters, dedtypes, psparam);
8036 if (auto ttp = tp.isTemplateTupleParameter())
8037 return matchArgTuple(ttp);
8038 else
8039 return matchArgParameter();
8042 MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
8044 MATCH matchArgNoMatch()
8046 //printf("\tm = %d\n", MATCH.nomatch);
8047 if (psparam)
8048 *psparam = null;
8049 return MATCH.nomatch;
8052 MATCH matchArgType(TemplateTypeParameter ttp)
8054 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
8055 MATCH m = MATCH.exact;
8056 Type ta = isType(oarg);
8057 if (!ta)
8059 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
8060 return matchArgNoMatch();
8062 //printf("ta is %s\n", ta.toChars());
8064 if (ttp.specType)
8066 if (!ta || ta == TemplateTypeParameter.tdummy)
8067 return matchArgNoMatch();
8069 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
8070 MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
8071 if (m2 == MATCH.nomatch)
8073 //printf("\tfailed deduceType\n");
8074 return matchArgNoMatch();
8077 if (m2 < m)
8078 m = m2;
8079 if ((*dedtypes)[i])
8081 Type t = cast(Type)(*dedtypes)[i];
8083 if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
8084 return matchArgNoMatch();
8086 /* This is a self-dependent parameter. For example:
8087 * template X(T : T*) {}
8088 * template X(T : S!T, alias S) {}
8090 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8091 ta = t;
8094 else
8096 if ((*dedtypes)[i])
8098 // Must match already deduced type
8099 Type t = cast(Type)(*dedtypes)[i];
8101 if (!t.equals(ta))
8103 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8104 return matchArgNoMatch();
8107 else
8109 // So that matches with specializations are better
8110 m = MATCH.convert;
8113 (*dedtypes)[i] = ta;
8115 if (psparam)
8116 *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
8117 //printf("\tm = %d\n", m);
8118 return ttp.dependent ? MATCH.exact : m;
8121 MATCH matchArgValue(TemplateValueParameter tvp)
8123 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
8124 MATCH m = MATCH.exact;
8126 Expression ei = isExpression(oarg);
8127 Type vt;
8129 if (!ei && oarg)
8131 Dsymbol si = isDsymbol(oarg);
8132 FuncDeclaration f = si ? si.isFuncDeclaration() : null;
8133 if (!f || !f.fbody || f.needThis())
8134 return matchArgNoMatch();
8136 ei = new VarExp(tvp.loc, f);
8137 ei = ei.expressionSemantic(sc);
8139 /* If a function is really property-like, and then
8140 * it's CTFEable, ei will be a literal expression.
8142 uint olderrors = global.startGagging();
8143 ei = resolveProperties(sc, ei);
8144 ei = ei.ctfeInterpret();
8145 if (global.endGagging(olderrors) || ei.op == EXP.error)
8146 return matchArgNoMatch();
8148 /* https://issues.dlang.org/show_bug.cgi?id=14520
8149 * A property-like function can match to both
8150 * TemplateAlias and ValueParameter. But for template overloads,
8151 * it should always prefer alias parameter to be consistent
8152 * template match result.
8154 * template X(alias f) { enum X = 1; }
8155 * template X(int val) { enum X = 2; }
8156 * int f1() { return 0; } // CTFEable
8157 * int f2(); // body-less function is not CTFEable
8158 * enum x1 = X!f1; // should be 1
8159 * enum x2 = X!f2; // should be 1
8161 * e.g. The x1 value must be same even if the f1 definition will be moved
8162 * into di while stripping body code.
8164 m = MATCH.convert;
8167 if (ei && ei.op == EXP.variable)
8169 // Resolve const variables that we had skipped earlier
8170 ei = ei.ctfeInterpret();
8173 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
8174 vt = tvp.valType.typeSemantic(tvp.loc, sc);
8175 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
8176 //printf("vt = %s\n", vt.toChars());
8178 if (ei.type)
8180 MATCH m2 = ei.implicitConvTo(vt);
8181 //printf("m: %d\n", m);
8182 if (m2 < m)
8183 m = m2;
8184 if (m == MATCH.nomatch)
8185 return matchArgNoMatch();
8186 ei = ei.implicitCastTo(sc, vt);
8187 ei = ei.ctfeInterpret();
8190 if (tvp.specValue)
8192 if (ei is null || (cast(void*)ei.type in TemplateValueParameter.edummies &&
8193 TemplateValueParameter.edummies[cast(void*)ei.type] == ei))
8194 return matchArgNoMatch();
8196 Expression e = tvp.specValue;
8198 sc = sc.startCTFE();
8199 e = e.expressionSemantic(sc);
8200 e = resolveProperties(sc, e);
8201 sc = sc.endCTFE();
8202 e = e.implicitCastTo(sc, vt);
8203 e = e.ctfeInterpret();
8205 ei = ei.syntaxCopy();
8206 sc = sc.startCTFE();
8207 ei = ei.expressionSemantic(sc);
8208 sc = sc.endCTFE();
8209 ei = ei.implicitCastTo(sc, vt);
8210 ei = ei.ctfeInterpret();
8211 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
8212 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
8213 if (!ei.equals(e))
8214 return matchArgNoMatch();
8216 else
8218 if ((*dedtypes)[i])
8220 // Must match already deduced value
8221 Expression e = cast(Expression)(*dedtypes)[i];
8222 if (!ei || !ei.equals(e))
8223 return matchArgNoMatch();
8226 (*dedtypes)[i] = ei;
8228 if (psparam)
8230 Initializer _init = new ExpInitializer(tvp.loc, ei);
8231 Declaration sparam = new VarDeclaration(tvp.loc, vt, tvp.ident, _init);
8232 sparam.storage_class = STC.manifest;
8233 *psparam = sparam;
8235 return tvp.dependent ? MATCH.exact : m;
8238 MATCH matchArgAlias(TemplateAliasParameter tap)
8240 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
8241 MATCH m = MATCH.exact;
8242 Type ta = isType(oarg);
8243 RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
8244 Expression ea = isExpression(oarg);
8245 if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
8246 sa = (cast(ThisExp)ea).var;
8247 else if (ea && ea.op == EXP.scope_)
8248 sa = (cast(ScopeExp)ea).sds;
8249 if (sa)
8251 if ((cast(Dsymbol)sa).isAggregateDeclaration())
8252 m = MATCH.convert;
8254 /* specType means the alias must be a declaration with a type
8255 * that matches specType.
8257 if (tap.specType)
8259 Declaration d = (cast(Dsymbol)sa).isDeclaration();
8260 if (!d)
8261 return matchArgNoMatch();
8262 if (!d.type.equals(tap.specType))
8263 return matchArgNoMatch();
8266 else
8268 sa = oarg;
8269 if (ea)
8271 if (tap.specType)
8273 if (!ea.type.equals(tap.specType))
8274 return matchArgNoMatch();
8277 else if (ta && ta.ty == Tinstance && !tap.specAlias)
8279 /* Specialized parameter should be preferred
8280 * match to the template type parameter.
8281 * template X(alias a) {} // a == this
8282 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
8285 else if (sa && sa == TemplateTypeParameter.tdummy)
8287 /* https://issues.dlang.org/show_bug.cgi?id=2025
8288 * Aggregate Types should preferentially
8289 * match to the template type parameter.
8290 * template X(alias a) {} // a == this
8291 * template X(T) {} // T => sa
8294 else if (ta && ta.ty != Tident)
8296 /* Match any type that's not a TypeIdentifier to alias parameters,
8297 * but prefer type parameter.
8298 * template X(alias a) { } // a == ta
8300 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
8302 m = MATCH.convert;
8304 else
8305 return matchArgNoMatch();
8308 if (tap.specAlias)
8310 if (sa == TemplateAliasParameter.sdummy)
8311 return matchArgNoMatch();
8312 // check specialization if template arg is a symbol
8313 Dsymbol sx = isDsymbol(sa);
8314 if (sa != tap.specAlias && sx)
8316 Type talias = isType(tap.specAlias);
8317 if (!talias)
8318 return matchArgNoMatch();
8320 TemplateInstance ti = sx.isTemplateInstance();
8321 if (!ti && sx.parent)
8323 ti = sx.parent.isTemplateInstance();
8324 if (ti && ti.name != sx.ident)
8325 return matchArgNoMatch();
8327 if (!ti)
8328 return matchArgNoMatch();
8330 Type t = new TypeInstance(Loc.initial, ti);
8331 MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
8332 if (m2 == MATCH.nomatch)
8333 return matchArgNoMatch();
8335 // check specialization if template arg is a type
8336 else if (ta)
8338 if (Type tspec = isType(tap.specAlias))
8340 MATCH m2 = ta.implicitConvTo(tspec);
8341 if (m2 == MATCH.nomatch)
8342 return matchArgNoMatch();
8344 else
8346 error(tap.loc, "template parameter specialization for a type must be a type and not `%s`",
8347 tap.specAlias.toChars());
8348 return matchArgNoMatch();
8352 else if ((*dedtypes)[i])
8354 // Must match already deduced symbol
8355 RootObject si = (*dedtypes)[i];
8356 if (!sa || si != sa)
8357 return matchArgNoMatch();
8359 (*dedtypes)[i] = sa;
8361 if (psparam)
8363 if (Dsymbol s = isDsymbol(sa))
8365 *psparam = new AliasDeclaration(tap.loc, tap.ident, s);
8367 else if (Type t = isType(sa))
8369 *psparam = new AliasDeclaration(tap.loc, tap.ident, t);
8371 else
8373 assert(ea);
8375 // Declare manifest constant
8376 Initializer _init = new ExpInitializer(tap.loc, ea);
8377 auto v = new VarDeclaration(tap.loc, null, tap.ident, _init);
8378 v.storage_class = STC.manifest;
8379 v.dsymbolSemantic(sc);
8380 *psparam = v;
8383 return tap.dependent ? MATCH.exact : m;
8386 MATCH matchArgTuple(TemplateTupleParameter ttp)
8388 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
8389 Tuple ovar = isTuple(oarg);
8390 if (!ovar)
8391 return MATCH.nomatch;
8392 if ((*dedtypes)[i])
8394 Tuple tup = isTuple((*dedtypes)[i]);
8395 if (!tup)
8396 return MATCH.nomatch;
8397 if (!match(tup, ovar))
8398 return MATCH.nomatch;
8400 (*dedtypes)[i] = ovar;
8402 if (psparam)
8403 *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
8404 return ttp.dependent ? MATCH.exact : MATCH.convert;
8407 if (auto ttp = tp.isTemplateTypeParameter())
8408 return matchArgType(ttp);
8409 else if (auto tvp = tp.isTemplateValueParameter())
8410 return matchArgValue(tvp);
8411 else if (auto tap = tp.isTemplateAliasParameter())
8412 return matchArgAlias(tap);
8413 else if (auto ttp = tp.isTemplateTupleParameter())
8414 return matchArgTuple(ttp);
8415 else
8416 assert(0);
8420 /***********************************************
8421 * Collect and print statistics on template instantiations.
8423 struct TemplateStats
8425 __gshared TemplateStats[const void*] stats;
8427 uint numInstantiations; // number of instantiations of the template
8428 uint uniqueInstantiations; // number of unique instantiations of the template
8430 TemplateInstances* allInstances;
8432 /*******************************
8433 * Add this instance
8435 static void incInstance(const TemplateDeclaration td,
8436 const TemplateInstance ti)
8438 void log(ref TemplateStats ts)
8440 if (ts.allInstances is null)
8441 ts.allInstances = new TemplateInstances();
8442 if (global.params.vtemplatesListInstances)
8443 ts.allInstances.push(cast() ti);
8446 // message(ti.loc, "incInstance %p %p", td, ti);
8447 if (!global.params.vtemplates)
8448 return;
8449 if (!td)
8450 return;
8451 assert(ti);
8452 if (auto ts = cast(const void*) td in stats)
8454 log(*ts);
8455 ++ts.numInstantiations;
8457 else
8459 stats[cast(const void*) td] = TemplateStats(1, 0);
8460 log(stats[cast(const void*) td]);
8464 /*******************************
8465 * Add this unique instance
8467 static void incUnique(const TemplateDeclaration td,
8468 const TemplateInstance ti)
8470 // message(ti.loc, "incUnique %p %p", td, ti);
8471 if (!global.params.vtemplates)
8472 return;
8473 if (!td)
8474 return;
8475 assert(ti);
8476 if (auto ts = cast(const void*) td in stats)
8477 ++ts.uniqueInstantiations;
8478 else
8479 stats[cast(const void*) td] = TemplateStats(0, 1);
8483 extern (C++) void printTemplateStats()
8485 static struct TemplateDeclarationStats
8487 TemplateDeclaration td;
8488 TemplateStats ts;
8489 static int compare(scope const TemplateDeclarationStats* a,
8490 scope const TemplateDeclarationStats* b) @safe nothrow @nogc pure
8492 auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations;
8493 if (diff)
8494 return diff;
8495 else
8496 return b.ts.numInstantiations - a.ts.numInstantiations;
8500 if (!global.params.vtemplates)
8501 return;
8503 Array!(TemplateDeclarationStats) sortedStats;
8504 sortedStats.reserve(TemplateStats.stats.length);
8505 foreach (td_, ref ts; TemplateStats.stats)
8507 sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
8510 sortedStats.sort!(TemplateDeclarationStats.compare);
8512 foreach (const ref ss; sortedStats[])
8514 if (global.params.vtemplatesListInstances &&
8515 ss.ts.allInstances)
8517 message(ss.td.loc,
8518 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
8519 ss.ts.numInstantiations,
8520 ss.ts.uniqueInstantiations,
8521 ss.td.toCharsNoConstraints());
8522 foreach (const ti; (*ss.ts.allInstances)[])
8524 if (ti.tinst) // if has enclosing instance
8525 message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
8526 else
8527 message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
8530 else
8532 message(ss.td.loc,
8533 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
8534 ss.ts.numInstantiations,
8535 ss.ts.uniqueInstantiations,
8536 ss.td.toCharsNoConstraints());
8541 /// Pair of MATCHes
8542 private struct MATCHpair
8544 MATCH mta; /// match template parameters by initial template arguments
8545 MATCH mfa; /// match template parameters by inferred template arguments
8547 debug this(MATCH mta, MATCH mfa)
8549 assert(MATCH.min <= mta && mta <= MATCH.max);
8550 assert(MATCH.min <= mfa && mfa <= MATCH.max);
8551 this.mta = mta;
8552 this.mfa = mfa;
8556 private void write(ref OutBuffer buf, RootObject obj)
8558 if (obj)
8560 buf.writestring(obj.toChars());