d: Merge upstream dmd, druntime 4c18eed967, phobos d945686a4.
[official-gcc.git] / gcc / d / dmd / dtemplate.d
blob23d1140fe3815feff6e1fa4efc202f73b5d0ba2e
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 @safe
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 OutBuffer buf;
745 HdrGenState hgs;
747 buf.writestring(ident.toString());
748 buf.writeByte('(');
749 foreach (i, const tp; *parameters)
751 if (i)
752 buf.writestring(", ");
753 toCBuffer(tp, buf, hgs);
755 buf.writeByte(')');
757 if (onemember)
759 const FuncDeclaration fd = onemember.isFuncDeclaration();
760 if (fd && fd.type)
762 TypeFunction tf = cast(TypeFunction)fd.type;
763 buf.writestring(parametersTypeToChars(tf.parameterList));
767 if (includeConstraints &&
768 constraint)
770 buf.writestring(" if (");
771 toCBuffer(constraint, buf, hgs);
772 buf.writeByte(')');
775 return buf.extractChars();
778 override Visibility visible() pure nothrow @nogc @safe
780 return visibility;
783 /****************************
784 * Check to see if constraint is satisfied.
786 extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
788 /* Detect recursive attempts to instantiate this template declaration,
789 * https://issues.dlang.org/show_bug.cgi?id=4072
790 * void foo(T)(T x) if (is(typeof(foo(x)))) { }
791 * static assert(!is(typeof(foo(7))));
792 * Recursive attempts are regarded as a constraint failure.
794 /* There's a chicken-and-egg problem here. We don't know yet if this template
795 * instantiation will be a local one (enclosing is set), and we won't know until
796 * after selecting the correct template. Thus, function we're nesting inside
797 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
798 * Workaround the problem by setting a flag to relax the checking on frame errors.
801 for (TemplatePrevious* p = previous; p; p = p.prev)
803 if (!arrayObjectMatch(p.dedargs, dedargs))
804 continue;
805 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
806 /* It must be a subscope of p.sc, other scope chains are not recursive
807 * instantiations.
808 * the chain of enclosing scopes is broken by paramscope (its enclosing
809 * scope is _scope, but paramscope.callsc is the instantiating scope). So
810 * it's good enough to check the chain of callsc
812 for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
814 // The first scx might be identical for nested eponymeous templates, e.g.
815 // template foo() { void foo()() {...} }
816 if (scx == p.sc && scx !is paramscope.callsc)
817 return false;
819 /* BUG: should also check for ref param differences
823 TemplatePrevious pr;
824 pr.prev = previous;
825 pr.sc = paramscope.callsc;
826 pr.dedargs = dedargs;
827 previous = &pr; // add this to threaded list
829 Scope* scx = paramscope.push(ti);
830 scx.parent = ti;
831 scx.tinst = null;
832 scx.minst = null;
833 // Set SCOPE.constraint before declaring function parameters for the static condition
834 // (previously, this was immediately before calling evalStaticCondition), so the
835 // semantic pass knows not to issue deprecation warnings for these throw-away decls.
836 // https://issues.dlang.org/show_bug.cgi?id=21831
837 scx.flags |= SCOPE.constraint;
839 assert(!ti.symtab);
840 if (fd)
842 /* Declare all the function parameters as variables and add them to the scope
843 * Making parameters is similar to FuncDeclaration.semantic3
845 auto tf = fd.type.isTypeFunction();
847 scx.parent = fd;
849 Parameters* fparameters = tf.parameterList.parameters;
850 const nfparams = tf.parameterList.length;
851 foreach (i, fparam; tf.parameterList)
853 fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
854 fparam.storageClass |= STC.parameter;
855 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams)
857 fparam.storageClass |= STC.variadic;
858 /* Don't need to set STC.scope_ because this will only
859 * be evaluated at compile time
863 foreach (fparam; *fparameters)
865 if (!fparam.ident)
866 continue;
867 // don't add it, if it has no name
868 auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null);
869 fparam.storageClass |= STC.parameter;
870 v.storage_class = fparam.storageClass;
871 v.dsymbolSemantic(scx);
872 if (!ti.symtab)
873 ti.symtab = new DsymbolTable();
874 if (!scx.insert(v))
875 .error(loc, "%s `%s` parameter `%s.%s` is already defined", kind, toPrettyChars, toChars(), v.toChars());
876 else
877 v.parent = fd;
879 if (isstatic)
880 fd.storage_class |= STC.static_;
881 fd.declareThis(scx);
884 lastConstraint = constraint.syntaxCopy();
885 lastConstraintTiargs = ti.tiargs;
886 lastConstraintNegs.setDim(0);
888 import dmd.staticcond;
890 assert(ti.inst is null);
891 ti.inst = ti; // temporary instantiation to enable genIdent()
892 bool errors;
893 const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs);
894 if (result || errors)
896 lastConstraint = null;
897 lastConstraintTiargs = null;
898 lastConstraintNegs.setDim(0);
900 ti.inst = null;
901 ti.symtab = null;
902 scx = scx.pop();
903 previous = pr.prev; // unlink from threaded list
904 if (errors)
905 return false;
906 return result;
909 /****************************
910 * Destructively get the error message from the last constraint evaluation
911 * Params:
912 * tip = tip to show after printing all overloads
914 const(char)* getConstraintEvalError(ref const(char)* tip)
916 import dmd.staticcond;
918 // there will be a full tree view in verbose mode, and more compact list in the usual
919 const full = global.params.v.verbose;
920 uint count;
921 const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count);
922 scope (exit)
924 lastConstraint = null;
925 lastConstraintTiargs = null;
926 lastConstraintNegs.setDim(0);
928 if (!msg)
929 return null;
931 OutBuffer buf;
933 assert(parameters && lastConstraintTiargs);
934 if (parameters.length > 0)
936 formatParamsWithTiargs(*lastConstraintTiargs, buf);
937 buf.writenl();
939 if (!full)
941 // choosing singular/plural
942 const s = (count == 1) ?
943 " must satisfy the following constraint:" :
944 " must satisfy one of the following constraints:";
945 buf.writestring(s);
946 buf.writenl();
947 // the constraints
948 buf.writeByte('`');
949 buf.writestring(msg);
950 buf.writeByte('`');
952 else
954 buf.writestring(" whose parameters have the following constraints:");
955 buf.writenl();
956 const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
957 buf.writestring(sep);
958 buf.writenl();
959 // the constraints
960 buf.writeByte('`');
961 buf.writestring(msg);
962 buf.writeByte('`');
963 buf.writestring(sep);
964 tip = "not satisfied constraints are marked with `>`";
966 return buf.extractChars();
969 private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf)
971 buf.writestring(" with `");
973 // write usual arguments line-by-line
974 // skips trailing default ones - they are not present in `tiargs`
975 const bool variadic = isVariadic() !is null;
976 const end = cast(int)parameters.length - (variadic ? 1 : 0);
977 uint i;
978 for (; i < tiargs.length && i < end; i++)
980 if (i > 0)
982 buf.writeByte(',');
983 buf.writenl();
984 buf.writestring(" ");
986 write(buf, (*parameters)[i]);
987 buf.writestring(" = ");
988 write(buf, tiargs[i]);
990 // write remaining variadic arguments on the last line
991 if (variadic)
993 if (i > 0)
995 buf.writeByte(',');
996 buf.writenl();
997 buf.writestring(" ");
999 write(buf, (*parameters)[end]);
1000 buf.writestring(" = ");
1001 buf.writeByte('(');
1002 if (cast(int)tiargs.length - end > 0)
1004 write(buf, tiargs[end]);
1005 foreach (j; parameters.length .. tiargs.length)
1007 buf.writestring(", ");
1008 write(buf, tiargs[j]);
1011 buf.writeByte(')');
1013 buf.writeByte('`');
1016 /******************************
1017 * Create a scope for the parameters of the TemplateInstance
1018 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
1020 * If paramsym is null a new ScopeDsymbol is used in place of
1021 * paramsym.
1022 * Params:
1023 * ti = the TemplateInstance whose parameters to generate the scope for.
1024 * sc = the parent scope of ti
1025 * Returns:
1026 * a scope for the parameters of ti
1028 Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc)
1030 ScopeDsymbol paramsym = new ScopeDsymbol();
1031 paramsym.parent = _scope.parent;
1032 Scope* paramscope = _scope.push(paramsym);
1033 paramscope.tinst = ti;
1034 paramscope.minst = sc.minst;
1035 paramscope.callsc = sc;
1036 paramscope.stc = 0;
1037 return paramscope;
1040 /***************************************
1041 * Given that ti is an instance of this TemplateDeclaration,
1042 * deduce the types of the parameters to this, and store
1043 * those deduced types in dedtypes[].
1044 * Input:
1045 * flag 1: don't do semantic() because of dummy types
1046 * 2: don't change types in matchArg()
1047 * Output:
1048 * dedtypes deduced arguments
1049 * Return match level.
1051 extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag)
1053 enum LOGM = 0;
1054 static if (LOGM)
1056 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag);
1058 version (none)
1060 printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length);
1061 if (ti.tiargs.length)
1062 printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]);
1064 MATCH nomatch()
1066 static if (LOGM)
1068 printf(" no match\n");
1070 return MATCH.nomatch;
1072 MATCH m;
1073 size_t dedtypes_dim = dedtypes.length;
1075 dedtypes.zero();
1077 if (errors)
1078 return MATCH.nomatch;
1080 size_t parameters_dim = parameters.length;
1081 int variadic = isVariadic() !is null;
1083 // If more arguments than parameters, no match
1084 if (ti.tiargs.length > parameters_dim && !variadic)
1086 static if (LOGM)
1088 printf(" no match: more arguments than parameters\n");
1090 return MATCH.nomatch;
1093 assert(dedtypes_dim == parameters_dim);
1094 assert(dedtypes_dim >= ti.tiargs.length || variadic);
1096 assert(_scope);
1098 // Set up scope for template parameters
1099 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1101 // Attempt type deduction
1102 m = MATCH.exact;
1103 for (size_t i = 0; i < dedtypes_dim; i++)
1105 MATCH m2;
1106 TemplateParameter tp = (*parameters)[i];
1107 Declaration sparam;
1109 //printf("\targument [%d]\n", i);
1110 static if (LOGM)
1112 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
1113 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
1114 if (ttp)
1115 printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
1118 m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam);
1119 //printf("\tm2 = %d\n", m2);
1120 if (m2 == MATCH.nomatch)
1122 version (none)
1124 printf("\tmatchArg() for parameter %i failed\n", i);
1126 return nomatch();
1129 if (m2 < m)
1130 m = m2;
1132 if (!flag)
1133 sparam.dsymbolSemantic(paramscope);
1134 if (!paramscope.insert(sparam)) // TODO: This check can make more early
1136 // in TemplateDeclaration.semantic, and
1137 // then we don't need to make sparam if flags == 0
1138 return nomatch();
1142 if (!flag)
1144 /* Any parameter left without a type gets the type of
1145 * its corresponding arg
1147 foreach (i, ref dedtype; *dedtypes)
1149 if (!dedtype)
1151 assert(i < ti.tiargs.length);
1152 dedtype = cast(Type)(*ti.tiargs)[i];
1157 if (m > MATCH.nomatch && constraint && !flag)
1159 if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error
1160 ti.parent = ti.enclosing;
1161 else
1162 ti.parent = this.parent;
1164 // Similar to doHeaderInstantiation
1165 FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null;
1166 if (fd)
1168 TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
1169 if (argumentList.hasNames)
1170 return nomatch();
1171 Expressions* fargs = argumentList.arguments;
1172 // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
1173 // if (!fargs)
1174 // return nomatch();
1176 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
1177 fd.parent = ti;
1178 fd.inferRetType = true;
1180 // Shouldn't run semantic on default arguments and return type.
1181 foreach (ref param; *tf.parameterList.parameters)
1182 param.defaultArg = null;
1184 tf.next = null;
1185 tf.incomplete = true;
1187 // Resolve parameter types and 'auto ref's.
1188 tf.fargs = fargs;
1189 uint olderrors = global.startGagging();
1190 fd.type = tf.typeSemantic(loc, paramscope);
1191 global.endGagging(olderrors);
1192 if (fd.type.ty != Tfunction)
1193 return nomatch();
1194 fd.originalType = fd.type; // for mangling
1197 // TODO: dedtypes => ti.tiargs ?
1198 if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
1199 return nomatch();
1202 static if (LOGM)
1204 // Print out the results
1205 printf("--------------------------\n");
1206 printf("template %s\n", toChars());
1207 printf("instance %s\n", ti.toChars());
1208 if (m > MATCH.nomatch)
1210 for (size_t i = 0; i < dedtypes_dim; i++)
1212 TemplateParameter tp = (*parameters)[i];
1213 RootObject oarg;
1214 printf(" [%d]", i);
1215 if (i < ti.tiargs.length)
1216 oarg = (*ti.tiargs)[i];
1217 else
1218 oarg = null;
1219 tp.print(oarg, (*dedtypes)[i]);
1222 else
1223 return nomatch();
1225 static if (LOGM)
1227 printf(" match = %d\n", m);
1230 paramscope.pop();
1231 static if (LOGM)
1233 printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m);
1235 return m;
1238 /********************************************
1239 * Determine partial specialization order of 'this' vs td2.
1240 * Returns:
1241 * match this is at least as specialized as td2
1242 * 0 td2 is more specialized than this
1244 MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList)
1246 enum LOG_LEASTAS = 0;
1247 static if (LOG_LEASTAS)
1249 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
1252 /* This works by taking the template parameters to this template
1253 * declaration and feeding them to td2 as if it were a template
1254 * instance.
1255 * If it works, then this template is at least as specialized
1256 * as td2.
1259 // Set type arguments to dummy template instance to be types
1260 // generated from the parameters to this template declaration
1261 auto tiargs = new Objects();
1262 tiargs.reserve(parameters.length);
1263 foreach (tp; *parameters)
1265 if (tp.dependent)
1266 break;
1267 RootObject p = tp.dummyArg();
1268 if (!p) //TemplateTupleParameter
1269 break;
1271 tiargs.push(p);
1273 scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance
1275 // Temporary Array to hold deduced types
1276 Objects dedtypes = Objects(td2.parameters.length);
1278 // Attempt a type deduction
1279 MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1);
1280 if (m > MATCH.nomatch)
1282 /* A non-variadic template is more specialized than a
1283 * variadic one.
1285 TemplateTupleParameter tp = isVariadic();
1286 if (tp && !tp.dependent && !td2.isVariadic())
1287 goto L1;
1289 static if (LOG_LEASTAS)
1291 printf(" matches %d, so is least as specialized\n", m);
1293 return m;
1296 static if (LOG_LEASTAS)
1298 printf(" doesn't match, so is not as specialized\n");
1300 return MATCH.nomatch;
1303 /*************************************************
1304 * Match function arguments against a specific template function.
1306 * Params:
1307 * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments
1308 * sc = instantiation scope
1309 * fd = Partially instantiated function declaration, which is set to an instantiated function declaration
1310 * tthis = 'this' argument if !NULL
1311 * argumentList = arguments to function
1313 * Returns:
1314 * match pair of initial and inferred template arguments
1316 extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList)
1318 version (none)
1320 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
1321 for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
1323 Expression e = (*fargs)[i];
1324 printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars());
1326 printf("fd = %s\n", fd.toChars());
1327 printf("fd.type = %s\n", fd.type.toChars());
1328 if (tthis)
1329 printf("tthis = %s\n", tthis.toChars());
1332 assert(_scope);
1334 auto dedargs = new Objects(parameters.length);
1335 dedargs.zero();
1337 Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
1338 dedtypes.setDim(parameters.length);
1339 dedtypes.zero();
1341 if (errors || fd.errors)
1342 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1344 // Set up scope for parameters
1345 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1347 MATCHpair nomatch()
1349 paramscope.pop();
1350 //printf("\tnomatch\n");
1351 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1354 MATCHpair matcherror()
1356 // todo: for the future improvement
1357 paramscope.pop();
1358 //printf("\terror\n");
1359 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1361 // Mark the parameter scope as deprecated if the templated
1362 // function is deprecated (since paramscope.enclosing is the
1363 // calling scope already)
1364 paramscope.stc |= fd.storage_class & STC.deprecated_;
1366 TemplateTupleParameter tp = isVariadic();
1367 Tuple declaredTuple = null;
1369 version (none)
1371 for (size_t i = 0; i < dedargs.length; i++)
1373 printf("\tdedarg[%d] = ", i);
1374 RootObject oarg = (*dedargs)[i];
1375 if (oarg)
1376 printf("%s", oarg.toChars());
1377 printf("\n");
1381 size_t ntargs = 0; // array size of tiargs
1382 size_t inferStart = 0; // index of first parameter to infer
1383 const Loc instLoc = ti.loc;
1384 MATCH matchTiargs = MATCH.exact;
1386 if (auto tiargs = ti.tiargs)
1388 // Set initial template arguments
1389 ntargs = tiargs.length;
1390 size_t n = parameters.length;
1391 if (tp)
1392 n--;
1393 if (ntargs > n)
1395 if (!tp)
1396 return nomatch();
1398 /* The extra initial template arguments
1399 * now form the tuple argument.
1401 auto t = new Tuple(ntargs - n);
1402 assert(parameters.length);
1403 (*dedargs)[parameters.length - 1] = t;
1405 for (size_t i = 0; i < t.objects.length; i++)
1407 t.objects[i] = (*tiargs)[n + i];
1409 declareParameter(paramscope, tp, t);
1410 declaredTuple = t;
1412 else
1413 n = ntargs;
1415 memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
1417 for (size_t i = 0; i < n; i++)
1419 assert(i < parameters.length);
1420 Declaration sparam = null;
1421 MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
1422 //printf("\tdeduceType m = %d\n", m);
1423 if (m == MATCH.nomatch)
1424 return nomatch();
1425 if (m < matchTiargs)
1426 matchTiargs = m;
1428 sparam.dsymbolSemantic(paramscope);
1429 if (!paramscope.insert(sparam))
1430 return nomatch();
1432 if (n < parameters.length && !declaredTuple)
1434 inferStart = n;
1436 else
1437 inferStart = parameters.length;
1438 //printf("tiargs matchTiargs = %d\n", matchTiargs);
1440 version (none)
1442 for (size_t i = 0; i < dedargs.length; i++)
1444 printf("\tdedarg[%d] = ", i);
1445 RootObject oarg = (*dedargs)[i];
1446 if (oarg)
1447 printf("%s", oarg.toChars());
1448 printf("\n");
1452 ParameterList fparameters = fd.getParameterList(); // function parameter list
1453 const nfparams = fparameters.length; // number of function parameters
1454 const nfargs = argumentList.length; // number of function arguments
1455 if (argumentList.hasNames)
1456 return matcherror(); // TODO: resolve named args
1457 Expressions* fargs = argumentList.arguments; // TODO: resolve named args
1459 /* Check for match of function arguments with variadic template
1460 * parameter, such as:
1462 * void foo(T, A...)(T t, A a);
1463 * void main() { foo(1,2,3); }
1465 size_t fptupindex = IDX_NOTFOUND;
1466 if (tp) // if variadic
1468 // TemplateTupleParameter always makes most lesser matching.
1469 matchTiargs = MATCH.convert;
1471 if (nfparams == 0 && nfargs != 0) // if no function parameters
1473 if (!declaredTuple)
1475 auto t = new Tuple();
1476 //printf("t = %p\n", t);
1477 (*dedargs)[parameters.length - 1] = t;
1478 declareParameter(paramscope, tp, t);
1479 declaredTuple = t;
1482 else
1484 /* Figure out which of the function parameters matches
1485 * the tuple template parameter. Do this by matching
1486 * type identifiers.
1487 * Set the index of this function parameter to fptupindex.
1489 for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
1491 auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
1492 if (fparam.type.ty != Tident)
1493 continue;
1494 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
1495 if (!tp.ident.equals(tid.ident) || tid.idents.length)
1496 continue;
1498 if (fparameters.varargs != VarArg.none) // variadic function doesn't
1499 return nomatch(); // go with variadic template
1501 goto L1;
1503 fptupindex = IDX_NOTFOUND;
1508 MATCH match = MATCH.exact;
1509 if (toParent().isModule())
1510 tthis = null;
1511 if (tthis)
1513 bool hasttp = false;
1515 // Match 'tthis' to any TemplateThisParameter's
1516 foreach (param; *parameters)
1518 if (auto ttp = param.isTemplateThisParameter())
1520 hasttp = true;
1522 Type t = new TypeIdentifier(Loc.initial, ttp.ident);
1523 MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
1524 if (m == MATCH.nomatch)
1525 return nomatch();
1526 if (m < match)
1527 match = m; // pick worst match
1531 // Match attributes of tthis against attributes of fd
1532 if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_))
1534 StorageClass stc = _scope.stc | fd.storage_class2;
1535 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
1536 Dsymbol p = parent;
1537 while (p.isTemplateDeclaration() || p.isTemplateInstance())
1538 p = p.parent;
1539 AggregateDeclaration ad = p.isAggregateDeclaration();
1540 if (ad)
1541 stc |= ad.storage_class;
1543 ubyte mod = fd.type.mod;
1544 if (stc & STC.immutable_)
1545 mod = MODFlags.immutable_;
1546 else
1548 if (stc & (STC.shared_ | STC.synchronized_))
1549 mod |= MODFlags.shared_;
1550 if (stc & STC.const_)
1551 mod |= MODFlags.const_;
1552 if (stc & STC.wild)
1553 mod |= MODFlags.wild;
1556 ubyte thismod = tthis.mod;
1557 if (hasttp)
1558 mod = MODmerge(thismod, mod);
1559 MATCH m = MODmethodConv(thismod, mod);
1560 if (m == MATCH.nomatch)
1561 return nomatch();
1562 if (m < match)
1563 match = m;
1567 // Loop through the function parameters
1569 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
1570 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
1571 size_t argi = 0;
1572 size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
1573 uint inoutMatch = 0; // for debugging only
1574 for (size_t parami = 0; parami < nfparams; parami++)
1576 Parameter fparam = fparameters[parami];
1578 // Apply function parameter storage classes to parameter types
1579 Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
1581 Expression farg;
1583 /* See function parameters which wound up
1584 * as part of a template tuple parameter.
1586 if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
1588 assert(prmtype.ty == Tident);
1589 TypeIdentifier tid = cast(TypeIdentifier)prmtype;
1590 if (!declaredTuple)
1592 /* The types of the function arguments
1593 * now form the tuple argument.
1595 declaredTuple = new Tuple();
1596 (*dedargs)[parameters.length - 1] = declaredTuple;
1598 /* Count function parameters with no defaults following a tuple parameter.
1599 * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
1601 size_t rem = 0;
1602 for (size_t j = parami + 1; j < nfparams; j++)
1604 Parameter p = fparameters[j];
1605 if (p.defaultArg)
1607 break;
1609 if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length]))
1611 Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
1612 rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1;
1614 else
1616 ++rem;
1620 if (nfargs2 - argi < rem)
1621 return nomatch();
1622 declaredTuple.objects.setDim(nfargs2 - argi - rem);
1623 for (size_t i = 0; i < declaredTuple.objects.length; i++)
1625 farg = (*fargs)[argi + i];
1627 // Check invalid arguments to detect errors early.
1628 if (farg.op == EXP.error || farg.type.ty == Terror)
1629 return nomatch();
1631 if (!fparam.isLazy() && farg.type.ty == Tvoid)
1632 return nomatch();
1634 Type tt;
1635 MATCH m;
1636 if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
1638 inoutMatch |= wm;
1639 m = MATCH.constant;
1641 else
1643 m = deduceTypeHelper(farg.type, &tt, tid);
1645 if (m == MATCH.nomatch)
1646 return nomatch();
1647 if (m < match)
1648 match = m;
1650 /* Remove top const for dynamic array types and pointer types
1652 if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
1654 tt = tt.mutableOf();
1656 declaredTuple.objects[i] = tt;
1658 declareParameter(paramscope, tp, declaredTuple);
1660 else
1662 // https://issues.dlang.org/show_bug.cgi?id=6810
1663 // If declared tuple is not a type tuple,
1664 // it cannot be function parameter types.
1665 for (size_t i = 0; i < declaredTuple.objects.length; i++)
1667 if (!isType(declaredTuple.objects[i]))
1668 return nomatch();
1671 assert(declaredTuple);
1672 argi += declaredTuple.objects.length;
1673 continue;
1676 // If parameter type doesn't depend on inferred template parameters,
1677 // semantic it to get actual type.
1678 if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.length]))
1680 // should copy prmtype to avoid affecting semantic result
1681 prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
1683 if (prmtype.ty == Ttuple)
1685 TypeTuple tt = cast(TypeTuple)prmtype;
1686 size_t tt_dim = tt.arguments.length;
1687 for (size_t j = 0; j < tt_dim; j++, ++argi)
1689 Parameter p = (*tt.arguments)[j];
1690 if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
1691 parami + 1 == nfparams && argi < nfargs)
1693 prmtype = p.type;
1694 goto Lvarargs;
1696 if (argi >= nfargs)
1698 if (p.defaultArg)
1699 continue;
1701 // https://issues.dlang.org/show_bug.cgi?id=19888
1702 if (fparam.defaultArg)
1703 break;
1705 return nomatch();
1707 farg = (*fargs)[argi];
1708 if (!farg.implicitConvTo(p.type))
1709 return nomatch();
1711 continue;
1715 if (argi >= nfargs) // if not enough arguments
1717 if (!fparam.defaultArg)
1718 goto Lvarargs;
1720 /* https://issues.dlang.org/show_bug.cgi?id=2803
1721 * Before the starting of type deduction from the function
1722 * default arguments, set the already deduced parameters into paramscope.
1723 * It's necessary to avoid breaking existing acceptable code. Cases:
1725 * 1. Already deduced template parameters can appear in fparam.defaultArg:
1726 * auto foo(A, B)(A a, B b = A.stringof);
1727 * foo(1);
1728 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
1730 * 2. If prmtype depends on default-specified template parameter, the
1731 * default type should be preferred.
1732 * auto foo(N = size_t, R)(R r, N start = 0)
1733 * foo([1,2,3]);
1734 * // at fparam `N start = 0`, N should be 'size_t' before
1735 * // the deduction result from fparam.defaultArg.
1737 if (argi == nfargs)
1739 foreach (ref dedtype; *dedtypes)
1741 Type at = isType(dedtype);
1742 if (at && at.ty == Tnone)
1744 TypeDeduced xt = cast(TypeDeduced)at;
1745 dedtype = xt.tded; // 'unbox'
1748 for (size_t i = ntargs; i < dedargs.length; i++)
1750 TemplateParameter tparam = (*parameters)[i];
1752 RootObject oarg = (*dedargs)[i];
1753 RootObject oded = (*dedtypes)[i];
1754 if (oarg)
1755 continue;
1757 if (oded)
1759 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
1761 /* The specialization can work as long as afterwards
1762 * the oded == oarg
1764 (*dedargs)[i] = oded;
1765 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
1766 //printf("m2 = %d\n", m2);
1767 if (m2 == MATCH.nomatch)
1768 return nomatch();
1769 if (m2 < matchTiargs)
1770 matchTiargs = m2; // pick worst match
1771 if (!(*dedtypes)[i].equals(oded))
1772 .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, kind, toPrettyChars, tparam.ident.toChars());
1774 else
1776 if (MATCH.convert < matchTiargs)
1777 matchTiargs = MATCH.convert;
1779 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1781 else
1783 oded = tparam.defaultArg(instLoc, paramscope);
1784 if (oded)
1785 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1789 nfargs2 = argi + 1;
1791 /* If prmtype does not depend on any template parameters:
1793 * auto foo(T)(T v, double x = 0);
1794 * foo("str");
1795 * // at fparam == 'double x = 0'
1797 * or, if all template parameters in the prmtype are already deduced:
1799 * auto foo(R)(R range, ElementType!R sum = 0);
1800 * foo([1,2,3]);
1801 * // at fparam == 'ElementType!R sum = 0'
1803 * Deducing prmtype from fparam.defaultArg is not necessary.
1805 if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope))
1807 ++argi;
1808 continue;
1811 // Deduce prmtype from the defaultArg.
1812 farg = fparam.defaultArg.syntaxCopy();
1813 farg = farg.expressionSemantic(paramscope);
1814 farg = resolveProperties(paramscope, farg);
1816 else
1818 farg = (*fargs)[argi];
1821 // Check invalid arguments to detect errors early.
1822 if (farg.op == EXP.error || farg.type.ty == Terror)
1823 return nomatch();
1825 Type att = null;
1826 Lretry:
1827 version (none)
1829 printf("\tfarg.type = %s\n", farg.type.toChars());
1830 printf("\tfparam.type = %s\n", prmtype.toChars());
1832 Type argtype = farg.type;
1834 if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_)
1835 return nomatch();
1837 // https://issues.dlang.org/show_bug.cgi?id=12876
1838 // Optimize argument to allow CT-known length matching
1839 farg = farg.optimize(WANTvalue, fparam.isReference());
1840 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
1842 RootObject oarg = farg;
1843 if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
1845 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
1847 Type taai;
1848 if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
1850 if (StringExp se = farg.isStringExp())
1852 argtype = se.type.nextOf().sarrayOf(se.len);
1854 else if (ArrayLiteralExp ae = farg.isArrayLiteralExp())
1856 argtype = ae.type.nextOf().sarrayOf(ae.elements.length);
1858 else if (SliceExp se = farg.isSliceExp())
1860 if (Type tsa = toStaticArrayType(se))
1861 argtype = tsa;
1865 oarg = argtype;
1867 else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0)
1869 /* The farg passing to the prmtype always make a copy. Therefore,
1870 * we can shrink the set of the deduced type arguments for prmtype
1871 * by adjusting top-qualifier of the argtype.
1873 * prmtype argtype ta
1874 * T <- const(E)[] const(E)[]
1875 * T <- const(E[]) const(E)[]
1876 * qualifier(T) <- const(E)[] const(E[])
1877 * qualifier(T) <- const(E[]) const(E[])
1879 Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
1880 if (ta != argtype)
1882 Expression ea = farg.copy();
1883 ea.type = ta;
1884 oarg = ea;
1888 if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
1889 goto Lvarargs;
1891 uint im = 0;
1892 MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart);
1893 //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
1894 inoutMatch |= im;
1896 /* If no match, see if the argument can be matched by using
1897 * implicit conversions.
1899 if (m == MATCH.nomatch && prmtype.deco)
1900 m = farg.implicitConvTo(prmtype);
1902 if (m == MATCH.nomatch)
1904 AggregateDeclaration ad = isAggregate(farg.type);
1905 if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
1907 // https://issues.dlang.org/show_bug.cgi?id=12537
1908 // The isRecursiveAliasThis() call above
1910 /* If a semantic error occurs while doing alias this,
1911 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
1912 * just regard it as not a match.
1914 * We also save/restore sc.func.flags to avoid messing up
1915 * attribute inference in the evaluation.
1917 const oldflags = sc.func ? sc.func.flags : 0;
1918 auto e = resolveAliasThis(sc, farg, true);
1919 if (sc.func)
1920 sc.func.flags = oldflags;
1921 if (e)
1923 farg = e;
1924 goto Lretry;
1929 if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
1931 if (!farg.isLvalue())
1933 if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
1935 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1937 else if (global.params.rvalueRefParam == FeatureState.enabled)
1939 // Allow implicit conversion to ref
1941 else
1942 return nomatch();
1945 if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
1947 if (!farg.isLvalue())
1948 return nomatch();
1949 if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1950 return nomatch();
1952 if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
1953 m = MATCH.convert;
1954 if (m != MATCH.nomatch)
1956 if (m < match)
1957 match = m; // pick worst match
1958 argi++;
1959 continue;
1963 Lvarargs:
1964 /* The following code for variadic arguments closely
1965 * matches TypeFunction.callMatch()
1967 if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
1968 return nomatch();
1970 /* Check for match with function parameter T...
1972 Type tb = prmtype.toBasetype();
1973 switch (tb.ty)
1975 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1976 case Tsarray:
1977 case Taarray:
1979 // Perhaps we can do better with this, see TypeFunction.callMatch()
1980 if (tb.ty == Tsarray)
1982 TypeSArray tsa = cast(TypeSArray)tb;
1983 dinteger_t sz = tsa.dim.toInteger();
1984 if (sz != nfargs - argi)
1985 return nomatch();
1987 else if (tb.ty == Taarray)
1989 TypeAArray taa = cast(TypeAArray)tb;
1990 Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
1992 size_t i = templateParameterLookup(taa.index, parameters);
1993 if (i == IDX_NOTFOUND)
1995 Expression e;
1996 Type t;
1997 Dsymbol s;
1998 Scope *sco;
2000 uint errors = global.startGagging();
2001 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
2002 * The parameter isn't part of the template
2003 * ones, let's try to find it in the
2004 * instantiation scope 'sc' and the one
2005 * belonging to the template itself. */
2006 sco = sc;
2007 taa.index.resolve(instLoc, sco, e, t, s);
2008 if (!e)
2010 sco = paramscope;
2011 taa.index.resolve(instLoc, sco, e, t, s);
2013 global.endGagging(errors);
2015 if (!e)
2016 return nomatch();
2018 e = e.ctfeInterpret();
2019 e = e.implicitCastTo(sco, Type.tsize_t);
2020 e = e.optimize(WANTvalue);
2021 if (!dim.equals(e))
2022 return nomatch();
2024 else
2026 // This code matches code in TypeInstance.deduceType()
2027 TemplateParameter tprm = (*parameters)[i];
2028 TemplateValueParameter tvp = tprm.isTemplateValueParameter();
2029 if (!tvp)
2030 return nomatch();
2031 Expression e = cast(Expression)(*dedtypes)[i];
2032 if (e)
2034 if (!dim.equals(e))
2035 return nomatch();
2037 else
2039 Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
2040 MATCH m = dim.implicitConvTo(vt);
2041 if (m == MATCH.nomatch)
2042 return nomatch();
2043 (*dedtypes)[i] = dim;
2047 goto case Tarray;
2049 case Tarray:
2051 TypeArray ta = cast(TypeArray)tb;
2052 Type tret = fparam.isLazyArray();
2053 for (; argi < nfargs; argi++)
2055 Expression arg = (*fargs)[argi];
2056 assert(arg);
2058 MATCH m;
2059 /* If lazy array of delegates,
2060 * convert arg(s) to delegate(s)
2062 if (tret)
2064 if (ta.next.equals(arg.type))
2066 m = MATCH.exact;
2068 else
2070 m = arg.implicitConvTo(tret);
2071 if (m == MATCH.nomatch)
2073 if (tret.toBasetype().ty == Tvoid)
2074 m = MATCH.convert;
2078 else
2080 uint wm = 0;
2081 m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
2082 inoutMatch |= wm;
2084 if (m == MATCH.nomatch)
2085 return nomatch();
2086 if (m < match)
2087 match = m;
2089 goto Lmatch;
2091 case Tclass:
2092 case Tident:
2093 goto Lmatch;
2095 default:
2096 return nomatch();
2098 assert(0);
2100 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
2101 if (argi != nfargs2 && fparameters.varargs == VarArg.none)
2102 return nomatch();
2105 Lmatch:
2106 foreach (ref dedtype; *dedtypes)
2108 Type at = isType(dedtype);
2109 if (at)
2111 if (at.ty == Tnone)
2113 TypeDeduced xt = cast(TypeDeduced)at;
2114 at = xt.tded; // 'unbox'
2116 dedtype = at.merge2();
2119 for (size_t i = ntargs; i < dedargs.length; i++)
2121 TemplateParameter tparam = (*parameters)[i];
2122 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
2124 /* For T:T*, the dedargs is the T*, dedtypes is the T
2125 * But for function templates, we really need them to match
2127 RootObject oarg = (*dedargs)[i];
2128 RootObject oded = (*dedtypes)[i];
2129 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
2130 //if (oarg) printf("oarg: %s\n", oarg.toChars());
2131 //if (oded) printf("oded: %s\n", oded.toChars());
2132 if (oarg)
2133 continue;
2135 if (oded)
2137 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
2139 /* The specialization can work as long as afterwards
2140 * the oded == oarg
2142 (*dedargs)[i] = oded;
2143 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2144 //printf("m2 = %d\n", m2);
2145 if (m2 == MATCH.nomatch)
2146 return nomatch();
2147 if (m2 < matchTiargs)
2148 matchTiargs = m2; // pick worst match
2149 if (!(*dedtypes)[i].equals(oded))
2150 .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars());
2152 else
2154 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
2155 if (MATCH.convert < matchTiargs)
2156 matchTiargs = MATCH.convert;
2159 else
2161 oded = tparam.defaultArg(instLoc, paramscope);
2162 if (!oded)
2164 // if tuple parameter and
2165 // tuple parameter was not in function parameter list and
2166 // we're one or more arguments short (i.e. no tuple argument)
2167 if (tparam == tp &&
2168 fptupindex == IDX_NOTFOUND &&
2169 ntargs <= dedargs.length - 1)
2171 // make tuple argument an empty tuple
2172 oded = new Tuple();
2174 else
2175 return nomatch();
2177 if (isError(oded))
2178 return matcherror();
2179 ntargs++;
2181 /* At the template parameter T, the picked default template argument
2182 * X!int should be matched to T in order to deduce dependent
2183 * template parameter A.
2184 * auto foo(T : X!A = X!int, A...)() { ... }
2185 * foo(); // T <-- X!int, A <-- (int)
2187 if (tparam.specialization())
2189 (*dedargs)[i] = oded;
2190 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2191 //printf("m2 = %d\n", m2);
2192 if (m2 == MATCH.nomatch)
2193 return nomatch();
2194 if (m2 < matchTiargs)
2195 matchTiargs = m2; // pick worst match
2196 if (!(*dedtypes)[i].equals(oded))
2197 .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars());
2200 oded = declareParameter(paramscope, tparam, oded);
2201 (*dedargs)[i] = oded;
2204 /* https://issues.dlang.org/show_bug.cgi?id=7469
2205 * As same as the code for 7469 in findBestMatch,
2206 * expand a Tuple in dedargs to normalize template arguments.
2208 if (auto d = dedargs.length)
2210 if (auto va = isTuple((*dedargs)[d - 1]))
2212 dedargs.setDim(d - 1);
2213 dedargs.insert(d - 1, &va.objects);
2216 ti.tiargs = dedargs; // update to the normalized template arguments.
2218 // Partially instantiate function for constraint and fd.leastAsSpecialized()
2220 assert(paramscope.scopesym);
2221 Scope* sc2 = _scope;
2222 sc2 = sc2.push(paramscope.scopesym);
2223 sc2 = sc2.push(ti);
2224 sc2.parent = ti;
2225 sc2.tinst = ti;
2226 sc2.minst = sc.minst;
2227 sc2.stc |= fd.storage_class & STC.deprecated_;
2229 fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
2231 sc2 = sc2.pop();
2232 sc2 = sc2.pop();
2234 if (!fd)
2235 return nomatch();
2238 if (constraint)
2240 if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
2241 return nomatch();
2244 version (none)
2246 for (size_t i = 0; i < dedargs.length; i++)
2248 RootObject o = (*dedargs)[i];
2249 printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
2253 paramscope.pop();
2254 //printf("\tmatch %d\n", match);
2255 return MATCHpair(matchTiargs, match);
2258 /**************************************************
2259 * Declare template parameter tp with value o, and install it in the scope sc.
2261 RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o)
2263 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
2264 Type ta = isType(o);
2265 Expression ea = isExpression(o);
2266 Dsymbol sa = isDsymbol(o);
2267 Tuple va = isTuple(o);
2269 Declaration d;
2270 VarDeclaration v = null;
2272 if (ea)
2274 if (ea.op == EXP.type)
2275 ta = ea.type;
2276 else if (auto se = ea.isScopeExp())
2277 sa = se.sds;
2278 else if (auto te = ea.isThisExp())
2279 sa = te.var;
2280 else if (auto se = ea.isSuperExp())
2281 sa = se.var;
2282 else if (auto fe = ea.isFuncExp())
2284 if (fe.td)
2285 sa = fe.td;
2286 else
2287 sa = fe.fd;
2291 if (ta)
2293 //printf("type %s\n", ta.toChars());
2294 auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta);
2295 ad.storage_class |= STC.templateparameter;
2296 d = ad;
2298 else if (sa)
2300 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
2301 auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa);
2302 ad.storage_class |= STC.templateparameter;
2303 d = ad;
2305 else if (ea)
2307 // tdtypes.data[i] always matches ea here
2308 Initializer _init = new ExpInitializer(loc, ea);
2309 TemplateValueParameter tvp = tp.isTemplateValueParameter();
2310 Type t = tvp ? tvp.valType : null;
2311 v = new VarDeclaration(loc, t, tp.ident, _init);
2312 v.storage_class = STC.manifest | STC.templateparameter;
2313 d = v;
2315 else if (va)
2317 //printf("\ttuple\n");
2318 d = new TupleDeclaration(loc, tp.ident, &va.objects);
2320 else
2322 assert(0);
2324 d.storage_class |= STC.templateparameter;
2326 if (ta)
2328 Type t = ta;
2329 // consistent with Type.checkDeprecated()
2330 while (t.ty != Tenum)
2332 if (!t.nextOf())
2333 break;
2334 t = (cast(TypeNext)t).next;
2336 if (Dsymbol s = t.toDsymbol(sc))
2338 if (s.isDeprecated())
2339 d.storage_class |= STC.deprecated_;
2342 else if (sa)
2344 if (sa.isDeprecated())
2345 d.storage_class |= STC.deprecated_;
2348 if (!sc.insert(d))
2349 .error(loc, "%s `%s` declaration `%s` is already defined", kind, toPrettyChars, tp.ident.toChars());
2350 d.dsymbolSemantic(sc);
2351 /* So the caller's o gets updated with the result of semantic() being run on o
2353 if (v)
2354 o = v._init.initializerToExpression();
2355 return o;
2358 /*************************************************
2359 * Limited function template instantiation for using fd.leastAsSpecialized()
2361 extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs)
2363 assert(fd);
2364 version (none)
2366 printf("doHeaderInstantiation this = %s\n", toChars());
2369 // function body and contracts are not need
2370 if (fd.isCtorDeclaration())
2371 fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy());
2372 else
2373 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy());
2374 fd.parent = ti;
2376 assert(fd.type.ty == Tfunction);
2377 auto tf = fd.type.isTypeFunction();
2378 tf.fargs = fargs;
2380 if (tthis)
2382 // Match 'tthis' to any TemplateThisParameter's
2383 bool hasttp = false;
2384 foreach (tp; *parameters)
2386 TemplateThisParameter ttp = tp.isTemplateThisParameter();
2387 if (ttp)
2388 hasttp = true;
2390 if (hasttp)
2392 tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
2393 assert(!tf.deco);
2397 Scope* scx = sc2.push();
2399 // Shouldn't run semantic on default arguments and return type.
2400 foreach (ref params; *tf.parameterList.parameters)
2401 params.defaultArg = null;
2402 tf.incomplete = true;
2404 if (fd.isCtorDeclaration())
2406 // For constructors, emitting return type is necessary for
2407 // isReturnIsolated() in functionResolve.
2408 tf.isctor = true;
2410 Dsymbol parent = toParentDecl();
2411 Type tret;
2412 AggregateDeclaration ad = parent.isAggregateDeclaration();
2413 if (!ad || parent.isUnionDeclaration())
2415 tret = Type.tvoid;
2417 else
2419 tret = ad.handleType();
2420 assert(tret);
2421 tret = tret.addStorageClass(fd.storage_class | scx.stc);
2422 tret = tret.addMod(tf.mod);
2424 tf.next = tret;
2425 if (ad && ad.isStructDeclaration())
2426 tf.isref = 1;
2427 //printf("tf = %s\n", tf.toChars());
2429 else
2430 tf.next = null;
2431 fd.type = tf;
2432 fd.type = fd.type.addSTC(scx.stc);
2433 fd.type = fd.type.typeSemantic(fd.loc, scx);
2434 scx = scx.pop();
2436 if (fd.type.ty != Tfunction)
2437 return null;
2439 fd.originalType = fd.type; // for mangling
2440 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
2441 //printf("fd.needThis() = %d\n", fd.needThis());
2443 return fd;
2446 debug (FindExistingInstance)
2448 __gshared uint nFound, nNotFound, nAdded, nRemoved;
2450 shared static ~this()
2452 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
2453 nFound, nNotFound, nAdded, nRemoved);
2457 /****************************************************
2458 * Given a new instance tithis of this TemplateDeclaration,
2459 * see if there already exists an instance.
2460 * If so, return that existing instance.
2462 extern (D) TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs)
2464 //printf("findExistingInstance() %s\n", tithis.toChars());
2465 tithis.fargs = fargs;
2466 auto tibox = TemplateInstanceBox(tithis);
2467 auto p = tibox in instances;
2468 debug (FindExistingInstance) ++(p ? nFound : nNotFound);
2469 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
2470 return p ? *p : null;
2473 /********************************************
2474 * Add instance ti to TemplateDeclaration's table of instances.
2475 * Return a handle we can use to later remove it if it fails instantiation.
2477 extern (D) TemplateInstance addInstance(TemplateInstance ti)
2479 //printf("addInstance() %p %s\n", instances, ti.toChars());
2480 auto tibox = TemplateInstanceBox(ti);
2481 instances[tibox] = ti;
2482 debug (FindExistingInstance) ++nAdded;
2483 return ti;
2486 /*******************************************
2487 * Remove TemplateInstance from table of instances.
2488 * Input:
2489 * handle returned by addInstance()
2491 extern (D) void removeInstance(TemplateInstance ti)
2493 //printf("removeInstance() %s\n", ti.toChars());
2494 auto tibox = TemplateInstanceBox(ti);
2495 debug (FindExistingInstance) ++nRemoved;
2496 instances.remove(tibox);
2499 override inout(TemplateDeclaration) isTemplateDeclaration() inout
2501 return this;
2505 * Check if the last template parameter is a tuple one,
2506 * and returns it if so, else returns `null`.
2508 * Returns:
2509 * The last template parameter if it's a `TemplateTupleParameter`
2511 TemplateTupleParameter isVariadic()
2513 size_t dim = parameters.length;
2514 if (dim == 0)
2515 return null;
2516 return (*parameters)[dim - 1].isTemplateTupleParameter();
2519 extern(C++) override bool isDeprecated() const
2521 return this.deprecated_;
2524 /***********************************
2525 * We can overload templates.
2527 override bool isOverloadable() const
2529 return true;
2532 override void accept(Visitor v)
2534 v.visit(this);
2538 extern (C++) final class TypeDeduced : Type
2540 Type tded;
2541 Expressions argexps; // corresponding expressions
2542 Types tparams; // tparams[i].mod
2544 extern (D) this(Type tt, Expression e, Type tparam)
2546 super(Tnone);
2547 tded = tt;
2548 argexps.push(e);
2549 tparams.push(tparam);
2552 void update(Expression e, Type tparam)
2554 argexps.push(e);
2555 tparams.push(tparam);
2558 void update(Type tt, Expression e, Type tparam)
2560 tded = tt;
2561 argexps.push(e);
2562 tparams.push(tparam);
2565 MATCH matchAll(Type tt)
2567 MATCH match = MATCH.exact;
2568 foreach (j, e; argexps)
2570 assert(e);
2571 if (e == emptyArrayElement)
2572 continue;
2574 Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_);
2576 MATCH m = e.implicitConvTo(t);
2577 if (match > m)
2578 match = m;
2579 if (match == MATCH.nomatch)
2580 break;
2582 return match;
2587 /*************************************************
2588 * Given function arguments, figure out which template function
2589 * to expand, and return matching result.
2590 * Params:
2591 * m = matching result
2592 * dstart = the root of overloaded function templates
2593 * loc = instantiation location
2594 * sc = instantiation scope
2595 * tiargs = initial list of template arguments
2596 * tthis = if !NULL, the 'this' pointer argument
2597 * argumentList= arguments to function
2598 * pMessage = address to store error message, or null
2600 void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
2601 Type tthis, ArgumentList argumentList, const(char)** pMessage = null)
2603 version (none)
2605 printf("functionResolve() dstart = %s\n", dstart.toChars());
2606 printf(" tiargs:\n");
2607 if (tiargs)
2609 for (size_t i = 0; i < tiargs.length; i++)
2611 RootObject arg = (*tiargs)[i];
2612 printf("\t%s\n", arg.toChars());
2615 printf(" fargs:\n");
2616 for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
2618 Expression arg = (*fargs)[i];
2619 printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
2620 //printf("\tty = %d\n", arg.type.ty);
2622 //printf("stc = %llx\n", dstart._scope.stc);
2623 //printf("match:t/f = %d/%d\n", ta_last, m.last);
2626 // results
2627 int property = 0; // 0: uninitialized
2628 // 1: seen @property
2629 // 2: not @property
2630 size_t ov_index = 0;
2631 TemplateDeclaration td_best;
2632 TemplateInstance ti_best;
2633 MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch;
2634 Type tthis_best;
2636 int applyFunction(FuncDeclaration fd)
2638 // skip duplicates
2639 if (fd == m.lastf)
2640 return 0;
2641 // explicitly specified tiargs never match to non template function
2642 if (tiargs && tiargs.length > 0)
2643 return 0;
2645 // constructors need a valid scope in order to detect semantic errors
2646 if (!fd.isCtorDeclaration &&
2647 fd.semanticRun < PASS.semanticdone)
2649 Ungag ungag = fd.ungagSpeculative();
2650 fd.dsymbolSemantic(null);
2652 if (fd.semanticRun < PASS.semanticdone)
2654 .error(loc, "forward reference to template `%s`", fd.toChars());
2655 return 1;
2657 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
2658 auto tf = cast(TypeFunction)fd.type;
2660 int prop = tf.isproperty ? 1 : 2;
2661 if (property == 0)
2662 property = prop;
2663 else if (property != prop)
2664 error(fd.loc, "cannot overload both property and non-property functions");
2666 /* For constructors, qualifier check will be opposite direction.
2667 * Qualified constructor always makes qualified object, then will be checked
2668 * that it is implicitly convertible to tthis.
2670 Type tthis_fd = fd.needThis() ? tthis : null;
2671 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2672 if (isCtorCall)
2674 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
2675 // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
2676 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2677 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2678 fd.isReturnIsolated())
2680 /* && tf.isShared() == tthis_fd.isShared()*/
2681 // Uniquely constructed object can ignore shared qualifier.
2682 // TODO: Is this appropriate?
2683 tthis_fd = null;
2685 else
2686 return 0; // MATCH.nomatch
2688 /* Fix Issue 17970:
2689 If a struct is declared as shared the dtor is automatically
2690 considered to be shared, but when the struct is instantiated
2691 the instance is no longer considered to be shared when the
2692 function call matching is done. The fix makes it so that if a
2693 struct declaration is shared, when the destructor is called,
2694 the instantiated struct is also considered shared.
2696 if (auto dt = fd.isDtorDeclaration())
2698 auto dtmod = dt.type.toTypeFunction();
2699 auto shared_dtor = dtmod.mod & MODFlags.shared_;
2700 auto shared_this = tthis_fd !is null ?
2701 tthis_fd.mod & MODFlags.shared_ : 0;
2702 if (shared_dtor && !shared_this)
2703 tthis_fd = dtmod;
2704 else if (shared_this && !shared_dtor && tthis_fd !is null)
2705 tf.mod = tthis_fd.mod;
2707 MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc);
2708 //printf("test1: mfa = %d\n", mfa);
2709 if (mfa == MATCH.nomatch)
2710 return 0;
2712 int firstIsBetter()
2714 td_best = null;
2715 ti_best = null;
2716 ta_last = MATCH.exact;
2717 m.last = mfa;
2718 m.lastf = fd;
2719 tthis_best = tthis_fd;
2720 ov_index = 0;
2721 m.count = 1;
2722 return 0;
2725 if (mfa > m.last) return firstIsBetter();
2726 if (mfa < m.last) return 0;
2728 /* See if one of the matches overrides the other.
2730 assert(m.lastf);
2731 if (m.lastf.overrides(fd)) return 0;
2732 if (fd.overrides(m.lastf)) return firstIsBetter();
2734 /* Try to disambiguate using template-style partial ordering rules.
2735 * In essence, if f() and g() are ambiguous, if f() can call g(),
2736 * but g() cannot call f(), then pick f().
2737 * This is because f() is "more specialized."
2740 MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
2741 MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
2742 //printf("c1 = %d, c2 = %d\n", c1, c2);
2743 if (c1 > c2) return firstIsBetter();
2744 if (c1 < c2) return 0;
2747 /* The 'overrides' check above does covariant checking only
2748 * for virtual member functions. It should do it for all functions,
2749 * but in order to not risk breaking code we put it after
2750 * the 'leastAsSpecialized' check.
2751 * In the future try moving it before.
2752 * I.e. a not-the-same-but-covariant match is preferred,
2753 * as it is more restrictive.
2755 if (!m.lastf.type.equals(fd.type))
2757 //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
2758 const lastCovariant = m.lastf.type.covariant(fd.type);
2759 const firstCovariant = fd.type.covariant(m.lastf.type);
2761 if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no)
2763 if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no)
2765 return 0;
2768 else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no)
2770 return firstIsBetter();
2774 /* If the two functions are the same function, like:
2775 * int foo(int);
2776 * int foo(int x) { ... }
2777 * then pick the one with the body.
2779 * If none has a body then don't care because the same
2780 * real function would be linked to the decl (e.g from object file)
2782 if (tf.equals(m.lastf.type) &&
2783 fd.storage_class == m.lastf.storage_class &&
2784 fd.parent == m.lastf.parent &&
2785 fd.visibility == m.lastf.visibility &&
2786 fd._linkage == m.lastf._linkage)
2788 if (fd.fbody && !m.lastf.fbody)
2789 return firstIsBetter();
2790 if (!fd.fbody)
2791 return 0;
2794 // https://issues.dlang.org/show_bug.cgi?id=14450
2795 // Prefer exact qualified constructor for the creating object type
2796 if (isCtorCall && tf.mod != m.lastf.type.mod)
2798 if (tthis.mod == tf.mod) return firstIsBetter();
2799 if (tthis.mod == m.lastf.type.mod) return 0;
2802 m.nextf = fd;
2803 m.count++;
2804 return 0;
2807 int applyTemplate(TemplateDeclaration td)
2809 //printf("applyTemplate(): td = %s\n", td.toChars());
2810 if (td == td_best) // skip duplicates
2811 return 0;
2813 if (!sc)
2814 sc = td._scope; // workaround for Type.aliasthisOf
2816 if (td.semanticRun == PASS.initial && td._scope)
2818 // Try to fix forward reference. Ungag errors while doing so.
2819 Ungag ungag = td.ungagSpeculative();
2820 td.dsymbolSemantic(td._scope);
2822 if (td.semanticRun == PASS.initial)
2824 .error(loc, "forward reference to template `%s`", td.toChars());
2825 Lerror:
2826 m.lastf = null;
2827 m.count = 0;
2828 m.last = MATCH.nomatch;
2829 return 1;
2831 //printf("td = %s\n", td.toChars());
2833 if (argumentList.hasNames)
2835 .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet");
2836 goto Lerror;
2838 auto f = td.onemember ? td.onemember.isFuncDeclaration() : null;
2839 if (!f)
2841 if (!tiargs)
2842 tiargs = new Objects();
2843 auto ti = new TemplateInstance(loc, td, tiargs);
2844 Objects dedtypes = Objects(td.parameters.length);
2845 assert(td.semanticRun != PASS.initial);
2846 MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0);
2847 //printf("matchWithInstance = %d\n", mta);
2848 if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
2849 return 0;
2851 ti.templateInstanceSemantic(sc, argumentList);
2852 if (!ti.inst) // if template failed to expand
2853 return 0;
2855 Dsymbol s = ti.inst.toAlias();
2856 FuncDeclaration fd;
2857 if (auto tdx = s.isTemplateDeclaration())
2859 Objects dedtypesX; // empty tiargs
2861 // https://issues.dlang.org/show_bug.cgi?id=11553
2862 // Check for recursive instantiation of tdx.
2863 for (TemplatePrevious* p = tdx.previous; p; p = p.prev)
2865 if (arrayObjectMatch(p.dedargs, &dedtypesX))
2867 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
2868 /* It must be a subscope of p.sc, other scope chains are not recursive
2869 * instantiations.
2871 for (Scope* scx = sc; scx; scx = scx.enclosing)
2873 if (scx == p.sc)
2875 error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars());
2876 goto Lerror;
2880 /* BUG: should also check for ref param differences
2884 TemplatePrevious pr;
2885 pr.prev = tdx.previous;
2886 pr.sc = sc;
2887 pr.dedargs = &dedtypesX;
2888 tdx.previous = &pr; // add this to threaded list
2890 fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet);
2892 tdx.previous = pr.prev; // unlink from threaded list
2894 else if (s.isFuncDeclaration())
2896 fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet);
2898 else
2899 goto Lerror;
2901 if (!fd)
2902 return 0;
2904 if (fd.type.ty != Tfunction)
2906 m.lastf = fd; // to propagate "error match"
2907 m.count = 1;
2908 m.last = MATCH.nomatch;
2909 return 1;
2912 Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
2914 auto tf = cast(TypeFunction)fd.type;
2915 MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc);
2916 if (mfa < m.last)
2917 return 0;
2919 if (mta < ta_last) goto Ltd_best2;
2920 if (mta > ta_last) goto Ltd2;
2922 if (mfa < m.last) goto Ltd_best2;
2923 if (mfa > m.last) goto Ltd2;
2925 // td_best and td are ambiguous
2926 //printf("Lambig2\n");
2927 m.nextf = fd;
2928 m.count++;
2929 return 0;
2931 Ltd_best2:
2932 return 0;
2934 Ltd2:
2935 // td is the new best match
2936 assert(td._scope);
2937 td_best = td;
2938 ti_best = null;
2939 property = 0; // (backward compatibility)
2940 ta_last = mta;
2941 m.last = mfa;
2942 m.lastf = fd;
2943 tthis_best = tthis_fd;
2944 ov_index = 0;
2945 m.nextf = null;
2946 m.count = 1;
2947 return 0;
2950 //printf("td = %s\n", td.toChars());
2951 for (size_t ovi = 0; f; f = f.overnext0, ovi++)
2953 if (f.type.ty != Tfunction || f.errors)
2954 goto Lerror;
2956 /* This is a 'dummy' instance to evaluate constraint properly.
2958 auto ti = new TemplateInstance(loc, td, tiargs);
2959 ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary.
2961 auto fd = f;
2962 MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList);
2963 MATCH mta = x.mta;
2964 MATCH mfa = x.mfa;
2965 //printf("match:t/f = %d/%d\n", mta, mfa);
2966 if (!fd || mfa == MATCH.nomatch)
2967 continue;
2969 Type tthis_fd = fd.needThis() ? tthis : null;
2971 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2972 if (isCtorCall)
2974 // Constructor call requires additional check.
2975 auto tf = cast(TypeFunction)fd.type;
2976 assert(tf.next);
2977 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2978 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2979 fd.isReturnIsolated())
2981 tthis_fd = null;
2983 else
2984 continue; // MATCH.nomatch
2986 // need to check here whether the constructor is the member of a struct
2987 // declaration that defines a copy constructor. This is already checked
2988 // in the semantic of CtorDeclaration, however, when matching functions,
2989 // the template instance is not expanded.
2990 // https://issues.dlang.org/show_bug.cgi?id=21613
2991 auto ad = fd.isThis();
2992 auto sd = ad.isStructDeclaration();
2993 if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti))
2994 continue;
2997 if (mta < ta_last) goto Ltd_best;
2998 if (mta > ta_last) goto Ltd;
3000 if (mfa < m.last) goto Ltd_best;
3001 if (mfa > m.last) goto Ltd;
3003 if (td_best)
3005 // Disambiguate by picking the most specialized TemplateDeclaration
3006 MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
3007 MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
3008 //printf("1: c1 = %d, c2 = %d\n", c1, c2);
3009 if (c1 > c2) goto Ltd;
3010 if (c1 < c2) goto Ltd_best;
3012 assert(fd && m.lastf);
3014 // Disambiguate by tf.callMatch
3015 auto tf1 = fd.type.isTypeFunction();
3016 auto tf2 = m.lastf.type.isTypeFunction();
3017 MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc);
3018 MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc);
3019 //printf("2: c1 = %d, c2 = %d\n", c1, c2);
3020 if (c1 > c2) goto Ltd;
3021 if (c1 < c2) goto Ltd_best;
3024 // Disambiguate by picking the most specialized FunctionDeclaration
3025 MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names);
3026 MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names);
3027 //printf("3: c1 = %d, c2 = %d\n", c1, c2);
3028 if (c1 > c2) goto Ltd;
3029 if (c1 < c2) goto Ltd_best;
3032 // https://issues.dlang.org/show_bug.cgi?id=14450
3033 // Prefer exact qualified constructor for the creating object type
3034 if (isCtorCall && fd.type.mod != m.lastf.type.mod)
3036 if (tthis.mod == fd.type.mod) goto Ltd;
3037 if (tthis.mod == m.lastf.type.mod) goto Ltd_best;
3040 m.nextf = fd;
3041 m.count++;
3042 continue;
3044 Ltd_best: // td_best is the best match so far
3045 //printf("Ltd_best\n");
3046 continue;
3048 Ltd: // td is the new best match
3049 //printf("Ltd\n");
3050 assert(td._scope);
3051 td_best = td;
3052 ti_best = ti;
3053 property = 0; // (backward compatibility)
3054 ta_last = mta;
3055 m.last = mfa;
3056 m.lastf = fd;
3057 tthis_best = tthis_fd;
3058 ov_index = ovi;
3059 m.nextf = null;
3060 m.count = 1;
3061 continue;
3063 return 0;
3066 auto td = dstart.isTemplateDeclaration();
3067 if (td && td.funcroot)
3068 dstart = td.funcroot;
3069 overloadApply(dstart, (Dsymbol s)
3071 if (s.errors)
3072 return 0;
3073 if (auto fd = s.isFuncDeclaration())
3074 return applyFunction(fd);
3075 if (auto td = s.isTemplateDeclaration())
3076 return applyTemplate(td);
3077 return 0;
3078 }, sc);
3080 //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf);
3081 if (td_best && ti_best && m.count == 1)
3083 // Matches to template function
3084 assert(td_best.onemember && td_best.onemember.isFuncDeclaration());
3085 /* The best match is td_best with arguments tdargs.
3086 * Now instantiate the template.
3088 assert(td_best._scope);
3089 if (!sc)
3090 sc = td_best._scope; // workaround for Type.aliasthisOf
3092 auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs);
3093 ti.templateInstanceSemantic(sc, argumentList);
3095 m.lastf = ti.toAlias().isFuncDeclaration();
3096 if (!m.lastf)
3097 goto Lnomatch;
3098 if (ti.errors)
3100 Lerror:
3101 m.count = 1;
3102 assert(m.lastf);
3103 m.last = MATCH.nomatch;
3104 return;
3107 // look forward instantiated overload function
3108 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
3109 // it has filled overnext0d
3110 while (ov_index--)
3112 m.lastf = m.lastf.overnext0;
3113 assert(m.lastf);
3116 tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null;
3118 if (m.lastf.type.ty == Terror)
3119 goto Lerror;
3120 auto tf = m.lastf.type.isTypeFunction();
3121 if (!tf.callMatch(tthis_best, argumentList, 0, null, sc))
3122 goto Lnomatch;
3124 /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
3125 * a template instance can be matched while instantiating
3126 * that same template. Thus, the function type can be incomplete. Complete it.
3128 * https://issues.dlang.org/show_bug.cgi?id=9208
3129 * For auto function, completion should be deferred to the end of
3130 * its semantic3. Should not complete it in here.
3132 if (tf.next && !m.lastf.inferRetType)
3134 m.lastf.type = tf.typeSemantic(loc, sc);
3137 else if (m.lastf)
3139 // Matches to non template function,
3140 // or found matches were ambiguous.
3141 assert(m.count >= 1);
3143 else
3145 Lnomatch:
3146 m.count = 0;
3147 m.lastf = null;
3148 m.last = MATCH.nomatch;
3152 /* ======================== Type ============================================ */
3154 /****
3155 * Given an identifier, figure out which TemplateParameter it is.
3156 * Return IDX_NOTFOUND if not found.
3158 private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters)
3160 for (size_t i = 0; i < parameters.length; i++)
3162 TemplateParameter tp = (*parameters)[i];
3163 if (tp.ident.equals(id))
3164 return i;
3166 return IDX_NOTFOUND;
3169 private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
3171 if (tparam.ty == Tident)
3173 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3174 //printf("\ttident = '%s'\n", tident.toChars());
3175 return templateIdentifierLookup(tident.ident, parameters);
3177 return IDX_NOTFOUND;
3180 private ubyte deduceWildHelper(Type t, Type* at, Type tparam)
3182 if ((tparam.mod & MODFlags.wild) == 0)
3183 return 0;
3185 *at = null;
3187 auto X(T, U)(T U, U T)
3189 return (U << 4) | T;
3192 switch (X(tparam.mod, t.mod))
3194 case X(MODFlags.wild, 0):
3195 case X(MODFlags.wild, MODFlags.const_):
3196 case X(MODFlags.wild, MODFlags.shared_):
3197 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3198 case X(MODFlags.wild, MODFlags.immutable_):
3199 case X(MODFlags.wildconst, 0):
3200 case X(MODFlags.wildconst, MODFlags.const_):
3201 case X(MODFlags.wildconst, MODFlags.shared_):
3202 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3203 case X(MODFlags.wildconst, MODFlags.immutable_):
3204 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
3205 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3206 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
3207 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
3208 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3209 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
3211 ubyte wm = (t.mod & ~MODFlags.shared_);
3212 if (wm == 0)
3213 wm = MODFlags.mutable;
3214 ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_);
3215 *at = t.unqualify(m);
3216 return wm;
3218 case X(MODFlags.wild, MODFlags.wild):
3219 case X(MODFlags.wild, MODFlags.wildconst):
3220 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3221 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3222 case X(MODFlags.wildconst, MODFlags.wild):
3223 case X(MODFlags.wildconst, MODFlags.wildconst):
3224 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3225 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3226 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3227 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3228 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3229 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3231 *at = t.unqualify(tparam.mod & t.mod);
3232 return MODFlags.wild;
3234 default:
3235 return 0;
3240 * Returns the common type of the 2 types.
3242 private Type rawTypeMerge(Type t1, Type t2)
3244 if (t1.equals(t2))
3245 return t1;
3246 if (t1.equivalent(t2))
3247 return t1.castMod(MODmerge(t1.mod, t2.mod));
3249 auto t1b = t1.toBasetype();
3250 auto t2b = t2.toBasetype();
3251 if (t1b.equals(t2b))
3252 return t1b;
3253 if (t1b.equivalent(t2b))
3254 return t1b.castMod(MODmerge(t1b.mod, t2b.mod));
3256 auto ty = implicitConvCommonTy(t1b.ty, t2b.ty);
3257 if (ty != Terror)
3258 return Type.basic[ty];
3260 return null;
3263 private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
3265 // 9*9 == 81 cases
3267 auto X(T, U)(T U, U T)
3269 return (U << 4) | T;
3272 switch (X(tparam.mod, t.mod))
3274 case X(0, 0):
3275 case X(0, MODFlags.const_):
3276 case X(0, MODFlags.wild):
3277 case X(0, MODFlags.wildconst):
3278 case X(0, MODFlags.shared_):
3279 case X(0, MODFlags.shared_ | MODFlags.const_):
3280 case X(0, MODFlags.shared_ | MODFlags.wild):
3281 case X(0, MODFlags.shared_ | MODFlags.wildconst):
3282 case X(0, MODFlags.immutable_):
3283 // foo(U) T => T
3284 // foo(U) const(T) => const(T)
3285 // foo(U) inout(T) => inout(T)
3286 // foo(U) inout(const(T)) => inout(const(T))
3287 // foo(U) shared(T) => shared(T)
3288 // foo(U) shared(const(T)) => shared(const(T))
3289 // foo(U) shared(inout(T)) => shared(inout(T))
3290 // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
3291 // foo(U) immutable(T) => immutable(T)
3293 *at = t;
3294 return MATCH.exact;
3296 case X(MODFlags.const_, MODFlags.const_):
3297 case X(MODFlags.wild, MODFlags.wild):
3298 case X(MODFlags.wildconst, MODFlags.wildconst):
3299 case X(MODFlags.shared_, MODFlags.shared_):
3300 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
3301 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3302 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3303 case X(MODFlags.immutable_, MODFlags.immutable_):
3304 // foo(const(U)) const(T) => T
3305 // foo(inout(U)) inout(T) => T
3306 // foo(inout(const(U))) inout(const(T)) => T
3307 // foo(shared(U)) shared(T) => T
3308 // foo(shared(const(U))) shared(const(T)) => T
3309 // foo(shared(inout(U))) shared(inout(T)) => T
3310 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
3311 // foo(immutable(U)) immutable(T) => T
3313 *at = t.mutableOf().unSharedOf();
3314 return MATCH.exact;
3316 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
3317 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
3318 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
3319 // foo(const(U)) shared(const(T)) => shared(T)
3320 // foo(inout(U)) shared(inout(T)) => shared(T)
3321 // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
3323 *at = t.mutableOf();
3324 return MATCH.exact;
3326 case X(MODFlags.const_, 0):
3327 case X(MODFlags.const_, MODFlags.wild):
3328 case X(MODFlags.const_, MODFlags.wildconst):
3329 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
3330 case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
3331 case X(MODFlags.const_, MODFlags.immutable_):
3332 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.immutable_):
3333 // foo(const(U)) T => T
3334 // foo(const(U)) inout(T) => T
3335 // foo(const(U)) inout(const(T)) => T
3336 // foo(const(U)) shared(inout(T)) => shared(T)
3337 // foo(const(U)) shared(inout(const(T))) => shared(T)
3338 // foo(const(U)) immutable(T) => T
3339 // foo(shared(const(U))) immutable(T) => T
3341 *at = t.mutableOf();
3342 return MATCH.constant;
3344 case X(MODFlags.const_, MODFlags.shared_):
3345 // foo(const(U)) shared(T) => shared(T)
3347 *at = t;
3348 return MATCH.constant;
3350 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
3351 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
3352 case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wildconst):
3353 // foo(shared(U)) shared(const(T)) => const(T)
3354 // foo(shared(U)) shared(inout(T)) => inout(T)
3355 // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
3357 *at = t.unSharedOf();
3358 return MATCH.exact;
3360 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
3361 // foo(shared(const(U))) shared(T) => T
3363 *at = t.unSharedOf();
3364 return MATCH.constant;
3366 case X(MODFlags.wildconst, MODFlags.immutable_):
3367 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
3368 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
3369 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3370 // foo(inout(const(U))) immutable(T) => T
3371 // foo(shared(const(U))) shared(inout(const(T))) => T
3372 // foo(shared(inout(const(U)))) immutable(T) => T
3373 // foo(shared(inout(const(U)))) shared(inout(T)) => T
3375 *at = t.unSharedOf().mutableOf();
3376 return MATCH.constant;
3378 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
3379 // foo(shared(const(U))) shared(inout(T)) => T
3381 *at = t.unSharedOf().mutableOf();
3382 return MATCH.constant;
3384 case X(MODFlags.wild, 0):
3385 case X(MODFlags.wild, MODFlags.const_):
3386 case X(MODFlags.wild, MODFlags.wildconst):
3387 case X(MODFlags.wild, MODFlags.immutable_):
3388 case X(MODFlags.wild, MODFlags.shared_):
3389 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3390 case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3391 case X(MODFlags.wildconst, 0):
3392 case X(MODFlags.wildconst, MODFlags.const_):
3393 case X(MODFlags.wildconst, MODFlags.wild):
3394 case X(MODFlags.wildconst, MODFlags.shared_):
3395 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3396 case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
3397 case X(MODFlags.shared_, 0):
3398 case X(MODFlags.shared_, MODFlags.const_):
3399 case X(MODFlags.shared_, MODFlags.wild):
3400 case X(MODFlags.shared_, MODFlags.wildconst):
3401 case X(MODFlags.shared_, MODFlags.immutable_):
3402 case X(MODFlags.shared_ | MODFlags.const_, 0):
3403 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.const_):
3404 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wild):
3405 case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wildconst):
3406 case X(MODFlags.shared_ | MODFlags.wild, 0):
3407 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.const_):
3408 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wild):
3409 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wildconst):
3410 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
3411 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
3412 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
3413 case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
3414 case X(MODFlags.shared_ | MODFlags.wildconst, 0):
3415 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.const_):
3416 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wild):
3417 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wildconst):
3418 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
3419 case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
3420 case X(MODFlags.immutable_, 0):
3421 case X(MODFlags.immutable_, MODFlags.const_):
3422 case X(MODFlags.immutable_, MODFlags.wild):
3423 case X(MODFlags.immutable_, MODFlags.wildconst):
3424 case X(MODFlags.immutable_, MODFlags.shared_):
3425 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.const_):
3426 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
3427 case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wildconst):
3428 // foo(inout(U)) T => nomatch
3429 // foo(inout(U)) const(T) => nomatch
3430 // foo(inout(U)) inout(const(T)) => nomatch
3431 // foo(inout(U)) immutable(T) => nomatch
3432 // foo(inout(U)) shared(T) => nomatch
3433 // foo(inout(U)) shared(const(T)) => nomatch
3434 // foo(inout(U)) shared(inout(const(T))) => nomatch
3435 // foo(inout(const(U))) T => nomatch
3436 // foo(inout(const(U))) const(T) => nomatch
3437 // foo(inout(const(U))) inout(T) => nomatch
3438 // foo(inout(const(U))) shared(T) => nomatch
3439 // foo(inout(const(U))) shared(const(T)) => nomatch
3440 // foo(inout(const(U))) shared(inout(T)) => nomatch
3441 // foo(shared(U)) T => nomatch
3442 // foo(shared(U)) const(T) => nomatch
3443 // foo(shared(U)) inout(T) => nomatch
3444 // foo(shared(U)) inout(const(T)) => nomatch
3445 // foo(shared(U)) immutable(T) => nomatch
3446 // foo(shared(const(U))) T => nomatch
3447 // foo(shared(const(U))) const(T) => nomatch
3448 // foo(shared(const(U))) inout(T) => nomatch
3449 // foo(shared(const(U))) inout(const(T)) => nomatch
3450 // foo(shared(inout(U))) T => nomatch
3451 // foo(shared(inout(U))) const(T) => nomatch
3452 // foo(shared(inout(U))) inout(T) => nomatch
3453 // foo(shared(inout(U))) inout(const(T)) => nomatch
3454 // foo(shared(inout(U))) immutable(T) => nomatch
3455 // foo(shared(inout(U))) shared(T) => nomatch
3456 // foo(shared(inout(U))) shared(const(T)) => nomatch
3457 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
3458 // foo(shared(inout(const(U)))) T => nomatch
3459 // foo(shared(inout(const(U)))) const(T) => nomatch
3460 // foo(shared(inout(const(U)))) inout(T) => nomatch
3461 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
3462 // foo(shared(inout(const(U)))) shared(T) => nomatch
3463 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
3464 // foo(immutable(U)) T => nomatch
3465 // foo(immutable(U)) const(T) => nomatch
3466 // foo(immutable(U)) inout(T) => nomatch
3467 // foo(immutable(U)) inout(const(T)) => nomatch
3468 // foo(immutable(U)) shared(T) => nomatch
3469 // foo(immutable(U)) shared(const(T)) => nomatch
3470 // foo(immutable(U)) shared(inout(T)) => nomatch
3471 // foo(immutable(U)) shared(inout(const(T))) => nomatch
3472 return MATCH.nomatch;
3474 default:
3475 assert(0);
3479 __gshared Expression emptyArrayElement = null;
3481 /* These form the heart of template argument deduction.
3482 * Given 'this' being the type argument to the template instance,
3483 * it is matched against the template declaration parameter specialization
3484 * 'tparam' to determine the type to be used for the parameter.
3485 * Example:
3486 * template Foo(T:T*) // template declaration
3487 * Foo!(int*) // template instantiation
3488 * Input:
3489 * this = int*
3490 * tparam = T*
3491 * parameters = [ T:T* ] // Array of TemplateParameter's
3492 * Output:
3493 * dedtypes = [ int ] // Array of Expression/Type's
3495 MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
3497 extern (C++) final class DeduceType : Visitor
3499 alias visit = Visitor.visit;
3500 public:
3501 Scope* sc;
3502 Type tparam;
3503 TemplateParameters* parameters;
3504 Objects* dedtypes;
3505 uint* wm;
3506 size_t inferStart;
3507 bool ignoreAliasThis;
3508 MATCH result;
3510 extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe
3512 this.sc = sc;
3513 this.tparam = tparam;
3514 this.parameters = parameters;
3515 this.dedtypes = dedtypes;
3516 this.wm = wm;
3517 this.inferStart = inferStart;
3518 this.ignoreAliasThis = ignoreAliasThis;
3519 result = MATCH.nomatch;
3522 override void visit(Type t)
3524 if (!tparam)
3525 goto Lnomatch;
3527 if (t == tparam)
3528 goto Lexact;
3530 if (tparam.ty == Tident)
3532 // Determine which parameter tparam is
3533 size_t i = templateParameterLookup(tparam, parameters);
3534 if (i == IDX_NOTFOUND)
3536 if (!sc)
3537 goto Lnomatch;
3539 /* Need a loc to go with the semantic routine.
3541 Loc loc;
3542 if (parameters.length)
3544 TemplateParameter tp = (*parameters)[0];
3545 loc = tp.loc;
3548 /* BUG: what if tparam is a template instance, that
3549 * has as an argument another Tident?
3551 tparam = tparam.typeSemantic(loc, sc);
3552 assert(tparam.ty != Tident);
3553 result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
3554 return;
3557 TemplateParameter tp = (*parameters)[i];
3559 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3560 if (tident.idents.length > 0)
3562 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
3563 Dsymbol s = t.toDsymbol(sc);
3564 for (size_t j = tident.idents.length; j-- > 0;)
3566 RootObject id = tident.idents[j];
3567 if (id.dyncast() == DYNCAST.identifier)
3569 if (!s || !s.parent)
3570 goto Lnomatch;
3571 Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id);
3572 if (!s2)
3573 goto Lnomatch;
3574 s2 = s2.toAlias();
3575 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
3576 if (s != s2)
3578 if (Type tx = s2.getType())
3580 if (s != tx.toDsymbol(sc))
3581 goto Lnomatch;
3583 else
3584 goto Lnomatch;
3586 s = s.parent;
3588 else
3589 goto Lnomatch;
3591 //printf("[e] s = %s\n", s?s.toChars():"(null)");
3592 if (tp.isTemplateTypeParameter())
3594 Type tt = s.getType();
3595 if (!tt)
3596 goto Lnomatch;
3597 Type at = cast(Type)(*dedtypes)[i];
3598 if (at && at.ty == Tnone)
3599 at = (cast(TypeDeduced)at).tded;
3600 if (!at || tt.equals(at))
3602 (*dedtypes)[i] = tt;
3603 goto Lexact;
3606 if (tp.isTemplateAliasParameter())
3608 Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
3609 if (!s2 || s == s2)
3611 (*dedtypes)[i] = s;
3612 goto Lexact;
3615 goto Lnomatch;
3618 // Found the corresponding parameter tp
3620 https://issues.dlang.org/show_bug.cgi?id=23578
3621 To pattern match:
3622 static if (is(S!int == S!av, alias av))
3624 We eventually need to deduce `int` (Tint32 [0]) and `av` (Tident).
3625 Previously this would not get pattern matched at all, but now we check if the
3626 template parameter `av` came from.
3628 This note has been left to serve as a hint for further explorers into
3629 how IsExp matching works.
3631 if (auto ta = tp.isTemplateAliasParameter())
3633 (*dedtypes)[i] = t;
3634 goto Lexact;
3636 // (23578) - ensure previous behaviour for non-alias template params
3637 if (!tp.isTemplateTypeParameter())
3639 goto Lnomatch;
3642 Type at = cast(Type)(*dedtypes)[i];
3643 Type tt;
3644 if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
3646 // type vs (none)
3647 if (!at)
3649 (*dedtypes)[i] = tt;
3650 *wm |= wx;
3651 result = MATCH.constant;
3652 return;
3655 // type vs expressions
3656 if (at.ty == Tnone)
3658 TypeDeduced xt = cast(TypeDeduced)at;
3659 result = xt.matchAll(tt);
3660 if (result > MATCH.nomatch)
3662 (*dedtypes)[i] = tt;
3663 if (result > MATCH.constant)
3664 result = MATCH.constant; // limit level for inout matches
3666 return;
3669 // type vs type
3670 if (tt.equals(at))
3672 (*dedtypes)[i] = tt; // Prefer current type match
3673 goto Lconst;
3675 if (tt.implicitConvTo(at.constOf()))
3677 (*dedtypes)[i] = at.constOf().mutableOf();
3678 *wm |= MODFlags.const_;
3679 goto Lconst;
3681 if (at.implicitConvTo(tt.constOf()))
3683 (*dedtypes)[i] = tt.constOf().mutableOf();
3684 *wm |= MODFlags.const_;
3685 goto Lconst;
3687 goto Lnomatch;
3689 else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
3691 // type vs (none)
3692 if (!at)
3694 (*dedtypes)[i] = tt;
3695 result = m;
3696 return;
3699 // type vs expressions
3700 if (at.ty == Tnone)
3702 TypeDeduced xt = cast(TypeDeduced)at;
3703 result = xt.matchAll(tt);
3704 if (result > MATCH.nomatch)
3706 (*dedtypes)[i] = tt;
3708 return;
3711 // type vs type
3712 if (tt.equals(at))
3714 goto Lexact;
3716 if (tt.ty == Tclass && at.ty == Tclass)
3718 result = tt.implicitConvTo(at);
3719 return;
3721 if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant)
3723 goto Lexact;
3726 goto Lnomatch;
3729 if (tparam.ty == Ttypeof)
3731 /* Need a loc to go with the semantic routine.
3733 Loc loc;
3734 if (parameters.length)
3736 TemplateParameter tp = (*parameters)[0];
3737 loc = tp.loc;
3740 tparam = tparam.typeSemantic(loc, sc);
3742 if (t.ty != tparam.ty)
3744 if (Dsymbol sym = t.toDsymbol(sc))
3746 if (sym.isforwardRef() && !tparam.deco)
3747 goto Lnomatch;
3750 MATCH m = t.implicitConvTo(tparam);
3751 if (m == MATCH.nomatch && !ignoreAliasThis)
3753 if (t.ty == Tclass)
3755 TypeClass tc = cast(TypeClass)t;
3756 if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
3758 if (auto ato = t.aliasthisOf())
3760 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT);
3761 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3762 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT);
3766 else if (t.ty == Tstruct)
3768 TypeStruct ts = cast(TypeStruct)t;
3769 if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
3771 if (auto ato = t.aliasthisOf())
3773 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT);
3774 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3775 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT);
3780 result = m;
3781 return;
3784 if (t.nextOf())
3786 if (tparam.deco && !tparam.hasWild())
3788 result = t.implicitConvTo(tparam);
3789 return;
3792 Type tpn = tparam.nextOf();
3793 if (wm && t.ty == Taarray && tparam.isWild())
3795 // https://issues.dlang.org/show_bug.cgi?id=12403
3796 // In IFTI, stop inout matching on transitive part of AA types.
3797 tpn = tpn.substWildTo(MODFlags.mutable);
3800 result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm);
3801 return;
3804 Lexact:
3805 result = MATCH.exact;
3806 return;
3808 Lnomatch:
3809 result = MATCH.nomatch;
3810 return;
3812 Lconst:
3813 result = MATCH.constant;
3816 override void visit(TypeVector t)
3818 if (tparam.ty == Tvector)
3820 TypeVector tp = cast(TypeVector)tparam;
3821 result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
3822 return;
3824 visit(cast(Type)t);
3827 override void visit(TypeDArray t)
3829 visit(cast(Type)t);
3832 override void visit(TypeSArray t)
3834 // Extra check that array dimensions must match
3835 if (tparam)
3837 if (tparam.ty == Tarray)
3839 MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3840 result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
3841 return;
3844 TemplateParameter tp = null;
3845 Expression edim = null;
3846 size_t i;
3847 if (tparam.ty == Tsarray)
3849 TypeSArray tsa = cast(TypeSArray)tparam;
3850 if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
3852 Identifier id = tsa.dim.isVarExp().var.ident;
3853 i = templateIdentifierLookup(id, parameters);
3854 assert(i != IDX_NOTFOUND);
3855 tp = (*parameters)[i];
3857 else
3858 edim = tsa.dim;
3860 else if (tparam.ty == Taarray)
3862 TypeAArray taa = cast(TypeAArray)tparam;
3863 i = templateParameterLookup(taa.index, parameters);
3864 if (i != IDX_NOTFOUND)
3865 tp = (*parameters)[i];
3866 else
3868 Loc loc;
3869 // The "type" (it hasn't been resolved yet) of the function parameter
3870 // does not have a location but the parameter it is related to does,
3871 // so we use that for the resolution (better error message).
3872 if (inferStart < parameters.length)
3874 TemplateParameter loctp = (*parameters)[inferStart];
3875 loc = loctp.loc;
3878 Expression e;
3879 Type tx;
3880 Dsymbol s;
3881 taa.index.resolve(loc, sc, e, tx, s);
3882 edim = s ? getValue(s) : getValue(e);
3885 if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
3887 result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3888 return;
3891 visit(cast(Type)t);
3894 override void visit(TypeAArray t)
3896 // Extra check that index type must match
3897 if (tparam && tparam.ty == Taarray)
3899 TypeAArray tp = cast(TypeAArray)tparam;
3900 if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
3902 result = MATCH.nomatch;
3903 return;
3906 visit(cast(Type)t);
3909 override void visit(TypeFunction t)
3911 // Extra check that function characteristics must match
3912 if (!tparam)
3913 return visit(cast(Type)t);
3915 if (auto tp = tparam.isTypeFunction())
3917 if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
3919 result = MATCH.nomatch;
3920 return;
3923 foreach (fparam; *tp.parameterList.parameters)
3925 // https://issues.dlang.org/show_bug.cgi?id=2579
3926 // Apply function parameter storage classes to parameter types
3927 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
3928 fparam.storageClass &= ~STC.TYPECTOR;
3930 // https://issues.dlang.org/show_bug.cgi?id=15243
3931 // Resolve parameter type if it's not related with template parameters
3932 if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length]))
3934 auto tx = fparam.type.typeSemantic(Loc.initial, sc);
3935 if (tx.ty == Terror)
3937 result = MATCH.nomatch;
3938 return;
3940 fparam.type = tx;
3944 size_t nfargs = t.parameterList.length;
3945 size_t nfparams = tp.parameterList.length;
3947 /* See if tuple match
3949 if (nfparams > 0 && nfargs >= nfparams - 1)
3951 /* See if 'A' of the template parameter matches 'A'
3952 * of the type of the last function parameter.
3954 Parameter fparam = tp.parameterList[nfparams - 1];
3955 assert(fparam);
3956 assert(fparam.type);
3957 if (fparam.type.ty != Tident)
3958 goto L1;
3959 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
3960 if (tid.idents.length)
3961 goto L1;
3963 /* Look through parameters to find tuple matching tid.ident
3965 size_t tupi = 0;
3966 for (; 1; tupi++)
3968 if (tupi == parameters.length)
3969 goto L1;
3970 TemplateParameter tx = (*parameters)[tupi];
3971 TemplateTupleParameter tup = tx.isTemplateTupleParameter();
3972 if (tup && tup.ident.equals(tid.ident))
3973 break;
3976 /* The types of the function arguments [nfparams - 1 .. nfargs]
3977 * now form the tuple argument.
3979 size_t tuple_dim = nfargs - (nfparams - 1);
3981 /* See if existing tuple, and whether it matches or not
3983 RootObject o = (*dedtypes)[tupi];
3984 if (o)
3986 // Existing deduced argument must be a tuple, and must match
3987 Tuple tup = isTuple(o);
3988 if (!tup || tup.objects.length != tuple_dim)
3990 result = MATCH.nomatch;
3991 return;
3993 for (size_t i = 0; i < tuple_dim; i++)
3995 Parameter arg = t.parameterList[nfparams - 1 + i];
3996 if (!arg.type.equals(tup.objects[i]))
3998 result = MATCH.nomatch;
3999 return;
4003 else
4005 // Create new tuple
4006 auto tup = new Tuple(tuple_dim);
4007 for (size_t i = 0; i < tuple_dim; i++)
4009 Parameter arg = t.parameterList[nfparams - 1 + i];
4010 tup.objects[i] = arg.type;
4012 (*dedtypes)[tupi] = tup;
4014 nfparams--; // don't consider the last parameter for type deduction
4015 goto L2;
4019 if (nfargs != nfparams)
4021 result = MATCH.nomatch;
4022 return;
4025 assert(nfparams <= tp.parameterList.length);
4026 foreach (i, ap; tp.parameterList)
4028 if (i == nfparams)
4029 break;
4031 Parameter a = t.parameterList[i];
4033 if (!a.isCovariant(t.isref, ap) ||
4034 !deduceType(a.type, sc, ap.type, parameters, dedtypes))
4036 result = MATCH.nomatch;
4037 return;
4041 visit(cast(Type)t);
4044 override void visit(TypeIdentifier t)
4046 // Extra check
4047 if (tparam && tparam.ty == Tident)
4049 TypeIdentifier tp = cast(TypeIdentifier)tparam;
4050 for (size_t i = 0; i < t.idents.length; i++)
4052 RootObject id1 = t.idents[i];
4053 RootObject id2 = tp.idents[i];
4054 if (!id1.equals(id2))
4056 result = MATCH.nomatch;
4057 return;
4061 visit(cast(Type)t);
4064 override void visit(TypeInstance t)
4066 // Extra check
4067 if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl)
4069 TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
4070 assert(tempdecl);
4072 TypeInstance tp = cast(TypeInstance)tparam;
4074 //printf("tempinst.tempdecl = %p\n", tempdecl);
4075 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
4076 if (!tp.tempinst.tempdecl)
4078 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
4080 /* Handle case of:
4081 * template Foo(T : sa!(T), alias sa)
4083 size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
4084 if (i == IDX_NOTFOUND)
4086 /* Didn't find it as a parameter identifier. Try looking
4087 * it up and seeing if is an alias.
4088 * https://issues.dlang.org/show_bug.cgi?id=1454
4090 auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name);
4091 Type tx;
4092 Expression e;
4093 Dsymbol s;
4094 tid.resolve(tp.loc, sc, e, tx, s);
4095 if (tx)
4097 s = tx.toDsymbol(sc);
4098 if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null)
4100 // https://issues.dlang.org/show_bug.cgi?id=14290
4101 // Try to match with ti.tempecl,
4102 // only when ti is an enclosing instance.
4103 Dsymbol p = sc.parent;
4104 while (p && p != ti)
4105 p = p.parent;
4106 if (p)
4107 s = ti.tempdecl;
4110 if (s)
4112 s = s.toAlias();
4113 TemplateDeclaration td = s.isTemplateDeclaration();
4114 if (td)
4116 if (td.overroot)
4117 td = td.overroot;
4118 for (; td; td = td.overnext)
4120 if (td == tempdecl)
4121 goto L2;
4125 goto Lnomatch;
4128 TemplateParameter tpx = (*parameters)[i];
4129 if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
4130 goto Lnomatch;
4132 else if (tempdecl != tp.tempinst.tempdecl)
4133 goto Lnomatch;
4136 if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes))
4137 goto Lnomatch;
4139 visit(cast(Type)t);
4140 return;
4142 Lnomatch:
4143 //printf("no match\n");
4144 result = MATCH.nomatch;
4147 /********************
4148 * Match template `parameters` to the target template instance.
4149 * Example:
4150 * struct Temp(U, int Z) {}
4151 * void foo(T)(Temp!(T, 3));
4152 * foo(Temp!(int, 3)());
4153 * Input:
4154 * this.parameters = template params of foo -> [T]
4155 * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3]
4156 * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3]
4157 * tempdecl = <struct Temp!(T, int Z)> -> [T, Z]
4158 * tp = <Temp!(T, 3)>
4159 * Output:
4160 * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int]
4162 private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes)
4164 for (size_t i = 0; 1; i++)
4166 //printf("\ttest: tempinst.tiargs[%zu]\n", i);
4167 RootObject o1 = null;
4168 if (i < tiargs.length)
4169 o1 = (*tiargs)[i];
4170 else if (i < tdtypes.length && i < tp.tempinst.tiargs.length)
4172 // Pick up default arg
4173 o1 = (*tdtypes)[i];
4175 else if (i >= tp.tempinst.tiargs.length)
4176 break;
4177 //printf("\ttest: o1 = %s\n", o1.toChars());
4178 if (i >= tp.tempinst.tiargs.length)
4180 size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
4181 while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
4183 i++;
4185 if (i >= dim)
4186 break; // match if all remained parameters are dependent
4187 return false;
4190 RootObject o2 = (*tp.tempinst.tiargs)[i];
4191 Type t2 = isType(o2);
4192 //printf("\ttest: o2 = %s\n", o2.toChars());
4193 size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
4194 ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
4195 if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
4196 (*parameters)[j].isTemplateTupleParameter())
4198 /* Given:
4199 * struct A(B...) {}
4200 * alias A!(int, float) X;
4201 * static if (is(X Y == A!(Z), Z...)) {}
4202 * deduce that Z is a tuple(int, float)
4205 /* Create tuple from remaining args
4207 size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i;
4208 auto vt = new Tuple(vtdim);
4209 for (size_t k = 0; k < vtdim; k++)
4211 RootObject o;
4212 if (k < tiargs.length)
4213 o = (*tiargs)[i + k];
4214 else // Pick up default arg
4215 o = (*tdtypes)[i + k];
4216 vt.objects[k] = o;
4219 Tuple v = cast(Tuple)(*dedtypes)[j];
4220 if (v)
4222 if (!match(v, vt))
4223 return false;
4225 else
4226 (*dedtypes)[j] = vt;
4227 break;
4229 else if (!o1)
4230 break;
4232 Type t1 = isType(o1);
4233 Dsymbol s1 = isDsymbol(o1);
4234 Dsymbol s2 = isDsymbol(o2);
4235 Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
4236 Expression e2 = isExpression(o2);
4237 version (none)
4239 Tuple v1 = isTuple(o1);
4240 Tuple v2 = isTuple(o2);
4241 if (t1)
4242 printf("t1 = %s\n", t1.toChars());
4243 if (t2)
4244 printf("t2 = %s\n", t2.toChars());
4245 if (e1)
4246 printf("e1 = %s\n", e1.toChars());
4247 if (e2)
4248 printf("e2 = %s\n", e2.toChars());
4249 if (s1)
4250 printf("s1 = %s\n", s1.toChars());
4251 if (s2)
4252 printf("s2 = %s\n", s2.toChars());
4253 if (v1)
4254 printf("v1 = %s\n", v1.toChars());
4255 if (v2)
4256 printf("v2 = %s\n", v2.toChars());
4259 if (t1 && t2)
4261 if (!deduceType(t1, sc, t2, parameters, dedtypes))
4262 return false;
4264 else if (e1 && e2)
4267 e1 = e1.ctfeInterpret();
4269 /* If it is one of the template parameters for this template,
4270 * we should not attempt to interpret it. It already has a value.
4272 if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
4275 * (T:Number!(e2), int e2)
4277 j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
4278 if (j != IDX_NOTFOUND)
4279 goto L1;
4280 // The template parameter was not from this template
4281 // (it may be from a parent template, for example)
4284 e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
4285 e2 = e2.ctfeInterpret();
4287 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
4288 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
4289 if (!e1.equals(e2))
4291 if (!e2.implicitConvTo(e1.type))
4292 return false;
4294 e2 = e2.implicitCastTo(sc, e1.type);
4295 e2 = e2.ctfeInterpret();
4296 if (!e1.equals(e2))
4297 return false;
4300 else if (e1 && t2 && t2.ty == Tident)
4302 j = templateParameterLookup(t2, parameters);
4304 if (j == IDX_NOTFOUND)
4306 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4307 if (e2)
4308 goto Le;
4309 return false;
4311 if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
4312 return false;
4314 else if (s1 && s2)
4317 if (!s1.equals(s2))
4318 return false;
4320 else if (s1 && t2 && t2.ty == Tident)
4322 j = templateParameterLookup(t2, parameters);
4323 if (j == IDX_NOTFOUND)
4325 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4326 if (s2)
4327 goto Ls;
4328 return false;
4330 if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
4331 return false;
4333 else
4334 return false;
4336 return true;
4339 override void visit(TypeStruct t)
4341 /* If this struct is a template struct, and we're matching
4342 * it against a template instance, convert the struct type
4343 * to a template instance, too, and try again.
4345 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4347 if (tparam && tparam.ty == Tinstance)
4349 if (ti && ti.toAlias() == t.sym)
4351 auto tx = new TypeInstance(Loc.initial, ti);
4352 auto m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4353 // if we have a no match we still need to check alias this
4354 if (m != MATCH.nomatch)
4356 result = m;
4357 return;
4361 /* Match things like:
4362 * S!(T).foo
4364 TypeInstance tpi = cast(TypeInstance)tparam;
4365 if (tpi.idents.length)
4367 RootObject id = tpi.idents[tpi.idents.length - 1];
4368 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4370 Type tparent = t.sym.parent.getType();
4371 if (tparent)
4373 /* Slice off the .foo in S!(T).foo
4375 tpi.idents.length--;
4376 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4377 tpi.idents.length++;
4378 return;
4384 // Extra check
4385 if (tparam && tparam.ty == Tstruct)
4387 TypeStruct tp = cast(TypeStruct)tparam;
4389 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4390 if (wm && t.deduceWild(tparam, false))
4392 result = MATCH.constant;
4393 return;
4395 result = t.implicitConvTo(tp);
4396 return;
4398 visit(cast(Type)t);
4401 override void visit(TypeEnum t)
4403 // Extra check
4404 if (tparam && tparam.ty == Tenum)
4406 TypeEnum tp = cast(TypeEnum)tparam;
4407 if (t.sym == tp.sym)
4408 visit(cast(Type)t);
4409 else
4410 result = MATCH.nomatch;
4411 return;
4413 Type tb = t.toBasetype();
4414 if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray)
4416 result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
4417 if (result == MATCH.exact)
4418 result = MATCH.convert;
4419 return;
4421 visit(cast(Type)t);
4424 /* Helper for TypeClass.deduceType().
4425 * Classes can match with implicit conversion to a base class or interface.
4426 * This is complicated, because there may be more than one base class which
4427 * matches. In such cases, one or more parameters remain ambiguous.
4428 * For example,
4430 * interface I(X, Y) {}
4431 * class C : I(uint, double), I(char, double) {}
4432 * C x;
4433 * foo(T, U)( I!(T, U) x)
4435 * deduces that U is double, but T remains ambiguous (could be char or uint).
4437 * Given a baseclass b, and initial deduced types 'dedtypes', this function
4438 * tries to match tparam with b, and also tries all base interfaces of b.
4439 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
4440 * types are ANDed with the current 'best' estimate for dedtypes.
4442 static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
4444 TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
4445 if (parti)
4447 // Make a temporary copy of dedtypes so we don't destroy it
4448 auto tmpdedtypes = new Objects(dedtypes.length);
4449 memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
4451 auto t = new TypeInstance(Loc.initial, parti);
4452 MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
4453 if (m > MATCH.nomatch)
4455 // If this is the first ever match, it becomes our best estimate
4456 if (numBaseClassMatches == 0)
4457 memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
4458 else
4459 for (size_t k = 0; k < tmpdedtypes.length; ++k)
4461 // If we've found more than one possible type for a parameter,
4462 // mark it as unknown.
4463 if ((*tmpdedtypes)[k] != (*best)[k])
4464 (*best)[k] = (*dedtypes)[k];
4466 ++numBaseClassMatches;
4470 // Now recursively test the inherited interfaces
4471 foreach (ref bi; b.baseInterfaces)
4473 deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4477 override void visit(TypeClass t)
4479 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
4481 /* If this class is a template class, and we're matching
4482 * it against a template instance, convert the class type
4483 * to a template instance, too, and try again.
4485 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4487 if (tparam && tparam.ty == Tinstance)
4489 if (ti && ti.toAlias() == t.sym)
4491 auto tx = new TypeInstance(Loc.initial, ti);
4492 MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4493 // Even if the match fails, there is still a chance it could match
4494 // a base class.
4495 if (m != MATCH.nomatch)
4497 result = m;
4498 return;
4502 /* Match things like:
4503 * S!(T).foo
4505 TypeInstance tpi = cast(TypeInstance)tparam;
4506 if (tpi.idents.length)
4508 RootObject id = tpi.idents[tpi.idents.length - 1];
4509 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4511 Type tparent = t.sym.parent.getType();
4512 if (tparent)
4514 /* Slice off the .foo in S!(T).foo
4516 tpi.idents.length--;
4517 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4518 tpi.idents.length++;
4519 return;
4524 // If it matches exactly or via implicit conversion, we're done
4525 visit(cast(Type)t);
4526 if (result != MATCH.nomatch)
4527 return;
4529 /* There is still a chance to match via implicit conversion to
4530 * a base class or interface. Because there could be more than one such
4531 * match, we need to check them all.
4534 int numBaseClassMatches = 0; // Have we found an interface match?
4536 // Our best guess at dedtypes
4537 auto best = new Objects(dedtypes.length);
4539 ClassDeclaration s = t.sym;
4540 while (s && s.baseclasses.length > 0)
4542 // Test the base class
4543 deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4545 // Test the interfaces inherited by the base class
4546 foreach (b; s.interfaces)
4548 deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4550 s = (*s.baseclasses)[0].sym;
4553 if (numBaseClassMatches == 0)
4555 result = MATCH.nomatch;
4556 return;
4559 // If we got at least one match, copy the known types into dedtypes
4560 memcpy(dedtypes.tdata(), best.tdata(), best.length * (void*).sizeof);
4561 result = MATCH.convert;
4562 return;
4565 // Extra check
4566 if (tparam && tparam.ty == Tclass)
4568 TypeClass tp = cast(TypeClass)tparam;
4570 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4571 if (wm && t.deduceWild(tparam, false))
4573 result = MATCH.constant;
4574 return;
4576 result = t.implicitConvTo(tp);
4577 return;
4579 visit(cast(Type)t);
4582 override void visit(Expression e)
4584 //printf("Expression.deduceType(e = %s)\n", e.toChars());
4585 size_t i = templateParameterLookup(tparam, parameters);
4586 if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0)
4588 if (e == emptyArrayElement && tparam.ty == Tarray)
4590 Type tn = (cast(TypeNext)tparam).next;
4591 result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4592 return;
4594 e.type.accept(this);
4595 return;
4598 TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
4599 if (!tp)
4600 return; // nomatch
4602 if (e == emptyArrayElement)
4604 if ((*dedtypes)[i])
4606 result = MATCH.exact;
4607 return;
4609 if (tp.defaultType)
4611 tp.defaultType.accept(this);
4612 return;
4616 /* Returns `true` if `t` is a reference type, or an array of reference types
4618 bool isTopRef(Type t)
4620 auto tb = t.baseElemOf();
4621 return tb.ty == Tclass ||
4622 tb.ty == Taarray ||
4623 tb.ty == Tstruct && tb.hasPointers();
4626 Type at = cast(Type)(*dedtypes)[i];
4627 Type tt;
4628 if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
4630 *wm |= wx;
4631 result = MATCH.constant;
4633 else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
4635 result = m;
4637 else if (!isTopRef(e.type))
4639 /* https://issues.dlang.org/show_bug.cgi?id=15653
4640 * In IFTI, recognize top-qualifier conversions
4641 * through the value copy, e.g.
4642 * int --> immutable(int)
4643 * immutable(string[]) --> immutable(string)[]
4645 tt = e.type.mutableOf();
4646 result = MATCH.convert;
4648 else
4649 return; // nomatch
4651 // expression vs (none)
4652 if (!at)
4654 (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
4655 return;
4658 TypeDeduced xt = null;
4659 if (at.ty == Tnone)
4661 xt = cast(TypeDeduced)at;
4662 at = xt.tded;
4665 // From previous matched expressions to current deduced type
4666 MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch;
4668 // From current expressions to previous deduced type
4669 Type pt = at.addMod(tparam.mod);
4670 if (*wm)
4671 pt = pt.substWildTo(*wm);
4672 MATCH match2 = e.implicitConvTo(pt);
4674 if (match1 > MATCH.nomatch && match2 > MATCH.nomatch)
4676 if (at.implicitConvTo(tt) == MATCH.nomatch)
4677 match1 = MATCH.nomatch; // Prefer at
4678 else if (tt.implicitConvTo(at) == MATCH.nomatch)
4679 match2 = MATCH.nomatch; // Prefer tt
4680 else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod)
4682 if (!tt.isMutable() && !at.isMutable())
4683 tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod));
4684 else if (tt.isMutable())
4686 if (at.mod == 0) // Prefer unshared
4687 match1 = MATCH.nomatch;
4688 else
4689 match2 = MATCH.nomatch;
4691 else if (at.isMutable())
4693 if (tt.mod == 0) // Prefer unshared
4694 match2 = MATCH.nomatch;
4695 else
4696 match1 = MATCH.nomatch;
4698 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
4700 else
4702 match1 = MATCH.nomatch;
4703 match2 = MATCH.nomatch;
4706 if (match1 > MATCH.nomatch)
4708 // Prefer current match: tt
4709 if (xt)
4710 xt.update(tt, e, tparam);
4711 else
4712 (*dedtypes)[i] = tt;
4713 result = match1;
4714 return;
4716 if (match2 > MATCH.nomatch)
4718 // Prefer previous match: (*dedtypes)[i]
4719 if (xt)
4720 xt.update(e, tparam);
4721 result = match2;
4722 return;
4725 /* Deduce common type
4727 if (Type t = rawTypeMerge(at, tt))
4729 if (xt)
4730 xt.update(t, e, tparam);
4731 else
4732 (*dedtypes)[i] = t;
4734 pt = tt.addMod(tparam.mod);
4735 if (*wm)
4736 pt = pt.substWildTo(*wm);
4737 result = e.implicitConvTo(pt);
4738 return;
4741 result = MATCH.nomatch;
4744 MATCH deduceEmptyArrayElement()
4746 if (!emptyArrayElement)
4748 emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy
4749 emptyArrayElement.type = Type.tvoid;
4751 assert(tparam.ty == Tarray);
4753 Type tn = (cast(TypeNext)tparam).next;
4754 return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4757 override void visit(NullExp e)
4759 if (tparam.ty == Tarray && e.type.ty == Tnull)
4761 // tparam:T[] <- e:null (void[])
4762 result = deduceEmptyArrayElement();
4763 return;
4765 visit(cast(Expression)e);
4768 override void visit(StringExp e)
4770 Type taai;
4771 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
4773 // Consider compile-time known boundaries
4774 e.type.nextOf().sarrayOf(e.len).accept(this);
4775 return;
4777 visit(cast(Expression)e);
4780 override void visit(ArrayLiteralExp e)
4782 // https://issues.dlang.org/show_bug.cgi?id=20092
4783 if (e.elements && e.elements.length && e.type.toBasetype().nextOf().ty == Tvoid)
4785 result = deduceEmptyArrayElement();
4786 return;
4788 if ((!e.elements || !e.elements.length) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray)
4790 // tparam:T[] <- e:[] (void[])
4791 result = deduceEmptyArrayElement();
4792 return;
4795 if (tparam.ty == Tarray && e.elements && e.elements.length)
4797 Type tn = (cast(TypeDArray)tparam).next;
4798 result = MATCH.exact;
4799 if (e.basis)
4801 MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm);
4802 if (m < result)
4803 result = m;
4805 foreach (el; *e.elements)
4807 if (result == MATCH.nomatch)
4808 break;
4809 if (!el)
4810 continue;
4811 MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
4812 if (m < result)
4813 result = m;
4815 return;
4818 Type taai;
4819 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
4821 // Consider compile-time known boundaries
4822 e.type.nextOf().sarrayOf(e.elements.length).accept(this);
4823 return;
4825 visit(cast(Expression)e);
4828 override void visit(AssocArrayLiteralExp e)
4830 if (tparam.ty == Taarray && e.keys && e.keys.length)
4832 TypeAArray taa = cast(TypeAArray)tparam;
4833 result = MATCH.exact;
4834 foreach (i, key; *e.keys)
4836 MATCH m1 = deduceType(key, sc, taa.index, parameters, dedtypes, wm);
4837 if (m1 < result)
4838 result = m1;
4839 if (result == MATCH.nomatch)
4840 break;
4841 MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm);
4842 if (m2 < result)
4843 result = m2;
4844 if (result == MATCH.nomatch)
4845 break;
4847 return;
4849 visit(cast(Expression)e);
4852 override void visit(FuncExp e)
4854 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
4855 if (e.td)
4857 Type to = tparam;
4858 if (!to.nextOf())
4859 return;
4860 auto tof = to.nextOf().isTypeFunction();
4861 if (!tof)
4862 return;
4864 // Parameter types inference from 'tof'
4865 assert(e.td._scope);
4866 TypeFunction tf = cast(TypeFunction)e.fd.type;
4867 //printf("\ttof = %s\n", tof.toChars());
4868 //printf("\ttf = %s\n", tf.toChars());
4869 const dim = tf.parameterList.length;
4871 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
4872 return;
4874 auto tiargs = new Objects();
4875 tiargs.reserve(e.td.parameters.length);
4877 foreach (tp; *e.td.parameters)
4879 size_t u = 0;
4880 foreach (i, p; tf.parameterList)
4882 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4883 break;
4884 ++u;
4886 assert(u < dim);
4887 Parameter pto = tof.parameterList[u];
4888 if (!pto)
4889 break;
4890 Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
4891 if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length]))
4892 return;
4893 t = t.typeSemantic(e.loc, sc);
4894 if (t.ty == Terror)
4895 return;
4896 tiargs.push(t);
4899 // Set target of return type inference
4900 if (!tf.next && tof.next)
4901 e.fd.treq = tparam;
4903 auto ti = new TemplateInstance(e.loc, e.td, tiargs);
4904 Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope);
4906 // Reset inference target for the later re-semantic
4907 e.fd.treq = null;
4909 if (ex.op == EXP.error)
4910 return;
4911 if (ex.op != EXP.function_)
4912 return;
4913 visit(ex.type);
4914 return;
4917 Type t = e.type;
4919 if (t.ty == Tdelegate && tparam.ty == Tpointer)
4920 return;
4922 // Allow conversion from implicit function pointer to delegate
4923 if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
4925 TypeFunction tf = cast(TypeFunction)t.nextOf();
4926 t = (new TypeDelegate(tf)).merge();
4928 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
4929 visit(t);
4932 override void visit(SliceExp e)
4934 Type taai;
4935 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
4937 // Consider compile-time known boundaries
4938 if (Type tsa = toStaticArrayType(e))
4940 tsa.accept(this);
4941 if (result > MATCH.convert)
4942 result = MATCH.convert; // match with implicit conversion at most
4943 return;
4946 visit(cast(Expression)e);
4949 override void visit(CommaExp e)
4951 e.e2.accept(this);
4955 scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
4956 if (Type t = isType(o))
4957 t.accept(v);
4958 else if (Expression e = isExpression(o))
4960 assert(wm);
4961 e.accept(v);
4963 else
4964 assert(0);
4965 return v.result;
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.
4973 * iStart = Start index of tparams to limit the tested parameters. If it's
4974 * nonzero, tparams[0..iStart] will be excluded from the test target.
4976 bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
4978 return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.length]);
4981 /***********************************************************
4982 * Check whether the type t representation relies on one or more the template parameters.
4983 * Params:
4984 * t = Tested type, if null, returns false.
4985 * tparams = Template parameters.
4987 private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
4989 bool visitVector(TypeVector t)
4991 return t.basetype.reliesOnTemplateParameters(tparams);
4994 bool visitAArray(TypeAArray t)
4996 return t.next.reliesOnTemplateParameters(tparams) ||
4997 t.index.reliesOnTemplateParameters(tparams);
5000 bool visitFunction(TypeFunction t)
5002 foreach (i, fparam; t.parameterList)
5004 if (fparam.type.reliesOnTemplateParameters(tparams))
5005 return true;
5007 return t.next.reliesOnTemplateParameters(tparams);
5010 bool visitIdentifier(TypeIdentifier t)
5012 foreach (tp; tparams)
5014 if (tp.ident.equals(t.ident))
5015 return true;
5017 return false;
5020 bool visitInstance(TypeInstance t)
5022 foreach (tp; tparams)
5024 if (t.tempinst.name == tp.ident)
5025 return true;
5028 if (t.tempinst.tiargs)
5029 foreach (arg; *t.tempinst.tiargs)
5031 if (Type ta = isType(arg))
5033 if (ta.reliesOnTemplateParameters(tparams))
5034 return true;
5038 return false;
5041 bool visitTypeof(TypeTypeof t)
5043 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
5044 return t.exp.reliesOnTemplateParameters(tparams);
5047 bool visitTuple(TypeTuple t)
5049 if (t.arguments)
5050 foreach (arg; *t.arguments)
5052 if (arg.type.reliesOnTemplateParameters(tparams))
5053 return true;
5056 return false;
5059 if (!t)
5060 return false;
5062 Type tb = t.toBasetype();
5063 switch (tb.ty)
5065 case Tvector: return visitVector(tb.isTypeVector());
5066 case Taarray: return visitAArray(tb.isTypeAArray());
5067 case Tfunction: return visitFunction(tb.isTypeFunction());
5068 case Tident: return visitIdentifier(tb.isTypeIdentifier());
5069 case Tinstance: return visitInstance(tb.isTypeInstance());
5070 case Ttypeof: return visitTypeof(tb.isTypeTypeof());
5071 case Ttuple: return visitTuple(tb.isTypeTuple());
5072 case Tenum: return false;
5073 default: return tb.nextOf().reliesOnTemplateParameters(tparams);
5077 /***********************************************************
5078 * Check whether the expression representation relies on one or more the template parameters.
5079 * Params:
5080 * e = expression to test
5081 * tparams = Template parameters.
5082 * Returns:
5083 * true if it does
5085 private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
5087 extern (C++) final class ReliesOnTemplateParameters : Visitor
5089 alias visit = Visitor.visit;
5090 public:
5091 TemplateParameter[] tparams;
5092 bool result;
5094 extern (D) this(TemplateParameter[] tparams) @safe
5096 this.tparams = tparams;
5099 override void visit(Expression e)
5101 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
5104 override void visit(IdentifierExp e)
5106 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5107 foreach (tp; tparams)
5109 if (e.ident == tp.ident)
5111 result = true;
5112 return;
5117 override void visit(TupleExp e)
5119 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5120 if (e.exps)
5122 foreach (ea; *e.exps)
5124 ea.accept(this);
5125 if (result)
5126 return;
5131 override void visit(ArrayLiteralExp e)
5133 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5134 if (e.elements)
5136 foreach (el; *e.elements)
5138 el.accept(this);
5139 if (result)
5140 return;
5145 override void visit(AssocArrayLiteralExp e)
5147 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5148 foreach (ek; *e.keys)
5150 ek.accept(this);
5151 if (result)
5152 return;
5154 foreach (ev; *e.values)
5156 ev.accept(this);
5157 if (result)
5158 return;
5162 override void visit(StructLiteralExp e)
5164 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5165 if (e.elements)
5167 foreach (ea; *e.elements)
5169 ea.accept(this);
5170 if (result)
5171 return;
5176 override void visit(TypeExp e)
5178 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5179 result = e.type.reliesOnTemplateParameters(tparams);
5182 override void visit(NewExp e)
5184 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5185 if (e.thisexp)
5186 e.thisexp.accept(this);
5187 result = e.newtype.reliesOnTemplateParameters(tparams);
5188 if (!result && e.arguments)
5190 foreach (ea; *e.arguments)
5192 ea.accept(this);
5193 if (result)
5194 return;
5199 override void visit(NewAnonClassExp e)
5201 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5202 result = true;
5205 override void visit(FuncExp e)
5207 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5208 result = true;
5211 override void visit(TypeidExp e)
5213 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5214 if (auto ea = isExpression(e.obj))
5215 ea.accept(this);
5216 else if (auto ta = isType(e.obj))
5217 result = ta.reliesOnTemplateParameters(tparams);
5220 override void visit(TraitsExp e)
5222 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5223 if (e.args)
5225 foreach (oa; *e.args)
5227 if (auto ea = isExpression(oa))
5228 ea.accept(this);
5229 else if (auto ta = isType(oa))
5230 result = ta.reliesOnTemplateParameters(tparams);
5231 if (result)
5232 return;
5237 override void visit(IsExp e)
5239 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5240 result = e.targ.reliesOnTemplateParameters(tparams);
5243 override void visit(UnaExp e)
5245 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5246 e.e1.accept(this);
5249 override void visit(DotTemplateInstanceExp e)
5251 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5252 visit(e.isUnaExp());
5253 if (!result && e.ti.tiargs)
5255 foreach (oa; *e.ti.tiargs)
5257 if (auto ea = isExpression(oa))
5258 ea.accept(this);
5259 else if (auto ta = isType(oa))
5260 result = ta.reliesOnTemplateParameters(tparams);
5261 if (result)
5262 return;
5267 override void visit(CallExp e)
5269 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5270 visit(e.isUnaExp());
5271 if (!result && e.arguments)
5273 foreach (ea; *e.arguments)
5275 ea.accept(this);
5276 if (result)
5277 return;
5282 override void visit(CastExp e)
5284 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5285 visit(e.isUnaExp());
5286 // e.to can be null for cast() with no type
5287 if (!result && e.to)
5288 result = e.to.reliesOnTemplateParameters(tparams);
5291 override void visit(SliceExp e)
5293 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5294 visit(e.isUnaExp());
5295 if (!result && e.lwr)
5296 e.lwr.accept(this);
5297 if (!result && e.upr)
5298 e.upr.accept(this);
5301 override void visit(IntervalExp e)
5303 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5304 e.lwr.accept(this);
5305 if (!result)
5306 e.upr.accept(this);
5309 override void visit(ArrayExp e)
5311 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5312 visit(e.isUnaExp());
5313 if (!result && e.arguments)
5315 foreach (ea; *e.arguments)
5316 ea.accept(this);
5320 override void visit(BinExp e)
5322 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5323 e.e1.accept(this);
5324 if (!result)
5325 e.e2.accept(this);
5328 override void visit(CondExp e)
5330 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5331 e.econd.accept(this);
5332 if (!result)
5333 visit(e.isBinExp());
5337 scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
5338 e.accept(v);
5339 return v.result;
5342 /***********************************************************
5343 * https://dlang.org/spec/template.html#TemplateParameter
5345 extern (C++) class TemplateParameter : ASTNode
5347 Loc loc;
5348 Identifier ident;
5350 /* True if this is a part of precedent parameter specialization pattern.
5352 * template A(T : X!TL, alias X, TL...) {}
5353 * // X and TL are dependent template parameter
5355 * A dependent template parameter should return MATCH.exact in matchArg()
5356 * to respect the match level of the corresponding precedent parameter.
5358 bool dependent;
5360 /* ======================== TemplateParameter =============================== */
5361 extern (D) this(const ref Loc loc, Identifier ident) @safe
5363 this.loc = loc;
5364 this.ident = ident;
5367 TemplateTypeParameter isTemplateTypeParameter()
5369 return null;
5372 TemplateValueParameter isTemplateValueParameter()
5374 return null;
5377 TemplateAliasParameter isTemplateAliasParameter()
5379 return null;
5382 TemplateThisParameter isTemplateThisParameter()
5384 return null;
5387 TemplateTupleParameter isTemplateTupleParameter()
5389 return null;
5392 abstract TemplateParameter syntaxCopy();
5394 abstract bool declareParameter(Scope* sc);
5396 abstract void print(RootObject oarg, RootObject oded);
5398 abstract RootObject specialization();
5400 abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
5402 abstract bool hasDefaultArg();
5404 override const(char)* toChars() const
5406 return this.ident.toChars();
5409 override DYNCAST dyncast() const
5411 return DYNCAST.templateparameter;
5414 /* Create dummy argument based on parameter.
5416 abstract RootObject dummyArg();
5418 override void accept(Visitor v)
5420 v.visit(this);
5424 /***********************************************************
5425 * https://dlang.org/spec/template.html#TemplateTypeParameter
5426 * Syntax:
5427 * ident : specType = defaultType
5429 extern (C++) class TemplateTypeParameter : TemplateParameter
5431 Type specType; // if !=null, this is the type specialization
5432 Type defaultType;
5434 extern (D) __gshared Type tdummy = null;
5436 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType) @safe
5438 super(loc, ident);
5439 this.specType = specType;
5440 this.defaultType = defaultType;
5443 override final TemplateTypeParameter isTemplateTypeParameter()
5445 return this;
5448 override TemplateTypeParameter syntaxCopy()
5450 return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5453 override final bool declareParameter(Scope* sc)
5455 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
5456 auto ti = new TypeIdentifier(loc, ident);
5457 Declaration ad = new AliasDeclaration(loc, ident, ti);
5458 return sc.insert(ad) !is null;
5461 override final void print(RootObject oarg, RootObject oded)
5463 printf(" %s\n", ident.toChars());
5465 Type t = isType(oarg);
5466 Type ta = isType(oded);
5467 assert(ta);
5469 if (specType)
5470 printf("\tSpecialization: %s\n", specType.toChars());
5471 if (defaultType)
5472 printf("\tDefault: %s\n", defaultType.toChars());
5473 printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
5474 printf("\tDeduced Type: %s\n", ta.toChars());
5477 override final RootObject specialization()
5479 return specType;
5482 override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5484 Type t = defaultType;
5485 if (t)
5487 t = t.syntaxCopy();
5488 t = t.typeSemantic(loc, sc); // use the parameter loc
5490 return t;
5493 override final bool hasDefaultArg()
5495 return defaultType !is null;
5498 override final RootObject dummyArg()
5500 Type t = specType;
5501 if (!t)
5503 // Use this for alias-parameter's too (?)
5504 if (!tdummy)
5505 tdummy = new TypeIdentifier(loc, ident);
5506 t = tdummy;
5508 return t;
5511 override void accept(Visitor v)
5513 v.visit(this);
5517 /***********************************************************
5518 * https://dlang.org/spec/template.html#TemplateThisParameter
5519 * Syntax:
5520 * this ident : specType = defaultType
5522 extern (C++) final class TemplateThisParameter : TemplateTypeParameter
5524 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType) @safe
5526 super(loc, ident, specType, defaultType);
5529 override TemplateThisParameter isTemplateThisParameter()
5531 return this;
5534 override TemplateThisParameter syntaxCopy()
5536 return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5539 override void accept(Visitor v)
5541 v.visit(this);
5545 /***********************************************************
5546 * https://dlang.org/spec/template.html#TemplateValueParameter
5547 * Syntax:
5548 * valType ident : specValue = defaultValue
5550 extern (C++) final class TemplateValueParameter : TemplateParameter
5552 Type valType;
5553 Expression specValue;
5554 Expression defaultValue;
5556 extern (D) __gshared Expression[void*] edummies;
5558 extern (D) this(const ref Loc loc, Identifier ident, Type valType,
5559 Expression specValue, Expression defaultValue) @safe
5561 super(loc, ident);
5562 this.valType = valType;
5563 this.specValue = specValue;
5564 this.defaultValue = defaultValue;
5567 override TemplateValueParameter isTemplateValueParameter()
5569 return this;
5572 override TemplateValueParameter syntaxCopy()
5574 return new TemplateValueParameter(loc, ident,
5575 valType.syntaxCopy(),
5576 specValue ? specValue.syntaxCopy() : null,
5577 defaultValue ? defaultValue.syntaxCopy() : null);
5580 override bool declareParameter(Scope* sc)
5583 Do type semantic earlier.
5585 This means for certain erroneous value parameters
5586 their "type" can be known earlier and thus a better
5587 error message given.
5589 For example:
5590 `template test(x* x) {}`
5591 now yields "undefined identifier" rather than the opaque
5592 "variable `x` is used as a type".
5594 if (valType)
5595 valType = valType.typeSemantic(loc, sc);
5596 auto v = new VarDeclaration(loc, valType, ident, null);
5597 v.storage_class = STC.templateparameter;
5598 return sc.insert(v) !is null;
5601 override void print(RootObject oarg, RootObject oded)
5603 printf(" %s\n", ident.toChars());
5604 Expression ea = isExpression(oded);
5605 if (specValue)
5606 printf("\tSpecialization: %s\n", specValue.toChars());
5607 printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
5610 override RootObject specialization()
5612 return specValue;
5615 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5617 Expression e = defaultValue;
5618 if (e)
5620 e = e.syntaxCopy();
5621 if ((e = e.expressionSemantic(sc)) is null)
5622 return null;
5623 if (auto te = e.isTemplateExp())
5625 assert(sc && sc.tinst);
5626 if (te.td == sc.tinst.tempdecl)
5628 // defaultValue is a reference to its template declaration
5629 // i.e: `template T(int arg = T)`
5630 // Raise error now before calling resolveProperties otherwise we'll
5631 // start looping on the expansion of the template instance.
5632 auto td = sc.tinst.tempdecl;
5633 .error(td.loc, "%s `%s` recursive template expansion", td.kind, td.toPrettyChars);
5634 return ErrorExp.get();
5637 if ((e = resolveProperties(sc, e)) is null)
5638 return null;
5639 e = e.resolveLoc(instLoc, sc); // use the instantiated loc
5640 e = e.optimize(WANTvalue);
5642 return e;
5645 override bool hasDefaultArg()
5647 return defaultValue !is null;
5650 override RootObject dummyArg()
5652 Expression e = specValue;
5653 if (!e)
5655 // Create a dummy value
5656 auto pe = cast(void*)valType in edummies;
5657 if (!pe)
5659 e = valType.defaultInit(Loc.initial);
5660 edummies[cast(void*)valType] = e;
5662 else
5663 e = *pe;
5665 return e;
5668 override void accept(Visitor v)
5670 v.visit(this);
5674 /***********************************************************
5675 * https://dlang.org/spec/template.html#TemplateAliasParameter
5676 * Syntax:
5677 * specType ident : specAlias = defaultAlias
5679 extern (C++) final class TemplateAliasParameter : TemplateParameter
5681 Type specType;
5682 RootObject specAlias;
5683 RootObject defaultAlias;
5685 extern (D) __gshared Dsymbol sdummy = null;
5687 extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) @safe
5689 super(loc, ident);
5690 this.specType = specType;
5691 this.specAlias = specAlias;
5692 this.defaultAlias = defaultAlias;
5695 override TemplateAliasParameter isTemplateAliasParameter()
5697 return this;
5700 override TemplateAliasParameter syntaxCopy()
5702 return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
5705 override bool declareParameter(Scope* sc)
5707 auto ti = new TypeIdentifier(loc, ident);
5708 Declaration ad = new AliasDeclaration(loc, ident, ti);
5709 return sc.insert(ad) !is null;
5712 override void print(RootObject oarg, RootObject oded)
5714 printf(" %s\n", ident.toChars());
5715 Dsymbol sa = isDsymbol(oded);
5716 assert(sa);
5717 printf("\tParameter alias: %s\n", sa.toChars());
5720 override RootObject specialization()
5722 return specAlias;
5725 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5727 RootObject da = defaultAlias;
5728 Type ta = isType(defaultAlias);
5729 if (ta)
5731 if (ta.ty == Tinstance)
5733 // If the default arg is a template, instantiate for each type
5734 da = ta.syntaxCopy();
5738 RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc
5739 return o;
5742 override bool hasDefaultArg()
5744 return defaultAlias !is null;
5747 override RootObject dummyArg()
5749 RootObject s = specAlias;
5750 if (!s)
5752 if (!sdummy)
5753 sdummy = new Dsymbol();
5754 s = sdummy;
5756 return s;
5759 override void accept(Visitor v)
5761 v.visit(this);
5765 /***********************************************************
5766 * https://dlang.org/spec/template.html#TemplateSequenceParameter
5767 * Syntax:
5768 * ident ...
5770 extern (C++) final class TemplateTupleParameter : TemplateParameter
5772 extern (D) this(const ref Loc loc, Identifier ident) @safe
5774 super(loc, ident);
5777 override TemplateTupleParameter isTemplateTupleParameter()
5779 return this;
5782 override TemplateTupleParameter syntaxCopy()
5784 return new TemplateTupleParameter(loc, ident);
5787 override bool declareParameter(Scope* sc)
5789 auto ti = new TypeIdentifier(loc, ident);
5790 Declaration ad = new AliasDeclaration(loc, ident, ti);
5791 return sc.insert(ad) !is null;
5794 override void print(RootObject oarg, RootObject oded)
5796 printf(" %s... [", ident.toChars());
5797 Tuple v = isTuple(oded);
5798 assert(v);
5800 //printf("|%d| ", v.objects.length);
5801 foreach (i, o; v.objects)
5803 if (i)
5804 printf(", ");
5806 Dsymbol sa = isDsymbol(o);
5807 if (sa)
5808 printf("alias: %s", sa.toChars());
5809 Type ta = isType(o);
5810 if (ta)
5811 printf("type: %s", ta.toChars());
5812 Expression ea = isExpression(o);
5813 if (ea)
5814 printf("exp: %s", ea.toChars());
5816 assert(!isTuple(o)); // no nested Tuple arguments
5818 printf("]\n");
5821 override RootObject specialization()
5823 return null;
5826 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5828 return null;
5831 override bool hasDefaultArg()
5833 return false;
5836 override RootObject dummyArg()
5838 return null;
5841 override void accept(Visitor v)
5843 v.visit(this);
5847 /***********************************************************
5848 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
5849 * Given:
5850 * foo!(args) =>
5851 * name = foo
5852 * tiargs = args
5854 extern (C++) class TemplateInstance : ScopeDsymbol
5856 Identifier name;
5858 // Array of Types/Expressions of template
5859 // instance arguments [int*, char, 10*10]
5860 Objects* tiargs;
5862 // Array of Types/Expressions corresponding
5863 // to TemplateDeclaration.parameters
5864 // [int, char, 100]
5865 Objects tdtypes;
5867 // Modules imported by this template instance
5868 Modules importedModules;
5870 Dsymbol tempdecl; // referenced by foo.bar.abc
5871 Dsymbol enclosing; // if referencing local symbols, this is the context
5872 Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
5873 TemplateInstance inst; // refer to existing instance
5874 ScopeDsymbol argsym; // argument symbol table
5875 size_t hash; // cached result of toHash()
5876 Expressions* fargs; // for function template, these are the function arguments
5878 TemplateInstances* deferred;
5880 Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
5882 // Used to determine the instance needs code generation.
5883 // Note that these are inaccurate until semantic analysis phase completed.
5884 TemplateInstance tinst; // enclosing template instance
5885 TemplateInstance tnext; // non-first instantiated instances
5886 Module minst; // the top module that instantiated this instance
5888 private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
5889 ubyte inuse; // for recursive expansion detection
5891 private enum Flag : uint
5893 semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
5894 havetempdecl = semantictiargsdone >> 1,
5895 gagged = semantictiargsdone >> 2,
5896 available = gagged - 1 // always last flag minus one, 1s for all available bits
5899 extern(D) final @safe @property pure nothrow @nogc
5901 ushort nest() const { return _nest & Flag.available; }
5902 void nestUp() { assert(nest() < Flag.available); ++_nest; }
5903 void nestDown() { assert(nest() > 0); --_nest; }
5904 /// has semanticTiargs() been done?
5905 bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
5906 void semantictiargsdone(bool x)
5908 if (x) _nest |= Flag.semantictiargsdone;
5909 else _nest &= ~Flag.semantictiargsdone;
5911 /// if used second constructor
5912 bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
5913 void havetempdecl(bool x)
5915 if (x) _nest |= Flag.havetempdecl;
5916 else _nest &= ~Flag.havetempdecl;
5918 /// if the instantiation is done with error gagging
5919 bool gagged() const { return (_nest & Flag.gagged) != 0; }
5920 void gagged(bool x)
5922 if (x) _nest |= Flag.gagged;
5923 else _nest &= ~Flag.gagged;
5927 extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) scope
5929 super(loc, null);
5930 static if (LOG)
5932 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
5934 this.name = ident;
5935 this.tiargs = tiargs;
5938 /*****************
5939 * This constructor is only called when we figured out which function
5940 * template to instantiate.
5942 extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) scope
5944 super(loc, null);
5945 static if (LOG)
5947 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
5949 this.name = td.ident;
5950 this.tiargs = tiargs;
5951 this.tempdecl = td;
5952 this.semantictiargsdone = true;
5953 this.havetempdecl = true;
5954 assert(tempdecl._scope);
5957 extern (D) static Objects* arraySyntaxCopy(Objects* objs)
5959 Objects* a = null;
5960 if (objs)
5962 a = new Objects(objs.length);
5963 foreach (i, o; *objs)
5964 (*a)[i] = objectSyntaxCopy(o);
5966 return a;
5969 override TemplateInstance syntaxCopy(Dsymbol s)
5971 TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
5972 ti.tiargs = arraySyntaxCopy(tiargs);
5973 TemplateDeclaration td;
5974 if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
5975 td.ScopeDsymbol.syntaxCopy(ti);
5976 else
5977 ScopeDsymbol.syntaxCopy(ti);
5978 return ti;
5981 // resolve real symbol
5982 override final Dsymbol toAlias()
5984 static if (LOG)
5986 printf("TemplateInstance.toAlias()\n");
5988 if (!inst)
5990 // Maybe we can resolve it
5991 if (_scope)
5993 dsymbolSemantic(this, _scope);
5995 if (!inst)
5997 .error(loc, "%s `%s` cannot resolve forward reference", kind, toPrettyChars);
5998 errors = true;
5999 return this;
6003 if (inst != this)
6004 return inst.toAlias();
6006 if (aliasdecl)
6008 return aliasdecl.toAlias();
6011 return inst;
6014 override const(char)* kind() const
6016 return "template instance";
6019 override bool oneMember(Dsymbol* ps, Identifier ident)
6021 *ps = null;
6022 return true;
6025 override const(char)* toChars() const
6027 OutBuffer buf;
6028 toCBufferInstance(this, buf);
6029 return buf.extractChars();
6032 override final const(char)* toPrettyCharsHelper()
6034 OutBuffer buf;
6035 toCBufferInstance(this, buf, true);
6036 return buf.extractChars();
6039 /**************************************
6040 * Given an error instantiating the TemplateInstance,
6041 * give the nested TemplateInstance instantiations that got
6042 * us here. Those are a list threaded into the nested scopes.
6043 * Params:
6044 * cl = classification of this trace as printing either errors or deprecations
6045 * max_shown = maximum number of trace elements printed (controlled with -v/-verror-limit)
6047 extern(D) final void printInstantiationTrace(Classification cl = Classification.error,
6048 const(uint) max_shown = global.params.v.errorSupplementCount())
6050 if (global.gag)
6051 return;
6053 // Print full trace for verbose mode, otherwise only short traces
6054 const(char)* format = "instantiated from here: `%s`";
6056 // This returns a function pointer
6057 scope printFn = () {
6058 final switch (cl)
6060 case Classification.error:
6061 return &errorSupplemental;
6062 case Classification.deprecation:
6063 return &deprecationSupplemental;
6064 case Classification.gagged, Classification.tip, Classification.warning:
6065 assert(0);
6067 }();
6069 // determine instantiation depth and number of recursive instantiations
6070 int n_instantiations = 1;
6071 int n_totalrecursions = 0;
6072 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6074 ++n_instantiations;
6075 // Set error here as we don't want it to depend on the number of
6076 // entries that are being printed.
6077 if (cl == Classification.error ||
6078 (cl == Classification.warning && global.params.warnings == DiagnosticReporting.error) ||
6079 (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
6080 cur.errors = true;
6082 // If two instantiations use the same declaration, they are recursive.
6083 // (this works even if they are instantiated from different places in the
6084 // same template).
6085 // In principle, we could also check for multiple-template recursion, but it's
6086 // probably not worthwhile.
6087 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6088 ++n_totalrecursions;
6091 if (n_instantiations <= max_shown)
6093 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6094 printFn(cur.loc, format, cur.toChars());
6096 else if (n_instantiations - n_totalrecursions <= max_shown)
6098 // By collapsing recursive instantiations into a single line,
6099 // we can stay under the limit.
6100 int recursionDepth = 0;
6101 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6103 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6105 ++recursionDepth;
6107 else
6109 if (recursionDepth)
6110 printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
6111 else
6112 printFn(cur.loc, format, cur.toChars());
6113 recursionDepth = 0;
6117 else
6119 // Even after collapsing the recursions, the depth is too deep.
6120 // Just display the first few and last few instantiations.
6121 uint i = 0;
6122 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6124 if (i == max_shown / 2)
6125 printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
6127 if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
6128 printFn(cur.loc, format, cur.toChars());
6129 ++i;
6134 /*************************************
6135 * Lazily generate identifier for template instance.
6136 * This is because 75% of the ident's are never needed.
6138 override final Identifier getIdent()
6140 if (!ident && inst && !errors)
6141 ident = genIdent(tiargs); // need an identifier for name mangling purposes.
6142 return ident;
6145 /*************************************
6146 * Compare proposed template instantiation with existing template instantiation.
6147 * Note that this is not commutative because of the auto ref check.
6148 * Params:
6149 * ti = existing template instantiation
6150 * Returns:
6151 * true for match
6153 final bool equalsx(TemplateInstance ti)
6155 //printf("this = %p, ti = %p\n", this, ti);
6156 assert(tdtypes.length == ti.tdtypes.length);
6158 // Nesting must match
6159 if (enclosing != ti.enclosing)
6161 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
6162 goto Lnotequals;
6164 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
6166 if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
6167 goto Lnotequals;
6169 /* Template functions may have different instantiations based on
6170 * "auto ref" parameters.
6172 if (auto fd = ti.toAlias().isFuncDeclaration())
6174 if (!fd.errors)
6176 auto fparameters = fd.getParameterList();
6177 size_t nfparams = fparameters.length; // Num function parameters
6178 for (size_t j = 0; j < nfparams; j++)
6180 Parameter fparam = fparameters[j];
6181 if (fparam.storageClass & STC.autoref) // if "auto ref"
6183 Expression farg = fargs && j < fargs.length ? (*fargs)[j] : fparam.defaultArg;
6184 if (!farg)
6185 goto Lnotequals;
6186 if (farg.isLvalue())
6188 if (!(fparam.storageClass & STC.ref_))
6189 goto Lnotequals; // auto ref's don't match
6191 else
6193 if (fparam.storageClass & STC.ref_)
6194 goto Lnotequals; // auto ref's don't match
6200 return true;
6202 Lnotequals:
6203 return false;
6206 final size_t toHash()
6208 if (!hash)
6210 hash = cast(size_t)cast(void*)enclosing;
6211 hash += arrayObjectHash(&tdtypes);
6212 hash += hash == 0;
6214 return hash;
6218 Returns: true if the instances' innards are discardable.
6220 The idea of this function is to see if the template instantiation
6221 can be 100% replaced with its eponymous member. All other members
6222 can be discarded, even in the compiler to free memory (for example,
6223 the template could be expanded in a region allocator, deemed trivial,
6224 the end result copied back out independently and the entire region freed),
6225 and can be elided entirely from the binary.
6227 The current implementation affects code that generally looks like:
6230 template foo(args...) {
6231 some_basic_type_or_string helper() { .... }
6232 enum foo = helper();
6236 since it was the easiest starting point of implementation but it can and
6237 should be expanded more later.
6239 final bool isDiscardable()
6241 if (aliasdecl is null)
6242 return false;
6244 auto v = aliasdecl.isVarDeclaration();
6245 if (v is null)
6246 return false;
6248 if (!(v.storage_class & STC.manifest))
6249 return false;
6251 // Currently only doing basic types here because it is the easiest proof-of-concept
6252 // implementation with minimal risk of side effects, but it could likely be
6253 // expanded to any type that already exists outside this particular instance.
6254 if (!(v.type.equals(Type.tstring) || (v.type.isTypeBasic() !is null)))
6255 return false;
6257 // Static ctors and dtors, even in an eponymous enum template, are still run,
6258 // so if any of them are in here, we'd better not assume it is trivial lest
6259 // we break useful code
6260 foreach(member; *members)
6262 if(member.hasStaticCtorOrDtor())
6263 return false;
6264 if(member.isStaticDtorDeclaration())
6265 return false;
6266 if(member.isStaticCtorDeclaration())
6267 return false;
6270 // but if it passes through this gauntlet... it should be fine. D code will
6271 // see only the eponymous member, outside stuff can never access it, even through
6272 // reflection; the outside world ought to be none the wiser. Even dmd should be
6273 // able to simply free the memory of everything except the final result.
6275 return true;
6279 /***********************************************
6280 * Returns true if this is not instantiated in non-root module, and
6281 * is a part of non-speculative instantiatiation.
6283 * Note: minst does not stabilize until semantic analysis is completed,
6284 * so don't call this function during semantic analysis to return precise result.
6286 final bool needsCodegen()
6288 //printf("needsCodegen() %s\n", toChars());
6290 // minst is finalized after the 1st invocation.
6291 // tnext is only needed for the 1st invocation and
6292 // cleared for further invocations.
6293 TemplateInstance tnext = this.tnext;
6294 TemplateInstance tinst = this.tinst;
6295 this.tnext = null;
6297 // Don't do codegen if the instance has errors,
6298 // is a dummy instance (see evaluateConstraint),
6299 // or is determined to be discardable.
6300 if (errors || inst is null || inst.isDiscardable())
6302 minst = null; // mark as speculative
6303 return false;
6306 // This should only be called on the primary instantiation.
6307 assert(this is inst);
6309 if (global.params.allInst)
6311 // Do codegen if there is an instantiation from a root module, to maximize link-ability.
6312 static ThreeState needsCodegenAllInst(TemplateInstance tithis, TemplateInstance tinst)
6314 // Do codegen if `this` is instantiated from a root module.
6315 if (tithis.minst && tithis.minst.isRoot())
6316 return ThreeState.yes;
6318 // Do codegen if the ancestor needs it.
6319 if (tinst && tinst.inst && tinst.inst.needsCodegen())
6321 tithis.minst = tinst.inst.minst; // cache result
6322 assert(tithis.minst);
6323 assert(tithis.minst.isRoot());
6324 return ThreeState.yes;
6326 return ThreeState.none;
6329 if (const needsCodegen = needsCodegenAllInst(this, tinst))
6330 return needsCodegen == ThreeState.yes ? true : false;
6332 // Do codegen if a sibling needs it.
6333 for (; tnext; tnext = tnext.tnext)
6335 const needsCodegen = needsCodegenAllInst(tnext, tnext.tinst);
6336 if (needsCodegen == ThreeState.yes)
6338 minst = tnext.minst; // cache result
6339 assert(minst);
6340 assert(minst.isRoot());
6341 return true;
6343 else if (!minst && tnext.minst)
6345 minst = tnext.minst; // cache result from non-speculative sibling
6346 // continue searching
6348 else if (needsCodegen != ThreeState.none)
6349 break;
6352 // Elide codegen because there's no instantiation from any root modules.
6353 return false;
6355 else
6357 // Prefer instantiations from non-root modules, to minimize object code size.
6359 /* If a TemplateInstance is ever instantiated from a non-root module,
6360 * we do not have to generate code for it,
6361 * because it will be generated when the non-root module is compiled.
6363 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
6365 * The problem is if A imports B, and B imports A, and both A
6366 * and B instantiate the same template, does the compilation of A
6367 * or the compilation of B do the actual instantiation?
6369 * See https://issues.dlang.org/show_bug.cgi?id=2500.
6371 * => Elide codegen if there is at least one instantiation from a non-root module
6372 * which doesn't import any root modules.
6374 static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst)
6376 // If the ancestor isn't speculative,
6377 // 1. do codegen if the ancestor needs it
6378 // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
6379 if (tinst && tinst.inst)
6381 tinst = tinst.inst;
6382 const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
6383 if (tinst.minst) // not speculative
6385 tithis.minst = tinst.minst; // cache result
6386 return needsCodegen ? ThreeState.yes : ThreeState.no;
6390 // Elide codegen if `this` doesn't need it.
6391 if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
6392 return ThreeState.no;
6394 return ThreeState.none;
6397 if (const needsCodegen = needsCodegenRootOnly(this, tinst))
6398 return needsCodegen == ThreeState.yes ? true : false;
6400 // Elide codegen if a (non-speculative) sibling doesn't need it.
6401 for (; tnext; tnext = tnext.tnext)
6403 const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
6404 if (tnext.minst) // not speculative
6406 if (needsCodegen == ThreeState.no)
6408 minst = tnext.minst; // cache result
6409 assert(!minst.isRoot() && !minst.rootImports());
6410 return false;
6412 else if (!minst)
6414 minst = tnext.minst; // cache result from non-speculative sibling
6415 // continue searching
6417 else if (needsCodegen != ThreeState.none)
6418 break;
6422 // Unless `this` is still speculative (=> all further siblings speculative too),
6423 // do codegen because we found no guaranteed-codegen'd non-root instantiation.
6424 return minst !is null;
6428 /**********************************************
6429 * Find template declaration corresponding to template instance.
6431 * Returns:
6432 * false if finding fails.
6433 * Note:
6434 * This function is reentrant against error occurrence. If returns false,
6435 * any members of this object won't be modified, and repetition call will
6436 * reproduce same error.
6438 extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym)
6440 if (pwithsym)
6441 *pwithsym = null;
6443 if (havetempdecl)
6444 return true;
6446 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
6447 if (!tempdecl)
6449 /* Given:
6450 * foo!( ... )
6451 * figure out which TemplateDeclaration foo refers to.
6453 Identifier id = name;
6454 Dsymbol scopesym;
6455 Dsymbol s = sc.search(loc, id, &scopesym);
6456 if (!s)
6458 s = sc.search_correct(id);
6459 if (s)
6460 .error(loc, "%s `%s` template `%s` is not defined, did you mean %s?", kind, toPrettyChars, id.toChars(), s.toChars());
6461 else
6462 .error(loc, "%s `%s` template `%s` is not defined", kind, toPrettyChars, id.toChars());
6463 return false;
6465 static if (LOG)
6467 printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
6468 if (s.parent)
6469 printf("s.parent = '%s'\n", s.parent.toChars());
6471 if (pwithsym)
6472 *pwithsym = scopesym.isWithScopeSymbol();
6474 /* We might have found an alias within a template when
6475 * we really want the template.
6477 TemplateInstance ti;
6478 if (s.parent && (ti = s.parent.isTemplateInstance()) !is null)
6480 if (ti.tempdecl && ti.tempdecl.ident == id)
6482 /* This is so that one can refer to the enclosing
6483 * template, even if it has the same name as a member
6484 * of the template, if it has a !(arguments)
6486 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6487 assert(td);
6488 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6489 td = td.overroot; // then get the start
6490 s = td;
6494 // The template might originate from a selective import which implies that
6495 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
6496 // This is the last place where we see the deprecated alias because it is
6497 // stripped below, so check if the selective import was deprecated.
6498 // See https://issues.dlang.org/show_bug.cgi?id=20840.
6499 if (s.isAliasDeclaration())
6500 s.checkDeprecated(this.loc, sc);
6502 if (!updateTempDecl(sc, s))
6504 return false;
6507 assert(tempdecl);
6509 // Look for forward references
6510 auto tovers = tempdecl.isOverloadSet();
6511 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
6513 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6514 int r = overloadApply(dstart, (Dsymbol s)
6516 auto td = s.isTemplateDeclaration();
6517 if (!td)
6518 return 0;
6520 if (td.semanticRun == PASS.initial)
6522 if (td._scope)
6524 // Try to fix forward reference. Ungag errors while doing so.
6525 Ungag ungag = td.ungagSpeculative();
6526 td.dsymbolSemantic(td._scope);
6528 if (td.semanticRun == PASS.initial)
6530 .error(loc, "%s `%s` `%s` forward references template declaration `%s`", kind, toPrettyChars,
6531 toChars(), td.toChars());
6532 return 1;
6535 return 0;
6537 if (r)
6538 return false;
6540 return true;
6543 /**********************************************
6544 * Confirm s is a valid template, then store it.
6545 * Input:
6546 * sc
6547 * s candidate symbol of template. It may be:
6548 * TemplateDeclaration
6549 * FuncDeclaration with findTemplateDeclRoot() != NULL
6550 * OverloadSet which contains candidates
6551 * Returns:
6552 * true if updating succeeds.
6554 extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s)
6556 if (!s)
6557 return tempdecl !is null;
6559 Identifier id = name;
6560 s = s.toAlias();
6562 /* If an OverloadSet, look for a unique member that is a template declaration
6564 if (OverloadSet os = s.isOverloadSet())
6566 s = null;
6567 foreach (s2; os.a)
6569 if (FuncDeclaration f = s2.isFuncDeclaration())
6570 s2 = f.findTemplateDeclRoot();
6571 else
6572 s2 = s2.isTemplateDeclaration();
6573 if (s2)
6575 if (s)
6577 tempdecl = os;
6578 return true;
6580 s = s2;
6583 if (!s)
6585 .error(loc, "%s `%s` template `%s` is not defined", kind, toPrettyChars, id.toChars());
6586 return false;
6590 if (OverDeclaration od = s.isOverDeclaration())
6592 tempdecl = od; // TODO: more strict check
6593 return true;
6596 /* It should be a TemplateDeclaration, not some other symbol
6598 if (FuncDeclaration f = s.isFuncDeclaration())
6599 tempdecl = f.findTemplateDeclRoot();
6600 else
6601 tempdecl = s.isTemplateDeclaration();
6603 // We're done
6604 if (tempdecl)
6605 return true;
6607 // Error already issued, just return `false`
6608 if (!s.parent && global.errors)
6609 return false;
6611 if (!s.parent && s.getType())
6613 Dsymbol s2 = s.getType().toDsymbol(sc);
6614 if (!s2)
6616 .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());
6617 return false;
6619 // because s can be the alias created for a TemplateParameter
6620 const AliasDeclaration ad = s.isAliasDeclaration();
6621 version (none)
6623 if (ad && ad.isAliasedTemplateParameter())
6624 printf("`%s` is an alias created from a template parameter\n", s.toChars());
6626 if (!ad || !ad.isAliasedTemplateParameter())
6627 s = s2;
6630 TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
6632 /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
6634 static bool matchId(TemplateInstance ti, Identifier id)
6636 if (ti.aliasdecl && ti.aliasdecl.isVarDeclaration())
6637 return ti.aliasdecl.isVarDeclaration().ident == id;
6638 return ti.toAlias().ident == id;
6641 if (ti && (ti.name == s.ident || matchId(ti, s.ident)) && ti.tempdecl)
6643 /* This is so that one can refer to the enclosing
6644 * template, even if it has the same name as a member
6645 * of the template, if it has a !(arguments)
6647 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6648 assert(td);
6649 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6650 td = td.overroot; // then get the start
6651 tempdecl = td;
6652 return true;
6654 else
6656 .error(loc, "%s `%s` `%s` is not a template declaration, it is a %s", kind, toPrettyChars, id.toChars(), s.kind());
6657 return false;
6661 /**********************************
6662 * Run semantic of tiargs as arguments of template.
6663 * Input:
6664 * loc
6665 * sc
6666 * tiargs array of template arguments
6667 * flags 1: replace const variables with their initializers
6668 * 2: don't devolve Parameter to Type
6669 * atd tuple being optimized. If found, it's not expanded here
6670 * but in AliasAssign semantic.
6671 * Returns:
6672 * false if one or more arguments have errors.
6674 extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null)
6676 // Run semantic on each argument, place results in tiargs[]
6677 //printf("+TemplateInstance.semanticTiargs()\n");
6678 if (!tiargs)
6679 return true;
6680 bool err = false;
6681 for (size_t j = 0; j < tiargs.length; j++)
6683 RootObject o = (*tiargs)[j];
6684 Type ta = isType(o);
6685 Expression ea = isExpression(o);
6686 Dsymbol sa = isDsymbol(o);
6688 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
6689 if (ta)
6691 //printf("type %s\n", ta.toChars());
6693 // It might really be an Expression or an Alias
6694 ta.resolve(loc, sc, ea, ta, sa, (flags & 1) != 0);
6695 if (ea)
6696 goto Lexpr;
6697 if (sa)
6698 goto Ldsym;
6699 if (ta is null)
6701 assert(global.errors);
6702 ta = Type.terror;
6705 Ltype:
6706 if (ta.ty == Ttuple)
6708 // Expand tuple
6709 TypeTuple tt = cast(TypeTuple)ta;
6710 size_t dim = tt.arguments.length;
6711 tiargs.remove(j);
6712 if (dim)
6714 tiargs.reserve(dim);
6715 foreach (i, arg; *tt.arguments)
6717 if (flags & 2 && (arg.storageClass & STC.parameter))
6718 tiargs.insert(j + i, arg);
6719 else
6720 tiargs.insert(j + i, arg.type);
6723 j--;
6724 continue;
6726 if (ta.ty == Terror)
6728 err = true;
6729 continue;
6731 (*tiargs)[j] = ta.merge2();
6733 else if (ea)
6735 Lexpr:
6736 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6737 if (flags & 1) // only used by __traits
6739 ea = ea.expressionSemantic(sc);
6741 // must not interpret the args, excepting template parameters
6742 if (!ea.isVarExp() || (ea.isVarExp().var.storage_class & STC.templateparameter))
6744 ea = ea.optimize(WANTvalue);
6747 else
6749 sc = sc.startCTFE();
6750 ea = ea.expressionSemantic(sc);
6751 sc = sc.endCTFE();
6753 if (auto varExp = ea.isVarExp())
6755 /* If the parameter is a function that is not called
6756 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
6757 * then it is a dsymbol, not the return value of `func()`
6759 Declaration vd = varExp.var;
6760 if (auto fd = vd.isFuncDeclaration())
6762 sa = fd;
6763 goto Ldsym;
6765 /* Otherwise skip substituting a const var with
6766 * its initializer. The problem is the initializer won't
6767 * match with an 'alias' parameter. Instead, do the
6768 * const substitution in TemplateValueParameter.matchArg().
6771 else if (definitelyValueParameter(ea))
6773 if (ea.checkValue()) // check void expression
6774 ea = ErrorExp.get();
6775 uint olderrs = global.errors;
6776 ea = ea.ctfeInterpret();
6777 if (global.errors != olderrs)
6778 ea = ErrorExp.get();
6781 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6782 if (TupleExp te = ea.isTupleExp())
6784 // Expand tuple
6785 size_t dim = te.exps.length;
6786 tiargs.remove(j);
6787 if (dim)
6789 tiargs.reserve(dim);
6790 foreach (i, exp; *te.exps)
6791 tiargs.insert(j + i, exp);
6793 j--;
6794 continue;
6796 if (ea.op == EXP.error)
6798 err = true;
6799 continue;
6801 (*tiargs)[j] = ea;
6803 if (ea.op == EXP.type)
6805 ta = ea.type;
6806 goto Ltype;
6808 if (ea.op == EXP.scope_)
6810 sa = ea.isScopeExp().sds;
6811 goto Ldsym;
6813 if (FuncExp fe = ea.isFuncExp())
6815 /* A function literal, that is passed to template and
6816 * already semanticed as function pointer, never requires
6817 * outer frame. So convert it to global function is valid.
6819 if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer)
6821 // change to non-nested
6822 fe.fd.tok = TOK.function_;
6823 fe.fd.vthis = null;
6825 else if (fe.td)
6827 /* If template argument is a template lambda,
6828 * get template declaration itself. */
6829 //sa = fe.td;
6830 //goto Ldsym;
6833 if (ea.op == EXP.dotVariable && !(flags & 1))
6835 // translate expression to dsymbol.
6836 sa = ea.isDotVarExp().var;
6837 goto Ldsym;
6839 if (auto te = ea.isTemplateExp())
6841 sa = te.td;
6842 goto Ldsym;
6844 if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
6846 // translate expression to dsymbol.
6847 sa = ea.isDotTemplateExp().td;
6848 goto Ldsym;
6850 if (auto de = ea.isDotExp())
6852 if (auto se = de.e2.isScopeExp())
6854 sa = se.sds;
6855 goto Ldsym;
6859 else if (sa)
6861 Ldsym:
6862 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
6863 if (sa.errors)
6865 err = true;
6866 continue;
6869 TupleDeclaration d = sa.toAlias().isTupleDeclaration();
6870 if (d)
6872 if (d is atd)
6874 (*tiargs)[j] = d;
6875 continue;
6877 // Expand tuple
6878 tiargs.remove(j);
6879 tiargs.insert(j, d.objects);
6880 j--;
6881 continue;
6883 if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration())
6885 FuncDeclaration f = fa.toAliasFunc();
6886 if (!fa.hasOverloads && f.isUnique())
6888 // Strip FuncAlias only when the aliased function
6889 // does not have any overloads.
6890 sa = f;
6893 (*tiargs)[j] = sa;
6895 TemplateDeclaration td = sa.isTemplateDeclaration();
6896 if (td && td.semanticRun == PASS.initial && td.literal)
6898 td.dsymbolSemantic(sc);
6900 FuncDeclaration fd = sa.isFuncDeclaration();
6901 if (fd)
6902 fd.functionSemantic();
6904 else if (isParameter(o))
6907 else
6909 assert(0);
6911 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
6913 version (none)
6915 printf("-TemplateInstance.semanticTiargs()\n");
6916 for (size_t j = 0; j < tiargs.length; j++)
6918 RootObject o = (*tiargs)[j];
6919 Type ta = isType(o);
6920 Expression ea = isExpression(o);
6921 Dsymbol sa = isDsymbol(o);
6922 Tuple va = isTuple(o);
6923 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
6926 return !err;
6929 /**********************************
6930 * Run semantic on the elements of tiargs.
6931 * Input:
6932 * sc
6933 * Returns:
6934 * false if one or more arguments have errors.
6935 * Note:
6936 * This function is reentrant against error occurrence. If returns false,
6937 * all elements of tiargs won't be modified.
6939 extern (D) final bool semanticTiargs(Scope* sc)
6941 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
6942 if (semantictiargsdone)
6943 return true;
6944 if (semanticTiargs(loc, sc, tiargs, 0))
6946 // cache the result iff semantic analysis succeeded entirely
6947 semantictiargsdone = 1;
6948 return true;
6950 return false;
6953 /**********************************
6954 * Find the TemplateDeclaration that matches this TemplateInstance best.
6956 * Params:
6957 * sc = the scope this TemplateInstance resides in
6958 * argumentList = function arguments in case of a template function
6960 * Returns:
6961 * `true` if a match was found, `false` otherwise
6963 extern (D) final bool findBestMatch(Scope* sc, ArgumentList argumentList)
6965 if (havetempdecl)
6967 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
6968 assert(tempdecl);
6969 assert(tempdecl._scope);
6970 // Deduce tdtypes
6971 tdtypes.setDim(tempdecl.parameters.length);
6972 if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2))
6974 .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars);
6975 return false;
6977 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
6978 return true;
6981 static if (LOG)
6983 printf("TemplateInstance.findBestMatch()\n");
6986 uint errs = global.errors;
6987 TemplateDeclaration td_last = null;
6988 Objects dedtypes;
6990 /* Since there can be multiple TemplateDeclaration's with the same
6991 * name, look for the best match.
6993 auto tovers = tempdecl.isOverloadSet();
6994 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
6996 TemplateDeclaration td_best;
6997 TemplateDeclaration td_ambig;
6998 MATCH m_best = MATCH.nomatch;
7000 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7001 overloadApply(dstart, (Dsymbol s)
7003 auto td = s.isTemplateDeclaration();
7004 if (!td)
7005 return 0;
7006 if (td == td_best) // skip duplicates
7007 return 0;
7009 //printf("td = %s\n", td.toPrettyChars());
7010 // If more arguments than parameters,
7011 // then this is no match.
7012 if (td.parameters.length < tiargs.length)
7014 if (!td.isVariadic())
7015 return 0;
7018 dedtypes.setDim(td.parameters.length);
7019 dedtypes.zero();
7020 assert(td.semanticRun != PASS.initial);
7022 MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0);
7023 //printf("matchWithInstance = %d\n", m);
7024 if (m == MATCH.nomatch) // no match at all
7025 return 0;
7026 if (m < m_best) goto Ltd_best;
7027 if (m > m_best) goto Ltd;
7029 // Disambiguate by picking the most specialized TemplateDeclaration
7031 MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList);
7032 MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList);
7033 //printf("c1 = %d, c2 = %d\n", c1, c2);
7034 if (c1 > c2) goto Ltd;
7035 if (c1 < c2) goto Ltd_best;
7038 td_ambig = td;
7039 return 0;
7041 Ltd_best:
7042 // td_best is the best match so far
7043 td_ambig = null;
7044 return 0;
7046 Ltd:
7047 // td is the new best match
7048 td_ambig = null;
7049 td_best = td;
7050 m_best = m;
7051 tdtypes.setDim(dedtypes.length);
7052 memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.length * (void*).sizeof);
7053 return 0;
7056 if (td_ambig)
7058 .error(loc, "%s `%s.%s` matches more than one template declaration:",
7059 td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars());
7060 .errorSupplemental(td_best.loc, "`%s`\nand:", td_best.toChars());
7061 .errorSupplemental(td_ambig.loc, "`%s`", td_ambig.toChars());
7062 return false;
7064 if (td_best)
7066 if (!td_last)
7067 td_last = td_best;
7068 else if (td_last != td_best)
7070 ScopeDsymbol.multiplyDefined(loc, td_last, td_best);
7071 return false;
7076 if (td_last)
7078 /* https://issues.dlang.org/show_bug.cgi?id=7469
7079 * Normalize tiargs by using corresponding deduced
7080 * template value parameters and tuples for the correct mangling.
7082 * By doing this before hasNestedArgs, CTFEable local variable will be
7083 * accepted as a value parameter. For example:
7085 * void foo() {
7086 * struct S(int n) {} // non-global template
7087 * const int num = 1; // CTFEable local variable
7088 * S!num s; // S!1 is instantiated, not S!num
7091 size_t dim = td_last.parameters.length - (td_last.isVariadic() ? 1 : 0);
7092 for (size_t i = 0; i < dim; i++)
7094 if (tiargs.length <= i)
7095 tiargs.push(tdtypes[i]);
7096 assert(i < tiargs.length);
7098 auto tvp = (*td_last.parameters)[i].isTemplateValueParameter();
7099 if (!tvp)
7100 continue;
7101 assert(tdtypes[i]);
7102 // tdtypes[i] is already normalized to the required type in matchArg
7104 (*tiargs)[i] = tdtypes[i];
7106 if (td_last.isVariadic() && tiargs.length == dim && tdtypes[dim])
7108 Tuple va = isTuple(tdtypes[dim]);
7109 assert(va);
7110 tiargs.pushSlice(va.objects[]);
7113 else if (errors && inst)
7115 // instantiation was failed with error reporting
7116 assert(global.errors);
7117 return false;
7119 else
7121 auto tdecl = tempdecl.isTemplateDeclaration();
7123 if (errs != global.errors)
7124 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7125 else if (tdecl && !tdecl.overnext)
7127 // Only one template, so we can give better error message
7128 const(char)* msg = "does not match template declaration";
7129 const(char)* tip;
7130 const tmsg = tdecl.toCharsNoConstraints();
7131 const cmsg = tdecl.getConstraintEvalError(tip);
7132 if (cmsg)
7134 .error(loc, "%s `%s` %s `%s`\n%s", kind, toPrettyChars, msg, tmsg, cmsg);
7135 if (tip)
7136 .tip(tip);
7138 else
7140 .error(loc, "%s `%s` %s `%s`", kind, toPrettyChars, msg, tmsg);
7142 if (tdecl.parameters.length == tiargs.length)
7144 // https://issues.dlang.org/show_bug.cgi?id=7352
7145 // print additional information, e.g. `foo` is not a type
7146 foreach (i, param; *tdecl.parameters)
7148 MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
7149 auto arg = (*tiargs)[i];
7150 auto sym = arg.isDsymbol;
7151 auto exp = arg.isExpression;
7153 if (exp)
7154 exp = exp.optimize(WANTvalue);
7156 if (match == MATCH.nomatch &&
7157 ((sym && sym.isFuncDeclaration) ||
7158 (exp && exp.isVarExp)))
7160 if (param.isTemplateTypeParameter)
7161 errorSupplemental(loc, "`%s` is not a type", arg.toChars);
7162 else if (auto tvp = param.isTemplateValueParameter)
7163 errorSupplemental(loc, "`%s` is not of a value of type `%s`",
7164 arg.toChars, tvp.valType.toChars);
7171 else
7173 .error(loc, "%s `%s` does not match any template declaration", kind(), toPrettyChars());
7174 bool found;
7175 overloadApply(tempdecl, (s){
7176 if (!found)
7177 errorSupplemental(loc, "Candidates are:");
7178 found = true;
7179 errorSupplemental(s.loc, "%s", s.toChars());
7180 return 0;
7183 return false;
7186 /* The best match is td_last
7188 tempdecl = td_last;
7190 static if (LOG)
7192 printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
7194 return (errs == global.errors);
7197 /*****************************************************
7198 * Determine if template instance is really a template function,
7199 * and that template function needs to infer types from the function
7200 * arguments.
7202 * Like findBestMatch, iterate possible template candidates,
7203 * but just looks only the necessity of type inference.
7205 extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
7207 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
7208 if (semanticRun != PASS.initial)
7209 return false;
7211 uint olderrs = global.errors;
7212 Objects dedtypes;
7213 size_t count = 0;
7215 auto tovers = tempdecl.isOverloadSet();
7216 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
7218 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7219 int r = overloadApply(dstart, (Dsymbol s)
7221 auto td = s.isTemplateDeclaration();
7222 if (!td)
7223 return 0;
7225 /* If any of the overloaded template declarations need inference,
7226 * then return true
7228 if (!td.onemember)
7229 return 0;
7230 if (auto td2 = td.onemember.isTemplateDeclaration())
7232 if (!td2.onemember || !td2.onemember.isFuncDeclaration())
7233 return 0;
7234 if (tiargs.length >= td.parameters.length - (td.isVariadic() ? 1 : 0))
7235 return 0;
7236 return 1;
7238 auto fd = td.onemember.isFuncDeclaration();
7239 if (!fd || fd.type.ty != Tfunction)
7240 return 0;
7242 foreach (tp; *td.parameters)
7244 if (tp.isTemplateThisParameter())
7245 return 1;
7248 /* Determine if the instance arguments, tiargs, are all that is necessary
7249 * to instantiate the template.
7251 //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
7252 auto tf = cast(TypeFunction)fd.type;
7253 if (tf.parameterList.length)
7255 auto tp = td.isVariadic();
7256 if (tp && td.parameters.length > 1)
7257 return 1;
7259 if (!tp && tiargs.length < td.parameters.length)
7261 // Can remain tiargs be filled by default arguments?
7262 foreach (size_t i; tiargs.length .. td.parameters.length)
7264 if (!(*td.parameters)[i].hasDefaultArg())
7265 return 1;
7269 foreach (i, fparam; tf.parameterList)
7271 // 'auto ref' needs inference.
7272 if (fparam.storageClass & STC.auto_)
7273 return 1;
7277 if (!flag)
7279 /* Calculate the need for overload resolution.
7280 * When only one template can match with tiargs, inference is not necessary.
7282 dedtypes.setDim(td.parameters.length);
7283 dedtypes.zero();
7284 if (td.semanticRun == PASS.initial)
7286 if (td._scope)
7288 // Try to fix forward reference. Ungag errors while doing so.
7289 Ungag ungag = td.ungagSpeculative();
7290 td.dsymbolSemantic(td._scope);
7292 if (td.semanticRun == PASS.initial)
7294 .error(loc, "%s `%s` `%s` forward references template declaration `%s`", kind, toPrettyChars, toChars(), td.toChars());
7295 return 1;
7298 MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0);
7299 if (m == MATCH.nomatch)
7300 return 0;
7303 /* If there is more than one function template which matches, we may
7304 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
7306 return ++count > 1 ? 1 : 0;
7308 if (r)
7309 return true;
7312 if (olderrs != global.errors)
7314 if (!global.gag)
7316 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7317 semanticRun = PASS.semanticdone;
7318 inst = this;
7320 errors = true;
7322 //printf("false\n");
7323 return false;
7326 /*****************************************
7327 * Determines if a TemplateInstance will need a nested
7328 * generation of the TemplateDeclaration.
7329 * Sets enclosing property if so, and returns != 0;
7331 extern (D) final bool hasNestedArgs(Objects* args, bool isstatic)
7333 int nested = 0;
7334 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
7336 // arguments from parent instances are also accessible
7337 if (!enclosing)
7339 if (TemplateInstance ti = tempdecl.toParent().isTemplateInstance())
7340 enclosing = ti.enclosing;
7343 /* A nested instance happens when an argument references a local
7344 * symbol that is on the stack.
7346 foreach (o; *args)
7348 Expression ea = isExpression(o);
7349 Dsymbol sa = isDsymbol(o);
7350 Tuple va = isTuple(o);
7351 if (ea)
7353 if (auto ve = ea.isVarExp())
7355 sa = ve.var;
7356 goto Lsa;
7358 if (auto te = ea.isThisExp())
7360 sa = te.var;
7361 goto Lsa;
7363 if (auto fe = ea.isFuncExp())
7365 if (fe.td)
7366 sa = fe.td;
7367 else
7368 sa = fe.fd;
7369 goto Lsa;
7371 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
7372 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)
7374 if (!ea.type.isTypeError())
7375 .error(ea.loc, "%s `%s` expression `%s` is not a valid template value argument", kind, toPrettyChars, ea.toChars());
7376 errors = true;
7379 else if (sa)
7381 Lsa:
7382 sa = sa.toAlias();
7383 TemplateDeclaration td = sa.isTemplateDeclaration();
7384 if (td)
7386 TemplateInstance ti = sa.toParent().isTemplateInstance();
7387 if (ti && ti.enclosing)
7388 sa = ti;
7390 TemplateInstance ti = sa.isTemplateInstance();
7391 Declaration d = sa.isDeclaration();
7392 if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin()))
7394 Dsymbol dparent = sa.toParent2();
7395 if (!dparent || dparent.isModule)
7396 goto L1;
7397 else if (!enclosing)
7398 enclosing = dparent;
7399 else if (enclosing != dparent)
7401 /* Select the more deeply nested of the two.
7402 * Error if one is not nested inside the other.
7404 for (Dsymbol p = enclosing; p; p = p.parent)
7406 if (p == dparent)
7407 goto L1; // enclosing is most nested
7409 for (Dsymbol p = dparent; p; p = p.parent)
7411 if (p == enclosing)
7413 enclosing = dparent;
7414 goto L1; // dparent is most nested
7417 //https://issues.dlang.org/show_bug.cgi?id=17870
7418 if (dparent.isClassDeclaration() && enclosing.isClassDeclaration())
7420 auto pc = dparent.isClassDeclaration();
7421 auto ec = enclosing.isClassDeclaration();
7422 if (pc.isBaseOf(ec, null))
7423 goto L1;
7424 else if (ec.isBaseOf(pc, null))
7426 enclosing = dparent;
7427 goto L1;
7430 .error(loc, "%s `%s` `%s` is nested in both `%s` and `%s`", kind, toPrettyChars, toChars(), enclosing.toChars(), dparent.toChars());
7431 errors = true;
7434 //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
7435 nested |= 1;
7438 else if (va)
7440 nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
7443 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
7444 return nested != 0;
7447 /*****************************************
7448 * Append 'this' to the specific module members[]
7450 extern (D) final Dsymbols* appendToModuleMember()
7452 Module mi = minst; // instantiated . inserted module
7454 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
7455 // toPrettyChars(),
7456 // enclosing ? enclosing.toPrettyChars() : null,
7457 // mi ? mi.toPrettyChars() : null);
7458 if (global.params.allInst || !mi || mi.isRoot())
7460 /* If the instantiated module is speculative or root, insert to the
7461 * member of a root module. Then:
7462 * - semantic3 pass will get called on the instance members.
7463 * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
7465 static Dsymbol getStrictEnclosing(TemplateInstance ti)
7469 if (ti.enclosing)
7470 return ti.enclosing;
7471 ti = ti.tempdecl.isInstantiated();
7472 } while (ti);
7473 return null;
7476 Dsymbol enc = getStrictEnclosing(this);
7477 // insert target is made stable by using the module
7478 // where tempdecl is declared.
7479 mi = (enc ? enc : tempdecl).getModule();
7480 if (!mi.isRoot())
7482 if (mi.importedFrom)
7484 mi = mi.importedFrom;
7485 assert(mi.isRoot());
7487 else
7489 // This can happen when using the frontend as a library.
7490 // Append it to the non-root module.
7494 else
7496 /* If the instantiated module is non-root, insert to the member of the
7497 * non-root module. Then:
7498 * - semantic3 pass won't be called on the instance.
7499 * - codegen pass won't reach to the instance.
7500 * Unless it is re-appended to a root module later (with changed minst).
7503 //printf("\t-. mi = %s\n", mi.toPrettyChars());
7505 assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module");
7507 Dsymbols* a = mi.members;
7508 a.push(this);
7509 memberOf = mi;
7510 if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
7511 Module.addDeferredSemantic2(this);
7512 if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
7513 Module.addDeferredSemantic3(this);
7514 return a;
7517 /****************************************************
7518 * Declare parameters of template instance, initialize them with the
7519 * template instance arguments.
7521 extern (D) final void declareParameters(Scope* sc)
7523 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
7524 assert(tempdecl);
7526 //printf("TemplateInstance.declareParameters()\n");
7527 foreach (i, o; tdtypes) // initializer for tp
7529 TemplateParameter tp = (*tempdecl.parameters)[i];
7530 //printf("\ttdtypes[%d] = %p\n", i, o);
7531 tempdecl.declareParameter(sc, tp, o);
7535 /****************************************
7536 * This instance needs an identifier for name mangling purposes.
7537 * Create one by taking the template declaration name and adding
7538 * the type signature for it.
7540 extern (D) final Identifier genIdent(Objects* args)
7542 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
7543 assert(args is tiargs);
7544 OutBuffer buf;
7545 mangleToBuffer(this, buf);
7546 //printf("\tgenIdent = %s\n", buf.peekChars());
7547 return Identifier.idPool(buf[]);
7550 extern (D) final void expandMembers(Scope* sc2)
7552 members.foreachDsymbol( (s) { s.setScope (sc2); } );
7554 members.foreachDsymbol( (s) { s.importAll(sc2); } );
7556 if (!aliasdecl)
7558 /* static if's are crucial to evaluating aliasdecl correctly. But
7559 * evaluating the if/else bodies may require aliasdecl.
7560 * So, evaluate the condition for static if's, but not their if/else bodies.
7561 * Then try to set aliasdecl.
7562 * Later do the if/else bodies.
7563 * https://issues.dlang.org/show_bug.cgi?id=23598
7564 * It might be better to do this by attaching a lambda to the StaticIfDeclaration
7565 * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
7567 bool done;
7568 void staticIfDg(Dsymbol s)
7570 if (done || aliasdecl)
7571 return;
7572 //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
7573 if (!s.isStaticIfDeclaration())
7575 //s.dsymbolSemantic(sc2);
7576 done = true;
7577 return;
7579 auto sid = s.isStaticIfDeclaration();
7580 sid.include(sc2);
7581 if (members.length)
7583 Dsymbol sa;
7584 if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa)
7585 aliasdecl = sa;
7587 done = true;
7590 members.foreachDsymbol(&staticIfDg);
7593 void symbolDg(Dsymbol s)
7595 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
7596 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
7597 //if (enclosing)
7598 // s.parent = sc.parent;
7599 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7600 s.dsymbolSemantic(sc2);
7601 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7602 Module.runDeferredSemantic();
7605 members.foreachDsymbol(&symbolDg);
7608 extern (D) final void tryExpandMembers(Scope* sc2)
7610 __gshared int nest;
7611 // extracted to a function to allow windows SEH to work without destructors in the same function
7612 //printf("%d\n", nest);
7613 if (++nest > global.recursionLimit)
7615 global.gag = 0; // ensure error message gets printed
7616 .error(loc, "%s `%s` recursive expansion exceeded allowed nesting limit", kind, toPrettyChars);
7617 fatal();
7620 expandMembers(sc2);
7622 nest--;
7625 extern (D) final void trySemantic3(Scope* sc2)
7627 // extracted to a function to allow windows SEH to work without destructors in the same function
7628 __gshared int nest;
7629 //printf("%d\n", nest);
7630 if (++nest > global.recursionLimit)
7632 global.gag = 0; // ensure error message gets printed
7633 .error(loc, "%s `%s` recursive expansion exceeded allowed nesting limit", kind, toPrettyChars);
7634 fatal();
7637 semantic3(this, sc2);
7639 --nest;
7642 override final inout(TemplateInstance) isTemplateInstance() inout
7644 return this;
7647 override void accept(Visitor v)
7649 v.visit(this);
7653 /**************************************
7654 * IsExpression can evaluate the specified type speculatively, and even if
7655 * it instantiates any symbols, they are normally unnecessary for the
7656 * final executable.
7657 * However, if those symbols leak to the actual code, compiler should remark
7658 * them as non-speculative to generate their code and link to the final executable.
7660 void unSpeculative(Scope* sc, RootObject o)
7662 if (!o)
7663 return;
7665 if (Tuple tup = isTuple(o))
7667 foreach (obj; tup.objects)
7669 unSpeculative(sc, obj);
7671 return;
7674 Dsymbol s = getDsymbol(o);
7675 if (!s)
7676 return;
7678 if (Declaration d = s.isDeclaration())
7680 if (VarDeclaration vd = d.isVarDeclaration())
7681 o = vd.type;
7682 else if (AliasDeclaration ad = d.isAliasDeclaration())
7684 o = ad.getType();
7685 if (!o)
7686 o = ad.toAlias();
7688 else
7689 o = d.toAlias();
7691 s = getDsymbol(o);
7692 if (!s)
7693 return;
7696 if (TemplateInstance ti = s.isTemplateInstance())
7698 // If the instance is already non-speculative,
7699 // or it is leaked to the speculative scope.
7700 if (ti.minst !is null || sc.minst is null)
7701 return;
7703 // Remark as non-speculative instance.
7704 ti.minst = sc.minst;
7705 if (!ti.tinst)
7706 ti.tinst = sc.tinst;
7708 unSpeculative(sc, ti.tempdecl);
7711 if (TemplateInstance ti = s.isInstantiated())
7712 unSpeculative(sc, ti);
7715 /**********************************
7716 * Return true if e could be valid only as a template value parameter.
7717 * Return false if it might be an alias or tuple.
7718 * (Note that even in this case, it could still turn out to be a value).
7720 bool definitelyValueParameter(Expression e) @safe
7722 // None of these can be value parameters
7723 if (e.op == EXP.tuple || e.op == EXP.scope_ ||
7724 e.op == EXP.type || e.op == EXP.dotType ||
7725 e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration ||
7726 e.op == EXP.function_ || e.op == EXP.error ||
7727 e.op == EXP.this_ || e.op == EXP.super_ ||
7728 e.op == EXP.dot)
7729 return false;
7731 if (e.op != EXP.dotVariable)
7732 return true;
7734 /* Template instantiations involving a DotVar expression are difficult.
7735 * In most cases, they should be treated as a value parameter, and interpreted.
7736 * But they might also just be a fully qualified name, which should be treated
7737 * as an alias.
7740 // x.y.f cannot be a value
7741 FuncDeclaration f = e.isDotVarExp().var.isFuncDeclaration();
7742 if (f)
7743 return false;
7745 while (e.op == EXP.dotVariable)
7747 e = e.isDotVarExp().e1;
7749 // this.x.y and super.x.y couldn't possibly be valid values.
7750 if (e.op == EXP.this_ || e.op == EXP.super_)
7751 return false;
7753 // e.type.x could be an alias
7754 if (e.op == EXP.dotType)
7755 return false;
7757 // var.x.y is the only other possible form of alias
7758 if (e.op != EXP.variable)
7759 return true;
7761 VarDeclaration v = e.isVarExp().var.isVarDeclaration();
7762 // func.x.y is not an alias
7763 if (!v)
7764 return true;
7766 // https://issues.dlang.org/show_bug.cgi?id=16685
7767 // var.x.y where var is a constant available at compile time
7768 if (v.storage_class & STC.manifest)
7769 return true;
7771 // TODO: Should we force CTFE if it is a global constant?
7772 return false;
7775 /***********************************************************
7776 * https://dlang.org/spec/template-mixin.html
7777 * Syntax:
7778 * mixin MixinTemplateName [TemplateArguments] [Identifier];
7780 extern (C++) final class TemplateMixin : TemplateInstance
7782 TypeQualified tqual;
7784 extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
7786 super(loc,
7787 tqual.idents.length ? cast(Identifier)tqual.idents[tqual.idents.length - 1] : (cast(TypeIdentifier)tqual).ident,
7788 tiargs ? tiargs : new Objects());
7789 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
7790 this.ident = ident;
7791 this.tqual = tqual;
7794 override TemplateInstance syntaxCopy(Dsymbol s)
7796 auto tm = new TemplateMixin(loc, ident, tqual.syntaxCopy(), tiargs);
7797 return TemplateInstance.syntaxCopy(tm);
7800 override const(char)* kind() const
7802 return "mixin";
7805 override bool oneMember(Dsymbol* ps, Identifier ident)
7807 return Dsymbol.oneMember(ps, ident);
7810 override bool hasPointers()
7812 //printf("TemplateMixin.hasPointers() %s\n", toChars());
7813 return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
7816 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
7818 //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
7819 if (_scope) // if fwd reference
7820 dsymbolSemantic(this, null); // try to resolve it
7822 members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
7825 override const(char)* toChars() const
7827 OutBuffer buf;
7828 toCBufferInstance(this, buf);
7829 return buf.extractChars();
7832 extern (D) bool findTempDecl(Scope* sc)
7834 // Follow qualifications to find the TemplateDeclaration
7835 if (!tempdecl)
7837 Expression e;
7838 Type t;
7839 Dsymbol s;
7840 tqual.resolve(loc, sc, e, t, s);
7841 if (!s)
7843 .error(loc, "%s `%s` is not defined", kind, toPrettyChars);
7844 return false;
7846 s = s.toAlias();
7847 tempdecl = s.isTemplateDeclaration();
7848 OverloadSet os = s.isOverloadSet();
7850 /* If an OverloadSet, look for a unique member that is a template declaration
7852 if (os)
7854 Dsymbol ds = null;
7855 foreach (i, sym; os.a)
7857 Dsymbol s2 = sym.isTemplateDeclaration();
7858 if (s2)
7860 if (ds)
7862 tempdecl = os;
7863 break;
7865 ds = s2;
7869 if (!tempdecl)
7871 .error(loc, "%s `%s` - `%s` is a %s, not a template", kind, toPrettyChars, s.toChars(), s.kind());
7872 return false;
7875 assert(tempdecl);
7877 // Look for forward references
7878 auto tovers = tempdecl.isOverloadSet();
7879 foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
7881 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7882 int r = overloadApply(dstart, (Dsymbol s)
7884 auto td = s.isTemplateDeclaration();
7885 if (!td)
7886 return 0;
7888 if (td.semanticRun == PASS.initial)
7890 if (td._scope)
7891 td.dsymbolSemantic(td._scope);
7892 else
7894 semanticRun = PASS.initial;
7895 return 1;
7898 return 0;
7900 if (r)
7901 return false;
7903 return true;
7906 override inout(TemplateMixin) isTemplateMixin() inout
7908 return this;
7911 override void accept(Visitor v)
7913 v.visit(this);
7917 /************************************
7918 * This struct is needed for TemplateInstance to be the key in an associative array.
7919 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
7920 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
7922 struct TemplateInstanceBox
7924 TemplateInstance ti;
7926 this(TemplateInstance ti)
7928 this.ti = ti;
7929 this.ti.toHash();
7930 assert(this.ti.hash);
7933 size_t toHash() const @trusted pure nothrow
7935 assert(ti.hash);
7936 return ti.hash;
7939 bool opEquals(ref const TemplateInstanceBox s) @trusted const
7941 bool res = void;
7942 if (ti.inst && s.ti.inst)
7944 /* This clause is only used when an instance with errors
7945 * is replaced with a correct instance.
7947 res = ti is s.ti;
7949 else
7951 /* Used when a proposed instance is used to see if there's
7952 * an existing instance.
7954 static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
7955 res = (cast()s.ti).equalsx(cast()ti);
7956 else
7957 res = (cast()ti).equalsx(cast()s.ti);
7960 debug (FindExistingInstance) ++(res ? nHits : nCollisions);
7961 return res;
7964 debug (FindExistingInstance)
7966 __gshared uint nHits, nCollisions;
7968 shared static ~this()
7970 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
7971 nHits, nCollisions);
7976 /*******************************************
7977 * Match to a particular TemplateParameter.
7978 * Input:
7979 * instLoc location that the template is instantiated.
7980 * tiargs[] actual arguments to template instance
7981 * i i'th argument
7982 * parameters[] template parameters
7983 * dedtypes[] deduced arguments to template instance
7984 * *psparam set to symbol declared and initialized to dedtypes[i]
7986 MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
7988 MATCH matchArgNoMatch()
7990 if (psparam)
7991 *psparam = null;
7992 return MATCH.nomatch;
7995 MATCH matchArgParameter()
7997 RootObject oarg;
7999 if (i < tiargs.length)
8000 oarg = (*tiargs)[i];
8001 else
8003 // Get default argument instead
8004 oarg = tp.defaultArg(instLoc, sc);
8005 if (!oarg)
8007 assert(i < dedtypes.length);
8008 // It might have already been deduced
8009 oarg = (*dedtypes)[i];
8010 if (!oarg)
8011 return matchArgNoMatch();
8014 return tp.matchArg(sc, oarg, i, parameters, dedtypes, psparam);
8017 MATCH matchArgTuple(TemplateTupleParameter ttp)
8019 /* The rest of the actual arguments (tiargs[]) form the match
8020 * for the variadic parameter.
8022 assert(i + 1 == dedtypes.length); // must be the last one
8023 Tuple ovar;
8025 if (Tuple u = isTuple((*dedtypes)[i]))
8027 // It has already been deduced
8028 ovar = u;
8030 else if (i + 1 == tiargs.length && isTuple((*tiargs)[i]))
8031 ovar = isTuple((*tiargs)[i]);
8032 else
8034 ovar = new Tuple();
8035 //printf("ovar = %p\n", ovar);
8036 if (i < tiargs.length)
8038 //printf("i = %d, tiargs.length = %d\n", i, tiargs.length);
8039 ovar.objects.setDim(tiargs.length - i);
8040 foreach (j, ref obj; ovar.objects)
8041 obj = (*tiargs)[i + j];
8044 return ttp.matchArg(sc, ovar, i, parameters, dedtypes, psparam);
8047 if (auto ttp = tp.isTemplateTupleParameter())
8048 return matchArgTuple(ttp);
8049 else
8050 return matchArgParameter();
8053 MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
8055 MATCH matchArgNoMatch()
8057 //printf("\tm = %d\n", MATCH.nomatch);
8058 if (psparam)
8059 *psparam = null;
8060 return MATCH.nomatch;
8063 MATCH matchArgType(TemplateTypeParameter ttp)
8065 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
8066 MATCH m = MATCH.exact;
8067 Type ta = isType(oarg);
8068 if (!ta)
8070 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
8071 return matchArgNoMatch();
8073 //printf("ta is %s\n", ta.toChars());
8075 if (ttp.specType)
8077 if (!ta || ta == TemplateTypeParameter.tdummy)
8078 return matchArgNoMatch();
8080 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
8081 MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
8082 if (m2 == MATCH.nomatch)
8084 //printf("\tfailed deduceType\n");
8085 return matchArgNoMatch();
8088 if (m2 < m)
8089 m = m2;
8090 if ((*dedtypes)[i])
8092 Type t = cast(Type)(*dedtypes)[i];
8094 if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
8095 return matchArgNoMatch();
8097 /* This is a self-dependent parameter. For example:
8098 * template X(T : T*) {}
8099 * template X(T : S!T, alias S) {}
8101 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8102 ta = t;
8105 else
8107 if ((*dedtypes)[i])
8109 // Must match already deduced type
8110 Type t = cast(Type)(*dedtypes)[i];
8112 if (!t.equals(ta))
8114 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8115 return matchArgNoMatch();
8118 else
8120 // So that matches with specializations are better
8121 m = MATCH.convert;
8124 (*dedtypes)[i] = ta;
8126 if (psparam)
8127 *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
8128 //printf("\tm = %d\n", m);
8129 return ttp.dependent ? MATCH.exact : m;
8132 MATCH matchArgValue(TemplateValueParameter tvp)
8134 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
8135 MATCH m = MATCH.exact;
8137 Expression ei = isExpression(oarg);
8138 Type vt;
8140 if (!ei && oarg)
8142 Dsymbol si = isDsymbol(oarg);
8143 FuncDeclaration f = si ? si.isFuncDeclaration() : null;
8144 if (!f || !f.fbody || f.needThis())
8145 return matchArgNoMatch();
8147 ei = new VarExp(tvp.loc, f);
8148 ei = ei.expressionSemantic(sc);
8150 /* If a function is really property-like, and then
8151 * it's CTFEable, ei will be a literal expression.
8153 uint olderrors = global.startGagging();
8154 ei = resolveProperties(sc, ei);
8155 ei = ei.ctfeInterpret();
8156 if (global.endGagging(olderrors) || ei.op == EXP.error)
8157 return matchArgNoMatch();
8159 /* https://issues.dlang.org/show_bug.cgi?id=14520
8160 * A property-like function can match to both
8161 * TemplateAlias and ValueParameter. But for template overloads,
8162 * it should always prefer alias parameter to be consistent
8163 * template match result.
8165 * template X(alias f) { enum X = 1; }
8166 * template X(int val) { enum X = 2; }
8167 * int f1() { return 0; } // CTFEable
8168 * int f2(); // body-less function is not CTFEable
8169 * enum x1 = X!f1; // should be 1
8170 * enum x2 = X!f2; // should be 1
8172 * e.g. The x1 value must be same even if the f1 definition will be moved
8173 * into di while stripping body code.
8175 m = MATCH.convert;
8178 if (ei && ei.op == EXP.variable)
8180 // Resolve const variables that we had skipped earlier
8181 ei = ei.ctfeInterpret();
8184 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
8185 vt = tvp.valType.typeSemantic(tvp.loc, sc);
8186 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
8187 //printf("vt = %s\n", vt.toChars());
8189 if (ei.type)
8191 MATCH m2 = ei.implicitConvTo(vt);
8192 //printf("m: %d\n", m);
8193 if (m2 < m)
8194 m = m2;
8195 if (m == MATCH.nomatch)
8196 return matchArgNoMatch();
8197 ei = ei.implicitCastTo(sc, vt);
8198 ei = ei.ctfeInterpret();
8201 if (tvp.specValue)
8203 if (ei is null || (cast(void*)ei.type in TemplateValueParameter.edummies &&
8204 TemplateValueParameter.edummies[cast(void*)ei.type] == ei))
8205 return matchArgNoMatch();
8207 Expression e = tvp.specValue;
8209 sc = sc.startCTFE();
8210 e = e.expressionSemantic(sc);
8211 e = resolveProperties(sc, e);
8212 sc = sc.endCTFE();
8213 e = e.implicitCastTo(sc, vt);
8214 e = e.ctfeInterpret();
8216 ei = ei.syntaxCopy();
8217 sc = sc.startCTFE();
8218 ei = ei.expressionSemantic(sc);
8219 sc = sc.endCTFE();
8220 ei = ei.implicitCastTo(sc, vt);
8221 ei = ei.ctfeInterpret();
8222 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
8223 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
8224 if (!ei.equals(e))
8225 return matchArgNoMatch();
8227 else
8229 if ((*dedtypes)[i])
8231 // Must match already deduced value
8232 Expression e = cast(Expression)(*dedtypes)[i];
8233 if (!ei || !ei.equals(e))
8234 return matchArgNoMatch();
8237 (*dedtypes)[i] = ei;
8239 if (psparam)
8241 Initializer _init = new ExpInitializer(tvp.loc, ei);
8242 Declaration sparam = new VarDeclaration(tvp.loc, vt, tvp.ident, _init);
8243 sparam.storage_class = STC.manifest;
8244 *psparam = sparam;
8246 return tvp.dependent ? MATCH.exact : m;
8249 MATCH matchArgAlias(TemplateAliasParameter tap)
8251 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
8252 MATCH m = MATCH.exact;
8253 Type ta = isType(oarg);
8254 RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
8255 Expression ea = isExpression(oarg);
8256 if (ea)
8258 if (auto te = ea.isThisExp())
8259 sa = te.var;
8260 else if (auto se = ea.isSuperExp())
8261 sa = se.var;
8262 else if (auto se = ea.isScopeExp())
8263 sa = se.sds;
8265 if (sa)
8267 if ((cast(Dsymbol)sa).isAggregateDeclaration())
8268 m = MATCH.convert;
8270 /* specType means the alias must be a declaration with a type
8271 * that matches specType.
8273 if (tap.specType)
8275 tap.specType = typeSemantic(tap.specType, tap.loc, sc);
8276 Declaration d = (cast(Dsymbol)sa).isDeclaration();
8277 if (!d)
8278 return matchArgNoMatch();
8279 if (!d.type.equals(tap.specType))
8280 return matchArgNoMatch();
8283 else
8285 sa = oarg;
8286 if (ea)
8288 if (tap.specType)
8290 if (!ea.type.equals(tap.specType))
8291 return matchArgNoMatch();
8294 else if (ta && ta.ty == Tinstance && !tap.specAlias)
8296 /* Specialized parameter should be preferred
8297 * match to the template type parameter.
8298 * template X(alias a) {} // a == this
8299 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
8302 else if (sa && sa == TemplateTypeParameter.tdummy)
8304 /* https://issues.dlang.org/show_bug.cgi?id=2025
8305 * Aggregate Types should preferentially
8306 * match to the template type parameter.
8307 * template X(alias a) {} // a == this
8308 * template X(T) {} // T => sa
8311 else if (ta && ta.ty != Tident)
8313 /* Match any type that's not a TypeIdentifier to alias parameters,
8314 * but prefer type parameter.
8315 * template X(alias a) { } // a == ta
8317 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
8319 m = MATCH.convert;
8321 else
8322 return matchArgNoMatch();
8325 if (tap.specAlias)
8327 if (sa == TemplateAliasParameter.sdummy)
8328 return matchArgNoMatch();
8329 // check specialization if template arg is a symbol
8330 Dsymbol sx = isDsymbol(sa);
8331 if (sa != tap.specAlias && sx)
8333 Type talias = isType(tap.specAlias);
8334 if (!talias)
8335 return matchArgNoMatch();
8337 TemplateInstance ti = sx.isTemplateInstance();
8338 if (!ti && sx.parent)
8340 ti = sx.parent.isTemplateInstance();
8341 if (ti && ti.name != sx.ident)
8342 return matchArgNoMatch();
8344 if (!ti)
8345 return matchArgNoMatch();
8347 Type t = new TypeInstance(Loc.initial, ti);
8348 MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
8349 if (m2 == MATCH.nomatch)
8350 return matchArgNoMatch();
8352 // check specialization if template arg is a type
8353 else if (ta)
8355 if (Type tspec = isType(tap.specAlias))
8357 MATCH m2 = ta.implicitConvTo(tspec);
8358 if (m2 == MATCH.nomatch)
8359 return matchArgNoMatch();
8361 else
8363 error(tap.loc, "template parameter specialization for a type must be a type and not `%s`",
8364 tap.specAlias.toChars());
8365 return matchArgNoMatch();
8369 else if ((*dedtypes)[i])
8371 // Must match already deduced symbol
8372 RootObject si = (*dedtypes)[i];
8373 if (!sa || si != sa)
8374 return matchArgNoMatch();
8376 (*dedtypes)[i] = sa;
8378 if (psparam)
8380 if (Dsymbol s = isDsymbol(sa))
8382 *psparam = new AliasDeclaration(tap.loc, tap.ident, s);
8384 else if (Type t = isType(sa))
8386 *psparam = new AliasDeclaration(tap.loc, tap.ident, t);
8388 else
8390 assert(ea);
8392 // Declare manifest constant
8393 Initializer _init = new ExpInitializer(tap.loc, ea);
8394 auto v = new VarDeclaration(tap.loc, null, tap.ident, _init);
8395 v.storage_class = STC.manifest;
8396 v.dsymbolSemantic(sc);
8397 *psparam = v;
8400 return tap.dependent ? MATCH.exact : m;
8403 MATCH matchArgTuple(TemplateTupleParameter ttp)
8405 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
8406 Tuple ovar = isTuple(oarg);
8407 if (!ovar)
8408 return MATCH.nomatch;
8409 if ((*dedtypes)[i])
8411 Tuple tup = isTuple((*dedtypes)[i]);
8412 if (!tup)
8413 return MATCH.nomatch;
8414 if (!match(tup, ovar))
8415 return MATCH.nomatch;
8417 (*dedtypes)[i] = ovar;
8419 if (psparam)
8420 *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
8421 return ttp.dependent ? MATCH.exact : MATCH.convert;
8424 if (auto ttp = tp.isTemplateTypeParameter())
8425 return matchArgType(ttp);
8426 else if (auto tvp = tp.isTemplateValueParameter())
8427 return matchArgValue(tvp);
8428 else if (auto tap = tp.isTemplateAliasParameter())
8429 return matchArgAlias(tap);
8430 else if (auto ttp = tp.isTemplateTupleParameter())
8431 return matchArgTuple(ttp);
8432 else
8433 assert(0);
8437 /***********************************************
8438 * Collect and print statistics on template instantiations.
8440 struct TemplateStats
8442 __gshared TemplateStats[const void*] stats;
8444 uint numInstantiations; // number of instantiations of the template
8445 uint uniqueInstantiations; // number of unique instantiations of the template
8447 TemplateInstances* allInstances;
8449 /*******************************
8450 * Add this instance
8452 static void incInstance(const TemplateDeclaration td,
8453 const TemplateInstance ti)
8455 void log(ref TemplateStats ts)
8457 if (ts.allInstances is null)
8458 ts.allInstances = new TemplateInstances();
8459 if (global.params.v.templatesListInstances)
8460 ts.allInstances.push(cast() ti);
8463 // message(ti.loc, "incInstance %p %p", td, ti);
8464 if (!global.params.v.templates)
8465 return;
8466 if (!td)
8467 return;
8468 assert(ti);
8469 if (auto ts = cast(const void*) td in stats)
8471 log(*ts);
8472 ++ts.numInstantiations;
8474 else
8476 stats[cast(const void*) td] = TemplateStats(1, 0);
8477 log(stats[cast(const void*) td]);
8481 /*******************************
8482 * Add this unique instance
8484 static void incUnique(const TemplateDeclaration td,
8485 const TemplateInstance ti)
8487 // message(ti.loc, "incUnique %p %p", td, ti);
8488 if (!global.params.v.templates)
8489 return;
8490 if (!td)
8491 return;
8492 assert(ti);
8493 if (auto ts = cast(const void*) td in stats)
8494 ++ts.uniqueInstantiations;
8495 else
8496 stats[cast(const void*) td] = TemplateStats(0, 1);
8500 extern (C++) void printTemplateStats()
8502 static struct TemplateDeclarationStats
8504 TemplateDeclaration td;
8505 TemplateStats ts;
8506 static int compare(scope const TemplateDeclarationStats* a,
8507 scope const TemplateDeclarationStats* b) @safe nothrow @nogc pure
8509 auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations;
8510 if (diff)
8511 return diff;
8512 else
8513 return b.ts.numInstantiations - a.ts.numInstantiations;
8517 if (!global.params.v.templates)
8518 return;
8520 Array!(TemplateDeclarationStats) sortedStats;
8521 sortedStats.reserve(TemplateStats.stats.length);
8522 foreach (td_, ref ts; TemplateStats.stats)
8524 sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
8527 sortedStats.sort!(TemplateDeclarationStats.compare);
8529 foreach (const ref ss; sortedStats[])
8531 if (global.params.v.templatesListInstances &&
8532 ss.ts.allInstances)
8534 message(ss.td.loc,
8535 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
8536 ss.ts.numInstantiations,
8537 ss.ts.uniqueInstantiations,
8538 ss.td.toCharsNoConstraints());
8539 foreach (const ti; (*ss.ts.allInstances)[])
8541 if (ti.tinst) // if has enclosing instance
8542 message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
8543 else
8544 message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
8547 else
8549 message(ss.td.loc,
8550 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
8551 ss.ts.numInstantiations,
8552 ss.ts.uniqueInstantiations,
8553 ss.td.toCharsNoConstraints());
8558 /// Pair of MATCHes
8559 private struct MATCHpair
8561 MATCH mta; /// match template parameters by initial template arguments
8562 MATCH mfa; /// match template parameters by inferred template arguments
8564 debug this(MATCH mta, MATCH mfa)
8566 assert(MATCH.min <= mta && mta <= MATCH.max);
8567 assert(MATCH.min <= mfa && mfa <= MATCH.max);
8568 this.mta = mta;
8569 this.mfa = mfa;
8573 private void write(ref OutBuffer buf, RootObject obj)
8575 if (obj)
8577 buf.writestring(obj.toChars());