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.
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`
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-2021 by The D Language Foundation, All Rights Reserved
32 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
33 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
34 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d)
35 * Documentation: https://dlang.org/phobos/dmd_dtemplate.html
36 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d
41 import core.stdc.stdio;
42 import core.stdc.string;
45 import dmd.arraytypes;
50 import dmd.declaration;
55 import dmd.dsymbolsem;
57 import dmd.expression;
58 import dmd.expressionsem;
63 import dmd.identifier;
69 import dmd.root.array;
70 import dmd.common.outbuffer;
71 import dmd.root.rootobject;
78 import dmd.templateparamsem;
80 //debug = FindExistingInstance; // print debug stats of findExistingInstance
81 private enum LOG = false;
83 enum IDX_NOTFOUND = 0x12345678;
88 /********************************************
89 * These functions substitute for dynamic_cast. dynamic_cast does not work
90 * on earlier versions of gcc.
92 extern (C++) inout(Expression) isExpression(inout RootObject o)
94 //return dynamic_cast<Expression *>(o);
95 if (!o || o.dyncast() != DYNCAST.expression)
97 return cast(inout(Expression))o;
100 extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o)
102 //return dynamic_cast<Dsymbol *>(o);
103 if (!o || o.dyncast() != DYNCAST.dsymbol)
105 return cast(inout(Dsymbol))o;
108 extern (C++) inout(Type) isType(inout RootObject o)
110 //return dynamic_cast<Type *>(o);
111 if (!o || o.dyncast() != DYNCAST.type)
113 return cast(inout(Type))o;
116 extern (C++) inout(Tuple) isTuple(inout RootObject o)
118 //return dynamic_cast<Tuple *>(o);
119 if (!o || o.dyncast() != DYNCAST.tuple)
121 return cast(inout(Tuple))o;
124 extern (C++) inout(Parameter) isParameter(inout RootObject o)
126 //return dynamic_cast<Parameter *>(o);
127 if (!o || o.dyncast() != DYNCAST.parameter)
129 return cast(inout(Parameter))o;
132 extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o)
134 if (!o || o.dyncast() != DYNCAST.templateparameter)
136 return cast(inout(TemplateParameter))o;
139 /**************************************
140 * Is this Object an error?
142 extern (C++) bool isError(const RootObject o)
144 if (const t = isType(o))
145 return (t.ty == Terror);
146 if (const e = isExpression(o))
147 return (e.op == EXP.error || !e.type || e.type.ty == Terror);
148 if (const v = isTuple(o))
149 return arrayObjectIsError(&v.objects);
150 const s = isDsymbol(o);
154 return s.parent ? isError(s.parent) : false;
157 /**************************************
158 * Are any of the Objects an error?
160 bool arrayObjectIsError(const Objects* args)
162 foreach (const o; *args)
170 /***********************
171 * Try to get arg as a type.
173 inout(Type) getType(inout RootObject o)
178 if (inout e = isExpression(o))
186 Dsymbol getDsymbol(RootObject oarg)
188 //printf("getDsymbol()\n");
189 //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
190 if (auto ea = isExpression(oarg))
192 // Try to convert Expression to symbol
193 if (auto ve = ea.isVarExp())
195 else if (auto fe = ea.isFuncExp())
196 return fe.td ? fe.td : fe.fd;
197 else if (auto te = ea.isTemplateExp())
199 else if (auto te = ea.isScopeExp())
206 // Try to convert Type to symbol
207 if (auto ta = isType(oarg))
208 return ta.toDsymbol(null);
210 return isDsymbol(oarg); // if already a symbol
215 private Expression getValue(ref Dsymbol s)
219 if (VarDeclaration v = s.isVarDeclaration())
221 if (v.storage_class & STC.manifest)
222 return v.getConstInitializer();
228 /***********************
229 * Try to get value from manifest constant
231 private Expression getValue(Expression e)
235 if (auto ve = e.isVarExp())
237 if (auto v = ve.var.isVarDeclaration())
239 if (v.storage_class & STC.manifest)
241 e = v.getConstInitializer();
248 private Expression getExpression(RootObject o)
250 auto s = isDsymbol(o);
251 return s ? .getValue(s) : .getValue(isExpression(o));
254 /******************************
255 * If o1 matches o2, return true.
256 * Else, return false.
258 private bool match(RootObject o1, RootObject o2)
264 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
265 o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
268 /* A proper implementation of the various equals() overrides
269 * should make it possible to just do o1.equals(o2), but
270 * we'll do that another day.
272 /* Manifest constants should be compared by their values,
273 * at least in template arguments.
276 if (auto t1 = isType(o1))
278 auto t2 = isType(o2);
284 printf("\tt1 = %s\n", t1.toChars());
285 printf("\tt2 = %s\n", t2.toChars());
292 if (auto e1 = getExpression(o1))
294 auto e2 = getExpression(o2);
300 printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars());
301 printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars());
304 // two expressions can be equal although they do not have the same
305 // type; that happens when they have the same value. So check type
306 // as well as expression equality to ensure templates are properly
308 if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2))
313 if (auto s1 = isDsymbol(o1))
315 auto s2 = isDsymbol(o2);
321 printf("\ts1 = %s \n", s1.kind(), s1.toChars());
322 printf("\ts2 = %s \n", s2.kind(), s2.toChars());
326 if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
331 if (auto u1 = isTuple(o1))
333 auto u2 = isTuple(o2);
339 printf("\tu1 = %s\n", u1.toChars());
340 printf("\tu2 = %s\n", u2.toChars());
342 if (!arrayObjectMatch(&u1.objects, &u2.objects))
349 printf("\t. match\n");
354 printf("\t. nomatch\n");
358 /************************************
359 * Match an array of them.
361 private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
365 if (oa1.dim != oa2.dim)
367 immutable oa1dim = oa1.dim;
368 auto oa1d = (*oa1)[].ptr;
369 auto oa2d = (*oa2)[].ptr;
370 foreach (j; 0 .. oa1dim)
372 RootObject o1 = oa1d[j];
373 RootObject o2 = oa2d[j];
382 /************************************
383 * Return hash of Objects.
385 private size_t arrayObjectHash(Objects* oa1)
387 import dmd.root.hash : mixHash;
392 /* Must follow the logic of match()
394 if (auto t1 = isType(o1))
395 hash = mixHash(hash, cast(size_t)t1.deco);
396 else if (auto e1 = getExpression(o1))
397 hash = mixHash(hash, expressionHash(e1));
398 else if (auto s1 = isDsymbol(o1))
400 auto fa1 = s1.isFuncAliasDeclaration();
402 s1 = fa1.toAliasFunc();
403 hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
405 else if (auto u1 = isTuple(o1))
406 hash = mixHash(hash, arrayObjectHash(&u1.objects));
412 /************************************
413 * Computes hash of expression.
414 * Handles all Expression classes and MUST match their equals method,
415 * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2).
417 private size_t expressionHash(Expression e)
419 import dmd.root.ctfloat : CTFloat;
420 import dmd.root.hash : calcHash, mixHash;
425 return cast(size_t) e.isIntegerExp().getInteger();
428 return CTFloat.hash(e.isRealExp().value);
431 auto ce = e.isComplexExp();
432 return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary));
435 return cast(size_t)cast(void*) e.isIdentifierExp().ident;
438 return cast(size_t)cast(void*) e.isNullExp().type;
441 return calcHash(e.isStringExp.peekData());
445 auto te = e.isTupleExp();
447 hash += te.e0 ? expressionHash(te.e0) : 0;
448 foreach (elem; *te.exps)
449 hash = mixHash(hash, expressionHash(elem));
453 case EXP.arrayLiteral:
455 auto ae = e.isArrayLiteralExp();
457 foreach (i; 0 .. ae.elements.dim)
458 hash = mixHash(hash, expressionHash(ae[i]));
462 case EXP.assocArrayLiteral:
464 auto ae = e.isAssocArrayLiteralExp();
466 foreach (i; 0 .. ae.keys.dim)
467 // reduction needs associative op as keys are unsorted (use XOR)
468 hash ^= mixHash(expressionHash((*ae.keys)[i]), expressionHash((*ae.values)[i]));
472 case EXP.structLiteral:
474 auto se = e.isStructLiteralExp();
476 foreach (elem; *se.elements)
477 hash = mixHash(hash, elem ? expressionHash(elem) : 0);
482 return cast(size_t)cast(void*) e.isVarExp().var;
485 return cast(size_t)cast(void*) e.isFuncExp().fd;
488 // no custom equals for this expression
489 assert((&e.equals).funcptr is &RootObject.equals);
490 // equals based on identity
491 return cast(size_t)cast(void*) e;
495 RootObject objectSyntaxCopy(RootObject o)
499 if (Type t = isType(o))
500 return t.syntaxCopy();
501 if (Expression e = isExpression(o))
502 return e.syntaxCopy();
506 extern (C++) final class Tuple : RootObject
514 numObjects = The initial number of objects.
516 extern (D) this(size_t numObjects)
518 objects.setDim(numObjects);
521 // kludge for template.isType()
522 override DYNCAST dyncast() const
524 return DYNCAST.tuple;
527 override const(char)* toChars() const
529 return objects.toChars();
533 struct TemplatePrevious
535 TemplatePrevious* prev;
540 /***********************************************************
541 * [mixin] template Identifier (parameters) [Constraint]
542 * https://dlang.org/spec/template.html
543 * https://dlang.org/spec/template-mixin.html
545 extern (C++) final class TemplateDeclaration : ScopeDsymbol
547 import dmd.root.array : Array;
549 TemplateParameters* parameters; // array of TemplateParameter's
550 TemplateParameters* origParameters; // originals for Ddoc
552 Expression constraint;
554 // Hash table to look up TemplateInstance's of this TemplateDeclaration
555 TemplateInstance[TemplateInstanceBox] instances;
557 TemplateDeclaration overnext; // next overloaded TemplateDeclaration
558 TemplateDeclaration overroot; // first in overnext list
559 FuncDeclaration funcroot; // first function in unified overload list
561 Dsymbol onemember; // if !=null then one member of this template
563 bool literal; // this template declaration is a literal
564 bool ismixin; // this is a mixin template declaration
565 bool isstatic; // this is static template declaration
566 bool isTrivialAliasSeq; /// matches pattern `template AliasSeq(T...) { alias AliasSeq = T; }`
567 bool isTrivialAlias; /// matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
568 bool deprecated_; /// this template declaration is deprecated
569 Visibility visibility;
570 int inuse; /// for recursive expansion detection
572 // threaded list of previous instantiation attempts on stack
573 TemplatePrevious* previous;
575 private Expression lastConstraint; /// the constraint after the last failed evaluation
576 private Array!Expression lastConstraintNegs; /// its negative parts
577 private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
579 extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
584 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident.toChars());
589 for (int i = 0; i < parameters.dim; i++)
591 TemplateParameter tp = (*parameters)[i];
592 //printf("\tparameter[%d] = %p\n", i, tp);
593 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
596 printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
600 this.parameters = parameters;
601 this.origParameters = parameters;
602 this.constraint = constraint;
603 this.members = decldefs;
604 this.literal = literal;
605 this.ismixin = ismixin;
606 this.isstatic = true;
607 this.visibility = Visibility(Visibility.Kind.undefined);
609 // Compute in advance for Ddoc's use
610 // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails.
611 if (!members || !ident)
615 if (!Dsymbol.oneMembers(members, &s, ident) || !s)
621 /* Set isTrivialAliasSeq if this fits the pattern:
622 * template AliasSeq(T...) { alias AliasSeq = T; }
623 * or set isTrivialAlias if this fits the pattern:
624 * template Alias(T) { alias Alias = qualifiers(T); }
626 if (!(parameters && parameters.length == 1))
629 auto ad = s.isAliasDeclaration();
633 auto ti = ad.type.isTypeIdentifier();
635 if (!ti || ti.idents.length != 0)
638 if (auto ttp = (*parameters)[0].isTemplateTupleParameter())
640 if (ti.ident is ttp.ident &&
643 //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
644 isTrivialAliasSeq = true;
647 else if (auto ttp = (*parameters)[0].isTemplateTypeParameter())
649 if (ti.ident is ttp.ident)
651 //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
652 isTrivialAlias = true;
657 override TemplateDeclaration syntaxCopy(Dsymbol)
659 //printf("TemplateDeclaration.syntaxCopy()\n");
660 TemplateParameters* p = null;
663 p = new TemplateParameters(parameters.dim);
664 foreach (i, ref param; *p)
665 param = (*parameters)[i].syntaxCopy();
667 return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal);
670 /**********************************
671 * Overload existing TemplateDeclaration 'this' with the new one 's'.
672 * Return true if successful; i.e. no conflict.
674 override bool overloadInsert(Dsymbol s)
678 printf("TemplateDeclaration.overloadInsert('%s')\n", s.toChars());
680 FuncDeclaration fd = s.isFuncDeclaration();
684 return funcroot.overloadInsert(fd);
686 return funcroot.overloadInsert(this);
689 // https://issues.dlang.org/show_bug.cgi?id=15795
690 // if candidate is an alias and its sema is not run then
691 // insertion can fail because the thing it alias is not known
692 if (AliasDeclaration ad = s.isAliasDeclaration())
695 aliasSemantic(ad, s._scope);
696 if (ad.aliassym && ad.aliassym is this)
699 TemplateDeclaration td = s.toAlias().isTemplateDeclaration();
703 TemplateDeclaration pthis = this;
704 TemplateDeclaration* ptd;
705 for (ptd = &pthis; *ptd; ptd = &(*ptd).overnext)
713 printf("\ttrue: no conflict\n");
718 override bool hasStaticCtorOrDtor()
720 return false; // don't scan uninstantiated templates
723 override const(char)* kind() const
725 return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template";
728 override const(char)* toChars() const
730 return toCharsMaybeConstraints(true);
733 /****************************
734 * Similar to `toChars`, but does not print the template constraints
736 const(char)* toCharsNoConstraints() const
738 return toCharsMaybeConstraints(false);
741 const(char)* toCharsMaybeConstraints(bool includeConstraints) const
744 return Dsymbol.toChars();
749 buf.writestring(ident.toString());
751 foreach (i, const tp; *parameters)
754 buf.writestring(", ");
755 .toCBuffer(tp, &buf, &hgs);
761 const FuncDeclaration fd = onemember.isFuncDeclaration();
764 TypeFunction tf = cast(TypeFunction)fd.type;
765 buf.writestring(parametersTypeToChars(tf.parameterList));
769 if (includeConstraints &&
772 buf.writestring(" if (");
773 .toCBuffer(constraint, &buf, &hgs);
777 return buf.extractChars();
780 override Visibility visible() pure nothrow @nogc @safe
785 /****************************
786 * Check to see if constraint is satisfied.
788 extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
790 /* Detect recursive attempts to instantiate this template declaration,
791 * https://issues.dlang.org/show_bug.cgi?id=4072
792 * void foo(T)(T x) if (is(typeof(foo(x)))) { }
793 * static assert(!is(typeof(foo(7))));
794 * Recursive attempts are regarded as a constraint failure.
796 /* There's a chicken-and-egg problem here. We don't know yet if this template
797 * instantiation will be a local one (enclosing is set), and we won't know until
798 * after selecting the correct template. Thus, function we're nesting inside
799 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
800 * Workaround the problem by setting a flag to relax the checking on frame errors.
803 for (TemplatePrevious* p = previous; p; p = p.prev)
805 if (!arrayObjectMatch(p.dedargs, dedargs))
807 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
808 /* It must be a subscope of p.sc, other scope chains are not recursive
810 * the chain of enclosing scopes is broken by paramscope (its enclosing
811 * scope is _scope, but paramscope.callsc is the instantiating scope). So
812 * it's good enough to check the chain of callsc
814 for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
816 // The first scx might be identical for nested eponymeous templates, e.g.
817 // template foo() { void foo()() {...} }
818 if (scx == p.sc && scx !is paramscope.callsc)
821 /* BUG: should also check for ref param differences
827 pr.sc = paramscope.callsc;
828 pr.dedargs = dedargs;
829 previous = ≺ // add this to threaded list
831 Scope* scx = paramscope.push(ti);
835 // Set SCOPE.constraint before declaring function parameters for the static condition
836 // (previously, this was immediately before calling evalStaticCondition), so the
837 // semantic pass knows not to issue deprecation warnings for these throw-away decls.
838 // https://issues.dlang.org/show_bug.cgi?id=21831
839 scx.flags |= SCOPE.constraint;
844 /* Declare all the function parameters as variables and add them to the scope
845 * Making parameters is similar to FuncDeclaration.semantic3
847 auto tf = fd.type.isTypeFunction();
851 Parameters* fparameters = tf.parameterList.parameters;
852 const nfparams = tf.parameterList.length;
853 foreach (i, fparam; tf.parameterList)
855 fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
856 fparam.storageClass |= STC.parameter;
857 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams)
859 fparam.storageClass |= STC.variadic;
860 /* Don't need to set STC.scope_ because this will only
861 * be evaluated at compile time
865 foreach (fparam; *fparameters)
869 // don't add it, if it has no name
870 auto v = new VarDeclaration(loc, fparam.type, fparam.ident, null);
871 fparam.storageClass |= STC.parameter;
872 v.storage_class = fparam.storageClass;
873 v.dsymbolSemantic(scx);
875 ti.symtab = new DsymbolTable();
877 error("parameter `%s.%s` is already defined", toChars(), v.toChars());
882 fd.storage_class |= STC.static_;
886 lastConstraint = constraint.syntaxCopy();
887 lastConstraintTiargs = ti.tiargs;
888 lastConstraintNegs.setDim(0);
890 import dmd.staticcond;
892 assert(ti.inst is null);
893 ti.inst = ti; // temporary instantiation to enable genIdent()
895 const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs);
896 if (result || errors)
898 lastConstraint = null;
899 lastConstraintTiargs = null;
900 lastConstraintNegs.setDim(0);
905 previous = pr.prev; // unlink from threaded list
911 /****************************
912 * Destructively get the error message from the last constraint evaluation
914 * tip = tip to show after printing all overloads
916 const(char)* getConstraintEvalError(ref const(char)* tip)
918 import dmd.staticcond;
920 // there will be a full tree view in verbose mode, and more compact list in the usual
921 const full = global.params.verbose;
923 const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count);
926 lastConstraint = null;
927 lastConstraintTiargs = null;
928 lastConstraintNegs.setDim(0);
935 assert(parameters && lastConstraintTiargs);
936 if (parameters.length > 0)
938 formatParamsWithTiargs(*lastConstraintTiargs, buf);
943 // choosing singular/plural
944 const s = (count == 1) ?
945 " must satisfy the following constraint:" :
946 " must satisfy one of the following constraints:";
951 buf.writestring(msg);
956 buf.writestring(" whose parameters have the following constraints:");
958 const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
959 buf.writestring(sep);
963 buf.writestring(msg);
965 buf.writestring(sep);
966 tip = "not satisfied constraints are marked with `>`";
968 return buf.extractChars();
971 private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf)
973 buf.writestring(" with `");
975 // write usual arguments line-by-line
976 // skips trailing default ones - they are not present in `tiargs`
977 const bool variadic = isVariadic() !is null;
978 const end = cast(int)parameters.length - (variadic ? 1 : 0);
980 for (; i < tiargs.length && i < end; i++)
986 buf.writestring(" ");
988 write(buf, (*parameters)[i]);
989 buf.writestring(" = ");
990 write(buf, tiargs[i]);
992 // write remaining variadic arguments on the last line
999 buf.writestring(" ");
1001 write(buf, (*parameters)[end]);
1002 buf.writestring(" = ");
1004 if (cast(int)tiargs.length - end > 0)
1006 write(buf, tiargs[end]);
1007 foreach (j; parameters.length .. tiargs.length)
1009 buf.writestring(", ");
1010 write(buf, tiargs[j]);
1018 /******************************
1019 * Create a scope for the parameters of the TemplateInstance
1020 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
1022 * If paramsym is null a new ScopeDsymbol is used in place of
1025 * ti = the TemplateInstance whose parameters to generate the scope for.
1026 * sc = the parent scope of ti
1028 * a scope for the parameters of ti
1030 Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc)
1032 ScopeDsymbol paramsym = new ScopeDsymbol();
1033 paramsym.parent = _scope.parent;
1034 Scope* paramscope = _scope.push(paramsym);
1035 paramscope.tinst = ti;
1036 paramscope.minst = sc.minst;
1037 paramscope.callsc = sc;
1042 /***************************************
1043 * Given that ti is an instance of this TemplateDeclaration,
1044 * deduce the types of the parameters to this, and store
1045 * those deduced types in dedtypes[].
1047 * flag 1: don't do semantic() because of dummy types
1048 * 2: don't change types in matchArg()
1050 * dedtypes deduced arguments
1051 * Return match level.
1053 extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag)
1058 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag);
1062 printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes.dim, parameters.dim);
1064 printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, (*ti.tiargs)[0]);
1070 printf(" no match\n");
1072 return MATCH.nomatch;
1075 size_t dedtypes_dim = dedtypes.dim;
1080 return MATCH.nomatch;
1082 size_t parameters_dim = parameters.dim;
1083 int variadic = isVariadic() !is null;
1085 // If more arguments than parameters, no match
1086 if (ti.tiargs.dim > parameters_dim && !variadic)
1090 printf(" no match: more arguments than parameters\n");
1092 return MATCH.nomatch;
1095 assert(dedtypes_dim == parameters_dim);
1096 assert(dedtypes_dim >= ti.tiargs.dim || variadic);
1100 // Set up scope for template parameters
1101 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1103 // Attempt type deduction
1105 for (size_t i = 0; i < dedtypes_dim; i++)
1108 TemplateParameter tp = (*parameters)[i];
1111 //printf("\targument [%d]\n", i);
1114 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
1115 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
1117 printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
1121 m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam);
1123 //printf("\tm2 = %d\n", m2);
1124 if (m2 == MATCH.nomatch)
1128 printf("\tmatchArg() for parameter %i failed\n", i);
1137 sparam.dsymbolSemantic(paramscope);
1138 if (!paramscope.insert(sparam)) // TODO: This check can make more early
1140 // in TemplateDeclaration.semantic, and
1141 // then we don't need to make sparam if flags == 0
1148 /* Any parameter left without a type gets the type of
1149 * its corresponding arg
1151 foreach (i, ref dedtype; *dedtypes)
1155 assert(i < ti.tiargs.dim);
1156 dedtype = cast(Type)(*ti.tiargs)[i];
1161 if (m > MATCH.nomatch && constraint && !flag)
1163 if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error
1164 ti.parent = ti.enclosing;
1166 ti.parent = this.parent;
1168 // Similar to doHeaderInstantiation
1169 FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null;
1172 TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
1174 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
1176 fd.inferRetType = true;
1178 // Shouldn't run semantic on default arguments and return type.
1179 foreach (ref param; *tf.parameterList.parameters)
1180 param.defaultArg = null;
1183 tf.incomplete = true;
1185 // Resolve parameter types and 'auto ref's.
1187 uint olderrors = global.startGagging();
1188 fd.type = tf.typeSemantic(loc, paramscope);
1189 global.endGagging(olderrors);
1190 if (fd.type.ty != Tfunction)
1192 fd.originalType = fd.type; // for mangling
1195 // TODO: dedtypes => ti.tiargs ?
1196 if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
1202 // Print out the results
1203 printf("--------------------------\n");
1204 printf("template %s\n", toChars());
1205 printf("instance %s\n", ti.toChars());
1206 if (m > MATCH.nomatch)
1208 for (size_t i = 0; i < dedtypes_dim; i++)
1210 TemplateParameter tp = (*parameters)[i];
1213 if (i < ti.tiargs.dim)
1214 oarg = (*ti.tiargs)[i];
1217 tp.print(oarg, (*dedtypes)[i]);
1225 printf(" match = %d\n", m);
1231 printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
1236 /********************************************
1237 * Determine partial specialization order of 'this' vs td2.
1239 * match this is at least as specialized as td2
1240 * 0 td2 is more specialized than this
1242 MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs)
1244 enum LOG_LEASTAS = 0;
1245 static if (LOG_LEASTAS)
1247 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
1250 /* This works by taking the template parameters to this template
1251 * declaration and feeding them to td2 as if it were a template
1253 * If it works, then this template is at least as specialized
1257 // Set type arguments to dummy template instance to be types
1258 // generated from the parameters to this template declaration
1259 auto tiargs = new Objects();
1260 tiargs.reserve(parameters.dim);
1261 foreach (tp; *parameters)
1265 RootObject p = tp.dummyArg();
1266 if (!p) //TemplateTupleParameter
1271 scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance
1273 // Temporary Array to hold deduced types
1274 Objects dedtypes = Objects(td2.parameters.dim);
1276 // Attempt a type deduction
1277 MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1);
1278 if (m > MATCH.nomatch)
1280 /* A non-variadic template is more specialized than a
1283 TemplateTupleParameter tp = isVariadic();
1284 if (tp && !tp.dependent && !td2.isVariadic())
1287 static if (LOG_LEASTAS)
1289 printf(" matches %d, so is least as specialized\n", m);
1294 static if (LOG_LEASTAS)
1296 printf(" doesn't match, so is not as specialized\n");
1298 return MATCH.nomatch;
1301 /*************************************************
1302 * Match function arguments against a specific template function.
1305 * sc instantiation scope
1307 * tthis 'this' argument if !NULL
1308 * fargs arguments to function
1310 * fd Partially instantiated function declaration
1311 * ti.tdtypes Expression/Type deduced template arguments
1313 * match pair of initial and inferred template arguments
1315 extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs)
1319 size_t ntargs; // array size of tiargs
1320 size_t fptupindex = IDX_NOTFOUND;
1321 MATCH match = MATCH.exact;
1322 MATCH matchTiargs = MATCH.exact;
1323 ParameterList fparameters; // function parameter list
1324 VarArg fvarargs; // function varargs
1326 size_t inferStart = 0;
1328 Loc instLoc = ti.loc;
1329 Objects* tiargs = ti.tiargs;
1330 auto dedargs = new Objects();
1331 Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
1335 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
1336 for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++)
1338 Expression e = (*fargs)[i];
1339 printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars());
1341 printf("fd = %s\n", fd.toChars());
1342 printf("fd.type = %s\n", fd.type.toChars());
1344 printf("tthis = %s\n", tthis.toChars());
1349 dedargs.setDim(parameters.dim);
1352 dedtypes.setDim(parameters.dim);
1355 if (errors || fd.errors)
1356 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1358 // Set up scope for parameters
1359 Scope* paramscope = scopeForTemplateParameters(ti,sc);
1364 //printf("\tnomatch\n");
1365 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1368 MATCHpair matcherror()
1370 // todo: for the future improvement
1372 //printf("\terror\n");
1373 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
1375 // Mark the parameter scope as deprecated if the templated
1376 // function is deprecated (since paramscope.enclosing is the
1377 // calling scope already)
1378 paramscope.stc |= fd.storage_class & STC.deprecated_;
1380 TemplateTupleParameter tp = isVariadic();
1381 Tuple declaredTuple = null;
1385 for (size_t i = 0; i < dedargs.dim; i++)
1387 printf("\tdedarg[%d] = ", i);
1388 RootObject oarg = (*dedargs)[i];
1390 printf("%s", oarg.toChars());
1398 // Set initial template arguments
1399 ntargs = tiargs.dim;
1400 size_t n = parameters.dim;
1408 /* The extra initial template arguments
1409 * now form the tuple argument.
1411 auto t = new Tuple(ntargs - n);
1412 assert(parameters.dim);
1413 (*dedargs)[parameters.dim - 1] = t;
1415 for (size_t i = 0; i < t.objects.dim; i++)
1417 t.objects[i] = (*tiargs)[n + i];
1419 declareParameter(paramscope, tp, t);
1425 memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
1427 for (size_t i = 0; i < n; i++)
1429 assert(i < parameters.dim);
1430 Declaration sparam = null;
1431 MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
1432 //printf("\tdeduceType m = %d\n", m);
1433 if (m == MATCH.nomatch)
1435 if (m < matchTiargs)
1438 sparam.dsymbolSemantic(paramscope);
1439 if (!paramscope.insert(sparam))
1442 if (n < parameters.dim && !declaredTuple)
1447 inferStart = parameters.dim;
1448 //printf("tiargs matchTiargs = %d\n", matchTiargs);
1452 for (size_t i = 0; i < dedargs.dim; i++)
1454 printf("\tdedarg[%d] = ", i);
1455 RootObject oarg = (*dedargs)[i];
1457 printf("%s", oarg.toChars());
1462 fparameters = fd.getParameterList();
1463 nfparams = fparameters.length; // number of function parameters
1464 nfargs = fargs ? fargs.dim : 0; // number of function arguments
1466 /* Check for match of function arguments with variadic template
1467 * parameter, such as:
1469 * void foo(T, A...)(T t, A a);
1470 * void main() { foo(1,2,3); }
1472 if (tp) // if variadic
1474 // TemplateTupleParameter always makes most lesser matching.
1475 matchTiargs = MATCH.convert;
1477 if (nfparams == 0 && nfargs != 0) // if no function parameters
1481 auto t = new Tuple();
1482 //printf("t = %p\n", t);
1483 (*dedargs)[parameters.dim - 1] = t;
1484 declareParameter(paramscope, tp, t);
1490 /* Figure out which of the function parameters matches
1491 * the tuple template parameter. Do this by matching
1493 * Set the index of this function parameter to fptupindex.
1495 for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
1497 auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
1498 if (fparam.type.ty != Tident)
1500 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
1501 if (!tp.ident.equals(tid.ident) || tid.idents.dim)
1504 if (fparameters.varargs != VarArg.none) // variadic function doesn't
1505 return nomatch(); // go with variadic template
1509 fptupindex = IDX_NOTFOUND;
1514 if (toParent().isModule() || (_scope.stc & STC.static_))
1518 bool hasttp = false;
1520 // Match 'tthis' to any TemplateThisParameter's
1521 foreach (param; *parameters)
1523 if (auto ttp = param.isTemplateThisParameter())
1527 Type t = new TypeIdentifier(Loc.initial, ttp.ident);
1528 MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
1529 if (m == MATCH.nomatch)
1532 match = m; // pick worst match
1536 // Match attributes of tthis against attributes of fd
1537 if (fd.type && !fd.isCtorDeclaration())
1539 StorageClass stc = _scope.stc | fd.storage_class2;
1540 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
1542 while (p.isTemplateDeclaration() || p.isTemplateInstance())
1544 AggregateDeclaration ad = p.isAggregateDeclaration();
1546 stc |= ad.storage_class;
1548 ubyte mod = fd.type.mod;
1549 if (stc & STC.immutable_)
1550 mod = MODFlags.immutable_;
1553 if (stc & (STC.shared_ | STC.synchronized_))
1554 mod |= MODFlags.shared_;
1555 if (stc & STC.const_)
1556 mod |= MODFlags.const_;
1558 mod |= MODFlags.wild;
1561 ubyte thismod = tthis.mod;
1563 mod = MODmerge(thismod, mod);
1564 MATCH m = MODmethodConv(thismod, mod);
1565 if (m == MATCH.nomatch)
1572 // Loop through the function parameters
1574 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.dim : 0);
1575 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
1577 size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
1578 for (size_t parami = 0; parami < nfparams; parami++)
1580 Parameter fparam = fparameters[parami];
1582 // Apply function parameter storage classes to parameter types
1583 Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
1587 /* See function parameters which wound up
1588 * as part of a template tuple parameter.
1590 if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
1592 assert(prmtype.ty == Tident);
1593 TypeIdentifier tid = cast(TypeIdentifier)prmtype;
1596 /* The types of the function arguments
1597 * now form the tuple argument.
1599 declaredTuple = new Tuple();
1600 (*dedargs)[parameters.dim - 1] = declaredTuple;
1602 /* Count function parameters with no defaults following a tuple parameter.
1603 * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
1606 for (size_t j = parami + 1; j < nfparams; j++)
1608 Parameter p = fparameters[j];
1613 if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.dim]))
1615 Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
1616 rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.dim : 1;
1624 if (nfargs2 - argi < rem)
1626 declaredTuple.objects.setDim(nfargs2 - argi - rem);
1627 for (size_t i = 0; i < declaredTuple.objects.dim; i++)
1629 farg = (*fargs)[argi + i];
1631 // Check invalid arguments to detect errors early.
1632 if (farg.op == EXP.error || farg.type.ty == Terror)
1635 if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid)
1640 if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
1647 m = deduceTypeHelper(farg.type, &tt, tid);
1649 if (m == MATCH.nomatch)
1654 /* Remove top const for dynamic array types and pointer types
1656 if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
1658 tt = tt.mutableOf();
1660 declaredTuple.objects[i] = tt;
1662 declareParameter(paramscope, tp, declaredTuple);
1666 // https://issues.dlang.org/show_bug.cgi?id=6810
1667 // If declared tuple is not a type tuple,
1668 // it cannot be function parameter types.
1669 for (size_t i = 0; i < declaredTuple.objects.dim; i++)
1671 if (!isType(declaredTuple.objects[i]))
1675 assert(declaredTuple);
1676 argi += declaredTuple.objects.dim;
1680 // If parameter type doesn't depend on inferred template parameters,
1681 // semantic it to get actual type.
1682 if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.dim]))
1684 // should copy prmtype to avoid affecting semantic result
1685 prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
1687 if (prmtype.ty == Ttuple)
1689 TypeTuple tt = cast(TypeTuple)prmtype;
1690 size_t tt_dim = tt.arguments.dim;
1691 for (size_t j = 0; j < tt_dim; j++, ++argi)
1693 Parameter p = (*tt.arguments)[j];
1694 if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
1695 parami + 1 == nfparams && argi < nfargs)
1705 // https://issues.dlang.org/show_bug.cgi?id=19888
1706 if (fparam.defaultArg)
1711 farg = (*fargs)[argi];
1712 if (!farg.implicitConvTo(p.type))
1719 if (argi >= nfargs) // if not enough arguments
1721 if (!fparam.defaultArg)
1724 /* https://issues.dlang.org/show_bug.cgi?id=2803
1725 * Before the starting of type deduction from the function
1726 * default arguments, set the already deduced parameters into paramscope.
1727 * It's necessary to avoid breaking existing acceptable code. Cases:
1729 * 1. Already deduced template parameters can appear in fparam.defaultArg:
1730 * auto foo(A, B)(A a, B b = A.stringof);
1732 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
1734 * 2. If prmtype depends on default-specified template parameter, the
1735 * default type should be preferred.
1736 * auto foo(N = size_t, R)(R r, N start = 0)
1738 * // at fparam `N start = 0`, N should be 'size_t' before
1739 * // the deduction result from fparam.defaultArg.
1743 foreach (ref dedtype; *dedtypes)
1745 Type at = isType(dedtype);
1746 if (at && at.ty == Tnone)
1748 TypeDeduced xt = cast(TypeDeduced)at;
1749 dedtype = xt.tded; // 'unbox'
1752 for (size_t i = ntargs; i < dedargs.dim; i++)
1754 TemplateParameter tparam = (*parameters)[i];
1756 RootObject oarg = (*dedargs)[i];
1757 RootObject oded = (*dedtypes)[i];
1763 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
1765 /* The specialization can work as long as afterwards
1768 (*dedargs)[i] = oded;
1769 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
1770 //printf("m2 = %d\n", m2);
1771 if (m2 == MATCH.nomatch)
1773 if (m2 < matchTiargs)
1774 matchTiargs = m2; // pick worst match
1775 if (!(*dedtypes)[i].equals(oded))
1776 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
1780 if (MATCH.convert < matchTiargs)
1781 matchTiargs = MATCH.convert;
1783 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1788 oded = tparam.defaultArg(instLoc, paramscope);
1791 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
1797 /* If prmtype does not depend on any template parameters:
1799 * auto foo(T)(T v, double x = 0);
1801 * // at fparam == 'double x = 0'
1803 * or, if all template parameters in the prmtype are already deduced:
1805 * auto foo(R)(R range, ElementType!R sum = 0);
1807 * // at fparam == 'ElementType!R sum = 0'
1809 * Deducing prmtype from fparam.defaultArg is not necessary.
1811 if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope))
1817 // Deduce prmtype from the defaultArg.
1818 farg = fparam.defaultArg.syntaxCopy();
1819 farg = farg.expressionSemantic(paramscope);
1820 farg = resolveProperties(paramscope, farg);
1824 farg = (*fargs)[argi];
1827 // Check invalid arguments to detect errors early.
1828 if (farg.op == EXP.error || farg.type.ty == Terror)
1835 printf("\tfarg.type = %s\n", farg.type.toChars());
1836 printf("\tfparam.type = %s\n", prmtype.toChars());
1838 Type argtype = farg.type;
1840 if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != EXP.function_)
1843 // https://issues.dlang.org/show_bug.cgi?id=12876
1844 // Optimize argument to allow CT-known length matching
1845 farg = farg.optimize(WANTvalue, fparam.isReference());
1846 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
1848 RootObject oarg = farg;
1849 if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
1851 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
1854 if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
1856 if (farg.op == EXP.string_)
1858 StringExp se = cast(StringExp)farg;
1859 argtype = se.type.nextOf().sarrayOf(se.len);
1861 else if (farg.op == EXP.arrayLiteral)
1863 ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
1864 argtype = ae.type.nextOf().sarrayOf(ae.elements.dim);
1866 else if (farg.op == EXP.slice)
1868 SliceExp se = cast(SliceExp)farg;
1869 if (Type tsa = toStaticArrayType(se))
1876 else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.dim == 0)
1878 /* The farg passing to the prmtype always make a copy. Therefore,
1879 * we can shrink the set of the deduced type arguments for prmtype
1880 * by adjusting top-qualifier of the argtype.
1882 * prmtype argtype ta
1883 * T <- const(E)[] const(E)[]
1884 * T <- const(E[]) const(E)[]
1885 * qualifier(T) <- const(E)[] const(E[])
1886 * qualifier(T) <- const(E[]) const(E[])
1888 Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
1891 Expression ea = farg.copy();
1897 if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
1901 MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart);
1902 //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
1905 /* If no match, see if the argument can be matched by using
1906 * implicit conversions.
1908 if (m == MATCH.nomatch && prmtype.deco)
1909 m = farg.implicitConvTo(prmtype);
1911 if (m == MATCH.nomatch)
1913 AggregateDeclaration ad = isAggregate(farg.type);
1914 if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
1916 // https://issues.dlang.org/show_bug.cgi?id=12537
1917 // The isRecursiveAliasThis() call above
1919 /* If a semantic error occurs while doing alias this,
1920 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
1921 * just regard it as not a match.
1923 * We also save/restore sc.func.flags to avoid messing up
1924 * attribute inference in the evaluation.
1926 const oldflags = sc.func ? sc.func.flags : 0;
1927 auto e = resolveAliasThis(sc, farg, true);
1929 sc.func.flags = oldflags;
1938 if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
1940 if (!farg.isLvalue())
1942 if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
1944 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1946 else if (global.params.rvalueRefParam)
1948 // Allow implicit conversion to ref
1954 if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
1956 if (!farg.isLvalue())
1958 if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1961 if (m == MATCH.nomatch && (fparam.storageClass & STC.lazy_) && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
1963 if (m != MATCH.nomatch)
1966 match = m; // pick worst match
1973 /* The following code for variadic arguments closely
1974 * matches TypeFunction.callMatch()
1976 if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
1979 /* Check for match with function parameter T...
1981 Type tb = prmtype.toBasetype();
1984 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1988 // Perhaps we can do better with this, see TypeFunction.callMatch()
1989 if (tb.ty == Tsarray)
1991 TypeSArray tsa = cast(TypeSArray)tb;
1992 dinteger_t sz = tsa.dim.toInteger();
1993 if (sz != nfargs - argi)
1996 else if (tb.ty == Taarray)
1998 TypeAArray taa = cast(TypeAArray)tb;
1999 Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
2001 size_t i = templateParameterLookup(taa.index, parameters);
2002 if (i == IDX_NOTFOUND)
2009 uint errors = global.startGagging();
2010 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
2011 * The parameter isn't part of the template
2012 * ones, let's try to find it in the
2013 * instantiation scope 'sc' and the one
2014 * belonging to the template itself. */
2016 taa.index.resolve(instLoc, sco, e, t, s);
2020 taa.index.resolve(instLoc, sco, e, t, s);
2022 global.endGagging(errors);
2027 e = e.ctfeInterpret();
2028 e = e.implicitCastTo(sco, Type.tsize_t);
2029 e = e.optimize(WANTvalue);
2035 // This code matches code in TypeInstance.deduceType()
2036 TemplateParameter tprm = (*parameters)[i];
2037 TemplateValueParameter tvp = tprm.isTemplateValueParameter();
2040 Expression e = cast(Expression)(*dedtypes)[i];
2048 Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
2049 MATCH m = dim.implicitConvTo(vt);
2050 if (m == MATCH.nomatch)
2052 (*dedtypes)[i] = dim;
2060 TypeArray ta = cast(TypeArray)tb;
2061 Type tret = fparam.isLazyArray();
2062 for (; argi < nfargs; argi++)
2064 Expression arg = (*fargs)[argi];
2068 /* If lazy array of delegates,
2069 * convert arg(s) to delegate(s)
2073 if (ta.next.equals(arg.type))
2079 m = arg.implicitConvTo(tret);
2080 if (m == MATCH.nomatch)
2082 if (tret.toBasetype().ty == Tvoid)
2090 m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
2093 if (m == MATCH.nomatch)
2109 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
2110 if (argi != nfargs2 && fparameters.varargs == VarArg.none)
2115 foreach (ref dedtype; *dedtypes)
2117 Type at = isType(dedtype);
2122 TypeDeduced xt = cast(TypeDeduced)at;
2123 at = xt.tded; // 'unbox'
2125 dedtype = at.merge2();
2128 for (size_t i = ntargs; i < dedargs.dim; i++)
2130 TemplateParameter tparam = (*parameters)[i];
2131 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
2133 /* For T:T*, the dedargs is the T*, dedtypes is the T
2134 * But for function templates, we really need them to match
2136 RootObject oarg = (*dedargs)[i];
2137 RootObject oded = (*dedtypes)[i];
2138 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
2139 //if (oarg) printf("oarg: %s\n", oarg.toChars());
2140 //if (oded) printf("oded: %s\n", oded.toChars());
2146 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
2148 /* The specialization can work as long as afterwards
2151 (*dedargs)[i] = oded;
2152 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2153 //printf("m2 = %d\n", m2);
2154 if (m2 == MATCH.nomatch)
2156 if (m2 < matchTiargs)
2157 matchTiargs = m2; // pick worst match
2158 if (!(*dedtypes)[i].equals(oded))
2159 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
2163 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
2164 if (MATCH.convert < matchTiargs)
2165 matchTiargs = MATCH.convert;
2171 oded = tparam.defaultArg(instLoc, paramscope);
2175 // if tuple parameter and
2176 // tuple parameter was not in function parameter list and
2177 // we're one or more arguments short (i.e. no tuple argument)
2179 fptupindex == IDX_NOTFOUND &&
2180 ntargs <= dedargs.dim - 1)
2182 // make tuple argument an empty tuple
2189 return matcherror();
2192 /* At the template parameter T, the picked default template argument
2193 * X!int should be matched to T in order to deduce dependent
2194 * template parameter A.
2195 * auto foo(T : X!A = X!int, A...)() { ... }
2196 * foo(); // T <-- X!int, A <-- (int)
2198 if (tparam.specialization())
2200 (*dedargs)[i] = oded;
2201 MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
2202 //printf("m2 = %d\n", m2);
2203 if (m2 == MATCH.nomatch)
2205 if (m2 < matchTiargs)
2206 matchTiargs = m2; // pick worst match
2207 if (!(*dedtypes)[i].equals(oded))
2208 error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
2211 oded = declareParameter(paramscope, tparam, oded);
2212 (*dedargs)[i] = oded;
2215 /* https://issues.dlang.org/show_bug.cgi?id=7469
2216 * As same as the code for 7469 in findBestMatch,
2217 * expand a Tuple in dedargs to normalize template arguments.
2219 if (auto d = dedargs.dim)
2221 if (auto va = isTuple((*dedargs)[d - 1]))
2223 dedargs.setDim(d - 1);
2224 dedargs.insert(d - 1, &va.objects);
2227 ti.tiargs = dedargs; // update to the normalized template arguments.
2229 // Partially instantiate function for constraint and fd.leastAsSpecialized()
2231 assert(paramscope.scopesym);
2232 Scope* sc2 = _scope;
2233 sc2 = sc2.push(paramscope.scopesym);
2237 sc2.minst = sc.minst;
2238 sc2.stc |= fd.storage_class & STC.deprecated_;
2240 fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
2251 if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
2257 for (size_t i = 0; i < dedargs.dim; i++)
2259 RootObject o = (*dedargs)[i];
2260 printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
2265 //printf("\tmatch %d\n", match);
2266 return MATCHpair(matchTiargs, match);
2269 /**************************************************
2270 * Declare template parameter tp with value o, and install it in the scope sc.
2272 RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o)
2274 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
2275 Type ta = isType(o);
2276 Expression ea = isExpression(o);
2277 Dsymbol sa = isDsymbol(o);
2278 Tuple va = isTuple(o);
2281 VarDeclaration v = null;
2283 if (ea && ea.op == EXP.type)
2285 else if (ea && ea.op == EXP.scope_)
2286 sa = (cast(ScopeExp)ea).sds;
2287 else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
2288 sa = (cast(ThisExp)ea).var;
2289 else if (ea && ea.op == EXP.function_)
2291 if ((cast(FuncExp)ea).td)
2292 sa = (cast(FuncExp)ea).td;
2294 sa = (cast(FuncExp)ea).fd;
2299 //printf("type %s\n", ta.toChars());
2300 auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta);
2301 ad.storage_class |= STC.templateparameter;
2306 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
2307 auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa);
2308 ad.storage_class |= STC.templateparameter;
2313 // tdtypes.data[i] always matches ea here
2314 Initializer _init = new ExpInitializer(loc, ea);
2315 TemplateValueParameter tvp = tp.isTemplateValueParameter();
2316 Type t = tvp ? tvp.valType : null;
2317 v = new VarDeclaration(loc, t, tp.ident, _init);
2318 v.storage_class = STC.manifest | STC.templateparameter;
2323 //printf("\ttuple\n");
2324 d = new TupleDeclaration(loc, tp.ident, &va.objects);
2330 d.storage_class |= STC.templateparameter;
2335 // consistent with Type.checkDeprecated()
2336 while (t.ty != Tenum)
2340 t = (cast(TypeNext)t).next;
2342 if (Dsymbol s = t.toDsymbol(sc))
2344 if (s.isDeprecated())
2345 d.storage_class |= STC.deprecated_;
2350 if (sa.isDeprecated())
2351 d.storage_class |= STC.deprecated_;
2355 error("declaration `%s` is already defined", tp.ident.toChars());
2356 d.dsymbolSemantic(sc);
2357 /* So the caller's o gets updated with the result of semantic() being run on o
2360 o = v._init.initializerToExpression();
2364 /*************************************************
2365 * Limited function template instantiation for using fd.leastAsSpecialized()
2367 extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs)
2372 printf("doHeaderInstantiation this = %s\n", toChars());
2375 // function body and contracts are not need
2376 if (fd.isCtorDeclaration())
2377 fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy());
2379 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy());
2382 assert(fd.type.ty == Tfunction);
2383 auto tf = fd.type.isTypeFunction();
2388 // Match 'tthis' to any TemplateThisParameter's
2389 bool hasttp = false;
2390 foreach (tp; *parameters)
2392 TemplateThisParameter ttp = tp.isTemplateThisParameter();
2398 tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
2403 Scope* scx = sc2.push();
2405 // Shouldn't run semantic on default arguments and return type.
2406 foreach (ref params; *tf.parameterList.parameters)
2407 params.defaultArg = null;
2408 tf.incomplete = true;
2410 if (fd.isCtorDeclaration())
2412 // For constructors, emitting return type is necessary for
2413 // isReturnIsolated() in functionResolve.
2416 Dsymbol parent = toParentDecl();
2418 AggregateDeclaration ad = parent.isAggregateDeclaration();
2419 if (!ad || parent.isUnionDeclaration())
2425 tret = ad.handleType();
2427 tret = tret.addStorageClass(fd.storage_class | scx.stc);
2428 tret = tret.addMod(tf.mod);
2431 if (ad && ad.isStructDeclaration())
2433 //printf("tf = %s\n", tf.toChars());
2438 fd.type = fd.type.addSTC(scx.stc);
2439 fd.type = fd.type.typeSemantic(fd.loc, scx);
2442 if (fd.type.ty != Tfunction)
2445 fd.originalType = fd.type; // for mangling
2446 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
2447 //printf("fd.needThis() = %d\n", fd.needThis());
2452 debug (FindExistingInstance)
2454 __gshared uint nFound, nNotFound, nAdded, nRemoved;
2456 shared static ~this()
2458 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
2459 nFound, nNotFound, nAdded, nRemoved);
2463 /****************************************************
2464 * Given a new instance tithis of this TemplateDeclaration,
2465 * see if there already exists an instance.
2466 * If so, return that existing instance.
2468 extern (D) TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs)
2470 //printf("findExistingInstance() %s\n", tithis.toChars());
2471 tithis.fargs = fargs;
2472 auto tibox = TemplateInstanceBox(tithis);
2473 auto p = tibox in instances;
2474 debug (FindExistingInstance) ++(p ? nFound : nNotFound);
2475 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
2476 return p ? *p : null;
2479 /********************************************
2480 * Add instance ti to TemplateDeclaration's table of instances.
2481 * Return a handle we can use to later remove it if it fails instantiation.
2483 extern (D) TemplateInstance addInstance(TemplateInstance ti)
2485 //printf("addInstance() %p %s\n", instances, ti.toChars());
2486 auto tibox = TemplateInstanceBox(ti);
2487 instances[tibox] = ti;
2488 debug (FindExistingInstance) ++nAdded;
2492 /*******************************************
2493 * Remove TemplateInstance from table of instances.
2495 * handle returned by addInstance()
2497 extern (D) void removeInstance(TemplateInstance ti)
2499 //printf("removeInstance() %s\n", ti.toChars());
2500 auto tibox = TemplateInstanceBox(ti);
2501 debug (FindExistingInstance) ++nRemoved;
2502 instances.remove(tibox);
2505 override inout(TemplateDeclaration) isTemplateDeclaration() inout
2511 * Check if the last template parameter is a tuple one,
2512 * and returns it if so, else returns `null`.
2515 * The last template parameter if it's a `TemplateTupleParameter`
2517 TemplateTupleParameter isVariadic()
2519 size_t dim = parameters.dim;
2522 return (*parameters)[dim - 1].isTemplateTupleParameter();
2525 extern(C++) override bool isDeprecated() const
2527 return this.deprecated_;
2530 /***********************************
2531 * We can overload templates.
2533 override bool isOverloadable() const
2538 override void accept(Visitor v)
2544 extern (C++) final class TypeDeduced : Type
2547 Expressions argexps; // corresponding expressions
2548 Types tparams; // tparams[i].mod
2550 extern (D) this(Type tt, Expression e, Type tparam)
2555 tparams.push(tparam);
2558 void update(Expression e, Type tparam)
2561 tparams.push(tparam);
2564 void update(Type tt, Expression e, Type tparam)
2568 tparams.push(tparam);
2571 MATCH matchAll(Type tt)
2573 MATCH match = MATCH.exact;
2574 foreach (j, e; argexps)
2577 if (e == emptyArrayElement)
2580 Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_);
2582 MATCH m = e.implicitConvTo(t);
2585 if (match == MATCH.nomatch)
2593 /*************************************************
2594 * Given function arguments, figure out which template function
2595 * to expand, and return matching result.
2597 * m = matching result
2598 * dstart = the root of overloaded function templates
2599 * loc = instantiation location
2600 * sc = instantiation scope
2601 * tiargs = initial list of template arguments
2602 * tthis = if !NULL, the 'this' pointer argument
2603 * fargs = arguments to function
2604 * pMessage = address to store error message, or null
2606 void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
2607 Type tthis, Expressions* fargs, const(char)** pMessage = null)
2609 Expression[] fargs_ = fargs.peekSlice();
2612 printf("functionResolve() dstart = %s\n", dstart.toChars());
2613 printf(" tiargs:\n");
2616 for (size_t i = 0; i < tiargs.dim; i++)
2618 RootObject arg = (*tiargs)[i];
2619 printf("\t%s\n", arg.toChars());
2622 printf(" fargs:\n");
2623 for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++)
2625 Expression arg = (*fargs)[i];
2626 printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
2627 //printf("\tty = %d\n", arg.type.ty);
2629 //printf("stc = %llx\n", dstart.scope.stc);
2630 //printf("match:t/f = %d/%d\n", ta_last, m.last);
2634 int property = 0; // 0: uninitialized
2635 // 1: seen @property
2637 size_t ov_index = 0;
2638 TemplateDeclaration td_best;
2639 TemplateInstance ti_best;
2640 MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch;
2643 int applyFunction(FuncDeclaration fd)
2648 // explicitly specified tiargs never match to non template function
2649 if (tiargs && tiargs.dim > 0)
2652 // constructors need a valid scope in order to detect semantic errors
2653 if (!fd.isCtorDeclaration &&
2654 fd.semanticRun < PASS.semanticdone)
2656 Ungag ungag = fd.ungagSpeculative();
2657 fd.dsymbolSemantic(null);
2659 if (fd.semanticRun < PASS.semanticdone)
2661 .error(loc, "forward reference to template `%s`", fd.toChars());
2664 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
2665 auto tf = cast(TypeFunction)fd.type;
2667 int prop = tf.isproperty ? 1 : 2;
2670 else if (property != prop)
2671 error(fd.loc, "cannot overload both property and non-property functions");
2673 /* For constructors, qualifier check will be opposite direction.
2674 * Qualified constructor always makes qualified object, then will be checked
2675 * that it is implicitly convertible to tthis.
2677 Type tthis_fd = fd.needThis() ? tthis : null;
2678 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2681 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
2682 // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
2683 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2684 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2685 fd.isReturnIsolated())
2687 /* && tf.isShared() == tthis_fd.isShared()*/
2688 // Uniquely constructed object can ignore shared qualifier.
2689 // TODO: Is this appropriate?
2693 return 0; // MATCH.nomatch
2696 If a struct is declared as shared the dtor is automatically
2697 considered to be shared, but when the struct is instantiated
2698 the instance is no longer considered to be shared when the
2699 function call matching is done. The fix makes it so that if a
2700 struct declaration is shared, when the destructor is called,
2701 the instantiated struct is also considered shared.
2703 if (auto dt = fd.isDtorDeclaration())
2705 auto dtmod = dt.type.toTypeFunction();
2706 auto shared_dtor = dtmod.mod & MODFlags.shared_;
2707 auto shared_this = tthis_fd !is null ?
2708 tthis_fd.mod & MODFlags.shared_ : 0;
2709 if (shared_dtor && !shared_this)
2711 else if (shared_this && !shared_dtor && tthis_fd !is null)
2712 tf.mod = tthis_fd.mod;
2714 MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, pMessage, sc);
2715 //printf("test1: mfa = %d\n", mfa);
2716 if (mfa == MATCH.nomatch)
2719 if (mfa > m.last) goto LfIsBetter;
2720 if (mfa < m.last) goto LlastIsBetter;
2722 /* See if one of the matches overrides the other.
2725 if (m.lastf.overrides(fd)) goto LlastIsBetter;
2726 if (fd.overrides(m.lastf)) goto LfIsBetter;
2728 /* Try to disambiguate using template-style partial ordering rules.
2729 * In essence, if f() and g() are ambiguous, if f() can call g(),
2730 * but g() cannot call f(), then pick f().
2731 * This is because f() is "more specialized."
2734 MATCH c1 = fd.leastAsSpecialized(m.lastf);
2735 MATCH c2 = m.lastf.leastAsSpecialized(fd);
2736 //printf("c1 = %d, c2 = %d\n", c1, c2);
2737 if (c1 > c2) goto LfIsBetter;
2738 if (c1 < c2) goto LlastIsBetter;
2741 /* The 'overrides' check above does covariant checking only
2742 * for virtual member functions. It should do it for all functions,
2743 * but in order to not risk breaking code we put it after
2744 * the 'leastAsSpecialized' check.
2745 * In the future try moving it before.
2746 * I.e. a not-the-same-but-covariant match is preferred,
2747 * as it is more restrictive.
2749 if (!m.lastf.type.equals(fd.type))
2751 //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
2752 const lastCovariant = m.lastf.type.covariant(fd.type);
2753 const firstCovariant = fd.type.covariant(m.lastf.type);
2755 if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no)
2757 if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no)
2762 else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no)
2768 /* If the two functions are the same function, like:
2770 * int foo(int x) { ... }
2771 * then pick the one with the body.
2773 * If none has a body then don't care because the same
2774 * real function would be linked to the decl (e.g from object file)
2776 if (tf.equals(m.lastf.type) &&
2777 fd.storage_class == m.lastf.storage_class &&
2778 fd.parent == m.lastf.parent &&
2779 fd.visibility == m.lastf.visibility &&
2780 fd.linkage == m.lastf.linkage)
2782 if (fd.fbody && !m.lastf.fbody)
2788 // https://issues.dlang.org/show_bug.cgi?id=14450
2789 // Prefer exact qualified constructor for the creating object type
2790 if (isCtorCall && tf.mod != m.lastf.type.mod)
2792 if (tthis.mod == tf.mod) goto LfIsBetter;
2793 if (tthis.mod == m.lastf.type.mod) goto LlastIsBetter;
2806 ta_last = MATCH.exact;
2809 tthis_best = tthis_fd;
2816 int applyTemplate(TemplateDeclaration td)
2818 //printf("applyTemplate()\n");
2821 td.error(loc, "recursive template expansion");
2824 if (td == td_best) // skip duplicates
2828 sc = td._scope; // workaround for Type.aliasthisOf
2830 if (td.semanticRun == PASS.init && td._scope)
2832 // Try to fix forward reference. Ungag errors while doing so.
2833 Ungag ungag = td.ungagSpeculative();
2834 td.dsymbolSemantic(td._scope);
2836 if (td.semanticRun == PASS.init)
2838 .error(loc, "forward reference to template `%s`", td.toChars());
2842 m.last = MATCH.nomatch;
2845 //printf("td = %s\n", td.toChars());
2847 auto f = td.onemember ? td.onemember.isFuncDeclaration() : null;
2851 tiargs = new Objects();
2852 auto ti = new TemplateInstance(loc, td, tiargs);
2853 Objects dedtypes = Objects(td.parameters.dim);
2854 assert(td.semanticRun != PASS.init);
2855 MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0);
2856 //printf("matchWithInstance = %d\n", mta);
2857 if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
2860 ti.templateInstanceSemantic(sc, fargs);
2861 if (!ti.inst) // if template failed to expand
2864 Dsymbol s = ti.inst.toAlias();
2866 if (auto tdx = s.isTemplateDeclaration())
2868 Objects dedtypesX; // empty tiargs
2870 // https://issues.dlang.org/show_bug.cgi?id=11553
2871 // Check for recursive instantiation of tdx.
2872 for (TemplatePrevious* p = tdx.previous; p; p = p.prev)
2874 if (arrayObjectMatch(p.dedargs, &dedtypesX))
2876 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
2877 /* It must be a subscope of p.sc, other scope chains are not recursive
2880 for (Scope* scx = sc; scx; scx = scx.enclosing)
2884 error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars());
2889 /* BUG: should also check for ref param differences
2893 TemplatePrevious pr;
2894 pr.prev = tdx.previous;
2896 pr.dedargs = &dedtypesX;
2897 tdx.previous = ≺ // add this to threaded list
2899 fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
2901 tdx.previous = pr.prev; // unlink from threaded list
2903 else if (s.isFuncDeclaration())
2905 fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
2913 if (fd.type.ty != Tfunction)
2915 m.lastf = fd; // to propagate "error match"
2917 m.last = MATCH.nomatch;
2921 Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
2923 auto tf = cast(TypeFunction)fd.type;
2924 MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, null, sc);
2928 if (mta < ta_last) goto Ltd_best2;
2929 if (mta > ta_last) goto Ltd2;
2931 if (mfa < m.last) goto Ltd_best2;
2932 if (mfa > m.last) goto Ltd2;
2934 // td_best and td are ambiguous
2935 //printf("Lambig2\n");
2944 // td is the new best match
2948 property = 0; // (backward compatibility)
2952 tthis_best = tthis_fd;
2959 //printf("td = %s\n", td.toChars());
2960 for (size_t ovi = 0; f; f = f.overnext0, ovi++)
2962 if (f.type.ty != Tfunction || f.errors)
2965 /* This is a 'dummy' instance to evaluate constraint properly.
2967 auto ti = new TemplateInstance(loc, td, tiargs);
2968 ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary.
2971 MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
2974 //printf("match:t/f = %d/%d\n", mta, mfa);
2975 if (!fd || mfa == MATCH.nomatch)
2978 Type tthis_fd = fd.needThis() ? tthis : null;
2980 bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
2983 // Constructor call requires additional check.
2985 auto tf = cast(TypeFunction)fd.type;
2987 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
2988 tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
2989 fd.isReturnIsolated())
2994 continue; // MATCH.nomatch
2997 if (mta < ta_last) goto Ltd_best;
2998 if (mta > ta_last) goto Ltd;
3000 if (mfa < m.last) goto Ltd_best;
3001 if (mfa > m.last) goto Ltd;
3005 // Disambiguate by picking the most specialized TemplateDeclaration
3006 MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
3007 MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
3008 //printf("1: c1 = %d, c2 = %d\n", c1, c2);
3009 if (c1 > c2) goto Ltd;
3010 if (c1 < c2) goto Ltd_best;
3012 assert(fd && m.lastf);
3014 // Disambiguate by tf.callMatch
3015 auto tf1 = fd.type.isTypeFunction();
3016 auto tf2 = m.lastf.type.isTypeFunction();
3017 MATCH c1 = tf1.callMatch(tthis_fd, fargs_, 0, null, sc);
3018 MATCH c2 = tf2.callMatch(tthis_best, fargs_, 0, null, sc);
3019 //printf("2: c1 = %d, c2 = %d\n", c1, c2);
3020 if (c1 > c2) goto Ltd;
3021 if (c1 < c2) goto Ltd_best;
3024 // Disambiguate by picking the most specialized FunctionDeclaration
3025 MATCH c1 = fd.leastAsSpecialized(m.lastf);
3026 MATCH c2 = m.lastf.leastAsSpecialized(fd);
3027 //printf("3: c1 = %d, c2 = %d\n", c1, c2);
3028 if (c1 > c2) goto Ltd;
3029 if (c1 < c2) goto Ltd_best;
3032 // https://issues.dlang.org/show_bug.cgi?id=14450
3033 // Prefer exact qualified constructor for the creating object type
3034 if (isCtorCall && fd.type.mod != m.lastf.type.mod)
3036 if (tthis.mod == fd.type.mod) goto Ltd;
3037 if (tthis.mod == m.lastf.type.mod) goto Ltd_best;
3044 Ltd_best: // td_best is the best match so far
3045 //printf("Ltd_best\n");
3048 Ltd: // td is the new best match
3053 property = 0; // (backward compatibility)
3057 tthis_best = tthis_fd;
3066 auto td = dstart.isTemplateDeclaration();
3067 if (td && td.funcroot)
3068 dstart = td.funcroot;
3069 overloadApply(dstart, (Dsymbol s)
3073 if (auto fd = s.isFuncDeclaration())
3074 return applyFunction(fd);
3075 if (auto td = s.isTemplateDeclaration())
3076 return applyTemplate(td);
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);
3090 sc = td_best._scope; // workaround for Type.aliasthisOf
3092 auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs);
3093 ti.templateInstanceSemantic(sc, fargs);
3095 m.lastf = ti.toAlias().isFuncDeclaration();
3103 m.last = MATCH.nomatch;
3107 // look forward instantiated overload function
3108 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
3109 // it has filled overnext0d
3112 m.lastf = m.lastf.overnext0;
3116 tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null;
3118 if (m.lastf.type.ty == Terror)
3120 auto tf = m.lastf.type.isTypeFunction();
3121 if (!tf.callMatch(tthis_best, fargs_, 0, null, sc))
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);
3139 // Matches to non template function,
3140 // or found matches were ambiguous.
3141 assert(m.count >= 1);
3148 m.last = MATCH.nomatch;
3152 /* ======================== Type ============================================ */
3155 * Given an identifier, figure out which TemplateParameter it is.
3156 * Return IDX_NOTFOUND if not found.
3158 private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters)
3160 for (size_t i = 0; i < parameters.dim; i++)
3162 TemplateParameter tp = (*parameters)[i];
3163 if (tp.ident.equals(id))
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)
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_);
3213 wm = MODFlags.mutable;
3214 ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_);
3215 *at = t.unqualify(m);
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;
3240 * Returns the common type of the 2 types.
3242 private Type rawTypeMerge(Type t1, Type t2)
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))
3253 if (t1b.equivalent(t2b))
3254 return t1b.castMod(MODmerge(t1b.mod, t2b.mod));
3256 auto ty = implicitConvCommonTy(t1b.ty, t2b.ty);
3258 return Type.basic[ty];
3263 private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
3267 auto X(T, U)(T U, U T)
3269 return (U << 4) | T;
3272 switch (X(tparam.mod, t.mod))
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_):
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)
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();
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();
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)
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();
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;
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.
3486 * template Foo(T:T*) // template declaration
3487 * Foo!(int*) // template instantiation
3491 * parameters = [ T:T* ] // Array of TemplateParameter's
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;
3503 TemplateParameters* parameters;
3507 bool ignoreAliasThis;
3510 extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis)
3513 this.tparam = tparam;
3514 this.parameters = parameters;
3515 this.dedtypes = dedtypes;
3517 this.inferStart = inferStart;
3518 this.ignoreAliasThis = ignoreAliasThis;
3519 result = MATCH.nomatch;
3522 override void visit(Type t)
3530 if (tparam.ty == Tident)
3532 // Determine which parameter tparam is
3533 size_t i = templateParameterLookup(tparam, parameters);
3534 if (i == IDX_NOTFOUND)
3539 /* Need a loc to go with the semantic routine.
3544 TemplateParameter tp = (*parameters)[0];
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);
3557 TemplateParameter tp = (*parameters)[i];
3559 TypeIdentifier tident = cast(TypeIdentifier)tparam;
3560 if (tident.idents.dim > 0)
3562 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
3563 Dsymbol s = t.toDsymbol(sc);
3564 for (size_t j = tident.idents.dim; j-- > 0;)
3566 RootObject id = tident.idents[j];
3567 if (id.dyncast() == DYNCAST.identifier)
3569 if (!s || !s.parent)
3571 Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id);
3575 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
3578 if (Type tx = s2.getType())
3580 if (s != tx.toDsymbol(sc))
3591 //printf("[e] s = %s\n", s?s.toChars():"(null)");
3592 if (tp.isTemplateTypeParameter())
3594 Type tt = s.getType();
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;
3606 if (tp.isTemplateAliasParameter())
3608 Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
3618 // Found the corresponding parameter tp
3619 if (!tp.isTemplateTypeParameter())
3621 Type at = cast(Type)(*dedtypes)[i];
3623 if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
3628 (*dedtypes)[i] = tt;
3630 result = MATCH.constant;
3634 // type vs expressions
3637 TypeDeduced xt = cast(TypeDeduced)at;
3638 result = xt.matchAll(tt);
3639 if (result > MATCH.nomatch)
3641 (*dedtypes)[i] = tt;
3642 if (result > MATCH.constant)
3643 result = MATCH.constant; // limit level for inout matches
3651 (*dedtypes)[i] = tt; // Prefer current type match
3654 if (tt.implicitConvTo(at.constOf()))
3656 (*dedtypes)[i] = at.constOf().mutableOf();
3657 *wm |= MODFlags.const_;
3660 if (at.implicitConvTo(tt.constOf()))
3662 (*dedtypes)[i] = tt.constOf().mutableOf();
3663 *wm |= MODFlags.const_;
3668 else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
3673 (*dedtypes)[i] = tt;
3678 // type vs expressions
3681 TypeDeduced xt = cast(TypeDeduced)at;
3682 result = xt.matchAll(tt);
3683 if (result > MATCH.nomatch)
3685 (*dedtypes)[i] = tt;
3695 if (tt.ty == Tclass && at.ty == Tclass)
3697 result = tt.implicitConvTo(at);
3700 if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant)
3708 if (tparam.ty == Ttypeof)
3710 /* Need a loc to go with the semantic routine.
3715 TemplateParameter tp = (*parameters)[0];
3719 tparam = tparam.typeSemantic(loc, sc);
3721 if (t.ty != tparam.ty)
3723 if (Dsymbol sym = t.toDsymbol(sc))
3725 if (sym.isforwardRef() && !tparam.deco)
3729 MATCH m = t.implicitConvTo(tparam);
3730 if (m == MATCH.nomatch && !ignoreAliasThis)
3734 TypeClass tc = cast(TypeClass)t;
3735 if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
3737 if (auto ato = t.aliasthisOf())
3739 tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT);
3740 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3741 tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT);
3745 else if (t.ty == Tstruct)
3747 TypeStruct ts = cast(TypeStruct)t;
3748 if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
3750 if (auto ato = t.aliasthisOf())
3752 ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT);
3753 m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
3754 ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT);
3765 if (tparam.deco && !tparam.hasWild())
3767 result = t.implicitConvTo(tparam);
3771 Type tpn = tparam.nextOf();
3772 if (wm && t.ty == Taarray && tparam.isWild())
3774 // https://issues.dlang.org/show_bug.cgi?id=12403
3775 // In IFTI, stop inout matching on transitive part of AA types.
3776 tpn = tpn.substWildTo(MODFlags.mutable);
3779 result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm);
3784 result = MATCH.exact;
3788 result = MATCH.nomatch;
3792 result = MATCH.constant;
3795 override void visit(TypeVector t)
3797 if (tparam.ty == Tvector)
3799 TypeVector tp = cast(TypeVector)tparam;
3800 result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
3806 override void visit(TypeDArray t)
3811 override void visit(TypeSArray t)
3813 // Extra check that array dimensions must match
3816 if (tparam.ty == Tarray)
3818 MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3819 result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
3823 TemplateParameter tp = null;
3824 Expression edim = null;
3826 if (tparam.ty == Tsarray)
3828 TypeSArray tsa = cast(TypeSArray)tparam;
3829 if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
3831 Identifier id = (cast(VarExp)tsa.dim).var.ident;
3832 i = templateIdentifierLookup(id, parameters);
3833 assert(i != IDX_NOTFOUND);
3834 tp = (*parameters)[i];
3839 else if (tparam.ty == Taarray)
3841 TypeAArray taa = cast(TypeAArray)tparam;
3842 i = templateParameterLookup(taa.index, parameters);
3843 if (i != IDX_NOTFOUND)
3844 tp = (*parameters)[i];
3850 taa.index.resolve(Loc.initial, sc, e, tx, s);
3851 edim = s ? getValue(s) : getValue(e);
3854 if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
3856 result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
3863 override void visit(TypeAArray t)
3865 // Extra check that index type must match
3866 if (tparam && tparam.ty == Taarray)
3868 TypeAArray tp = cast(TypeAArray)tparam;
3869 if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
3871 result = MATCH.nomatch;
3878 override void visit(TypeFunction t)
3880 // Extra check that function characteristics must match
3882 return visit(cast(Type)t);
3884 if (auto tp = tparam.isTypeFunction())
3886 if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
3888 result = MATCH.nomatch;
3892 foreach (fparam; *tp.parameterList.parameters)
3894 // https://issues.dlang.org/show_bug.cgi?id=2579
3895 // Apply function parameter storage classes to parameter types
3896 fparam.type = fparam.type.addStorageClass(fparam.storageClass);
3897 fparam.storageClass &= ~(STC.TYPECTOR | STC.in_);
3899 // https://issues.dlang.org/show_bug.cgi?id=15243
3900 // Resolve parameter type if it's not related with template parameters
3901 if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.dim]))
3903 auto tx = fparam.type.typeSemantic(Loc.initial, sc);
3904 if (tx.ty == Terror)
3906 result = MATCH.nomatch;
3913 size_t nfargs = t.parameterList.length;
3914 size_t nfparams = tp.parameterList.length;
3916 /* See if tuple match
3918 if (nfparams > 0 && nfargs >= nfparams - 1)
3920 /* See if 'A' of the template parameter matches 'A'
3921 * of the type of the last function parameter.
3923 Parameter fparam = tp.parameterList[nfparams - 1];
3925 assert(fparam.type);
3926 if (fparam.type.ty != Tident)
3928 TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
3932 /* Look through parameters to find tuple matching tid.ident
3937 if (tupi == parameters.dim)
3939 TemplateParameter tx = (*parameters)[tupi];
3940 TemplateTupleParameter tup = tx.isTemplateTupleParameter();
3941 if (tup && tup.ident.equals(tid.ident))
3945 /* The types of the function arguments [nfparams - 1 .. nfargs]
3946 * now form the tuple argument.
3948 size_t tuple_dim = nfargs - (nfparams - 1);
3950 /* See if existing tuple, and whether it matches or not
3952 RootObject o = (*dedtypes)[tupi];
3955 // Existing deduced argument must be a tuple, and must match
3956 Tuple tup = isTuple(o);
3957 if (!tup || tup.objects.dim != tuple_dim)
3959 result = MATCH.nomatch;
3962 for (size_t i = 0; i < tuple_dim; i++)
3964 Parameter arg = t.parameterList[nfparams - 1 + i];
3965 if (!arg.type.equals(tup.objects[i]))
3967 result = MATCH.nomatch;
3975 auto tup = new Tuple(tuple_dim);
3976 for (size_t i = 0; i < tuple_dim; i++)
3978 Parameter arg = t.parameterList[nfparams - 1 + i];
3979 tup.objects[i] = arg.type;
3981 (*dedtypes)[tupi] = tup;
3983 nfparams--; // don't consider the last parameter for type deduction
3988 if (nfargs != nfparams)
3990 result = MATCH.nomatch;
3994 assert(nfparams <= tp.parameterList.length);
3995 foreach (i, ap; tp.parameterList)
4000 Parameter a = t.parameterList[i];
4002 if (!a.isCovariant(t.isref, ap) ||
4003 !deduceType(a.type, sc, ap.type, parameters, dedtypes))
4005 result = MATCH.nomatch;
4013 override void visit(TypeIdentifier t)
4016 if (tparam && tparam.ty == Tident)
4018 TypeIdentifier tp = cast(TypeIdentifier)tparam;
4019 for (size_t i = 0; i < t.idents.dim; i++)
4021 RootObject id1 = t.idents[i];
4022 RootObject id2 = tp.idents[i];
4023 if (!id1.equals(id2))
4025 result = MATCH.nomatch;
4033 override void visit(TypeInstance t)
4036 if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl)
4038 TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
4041 TypeInstance tp = cast(TypeInstance)tparam;
4043 //printf("tempinst.tempdecl = %p\n", tempdecl);
4044 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
4045 if (!tp.tempinst.tempdecl)
4047 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
4050 * template Foo(T : sa!(T), alias sa)
4052 size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
4053 if (i == IDX_NOTFOUND)
4055 /* Didn't find it as a parameter identifier. Try looking
4056 * it up and seeing if is an alias.
4057 * https://issues.dlang.org/show_bug.cgi?id=1454
4059 auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name);
4063 tid.resolve(tp.loc, sc, e, tx, s);
4066 s = tx.toDsymbol(sc);
4067 if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null)
4069 // https://issues.dlang.org/show_bug.cgi?id=14290
4070 // Try to match with ti.tempecl,
4071 // only when ti is an enclosing instance.
4072 Dsymbol p = sc.parent;
4073 while (p && p != ti)
4082 TemplateDeclaration td = s.isTemplateDeclaration();
4087 for (; td; td = td.overnext)
4096 TemplateParameter tpx = (*parameters)[i];
4097 if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
4100 else if (tempdecl != tp.tempinst.tempdecl)
4104 for (size_t i = 0; 1; i++)
4106 //printf("\ttest: tempinst.tiargs[%d]\n", i);
4107 RootObject o1 = null;
4108 if (i < t.tempinst.tiargs.dim)
4109 o1 = (*t.tempinst.tiargs)[i];
4110 else if (i < t.tempinst.tdtypes.dim && i < tp.tempinst.tiargs.dim)
4112 // Pick up default arg
4113 o1 = t.tempinst.tdtypes[i];
4115 else if (i >= tp.tempinst.tiargs.dim)
4118 if (i >= tp.tempinst.tiargs.dim)
4120 size_t dim = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
4121 while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
4126 break; // match if all remained parameters are dependent
4130 RootObject o2 = (*tp.tempinst.tiargs)[i];
4131 Type t2 = isType(o2);
4133 size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.dim - 1)
4134 ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
4135 if (j != IDX_NOTFOUND && j == parameters.dim - 1 &&
4136 (*parameters)[j].isTemplateTupleParameter())
4140 * alias A!(int, float) X;
4141 * static if (is(X Y == A!(Z), Z...)) {}
4142 * deduce that Z is a tuple(int, float)
4145 /* Create tuple from remaining args
4147 size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.dim : t.tempinst.tdtypes.dim) - i;
4148 auto vt = new Tuple(vtdim);
4149 for (size_t k = 0; k < vtdim; k++)
4152 if (k < t.tempinst.tiargs.dim)
4153 o = (*t.tempinst.tiargs)[i + k];
4154 else // Pick up default arg
4155 o = t.tempinst.tdtypes[i + k];
4159 Tuple v = cast(Tuple)(*dedtypes)[j];
4166 (*dedtypes)[j] = vt;
4172 Type t1 = isType(o1);
4173 Dsymbol s1 = isDsymbol(o1);
4174 Dsymbol s2 = isDsymbol(o2);
4175 Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
4176 Expression e2 = isExpression(o2);
4179 Tuple v1 = isTuple(o1);
4180 Tuple v2 = isTuple(o2);
4182 printf("t1 = %s\n", t1.toChars());
4184 printf("t2 = %s\n", t2.toChars());
4186 printf("e1 = %s\n", e1.toChars());
4188 printf("e2 = %s\n", e2.toChars());
4190 printf("s1 = %s\n", s1.toChars());
4192 printf("s2 = %s\n", s2.toChars());
4194 printf("v1 = %s\n", v1.toChars());
4196 printf("v2 = %s\n", v2.toChars());
4201 if (!deduceType(t1, sc, t2, parameters, dedtypes))
4207 e1 = e1.ctfeInterpret();
4209 /* If it is one of the template parameters for this template,
4210 * we should not attempt to interpret it. It already has a value.
4212 if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
4215 * (T:Number!(e2), int e2)
4217 j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters);
4218 if (j != IDX_NOTFOUND)
4220 // The template parameter was not from this template
4221 // (it may be from a parent template, for example)
4224 e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
4225 e2 = e2.ctfeInterpret();
4227 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
4228 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
4231 if (!e2.implicitConvTo(e1.type))
4234 e2 = e2.implicitCastTo(sc, e1.type);
4235 e2 = e2.ctfeInterpret();
4240 else if (e1 && t2 && t2.ty == Tident)
4242 j = templateParameterLookup(t2, parameters);
4244 if (j == IDX_NOTFOUND)
4246 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4251 if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
4260 else if (s1 && t2 && t2.ty == Tident)
4262 j = templateParameterLookup(t2, parameters);
4263 if (j == IDX_NOTFOUND)
4265 t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
4270 if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
4281 //printf("no match\n");
4282 result = MATCH.nomatch;
4285 override void visit(TypeStruct t)
4287 /* If this struct is a template struct, and we're matching
4288 * it against a template instance, convert the struct type
4289 * to a template instance, too, and try again.
4291 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4293 if (tparam && tparam.ty == Tinstance)
4295 if (ti && ti.toAlias() == t.sym)
4297 auto tx = new TypeInstance(Loc.initial, ti);
4298 result = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4302 /* Match things like:
4305 TypeInstance tpi = cast(TypeInstance)tparam;
4308 RootObject id = tpi.idents[tpi.idents.dim - 1];
4309 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4311 Type tparent = t.sym.parent.getType();
4314 /* Slice off the .foo in S!(T).foo
4317 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4326 if (tparam && tparam.ty == Tstruct)
4328 TypeStruct tp = cast(TypeStruct)tparam;
4330 //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
4331 if (wm && t.deduceWild(tparam, false))
4333 result = MATCH.constant;
4336 result = t.implicitConvTo(tp);
4342 override void visit(TypeEnum t)
4345 if (tparam && tparam.ty == Tenum)
4347 TypeEnum tp = cast(TypeEnum)tparam;
4348 if (t.sym == tp.sym)
4351 result = MATCH.nomatch;
4354 Type tb = t.toBasetype();
4355 if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray)
4357 result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
4358 if (result == MATCH.exact)
4359 result = MATCH.convert;
4365 /* Helper for TypeClass.deduceType().
4366 * Classes can match with implicit conversion to a base class or interface.
4367 * This is complicated, because there may be more than one base class which
4368 * matches. In such cases, one or more parameters remain ambiguous.
4371 * interface I(X, Y) {}
4372 * class C : I(uint, double), I(char, double) {}
4374 * foo(T, U)( I!(T, U) x)
4376 * deduces that U is double, but T remains ambiguous (could be char or uint).
4378 * Given a baseclass b, and initial deduced types 'dedtypes', this function
4379 * tries to match tparam with b, and also tries all base interfaces of b.
4380 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
4381 * types are ANDed with the current 'best' estimate for dedtypes.
4383 static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
4385 TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
4388 // Make a temporary copy of dedtypes so we don't destroy it
4389 auto tmpdedtypes = new Objects(dedtypes.dim);
4390 memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.dim * (void*).sizeof);
4392 auto t = new TypeInstance(Loc.initial, parti);
4393 MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
4394 if (m > MATCH.nomatch)
4396 // If this is the first ever match, it becomes our best estimate
4397 if (numBaseClassMatches == 0)
4398 memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.dim * (void*).sizeof);
4400 for (size_t k = 0; k < tmpdedtypes.dim; ++k)
4402 // If we've found more than one possible type for a parameter,
4403 // mark it as unknown.
4404 if ((*tmpdedtypes)[k] != (*best)[k])
4405 (*best)[k] = (*dedtypes)[k];
4407 ++numBaseClassMatches;
4411 // Now recursively test the inherited interfaces
4412 foreach (ref bi; b.baseInterfaces)
4414 deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4418 override void visit(TypeClass t)
4420 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
4422 /* If this class is a template class, and we're matching
4423 * it against a template instance, convert the class type
4424 * to a template instance, too, and try again.
4426 TemplateInstance ti = t.sym.parent.isTemplateInstance();
4428 if (tparam && tparam.ty == Tinstance)
4430 if (ti && ti.toAlias() == t.sym)
4432 auto tx = new TypeInstance(Loc.initial, ti);
4433 MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
4434 // Even if the match fails, there is still a chance it could match
4436 if (m != MATCH.nomatch)
4443 /* Match things like:
4446 TypeInstance tpi = cast(TypeInstance)tparam;
4449 RootObject id = tpi.idents[tpi.idents.dim - 1];
4450 if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
4452 Type tparent = t.sym.parent.getType();
4455 /* Slice off the .foo in S!(T).foo
4458 result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
4465 // If it matches exactly or via implicit conversion, we're done
4467 if (result != MATCH.nomatch)
4470 /* There is still a chance to match via implicit conversion to
4471 * a base class or interface. Because there could be more than one such
4472 * match, we need to check them all.
4475 int numBaseClassMatches = 0; // Have we found an interface match?
4477 // Our best guess at dedtypes
4478 auto best = new Objects(dedtypes.dim);
4480 ClassDeclaration s = t.sym;
4481 while (s && s.baseclasses.dim > 0)
4483 // Test the base class
4484 deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4486 // Test the interfaces inherited by the base class
4487 foreach (b; s.interfaces)
4489 deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
4491 s = (*s.baseclasses)[0].sym;
4494 if (numBaseClassMatches == 0)
4496 result = MATCH.nomatch;
4500 // If we got at least one match, copy the known types into dedtypes
4501 memcpy(dedtypes.tdata(), best.tdata(), best.dim * (void*).sizeof);
4502 result = MATCH.convert;
4507 if (tparam && tparam.ty == Tclass)
4509 TypeClass tp = cast(TypeClass)tparam;
4511 //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
4512 if (wm && t.deduceWild(tparam, false))
4514 result = MATCH.constant;
4517 result = t.implicitConvTo(tp);
4523 override void visit(Expression e)
4525 //printf("Expression.deduceType(e = %s)\n", e.toChars());
4526 size_t i = templateParameterLookup(tparam, parameters);
4527 if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.dim > 0)
4529 if (e == emptyArrayElement && tparam.ty == Tarray)
4531 Type tn = (cast(TypeNext)tparam).next;
4532 result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4535 e.type.accept(this);
4539 TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
4543 if (e == emptyArrayElement)
4547 result = MATCH.exact;
4552 tp.defaultType.accept(this);
4557 /* Returns `true` if `t` is a reference type, or an array of reference types
4559 bool isTopRef(Type t)
4561 auto tb = t.baseElemOf();
4562 return tb.ty == Tclass ||
4564 tb.ty == Tstruct && tb.hasPointers();
4567 Type at = cast(Type)(*dedtypes)[i];
4569 if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
4572 result = MATCH.constant;
4574 else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
4578 else if (!isTopRef(e.type))
4580 /* https://issues.dlang.org/show_bug.cgi?id=15653
4581 * In IFTI, recognize top-qualifier conversions
4582 * through the value copy, e.g.
4583 * int --> immutable(int)
4584 * immutable(string[]) --> immutable(string)[]
4586 tt = e.type.mutableOf();
4587 result = MATCH.convert;
4592 // expression vs (none)
4595 (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
4599 TypeDeduced xt = null;
4602 xt = cast(TypeDeduced)at;
4606 // From previous matched expressions to current deduced type
4607 MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch;
4609 // From current expressions to previous deduced type
4610 Type pt = at.addMod(tparam.mod);
4612 pt = pt.substWildTo(*wm);
4613 MATCH match2 = e.implicitConvTo(pt);
4615 if (match1 > MATCH.nomatch && match2 > MATCH.nomatch)
4617 if (at.implicitConvTo(tt) == MATCH.nomatch)
4618 match1 = MATCH.nomatch; // Prefer at
4619 else if (tt.implicitConvTo(at) == MATCH.nomatch)
4620 match2 = MATCH.nomatch; // Prefer tt
4621 else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod)
4623 if (!tt.isMutable() && !at.isMutable())
4624 tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod));
4625 else if (tt.isMutable())
4627 if (at.mod == 0) // Prefer unshared
4628 match1 = MATCH.nomatch;
4630 match2 = MATCH.nomatch;
4632 else if (at.isMutable())
4634 if (tt.mod == 0) // Prefer unshared
4635 match2 = MATCH.nomatch;
4637 match1 = MATCH.nomatch;
4639 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
4643 match1 = MATCH.nomatch;
4644 match2 = MATCH.nomatch;
4647 if (match1 > MATCH.nomatch)
4649 // Prefer current match: tt
4651 xt.update(tt, e, tparam);
4653 (*dedtypes)[i] = tt;
4657 if (match2 > MATCH.nomatch)
4659 // Prefer previous match: (*dedtypes)[i]
4661 xt.update(e, tparam);
4666 /* Deduce common type
4668 if (Type t = rawTypeMerge(at, tt))
4671 xt.update(t, e, tparam);
4675 pt = tt.addMod(tparam.mod);
4677 pt = pt.substWildTo(*wm);
4678 result = e.implicitConvTo(pt);
4682 result = MATCH.nomatch;
4685 MATCH deduceEmptyArrayElement()
4687 if (!emptyArrayElement)
4689 emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy
4690 emptyArrayElement.type = Type.tvoid;
4692 assert(tparam.ty == Tarray);
4694 Type tn = (cast(TypeNext)tparam).next;
4695 return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
4698 override void visit(NullExp e)
4700 if (tparam.ty == Tarray && e.type.ty == Tnull)
4702 // tparam:T[] <- e:null (void[])
4703 result = deduceEmptyArrayElement();
4706 visit(cast(Expression)e);
4709 override void visit(StringExp e)
4712 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
4714 // Consider compile-time known boundaries
4715 e.type.nextOf().sarrayOf(e.len).accept(this);
4718 visit(cast(Expression)e);
4721 override void visit(ArrayLiteralExp e)
4723 // https://issues.dlang.org/show_bug.cgi?id=20092
4724 if (e.elements && e.elements.dim && e.type.toBasetype().nextOf().ty == Tvoid)
4726 result = deduceEmptyArrayElement();
4729 if ((!e.elements || !e.elements.dim) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray)
4731 // tparam:T[] <- e:[] (void[])
4732 result = deduceEmptyArrayElement();
4736 if (tparam.ty == Tarray && e.elements && e.elements.dim)
4738 Type tn = (cast(TypeDArray)tparam).next;
4739 result = MATCH.exact;
4742 MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm);
4746 foreach (el; *e.elements)
4748 if (result == MATCH.nomatch)
4752 MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
4760 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
4762 // Consider compile-time known boundaries
4763 e.type.nextOf().sarrayOf(e.elements.dim).accept(this);
4766 visit(cast(Expression)e);
4769 override void visit(AssocArrayLiteralExp e)
4771 if (tparam.ty == Taarray && e.keys && e.keys.dim)
4773 TypeAArray taa = cast(TypeAArray)tparam;
4774 result = MATCH.exact;
4775 foreach (i, key; *e.keys)
4777 MATCH m1 = deduceType(key, sc, taa.index, parameters, dedtypes, wm);
4780 if (result == MATCH.nomatch)
4782 MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm);
4785 if (result == MATCH.nomatch)
4790 visit(cast(Expression)e);
4793 override void visit(FuncExp e)
4795 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
4801 auto tof = to.nextOf().isTypeFunction();
4805 // Parameter types inference from 'tof'
4806 assert(e.td._scope);
4807 TypeFunction tf = cast(TypeFunction)e.fd.type;
4808 //printf("\ttof = %s\n", tof.toChars());
4809 //printf("\ttf = %s\n", tf.toChars());
4810 const dim = tf.parameterList.length;
4812 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
4815 auto tiargs = new Objects();
4816 tiargs.reserve(e.td.parameters.dim);
4818 foreach (tp; *e.td.parameters)
4821 foreach (i, p; tf.parameterList)
4823 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4828 Parameter pto = tof.parameterList[u];
4831 Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
4832 if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.dim]))
4834 t = t.typeSemantic(e.loc, sc);
4840 // Set target of return type inference
4841 if (!tf.next && tof.next)
4844 auto ti = new TemplateInstance(e.loc, e.td, tiargs);
4845 Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope);
4847 // Reset inference target for the later re-semantic
4850 if (ex.op == EXP.error)
4852 if (ex.op != EXP.function_)
4860 if (t.ty == Tdelegate && tparam.ty == Tpointer)
4863 // Allow conversion from implicit function pointer to delegate
4864 if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
4866 TypeFunction tf = cast(TypeFunction)t.nextOf();
4867 t = (new TypeDelegate(tf)).merge();
4869 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
4873 override void visit(SliceExp e)
4876 if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
4878 // Consider compile-time known boundaries
4879 if (Type tsa = toStaticArrayType(e))
4882 if (result > MATCH.convert)
4883 result = MATCH.convert; // match with implicit conversion at most
4887 visit(cast(Expression)e);
4890 override void visit(CommaExp e)
4896 scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
4897 if (Type t = isType(o))
4899 else if (Expression e = isExpression(o))
4909 /***********************************************************
4910 * Check whether the type t representation relies on one or more the template parameters.
4912 * t = Tested type, if null, returns false.
4913 * tparams = Template parameters.
4914 * iStart = Start index of tparams to limit the tested parameters. If it's
4915 * nonzero, tparams[0..iStart] will be excluded from the test target.
4917 bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
4919 return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.dim]);
4922 /***********************************************************
4923 * Check whether the type t representation relies on one or more the template parameters.
4925 * t = Tested type, if null, returns false.
4926 * tparams = Template parameters.
4928 private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
4930 bool visitVector(TypeVector t)
4932 return t.basetype.reliesOnTemplateParameters(tparams);
4935 bool visitAArray(TypeAArray t)
4937 return t.next.reliesOnTemplateParameters(tparams) ||
4938 t.index.reliesOnTemplateParameters(tparams);
4941 bool visitFunction(TypeFunction t)
4943 foreach (i, fparam; t.parameterList)
4945 if (fparam.type.reliesOnTemplateParameters(tparams))
4948 return t.next.reliesOnTemplateParameters(tparams);
4951 bool visitIdentifier(TypeIdentifier t)
4953 foreach (tp; tparams)
4955 if (tp.ident.equals(t.ident))
4961 bool visitInstance(TypeInstance t)
4963 foreach (tp; tparams)
4965 if (t.tempinst.name == tp.ident)
4969 if (t.tempinst.tiargs)
4970 foreach (arg; *t.tempinst.tiargs)
4972 if (Type ta = isType(arg))
4974 if (ta.reliesOnTemplateParameters(tparams))
4982 bool visitTypeof(TypeTypeof t)
4984 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
4985 return t.exp.reliesOnTemplateParameters(tparams);
4988 bool visitTuple(TypeTuple t)
4991 foreach (arg; *t.arguments)
4993 if (arg.type.reliesOnTemplateParameters(tparams))
5003 Type tb = t.toBasetype();
5006 case Tvector: return visitVector(tb.isTypeVector());
5007 case Taarray: return visitAArray(tb.isTypeAArray());
5008 case Tfunction: return visitFunction(tb.isTypeFunction());
5009 case Tident: return visitIdentifier(tb.isTypeIdentifier());
5010 case Tinstance: return visitInstance(tb.isTypeInstance());
5011 case Ttypeof: return visitTypeof(tb.isTypeTypeof());
5012 case Ttuple: return visitTuple(tb.isTypeTuple());
5013 case Tenum: return false;
5014 default: return tb.nextOf().reliesOnTemplateParameters(tparams);
5018 /***********************************************************
5019 * Check whether the expression representation relies on one or more the template parameters.
5021 * e = expression to test
5022 * tparams = Template parameters.
5026 private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
5028 extern (C++) final class ReliesOnTemplateParameters : Visitor
5030 alias visit = Visitor.visit;
5032 TemplateParameter[] tparams;
5035 extern (D) this(TemplateParameter[] tparams)
5037 this.tparams = tparams;
5040 override void visit(Expression e)
5042 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
5045 override void visit(IdentifierExp e)
5047 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5048 foreach (tp; tparams)
5050 if (e.ident == tp.ident)
5058 override void visit(TupleExp e)
5060 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5063 foreach (ea; *e.exps)
5072 override void visit(ArrayLiteralExp e)
5074 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5077 foreach (el; *e.elements)
5086 override void visit(AssocArrayLiteralExp e)
5088 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5089 foreach (ek; *e.keys)
5095 foreach (ev; *e.values)
5103 override void visit(StructLiteralExp e)
5105 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5108 foreach (ea; *e.elements)
5117 override void visit(TypeExp e)
5119 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5120 result = e.type.reliesOnTemplateParameters(tparams);
5123 override void visit(NewExp e)
5125 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5127 e.thisexp.accept(this);
5128 if (!result && e.newargs)
5130 foreach (ea; *e.newargs)
5137 result = e.newtype.reliesOnTemplateParameters(tparams);
5138 if (!result && e.arguments)
5140 foreach (ea; *e.arguments)
5149 override void visit(NewAnonClassExp e)
5151 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5155 override void visit(FuncExp e)
5157 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5161 override void visit(TypeidExp e)
5163 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5164 if (auto ea = isExpression(e.obj))
5166 else if (auto ta = isType(e.obj))
5167 result = ta.reliesOnTemplateParameters(tparams);
5170 override void visit(TraitsExp e)
5172 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5175 foreach (oa; *e.args)
5177 if (auto ea = isExpression(oa))
5179 else if (auto ta = isType(oa))
5180 result = ta.reliesOnTemplateParameters(tparams);
5187 override void visit(IsExp e)
5189 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5190 result = e.targ.reliesOnTemplateParameters(tparams);
5193 override void visit(UnaExp e)
5195 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5199 override void visit(DotTemplateInstanceExp e)
5201 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5202 visit(cast(UnaExp)e);
5203 if (!result && e.ti.tiargs)
5205 foreach (oa; *e.ti.tiargs)
5207 if (auto ea = isExpression(oa))
5209 else if (auto ta = isType(oa))
5210 result = ta.reliesOnTemplateParameters(tparams);
5217 override void visit(CallExp e)
5219 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5220 visit(cast(UnaExp)e);
5221 if (!result && e.arguments)
5223 foreach (ea; *e.arguments)
5232 override void visit(CastExp e)
5234 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5235 visit(cast(UnaExp)e);
5236 // e.to can be null for cast() with no type
5237 if (!result && e.to)
5238 result = e.to.reliesOnTemplateParameters(tparams);
5241 override void visit(SliceExp e)
5243 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5244 visit(cast(UnaExp)e);
5245 if (!result && e.lwr)
5247 if (!result && e.upr)
5251 override void visit(IntervalExp e)
5253 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5259 override void visit(ArrayExp e)
5261 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5262 visit(cast(UnaExp)e);
5263 if (!result && e.arguments)
5265 foreach (ea; *e.arguments)
5270 override void visit(BinExp e)
5272 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5278 override void visit(CondExp e)
5280 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5281 e.econd.accept(this);
5283 visit(cast(BinExp)e);
5287 scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
5292 /***********************************************************
5293 * https://dlang.org/spec/template.html#TemplateParameter
5295 extern (C++) class TemplateParameter : ASTNode
5300 /* True if this is a part of precedent parameter specialization pattern.
5302 * template A(T : X!TL, alias X, TL...) {}
5303 * // X and TL are dependent template parameter
5305 * A dependent template parameter should return MATCH.exact in matchArg()
5306 * to respect the match level of the corresponding precedent parameter.
5310 /* ======================== TemplateParameter =============================== */
5311 extern (D) this(const ref Loc loc, Identifier ident)
5317 TemplateTypeParameter isTemplateTypeParameter()
5322 TemplateValueParameter isTemplateValueParameter()
5327 TemplateAliasParameter isTemplateAliasParameter()
5332 TemplateThisParameter isTemplateThisParameter()
5337 TemplateTupleParameter isTemplateTupleParameter()
5342 abstract TemplateParameter syntaxCopy();
5344 abstract bool declareParameter(Scope* sc);
5346 abstract void print(RootObject oarg, RootObject oded);
5348 abstract RootObject specialization();
5350 abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
5352 abstract bool hasDefaultArg();
5354 override const(char)* toChars() const
5356 return this.ident.toChars();
5359 override DYNCAST dyncast() const pure @nogc nothrow @safe
5361 return DYNCAST.templateparameter;
5364 /* Create dummy argument based on parameter.
5366 abstract RootObject dummyArg();
5368 override void accept(Visitor v)
5374 /***********************************************************
5375 * https://dlang.org/spec/template.html#TemplateTypeParameter
5377 * ident : specType = defaultType
5379 extern (C++) class TemplateTypeParameter : TemplateParameter
5381 Type specType; // if !=null, this is the type specialization
5384 extern (D) __gshared Type tdummy = null;
5386 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
5389 this.specType = specType;
5390 this.defaultType = defaultType;
5393 override final TemplateTypeParameter isTemplateTypeParameter()
5398 override TemplateTypeParameter syntaxCopy()
5400 return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5403 override final bool declareParameter(Scope* sc)
5405 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
5406 auto ti = new TypeIdentifier(loc, ident);
5407 Declaration ad = new AliasDeclaration(loc, ident, ti);
5408 return sc.insert(ad) !is null;
5411 override final void print(RootObject oarg, RootObject oded)
5413 printf(" %s\n", ident.toChars());
5415 Type t = isType(oarg);
5416 Type ta = isType(oded);
5420 printf("\tSpecialization: %s\n", specType.toChars());
5422 printf("\tDefault: %s\n", defaultType.toChars());
5423 printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
5424 printf("\tDeduced Type: %s\n", ta.toChars());
5427 override final RootObject specialization()
5432 override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5434 Type t = defaultType;
5438 t = t.typeSemantic(loc, sc); // use the parameter loc
5443 override final bool hasDefaultArg()
5445 return defaultType !is null;
5448 override final RootObject dummyArg()
5453 // Use this for alias-parameter's too (?)
5455 tdummy = new TypeIdentifier(loc, ident);
5461 override void accept(Visitor v)
5467 /***********************************************************
5468 * https://dlang.org/spec/template.html#TemplateThisParameter
5470 * this ident : specType = defaultType
5472 extern (C++) final class TemplateThisParameter : TemplateTypeParameter
5474 extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
5476 super(loc, ident, specType, defaultType);
5479 override TemplateThisParameter isTemplateThisParameter()
5484 override TemplateThisParameter syntaxCopy()
5486 return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
5489 override void accept(Visitor v)
5495 /***********************************************************
5496 * https://dlang.org/spec/template.html#TemplateValueParameter
5498 * valType ident : specValue = defaultValue
5500 extern (C++) final class TemplateValueParameter : TemplateParameter
5503 Expression specValue;
5504 Expression defaultValue;
5506 extern (D) __gshared Expression[void*] edummies;
5508 extern (D) this(const ref Loc loc, Identifier ident, Type valType,
5509 Expression specValue, Expression defaultValue)
5512 this.valType = valType;
5513 this.specValue = specValue;
5514 this.defaultValue = defaultValue;
5517 override TemplateValueParameter isTemplateValueParameter()
5522 override TemplateValueParameter syntaxCopy()
5524 return new TemplateValueParameter(loc, ident,
5525 valType.syntaxCopy(),
5526 specValue ? specValue.syntaxCopy() : null,
5527 defaultValue ? defaultValue.syntaxCopy() : null);
5530 override bool declareParameter(Scope* sc)
5532 auto v = new VarDeclaration(loc, valType, ident, null);
5533 v.storage_class = STC.templateparameter;
5534 return sc.insert(v) !is null;
5537 override void print(RootObject oarg, RootObject oded)
5539 printf(" %s\n", ident.toChars());
5540 Expression ea = isExpression(oded);
5542 printf("\tSpecialization: %s\n", specValue.toChars());
5543 printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
5546 override RootObject specialization()
5551 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5553 Expression e = defaultValue;
5557 uint olderrs = global.errors;
5558 if ((e = e.expressionSemantic(sc)) is null)
5560 if ((e = resolveProperties(sc, e)) is null)
5562 e = e.resolveLoc(instLoc, sc); // use the instantiated loc
5563 e = e.optimize(WANTvalue);
5564 if (global.errors != olderrs)
5570 override bool hasDefaultArg()
5572 return defaultValue !is null;
5575 override RootObject dummyArg()
5577 Expression e = specValue;
5580 // Create a dummy value
5581 auto pe = cast(void*)valType in edummies;
5584 e = valType.defaultInit(Loc.initial);
5585 edummies[cast(void*)valType] = e;
5593 override void accept(Visitor v)
5599 /***********************************************************
5600 * https://dlang.org/spec/template.html#TemplateAliasParameter
5602 * specType ident : specAlias = defaultAlias
5604 extern (C++) final class TemplateAliasParameter : TemplateParameter
5607 RootObject specAlias;
5608 RootObject defaultAlias;
5610 extern (D) __gshared Dsymbol sdummy = null;
5612 extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias)
5615 this.specType = specType;
5616 this.specAlias = specAlias;
5617 this.defaultAlias = defaultAlias;
5620 override TemplateAliasParameter isTemplateAliasParameter()
5625 override TemplateAliasParameter syntaxCopy()
5627 return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
5630 override bool declareParameter(Scope* sc)
5632 auto ti = new TypeIdentifier(loc, ident);
5633 Declaration ad = new AliasDeclaration(loc, ident, ti);
5634 return sc.insert(ad) !is null;
5637 override void print(RootObject oarg, RootObject oded)
5639 printf(" %s\n", ident.toChars());
5640 Dsymbol sa = isDsymbol(oded);
5642 printf("\tParameter alias: %s\n", sa.toChars());
5645 override RootObject specialization()
5650 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5652 RootObject da = defaultAlias;
5653 Type ta = isType(defaultAlias);
5656 if (ta.ty == Tinstance)
5658 // If the default arg is a template, instantiate for each type
5659 da = ta.syntaxCopy();
5663 RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc
5667 override bool hasDefaultArg()
5669 return defaultAlias !is null;
5672 override RootObject dummyArg()
5674 RootObject s = specAlias;
5678 sdummy = new Dsymbol();
5684 override void accept(Visitor v)
5690 /***********************************************************
5691 * https://dlang.org/spec/template.html#TemplateSequenceParameter
5695 extern (C++) final class TemplateTupleParameter : TemplateParameter
5697 extern (D) this(const ref Loc loc, Identifier ident)
5702 override TemplateTupleParameter isTemplateTupleParameter()
5707 override TemplateTupleParameter syntaxCopy()
5709 return new TemplateTupleParameter(loc, ident);
5712 override bool declareParameter(Scope* sc)
5714 auto ti = new TypeIdentifier(loc, ident);
5715 Declaration ad = new AliasDeclaration(loc, ident, ti);
5716 return sc.insert(ad) !is null;
5719 override void print(RootObject oarg, RootObject oded)
5721 printf(" %s... [", ident.toChars());
5722 Tuple v = isTuple(oded);
5725 //printf("|%d| ", v.objects.dim);
5726 foreach (i, o; v.objects)
5731 Dsymbol sa = isDsymbol(o);
5733 printf("alias: %s", sa.toChars());
5734 Type ta = isType(o);
5736 printf("type: %s", ta.toChars());
5737 Expression ea = isExpression(o);
5739 printf("exp: %s", ea.toChars());
5741 assert(!isTuple(o)); // no nested Tuple arguments
5746 override RootObject specialization()
5751 override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
5756 override bool hasDefaultArg()
5761 override RootObject dummyArg()
5766 override void accept(Visitor v)
5772 /***********************************************************
5773 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
5779 extern (C++) class TemplateInstance : ScopeDsymbol
5783 // Array of Types/Expressions of template
5784 // instance arguments [int*, char, 10*10]
5787 // Array of Types/Expressions corresponding
5788 // to TemplateDeclaration.parameters
5792 // Modules imported by this template instance
5793 Modules importedModules;
5795 Dsymbol tempdecl; // referenced by foo.bar.abc
5796 Dsymbol enclosing; // if referencing local symbols, this is the context
5797 Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
5798 TemplateInstance inst; // refer to existing instance
5799 ScopeDsymbol argsym; // argument symbol table
5800 size_t hash; // cached result of toHash()
5801 Expressions* fargs; // for function template, these are the function arguments
5803 TemplateInstances* deferred;
5805 Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
5807 // Used to determine the instance needs code generation.
5808 // Note that these are inaccurate until semantic analysis phase completed.
5809 TemplateInstance tinst; // enclosing template instance
5810 TemplateInstance tnext; // non-first instantiated instances
5811 Module minst; // the top module that instantiated this instance
5813 private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
5814 ubyte inuse; // for recursive expansion detection
5816 private enum Flag : uint
5818 semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
5819 havetempdecl = semantictiargsdone >> 1,
5820 gagged = semantictiargsdone >> 2,
5821 available = gagged - 1 // always last flag minus one, 1s for all available bits
5824 extern(D) final @safe @property pure nothrow @nogc
5826 ushort nest() const { return _nest & Flag.available; }
5827 void nestUp() { assert(nest() < Flag.available); ++_nest; }
5828 void nestDown() { assert(nest() > 0); --_nest; }
5829 /// has semanticTiargs() been done?
5830 bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
5831 void semantictiargsdone(bool x)
5833 if (x) _nest |= Flag.semantictiargsdone;
5834 else _nest &= ~Flag.semantictiargsdone;
5836 /// if used second constructor
5837 bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
5838 void havetempdecl(bool x)
5840 if (x) _nest |= Flag.havetempdecl;
5841 else _nest &= ~Flag.havetempdecl;
5843 /// if the instantiation is done with error gagging
5844 bool gagged() const { return (_nest & Flag.gagged) != 0; }
5847 if (x) _nest |= Flag.gagged;
5848 else _nest &= ~Flag.gagged;
5852 extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs)
5857 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
5860 this.tiargs = tiargs;
5864 * This constructor is only called when we figured out which function
5865 * template to instantiate.
5867 extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs)
5872 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
5874 this.name = td.ident;
5875 this.tiargs = tiargs;
5877 this.semantictiargsdone = true;
5878 this.havetempdecl = true;
5879 assert(tempdecl._scope);
5882 extern (D) static Objects* arraySyntaxCopy(Objects* objs)
5887 a = new Objects(objs.dim);
5888 foreach (i, o; *objs)
5889 (*a)[i] = objectSyntaxCopy(o);
5894 override TemplateInstance syntaxCopy(Dsymbol s)
5896 TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
5897 ti.tiargs = arraySyntaxCopy(tiargs);
5898 TemplateDeclaration td;
5899 if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
5900 td.ScopeDsymbol.syntaxCopy(ti);
5902 ScopeDsymbol.syntaxCopy(ti);
5906 // resolve real symbol
5907 override final Dsymbol toAlias()
5911 printf("TemplateInstance.toAlias()\n");
5915 // Maybe we can resolve it
5918 dsymbolSemantic(this, _scope);
5922 error("cannot resolve forward reference");
5929 return inst.toAlias();
5933 return aliasdecl.toAlias();
5939 override const(char)* kind() const
5941 return "template instance";
5944 override bool oneMember(Dsymbol* ps, Identifier ident)
5950 override const(char)* toChars() const
5953 toCBufferInstance(this, &buf);
5954 return buf.extractChars();
5957 override final const(char)* toPrettyCharsHelper()
5960 toCBufferInstance(this, &buf, true);
5961 return buf.extractChars();
5964 /**************************************
5965 * Given an error instantiating the TemplateInstance,
5966 * give the nested TemplateInstance instantiations that got
5967 * us here. Those are a list threaded into the nested scopes.
5969 extern(D) final void printInstantiationTrace(Classification cl = Classification.error)
5974 // Print full trace for verbose mode, otherwise only short traces
5975 const(uint) max_shown = !global.params.verbose ? 6 : uint.max;
5976 const(char)* format = "instantiated from here: `%s`";
5978 // This returns a function pointer
5979 scope printFn = () {
5982 case Classification.error:
5983 return &errorSupplemental;
5984 case Classification.warning:
5985 return &warningSupplemental;
5986 case Classification.deprecation:
5987 return &deprecationSupplemental;
5988 case Classification.gagged, Classification.tip:
5993 // determine instantiation depth and number of recursive instantiations
5994 int n_instantiations = 1;
5995 int n_totalrecursions = 0;
5996 for (TemplateInstance cur = this; cur; cur = cur.tinst)
5999 // Set error here as we don't want it to depend on the number of
6000 // entries that are being printed.
6001 if (cl == Classification.error ||
6002 (cl == Classification.warning && global.params.warnings == DiagnosticReporting.error) ||
6003 (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
6006 // If two instantiations use the same declaration, they are recursive.
6007 // (this works even if they are instantiated from different places in the
6009 // In principle, we could also check for multiple-template recursion, but it's
6010 // probably not worthwhile.
6011 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6012 ++n_totalrecursions;
6015 if (n_instantiations <= max_shown)
6017 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6018 printFn(cur.loc, format, cur.toChars());
6020 else if (n_instantiations - n_totalrecursions <= max_shown)
6022 // By collapsing recursive instantiations into a single line,
6023 // we can stay under the limit.
6024 int recursionDepth = 0;
6025 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6027 if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
6034 printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
6036 printFn(cur.loc, format, cur.toChars());
6043 // Even after collapsing the recursions, the depth is too deep.
6044 // Just display the first few and last few instantiations.
6046 for (TemplateInstance cur = this; cur; cur = cur.tinst)
6048 if (i == max_shown / 2)
6049 printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
6051 if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
6052 printFn(cur.loc, format, cur.toChars());
6058 /*************************************
6059 * Lazily generate identifier for template instance.
6060 * This is because 75% of the ident's are never needed.
6062 override final Identifier getIdent()
6064 if (!ident && inst && !errors)
6065 ident = genIdent(tiargs); // need an identifier for name mangling purposes.
6069 /*************************************
6070 * Compare proposed template instantiation with existing template instantiation.
6071 * Note that this is not commutative because of the auto ref check.
6073 * ti = existing template instantiation
6077 final bool equalsx(TemplateInstance ti)
6079 //printf("this = %p, ti = %p\n", this, ti);
6080 assert(tdtypes.dim == ti.tdtypes.dim);
6082 // Nesting must match
6083 if (enclosing != ti.enclosing)
6085 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
6088 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
6090 if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
6093 /* Template functions may have different instantiations based on
6094 * "auto ref" parameters.
6096 if (auto fd = ti.toAlias().isFuncDeclaration())
6100 auto fparameters = fd.getParameterList();
6101 size_t nfparams = fparameters.length; // Num function parameters
6102 for (size_t j = 0; j < nfparams; j++)
6104 Parameter fparam = fparameters[j];
6105 if (fparam.storageClass & STC.autoref) // if "auto ref"
6107 Expression farg = fargs && j < fargs.dim ? (*fargs)[j] : fparam.defaultArg;
6110 if (farg.isLvalue())
6112 if (!(fparam.storageClass & STC.ref_))
6113 goto Lnotequals; // auto ref's don't match
6117 if (fparam.storageClass & STC.ref_)
6118 goto Lnotequals; // auto ref's don't match
6130 final size_t toHash()
6134 hash = cast(size_t)cast(void*)enclosing;
6135 hash += arrayObjectHash(&tdtypes);
6142 Returns: true if the instances' innards are discardable.
6144 The idea of this function is to see if the template instantiation
6145 can be 100% replaced with its eponymous member. All other members
6146 can be discarded, even in the compiler to free memory (for example,
6147 the template could be expanded in a region allocator, deemed trivial,
6148 the end result copied back out independently and the entire region freed),
6149 and can be elided entirely from the binary.
6151 The current implementation affects code that generally looks like:
6154 template foo(args...) {
6155 some_basic_type_or_string helper() { .... }
6156 enum foo = helper();
6160 since it was the easiest starting point of implementation but it can and
6161 should be expanded more later.
6163 final bool isDiscardable()
6165 if (aliasdecl is null)
6168 auto v = aliasdecl.isVarDeclaration();
6172 if (!(v.storage_class & STC.manifest))
6175 // Currently only doing basic types here because it is the easiest proof-of-concept
6176 // implementation with minimal risk of side effects, but it could likely be
6177 // expanded to any type that already exists outside this particular instance.
6178 if (!(v.type.equals(Type.tstring) || (v.type.isTypeBasic() !is null)))
6181 // Static ctors and dtors, even in an eponymous enum template, are still run,
6182 // so if any of them are in here, we'd better not assume it is trivial lest
6183 // we break useful code
6184 foreach(member; *members)
6186 if(member.hasStaticCtorOrDtor())
6188 if(member.isStaticDtorDeclaration())
6190 if(member.isStaticCtorDeclaration())
6194 // but if it passes through this gauntlet... it should be fine. D code will
6195 // see only the eponymous member, outside stuff can never access it, even through
6196 // reflection; the outside world ought to be none the wiser. Even dmd should be
6197 // able to simply free the memory of everything except the final result.
6203 /***********************************************
6204 * Returns true if this is not instantiated in non-root module, and
6205 * is a part of non-speculative instantiatiation.
6207 * Note: minst does not stabilize until semantic analysis is completed,
6208 * so don't call this function during semantic analysis to return precise result.
6210 final bool needsCodegen()
6214 // If this is a speculative instantiation,
6215 // 1. do codegen if ancestors really needs codegen.
6216 // 2. become non-speculative if siblings are not speculative
6218 TemplateInstance tnext = this.tnext;
6219 TemplateInstance tinst = this.tinst;
6220 // At first, disconnect chain first to prevent infinite recursion.
6224 // Determine necessity of tinst before tnext.
6225 if (tinst && tinst.needsCodegen())
6227 minst = tinst.minst; // cache result
6228 if (global.params.allInst && minst)
6233 assert(minst.isRoot() || minst.rootImports());
6236 if (tnext && (tnext.needsCodegen() || tnext.minst))
6238 minst = tnext.minst; // cache result
6239 if (global.params.allInst && minst)
6244 return minst.isRoot() || minst.rootImports();
6247 // Elide codegen because this is really speculative.
6251 if (global.params.allInst)
6256 if (isDiscardable())
6261 /* Even when this is reached to the codegen pass,
6262 * a non-root nested template should not generate code,
6263 * due to avoid ODR violation.
6265 if (enclosing && enclosing.inNonRoot())
6269 auto r = tinst.needsCodegen();
6270 minst = tinst.minst; // cache result
6275 auto r = tnext.needsCodegen();
6276 minst = tnext.minst; // cache result
6282 if (global.params.useUnitTests)
6284 // Prefer instantiations from root modules, to maximize link-ability.
6288 TemplateInstance tnext = this.tnext;
6289 TemplateInstance tinst = this.tinst;
6293 if (tinst && tinst.needsCodegen())
6295 minst = tinst.minst; // cache result
6297 assert(minst.isRoot() || minst.rootImports());
6300 if (tnext && tnext.needsCodegen())
6302 minst = tnext.minst; // cache result
6304 assert(minst.isRoot() || minst.rootImports());
6308 // https://issues.dlang.org/show_bug.cgi?id=2500 case
6309 if (minst.rootImports())
6312 // Elide codegen because this is not included in root instances.
6317 // Prefer instantiations from non-root module, to minimize object code size.
6319 /* If a TemplateInstance is ever instantiated by non-root modules,
6320 * we do not have to generate code for it,
6321 * because it will be generated when the non-root module is compiled.
6323 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
6325 * The problem is if A imports B, and B imports A, and both A
6326 * and B instantiate the same template, does the compilation of A
6327 * or the compilation of B do the actual instantiation?
6329 * See https://issues.dlang.org/show_bug.cgi?id=2500.
6331 if (!minst.isRoot() && !minst.rootImports())
6334 TemplateInstance tnext = this.tnext;
6337 if (tnext && !tnext.needsCodegen() && tnext.minst)
6339 minst = tnext.minst; // cache result
6340 assert(!minst.isRoot());
6344 // Do codegen because this is not included in non-root instances.
6349 /**********************************************
6350 * Find template declaration corresponding to template instance.
6353 * false if finding fails.
6355 * This function is reentrant against error occurrence. If returns false,
6356 * any members of this object won't be modified, and repetition call will
6357 * reproduce same error.
6359 extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym)
6367 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
6372 * figure out which TemplateDeclaration foo refers to.
6374 Identifier id = name;
6376 Dsymbol s = sc.search(loc, id, &scopesym);
6379 s = sc.search_correct(id);
6381 error("template `%s` is not defined, did you mean %s?", id.toChars(), s.toChars());
6383 error("template `%s` is not defined", id.toChars());
6388 printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
6390 printf("s.parent = '%s'\n", s.parent.toChars());
6393 *pwithsym = scopesym.isWithScopeSymbol();
6395 /* We might have found an alias within a template when
6396 * we really want the template.
6398 TemplateInstance ti;
6399 if (s.parent && (ti = s.parent.isTemplateInstance()) !is null)
6401 if (ti.tempdecl && ti.tempdecl.ident == id)
6403 /* This is so that one can refer to the enclosing
6404 * template, even if it has the same name as a member
6405 * of the template, if it has a !(arguments)
6407 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6409 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6410 td = td.overroot; // then get the start
6415 // The template might originate from a selective import which implies that
6416 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
6417 // This is the last place where we see the deprecated alias because it is
6418 // stripped below, so check if the selective import was deprecated.
6419 // See https://issues.dlang.org/show_bug.cgi?id=20840.
6420 if (s.isAliasDeclaration())
6421 s.checkDeprecated(this.loc, sc);
6423 if (!updateTempDecl(sc, s))
6430 // Look for forward references
6431 auto tovers = tempdecl.isOverloadSet();
6432 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
6434 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6435 int r = overloadApply(dstart, (Dsymbol s)
6437 auto td = s.isTemplateDeclaration();
6441 if (td.semanticRun == PASS.init)
6445 // Try to fix forward reference. Ungag errors while doing so.
6446 Ungag ungag = td.ungagSpeculative();
6447 td.dsymbolSemantic(td._scope);
6449 if (td.semanticRun == PASS.init)
6451 error("`%s` forward references template declaration `%s`",
6452 toChars(), td.toChars());
6464 /**********************************************
6465 * Confirm s is a valid template, then store it.
6468 * s candidate symbol of template. It may be:
6469 * TemplateDeclaration
6470 * FuncDeclaration with findTemplateDeclRoot() != NULL
6471 * OverloadSet which contains candidates
6473 * true if updating succeeds.
6475 extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s)
6478 return tempdecl !is null;
6480 Identifier id = name;
6483 /* If an OverloadSet, look for a unique member that is a template declaration
6485 if (OverloadSet os = s.isOverloadSet())
6490 if (FuncDeclaration f = s2.isFuncDeclaration())
6491 s2 = f.findTemplateDeclRoot();
6493 s2 = s2.isTemplateDeclaration();
6506 error("template `%s` is not defined", id.toChars());
6511 if (OverDeclaration od = s.isOverDeclaration())
6513 tempdecl = od; // TODO: more strict check
6517 /* It should be a TemplateDeclaration, not some other symbol
6519 if (FuncDeclaration f = s.isFuncDeclaration())
6520 tempdecl = f.findTemplateDeclRoot();
6522 tempdecl = s.isTemplateDeclaration();
6528 // Error already issued, just return `false`
6529 if (!s.parent && global.errors)
6532 if (!s.parent && s.getType())
6534 Dsymbol s2 = s.getType().toDsymbol(sc);
6537 .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());
6540 // because s can be the alias created for a TemplateParameter
6541 const AliasDeclaration ad = s.isAliasDeclaration();
6544 if (ad && ad.isAliasedTemplateParameter())
6545 printf("`%s` is an alias created from a template parameter\n", s.toChars());
6547 if (!ad || !ad.isAliasedTemplateParameter())
6551 TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
6552 if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl)
6554 /* This is so that one can refer to the enclosing
6555 * template, even if it has the same name as a member
6556 * of the template, if it has a !(arguments)
6558 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
6560 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
6561 td = td.overroot; // then get the start
6567 error("`%s` is not a template declaration, it is a %s", id.toChars(), s.kind());
6572 /**********************************
6573 * Run semantic of tiargs as arguments of template.
6577 * tiargs array of template arguments
6578 * flags 1: replace const variables with their initializers
6579 * 2: don't devolve Parameter to Type
6581 * false if one or more arguments have errors.
6583 extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags)
6585 // Run semantic on each argument, place results in tiargs[]
6586 //printf("+TemplateInstance.semanticTiargs()\n");
6590 for (size_t j = 0; j < tiargs.dim; j++)
6592 RootObject o = (*tiargs)[j];
6593 Type ta = isType(o);
6594 Expression ea = isExpression(o);
6595 Dsymbol sa = isDsymbol(o);
6597 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
6600 //printf("type %s\n", ta.toChars());
6602 // It might really be an Expression or an Alias
6603 ta.resolve(loc, sc, ea, ta, sa, (flags & 1) != 0);
6610 assert(global.errors);
6615 if (ta.ty == Ttuple)
6618 TypeTuple tt = cast(TypeTuple)ta;
6619 size_t dim = tt.arguments.dim;
6623 tiargs.reserve(dim);
6624 foreach (i, arg; *tt.arguments)
6626 if (flags & 2 && (arg.storageClass & STC.parameter))
6627 tiargs.insert(j + i, arg);
6629 tiargs.insert(j + i, arg.type);
6635 if (ta.ty == Terror)
6640 (*tiargs)[j] = ta.merge2();
6645 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6646 if (flags & 1) // only used by __traits
6648 ea = ea.expressionSemantic(sc);
6650 // must not interpret the args, excepting template parameters
6651 if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
6653 ea = ea.optimize(WANTvalue);
6658 sc = sc.startCTFE();
6659 ea = ea.expressionSemantic(sc);
6662 if (ea.op == EXP.variable)
6664 /* If the parameter is a function that is not called
6665 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
6666 * then it is a dsymbol, not the return value of `func()`
6668 Declaration vd = (cast(VarExp)ea).var;
6669 if (auto fd = vd.isFuncDeclaration())
6674 /* Otherwise skip substituting a const var with
6675 * its initializer. The problem is the initializer won't
6676 * match with an 'alias' parameter. Instead, do the
6677 * const substitution in TemplateValueParameter.matchArg().
6680 else if (definitelyValueParameter(ea))
6682 if (ea.checkValue()) // check void expression
6683 ea = ErrorExp.get();
6684 uint olderrs = global.errors;
6685 ea = ea.ctfeInterpret();
6686 if (global.errors != olderrs)
6687 ea = ErrorExp.get();
6690 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6691 if (ea.op == EXP.tuple)
6694 TupleExp te = cast(TupleExp)ea;
6695 size_t dim = te.exps.dim;
6699 tiargs.reserve(dim);
6700 foreach (i, exp; *te.exps)
6701 tiargs.insert(j + i, exp);
6706 if (ea.op == EXP.error)
6713 if (ea.op == EXP.type)
6718 if (ea.op == EXP.scope_)
6720 sa = (cast(ScopeExp)ea).sds;
6723 if (ea.op == EXP.function_)
6725 FuncExp fe = cast(FuncExp)ea;
6726 /* A function literal, that is passed to template and
6727 * already semanticed as function pointer, never requires
6728 * outer frame. So convert it to global function is valid.
6730 if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer)
6732 // change to non-nested
6733 fe.fd.tok = TOK.function_;
6738 /* If template argument is a template lambda,
6739 * get template declaration itself. */
6744 if (ea.op == EXP.dotVariable && !(flags & 1))
6746 // translate expression to dsymbol.
6747 sa = (cast(DotVarExp)ea).var;
6750 if (ea.op == EXP.template_)
6752 sa = (cast(TemplateExp)ea).td;
6755 if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
6757 // translate expression to dsymbol.
6758 sa = (cast(DotTemplateExp)ea).td;
6761 if (ea.op == EXP.dot)
6763 if (auto se = (cast(DotExp)ea).e2.isScopeExp())
6773 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
6780 TupleDeclaration d = sa.toAlias().isTupleDeclaration();
6785 tiargs.insert(j, d.objects);
6789 if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration())
6791 FuncDeclaration f = fa.toAliasFunc();
6792 if (!fa.hasOverloads && f.isUnique())
6794 // Strip FuncAlias only when the aliased function
6795 // does not have any overloads.
6801 TemplateDeclaration td = sa.isTemplateDeclaration();
6802 if (td && td.semanticRun == PASS.init && td.literal)
6804 td.dsymbolSemantic(sc);
6806 FuncDeclaration fd = sa.isFuncDeclaration();
6808 fd.functionSemantic();
6810 else if (isParameter(o))
6817 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
6821 printf("-TemplateInstance.semanticTiargs()\n");
6822 for (size_t j = 0; j < tiargs.dim; j++)
6824 RootObject o = (*tiargs)[j];
6825 Type ta = isType(o);
6826 Expression ea = isExpression(o);
6827 Dsymbol sa = isDsymbol(o);
6828 Tuple va = isTuple(o);
6829 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
6835 /**********************************
6836 * Run semantic on the elements of tiargs.
6840 * false if one or more arguments have errors.
6842 * This function is reentrant against error occurrence. If returns false,
6843 * all elements of tiargs won't be modified.
6845 extern (D) final bool semanticTiargs(Scope* sc)
6847 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
6848 if (semantictiargsdone)
6850 if (semanticTiargs(loc, sc, tiargs, 0))
6852 // cache the result iff semantic analysis succeeded entirely
6853 semantictiargsdone = 1;
6859 /**********************************
6860 * Find the TemplateDeclaration that matches this TemplateInstance best.
6863 * sc = the scope this TemplateInstance resides in
6864 * fargs = function arguments in case of a template function, null otherwise
6867 * `true` if a match was found, `false` otherwise
6869 extern (D) final bool findBestMatch(Scope* sc, Expressions* fargs)
6873 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
6875 assert(tempdecl._scope);
6877 tdtypes.setDim(tempdecl.parameters.dim);
6878 if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2))
6880 error("incompatible arguments for template instantiation");
6883 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
6889 printf("TemplateInstance.findBestMatch()\n");
6892 uint errs = global.errors;
6893 TemplateDeclaration td_last = null;
6896 /* Since there can be multiple TemplateDeclaration's with the same
6897 * name, look for the best match.
6899 auto tovers = tempdecl.isOverloadSet();
6900 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
6902 TemplateDeclaration td_best;
6903 TemplateDeclaration td_ambig;
6904 MATCH m_best = MATCH.nomatch;
6906 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
6907 overloadApply(dstart, (Dsymbol s)
6909 auto td = s.isTemplateDeclaration();
6914 td.error(loc, "recursive template expansion");
6917 if (td == td_best) // skip duplicates
6920 //printf("td = %s\n", td.toPrettyChars());
6921 // If more arguments than parameters,
6922 // then this is no match.
6923 if (td.parameters.dim < tiargs.dim)
6925 if (!td.isVariadic())
6929 dedtypes.setDim(td.parameters.dim);
6931 assert(td.semanticRun != PASS.init);
6933 MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
6934 //printf("matchWithInstance = %d\n", m);
6935 if (m == MATCH.nomatch) // no match at all
6937 if (m < m_best) goto Ltd_best;
6938 if (m > m_best) goto Ltd;
6940 // Disambiguate by picking the most specialized TemplateDeclaration
6942 MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
6943 MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
6944 //printf("c1 = %d, c2 = %d\n", c1, c2);
6945 if (c1 > c2) goto Ltd;
6946 if (c1 < c2) goto Ltd_best;
6953 // td_best is the best match so far
6958 // td is the new best match
6962 tdtypes.setDim(dedtypes.dim);
6963 memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * (void*).sizeof);
6969 .error(loc, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`",
6970 td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(),
6971 td_best.loc.toChars(), td_best.toChars(),
6972 td_ambig.loc.toChars(), td_ambig.toChars());
6979 else if (td_last != td_best)
6981 ScopeDsymbol.multiplyDefined(loc, td_last, td_best);
6989 /* https://issues.dlang.org/show_bug.cgi?id=7469
6990 * Normalize tiargs by using corresponding deduced
6991 * template value parameters and tuples for the correct mangling.
6993 * By doing this before hasNestedArgs, CTFEable local variable will be
6994 * accepted as a value parameter. For example:
6997 * struct S(int n) {} // non-global template
6998 * const int num = 1; // CTFEable local variable
6999 * S!num s; // S!1 is instantiated, not S!num
7002 size_t dim = td_last.parameters.dim - (td_last.isVariadic() ? 1 : 0);
7003 for (size_t i = 0; i < dim; i++)
7005 if (tiargs.dim <= i)
7006 tiargs.push(tdtypes[i]);
7007 assert(i < tiargs.dim);
7009 auto tvp = (*td_last.parameters)[i].isTemplateValueParameter();
7013 // tdtypes[i] is already normalized to the required type in matchArg
7015 (*tiargs)[i] = tdtypes[i];
7017 if (td_last.isVariadic() && tiargs.dim == dim && tdtypes[dim])
7019 Tuple va = isTuple(tdtypes[dim]);
7021 tiargs.pushSlice(va.objects[]);
7024 else if (errors && inst)
7026 // instantiation was failed with error reporting
7027 assert(global.errors);
7032 auto tdecl = tempdecl.isTemplateDeclaration();
7034 if (errs != global.errors)
7035 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7036 else if (tdecl && !tdecl.overnext)
7038 // Only one template, so we can give better error message
7039 const(char)* msg = "does not match template declaration";
7041 const tmsg = tdecl.toCharsNoConstraints();
7042 const cmsg = tdecl.getConstraintEvalError(tip);
7045 error("%s `%s`\n%s", msg, tmsg, cmsg);
7051 error("%s `%s`", msg, tmsg);
7053 if (tdecl.parameters.dim == tiargs.dim)
7055 // https://issues.dlang.org/show_bug.cgi?id=7352
7056 // print additional information, e.g. `foo` is not a type
7057 foreach (i, param; *tdecl.parameters)
7059 MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
7060 auto arg = (*tiargs)[i];
7061 auto sym = arg.isDsymbol;
7062 auto exp = arg.isExpression;
7065 exp = exp.optimize(WANTvalue);
7067 if (match == MATCH.nomatch &&
7068 ((sym && sym.isFuncDeclaration) ||
7069 (exp && exp.isVarExp)))
7071 if (param.isTemplateTypeParameter)
7072 errorSupplemental(loc, "`%s` is not a type", arg.toChars);
7073 else if (auto tvp = param.isTemplateValueParameter)
7074 errorSupplemental(loc, "`%s` is not of a value of type `%s`",
7075 arg.toChars, tvp.valType.toChars);
7083 .error(loc, "%s `%s.%s` does not match any template declaration", tempdecl.kind(), tempdecl.parent.toPrettyChars(), tempdecl.ident.toChars());
7087 /* The best match is td_last
7093 printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
7095 return (errs == global.errors);
7098 /*****************************************************
7099 * Determine if template instance is really a template function,
7100 * and that template function needs to infer types from the function
7103 * Like findBestMatch, iterate possible template candidates,
7104 * but just looks only the necessity of type inference.
7106 extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
7108 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
7109 if (semanticRun != PASS.init)
7112 uint olderrs = global.errors;
7116 auto tovers = tempdecl.isOverloadSet();
7117 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
7119 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7120 int r = overloadApply(dstart, (Dsymbol s)
7122 auto td = s.isTemplateDeclaration();
7127 td.error(loc, "recursive template expansion");
7131 /* If any of the overloaded template declarations need inference,
7136 if (auto td2 = td.onemember.isTemplateDeclaration())
7138 if (!td2.onemember || !td2.onemember.isFuncDeclaration())
7140 if (tiargs.dim >= td.parameters.dim - (td.isVariadic() ? 1 : 0))
7144 auto fd = td.onemember.isFuncDeclaration();
7145 if (!fd || fd.type.ty != Tfunction)
7148 foreach (tp; *td.parameters)
7150 if (tp.isTemplateThisParameter())
7154 /* Determine if the instance arguments, tiargs, are all that is necessary
7155 * to instantiate the template.
7157 //printf("tp = %p, td.parameters.dim = %d, tiargs.dim = %d\n", tp, td.parameters.dim, tiargs.dim);
7158 auto tf = cast(TypeFunction)fd.type;
7159 if (tf.parameterList.length)
7161 auto tp = td.isVariadic();
7162 if (tp && td.parameters.dim > 1)
7165 if (!tp && tiargs.dim < td.parameters.dim)
7167 // Can remain tiargs be filled by default arguments?
7168 foreach (size_t i; tiargs.dim .. td.parameters.dim)
7170 if (!(*td.parameters)[i].hasDefaultArg())
7175 foreach (i, fparam; tf.parameterList)
7177 // 'auto ref' needs inference.
7178 if (fparam.storageClass & STC.auto_)
7185 /* Calculate the need for overload resolution.
7186 * When only one template can match with tiargs, inference is not necessary.
7188 dedtypes.setDim(td.parameters.dim);
7190 if (td.semanticRun == PASS.init)
7194 // Try to fix forward reference. Ungag errors while doing so.
7195 Ungag ungag = td.ungagSpeculative();
7196 td.dsymbolSemantic(td._scope);
7198 if (td.semanticRun == PASS.init)
7200 error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
7204 MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0);
7205 if (m == MATCH.nomatch)
7209 /* If there is more than one function template which matches, we may
7210 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
7212 return ++count > 1 ? 1 : 0;
7218 if (olderrs != global.errors)
7222 errorSupplemental(loc, "while looking for match for `%s`", toChars());
7223 semanticRun = PASS.semanticdone;
7228 //printf("false\n");
7232 /*****************************************
7233 * Determines if a TemplateInstance will need a nested
7234 * generation of the TemplateDeclaration.
7235 * Sets enclosing property if so, and returns != 0;
7237 extern (D) final bool hasNestedArgs(Objects* args, bool isstatic)
7240 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
7242 // arguments from parent instances are also accessible
7245 if (TemplateInstance ti = tempdecl.toParent().isTemplateInstance())
7246 enclosing = ti.enclosing;
7249 /* A nested instance happens when an argument references a local
7250 * symbol that is on the stack.
7254 Expression ea = isExpression(o);
7255 Dsymbol sa = isDsymbol(o);
7256 Tuple va = isTuple(o);
7259 if (ea.op == EXP.variable)
7261 sa = (cast(VarExp)ea).var;
7264 if (ea.op == EXP.this_)
7266 sa = (cast(ThisExp)ea).var;
7269 if (ea.op == EXP.function_)
7271 if ((cast(FuncExp)ea).td)
7272 sa = (cast(FuncExp)ea).td;
7274 sa = (cast(FuncExp)ea).fd;
7277 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
7278 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)
7280 ea.error("expression `%s` is not a valid template value argument", ea.toChars());
7288 TemplateDeclaration td = sa.isTemplateDeclaration();
7291 TemplateInstance ti = sa.toParent().isTemplateInstance();
7292 if (ti && ti.enclosing)
7295 TemplateInstance ti = sa.isTemplateInstance();
7296 Declaration d = sa.isDeclaration();
7297 if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin()))
7299 Dsymbol dparent = sa.toParent2();
7302 else if (!enclosing)
7303 enclosing = dparent;
7304 else if (enclosing != dparent)
7306 /* Select the more deeply nested of the two.
7307 * Error if one is not nested inside the other.
7309 for (Dsymbol p = enclosing; p; p = p.parent)
7312 goto L1; // enclosing is most nested
7314 for (Dsymbol p = dparent; p; p = p.parent)
7318 enclosing = dparent;
7319 goto L1; // dparent is most nested
7322 //https://issues.dlang.org/show_bug.cgi?id=17870
7323 if (dparent.isClassDeclaration() && enclosing.isClassDeclaration())
7325 auto pc = dparent.isClassDeclaration();
7326 auto ec = enclosing.isClassDeclaration();
7327 if (pc.isBaseOf(ec, null))
7329 else if (ec.isBaseOf(pc, null))
7331 enclosing = dparent;
7335 error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars());
7339 //printf("\tnested inside %s\n", enclosing.toChars());
7345 nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
7348 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
7352 /*****************************************
7353 * Append 'this' to the specific module members[]
7355 extern (D) final Dsymbols* appendToModuleMember()
7357 Module mi = minst; // instantiated . inserted module
7359 if (global.params.useUnitTests)
7361 // Turn all non-root instances to speculative
7362 if (mi && !mi.isRoot())
7366 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
7368 // enclosing ? enclosing.toPrettyChars() : null,
7369 // mi ? mi.toPrettyChars() : null);
7370 if (!mi || mi.isRoot())
7372 /* If the instantiated module is speculative or root, insert to the
7373 * member of a root module. Then:
7374 * - semantic3 pass will get called on the instance members.
7375 * - codegen pass will get a selection chance to do/skip it.
7377 static Dsymbol getStrictEnclosing(TemplateInstance ti)
7382 return ti.enclosing;
7383 ti = ti.tempdecl.isInstantiated();
7388 Dsymbol enc = getStrictEnclosing(this);
7389 // insert target is made stable by using the module
7390 // where tempdecl is declared.
7391 mi = (enc ? enc : tempdecl).getModule();
7393 mi = mi.importedFrom;
7394 assert(mi.isRoot());
7398 /* If the instantiated module is non-root, insert to the member of the
7399 * non-root module. Then:
7400 * - semantic3 pass won't be called on the instance.
7401 * - codegen pass won't reach to the instance.
7404 //printf("\t-. mi = %s\n", mi.toPrettyChars());
7406 if (memberOf is mi) // already a member
7408 debug // make sure it really is a member
7410 auto a = mi.members;
7411 for (size_t i = 0; 1; ++i)
7414 if (this == (*a)[i])
7421 Dsymbols* a = mi.members;
7424 if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
7425 Module.addDeferredSemantic2(this);
7426 if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
7427 Module.addDeferredSemantic3(this);
7431 /****************************************************
7432 * Declare parameters of template instance, initialize them with the
7433 * template instance arguments.
7435 extern (D) final void declareParameters(Scope* sc)
7437 TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
7440 //printf("TemplateInstance.declareParameters()\n");
7441 foreach (i, o; tdtypes) // initializer for tp
7443 TemplateParameter tp = (*tempdecl.parameters)[i];
7444 //printf("\ttdtypes[%d] = %p\n", i, o);
7445 tempdecl.declareParameter(sc, tp, o);
7449 /****************************************
7450 * This instance needs an identifier for name mangling purposes.
7451 * Create one by taking the template declaration name and adding
7452 * the type signature for it.
7454 extern (D) final Identifier genIdent(Objects* args)
7456 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
7457 assert(args is tiargs);
7459 mangleToBuffer(this, &buf);
7460 //printf("\tgenIdent = %s\n", buf.peekChars());
7461 return Identifier.idPool(buf[]);
7464 extern (D) final void expandMembers(Scope* sc2)
7466 members.foreachDsymbol( (s) { s.setScope (sc2); } );
7468 members.foreachDsymbol( (s) { s.importAll(sc2); } );
7470 void symbolDg(Dsymbol s)
7472 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
7473 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
7475 // s.parent = sc.parent;
7476 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7477 s.dsymbolSemantic(sc2);
7478 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7479 Module.runDeferredSemantic();
7482 members.foreachDsymbol(&symbolDg);
7485 extern (D) final void tryExpandMembers(Scope* sc2)
7488 // extracted to a function to allow windows SEH to work without destructors in the same function
7489 //printf("%d\n", nest);
7490 if (++nest > global.recursionLimit)
7492 global.gag = 0; // ensure error message gets printed
7493 error("recursive expansion exceeded allowed nesting limit");
7502 extern (D) final void trySemantic3(Scope* sc2)
7504 // extracted to a function to allow windows SEH to work without destructors in the same function
7506 //printf("%d\n", nest);
7507 if (++nest > global.recursionLimit)
7509 global.gag = 0; // ensure error message gets printed
7510 error("recursive expansion exceeded allowed nesting limit");
7514 semantic3(this, sc2);
7519 override final inout(TemplateInstance) isTemplateInstance() inout
7524 override void accept(Visitor v)
7530 /**************************************
7531 * IsExpression can evaluate the specified type speculatively, and even if
7532 * it instantiates any symbols, they are normally unnecessary for the
7534 * However, if those symbols leak to the actual code, compiler should remark
7535 * them as non-speculative to generate their code and link to the final executable.
7537 void unSpeculative(Scope* sc, RootObject o)
7542 if (Tuple tup = isTuple(o))
7544 foreach (obj; tup.objects)
7546 unSpeculative(sc, obj);
7551 Dsymbol s = getDsymbol(o);
7555 if (Declaration d = s.isDeclaration())
7557 if (VarDeclaration vd = d.isVarDeclaration())
7559 else if (AliasDeclaration ad = d.isAliasDeclaration())
7573 if (TemplateInstance ti = s.isTemplateInstance())
7575 // If the instance is already non-speculative,
7576 // or it is leaked to the speculative scope.
7577 if (ti.minst !is null || sc.minst is null)
7580 // Remark as non-speculative instance.
7581 ti.minst = sc.minst;
7583 ti.tinst = sc.tinst;
7585 unSpeculative(sc, ti.tempdecl);
7588 if (TemplateInstance ti = s.isInstantiated())
7589 unSpeculative(sc, ti);
7592 /**********************************
7593 * Return true if e could be valid only as a template value parameter.
7594 * Return false if it might be an alias or tuple.
7595 * (Note that even in this case, it could still turn out to be a value).
7597 bool definitelyValueParameter(Expression e)
7599 // None of these can be value parameters
7600 if (e.op == EXP.tuple || e.op == EXP.scope_ ||
7601 e.op == EXP.type || e.op == EXP.dotType ||
7602 e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration ||
7603 e.op == EXP.function_ || e.op == EXP.error ||
7604 e.op == EXP.this_ || e.op == EXP.super_ ||
7608 if (e.op != EXP.dotVariable)
7611 /* Template instantiations involving a DotVar expression are difficult.
7612 * In most cases, they should be treated as a value parameter, and interpreted.
7613 * But they might also just be a fully qualified name, which should be treated
7617 // x.y.f cannot be a value
7618 FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration();
7622 while (e.op == EXP.dotVariable)
7624 e = (cast(DotVarExp)e).e1;
7626 // this.x.y and super.x.y couldn't possibly be valid values.
7627 if (e.op == EXP.this_ || e.op == EXP.super_)
7630 // e.type.x could be an alias
7631 if (e.op == EXP.dotType)
7634 // var.x.y is the only other possible form of alias
7635 if (e.op != EXP.variable)
7638 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
7639 // func.x.y is not an alias
7643 // https://issues.dlang.org/show_bug.cgi?id=16685
7644 // var.x.y where var is a constant available at compile time
7645 if (v.storage_class & STC.manifest)
7648 // TODO: Should we force CTFE if it is a global constant?
7652 /***********************************************************
7653 * https://dlang.org/spec/template-mixin.html
7655 * mixin MixinTemplateName [TemplateArguments] [Identifier];
7657 extern (C++) final class TemplateMixin : TemplateInstance
7659 TypeQualified tqual;
7661 extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
7664 tqual.idents.dim ? cast(Identifier)tqual.idents[tqual.idents.dim - 1] : (cast(TypeIdentifier)tqual).ident,
7665 tiargs ? tiargs : new Objects());
7666 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
7671 override TemplateInstance syntaxCopy(Dsymbol s)
7673 auto tm = new TemplateMixin(loc, ident, tqual.syntaxCopy(), tiargs);
7674 return TemplateInstance.syntaxCopy(tm);
7677 override const(char)* kind() const
7682 override bool oneMember(Dsymbol* ps, Identifier ident)
7684 return Dsymbol.oneMember(ps, ident);
7687 override bool hasPointers()
7689 //printf("TemplateMixin.hasPointers() %s\n", toChars());
7690 return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
7693 override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
7695 //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
7696 if (_scope) // if fwd reference
7697 dsymbolSemantic(this, null); // try to resolve it
7699 members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
7702 override const(char)* toChars() const
7705 toCBufferInstance(this, &buf);
7706 return buf.extractChars();
7709 extern (D) bool findTempDecl(Scope* sc)
7711 // Follow qualifications to find the TemplateDeclaration
7717 tqual.resolve(loc, sc, e, t, s);
7720 error("is not defined");
7724 tempdecl = s.isTemplateDeclaration();
7725 OverloadSet os = s.isOverloadSet();
7727 /* If an OverloadSet, look for a unique member that is a template declaration
7732 foreach (i, sym; os.a)
7734 Dsymbol s2 = sym.isTemplateDeclaration();
7748 error("`%s` isn't a template", s.toChars());
7754 // Look for forward references
7755 auto tovers = tempdecl.isOverloadSet();
7756 foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
7758 Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
7759 int r = overloadApply(dstart, (Dsymbol s)
7761 auto td = s.isTemplateDeclaration();
7765 if (td.semanticRun == PASS.init)
7768 td.dsymbolSemantic(td._scope);
7771 semanticRun = PASS.init;
7783 override inout(TemplateMixin) isTemplateMixin() inout
7788 override void accept(Visitor v)
7794 /************************************
7795 * This struct is needed for TemplateInstance to be the key in an associative array.
7796 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
7797 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
7799 struct TemplateInstanceBox
7801 TemplateInstance ti;
7803 this(TemplateInstance ti)
7807 assert(this.ti.hash);
7810 size_t toHash() const @trusted pure nothrow
7816 bool opEquals(ref const TemplateInstanceBox s) @trusted const
7819 if (ti.inst && s.ti.inst)
7820 /* This clause is only used when an instance with errors
7821 * is replaced with a correct instance.
7825 /* Used when a proposed instance is used to see if there's
7826 * an existing instance.
7828 res = (cast()s.ti).equalsx(cast()ti);
7830 debug (FindExistingInstance) ++(res ? nHits : nCollisions);
7834 debug (FindExistingInstance)
7836 __gshared uint nHits, nCollisions;
7838 shared static ~this()
7840 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
7841 nHits, nCollisions);
7846 /*******************************************
7847 * Match to a particular TemplateParameter.
7849 * instLoc location that the template is instantiated.
7850 * tiargs[] actual arguments to template instance
7852 * parameters[] template parameters
7853 * dedtypes[] deduced arguments to template instance
7854 * *psparam set to symbol declared and initialized to dedtypes[i]
7856 MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
7858 MATCH matchArgNoMatch()
7862 return MATCH.nomatch;
7865 MATCH matchArgParameter()
7870 oarg = (*tiargs)[i];
7873 // Get default argument instead
7874 oarg = tp.defaultArg(instLoc, sc);
7877 assert(i < dedtypes.dim);
7878 // It might have already been deduced
7879 oarg = (*dedtypes)[i];
7881 return matchArgNoMatch();
7884 return tp.matchArg(sc, oarg, i, parameters, dedtypes, psparam);
7887 MATCH matchArgTuple(TemplateTupleParameter ttp)
7889 /* The rest of the actual arguments (tiargs[]) form the match
7890 * for the variadic parameter.
7892 assert(i + 1 == dedtypes.dim); // must be the last one
7895 if (Tuple u = isTuple((*dedtypes)[i]))
7897 // It has already been deduced
7900 else if (i + 1 == tiargs.dim && isTuple((*tiargs)[i]))
7901 ovar = isTuple((*tiargs)[i]);
7905 //printf("ovar = %p\n", ovar);
7908 //printf("i = %d, tiargs.dim = %d\n", i, tiargs.dim);
7909 ovar.objects.setDim(tiargs.dim - i);
7910 foreach (j, ref obj; ovar.objects)
7911 obj = (*tiargs)[i + j];
7914 return ttp.matchArg(sc, ovar, i, parameters, dedtypes, psparam);
7917 if (auto ttp = tp.isTemplateTupleParameter())
7918 return matchArgTuple(ttp);
7920 return matchArgParameter();
7923 MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
7925 MATCH matchArgNoMatch()
7927 //printf("\tm = %d\n", MATCH.nomatch);
7930 return MATCH.nomatch;
7933 MATCH matchArgType(TemplateTypeParameter ttp)
7935 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
7936 MATCH m = MATCH.exact;
7937 Type ta = isType(oarg);
7940 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
7941 return matchArgNoMatch();
7943 //printf("ta is %s\n", ta.toChars());
7947 if (!ta || ta == TemplateTypeParameter.tdummy)
7948 return matchArgNoMatch();
7950 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
7951 MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
7952 if (m2 == MATCH.nomatch)
7954 //printf("\tfailed deduceType\n");
7955 return matchArgNoMatch();
7962 Type t = cast(Type)(*dedtypes)[i];
7964 if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
7965 return matchArgNoMatch();
7967 /* This is a self-dependent parameter. For example:
7968 * template X(T : T*) {}
7969 * template X(T : S!T, alias S) {}
7971 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
7979 // Must match already deduced type
7980 Type t = cast(Type)(*dedtypes)[i];
7984 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
7985 return matchArgNoMatch();
7990 // So that matches with specializations are better
7994 (*dedtypes)[i] = ta;
7997 *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
7998 //printf("\tm = %d\n", m);
7999 return ttp.dependent ? MATCH.exact : m;
8002 MATCH matchArgValue(TemplateValueParameter tvp)
8004 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
8005 MATCH m = MATCH.exact;
8007 Expression ei = isExpression(oarg);
8012 Dsymbol si = isDsymbol(oarg);
8013 FuncDeclaration f = si ? si.isFuncDeclaration() : null;
8014 if (!f || !f.fbody || f.needThis())
8015 return matchArgNoMatch();
8017 ei = new VarExp(tvp.loc, f);
8018 ei = ei.expressionSemantic(sc);
8020 /* If a function is really property-like, and then
8021 * it's CTFEable, ei will be a literal expression.
8023 uint olderrors = global.startGagging();
8024 ei = resolveProperties(sc, ei);
8025 ei = ei.ctfeInterpret();
8026 if (global.endGagging(olderrors) || ei.op == EXP.error)
8027 return matchArgNoMatch();
8029 /* https://issues.dlang.org/show_bug.cgi?id=14520
8030 * A property-like function can match to both
8031 * TemplateAlias and ValueParameter. But for template overloads,
8032 * it should always prefer alias parameter to be consistent
8033 * template match result.
8035 * template X(alias f) { enum X = 1; }
8036 * template X(int val) { enum X = 2; }
8037 * int f1() { return 0; } // CTFEable
8038 * int f2(); // body-less function is not CTFEable
8039 * enum x1 = X!f1; // should be 1
8040 * enum x2 = X!f2; // should be 1
8042 * e.g. The x1 value must be same even if the f1 definition will be moved
8043 * into di while stripping body code.
8048 if (ei && ei.op == EXP.variable)
8050 // Resolve const variables that we had skipped earlier
8051 ei = ei.ctfeInterpret();
8054 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
8055 vt = tvp.valType.typeSemantic(tvp.loc, sc);
8056 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
8057 //printf("vt = %s\n", vt.toChars());
8061 MATCH m2 = ei.implicitConvTo(vt);
8062 //printf("m: %d\n", m);
8065 if (m == MATCH.nomatch)
8066 return matchArgNoMatch();
8067 ei = ei.implicitCastTo(sc, vt);
8068 ei = ei.ctfeInterpret();
8073 if (ei is null || (cast(void*)ei.type in TemplateValueParameter.edummies &&
8074 TemplateValueParameter.edummies[cast(void*)ei.type] == ei))
8075 return matchArgNoMatch();
8077 Expression e = tvp.specValue;
8079 sc = sc.startCTFE();
8080 e = e.expressionSemantic(sc);
8081 e = resolveProperties(sc, e);
8083 e = e.implicitCastTo(sc, vt);
8084 e = e.ctfeInterpret();
8086 ei = ei.syntaxCopy();
8087 sc = sc.startCTFE();
8088 ei = ei.expressionSemantic(sc);
8090 ei = ei.implicitCastTo(sc, vt);
8091 ei = ei.ctfeInterpret();
8092 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
8093 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
8095 return matchArgNoMatch();
8101 // Must match already deduced value
8102 Expression e = cast(Expression)(*dedtypes)[i];
8103 if (!ei || !ei.equals(e))
8104 return matchArgNoMatch();
8107 (*dedtypes)[i] = ei;
8111 Initializer _init = new ExpInitializer(tvp.loc, ei);
8112 Declaration sparam = new VarDeclaration(tvp.loc, vt, tvp.ident, _init);
8113 sparam.storage_class = STC.manifest;
8116 return tvp.dependent ? MATCH.exact : m;
8119 MATCH matchArgAlias(TemplateAliasParameter tap)
8121 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
8122 MATCH m = MATCH.exact;
8123 Type ta = isType(oarg);
8124 RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
8125 Expression ea = isExpression(oarg);
8126 if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
8127 sa = (cast(ThisExp)ea).var;
8128 else if (ea && ea.op == EXP.scope_)
8129 sa = (cast(ScopeExp)ea).sds;
8132 if ((cast(Dsymbol)sa).isAggregateDeclaration())
8135 /* specType means the alias must be a declaration with a type
8136 * that matches specType.
8140 Declaration d = (cast(Dsymbol)sa).isDeclaration();
8142 return matchArgNoMatch();
8143 if (!d.type.equals(tap.specType))
8144 return matchArgNoMatch();
8154 if (!ea.type.equals(tap.specType))
8155 return matchArgNoMatch();
8158 else if (ta && ta.ty == Tinstance && !tap.specAlias)
8160 /* Specialized parameter should be preferred
8161 * match to the template type parameter.
8162 * template X(alias a) {} // a == this
8163 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
8166 else if (sa && sa == TemplateTypeParameter.tdummy)
8168 /* https://issues.dlang.org/show_bug.cgi?id=2025
8169 * Aggregate Types should preferentially
8170 * match to the template type parameter.
8171 * template X(alias a) {} // a == this
8172 * template X(T) {} // T => sa
8175 else if (ta && ta.ty != Tident)
8177 /* Match any type that's not a TypeIdentifier to alias parameters,
8178 * but prefer type parameter.
8179 * template X(alias a) { } // a == ta
8181 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
8186 return matchArgNoMatch();
8191 if (sa == TemplateAliasParameter.sdummy)
8192 return matchArgNoMatch();
8193 // check specialization if template arg is a symbol
8194 Dsymbol sx = isDsymbol(sa);
8195 if (sa != tap.specAlias && sx)
8197 Type talias = isType(tap.specAlias);
8199 return matchArgNoMatch();
8201 TemplateInstance ti = sx.isTemplateInstance();
8202 if (!ti && sx.parent)
8204 ti = sx.parent.isTemplateInstance();
8205 if (ti && ti.name != sx.ident)
8206 return matchArgNoMatch();
8209 return matchArgNoMatch();
8211 Type t = new TypeInstance(Loc.initial, ti);
8212 MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
8213 if (m2 == MATCH.nomatch)
8214 return matchArgNoMatch();
8216 // check specialization if template arg is a type
8219 if (Type tspec = isType(tap.specAlias))
8221 MATCH m2 = ta.implicitConvTo(tspec);
8222 if (m2 == MATCH.nomatch)
8223 return matchArgNoMatch();
8227 error(tap.loc, "template parameter specialization for a type must be a type and not `%s`",
8228 tap.specAlias.toChars());
8229 return matchArgNoMatch();
8233 else if ((*dedtypes)[i])
8235 // Must match already deduced symbol
8236 RootObject si = (*dedtypes)[i];
8237 if (!sa || si != sa)
8238 return matchArgNoMatch();
8240 (*dedtypes)[i] = sa;
8244 if (Dsymbol s = isDsymbol(sa))
8246 *psparam = new AliasDeclaration(tap.loc, tap.ident, s);
8248 else if (Type t = isType(sa))
8250 *psparam = new AliasDeclaration(tap.loc, tap.ident, t);
8256 // Declare manifest constant
8257 Initializer _init = new ExpInitializer(tap.loc, ea);
8258 auto v = new VarDeclaration(tap.loc, null, tap.ident, _init);
8259 v.storage_class = STC.manifest;
8260 v.dsymbolSemantic(sc);
8264 return tap.dependent ? MATCH.exact : m;
8267 MATCH matchArgTuple(TemplateTupleParameter ttp)
8269 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
8270 Tuple ovar = isTuple(oarg);
8272 return MATCH.nomatch;
8275 Tuple tup = isTuple((*dedtypes)[i]);
8277 return MATCH.nomatch;
8278 if (!match(tup, ovar))
8279 return MATCH.nomatch;
8281 (*dedtypes)[i] = ovar;
8284 *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
8285 return ttp.dependent ? MATCH.exact : MATCH.convert;
8288 if (auto ttp = tp.isTemplateTypeParameter())
8289 return matchArgType(ttp);
8290 else if (auto tvp = tp.isTemplateValueParameter())
8291 return matchArgValue(tvp);
8292 else if (auto tap = tp.isTemplateAliasParameter())
8293 return matchArgAlias(tap);
8294 else if (auto ttp = tp.isTemplateTupleParameter())
8295 return matchArgTuple(ttp);
8301 /***********************************************
8302 * Collect and print statistics on template instantiations.
8304 struct TemplateStats
8306 __gshared TemplateStats[const void*] stats;
8308 uint numInstantiations; // number of instantiations of the template
8309 uint uniqueInstantiations; // number of unique instantiations of the template
8311 TemplateInstances* allInstances;
8313 /*******************************
8316 static void incInstance(const TemplateDeclaration td,
8317 const TemplateInstance ti)
8319 void log(ref TemplateStats ts)
8321 if (ts.allInstances is null)
8322 ts.allInstances = new TemplateInstances();
8323 if (global.params.vtemplatesListInstances)
8324 ts.allInstances.push(cast() ti);
8327 // message(ti.loc, "incInstance %p %p", td, ti);
8328 if (!global.params.vtemplates)
8333 if (auto ts = cast(const void*) td in stats)
8336 ++ts.numInstantiations;
8340 stats[cast(const void*) td] = TemplateStats(1, 0);
8341 log(stats[cast(const void*) td]);
8345 /*******************************
8346 * Add this unique instance
8348 static void incUnique(const TemplateDeclaration td,
8349 const TemplateInstance ti)
8351 // message(ti.loc, "incUnique %p %p", td, ti);
8352 if (!global.params.vtemplates)
8357 if (auto ts = cast(const void*) td in stats)
8358 ++ts.uniqueInstantiations;
8360 stats[cast(const void*) td] = TemplateStats(0, 1);
8364 void printTemplateStats()
8366 static struct TemplateDeclarationStats
8368 TemplateDeclaration td;
8370 static int compare(scope const TemplateDeclarationStats* a,
8371 scope const TemplateDeclarationStats* b) @safe nothrow @nogc pure
8373 auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations;
8377 return b.ts.numInstantiations - a.ts.numInstantiations;
8381 if (!global.params.vtemplates)
8384 Array!(TemplateDeclarationStats) sortedStats;
8385 sortedStats.reserve(TemplateStats.stats.length);
8386 foreach (td_, ref ts; TemplateStats.stats)
8388 sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
8391 sortedStats.sort!(TemplateDeclarationStats.compare);
8393 foreach (const ref ss; sortedStats[])
8395 if (global.params.vtemplatesListInstances &&
8399 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
8400 ss.ts.numInstantiations,
8401 ss.ts.uniqueInstantiations,
8402 ss.td.toCharsNoConstraints());
8403 foreach (const ti; (*ss.ts.allInstances)[])
8405 if (ti.tinst) // if has enclosing instance
8406 message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
8408 message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
8414 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
8415 ss.ts.numInstantiations,
8416 ss.ts.uniqueInstantiations,
8417 ss.td.toCharsNoConstraints());
8423 private struct MATCHpair
8425 MATCH mta; /// match template parameters by initial template arguments
8426 MATCH mfa; /// match template parameters by inferred template arguments
8428 debug this(MATCH mta, MATCH mfa)
8430 assert(MATCH.min <= mta && mta <= MATCH.max);
8431 assert(MATCH.min <= mfa && mfa <= MATCH.max);
8437 private void write(ref OutBuffer buf, RootObject obj)
8441 buf.writestring(obj.toChars());