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-2024 by The D Language Foundation, All Rights Reserved
32 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
33 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
34 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d)
35 * Documentation: https://dlang.org/phobos/dmd_dtemplate.html
36 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d
41 import core
.stdc
.stdio
;
42 import core
.stdc
.string
;
45 import dmd
.arraytypes
;
51 import dmd
.declaration
;
52 import dmd
.dinterpret
;
57 import dmd
.dsymbolsem
;
60 import dmd
.expression
;
61 import dmd
.expressionsem
;
67 import dmd
.identifier
;
75 import dmd
.root
.array
;
76 import dmd
.common
.outbuffer
;
77 import dmd
.rootobject
;
80 import dmd
.templatesem
;
85 import dmd
.templateparamsem
;
87 //debug = FindExistingInstance; // print debug stats of findExistingInstance
88 private enum LOG
= false;
90 enum IDX_NOTFOUND
= 0x12345678;
92 pure nothrow @nogc @safe
95 /********************************************
96 * These functions substitute for dynamic_cast. dynamic_cast does not work
97 * on earlier versions of gcc.
99 inout(Expression
) isExpression(inout RootObject o
)
101 //return dynamic_cast<Expression *>(o);
102 if (!o || o
.dyncast() != DYNCAST
.expression
)
104 return cast(inout(Expression
))o
;
107 inout(Dsymbol
) isDsymbol(inout RootObject o
)
109 //return dynamic_cast<Dsymbol *>(o);
110 if (!o || o
.dyncast() != DYNCAST
.dsymbol
)
112 return cast(inout(Dsymbol
))o
;
115 inout(Type
) isType(inout RootObject o
)
117 //return dynamic_cast<Type *>(o);
118 if (!o || o
.dyncast() != DYNCAST
.type
)
120 return cast(inout(Type
))o
;
123 inout(Tuple
) isTuple(inout RootObject o
)
125 //return dynamic_cast<Tuple *>(o);
126 if (!o || o
.dyncast() != DYNCAST
.tuple
)
128 return cast(inout(Tuple
))o
;
131 inout(Parameter
) isParameter(inout RootObject o
)
133 //return dynamic_cast<Parameter *>(o);
134 if (!o || o
.dyncast() != DYNCAST
.parameter
)
136 return cast(inout(Parameter
))o
;
139 inout(TemplateParameter
) isTemplateParameter(inout RootObject o
)
141 if (!o || o
.dyncast() != DYNCAST
.templateparameter
)
143 return cast(inout(TemplateParameter
))o
;
146 /**************************************
147 * Is this Object an error?
149 bool isError(const RootObject o
)
151 if (const t
= isType(o
))
152 return (t
.ty
== Terror
);
153 if (const e
= isExpression(o
))
154 return (e
.op
== EXP
.error ||
!e
.type || e
.type
.ty
== Terror
);
155 if (const v
= isTuple(o
))
156 return arrayObjectIsError(v
.objects
);
157 const s
= isDsymbol(o
);
161 return s
.parent ?
isError(s
.parent
) : false;
164 /**************************************
165 * Are any of the Objects an error?
167 bool arrayObjectIsError(const ref Objects args
)
169 foreach (const o
; args
)
177 /***********************
178 * Try to get arg as a type.
180 inout(Type
) getType(inout RootObject o
)
185 if (inout e
= isExpression(o
))
193 /***********************************
194 * If oarg represents a Dsymbol, return that Dsymbol
196 * oarg = argument to check
198 * Dsymbol if a symbol, null if not
200 Dsymbol
getDsymbol(RootObject oarg
)
202 //printf("getDsymbol()\n");
203 //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
204 if (auto ea
= isExpression(oarg
))
206 // Try to convert Expression to symbol
207 if (auto ve
= ea
.isVarExp())
209 else if (auto fe
= ea
.isFuncExp())
210 return fe
.td ? fe
.td
: fe
.fd
;
211 else if (auto te
= ea
.isTemplateExp())
213 else if (auto te
= ea
.isScopeExp())
220 // Try to convert Type to symbol
221 if (auto ta
= isType(oarg
))
222 return ta
.toDsymbol(null);
224 return isDsymbol(oarg
); // if already a symbol
229 private Expression
getValue(ref Dsymbol s
)
233 if (VarDeclaration v
= s
.isVarDeclaration())
235 if (v
.storage_class
& STC
.manifest
)
236 return v
.getConstInitializer();
242 /***********************
243 * Try to get value from manifest constant
245 private Expression
getValue(Expression e
)
249 if (auto ve
= e
.isVarExp())
251 if (auto v
= ve
.var
.isVarDeclaration())
253 if (v
.storage_class
& STC
.manifest
)
255 e
= v
.getConstInitializer();
262 private Expression
getExpression(RootObject o
)
264 auto s
= isDsymbol(o
);
265 return s ?
.getValue(s
) : .getValue(isExpression(o
));
268 /******************************
269 * See if two objects match
273 * Returns: true if they match
275 private bool match(RootObject o1
, RootObject o2
)
281 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
282 o1
, o1
.toChars(), o1
.dyncast(), o2
, o2
.toChars(), o2
.dyncast());
285 /* A proper implementation of the various equals() overrides
286 * should make it possible to just do o1.equals(o2), but
287 * we'll do that another day.
289 /* Manifest constants should be compared by their values,
290 * at least in template arguments.
293 if (auto t1
= isType(o1
))
295 auto t2
= isType(o2
);
301 printf("\tt1 = %s\n", t1
.toChars());
302 printf("\tt2 = %s\n", t2
.toChars());
309 if (auto e1
= getExpression(o1
))
311 auto e2
= getExpression(o2
);
317 printf("\te1 = %s '%s' %s\n", e1
.type ? e1
.type
.toChars() : "null", EXPtoString(e1
.op
).ptr
, e1
.toChars());
318 printf("\te2 = %s '%s' %s\n", e2
.type ? e2
.type
.toChars() : "null", EXPtoString(e2
.op
).ptr
, e2
.toChars());
321 // two expressions can be equal although they do not have the same
322 // type; that happens when they have the same value. So check type
323 // as well as expression equality to ensure templates are properly
325 if (!(e1
.type
&& e2
.type
&& e1
.type
.equals(e2
.type
)) ||
!e1
.equals(e2
))
330 if (auto s1
= isDsymbol(o1
))
332 auto s2
= isDsymbol(o2
);
338 printf("\ts1 = %s \n", s1
.kind(), s1
.toChars());
339 printf("\ts2 = %s \n", s2
.kind(), s2
.toChars());
343 if (s1
.parent
!= s2
.parent
&& !s1
.isFuncDeclaration() && !s2
.isFuncDeclaration())
348 if (auto u1
= isTuple(o1
))
350 auto u2
= isTuple(o2
);
356 printf("\tu1 = %s\n", u1
.toChars());
357 printf("\tu2 = %s\n", u2
.toChars());
359 if (!arrayObjectMatch(u1
.objects
, u2
.objects
))
366 printf("\t. match\n");
371 printf("\t. nomatch\n");
375 /************************************
376 * Match an array of them.
378 bool arrayObjectMatch(ref Objects oa1
, ref Objects oa2
)
382 if (oa1
.length
!= oa2
.length
)
384 immutable oa1dim
= oa1
.length
;
385 auto oa1d
= oa1
[].ptr
;
386 auto oa2d
= oa2
[].ptr
;
387 foreach (j
; 0 .. oa1dim
)
389 RootObject o1
= oa1d
[j
];
390 RootObject o2
= oa2d
[j
];
399 /************************************
400 * Return hash of Objects.
402 private size_t
arrayObjectHash(ref Objects oa1
)
404 import dmd
.root
.hash
: mixHash
;
409 /* Must follow the logic of match()
411 if (auto t1
= isType(o1
))
412 hash
= mixHash(hash
, cast(size_t
)t1
.deco
);
413 else if (auto e1
= getExpression(o1
))
414 hash
= mixHash(hash
, expressionHash(e1
));
415 else if (auto s1
= isDsymbol(o1
))
417 auto fa1
= s1
.isFuncAliasDeclaration();
419 s1
= fa1
.toAliasFunc();
420 hash
= mixHash(hash
, mixHash(cast(size_t
)cast(void*)s1
.getIdent(), cast(size_t
)cast(void*)s1
.parent
));
422 else if (auto u1
= isTuple(o1
))
423 hash
= mixHash(hash
, arrayObjectHash(u1
.objects
));
429 /************************************
430 * Computes hash of expression.
431 * Handles all Expression classes and MUST match their equals method,
432 * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2).
434 private size_t
expressionHash(Expression e
)
436 import dmd
.root
.ctfloat
: CTFloat
;
437 import dmd
.root
.hash
: calcHash
, mixHash
;
442 return cast(size_t
) e
.isIntegerExp().getInteger();
445 return CTFloat
.hash(e
.isRealExp().value
);
448 auto ce
= e
.isComplexExp();
449 return mixHash(CTFloat
.hash(ce
.toReal
), CTFloat
.hash(ce
.toImaginary
));
452 return cast(size_t
)cast(void*) e
.isIdentifierExp().ident
;
455 return cast(size_t
)cast(void*) e
.isNullExp().type
;
458 return calcHash(e
.isStringExp
.peekData());
462 auto te
= e
.isTupleExp();
464 hash
+= te
.e0 ?
expressionHash(te
.e0
) : 0;
465 foreach (elem
; *te
.exps
)
466 hash
= mixHash(hash
, expressionHash(elem
));
470 case EXP
.arrayLiteral
:
472 auto ae
= e
.isArrayLiteralExp();
474 foreach (i
; 0 .. ae
.elements
.length
)
475 hash
= mixHash(hash
, expressionHash(ae
[i
]));
479 case EXP
.assocArrayLiteral
:
481 auto ae
= e
.isAssocArrayLiteralExp();
483 foreach (i
; 0 .. ae
.keys
.length
)
484 // reduction needs associative op as keys are unsorted (use XOR)
485 hash ^
= mixHash(expressionHash((*ae
.keys
)[i
]), expressionHash((*ae
.values
)[i
]));
489 case EXP
.structLiteral
:
491 auto se
= e
.isStructLiteralExp();
493 foreach (elem
; *se
.elements
)
494 hash
= mixHash(hash
, elem ?
expressionHash(elem
) : 0);
499 return cast(size_t
)cast(void*) e
.isVarExp().var
;
502 return cast(size_t
)cast(void*) e
.isFuncExp().fd
;
505 // no custom equals for this expression
506 assert((&e
.equals
).funcptr
is &RootObject
.equals
);
507 // equals based on identity
508 return cast(size_t
)cast(void*) e
;
512 RootObject
objectSyntaxCopy(RootObject o
)
516 if (Type t
= isType(o
))
517 return t
.syntaxCopy();
518 if (Expression e
= isExpression(o
))
519 return e
.syntaxCopy();
523 extern (C
++) final class Tuple
: RootObject
531 numObjects = The initial number of objects.
533 extern (D
) this(size_t numObjects
)
535 objects
.setDim(numObjects
);
538 // kludge for template.isType()
539 override DYNCAST
dyncast() const
541 return DYNCAST
.tuple
;
544 override const(char)* toChars() const
546 return objects
.toChars();
550 struct TemplatePrevious
552 TemplatePrevious
* prev
;
557 /***********************************************************
558 * [mixin] template Identifier (parameters) [Constraint]
559 * https://dlang.org/spec/template.html
560 * https://dlang.org/spec/template-mixin.html
562 extern (C
++) final class TemplateDeclaration
: ScopeDsymbol
564 import dmd
.root
.array
: Array
;
566 TemplateParameters
* parameters
; // array of TemplateParameter's
567 TemplateParameters
* origParameters
; // originals for Ddoc
569 Expression constraint
;
571 // Hash table to look up TemplateInstance's of this TemplateDeclaration
572 TemplateInstance
[TemplateInstanceBox
] instances
;
574 TemplateDeclaration overnext
; // next overloaded TemplateDeclaration
575 TemplateDeclaration overroot
; // first in overnext list
576 FuncDeclaration funcroot
; // first function in unified overload list
578 Dsymbol onemember
; // if !=null then one member of this template
580 bool literal
; // this template declaration is a literal
581 bool ismixin
; // this is a mixin template declaration
582 bool isstatic
; // this is static template declaration
583 bool isTrivialAliasSeq
; /// matches pattern `template AliasSeq(T...) { alias AliasSeq = T; }`
584 bool isTrivialAlias
; /// matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
585 bool deprecated_
; /// this template declaration is deprecated
586 Visibility visibility
;
588 // threaded list of previous instantiation attempts on stack
589 TemplatePrevious
* previous
;
591 Expression lastConstraint
; /// the constraint after the last failed evaluation
592 Array
!Expression lastConstraintNegs
; /// its negative parts
593 Objects
* lastConstraintTiargs
; /// template instance arguments for `lastConstraint`
595 extern (D
) this(const ref Loc loc
, Identifier ident
, TemplateParameters
* parameters
, Expression constraint
, Dsymbols
* decldefs
, bool ismixin
= false, bool literal
= false)
600 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident
.toChars());
605 for (int i
= 0; i
< parameters
.length
; i
++)
607 TemplateParameter tp
= (*parameters
)[i
];
608 //printf("\tparameter[%d] = %p\n", i, tp);
609 TemplateTypeParameter ttp
= tp
.isTemplateTypeParameter();
612 printf("\tparameter[%d] = %s : %s\n", i
, tp
.ident
.toChars(), ttp
.specType ? ttp
.specType
.toChars() : "");
616 this.parameters
= parameters
;
617 this.origParameters
= parameters
;
618 this.constraint
= constraint
;
619 this.members
= decldefs
;
620 this.literal
= literal
;
621 this.ismixin
= ismixin
;
622 this.isstatic
= true;
623 this.visibility
= Visibility(Visibility
.Kind
.undefined
);
625 // Compute in advance for Ddoc's use
626 // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails.
627 if (!members ||
!ident
)
631 if (!Dsymbol
.oneMembers(members
, s
, ident
) ||
!s
)
637 /* Set isTrivialAliasSeq if this fits the pattern:
638 * template AliasSeq(T...) { alias AliasSeq = T; }
639 * or set isTrivialAlias if this fits the pattern:
640 * template Alias(T) { alias Alias = qualifiers(T); }
642 if (!(parameters
&& parameters
.length
== 1))
645 auto ad
= s
.isAliasDeclaration();
649 auto ti
= ad
.type
.isTypeIdentifier();
651 if (!ti || ti
.idents
.length
!= 0)
654 if (auto ttp
= (*parameters
)[0].isTemplateTupleParameter())
656 if (ti
.ident
is ttp
.ident
&&
659 //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
660 isTrivialAliasSeq
= true;
663 else if (auto ttp
= (*parameters
)[0].isTemplateTypeParameter())
665 if (ti
.ident
is ttp
.ident
)
667 //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
668 isTrivialAlias
= true;
673 override TemplateDeclaration
syntaxCopy(Dsymbol
)
675 //printf("TemplateDeclaration.syntaxCopy()\n");
676 TemplateParameters
* p
= null;
679 p
= new TemplateParameters(parameters
.length
);
680 foreach (i
, ref param
; *p
)
681 param
= (*parameters
)[i
].syntaxCopy();
683 return new TemplateDeclaration(loc
, ident
, p
, constraint ? constraint
.syntaxCopy() : null, Dsymbol
.arraySyntaxCopy(members
), ismixin
, literal
);
686 /**********************************
687 * Overload existing TemplateDeclaration 'this' with the new one 's'.
689 * s = symbol to be inserted
690 * Return: true if successful; i.e. no conflict.
692 override bool overloadInsert(Dsymbol s
)
696 printf("TemplateDeclaration.overloadInsert('%s')\n", s
.toChars());
698 FuncDeclaration fd
= s
.isFuncDeclaration();
702 return funcroot
.overloadInsert(fd
);
704 return funcroot
.overloadInsert(this);
707 // https://issues.dlang.org/show_bug.cgi?id=15795
708 // if candidate is an alias and its sema is not run then
709 // insertion can fail because the thing it alias is not known
710 if (AliasDeclaration ad
= s
.isAliasDeclaration())
713 aliasSemantic(ad
, s
._scope
);
714 if (ad
.aliassym
&& ad
.aliassym
is this)
717 TemplateDeclaration td
= s
.toAlias().isTemplateDeclaration();
721 TemplateDeclaration pthis
= this;
722 TemplateDeclaration
* ptd
;
723 for (ptd
= &pthis
; *ptd
; ptd
= &(*ptd
).overnext
)
731 printf("\ttrue: no conflict\n");
736 override bool hasStaticCtorOrDtor()
738 return false; // don't scan uninstantiated templates
741 override const(char)* kind() const
743 return (onemember
&& onemember
.isAggregateDeclaration()) ? onemember
.kind() : "template";
746 override const(char)* toChars() const
750 toCharsMaybeConstraints(this, buf
, hgs
);
751 return buf
.extractChars();
754 override Visibility
visible() pure nothrow @nogc @safe
759 /****************************
760 * Destructively get the error message from the last constraint evaluation
762 * tip = tip to show after printing all overloads
764 const(char)* getConstraintEvalError(ref const(char)* tip
)
766 import dmd
.staticcond
;
768 // there will be a full tree view in verbose mode, and more compact list in the usual
769 const full
= global
.params
.v
.verbose
;
771 const msg
= visualizeStaticCondition(constraint
, lastConstraint
, lastConstraintNegs
[], full
, count
);
774 lastConstraint
= null;
775 lastConstraintTiargs
= null;
776 lastConstraintNegs
.setDim(0);
783 assert(parameters
&& lastConstraintTiargs
);
784 if (parameters
.length
> 0)
786 formatParamsWithTiargs(*parameters
, *lastConstraintTiargs
, isVariadic() !is null, buf
);
791 // choosing singular/plural
792 const s
= (count
== 1) ?
793 " must satisfy the following constraint:" :
794 " must satisfy one of the following constraints:";
799 buf
.writestring(msg
);
804 buf
.writestring(" whose parameters have the following constraints:");
806 const sep
= " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
807 buf
.writestring(sep
);
811 buf
.writestring(msg
);
813 buf
.writestring(sep
);
814 tip
= "not satisfied constraints are marked with `>`";
816 return buf
.extractChars();
819 debug (FindExistingInstance
)
821 __gshared
uint nFound
, nNotFound
, nAdded
, nRemoved
;
823 shared static ~this()
825 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
826 nFound
, nNotFound
, nAdded
, nRemoved
);
830 /****************************************************
831 * Given a new instance `tithis` of this TemplateDeclaration,
832 * see if there already exists an instance.
835 * tithis = template instance to check
836 * argumentList = For function templates, needed because different
837 * `auto ref` resolutions create different instances,
838 * even when template parameters are identical
840 * Returns: that existing instance, or `null` when it doesn't exist
842 extern (D
) TemplateInstance
findExistingInstance(TemplateInstance tithis
, ArgumentList argumentList
)
844 //printf("findExistingInstance() %s\n", tithis.toChars());
845 tithis
.fargs
= argumentList
.arguments
;
846 tithis
.fnames
= argumentList
.names
;
847 auto tibox
= TemplateInstanceBox(tithis
);
848 auto p
= tibox
in this.instances
;
849 debug (FindExistingInstance
) ++(p ? nFound
: nNotFound
);
850 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
851 return p ?
*p
: null;
854 /********************************************
855 * Add instance ti to TemplateDeclaration's table of instances.
856 * Return a handle we can use to later remove it if it fails instantiation.
858 extern (D
) TemplateInstance
addInstance(TemplateInstance ti
)
860 //printf("addInstance() %p %s\n", instances, ti.toChars());
861 auto tibox
= TemplateInstanceBox(ti
);
862 instances
[tibox
] = ti
;
863 debug (FindExistingInstance
) ++nAdded
;
867 /*******************************************
868 * Remove TemplateInstance from table of instances.
870 * handle returned by addInstance()
872 extern (D
) void removeInstance(TemplateInstance ti
)
874 //printf("removeInstance() %s\n", ti.toChars());
875 auto tibox
= TemplateInstanceBox(ti
);
876 debug (FindExistingInstance
) ++nRemoved
;
877 instances
.remove(tibox
);
880 override inout(TemplateDeclaration
) isTemplateDeclaration() inout
886 * Check if the last template parameter is a tuple one,
887 * and returns it if so, else returns `null`.
890 * The last template parameter if it's a `TemplateTupleParameter`
892 extern (D
) TemplateTupleParameter
isVariadic()
894 size_t dim
= parameters
.length
;
897 return (*parameters
)[dim
- 1].isTemplateTupleParameter();
900 extern(C
++) override bool isDeprecated() const
902 return this.deprecated_
;
905 /***********************************
906 * We can overload templates.
908 override bool isOverloadable() const
913 override void accept(Visitor v
)
919 extern (C
++) final class TypeDeduced
: Type
922 Expressions argexps
; // corresponding expressions
923 Types tparams
; // tparams[i].mod
925 extern (D
) this(Type tt
, Expression e
, Type tparam
)
930 tparams
.push(tparam
);
933 void update(Expression e
, Type tparam
)
936 tparams
.push(tparam
);
939 void update(Type tt
, Expression e
, Type tparam
)
943 tparams
.push(tparam
);
946 MATCH
matchAll(Type tt
)
948 MATCH match
= MATCH
.exact
;
949 foreach (j
, e
; argexps
)
952 if (e
== emptyArrayElement
)
955 Type t
= tt
.addMod(tparams
[j
].mod
).substWildTo(MODFlags
.const_
);
957 MATCH m
= e
.implicitConvTo(t
);
960 if (match
== MATCH
.nomatch
)
968 /* ======================== Type ============================================ */
971 * Given an identifier, figure out which TemplateParameter it is.
972 * Return IDX_NOTFOUND if not found.
974 private size_t
templateIdentifierLookup(Identifier id
, TemplateParameters
* parameters
)
976 for (size_t i
= 0; i
< parameters
.length
; i
++)
978 TemplateParameter tp
= (*parameters
)[i
];
979 if (tp
.ident
.equals(id
))
985 size_t
templateParameterLookup(Type tparam
, TemplateParameters
* parameters
)
987 if (TypeIdentifier tident
= tparam
.isTypeIdentifier())
989 //printf("\ttident = '%s'\n", tident.toChars());
990 return templateIdentifierLookup(tident
.ident
, parameters
);
995 ubyte deduceWildHelper(Type t
, Type
* at
, Type tparam
)
997 if ((tparam
.mod
& MODFlags
.wild
) == 0)
1002 auto X(T
, U
)(T U
, U T
)
1004 return (U
<< 4) | T
;
1007 switch (X(tparam
.mod
, t
.mod
))
1009 case X(MODFlags
.wild
, 0):
1010 case X(MODFlags
.wild
, MODFlags
.const_
):
1011 case X(MODFlags
.wild
, MODFlags
.shared_
):
1012 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
1013 case X(MODFlags
.wild
, MODFlags
.immutable_
):
1014 case X(MODFlags
.wildconst
, 0):
1015 case X(MODFlags
.wildconst
, MODFlags
.const_
):
1016 case X(MODFlags
.wildconst
, MODFlags
.shared_
):
1017 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
1018 case X(MODFlags
.wildconst
, MODFlags
.immutable_
):
1019 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_
):
1020 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
1021 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.immutable_
):
1022 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_
):
1023 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
1024 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.immutable_
):
1026 ubyte wm
= (t
.mod
& ~MODFlags
.shared_
);
1028 wm
= MODFlags
.mutable
;
1029 ubyte m
= (t
.mod
& (MODFlags
.const_ | MODFlags
.immutable_
)) |
(tparam
.mod
& t
.mod
& MODFlags
.shared_
);
1030 *at
= t
.unqualify(m
);
1033 case X(MODFlags
.wild
, MODFlags
.wild
):
1034 case X(MODFlags
.wild
, MODFlags
.wildconst
):
1035 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
1036 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
1037 case X(MODFlags
.wildconst
, MODFlags
.wild
):
1038 case X(MODFlags
.wildconst
, MODFlags
.wildconst
):
1039 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
1040 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
1041 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
1042 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
1043 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
1044 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
1046 *at
= t
.unqualify(tparam
.mod
& t
.mod
);
1047 return MODFlags
.wild
;
1055 * Returns the common type of the 2 types.
1057 private Type
rawTypeMerge(Type t1
, Type t2
)
1061 if (t1
.equivalent(t2
))
1062 return t1
.castMod(MODmerge(t1
.mod
, t2
.mod
));
1064 auto t1b
= t1
.toBasetype();
1065 auto t2b
= t2
.toBasetype();
1066 if (t1b
.equals(t2b
))
1068 if (t1b
.equivalent(t2b
))
1069 return t1b
.castMod(MODmerge(t1b
.mod
, t2b
.mod
));
1071 auto ty
= implicitConvCommonTy(t1b
.ty
, t2b
.ty
);
1073 return Type
.basic
[ty
];
1078 MATCH
deduceTypeHelper(Type t
, out Type at
, Type tparam
)
1082 auto X(T
, U
)(T U
, U T
)
1084 return (U
<< 4) | T
;
1087 switch (X(tparam
.mod
, t
.mod
))
1090 case X(0, MODFlags
.const_
):
1091 case X(0, MODFlags
.wild
):
1092 case X(0, MODFlags
.wildconst
):
1093 case X(0, MODFlags
.shared_
):
1094 case X(0, MODFlags
.shared_ | MODFlags
.const_
):
1095 case X(0, MODFlags
.shared_ | MODFlags
.wild
):
1096 case X(0, MODFlags
.shared_ | MODFlags
.wildconst
):
1097 case X(0, MODFlags
.immutable_
):
1099 // foo(U) const(T) => const(T)
1100 // foo(U) inout(T) => inout(T)
1101 // foo(U) inout(const(T)) => inout(const(T))
1102 // foo(U) shared(T) => shared(T)
1103 // foo(U) shared(const(T)) => shared(const(T))
1104 // foo(U) shared(inout(T)) => shared(inout(T))
1105 // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
1106 // foo(U) immutable(T) => immutable(T)
1111 case X(MODFlags
.const_
, MODFlags
.const_
):
1112 case X(MODFlags
.wild
, MODFlags
.wild
):
1113 case X(MODFlags
.wildconst
, MODFlags
.wildconst
):
1114 case X(MODFlags
.shared_
, MODFlags
.shared_
):
1115 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.const_
):
1116 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
1117 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
1118 case X(MODFlags
.immutable_
, MODFlags
.immutable_
):
1119 // foo(const(U)) const(T) => T
1120 // foo(inout(U)) inout(T) => T
1121 // foo(inout(const(U))) inout(const(T)) => T
1122 // foo(shared(U)) shared(T) => T
1123 // foo(shared(const(U))) shared(const(T)) => T
1124 // foo(shared(inout(U))) shared(inout(T)) => T
1125 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
1126 // foo(immutable(U)) immutable(T) => T
1128 at
= t
.mutableOf().unSharedOf();
1131 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.const_
):
1132 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
1133 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
1134 // foo(const(U)) shared(const(T)) => shared(T)
1135 // foo(inout(U)) shared(inout(T)) => shared(T)
1136 // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
1141 case X(MODFlags
.const_
, 0):
1142 case X(MODFlags
.const_
, MODFlags
.wild
):
1143 case X(MODFlags
.const_
, MODFlags
.wildconst
):
1144 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wild
):
1145 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wildconst
):
1146 case X(MODFlags
.const_
, MODFlags
.immutable_
):
1147 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.immutable_
):
1148 // foo(const(U)) T => T
1149 // foo(const(U)) inout(T) => T
1150 // foo(const(U)) inout(const(T)) => T
1151 // foo(const(U)) shared(inout(T)) => shared(T)
1152 // foo(const(U)) shared(inout(const(T))) => shared(T)
1153 // foo(const(U)) immutable(T) => T
1154 // foo(shared(const(U))) immutable(T) => T
1157 return MATCH
.constant
;
1159 case X(MODFlags
.const_
, MODFlags
.shared_
):
1160 // foo(const(U)) shared(T) => shared(T)
1163 return MATCH
.constant
;
1165 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.const_
):
1166 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.wild
):
1167 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.wildconst
):
1168 // foo(shared(U)) shared(const(T)) => const(T)
1169 // foo(shared(U)) shared(inout(T)) => inout(T)
1170 // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
1172 at
= t
.unSharedOf();
1175 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_
):
1176 // foo(shared(const(U))) shared(T) => T
1178 at
= t
.unSharedOf();
1179 return MATCH
.constant
;
1181 case X(MODFlags
.wildconst
, MODFlags
.immutable_
):
1182 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wildconst
):
1183 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.immutable_
):
1184 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
1185 // foo(inout(const(U))) immutable(T) => T
1186 // foo(shared(const(U))) shared(inout(const(T))) => T
1187 // foo(shared(inout(const(U)))) immutable(T) => T
1188 // foo(shared(inout(const(U)))) shared(inout(T)) => T
1190 at
= t
.unSharedOf().mutableOf();
1191 return MATCH
.constant
;
1193 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wild
):
1194 // foo(shared(const(U))) shared(inout(T)) => T
1196 at
= t
.unSharedOf().mutableOf();
1197 return MATCH
.constant
;
1199 case X(MODFlags
.wild
, 0):
1200 case X(MODFlags
.wild
, MODFlags
.const_
):
1201 case X(MODFlags
.wild
, MODFlags
.wildconst
):
1202 case X(MODFlags
.wild
, MODFlags
.immutable_
):
1203 case X(MODFlags
.wild
, MODFlags
.shared_
):
1204 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
1205 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
1206 case X(MODFlags
.wildconst
, 0):
1207 case X(MODFlags
.wildconst
, MODFlags
.const_
):
1208 case X(MODFlags
.wildconst
, MODFlags
.wild
):
1209 case X(MODFlags
.wildconst
, MODFlags
.shared_
):
1210 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
1211 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
1212 case X(MODFlags
.shared_
, 0):
1213 case X(MODFlags
.shared_
, MODFlags
.const_
):
1214 case X(MODFlags
.shared_
, MODFlags
.wild
):
1215 case X(MODFlags
.shared_
, MODFlags
.wildconst
):
1216 case X(MODFlags
.shared_
, MODFlags
.immutable_
):
1217 case X(MODFlags
.shared_ | MODFlags
.const_
, 0):
1218 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.const_
):
1219 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.wild
):
1220 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.wildconst
):
1221 case X(MODFlags
.shared_ | MODFlags
.wild
, 0):
1222 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.const_
):
1223 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.wild
):
1224 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.wildconst
):
1225 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.immutable_
):
1226 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_
):
1227 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
1228 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
1229 case X(MODFlags
.shared_ | MODFlags
.wildconst
, 0):
1230 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.const_
):
1231 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.wild
):
1232 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.wildconst
):
1233 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_
):
1234 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
1235 case X(MODFlags
.immutable_
, 0):
1236 case X(MODFlags
.immutable_
, MODFlags
.const_
):
1237 case X(MODFlags
.immutable_
, MODFlags
.wild
):
1238 case X(MODFlags
.immutable_
, MODFlags
.wildconst
):
1239 case X(MODFlags
.immutable_
, MODFlags
.shared_
):
1240 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.const_
):
1241 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.wild
):
1242 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.wildconst
):
1243 // foo(inout(U)) T => nomatch
1244 // foo(inout(U)) const(T) => nomatch
1245 // foo(inout(U)) inout(const(T)) => nomatch
1246 // foo(inout(U)) immutable(T) => nomatch
1247 // foo(inout(U)) shared(T) => nomatch
1248 // foo(inout(U)) shared(const(T)) => nomatch
1249 // foo(inout(U)) shared(inout(const(T))) => nomatch
1250 // foo(inout(const(U))) T => nomatch
1251 // foo(inout(const(U))) const(T) => nomatch
1252 // foo(inout(const(U))) inout(T) => nomatch
1253 // foo(inout(const(U))) shared(T) => nomatch
1254 // foo(inout(const(U))) shared(const(T)) => nomatch
1255 // foo(inout(const(U))) shared(inout(T)) => nomatch
1256 // foo(shared(U)) T => nomatch
1257 // foo(shared(U)) const(T) => nomatch
1258 // foo(shared(U)) inout(T) => nomatch
1259 // foo(shared(U)) inout(const(T)) => nomatch
1260 // foo(shared(U)) immutable(T) => nomatch
1261 // foo(shared(const(U))) T => nomatch
1262 // foo(shared(const(U))) const(T) => nomatch
1263 // foo(shared(const(U))) inout(T) => nomatch
1264 // foo(shared(const(U))) inout(const(T)) => nomatch
1265 // foo(shared(inout(U))) T => nomatch
1266 // foo(shared(inout(U))) const(T) => nomatch
1267 // foo(shared(inout(U))) inout(T) => nomatch
1268 // foo(shared(inout(U))) inout(const(T)) => nomatch
1269 // foo(shared(inout(U))) immutable(T) => nomatch
1270 // foo(shared(inout(U))) shared(T) => nomatch
1271 // foo(shared(inout(U))) shared(const(T)) => nomatch
1272 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
1273 // foo(shared(inout(const(U)))) T => nomatch
1274 // foo(shared(inout(const(U)))) const(T) => nomatch
1275 // foo(shared(inout(const(U)))) inout(T) => nomatch
1276 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
1277 // foo(shared(inout(const(U)))) shared(T) => nomatch
1278 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
1279 // foo(immutable(U)) T => nomatch
1280 // foo(immutable(U)) const(T) => nomatch
1281 // foo(immutable(U)) inout(T) => nomatch
1282 // foo(immutable(U)) inout(const(T)) => nomatch
1283 // foo(immutable(U)) shared(T) => nomatch
1284 // foo(immutable(U)) shared(const(T)) => nomatch
1285 // foo(immutable(U)) shared(inout(T)) => nomatch
1286 // foo(immutable(U)) shared(inout(const(T))) => nomatch
1287 return MATCH
.nomatch
;
1294 __gshared Expression emptyArrayElement
= null;
1296 /* These form the heart of template argument deduction.
1297 * Given 'this' being the type argument to the template instance,
1298 * it is matched against the template declaration parameter specialization
1299 * 'tparam' to determine the type to be used for the parameter.
1301 * template Foo(T:T*) // template declaration
1302 * Foo!(int*) // template instantiation
1306 * parameters = [ T:T* ] // Array of TemplateParameter's
1308 * dedtypes = [ int ] // Array of Expression/Type's
1310 MATCH
deduceType(RootObject o
, Scope
* sc
, Type tparam
, ref TemplateParameters parameters
, ref Objects dedtypes
, uint* wm
= null, size_t inferStart
= 0, bool ignoreAliasThis
= false)
1312 extern (C
++) final class DeduceType
: Visitor
1314 alias visit
= Visitor
.visit
;
1318 extern (D
) this() @safe
1320 result
= MATCH
.nomatch
;
1323 override void visit(Type t
)
1331 if (tparam
.ty
== Tident
)
1333 // Determine which parameter tparam is
1334 size_t i
= templateParameterLookup(tparam
, ¶meters
);
1335 if (i
== IDX_NOTFOUND
)
1340 /* Need a loc to go with the semantic routine.
1343 if (parameters
.length
)
1345 TemplateParameter tp
= parameters
[0];
1349 /* BUG: what if tparam is a template instance, that
1350 * has as an argument another Tident?
1352 tparam
= tparam
.typeSemantic(loc
, sc
);
1353 assert(tparam
.ty
!= Tident
);
1354 result
= deduceType(t
, sc
, tparam
, parameters
, dedtypes
, wm
);
1358 TemplateParameter tp
= parameters
[i
];
1360 TypeIdentifier tident
= tparam
.isTypeIdentifier();
1361 if (tident
.idents
.length
> 0)
1363 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
1364 Dsymbol s
= t
.toDsymbol(sc
);
1365 for (size_t j
= tident
.idents
.length
; j
-- > 0;)
1367 RootObject id
= tident
.idents
[j
];
1368 if (id
.dyncast() == DYNCAST
.identifier
)
1370 if (!s ||
!s
.parent
)
1372 Dsymbol s2
= s
.parent
.search(Loc
.initial
, cast(Identifier
)id
);
1376 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
1379 if (Type tx
= s2
.getType())
1381 if (s
!= tx
.toDsymbol(sc
))
1392 //printf("[e] s = %s\n", s?s.toChars():"(null)");
1393 if (tp
.isTemplateTypeParameter())
1395 Type tt
= s
.getType();
1398 Type at
= cast(Type
)dedtypes
[i
];
1399 if (at
&& at
.ty
== Tnone
)
1400 at
= (cast(TypeDeduced
)at
).tded
;
1401 if (!at || tt
.equals(at
))
1407 if (tp
.isTemplateAliasParameter())
1409 Dsymbol s2
= cast(Dsymbol
)dedtypes
[i
];
1419 // Found the corresponding parameter tp
1421 https://issues.dlang.org/show_bug.cgi?id=23578
1423 static if (is(S!int == S!av, alias av))
1425 We eventually need to deduce `int` (Tint32 [0]) and `av` (Tident).
1426 Previously this would not get pattern matched at all, but now we check if the
1427 template parameter `av` came from.
1429 This note has been left to serve as a hint for further explorers into
1430 how IsExp matching works.
1432 if (auto ta
= tp
.isTemplateAliasParameter())
1437 // (23578) - ensure previous behaviour for non-alias template params
1438 if (!tp
.isTemplateTypeParameter())
1443 Type at
= cast(Type
)dedtypes
[i
];
1445 if (ubyte wx
= wm ?
deduceWildHelper(t
, &tt
, tparam
) : 0)
1452 result
= MATCH
.constant
;
1456 // type vs expressions
1459 auto xt
= cast(TypeDeduced
)at
;
1460 result
= xt
.matchAll(tt
);
1461 if (result
> MATCH
.nomatch
)
1464 if (result
> MATCH
.constant
)
1465 result
= MATCH
.constant
; // limit level for inout matches
1473 dedtypes
[i
] = tt
; // Prefer current type match
1476 if (tt
.implicitConvTo(at
.constOf()))
1478 dedtypes
[i
] = at
.constOf().mutableOf();
1479 *wm |
= MODFlags
.const_
;
1482 if (at
.implicitConvTo(tt
.constOf()))
1484 dedtypes
[i
] = tt
.constOf().mutableOf();
1485 *wm |
= MODFlags
.const_
;
1490 else if (MATCH m
= deduceTypeHelper(t
, tt
, tparam
))
1500 // type vs expressions
1503 auto xt
= cast(TypeDeduced
)at
;
1504 result
= xt
.matchAll(tt
);
1505 if (result
> MATCH
.nomatch
)
1517 if (tt
.ty
== Tclass
&& at
.ty
== Tclass
)
1519 result
= tt
.implicitConvTo(at
);
1522 if (tt
.ty
== Tsarray
&& at
.ty
== Tarray
&& tt
.nextOf().implicitConvTo(at
.nextOf()) >= MATCH
.constant
)
1530 if (tparam
.ty
== Ttypeof
)
1532 /* Need a loc to go with the semantic routine.
1535 if (parameters
.length
)
1537 TemplateParameter tp
= parameters
[0];
1541 tparam
= tparam
.typeSemantic(loc
, sc
);
1543 if (t
.ty
!= tparam
.ty
)
1545 if (Dsymbol sym
= t
.toDsymbol(sc
))
1547 if (sym
.isforwardRef() && !tparam
.deco
)
1551 MATCH m
= t
.implicitConvTo(tparam
);
1552 if (m
== MATCH
.nomatch
&& !ignoreAliasThis
)
1554 if (auto tc
= t
.isTypeClass())
1556 if (tc
.sym
.aliasthis
&& !(tc
.att
& AliasThisRec
.tracingDT
))
1558 if (auto ato
= t
.aliasthisOf())
1560 tc
.att
= cast(AliasThisRec
)(tc
.att | AliasThisRec
.tracingDT
);
1561 m
= deduceType(ato
, sc
, tparam
, parameters
, dedtypes
, wm
);
1562 tc
.att
= cast(AliasThisRec
)(tc
.att
& ~AliasThisRec
.tracingDT
);
1566 else if (auto ts
= t
.isTypeStruct())
1568 if (ts
.sym
.aliasthis
&& !(ts
.att
& AliasThisRec
.tracingDT
))
1570 if (auto ato
= t
.aliasthisOf())
1572 ts
.att
= cast(AliasThisRec
)(ts
.att | AliasThisRec
.tracingDT
);
1573 m
= deduceType(ato
, sc
, tparam
, parameters
, dedtypes
, wm
);
1574 ts
.att
= cast(AliasThisRec
)(ts
.att
& ~AliasThisRec
.tracingDT
);
1585 if (tparam
.deco
&& !tparam
.hasWild())
1587 result
= t
.implicitConvTo(tparam
);
1591 Type tpn
= tparam
.nextOf();
1592 if (wm
&& t
.ty
== Taarray
&& tparam
.isWild())
1594 // https://issues.dlang.org/show_bug.cgi?id=12403
1595 // In IFTI, stop inout matching on transitive part of AA types.
1596 tpn
= tpn
.substWildTo(MODFlags
.mutable
);
1599 result
= deduceType(t
.nextOf(), sc
, tpn
, parameters
, dedtypes
, wm
);
1604 result
= MATCH
.exact
;
1608 result
= MATCH
.nomatch
;
1612 result
= MATCH
.constant
;
1615 override void visit(TypeVector t
)
1617 if (auto tp
= tparam
.isTypeVector())
1619 result
= deduceType(t
.basetype
, sc
, tp
.basetype
, parameters
, dedtypes
, wm
);
1625 override void visit(TypeDArray t
)
1630 override void visit(TypeSArray t
)
1632 // Extra check that array dimensions must match
1635 if (tparam
.ty
== Tarray
)
1637 MATCH m
= deduceType(t
.next
, sc
, tparam
.nextOf(), parameters
, dedtypes
, wm
);
1638 result
= (m
>= MATCH
.constant
) ? MATCH
.convert
: MATCH
.nomatch
;
1642 TemplateParameter tp
= null;
1643 Expression edim
= null;
1645 if (auto tsa
= tparam
.isTypeSArray())
1647 if (tsa
.dim
.isVarExp() && tsa
.dim
.isVarExp().var
.storage_class
& STC
.templateparameter
)
1649 Identifier id
= tsa
.dim
.isVarExp().var
.ident
;
1650 i
= templateIdentifierLookup(id
, ¶meters
);
1651 assert(i
!= IDX_NOTFOUND
);
1657 else if (auto taa
= tparam
.isTypeAArray())
1659 i
= templateParameterLookup(taa
.index
, ¶meters
);
1660 if (i
!= IDX_NOTFOUND
)
1665 // The "type" (it hasn't been resolved yet) of the function parameter
1666 // does not have a location but the parameter it is related to does,
1667 // so we use that for the resolution (better error message).
1668 if (inferStart
< parameters
.length
)
1670 TemplateParameter loctp
= parameters
[inferStart
];
1677 taa
.index
.resolve(loc
, sc
, e
, tx
, s
);
1678 edim
= s ?
getValue(s
) : getValue(e
);
1681 if (tp
&& tp
.matchArg(sc
, t
.dim
, i
, ¶meters
, dedtypes
, null) || edim
&& edim
.toInteger() == t
.dim
.toInteger())
1683 result
= deduceType(t
.next
, sc
, tparam
.nextOf(), parameters
, dedtypes
, wm
);
1690 override void visit(TypeAArray t
)
1692 // Extra check that index type must match
1693 if (tparam
&& tparam
.ty
== Taarray
)
1695 TypeAArray tp
= tparam
.isTypeAArray();
1696 if (!deduceType(t
.index
, sc
, tp
.index
, parameters
, dedtypes
))
1698 result
= MATCH
.nomatch
;
1705 override void visit(TypeFunction t
)
1707 // Extra check that function characteristics must match
1709 return visit(cast(Type
)t
);
1711 if (auto tp
= tparam
.isTypeFunction())
1713 if (t
.parameterList
.varargs
!= tp
.parameterList
.varargs || t
.linkage
!= tp
.linkage
)
1715 result
= MATCH
.nomatch
;
1719 foreach (fparam
; *tp
.parameterList
.parameters
)
1721 // https://issues.dlang.org/show_bug.cgi?id=2579
1722 // Apply function parameter storage classes to parameter types
1723 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1724 fparam
.storageClass
&= ~STC
.TYPECTOR
;
1726 // https://issues.dlang.org/show_bug.cgi?id=15243
1727 // Resolve parameter type if it's not related with template parameters
1728 if (!reliesOnTemplateParameters(fparam
.type
, parameters
[inferStart
.. parameters
.length
]))
1730 auto tx
= fparam
.type
.typeSemantic(Loc
.initial
, sc
);
1731 if (tx
.ty
== Terror
)
1733 result
= MATCH
.nomatch
;
1740 const size_t nfargs
= t
.parameterList
.length
;
1741 size_t nfparams
= tp
.parameterList
.length
;
1743 /* See if tuple match
1745 if (nfparams
> 0 && nfargs
>= nfparams
- 1)
1747 /* See if 'A' of the template parameter matches 'A'
1748 * of the type of the last function parameter.
1750 Parameter fparam
= tp
.parameterList
[nfparams
- 1];
1752 assert(fparam
.type
);
1753 if (fparam
.type
.ty
!= Tident
)
1755 TypeIdentifier tid
= fparam
.type
.isTypeIdentifier();
1756 if (tid
.idents
.length
)
1759 /* Look through parameters to find tuple matching tid.ident
1764 if (tupi
== parameters
.length
)
1766 TemplateParameter tx
= parameters
[tupi
];
1767 TemplateTupleParameter tup
= tx
.isTemplateTupleParameter();
1768 if (tup
&& tup
.ident
.equals(tid
.ident
))
1772 /* The types of the function arguments [nfparams - 1 .. nfargs]
1773 * now form the tuple argument.
1775 size_t tuple_dim
= nfargs
- (nfparams
- 1);
1777 /* See if existing tuple, and whether it matches or not
1779 RootObject o
= dedtypes
[tupi
];
1782 // Existing deduced argument must be a tuple, and must match
1783 Tuple tup
= isTuple(o
);
1784 if (!tup || tup
.objects
.length
!= tuple_dim
)
1786 result
= MATCH
.nomatch
;
1789 for (size_t i
= 0; i
< tuple_dim
; i
++)
1791 Parameter arg
= t
.parameterList
[nfparams
- 1 + i
];
1792 if (!arg
.type
.equals(tup
.objects
[i
]))
1794 result
= MATCH
.nomatch
;
1802 auto tup
= new Tuple(tuple_dim
);
1803 for (size_t i
= 0; i
< tuple_dim
; i
++)
1805 Parameter arg
= t
.parameterList
[nfparams
- 1 + i
];
1806 tup
.objects
[i
] = arg
.type
;
1808 dedtypes
[tupi
] = tup
;
1810 nfparams
--; // don't consider the last parameter for type deduction
1815 if (nfargs
!= nfparams
)
1817 result
= MATCH
.nomatch
;
1821 assert(nfparams
<= tp
.parameterList
.length
);
1822 foreach (i
, ap
; tp
.parameterList
)
1827 Parameter a
= t
.parameterList
[i
];
1829 if (!a
.isCovariant(t
.isref
, ap
) ||
1830 !deduceType(a
.type
, sc
, ap
.type
, parameters
, dedtypes
))
1832 result
= MATCH
.nomatch
;
1840 override void visit(TypeIdentifier t
)
1843 if (tparam
&& tparam
.ty
== Tident
)
1845 TypeIdentifier tp
= tparam
.isTypeIdentifier();
1846 for (size_t i
= 0; i
< t
.idents
.length
; i
++)
1848 RootObject id1
= t
.idents
[i
];
1849 RootObject id2
= tp
.idents
[i
];
1850 if (!id1
.equals(id2
))
1852 result
= MATCH
.nomatch
;
1860 override void visit(TypeInstance t
)
1863 if (tparam
&& tparam
.ty
== Tinstance
&& t
.tempinst
.tempdecl
)
1865 TemplateDeclaration tempdecl
= t
.tempinst
.tempdecl
.isTemplateDeclaration();
1868 TypeInstance tp
= tparam
.isTypeInstance();
1870 //printf("tempinst.tempdecl = %p\n", tempdecl);
1871 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
1872 if (!tp
.tempinst
.tempdecl
)
1874 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
1877 * template Foo(T : sa!(T), alias sa)
1879 size_t i
= templateIdentifierLookup(tp
.tempinst
.name
, ¶meters
);
1880 if (i
== IDX_NOTFOUND
)
1882 /* Didn't find it as a parameter identifier. Try looking
1883 * it up and seeing if is an alias.
1884 * https://issues.dlang.org/show_bug.cgi?id=1454
1886 auto tid
= new TypeIdentifier(tp
.loc
, tp
.tempinst
.name
);
1890 tid
.resolve(tp
.loc
, sc
, e
, tx
, s
);
1893 s
= tx
.toDsymbol(sc
);
1894 if (TemplateInstance ti
= s ? s
.parent
.isTemplateInstance() : null)
1896 // https://issues.dlang.org/show_bug.cgi?id=14290
1897 // Try to match with ti.tempecl,
1898 // only when ti is an enclosing instance.
1899 Dsymbol p
= sc
.parent
;
1900 while (p
&& p
!= ti
)
1909 TemplateDeclaration td
= s
.isTemplateDeclaration();
1914 for (; td
; td
= td
.overnext
)
1924 TemplateParameter tpx
= parameters
[i
];
1925 if (!tpx
.matchArg(sc
, tempdecl
, i
, ¶meters
, dedtypes
, null))
1928 else if (tempdecl
!= tp
.tempinst
.tempdecl
)
1932 if (!resolveTemplateInstantiation(sc
, ¶meters
, t
.tempinst
.tiargs
, &t
.tempinst
.tdtypes
, tempdecl
, tp
, &dedtypes
))
1939 //printf("no match\n");
1940 result
= MATCH
.nomatch
;
1943 override void visit(TypeStruct t
)
1945 /* If this struct is a template struct, and we're matching
1946 * it against a template instance, convert the struct type
1947 * to a template instance, too, and try again.
1949 TemplateInstance ti
= t
.sym
.parent
.isTemplateInstance();
1951 if (tparam
&& tparam
.ty
== Tinstance
)
1953 if (ti
&& ti
.toAlias() == t
.sym
)
1955 auto tx
= new TypeInstance(Loc
.initial
, ti
);
1956 auto m
= deduceType(tx
, sc
, tparam
, parameters
, dedtypes
, wm
);
1957 // if we have a no match we still need to check alias this
1958 if (m
!= MATCH
.nomatch
)
1965 /* Match things like:
1968 TypeInstance tpi
= tparam
.isTypeInstance();
1969 if (tpi
.idents
.length
)
1971 RootObject id
= tpi
.idents
[tpi
.idents
.length
- 1];
1972 if (id
.dyncast() == DYNCAST
.identifier
&& t
.sym
.ident
.equals(cast(Identifier
)id
))
1974 Type tparent
= t
.sym
.parent
.getType();
1977 /* Slice off the .foo in S!(T).foo
1979 tpi
.idents
.length
--;
1980 result
= deduceType(tparent
, sc
, tpi
, parameters
, dedtypes
, wm
);
1981 tpi
.idents
.length
++;
1989 if (tparam
&& tparam
.ty
== Tstruct
)
1991 TypeStruct tp
= tparam
.isTypeStruct();
1993 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
1994 if (wm
&& t
.deduceWild(tparam
, false))
1996 result
= MATCH
.constant
;
1999 result
= t
.implicitConvTo(tp
);
2005 override void visit(TypeEnum t
)
2008 if (tparam
&& tparam
.ty
== Tenum
)
2010 TypeEnum tp
= tparam
.isTypeEnum();
2011 if (t
.sym
== tp
.sym
)
2014 result
= MATCH
.nomatch
;
2017 Type tb
= t
.toBasetype();
2018 if (tb
.ty
== tparam
.ty || tb
.ty
== Tsarray
&& tparam
.ty
== Taarray
)
2020 result
= deduceType(tb
, sc
, tparam
, parameters
, dedtypes
, wm
);
2021 if (result
== MATCH
.exact
)
2022 result
= MATCH
.convert
;
2028 override void visit(TypeClass t
)
2030 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
2032 /* If this class is a template class, and we're matching
2033 * it against a template instance, convert the class type
2034 * to a template instance, too, and try again.
2036 TemplateInstance ti
= t
.sym
.parent
.isTemplateInstance();
2038 if (tparam
&& tparam
.ty
== Tinstance
)
2040 if (ti
&& ti
.toAlias() == t
.sym
)
2042 auto tx
= new TypeInstance(Loc
.initial
, ti
);
2043 MATCH m
= deduceType(tx
, sc
, tparam
, parameters
, dedtypes
, wm
);
2044 // Even if the match fails, there is still a chance it could match
2046 if (m
!= MATCH
.nomatch
)
2053 /* Match things like:
2056 TypeInstance tpi
= tparam
.isTypeInstance();
2057 if (tpi
.idents
.length
)
2059 RootObject id
= tpi
.idents
[tpi
.idents
.length
- 1];
2060 if (id
.dyncast() == DYNCAST
.identifier
&& t
.sym
.ident
.equals(cast(Identifier
)id
))
2062 Type tparent
= t
.sym
.parent
.getType();
2065 /* Slice off the .foo in S!(T).foo
2067 tpi
.idents
.length
--;
2068 result
= deduceType(tparent
, sc
, tpi
, parameters
, dedtypes
, wm
);
2069 tpi
.idents
.length
++;
2075 // If it matches exactly or via implicit conversion, we're done
2077 if (result
!= MATCH
.nomatch
)
2080 /* There is still a chance to match via implicit conversion to
2081 * a base class or interface. Because there could be more than one such
2082 * match, we need to check them all.
2085 int numBaseClassMatches
= 0; // Have we found an interface match?
2087 // Our best guess at dedtypes
2088 auto best
= new Objects(dedtypes
.length
);
2090 ClassDeclaration s
= t
.sym
;
2091 while (s
&& s
.baseclasses
.length
> 0)
2093 // Test the base class
2094 deduceBaseClassParameters(*(*s
.baseclasses
)[0], sc
, tparam
, parameters
, dedtypes
, *best
, numBaseClassMatches
);
2096 // Test the interfaces inherited by the base class
2097 foreach (b
; s
.interfaces
)
2099 deduceBaseClassParameters(*b
, sc
, tparam
, parameters
, dedtypes
, *best
, numBaseClassMatches
);
2101 s
= (*s
.baseclasses
)[0].sym
;
2104 if (numBaseClassMatches
== 0)
2106 result
= MATCH
.nomatch
;
2110 // If we got at least one match, copy the known types into dedtypes
2111 memcpy(dedtypes
.tdata(), best
.tdata(), best
.length
* (void*).sizeof
);
2112 result
= MATCH
.convert
;
2117 if (tparam
&& tparam
.ty
== Tclass
)
2119 TypeClass tp
= tparam
.isTypeClass();
2121 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
2122 if (wm
&& t
.deduceWild(tparam
, false))
2124 result
= MATCH
.constant
;
2127 result
= t
.implicitConvTo(tp
);
2133 override void visit(Expression e
)
2135 //printf("Expression.deduceType(e = %s)\n", e.toChars());
2136 size_t i
= templateParameterLookup(tparam
, ¶meters
);
2137 if (i
== IDX_NOTFOUND || tparam
.isTypeIdentifier().idents
.length
> 0)
2139 if (e
== emptyArrayElement
&& tparam
.ty
== Tarray
)
2141 Type tn
= (cast(TypeNext
)tparam
).next
;
2142 result
= deduceType(emptyArrayElement
, sc
, tn
, parameters
, dedtypes
, wm
);
2145 e
.type
.accept(this);
2149 TemplateTypeParameter tp
= parameters
[i
].isTemplateTypeParameter();
2153 if (e
== emptyArrayElement
)
2157 result
= MATCH
.exact
;
2162 tp
.defaultType
.accept(this);
2167 /* Returns `true` if `t` is a reference type, or an array of reference types
2169 bool isTopRef(Type t
)
2171 auto tb
= t
.baseElemOf();
2172 return tb
.ty
== Tclass ||
2174 tb
.ty
== Tstruct
&& tb
.hasPointers();
2177 Type at
= cast(Type
)dedtypes
[i
];
2179 if (ubyte wx
= deduceWildHelper(e
.type
, &tt
, tparam
))
2182 result
= MATCH
.constant
;
2184 else if (MATCH m
= deduceTypeHelper(e
.type
, tt
, tparam
))
2188 else if (!isTopRef(e
.type
))
2190 /* https://issues.dlang.org/show_bug.cgi?id=15653
2191 * In IFTI, recognize top-qualifier conversions
2192 * through the value copy, e.g.
2193 * int --> immutable(int)
2194 * immutable(string[]) --> immutable(string)[]
2196 tt
= e
.type
.mutableOf();
2197 result
= MATCH
.convert
;
2202 // expression vs (none)
2205 dedtypes
[i
] = new TypeDeduced(tt
, e
, tparam
);
2209 TypeDeduced xt
= null;
2212 xt
= cast(TypeDeduced
)at
;
2216 // From previous matched expressions to current deduced type
2217 MATCH match1
= xt ? xt
.matchAll(tt
) : MATCH
.nomatch
;
2219 // From current expressions to previous deduced type
2220 Type pt
= at
.addMod(tparam
.mod
);
2222 pt
= pt
.substWildTo(*wm
);
2223 MATCH match2
= e
.implicitConvTo(pt
);
2225 if (match1
> MATCH
.nomatch
&& match2
> MATCH
.nomatch
)
2227 if (at
.implicitConvTo(tt
) == MATCH
.nomatch
)
2228 match1
= MATCH
.nomatch
; // Prefer at
2229 else if (tt
.implicitConvTo(at
) == MATCH
.nomatch
)
2230 match2
= MATCH
.nomatch
; // Prefer tt
2231 else if (tt
.isTypeBasic() && tt
.ty
== at
.ty
&& tt
.mod
!= at
.mod
)
2233 if (!tt
.isMutable() && !at
.isMutable())
2234 tt
= tt
.mutableOf().addMod(MODmerge(tt
.mod
, at
.mod
));
2235 else if (tt
.isMutable())
2237 if (at
.mod
== 0) // Prefer unshared
2238 match1
= MATCH
.nomatch
;
2240 match2
= MATCH
.nomatch
;
2242 else if (at
.isMutable())
2244 if (tt
.mod
== 0) // Prefer unshared
2245 match2
= MATCH
.nomatch
;
2247 match1
= MATCH
.nomatch
;
2249 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
2253 match1
= MATCH
.nomatch
;
2254 match2
= MATCH
.nomatch
;
2257 if (match1
> MATCH
.nomatch
)
2259 // Prefer current match: tt
2261 xt
.update(tt
, e
, tparam
);
2267 if (match2
> MATCH
.nomatch
)
2269 // Prefer previous match: (*dedtypes)[i]
2271 xt
.update(e
, tparam
);
2276 /* Deduce common type
2278 if (Type t
= rawTypeMerge(at
, tt
))
2281 xt
.update(t
, e
, tparam
);
2285 pt
= tt
.addMod(tparam
.mod
);
2287 pt
= pt
.substWildTo(*wm
);
2288 result
= e
.implicitConvTo(pt
);
2292 result
= MATCH
.nomatch
;
2295 MATCH
deduceEmptyArrayElement()
2297 if (!emptyArrayElement
)
2299 emptyArrayElement
= new IdentifierExp(Loc
.initial
, Id
.p
); // dummy
2300 emptyArrayElement
.type
= Type
.tvoid
;
2302 assert(tparam
.ty
== Tarray
);
2304 Type tn
= (cast(TypeNext
)tparam
).next
;
2305 return deduceType(emptyArrayElement
, sc
, tn
, parameters
, dedtypes
, wm
);
2308 override void visit(NullExp e
)
2310 if (tparam
.ty
== Tarray
&& e
.type
.ty
== Tnull
)
2312 // tparam:T[] <- e:null (void[])
2313 result
= deduceEmptyArrayElement();
2316 visit(cast(Expression
)e
);
2319 override void visit(StringExp e
)
2322 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
2324 // Consider compile-time known boundaries
2325 e
.type
.nextOf().sarrayOf(e
.len
).accept(this);
2328 visit(cast(Expression
)e
);
2331 override void visit(ArrayLiteralExp e
)
2333 // https://issues.dlang.org/show_bug.cgi?id=20092
2334 if (e
.elements
&& e
.elements
.length
&& e
.type
.toBasetype().nextOf().ty
== Tvoid
)
2336 result
= deduceEmptyArrayElement();
2339 if ((!e
.elements ||
!e
.elements
.length
) && e
.type
.toBasetype().nextOf().ty
== Tvoid
&& tparam
.ty
== Tarray
)
2341 // tparam:T[] <- e:[] (void[])
2342 result
= deduceEmptyArrayElement();
2346 if (tparam
.ty
== Tarray
&& e
.elements
&& e
.elements
.length
)
2348 Type tn
= (cast(TypeDArray
)tparam
).next
;
2349 result
= MATCH
.exact
;
2352 MATCH m
= deduceType(e
.basis
, sc
, tn
, parameters
, dedtypes
, wm
);
2356 foreach (el
; *e
.elements
)
2358 if (result
== MATCH
.nomatch
)
2362 MATCH m
= deduceType(el
, sc
, tn
, parameters
, dedtypes
, wm
);
2370 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
2372 // Consider compile-time known boundaries
2373 e
.type
.nextOf().sarrayOf(e
.elements
.length
).accept(this);
2376 visit(cast(Expression
)e
);
2379 override void visit(AssocArrayLiteralExp e
)
2381 if (tparam
.ty
== Taarray
&& e
.keys
&& e
.keys
.length
)
2383 TypeAArray taa
= cast(TypeAArray
)tparam
;
2384 result
= MATCH
.exact
;
2385 foreach (i
, key
; *e
.keys
)
2387 MATCH m1
= deduceType(key
, sc
, taa
.index
, parameters
, dedtypes
, wm
);
2390 if (result
== MATCH
.nomatch
)
2392 MATCH m2
= deduceType((*e
.values
)[i
], sc
, taa
.next
, parameters
, dedtypes
, wm
);
2395 if (result
== MATCH
.nomatch
)
2400 visit(cast(Expression
)e
);
2403 override void visit(FuncExp e
)
2405 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
2411 auto tof
= to
.nextOf().isTypeFunction();
2415 // Parameter types inference from 'tof'
2416 assert(e
.td
._scope
);
2417 TypeFunction tf
= e
.fd
.type
.isTypeFunction();
2418 //printf("\ttof = %s\n", tof.toChars());
2419 //printf("\ttf = %s\n", tf.toChars());
2420 const dim
= tf
.parameterList
.length
;
2422 if (tof
.parameterList
.length
!= dim || tof
.parameterList
.varargs
!= tf
.parameterList
.varargs
)
2425 auto tiargs
= new Objects();
2426 tiargs
.reserve(e
.td
.parameters
.length
);
2428 foreach (tp
; *e
.td
.parameters
)
2431 foreach (i
, p
; tf
.parameterList
)
2433 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
2438 Parameter pto
= tof
.parameterList
[u
];
2441 Type t
= pto
.type
.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
2442 if (reliesOnTemplateParameters(t
, parameters
[inferStart
.. parameters
.length
]))
2444 t
= t
.typeSemantic(e
.loc
, sc
);
2450 // Set target of return type inference
2451 if (!tf
.next
&& tof
.next
)
2454 auto ti
= new TemplateInstance(e
.loc
, e
.td
, tiargs
);
2455 Expression ex
= (new ScopeExp(e
.loc
, ti
)).expressionSemantic(e
.td
._scope
);
2457 // Reset inference target for the later re-semantic
2460 if (ex
.op
== EXP
.error
)
2462 if (ex
.op
!= EXP
.function_
)
2470 if (t
.ty
== Tdelegate
&& tparam
.ty
== Tpointer
)
2473 // Allow conversion from implicit function pointer to delegate
2474 if (e
.tok
== TOK
.reserved
&& t
.ty
== Tpointer
&& tparam
.ty
== Tdelegate
)
2476 TypeFunction tf
= t
.nextOf().isTypeFunction();
2477 t
= (new TypeDelegate(tf
)).merge();
2479 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
2483 override void visit(SliceExp e
)
2486 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
2488 // Consider compile-time known boundaries
2489 if (Type tsa
= toStaticArrayType(e
))
2492 if (result
> MATCH
.convert
)
2493 result
= MATCH
.convert
; // match with implicit conversion at most
2497 visit(cast(Expression
)e
);
2500 override void visit(CommaExp e
)
2506 scope DeduceType v
= new DeduceType();
2507 if (Type t
= isType(o
))
2509 else if (Expression e
= isExpression(o
))
2520 /* Helper for TypeClass.deduceType().
2521 * Classes can match with implicit conversion to a base class or interface.
2522 * This is complicated, because there may be more than one base class which
2523 * matches. In such cases, one or more parameters remain ambiguous.
2526 * interface I(X, Y) {}
2527 * class C : I(uint, double), I(char, double) {}
2529 * foo(T, U)( I!(T, U) x)
2531 * deduces that U is double, but T remains ambiguous (could be char or uint).
2533 * Given a baseclass b, and initial deduced types 'dedtypes', this function
2534 * tries to match tparam with b, and also tries all base interfaces of b.
2535 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
2536 * types are ANDed with the current 'best' estimate for dedtypes.
2538 private void deduceBaseClassParameters(ref BaseClass b
, Scope
* sc
, Type tparam
, ref TemplateParameters parameters
, ref Objects dedtypes
, ref Objects best
, ref int numBaseClassMatches
)
2540 TemplateInstance parti
= b
.sym ? b
.sym
.parent
.isTemplateInstance() : null;
2543 // Make a temporary copy of dedtypes so we don't destroy it
2544 auto tmpdedtypes
= new Objects(dedtypes
.length
);
2545 memcpy(tmpdedtypes
.tdata(), dedtypes
.tdata(), dedtypes
.length
* (void*).sizeof
);
2547 auto t
= new TypeInstance(Loc
.initial
, parti
);
2548 MATCH m
= deduceType(t
, sc
, tparam
, parameters
, *tmpdedtypes
);
2549 if (m
> MATCH
.nomatch
)
2551 // If this is the first ever match, it becomes our best estimate
2552 if (numBaseClassMatches
== 0)
2553 memcpy(best
.tdata(), tmpdedtypes
.tdata(), tmpdedtypes
.length
* (void*).sizeof
);
2555 for (size_t k
= 0; k
< tmpdedtypes
.length
; ++k
)
2557 // If we've found more than one possible type for a parameter,
2558 // mark it as unknown.
2559 if ((*tmpdedtypes
)[k
] != best
[k
])
2560 best
[k
] = dedtypes
[k
];
2562 ++numBaseClassMatches
;
2566 // Now recursively test the inherited interfaces
2567 foreach (ref bi
; b
.baseInterfaces
)
2569 deduceBaseClassParameters(bi
, sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
2573 /********************
2574 * Match template `parameters` to the target template instance.
2576 * struct Temp(U, int Z) {}
2577 * void foo(T)(Temp!(T, 3));
2578 * foo(Temp!(int, 3)());
2581 * parameters = template params of foo -> [T]
2582 * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3]
2583 * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3]
2584 * tempdecl = <struct Temp!(T, int Z)> -> [T, Z]
2585 * tp = <Temp!(T, 3)>
2587 * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int]
2589 private bool resolveTemplateInstantiation(Scope
* sc
, TemplateParameters
* parameters
, Objects
* tiargs
, Objects
* tdtypes
, TemplateDeclaration tempdecl
, TypeInstance tp
, Objects
* dedtypes
)
2591 for (size_t i
= 0; 1; i
++)
2593 //printf("\ttest: tempinst.tiargs[%zu]\n", i);
2594 RootObject o1
= null;
2595 if (i
< tiargs
.length
)
2597 else if (i
< tdtypes
.length
&& i
< tp
.tempinst
.tiargs
.length
)
2599 // Pick up default arg
2602 else if (i
>= tp
.tempinst
.tiargs
.length
)
2604 //printf("\ttest: o1 = %s\n", o1.toChars());
2605 if (i
>= tp
.tempinst
.tiargs
.length
)
2607 size_t dim
= tempdecl
.parameters
.length
- (tempdecl
.isVariadic() ?
1 : 0);
2608 while (i
< dim
&& ((*tempdecl
.parameters
)[i
].dependent ||
(*tempdecl
.parameters
)[i
].hasDefaultArg()))
2613 break; // match if all remained parameters are dependent
2617 RootObject o2
= (*tp
.tempinst
.tiargs
)[i
];
2618 Type t2
= isType(o2
);
2619 //printf("\ttest: o2 = %s\n", o2.toChars());
2620 size_t j
= (t2
&& t2
.ty
== Tident
&& i
== tp
.tempinst
.tiargs
.length
- 1)
2621 ?
templateParameterLookup(t2
, parameters
) : IDX_NOTFOUND
;
2622 if (j
!= IDX_NOTFOUND
&& j
== parameters
.length
- 1 &&
2623 (*parameters
)[j
].isTemplateTupleParameter())
2627 * alias A!(int, float) X;
2628 * static if (is(X Y == A!(Z), Z...)) {}
2629 * deduce that Z is a tuple(int, float)
2632 /* Create tuple from remaining args
2634 size_t vtdim
= (tempdecl
.isVariadic() ? tiargs
.length
: tdtypes
.length
) - i
;
2635 auto vt
= new Tuple(vtdim
);
2636 for (size_t k
= 0; k
< vtdim
; k
++)
2639 if (k
< tiargs
.length
)
2640 o
= (*tiargs
)[i
+ k
];
2641 else // Pick up default arg
2642 o
= (*tdtypes
)[i
+ k
];
2646 Tuple v
= cast(Tuple
)(*dedtypes
)[j
];
2653 (*dedtypes
)[j
] = vt
;
2659 Type t1
= isType(o1
);
2660 Dsymbol s1
= isDsymbol(o1
);
2661 Dsymbol s2
= isDsymbol(o2
);
2662 Expression e1
= s1 ?
getValue(s1
) : getValue(isExpression(o1
));
2663 Expression e2
= isExpression(o2
);
2666 Tuple v1
= isTuple(o1
);
2667 Tuple v2
= isTuple(o2
);
2669 printf("t1 = %s\n", t1
.toChars());
2671 printf("t2 = %s\n", t2
.toChars());
2673 printf("e1 = %s\n", e1
.toChars());
2675 printf("e2 = %s\n", e2
.toChars());
2677 printf("s1 = %s\n", s1
.toChars());
2679 printf("s2 = %s\n", s2
.toChars());
2681 printf("v1 = %s\n", v1
.toChars());
2683 printf("v2 = %s\n", v2
.toChars());
2688 if (!deduceType(t1
, sc
, t2
, *parameters
, *dedtypes
))
2694 e1
= e1
.ctfeInterpret();
2696 /* If it is one of the template parameters for this template,
2697 * we should not attempt to interpret it. It already has a value.
2699 if (e2
.op
== EXP
.variable
&& (e2
.isVarExp().var
.storage_class
& STC
.templateparameter
))
2702 * (T:Number!(e2), int e2)
2704 j
= templateIdentifierLookup(e2
.isVarExp().var
.ident
, parameters
);
2705 if (j
!= IDX_NOTFOUND
)
2707 // The template parameter was not from this template
2708 // (it may be from a parent template, for example)
2711 e2
= e2
.expressionSemantic(sc
); // https://issues.dlang.org/show_bug.cgi?id=13417
2712 e2
= e2
.ctfeInterpret();
2714 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
2715 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
2718 if (!e2
.implicitConvTo(e1
.type
))
2721 e2
= e2
.implicitCastTo(sc
, e1
.type
);
2722 e2
= e2
.ctfeInterpret();
2727 else if (e1
&& t2
&& t2
.ty
== Tident
)
2729 j
= templateParameterLookup(t2
, parameters
);
2731 if (j
== IDX_NOTFOUND
)
2733 t2
.resolve((cast(TypeIdentifier
)t2
).loc
, sc
, e2
, t2
, s2
);
2738 if (!(*parameters
)[j
].matchArg(sc
, e1
, j
, parameters
, *dedtypes
, null))
2747 else if (s1
&& t2
&& t2
.ty
== Tident
)
2749 j
= templateParameterLookup(t2
, parameters
);
2750 if (j
== IDX_NOTFOUND
)
2752 t2
.resolve((cast(TypeIdentifier
)t2
).loc
, sc
, e2
, t2
, s2
);
2757 if (!(*parameters
)[j
].matchArg(sc
, s1
, j
, parameters
, *dedtypes
, null))
2767 /***********************************************************
2768 * Check whether the type t representation relies on one or more the template parameters.
2770 * t = Tested type, if null, returns false.
2771 * tparams = Template parameters.
2772 * iStart = Start index of tparams to limit the tested parameters. If it's
2773 * nonzero, tparams[0..iStart] will be excluded from the test target.
2775 bool reliesOnTident(Type t
, TemplateParameters
* tparams
, size_t iStart
= 0)
2777 return reliesOnTemplateParameters(t
, (*tparams
)[0 .. tparams
.length
]);
2780 /***********************************************************
2781 * Check whether the type t representation relies on one or more the template parameters.
2783 * t = Tested type, if null, returns false.
2784 * tparams = Template parameters.
2786 bool reliesOnTemplateParameters(Type t
, TemplateParameter
[] tparams
)
2788 bool visitVector(TypeVector t
)
2790 return t
.basetype
.reliesOnTemplateParameters(tparams
);
2793 bool visitAArray(TypeAArray t
)
2795 return t
.next
.reliesOnTemplateParameters(tparams
) ||
2796 t
.index
.reliesOnTemplateParameters(tparams
);
2799 bool visitFunction(TypeFunction t
)
2801 foreach (i
, fparam
; t
.parameterList
)
2803 if (fparam
.type
.reliesOnTemplateParameters(tparams
))
2806 return t
.next
.reliesOnTemplateParameters(tparams
);
2809 bool visitIdentifier(TypeIdentifier t
)
2811 foreach (tp
; tparams
)
2813 if (tp
.ident
.equals(t
.ident
))
2819 bool visitInstance(TypeInstance t
)
2821 foreach (tp
; tparams
)
2823 if (t
.tempinst
.name
== tp
.ident
)
2827 if (t
.tempinst
.tiargs
)
2828 foreach (arg
; *t
.tempinst
.tiargs
)
2830 if (Type ta
= isType(arg
))
2832 if (ta
.reliesOnTemplateParameters(tparams
))
2840 bool visitTypeof(TypeTypeof t
)
2842 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
2843 return t
.exp
.reliesOnTemplateParameters(tparams
);
2846 bool visitTuple(TypeTuple t
)
2849 foreach (arg
; *t
.arguments
)
2851 if (arg
.type
.reliesOnTemplateParameters(tparams
))
2861 Type tb
= t
.toBasetype();
2864 case Tvector
: return visitVector(tb
.isTypeVector());
2865 case Taarray
: return visitAArray(tb
.isTypeAArray());
2866 case Tfunction
: return visitFunction(tb
.isTypeFunction());
2867 case Tident
: return visitIdentifier(tb
.isTypeIdentifier());
2868 case Tinstance
: return visitInstance(tb
.isTypeInstance());
2869 case Ttypeof
: return visitTypeof(tb
.isTypeTypeof());
2870 case Ttuple
: return visitTuple(tb
.isTypeTuple());
2871 case Tenum
: return false;
2872 default: return tb
.nextOf().reliesOnTemplateParameters(tparams
);
2876 /***********************************************************
2877 * Check whether the expression representation relies on one or more the template parameters.
2879 * e = expression to test
2880 * tparams = Template parameters.
2884 private bool reliesOnTemplateParameters(Expression e
, TemplateParameter
[] tparams
)
2886 extern (C
++) final class ReliesOnTemplateParameters
: Visitor
2888 alias visit
= Visitor
.visit
;
2890 TemplateParameter
[] tparams
;
2893 extern (D
) this(TemplateParameter
[] tparams
) @safe
2895 this.tparams
= tparams
;
2898 override void visit(Expression e
)
2900 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
2903 override void visit(IdentifierExp e
)
2905 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2906 foreach (tp
; tparams
)
2908 if (e
.ident
== tp
.ident
)
2916 override void visit(TupleExp e
)
2918 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2921 foreach (ea
; *e
.exps
)
2930 override void visit(ArrayLiteralExp e
)
2932 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2935 foreach (el
; *e
.elements
)
2944 override void visit(AssocArrayLiteralExp e
)
2946 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2947 foreach (ek
; *e
.keys
)
2953 foreach (ev
; *e
.values
)
2961 override void visit(StructLiteralExp e
)
2963 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2966 foreach (ea
; *e
.elements
)
2975 override void visit(TypeExp e
)
2977 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2978 result
= e
.type
.reliesOnTemplateParameters(tparams
);
2981 override void visit(NewExp e
)
2983 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
2985 e
.thisexp
.accept(this);
2986 result
= e
.newtype
.reliesOnTemplateParameters(tparams
);
2987 if (!result
&& e
.arguments
)
2989 foreach (ea
; *e
.arguments
)
2998 override void visit(NewAnonClassExp e
)
3000 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3004 override void visit(FuncExp e
)
3006 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3010 override void visit(TypeidExp e
)
3012 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3013 if (auto ea
= isExpression(e
.obj
))
3015 else if (auto ta
= isType(e
.obj
))
3016 result
= ta
.reliesOnTemplateParameters(tparams
);
3019 override void visit(TraitsExp e
)
3021 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3024 foreach (oa
; *e
.args
)
3026 if (auto ea
= isExpression(oa
))
3028 else if (auto ta
= isType(oa
))
3029 result
= ta
.reliesOnTemplateParameters(tparams
);
3036 override void visit(IsExp e
)
3038 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3039 result
= e
.targ
.reliesOnTemplateParameters(tparams
);
3042 override void visit(UnaExp e
)
3044 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3048 override void visit(DotTemplateInstanceExp e
)
3050 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3051 visit(e
.isUnaExp());
3052 if (!result
&& e
.ti
.tiargs
)
3054 foreach (oa
; *e
.ti
.tiargs
)
3056 if (auto ea
= isExpression(oa
))
3058 else if (auto ta
= isType(oa
))
3059 result
= ta
.reliesOnTemplateParameters(tparams
);
3066 override void visit(CallExp e
)
3068 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3069 visit(e
.isUnaExp());
3070 if (!result
&& e
.arguments
)
3072 foreach (ea
; *e
.arguments
)
3081 override void visit(CastExp e
)
3083 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3084 visit(e
.isUnaExp());
3085 // e.to can be null for cast() with no type
3086 if (!result
&& e
.to
)
3087 result
= e
.to
.reliesOnTemplateParameters(tparams
);
3090 override void visit(SliceExp e
)
3092 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3093 visit(e
.isUnaExp());
3094 if (!result
&& e
.lwr
)
3096 if (!result
&& e
.upr
)
3100 override void visit(IntervalExp e
)
3102 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3108 override void visit(ArrayExp e
)
3110 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3111 visit(e
.isUnaExp());
3112 if (!result
&& e
.arguments
)
3114 foreach (ea
; *e
.arguments
)
3119 override void visit(BinExp e
)
3121 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3127 override void visit(CondExp e
)
3129 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
3130 e
.econd
.accept(this);
3132 visit(e
.isBinExp());
3136 scope ReliesOnTemplateParameters v
= new ReliesOnTemplateParameters(tparams
);
3141 /***********************************************************
3142 * https://dlang.org/spec/template.html#TemplateParameter
3144 extern (C
++) class TemplateParameter
: ASTNode
3149 /* True if this is a part of precedent parameter specialization pattern.
3151 * template A(T : X!TL, alias X, TL...) {}
3152 * // X and TL are dependent template parameter
3154 * A dependent template parameter should return MATCH.exact in matchArg()
3155 * to respect the match level of the corresponding precedent parameter.
3159 /* ======================== TemplateParameter =============================== */
3160 extern (D
) this(const ref Loc loc
, Identifier ident
) @safe
3166 TemplateTypeParameter
isTemplateTypeParameter()
3171 TemplateValueParameter
isTemplateValueParameter()
3176 TemplateAliasParameter
isTemplateAliasParameter()
3181 TemplateThisParameter
isTemplateThisParameter()
3186 TemplateTupleParameter
isTemplateTupleParameter()
3191 abstract TemplateParameter
syntaxCopy();
3193 abstract bool declareParameter(Scope
* sc
);
3195 abstract void print(RootObject oarg
, RootObject oded
);
3197 abstract RootObject
specialization();
3199 abstract RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
);
3201 abstract bool hasDefaultArg();
3203 override const(char)* toChars() const
3205 return this.ident
.toChars();
3208 override DYNCAST
dyncast() const
3210 return DYNCAST
.templateparameter
;
3213 /* Create dummy argument based on parameter.
3215 abstract RootObject
dummyArg();
3217 override void accept(Visitor v
)
3223 /***********************************************************
3224 * https://dlang.org/spec/template.html#TemplateTypeParameter
3226 * ident : specType = defaultType
3228 extern (C
++) class TemplateTypeParameter
: TemplateParameter
3230 Type specType
; // if !=null, this is the type specialization
3233 extern (D
) __gshared Type tdummy
= null;
3235 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, Type defaultType
) @safe
3238 this.specType
= specType
;
3239 this.defaultType
= defaultType
;
3242 override final TemplateTypeParameter
isTemplateTypeParameter()
3247 override TemplateTypeParameter
syntaxCopy()
3249 return new TemplateTypeParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, defaultType ? defaultType
.syntaxCopy() : null);
3252 override final bool declareParameter(Scope
* sc
)
3254 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
3255 auto ti
= new TypeIdentifier(loc
, ident
);
3256 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
3257 return sc
.insert(ad
) !is null;
3260 override final void print(RootObject oarg
, RootObject oded
)
3262 printf(" %s\n", ident
.toChars());
3264 Type t
= isType(oarg
);
3265 Type ta
= isType(oded
);
3269 printf("\tSpecialization: %s\n", specType
.toChars());
3271 printf("\tDefault: %s\n", defaultType
.toChars());
3272 printf("\tParameter: %s\n", t ? t
.toChars() : "NULL");
3273 printf("\tDeduced Type: %s\n", ta
.toChars());
3276 override final RootObject
specialization()
3281 override final RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
3283 Type t
= defaultType
;
3287 t
= t
.typeSemantic(loc
, sc
); // use the parameter loc
3292 override final bool hasDefaultArg()
3294 return defaultType
!is null;
3297 override final RootObject
dummyArg()
3302 // Use this for alias-parameter's too (?)
3304 tdummy
= new TypeIdentifier(loc
, ident
);
3310 override void accept(Visitor v
)
3316 /***********************************************************
3317 * https://dlang.org/spec/template.html#TemplateThisParameter
3319 * this ident : specType = defaultType
3321 extern (C
++) final class TemplateThisParameter
: TemplateTypeParameter
3323 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, Type defaultType
) @safe
3325 super(loc
, ident
, specType
, defaultType
);
3328 override TemplateThisParameter
isTemplateThisParameter()
3333 override TemplateThisParameter
syntaxCopy()
3335 return new TemplateThisParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, defaultType ? defaultType
.syntaxCopy() : null);
3338 override void accept(Visitor v
)
3344 /***********************************************************
3345 * https://dlang.org/spec/template.html#TemplateValueParameter
3347 * valType ident : specValue = defaultValue
3349 extern (C
++) final class TemplateValueParameter
: TemplateParameter
3352 Expression specValue
;
3353 Expression defaultValue
;
3355 extern (D
) __gshared Expression
[void*] edummies
;
3357 extern (D
) this(const ref Loc loc
, Identifier ident
, Type valType
,
3358 Expression specValue
, Expression defaultValue
) @safe
3361 this.valType
= valType
;
3362 this.specValue
= specValue
;
3363 this.defaultValue
= defaultValue
;
3366 override TemplateValueParameter
isTemplateValueParameter()
3371 override TemplateValueParameter
syntaxCopy()
3373 return new TemplateValueParameter(loc
, ident
,
3374 valType
.syntaxCopy(),
3375 specValue ? specValue
.syntaxCopy() : null,
3376 defaultValue ? defaultValue
.syntaxCopy() : null);
3379 override bool declareParameter(Scope
* sc
)
3382 Do type semantic earlier.
3384 This means for certain erroneous value parameters
3385 their "type" can be known earlier and thus a better
3386 error message given.
3389 `template test(x* x) {}`
3390 now yields "undefined identifier" rather than the opaque
3391 "variable `x` is used as a type".
3394 valType
= valType
.typeSemantic(loc
, sc
);
3395 auto v
= new VarDeclaration(loc
, valType
, ident
, null);
3396 v
.storage_class
= STC
.templateparameter
;
3397 return sc
.insert(v
) !is null;
3400 override void print(RootObject oarg
, RootObject oded
)
3402 printf(" %s\n", ident
.toChars());
3403 Expression ea
= isExpression(oded
);
3405 printf("\tSpecialization: %s\n", specValue
.toChars());
3406 printf("\tParameter Value: %s\n", ea ? ea
.toChars() : "NULL");
3409 override RootObject
specialization()
3414 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
3416 Expression e
= defaultValue
;
3420 Scope
* sc2
= sc
.push();
3421 sc2
.inDefaultArg
= true;
3422 e
= e
.expressionSemantic(sc2
);
3426 if (auto te
= e
.isTemplateExp())
3428 assert(sc
&& sc
.tinst
);
3429 if (te
.td
== sc
.tinst
.tempdecl
)
3431 // defaultValue is a reference to its template declaration
3432 // i.e: `template T(int arg = T)`
3433 // Raise error now before calling resolveProperties otherwise we'll
3434 // start looping on the expansion of the template instance.
3435 auto td
= sc
.tinst
.tempdecl
;
3436 .error(td
.loc
, "%s `%s` recursive template expansion", td
.kind
, td
.toPrettyChars
);
3437 return ErrorExp
.get();
3440 if ((e
= resolveProperties(sc
, e
)) is null)
3442 e
= e
.resolveLoc(instLoc
, sc
); // use the instantiated loc
3443 e
= e
.optimize(WANTvalue
);
3448 override bool hasDefaultArg()
3450 return defaultValue
!is null;
3453 override RootObject
dummyArg()
3455 Expression e
= specValue
;
3458 // Create a dummy value
3459 auto pe
= cast(void*)valType
in edummies
;
3462 e
= valType
.defaultInit(Loc
.initial
);
3463 edummies
[cast(void*)valType
] = e
;
3471 override void accept(Visitor v
)
3477 /***********************************************************
3478 * https://dlang.org/spec/template.html#TemplateAliasParameter
3480 * specType ident : specAlias = defaultAlias
3482 extern (C
++) final class TemplateAliasParameter
: TemplateParameter
3485 RootObject specAlias
;
3486 RootObject defaultAlias
;
3488 extern (D
) __gshared Dsymbol sdummy
= null;
3490 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, RootObject specAlias
, RootObject defaultAlias
) @safe
3493 this.specType
= specType
;
3494 this.specAlias
= specAlias
;
3495 this.defaultAlias
= defaultAlias
;
3498 override TemplateAliasParameter
isTemplateAliasParameter()
3503 override TemplateAliasParameter
syntaxCopy()
3505 return new TemplateAliasParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, objectSyntaxCopy(specAlias
), objectSyntaxCopy(defaultAlias
));
3508 override bool declareParameter(Scope
* sc
)
3510 auto ti
= new TypeIdentifier(loc
, ident
);
3511 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
3512 return sc
.insert(ad
) !is null;
3515 override void print(RootObject oarg
, RootObject oded
)
3517 printf(" %s\n", ident
.toChars());
3518 Dsymbol sa
= isDsymbol(oded
);
3520 printf("\tParameter alias: %s\n", sa
.toChars());
3523 override RootObject
specialization()
3528 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
3530 RootObject
da = defaultAlias
;
3531 if (auto ta
= isType(defaultAlias
))
3535 // If the default arg is a template, instantiate for each type
3537 // same if the default arg is a mixin, traits, typeof
3538 // since the content might rely on a previous parameter
3539 // (https://issues.dlang.org/show_bug.cgi?id=23686)
3540 case Tmixin
, Ttypeof
, Ttraits
:
3541 da = ta
.syntaxCopy();
3547 RootObject o
= aliasParameterSemantic(loc
, sc
, da, null); // use the parameter loc
3551 override bool hasDefaultArg()
3553 return defaultAlias
!is null;
3556 override RootObject
dummyArg()
3558 RootObject s
= specAlias
;
3562 sdummy
= new Dsymbol();
3568 override void accept(Visitor v
)
3574 /***********************************************************
3575 * https://dlang.org/spec/template.html#TemplateSequenceParameter
3579 extern (C
++) final class TemplateTupleParameter
: TemplateParameter
3581 extern (D
) this(const ref Loc loc
, Identifier ident
) @safe
3586 override TemplateTupleParameter
isTemplateTupleParameter()
3591 override TemplateTupleParameter
syntaxCopy()
3593 return new TemplateTupleParameter(loc
, ident
);
3596 override bool declareParameter(Scope
* sc
)
3598 auto ti
= new TypeIdentifier(loc
, ident
);
3599 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
3600 return sc
.insert(ad
) !is null;
3603 override void print(RootObject oarg
, RootObject oded
)
3605 printf(" %s... [", ident
.toChars());
3606 Tuple v
= isTuple(oded
);
3609 //printf("|%d| ", v.objects.length);
3610 foreach (i
, o
; v
.objects
)
3615 Dsymbol sa
= isDsymbol(o
);
3617 printf("alias: %s", sa
.toChars());
3618 Type ta
= isType(o
);
3620 printf("type: %s", ta
.toChars());
3621 Expression ea
= isExpression(o
);
3623 printf("exp: %s", ea
.toChars());
3625 assert(!isTuple(o
)); // no nested Tuple arguments
3630 override RootObject
specialization()
3635 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
3640 override bool hasDefaultArg()
3645 override RootObject
dummyArg()
3650 override void accept(Visitor v
)
3656 /***********************************************************
3657 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
3663 extern (C
++) class TemplateInstance
: ScopeDsymbol
3667 // Array of Types/Expressions of template
3668 // instance arguments [int*, char, 10*10]
3671 // Array of Types/Expressions corresponding
3672 // to TemplateDeclaration.parameters
3676 // Modules imported by this template instance
3677 Modules importedModules
;
3679 Dsymbol tempdecl
; // referenced by foo.bar.abc
3680 Dsymbol enclosing
; // if referencing local symbols, this is the context
3681 Dsymbol aliasdecl
; // !=null if instance is an alias for its sole member
3682 TemplateInstance inst
; // refer to existing instance
3683 ScopeDsymbol argsym
; // argument symbol table
3684 size_t hash
; // cached result of toHash()
3686 /// For function template, these are the function names and arguments
3687 /// Relevant because different resolutions of `auto ref` parameters
3688 /// create different template instances even with the same template arguments
3690 Identifiers
* fnames
;
3692 TemplateInstances
* deferred
;
3694 Module memberOf
; // if !null, then this TemplateInstance appears in memberOf.members[]
3696 // Used to determine the instance needs code generation.
3697 // Note that these are inaccurate until semantic analysis phase completed.
3698 TemplateInstance tinst
; // enclosing template instance
3699 TemplateInstance tnext
; // non-first instantiated instances
3700 Module minst
; // the top module that instantiated this instance
3702 private ushort _nest
; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
3703 ubyte inuse
; // for recursive expansion detection
3705 private enum Flag
: uint
3707 semantictiargsdone
= 1u << (_nest
.sizeof
* 8 - 1), // MSB of _nest
3708 havetempdecl
= semantictiargsdone
>> 1,
3709 gagged
= semantictiargsdone
>> 2,
3710 available
= gagged
- 1 // always last flag minus one, 1s for all available bits
3713 extern(D
) final @safe @property pure nothrow @nogc
3715 ushort nest() const { return _nest
& Flag
.available
; }
3716 void nestUp() { assert(nest() < Flag
.available
); ++_nest
; }
3717 void nestDown() { assert(nest() > 0); --_nest
; }
3718 /// has semanticTiargs() been done?
3719 bool semantictiargsdone() const { return (_nest
& Flag
.semantictiargsdone
) != 0; }
3720 void semantictiargsdone(bool x
)
3722 if (x
) _nest |
= Flag
.semantictiargsdone
;
3723 else _nest
&= ~Flag
.semantictiargsdone
;
3725 /// if used second constructor
3726 bool havetempdecl() const { return (_nest
& Flag
.havetempdecl
) != 0; }
3727 void havetempdecl(bool x
)
3729 if (x
) _nest |
= Flag
.havetempdecl
;
3730 else _nest
&= ~Flag
.havetempdecl
;
3732 /// if the instantiation is done with error gagging
3733 bool gagged() const { return (_nest
& Flag
.gagged
) != 0; }
3736 if (x
) _nest |
= Flag
.gagged
;
3737 else _nest
&= ~Flag
.gagged
;
3741 extern (D
) this(const ref Loc loc
, Identifier ident
, Objects
* tiargs
) scope
3746 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident
.toChars() : "null");
3749 this.tiargs
= tiargs
;
3753 * This constructor is only called when we figured out which function
3754 * template to instantiate.
3756 extern (D
) this(const ref Loc loc
, TemplateDeclaration td
, Objects
* tiargs
) scope
3761 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td
.toChars());
3763 this.name
= td
.ident
;
3764 this.tiargs
= tiargs
;
3766 this.semantictiargsdone
= true;
3767 this.havetempdecl
= true;
3768 assert(tempdecl
._scope
);
3771 extern (D
) static Objects
* arraySyntaxCopy(Objects
* objs
)
3776 a
= new Objects(objs
.length
);
3777 foreach (i
, o
; *objs
)
3778 (*a
)[i
] = objectSyntaxCopy(o
);
3783 override TemplateInstance
syntaxCopy(Dsymbol s
)
3785 TemplateInstance ti
= s ?
cast(TemplateInstance
)s
: new TemplateInstance(loc
, name
, null);
3786 ti
.tiargs
= arraySyntaxCopy(tiargs
);
3787 TemplateDeclaration td
;
3788 if (inst
&& tempdecl
&& (td
= tempdecl
.isTemplateDeclaration()) !is null)
3789 td
.ScopeDsymbol
.syntaxCopy(ti
);
3791 ScopeDsymbol
.syntaxCopy(ti
);
3795 // resolve real symbol
3796 override final Dsymbol
toAlias()
3800 printf("TemplateInstance.toAlias()\n");
3804 // Maybe we can resolve it
3807 dsymbolSemantic(this, _scope
);
3811 .error(loc
, "%s `%s` cannot resolve forward reference", kind
, toPrettyChars
);
3818 return inst
.toAlias();
3822 return aliasdecl
.toAlias();
3828 override const(char)* kind() const
3830 return "template instance";
3833 override bool oneMember(out Dsymbol ps
, Identifier ident
)
3839 override const(char)* toChars() const
3842 toCBufferInstance(this, buf
);
3843 return buf
.extractChars();
3846 override final const(char)* toPrettyCharsHelper()
3849 toCBufferInstance(this, buf
, true);
3850 return buf
.extractChars();
3853 /**************************************
3854 * Given an error instantiating the TemplateInstance,
3855 * give the nested TemplateInstance instantiations that got
3856 * us here. Those are a list threaded into the nested scopes.
3858 * cl = classification of this trace as printing either errors or deprecations
3859 * max_shown = maximum number of trace elements printed (controlled with -v/-verror-limit)
3861 extern(D
) final void printInstantiationTrace(Classification cl
= Classification
.error
,
3862 const(uint) max_shown
= global
.params
.v
.errorSupplementCount())
3867 // Print full trace for verbose mode, otherwise only short traces
3868 const(char)* format
= "instantiated from here: `%s`";
3870 // This returns a function pointer
3871 scope printFn
= () {
3874 case Classification
.error
:
3875 return &errorSupplemental
;
3876 case Classification
.deprecation
:
3877 return &deprecationSupplemental
;
3878 case Classification
.gagged
, Classification
.tip
, Classification
.warning
:
3883 // determine instantiation depth and number of recursive instantiations
3884 int n_instantiations
= 1;
3885 int n_totalrecursions
= 0;
3886 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
3889 // Set error here as we don't want it to depend on the number of
3890 // entries that are being printed.
3891 if (cl
== Classification
.error ||
3892 (cl
== Classification
.warning
&& global
.params
.warnings
== DiagnosticReporting
.error
) ||
3893 (cl
== Classification
.deprecation
&& global
.params
.useDeprecated
== DiagnosticReporting
.error
))
3896 // If two instantiations use the same declaration, they are recursive.
3897 // (this works even if they are instantiated from different places in the
3899 // In principle, we could also check for multiple-template recursion, but it's
3900 // probably not worthwhile.
3901 if (cur
.tinst
&& cur
.tempdecl
&& cur
.tinst
.tempdecl
&& cur
.tempdecl
.loc
.equals(cur
.tinst
.tempdecl
.loc
))
3902 ++n_totalrecursions
;
3905 if (n_instantiations
<= max_shown
)
3907 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
3908 printFn(cur
.loc
, format
, cur
.toChars());
3910 else if (n_instantiations
- n_totalrecursions
<= max_shown
)
3912 // By collapsing recursive instantiations into a single line,
3913 // we can stay under the limit.
3914 int recursionDepth
= 0;
3915 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
3917 if (cur
.tinst
&& cur
.tempdecl
&& cur
.tinst
.tempdecl
&& cur
.tempdecl
.loc
.equals(cur
.tinst
.tempdecl
.loc
))
3924 printFn(cur
.loc
, "%d recursive instantiations from here: `%s`", recursionDepth
+ 2, cur
.toChars());
3926 printFn(cur
.loc
, format
, cur
.toChars());
3933 // Even after collapsing the recursions, the depth is too deep.
3934 // Just display the first few and last few instantiations.
3936 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
3938 if (i
== max_shown
/ 2)
3939 printFn(cur
.loc
, "... (%d instantiations, -v to show) ...", n_instantiations
- max_shown
);
3941 if (i
< max_shown
/ 2 || i
>= n_instantiations
- max_shown
+ max_shown
/ 2)
3942 printFn(cur
.loc
, format
, cur
.toChars());
3948 /*************************************
3949 * Lazily generate identifier for template instance.
3950 * This is because 75% of the ident's are never needed.
3952 override final Identifier
getIdent()
3954 if (!ident
&& inst
&& !errors
)
3955 ident
= genIdent(tiargs
); // need an identifier for name mangling purposes.
3959 /*************************************
3960 * Compare proposed template instantiation with existing template instantiation.
3961 * Note that this is not commutative because of the auto ref check.
3963 * ti = existing template instantiation
3967 final bool equalsx(TemplateInstance ti
)
3969 //printf("this = %p, ti = %p\n", this, ti);
3970 assert(tdtypes
.length
== ti
.tdtypes
.length
);
3972 // Nesting must match
3973 if (enclosing
!= ti
.enclosing
)
3975 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
3978 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
3980 if (!arrayObjectMatch(tdtypes
, ti
.tdtypes
))
3983 /* Template functions may have different instantiations based on
3984 * "auto ref" parameters.
3986 if (auto fd
= ti
.toAlias().isFuncDeclaration())
3990 auto resolvedArgs
= fd
.type
.isTypeFunction().resolveNamedArgs(
3991 ArgumentList(this.fargs
, this.fnames
), null);
3993 // resolvedArgs can be null when there's an error: fail_compilation/fail14669.d
3994 // In that case, equalsx returns true to prevent endless template instantiations
3995 // However, it can also mean the function was explicitly instantiated
3996 // without function arguments: fail_compilation/fail14669
3997 // Hence the following check:
3998 if (this.fargs
&& !resolvedArgs
)
4001 Expression
[] args
= resolvedArgs ?
(*resolvedArgs
)[] : [];
4003 auto fparameters
= fd
.getParameterList();
4004 size_t nfparams
= fparameters
.length
; // Num function parameters
4005 for (size_t j
= 0; j
< nfparams
; j
++)
4007 Parameter fparam
= fparameters
[j
];
4008 if (fparam
.storageClass
& STC
.autoref
) // if "auto ref"
4010 Expression farg
= (j
< args
.length
) ? args
[j
] : fparam
.defaultArg
;
4011 // resolveNamedArgs strips trailing nulls / default params
4012 // when it doesn't anymore, the ternary can be replaced with:
4013 // assert(j < resolvedArgs.length);
4015 farg
= fparam
.defaultArg
;
4018 if (farg
.isLvalue())
4020 if (!(fparam
.storageClass
& STC
.ref_
))
4021 goto Lnotequals
; // auto ref's don't match
4025 if (fparam
.storageClass
& STC
.ref_
)
4026 goto Lnotequals
; // auto ref's don't match
4038 extern (D
) final size_t
toHash()
4042 hash
= cast(size_t
)cast(void*)enclosing
;
4043 hash
+= arrayObjectHash(tdtypes
);
4050 Returns: true if the instances' innards are discardable.
4052 The idea of this function is to see if the template instantiation
4053 can be 100% replaced with its eponymous member. All other members
4054 can be discarded, even in the compiler to free memory (for example,
4055 the template could be expanded in a region allocator, deemed trivial,
4056 the end result copied back out independently and the entire region freed),
4057 and can be elided entirely from the binary.
4059 The current implementation affects code that generally looks like:
4062 template foo(args...) {
4063 some_basic_type_or_string helper() { .... }
4064 enum foo = helper();
4068 since it was the easiest starting point of implementation but it can and
4069 should be expanded more later.
4071 final bool isDiscardable()
4073 if (aliasdecl
is null)
4076 auto v
= aliasdecl
.isVarDeclaration();
4080 if (!(v
.storage_class
& STC
.manifest
))
4083 // Currently only doing basic types here because it is the easiest proof-of-concept
4084 // implementation with minimal risk of side effects, but it could likely be
4085 // expanded to any type that already exists outside this particular instance.
4086 if (!(v
.type
.equals(Type
.tstring
) ||
(v
.type
.isTypeBasic() !is null)))
4089 // Static ctors and dtors, even in an eponymous enum template, are still run,
4090 // so if any of them are in here, we'd better not assume it is trivial lest
4091 // we break useful code
4092 foreach(member
; *members
)
4094 if(member
.hasStaticCtorOrDtor())
4096 if(member
.isStaticDtorDeclaration())
4098 if(member
.isStaticCtorDeclaration())
4102 // but if it passes through this gauntlet... it should be fine. D code will
4103 // see only the eponymous member, outside stuff can never access it, even through
4104 // reflection; the outside world ought to be none the wiser. Even dmd should be
4105 // able to simply free the memory of everything except the final result.
4111 /***********************************************
4112 * Returns true if this is not instantiated in non-root module, and
4113 * is a part of non-speculative instantiatiation.
4115 * Note: minst does not stabilize until semantic analysis is completed,
4116 * so don't call this function during semantic analysis to return precise result.
4118 final bool needsCodegen()
4120 //printf("needsCodegen() %s\n", toChars());
4122 // minst is finalized after the 1st invocation.
4123 // tnext is only needed for the 1st invocation and
4124 // cleared for further invocations.
4125 TemplateInstance tnext
= this.tnext
;
4126 TemplateInstance tinst
= this.tinst
;
4129 // Don't do codegen if the instance has errors,
4130 // is a dummy instance (see evaluateConstraint),
4131 // or is determined to be discardable.
4132 if (errors || inst
is null || inst
.isDiscardable())
4134 minst
= null; // mark as speculative
4138 // This should only be called on the primary instantiation.
4139 assert(this is inst
);
4141 if (global
.params
.allInst
)
4143 // Do codegen if there is an instantiation from a root module, to maximize link-ability.
4144 static ThreeState
needsCodegenAllInst(TemplateInstance tithis
, TemplateInstance tinst
)
4146 // Do codegen if `this` is instantiated from a root module.
4147 if (tithis
.minst
&& tithis
.minst
.isRoot())
4148 return ThreeState
.yes
;
4150 // Do codegen if the ancestor needs it.
4151 if (tinst
&& tinst
.inst
&& tinst
.inst
.needsCodegen())
4153 tithis
.minst
= tinst
.inst
.minst
; // cache result
4154 assert(tithis
.minst
);
4155 assert(tithis
.minst
.isRoot());
4156 return ThreeState
.yes
;
4158 return ThreeState
.none
;
4161 if (const needsCodegen
= needsCodegenAllInst(this, tinst
))
4162 return needsCodegen
== ThreeState
.yes ?
true : false;
4164 // Do codegen if a sibling needs it.
4165 for (; tnext
; tnext
= tnext
.tnext
)
4167 const needsCodegen
= needsCodegenAllInst(tnext
, tnext
.tinst
);
4168 if (needsCodegen
== ThreeState
.yes
)
4170 minst
= tnext
.minst
; // cache result
4172 assert(minst
.isRoot());
4175 else if (!minst
&& tnext
.minst
)
4177 minst
= tnext
.minst
; // cache result from non-speculative sibling
4178 // continue searching
4180 else if (needsCodegen
!= ThreeState
.none
)
4184 // Elide codegen because there's no instantiation from any root modules.
4189 // Prefer instantiations from non-root modules, to minimize object code size.
4191 /* If a TemplateInstance is ever instantiated from a non-root module,
4192 * we do not have to generate code for it,
4193 * because it will be generated when the non-root module is compiled.
4195 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
4197 * The problem is if A imports B, and B imports A, and both A
4198 * and B instantiate the same template, does the compilation of A
4199 * or the compilation of B do the actual instantiation?
4201 * See https://issues.dlang.org/show_bug.cgi?id=2500.
4203 * => Elide codegen if there is at least one instantiation from a non-root module
4204 * which doesn't import any root modules.
4206 static ThreeState
needsCodegenRootOnly(TemplateInstance tithis
, TemplateInstance tinst
)
4208 // If the ancestor isn't speculative,
4209 // 1. do codegen if the ancestor needs it
4210 // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
4211 if (tinst
&& tinst
.inst
)
4214 const needsCodegen
= tinst
.needsCodegen(); // sets tinst.minst
4215 if (tinst
.minst
) // not speculative
4217 tithis
.minst
= tinst
.minst
; // cache result
4218 return needsCodegen ? ThreeState
.yes
: ThreeState
.no
;
4222 // Elide codegen if `this` doesn't need it.
4223 if (tithis
.minst
&& !tithis
.minst
.isRoot() && !tithis
.minst
.rootImports())
4224 return ThreeState
.no
;
4226 return ThreeState
.none
;
4229 if (const needsCodegen
= needsCodegenRootOnly(this, tinst
))
4230 return needsCodegen
== ThreeState
.yes ?
true : false;
4232 // Elide codegen if a (non-speculative) sibling doesn't need it.
4233 for (; tnext
; tnext
= tnext
.tnext
)
4235 const needsCodegen
= needsCodegenRootOnly(tnext
, tnext
.tinst
); // sets tnext.minst
4236 if (tnext
.minst
) // not speculative
4238 if (needsCodegen
== ThreeState
.no
)
4240 minst
= tnext
.minst
; // cache result
4241 assert(!minst
.isRoot() && !minst
.rootImports());
4246 minst
= tnext
.minst
; // cache result from non-speculative sibling
4247 // continue searching
4249 else if (needsCodegen
!= ThreeState
.none
)
4254 // Unless `this` is still speculative (=> all further siblings speculative too),
4255 // do codegen because we found no guaranteed-codegen'd non-root instantiation.
4256 return minst
!is null;
4260 /**********************************************
4261 * Find template declaration corresponding to template instance.
4264 * false if finding fails.
4266 * This function is reentrant against error occurrence. If returns false,
4267 * any members of this object won't be modified, and repetition call will
4268 * reproduce same error.
4270 extern (D
) final bool findTempDecl(Scope
* sc
, WithScopeSymbol
* pwithsym
)
4278 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
4283 * figure out which TemplateDeclaration foo refers to.
4285 Identifier id
= name
;
4287 Dsymbol s
= sc
.search(loc
, id
, scopesym
);
4290 s
= sc
.search_correct(id
);
4292 .error(loc
, "%s `%s` template `%s` is not defined, did you mean %s?", kind
, toPrettyChars
, id
.toChars(), s
.toChars());
4294 .error(loc
, "%s `%s` template `%s` is not defined", kind
, toPrettyChars
, id
.toChars());
4299 printf("It's an instance of '%s' kind '%s'\n", s
.toChars(), s
.kind());
4301 printf("s.parent = '%s'\n", s
.parent
.toChars());
4304 *pwithsym
= scopesym
.isWithScopeSymbol();
4306 /* We might have found an alias within a template when
4307 * we really want the template.
4309 TemplateInstance ti
;
4310 if (s
.parent
&& (ti
= s
.parent
.isTemplateInstance()) !is null)
4312 if (ti
.tempdecl
&& ti
.tempdecl
.ident
== id
)
4314 /* This is so that one can refer to the enclosing
4315 * template, even if it has the same name as a member
4316 * of the template, if it has a !(arguments)
4318 TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration();
4320 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
4321 td
= td
.overroot
; // then get the start
4326 // The template might originate from a selective import which implies that
4327 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
4328 // This is the last place where we see the deprecated alias because it is
4329 // stripped below, so check if the selective import was deprecated.
4330 // See https://issues.dlang.org/show_bug.cgi?id=20840.
4331 if (s
.isAliasDeclaration())
4332 s
.checkDeprecated(this.loc
, sc
);
4334 if (!updateTempDecl(sc
, s
))
4341 // Look for forward references
4342 auto tovers
= tempdecl
.isOverloadSet();
4343 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
4345 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
4346 int r
= overloadApply(dstart
, (Dsymbol s
)
4348 auto td
= s
.isTemplateDeclaration();
4352 if (td
.semanticRun
== PASS
.initial
)
4356 // Try to fix forward reference. Ungag errors while doing so.
4357 Ungag ungag
= td
.ungagSpeculative();
4358 td
.dsymbolSemantic(td
._scope
);
4360 if (td
.semanticRun
== PASS
.initial
)
4362 .error(loc
, "%s `%s` `%s` forward references template declaration `%s`", kind
, toPrettyChars
,
4363 toChars(), td
.toChars());
4375 /**********************************************
4376 * Confirm s is a valid template, then store it.
4379 * s candidate symbol of template. It may be:
4380 * TemplateDeclaration
4381 * FuncDeclaration with findTemplateDeclRoot() != NULL
4382 * OverloadSet which contains candidates
4384 * true if updating succeeds.
4386 extern (D
) final bool updateTempDecl(Scope
* sc
, Dsymbol s
)
4389 return tempdecl
!is null;
4391 Identifier id
= name
;
4394 /* If an OverloadSet, look for a unique member that is a template declaration
4396 if (OverloadSet os
= s
.isOverloadSet())
4401 if (FuncDeclaration f
= s2
.isFuncDeclaration())
4402 s2
= f
.findTemplateDeclRoot();
4404 s2
= s2
.isTemplateDeclaration();
4417 .error(loc
, "%s `%s` template `%s` is not defined", kind
, toPrettyChars
, id
.toChars());
4422 if (OverDeclaration od
= s
.isOverDeclaration())
4424 tempdecl
= od
; // TODO: more strict check
4428 /* It should be a TemplateDeclaration, not some other symbol
4430 if (FuncDeclaration f
= s
.isFuncDeclaration())
4431 tempdecl
= f
.findTemplateDeclRoot();
4433 tempdecl
= s
.isTemplateDeclaration();
4439 // Error already issued, just return `false`
4440 if (!s
.parent
&& global
.errors
)
4443 if (!s
.parent
&& s
.getType())
4445 Dsymbol s2
= s
.getType().toDsymbol(sc
);
4448 .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());
4451 // because s can be the alias created for a TemplateParameter
4452 const AliasDeclaration ad
= s
.isAliasDeclaration();
4455 if (ad
&& ad
.isAliasedTemplateParameter())
4456 printf("`%s` is an alias created from a template parameter\n", s
.toChars());
4458 if (!ad ||
!ad
.isAliasedTemplateParameter())
4462 TemplateInstance ti
= s
.parent ? s
.parent
.isTemplateInstance() : null;
4464 /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
4466 static bool matchId(TemplateInstance ti
, Identifier id
)
4468 if (ti
.aliasdecl
&& ti
.aliasdecl
.isVarDeclaration())
4469 return ti
.aliasdecl
.isVarDeclaration().ident
== id
;
4470 return ti
.toAlias().ident
== id
;
4473 if (ti
&& (ti
.name
== s
.ident ||
matchId(ti
, s
.ident
)) && ti
.tempdecl
)
4475 /* This is so that one can refer to the enclosing
4476 * template, even if it has the same name as a member
4477 * of the template, if it has a !(arguments)
4479 TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration();
4481 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
4482 td
= td
.overroot
; // then get the start
4488 .error(loc
, "%s `%s` `%s` is not a template declaration, it is a %s", kind
, toPrettyChars
, id
.toChars(), s
.kind());
4493 /**********************************
4494 * Run semantic of tiargs as arguments of template.
4498 * tiargs array of template arguments
4499 * flags 1: replace const variables with their initializers
4500 * 2: don't devolve Parameter to Type
4501 * atd tuple being optimized. If found, it's not expanded here
4502 * but in AliasAssign semantic.
4504 * false if one or more arguments have errors.
4506 extern (D
) static bool semanticTiargs(const ref Loc loc
, Scope
* sc
, Objects
* tiargs
, int flags
, TupleDeclaration atd
= null)
4508 // Run semantic on each argument, place results in tiargs[]
4509 //printf("+TemplateInstance.semanticTiargs()\n");
4514 // The arguments are not treated as part of a default argument,
4515 // because they are evaluated at compile time.
4517 sc
.inDefaultArg
= false;
4519 for (size_t j
= 0; j
< tiargs
.length
; j
++)
4521 RootObject o
= (*tiargs
)[j
];
4522 Type ta
= isType(o
);
4523 Expression ea
= isExpression(o
);
4524 Dsymbol sa
= isDsymbol(o
);
4526 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
4529 //printf("type %s\n", ta.toChars());
4531 // It might really be an Expression or an Alias
4532 ta
.resolve(loc
, sc
, ea
, ta
, sa
, (flags
& 1) != 0);
4539 assert(global
.errors
);
4544 if (TypeTuple tt
= ta
.isTypeTuple())
4547 size_t dim
= tt
.arguments
.length
;
4551 tiargs
.reserve(dim
);
4552 foreach (i
, arg
; *tt
.arguments
)
4554 if (flags
& 2 && (arg
.storageClass
& STC
.parameter
))
4555 tiargs
.insert(j
+ i
, arg
);
4557 tiargs
.insert(j
+ i
, arg
.type
);
4563 if (ta
.ty
== Terror
)
4568 (*tiargs
)[j
] = ta
.merge2();
4573 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
4574 if (flags
& 1) // only used by __traits
4576 ea
= ea
.expressionSemantic(sc
);
4578 // must not interpret the args, excepting template parameters
4579 if (!ea
.isVarExp() ||
(ea
.isVarExp().var
.storage_class
& STC
.templateparameter
))
4581 ea
= ea
.optimize(WANTvalue
);
4586 sc
= sc
.startCTFE();
4587 ea
= ea
.expressionSemantic(sc
);
4590 if (auto varExp
= ea
.isVarExp())
4592 /* If the parameter is a function that is not called
4593 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
4594 * then it is a dsymbol, not the return value of `func()`
4596 Declaration vd
= varExp
.var
;
4597 if (auto fd
= vd
.isFuncDeclaration())
4602 /* Otherwise skip substituting a const var with
4603 * its initializer. The problem is the initializer won't
4604 * match with an 'alias' parameter. Instead, do the
4605 * const substitution in TemplateValueParameter.matchArg().
4608 else if (definitelyValueParameter(ea
))
4610 if (ea
.checkValue()) // check void expression
4611 ea
= ErrorExp
.get();
4612 uint olderrs
= global
.errors
;
4613 ea
= ea
.ctfeInterpret();
4614 if (global
.errors
!= olderrs
)
4615 ea
= ErrorExp
.get();
4618 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
4619 if (TupleExp te
= ea
.isTupleExp())
4622 size_t dim
= te
.exps
.length
;
4626 tiargs
.reserve(dim
);
4627 foreach (i
, exp
; *te
.exps
)
4628 tiargs
.insert(j
+ i
, exp
);
4633 if (ea
.op
== EXP
.error
)
4640 if (ea
.op
== EXP
.type
)
4645 if (ea
.op
== EXP
.scope_
)
4647 sa
= ea
.isScopeExp().sds
;
4650 if (FuncExp fe
= ea
.isFuncExp())
4652 /* A function literal, that is passed to template and
4653 * already semanticed as function pointer, never requires
4654 * outer frame. So convert it to global function is valid.
4656 if (fe
.fd
.tok
== TOK
.reserved
&& fe
.type
.ty
== Tpointer
)
4658 // change to non-nested
4659 fe
.fd
.tok
= TOK
.function_
;
4664 /* If template argument is a template lambda,
4665 * get template declaration itself. */
4670 if (ea
.op
== EXP
.dotVariable
&& !(flags
& 1))
4672 // translate expression to dsymbol.
4673 sa
= ea
.isDotVarExp().var
;
4676 if (auto te
= ea
.isTemplateExp())
4681 if (ea
.op
== EXP
.dotTemplateDeclaration
&& !(flags
& 1))
4683 // translate expression to dsymbol.
4684 sa
= ea
.isDotTemplateExp().td
;
4687 if (auto de = ea
.isDotExp())
4689 if (auto se
= de.e2
.isScopeExp())
4699 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
4706 TupleDeclaration d
= sa
.toAlias().isTupleDeclaration();
4716 tiargs
.insert(j
, d
.objects
);
4720 if (FuncAliasDeclaration fa
= sa
.isFuncAliasDeclaration())
4722 FuncDeclaration f
= fa
.toAliasFunc();
4723 if (!fa
.hasOverloads
&& f
.isUnique())
4725 // Strip FuncAlias only when the aliased function
4726 // does not have any overloads.
4732 TemplateDeclaration td
= sa
.isTemplateDeclaration();
4733 if (td
&& td
.semanticRun
== PASS
.initial
&& td
.literal
)
4735 td
.dsymbolSemantic(sc
);
4737 FuncDeclaration fd
= sa
.isFuncDeclaration();
4739 functionSemantic(fd
);
4741 else if (isParameter(o
))
4748 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
4753 printf("-TemplateInstance.semanticTiargs()\n");
4754 for (size_t j
= 0; j
< tiargs
.length
; j
++)
4756 RootObject o
= (*tiargs
)[j
];
4757 Type ta
= isType(o
);
4758 Expression ea
= isExpression(o
);
4759 Dsymbol sa
= isDsymbol(o
);
4760 Tuple va
= isTuple(o
);
4761 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j
, ta
, ea
, sa
, va
);
4767 /**********************************
4768 * Run semantic on the elements of tiargs.
4772 * false if one or more arguments have errors.
4774 * This function is reentrant against error occurrence. If returns false,
4775 * all elements of tiargs won't be modified.
4777 extern (D
) final bool semanticTiargs(Scope
* sc
)
4779 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
4780 if (semantictiargsdone
)
4782 if (semanticTiargs(loc
, sc
, tiargs
, 0))
4784 // cache the result iff semantic analysis succeeded entirely
4785 semantictiargsdone
= 1;
4791 /**********************************
4792 * Find the TemplateDeclaration that matches this TemplateInstance best.
4795 * sc = the scope this TemplateInstance resides in
4796 * argumentList = function arguments in case of a template function
4799 * `true` if a match was found, `false` otherwise
4801 extern (D
) final bool findBestMatch(Scope
* sc
, ArgumentList argumentList
)
4805 TemplateDeclaration tempdecl
= this.tempdecl
.isTemplateDeclaration();
4807 assert(tempdecl
._scope
);
4809 tdtypes
.setDim(tempdecl
.parameters
.length
);
4810 if (!matchWithInstance(sc
, tempdecl
, this, tdtypes
, argumentList
, 2))
4812 .error(loc
, "%s `%s` incompatible arguments for template instantiation", kind
, toPrettyChars
);
4815 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
4821 printf("TemplateInstance.findBestMatch()\n");
4824 uint errs
= global
.errors
;
4825 TemplateDeclaration td_last
= null;
4828 /* Since there can be multiple TemplateDeclaration's with the same
4829 * name, look for the best match.
4831 auto tovers
= tempdecl
.isOverloadSet();
4832 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
4834 TemplateDeclaration td_best
;
4835 TemplateDeclaration td_ambig
;
4836 MATCH m_best
= MATCH
.nomatch
;
4838 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
4839 overloadApply(dstart
, (Dsymbol s
)
4841 auto td
= s
.isTemplateDeclaration();
4844 if (td
== td_best
) // skip duplicates
4847 //printf("td = %s\n", td.toPrettyChars());
4848 // If more arguments than parameters,
4849 // then this is no match.
4850 if (td
.parameters
.length
< tiargs
.length
)
4852 if (!td
.isVariadic())
4856 dedtypes
.setDim(td
.parameters
.length
);
4858 assert(td
.semanticRun
!= PASS
.initial
);
4860 MATCH m
= matchWithInstance(sc
, td
, this, dedtypes
, argumentList
, 0);
4861 //printf("matchWithInstance = %d\n", m);
4862 if (m
== MATCH
.nomatch
) // no match at all
4864 if (m
< m_best
) goto Ltd_best
;
4865 if (m
> m_best
) goto Ltd
;
4867 // Disambiguate by picking the most specialized TemplateDeclaration
4869 MATCH c1
= leastAsSpecialized(sc
, td
, td_best
, argumentList
);
4870 MATCH c2
= leastAsSpecialized(sc
, td_best
, td
, argumentList
);
4871 //printf("c1 = %d, c2 = %d\n", c1, c2);
4872 if (c1
> c2
) goto Ltd
;
4873 if (c1
< c2
) goto Ltd_best
;
4880 // td_best is the best match so far
4885 // td is the new best match
4889 tdtypes
.setDim(dedtypes
.length
);
4890 memcpy(tdtypes
.tdata(), dedtypes
.tdata(), tdtypes
.length
* (void*).sizeof
);
4896 .error(loc
, "%s `%s.%s` matches more than one template declaration:",
4897 td_best
.kind(), td_best
.parent
.toPrettyChars(), td_best
.ident
.toChars());
4898 .errorSupplemental(td_best
.loc
, "`%s`\nand:", td_best
.toChars());
4899 .errorSupplemental(td_ambig
.loc
, "`%s`", td_ambig
.toChars());
4906 else if (td_last
!= td_best
)
4908 ScopeDsymbol
.multiplyDefined(loc
, td_last
, td_best
);
4916 /* https://issues.dlang.org/show_bug.cgi?id=7469
4917 * Normalize tiargs by using corresponding deduced
4918 * template value parameters and tuples for the correct mangling.
4920 * By doing this before hasNestedArgs, CTFEable local variable will be
4921 * accepted as a value parameter. For example:
4924 * struct S(int n) {} // non-global template
4925 * const int num = 1; // CTFEable local variable
4926 * S!num s; // S!1 is instantiated, not S!num
4929 size_t dim
= td_last
.parameters
.length
- (td_last
.isVariadic() ?
1 : 0);
4930 for (size_t i
= 0; i
< dim
; i
++)
4932 if (tiargs
.length
<= i
)
4933 tiargs
.push(tdtypes
[i
]);
4934 assert(i
< tiargs
.length
);
4936 auto tvp
= (*td_last
.parameters
)[i
].isTemplateValueParameter();
4940 // tdtypes[i] is already normalized to the required type in matchArg
4942 (*tiargs
)[i
] = tdtypes
[i
];
4944 if (td_last
.isVariadic() && tiargs
.length
== dim
&& tdtypes
[dim
])
4946 Tuple va
= isTuple(tdtypes
[dim
]);
4948 tiargs
.pushSlice(va
.objects
[]);
4951 else if (errors
&& inst
)
4953 // instantiation was failed with error reporting
4954 assert(global
.errors
);
4959 auto tdecl
= tempdecl
.isTemplateDeclaration();
4961 if (errs
!= global
.errors
)
4962 errorSupplemental(loc
, "while looking for match for `%s`", toChars());
4963 else if (tdecl
&& !tdecl
.overnext
)
4965 // Only one template, so we can give better error message
4966 const(char)* msg
= "does not match template declaration";
4970 hgs
.skipConstraints
= true;
4971 toCharsMaybeConstraints(tdecl
, buf
, hgs
);
4972 const tmsg
= buf
.peekChars();
4973 const cmsg
= tdecl
.getConstraintEvalError(tip
);
4976 .error(loc
, "%s `%s` %s `%s`\n%s", kind
, toPrettyChars
, msg
, tmsg
, cmsg
);
4982 .error(loc
, "%s `%s` %s `%s`", kind
, toPrettyChars
, msg
, tmsg
);
4984 if (tdecl
.parameters
.length
== tiargs
.length
)
4986 // https://issues.dlang.org/show_bug.cgi?id=7352
4987 // print additional information, e.g. `foo` is not a type
4988 foreach (i
, param
; *tdecl
.parameters
)
4990 MATCH match
= param
.matchArg(loc
, sc
, tiargs
, i
, tdecl
.parameters
, dedtypes
, null);
4991 auto arg
= (*tiargs
)[i
];
4992 auto sym
= arg
.isDsymbol
;
4993 auto exp
= arg
.isExpression
;
4996 exp
= exp
.optimize(WANTvalue
);
4998 if (match
== MATCH
.nomatch
&&
4999 ((sym
&& sym
.isFuncDeclaration
) ||
5000 (exp
&& exp
.isVarExp
)))
5002 if (param
.isTemplateTypeParameter
)
5003 errorSupplemental(loc
, "`%s` is not a type", arg
.toChars
);
5004 else if (auto tvp
= param
.isTemplateValueParameter
)
5005 errorSupplemental(loc
, "`%s` is not of a value of type `%s`",
5006 arg
.toChars
, tvp
.valType
.toChars
);
5015 .error(loc
, "%s `%s` does not match any template declaration", kind(), toPrettyChars());
5017 overloadApply(tempdecl
, (s
){
5019 errorSupplemental(loc
, "Candidates are:");
5021 errorSupplemental(s
.loc
, "%s", s
.toChars());
5028 /* The best match is td_last
5034 printf("\tIt's a match with template declaration '%s'\n", tempdecl
.toChars());
5036 return (errs
== global
.errors
);
5039 /*****************************************************
5040 * Determine if template instance is really a template function,
5041 * and that template function needs to infer types from the function
5044 * Like findBestMatch, iterate possible template candidates,
5045 * but just looks only the necessity of type inference.
5047 extern (D
) final bool needsTypeInference(Scope
* sc
, int flag
= 0)
5049 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
5050 if (semanticRun
!= PASS
.initial
)
5053 uint olderrs
= global
.errors
;
5057 auto tovers
= tempdecl
.isOverloadSet();
5058 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
5060 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
5061 int r
= overloadApply(dstart
, (Dsymbol s
)
5063 auto td
= s
.isTemplateDeclaration();
5067 /* If any of the overloaded template declarations need inference,
5072 if (auto td2
= td
.onemember
.isTemplateDeclaration())
5074 if (!td2
.onemember ||
!td2
.onemember
.isFuncDeclaration())
5076 if (tiargs
.length
>= td
.parameters
.length
- (td
.isVariadic() ?
1 : 0))
5080 auto fd
= td
.onemember
.isFuncDeclaration();
5081 if (!fd || fd
.type
.ty
!= Tfunction
)
5084 foreach (tp
; *td
.parameters
)
5086 if (tp
.isTemplateThisParameter())
5090 /* Determine if the instance arguments, tiargs, are all that is necessary
5091 * to instantiate the template.
5093 //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
5094 auto tf
= fd
.type
.isTypeFunction();
5095 if (tf
.parameterList
.length
)
5097 auto tp
= td
.isVariadic();
5098 if (tp
&& td
.parameters
.length
> 1)
5101 if (!tp
&& tiargs
.length
< td
.parameters
.length
)
5103 // Can remain tiargs be filled by default arguments?
5104 foreach (size_t i
; tiargs
.length
.. td
.parameters
.length
)
5106 if (!(*td
.parameters
)[i
].hasDefaultArg())
5111 foreach (i
, fparam
; tf
.parameterList
)
5113 // 'auto ref' needs inference.
5114 if (fparam
.storageClass
& STC
.auto_
)
5121 /* Calculate the need for overload resolution.
5122 * When only one template can match with tiargs, inference is not necessary.
5124 dedtypes
.setDim(td
.parameters
.length
);
5126 if (td
.semanticRun
== PASS
.initial
)
5130 // Try to fix forward reference. Ungag errors while doing so.
5131 Ungag ungag
= td
.ungagSpeculative();
5132 td
.dsymbolSemantic(td
._scope
);
5134 if (td
.semanticRun
== PASS
.initial
)
5136 .error(loc
, "%s `%s` `%s` forward references template declaration `%s`", kind
, toPrettyChars
, toChars(), td
.toChars());
5140 MATCH m
= matchWithInstance(sc
, td
, this, dedtypes
, ArgumentList(), 0);
5141 if (m
== MATCH
.nomatch
)
5145 /* If there is more than one function template which matches, we may
5146 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
5148 return ++count
> 1 ?
1 : 0;
5154 if (olderrs
!= global
.errors
)
5158 errorSupplemental(loc
, "while looking for match for `%s`", toChars());
5159 semanticRun
= PASS
.semanticdone
;
5164 //printf("false\n");
5168 /*****************************************
5169 * Determines if a TemplateInstance will need a nested
5170 * generation of the TemplateDeclaration.
5171 * Sets enclosing property if so, and returns != 0;
5173 extern (D
) final bool hasNestedArgs(Objects
* args
, bool isstatic
)
5176 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
5178 // arguments from parent instances are also accessible
5181 if (TemplateInstance ti
= tempdecl
.toParent().isTemplateInstance())
5182 enclosing
= ti
.enclosing
;
5185 /* A nested instance happens when an argument references a local
5186 * symbol that is on the stack.
5190 Expression ea
= isExpression(o
);
5191 Dsymbol sa
= isDsymbol(o
);
5192 Tuple va
= isTuple(o
);
5195 if (auto ve
= ea
.isVarExp())
5200 if (auto te
= ea
.isThisExp())
5205 if (auto fe
= ea
.isFuncExp())
5213 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
5214 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
)
5216 if (!ea
.type
.isTypeError())
5217 .error(ea
.loc
, "%s `%s` expression `%s` is not a valid template value argument", kind
, toPrettyChars
, ea
.toChars());
5225 TemplateDeclaration td
= sa
.isTemplateDeclaration();
5228 TemplateInstance ti
= sa
.toParent().isTemplateInstance();
5229 if (ti
&& ti
.enclosing
)
5232 TemplateInstance ti
= sa
.isTemplateInstance();
5233 Declaration d
= sa
.isDeclaration();
5234 if ((td
&& td
.literal
) ||
(ti
&& ti
.enclosing
) ||
(d
&& !d
.isDataseg() && !(d
.storage_class
& STC
.manifest
) && (!d
.isFuncDeclaration() || d
.isFuncDeclaration().isNested()) && !isTemplateMixin()))
5236 Dsymbol dparent
= sa
.toParent2();
5237 if (!dparent || dparent
.isModule
)
5239 else if (!enclosing
)
5240 enclosing
= dparent
;
5241 else if (enclosing
!= dparent
)
5243 /* Select the more deeply nested of the two.
5244 * Error if one is not nested inside the other.
5246 for (Dsymbol p
= enclosing
; p
; p
= p
.parent
)
5249 goto L1
; // enclosing is most nested
5251 for (Dsymbol p
= dparent
; p
; p
= p
.parent
)
5255 enclosing
= dparent
;
5256 goto L1
; // dparent is most nested
5259 //https://issues.dlang.org/show_bug.cgi?id=17870
5260 if (dparent
.isClassDeclaration() && enclosing
.isClassDeclaration())
5262 auto pc
= dparent
.isClassDeclaration();
5263 auto ec
= enclosing
.isClassDeclaration();
5264 if (pc
.isBaseOf(ec
, null))
5266 else if (ec
.isBaseOf(pc
, null))
5268 enclosing
= dparent
;
5272 .error(loc
, "%s `%s` `%s` is nested in both `%s` and `%s`", kind
, toPrettyChars
, toChars(), enclosing
.toChars(), dparent
.toChars());
5276 //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
5282 nested |
= cast(int)hasNestedArgs(&va
.objects
, isstatic
);
5285 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
5289 /*****************************************
5290 * Append 'this' to the specific module members[]
5292 extern (D
) final Dsymbols
* appendToModuleMember()
5294 Module mi
= minst
; // instantiated . inserted module
5296 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
5298 // enclosing ? enclosing.toPrettyChars() : null,
5299 // mi ? mi.toPrettyChars() : null);
5300 if (global
.params
.allInst ||
!mi || mi
.isRoot())
5302 /* If the instantiated module is speculative or root, insert to the
5303 * member of a root module. Then:
5304 * - semantic3 pass will get called on the instance members.
5305 * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
5307 static Dsymbol
getStrictEnclosing(TemplateInstance ti
)
5312 return ti
.enclosing
;
5313 ti
= ti
.tempdecl
.isInstantiated();
5318 Dsymbol enc
= getStrictEnclosing(this);
5319 // insert target is made stable by using the module
5320 // where tempdecl is declared.
5321 mi
= (enc ? enc
: tempdecl
).getModule();
5324 if (mi
.importedFrom
)
5326 mi
= mi
.importedFrom
;
5327 assert(mi
.isRoot());
5331 // This can happen when using the frontend as a library.
5332 // Append it to the non-root module.
5338 /* If the instantiated module is non-root, insert to the member of the
5339 * non-root module. Then:
5340 * - semantic3 pass won't be called on the instance.
5341 * - codegen pass won't reach to the instance.
5342 * Unless it is re-appended to a root module later (with changed minst).
5345 //printf("\t-. mi = %s\n", mi.toPrettyChars());
5347 if (memberOf
) // already appended to some module
5349 assert(mi
.isRoot(), "can only re-append to a root module");
5350 if (memberOf
.isRoot())
5351 return null; // no need to move to another root module
5354 Dsymbols
* a
= mi
.members
;
5357 if (mi
.semanticRun
>= PASS
.semantic2done
&& mi
.isRoot())
5358 Module
.addDeferredSemantic2(this);
5359 if (mi
.semanticRun
>= PASS
.semantic3done
&& mi
.isRoot())
5360 Module
.addDeferredSemantic3(this);
5364 /****************************************************
5365 * Declare parameters of template instance, initialize them with the
5366 * template instance arguments.
5368 extern (D
) final void declareParameters(Scope
* sc
)
5370 TemplateDeclaration tempdecl
= this.tempdecl
.isTemplateDeclaration();
5373 //printf("TemplateInstance.declareParameters()\n");
5374 foreach (i
, o
; tdtypes
) // initializer for tp
5376 TemplateParameter tp
= (*tempdecl
.parameters
)[i
];
5377 //printf("\ttdtypes[%d] = %p\n", i, o);
5378 declareParameter(tempdecl
, sc
, tp
, o
);
5382 /****************************************
5383 * This instance needs an identifier for name mangling purposes.
5384 * Create one by taking the template declaration name and adding
5385 * the type signature for it.
5387 extern (D
) final Identifier
genIdent(Objects
* args
)
5389 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
5390 assert(args
is tiargs
);
5392 mangleToBuffer(this, buf
);
5393 //printf("\tgenIdent = %s\n", buf.peekChars());
5394 return Identifier
.idPool(buf
[]);
5397 extern (D
) final void expandMembers(Scope
* sc2
)
5399 members
.foreachDsymbol( (s
) { s
.setScope (sc2
); } );
5401 members
.foreachDsymbol( (s
) { s
.importAll(sc2
); } );
5405 /* static if's are crucial to evaluating aliasdecl correctly. But
5406 * evaluating the if/else bodies may require aliasdecl.
5407 * So, evaluate the condition for static if's, but not their if/else bodies.
5408 * Then try to set aliasdecl.
5409 * Later do the if/else bodies.
5410 * https://issues.dlang.org/show_bug.cgi?id=23598
5411 * It might be better to do this by attaching a lambda to the StaticIfDeclaration
5412 * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
5415 void staticIfDg(Dsymbol s
)
5417 if (done || aliasdecl
)
5419 //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
5420 if (!s
.isStaticIfDeclaration())
5422 //s.dsymbolSemantic(sc2);
5426 auto sid
= s
.isStaticIfDeclaration();
5431 if (Dsymbol
.oneMembers(members
, sa
, tempdecl
.ident
) && sa
)
5437 members
.foreachDsymbol(&staticIfDg
);
5440 void symbolDg(Dsymbol s
)
5442 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
5443 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
5445 // s.parent = sc.parent;
5446 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
5447 s
.dsymbolSemantic(sc2
);
5448 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
5449 Module
.runDeferredSemantic();
5452 members
.foreachDsymbol(&symbolDg
);
5455 extern (D
) final void tryExpandMembers(Scope
* sc2
)
5458 // extracted to a function to allow windows SEH to work without destructors in the same function
5459 //printf("%d\n", nest);
5460 if (++nest
> global
.recursionLimit
)
5462 global
.gag
= 0; // ensure error message gets printed
5463 .error(loc
, "%s `%s` recursive expansion exceeded allowed nesting limit", kind
, toPrettyChars
);
5472 extern (D
) final void trySemantic3(Scope
* sc2
)
5474 // extracted to a function to allow windows SEH to work without destructors in the same function
5476 //printf("%d\n", nest);
5477 if (++nest
> global
.recursionLimit
)
5479 global
.gag
= 0; // ensure error message gets printed
5480 .error(loc
, "%s `%s` recursive expansion exceeded allowed nesting limit", kind
, toPrettyChars
);
5484 semantic3(this, sc2
);
5489 override final inout(TemplateInstance
) isTemplateInstance() inout
5494 override void accept(Visitor v
)
5500 /**************************************
5501 * IsExpression can evaluate the specified type speculatively, and even if
5502 * it instantiates any symbols, they are normally unnecessary for the
5504 * However, if those symbols leak to the actual code, compiler should remark
5505 * them as non-speculative to generate their code and link to the final executable.
5507 void unSpeculative(Scope
* sc
, RootObject o
)
5512 if (Tuple tup
= isTuple(o
))
5514 foreach (obj
; tup
.objects
)
5516 unSpeculative(sc
, obj
);
5521 Dsymbol s
= getDsymbol(o
);
5525 if (Declaration d
= s
.isDeclaration())
5527 if (VarDeclaration vd
= d
.isVarDeclaration())
5529 else if (AliasDeclaration ad
= d
.isAliasDeclaration())
5543 if (TemplateInstance ti
= s
.isTemplateInstance())
5545 // If the instance is already non-speculative,
5546 // or it is leaked to the speculative scope.
5547 if (ti
.minst
!is null || sc
.minst
is null)
5550 // Remark as non-speculative instance.
5551 ti
.minst
= sc
.minst
;
5553 ti
.tinst
= sc
.tinst
;
5555 unSpeculative(sc
, ti
.tempdecl
);
5558 if (TemplateInstance ti
= s
.isInstantiated())
5559 unSpeculative(sc
, ti
);
5562 /**********************************
5563 * Return true if e could be valid only as a template value parameter.
5564 * Return false if it might be an alias or tuple.
5565 * (Note that even in this case, it could still turn out to be a value).
5567 bool definitelyValueParameter(Expression e
) @safe
5569 // None of these can be value parameters
5570 if (e
.op
== EXP
.tuple || e
.op
== EXP
.scope_ ||
5571 e
.op
== EXP
.type || e
.op
== EXP
.dotType ||
5572 e
.op
== EXP
.template_ || e
.op
== EXP
.dotTemplateDeclaration ||
5573 e
.op
== EXP
.function_ || e
.op
== EXP
.error ||
5574 e
.op
== EXP
.this_ || e
.op
== EXP
.super_ ||
5578 if (e
.op
!= EXP
.dotVariable
)
5581 /* Template instantiations involving a DotVar expression are difficult.
5582 * In most cases, they should be treated as a value parameter, and interpreted.
5583 * But they might also just be a fully qualified name, which should be treated
5587 // x.y.f cannot be a value
5588 FuncDeclaration f
= e
.isDotVarExp().var
.isFuncDeclaration();
5592 while (e
.op
== EXP
.dotVariable
)
5594 e
= e
.isDotVarExp().e1
;
5596 // this.x.y and super.x.y couldn't possibly be valid values.
5597 if (e
.op
== EXP
.this_ || e
.op
== EXP
.super_
)
5600 // e.type.x could be an alias
5601 if (e
.op
== EXP
.dotType
)
5604 // var.x.y is the only other possible form of alias
5605 if (e
.op
!= EXP
.variable
)
5608 VarDeclaration v
= e
.isVarExp().var
.isVarDeclaration();
5609 // func.x.y is not an alias
5613 // https://issues.dlang.org/show_bug.cgi?id=16685
5614 // var.x.y where var is a constant available at compile time
5615 if (v
.storage_class
& STC
.manifest
)
5618 // TODO: Should we force CTFE if it is a global constant?
5622 /***********************************************************
5623 * https://dlang.org/spec/template-mixin.html
5625 * mixin MixinTemplateName [TemplateArguments] [Identifier];
5627 extern (C
++) final class TemplateMixin
: TemplateInstance
5629 TypeQualified tqual
;
5631 extern (D
) this(const ref Loc loc
, Identifier ident
, TypeQualified tqual
, Objects
* tiargs
)
5634 tqual
.idents
.length ?
cast(Identifier
)tqual
.idents
[tqual
.idents
.length
- 1] : (cast(TypeIdentifier
)tqual
).ident
,
5635 tiargs ? tiargs
: new Objects());
5636 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
5641 override TemplateInstance
syntaxCopy(Dsymbol s
)
5643 auto tm
= new TemplateMixin(loc
, ident
, tqual
.syntaxCopy(), tiargs
);
5644 return TemplateInstance
.syntaxCopy(tm
);
5647 override const(char)* kind() const
5652 override bool oneMember(out Dsymbol ps
, Identifier ident
)
5654 return Dsymbol
.oneMember(ps
, ident
);
5657 override bool hasPointers()
5659 //printf("TemplateMixin.hasPointers() %s\n", toChars());
5660 return members
.foreachDsymbol( (s
) { return s
.hasPointers(); } ) != 0;
5663 override const(char)* toChars() const
5666 toCBufferInstance(this, buf
);
5667 return buf
.extractChars();
5670 extern (D
) bool findTempDecl(Scope
* sc
)
5672 // Follow qualifications to find the TemplateDeclaration
5678 tqual
.resolve(loc
, sc
, e
, t
, s
);
5681 .error(loc
, "%s `%s` is not defined", kind
, toPrettyChars
);
5685 tempdecl
= s
.isTemplateDeclaration();
5686 OverloadSet os
= s
.isOverloadSet();
5688 /* If an OverloadSet, look for a unique member that is a template declaration
5693 foreach (i
, sym
; os
.a
)
5695 Dsymbol s2
= sym
.isTemplateDeclaration();
5709 .error(loc
, "%s `%s` - `%s` is a %s, not a template", kind
, toPrettyChars
, s
.toChars(), s
.kind());
5715 // Look for forward references
5716 auto tovers
= tempdecl
.isOverloadSet();
5717 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
5719 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
5720 int r
= overloadApply(dstart
, (Dsymbol s
)
5722 auto td
= s
.isTemplateDeclaration();
5726 if (td
.semanticRun
== PASS
.initial
)
5729 td
.dsymbolSemantic(td
._scope
);
5732 semanticRun
= PASS
.initial
;
5744 override inout(TemplateMixin
) isTemplateMixin() inout
5749 override void accept(Visitor v
)
5755 /************************************
5756 * This struct is needed for TemplateInstance to be the key in an associative array.
5757 * Fixing https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
5759 struct TemplateInstanceBox
5761 TemplateInstance ti
;
5763 this(TemplateInstance ti
)
5767 assert(this.ti
.hash
);
5770 size_t
toHash() const @trusted pure nothrow
5776 bool opEquals(ref const TemplateInstanceBox s
) @trusted const
5779 if (ti
.inst
&& s
.ti
.inst
)
5781 /* This clause is only used when an instance with errors
5782 * is replaced with a correct instance.
5788 /* Used when a proposed instance is used to see if there's
5789 * an existing instance.
5791 static if (__VERSION__
< 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
5792 res
= (cast()s
.ti
).equalsx(cast()ti
);
5794 res
= (cast()ti
).equalsx(cast()s
.ti
);
5797 debug (FindExistingInstance
) ++(res ? nHits
: nCollisions
);
5801 debug (FindExistingInstance
)
5803 __gshared
uint nHits
, nCollisions
;
5805 shared static ~this()
5807 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
5808 nHits
, nCollisions
);
5813 /*******************************************
5814 * Match to a particular TemplateParameter.
5816 * instLoc location that the template is instantiated.
5817 * tiargs[] actual arguments to template instance
5819 * parameters[] template parameters
5820 * dedtypes[] deduced arguments to template instance
5821 * *psparam set to symbol declared and initialized to dedtypes[i]
5823 MATCH
matchArg(TemplateParameter tp
, Loc instLoc
, Scope
* sc
, Objects
* tiargs
, size_t i
, TemplateParameters
* parameters
, ref Objects dedtypes
, Declaration
* psparam
)
5825 MATCH
matchArgNoMatch()
5829 return MATCH
.nomatch
;
5832 MATCH
matchArgParameter()
5836 if (i
< tiargs
.length
)
5837 oarg
= (*tiargs
)[i
];
5840 // Get default argument instead
5841 oarg
= tp
.defaultArg(instLoc
, sc
);
5844 assert(i
< dedtypes
.length
);
5845 // It might have already been deduced
5848 return matchArgNoMatch();
5851 return tp
.matchArg(sc
, oarg
, i
, parameters
, dedtypes
, psparam
);
5854 MATCH
matchArgTuple(TemplateTupleParameter ttp
)
5856 /* The rest of the actual arguments (tiargs[]) form the match
5857 * for the variadic parameter.
5859 assert(i
+ 1 == dedtypes
.length
); // must be the last one
5862 if (Tuple u
= isTuple(dedtypes
[i
]))
5864 // It has already been deduced
5867 else if (i
+ 1 == tiargs
.length
&& isTuple((*tiargs
)[i
]))
5868 ovar
= isTuple((*tiargs
)[i
]);
5872 //printf("ovar = %p\n", ovar);
5873 if (i
< tiargs
.length
)
5875 //printf("i = %d, tiargs.length = %d\n", i, tiargs.length);
5876 ovar
.objects
.setDim(tiargs
.length
- i
);
5877 foreach (j
, ref obj
; ovar
.objects
)
5878 obj
= (*tiargs
)[i
+ j
];
5881 return ttp
.matchArg(sc
, ovar
, i
, parameters
, dedtypes
, psparam
);
5884 if (auto ttp
= tp
.isTemplateTupleParameter())
5885 return matchArgTuple(ttp
);
5887 return matchArgParameter();
5890 MATCH
matchArg(TemplateParameter tp
, Scope
* sc
, RootObject oarg
, size_t i
, TemplateParameters
* parameters
, ref Objects dedtypes
, Declaration
* psparam
)
5892 MATCH
matchArgNoMatch()
5894 //printf("\tm = %d\n", MATCH.nomatch);
5897 return MATCH
.nomatch
;
5900 MATCH
matchArgType(TemplateTypeParameter ttp
)
5902 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
5903 MATCH m
= MATCH
.exact
;
5904 Type ta
= isType(oarg
);
5907 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
5908 return matchArgNoMatch();
5910 //printf("ta is %s\n", ta.toChars());
5914 if (!ta || ta
== TemplateTypeParameter
.tdummy
)
5915 return matchArgNoMatch();
5917 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
5918 MATCH m2
= deduceType(ta
, sc
, ttp
.specType
, *parameters
, dedtypes
);
5919 if (m2
== MATCH
.nomatch
)
5921 //printf("\tfailed deduceType\n");
5922 return matchArgNoMatch();
5929 Type t
= cast(Type
)dedtypes
[i
];
5931 if (ttp
.dependent
&& !t
.equals(ta
)) // https://issues.dlang.org/show_bug.cgi?id=14357
5932 return matchArgNoMatch();
5934 /* This is a self-dependent parameter. For example:
5935 * template X(T : T*) {}
5936 * template X(T : S!T, alias S) {}
5938 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
5946 // Must match already deduced type
5947 Type t
= cast(Type
)dedtypes
[i
];
5951 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
5952 return matchArgNoMatch();
5957 // So that matches with specializations are better
5964 *psparam
= new AliasDeclaration(ttp
.loc
, ttp
.ident
, ta
);
5965 //printf("\tm = %d\n", m);
5966 return ttp
.dependent ? MATCH
.exact
: m
;
5969 MATCH
matchArgValue(TemplateValueParameter tvp
)
5971 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
5972 MATCH m
= MATCH
.exact
;
5974 Expression ei
= isExpression(oarg
);
5979 Dsymbol si
= isDsymbol(oarg
);
5980 FuncDeclaration f
= si ? si
.isFuncDeclaration() : null;
5981 if (!f ||
!f
.fbody || f
.needThis())
5982 return matchArgNoMatch();
5984 ei
= new VarExp(tvp
.loc
, f
);
5985 ei
= ei
.expressionSemantic(sc
);
5987 /* If a function is really property-like, and then
5988 * it's CTFEable, ei will be a literal expression.
5990 uint olderrors
= global
.startGagging();
5991 ei
= resolveProperties(sc
, ei
);
5992 ei
= ei
.ctfeInterpret();
5993 if (global
.endGagging(olderrors
) || ei
.op
== EXP
.error
)
5994 return matchArgNoMatch();
5996 /* https://issues.dlang.org/show_bug.cgi?id=14520
5997 * A property-like function can match to both
5998 * TemplateAlias and ValueParameter. But for template overloads,
5999 * it should always prefer alias parameter to be consistent
6000 * template match result.
6002 * template X(alias f) { enum X = 1; }
6003 * template X(int val) { enum X = 2; }
6004 * int f1() { return 0; } // CTFEable
6005 * int f2(); // body-less function is not CTFEable
6006 * enum x1 = X!f1; // should be 1
6007 * enum x2 = X!f2; // should be 1
6009 * e.g. The x1 value must be same even if the f1 definition will be moved
6010 * into di while stripping body code.
6015 if (ei
&& ei
.op
== EXP
.variable
)
6017 // Resolve const variables that we had skipped earlier
6018 ei
= ei
.ctfeInterpret();
6021 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
6022 vt
= tvp
.valType
.typeSemantic(tvp
.loc
, sc
);
6023 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
6024 //printf("vt = %s\n", vt.toChars());
6028 MATCH m2
= ei
.implicitConvTo(vt
);
6029 //printf("m: %d\n", m);
6032 if (m
== MATCH
.nomatch
)
6033 return matchArgNoMatch();
6034 ei
= ei
.implicitCastTo(sc
, vt
);
6035 ei
= ei
.ctfeInterpret();
6040 if (ei
is null ||
(cast(void*)ei
.type
in TemplateValueParameter
.edummies
&&
6041 TemplateValueParameter
.edummies
[cast(void*)ei
.type
] == ei
))
6042 return matchArgNoMatch();
6044 Expression e
= tvp
.specValue
;
6046 sc
= sc
.startCTFE();
6047 e
= e
.expressionSemantic(sc
);
6048 e
= resolveProperties(sc
, e
);
6050 e
= e
.implicitCastTo(sc
, vt
);
6051 e
= e
.ctfeInterpret();
6053 ei
= ei
.syntaxCopy();
6054 sc
= sc
.startCTFE();
6055 ei
= ei
.expressionSemantic(sc
);
6057 ei
= ei
.implicitCastTo(sc
, vt
);
6058 ei
= ei
.ctfeInterpret();
6059 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
6060 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
6062 return matchArgNoMatch();
6068 // Must match already deduced value
6069 Expression e
= cast(Expression
)dedtypes
[i
];
6070 if (!ei ||
!ei
.equals(e
))
6071 return matchArgNoMatch();
6078 Initializer _init
= new ExpInitializer(tvp
.loc
, ei
);
6079 Declaration sparam
= new VarDeclaration(tvp
.loc
, vt
, tvp
.ident
, _init
);
6080 sparam
.storage_class
= STC
.manifest
;
6083 return tvp
.dependent ? MATCH
.exact
: m
;
6086 MATCH
matchArgAlias(TemplateAliasParameter tap
)
6088 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
6089 MATCH m
= MATCH
.exact
;
6090 Type ta
= isType(oarg
);
6091 RootObject sa
= ta
&& !ta
.deco ?
null : getDsymbol(oarg
);
6092 Expression ea
= isExpression(oarg
);
6095 if (auto te
= ea
.isThisExp())
6097 else if (auto se
= ea
.isSuperExp())
6099 else if (auto se
= ea
.isScopeExp())
6104 if ((cast(Dsymbol
)sa
).isAggregateDeclaration())
6107 /* specType means the alias must be a declaration with a type
6108 * that matches specType.
6112 tap
.specType
= typeSemantic(tap
.specType
, tap
.loc
, sc
);
6113 Declaration d
= (cast(Dsymbol
)sa
).isDeclaration();
6115 return matchArgNoMatch();
6116 if (!d
.type
.equals(tap
.specType
))
6117 return matchArgNoMatch();
6127 if (!ea
.type
.equals(tap
.specType
))
6128 return matchArgNoMatch();
6131 else if (ta
&& ta
.ty
== Tinstance
&& !tap
.specAlias
)
6133 /* Specialized parameter should be preferred
6134 * match to the template type parameter.
6135 * template X(alias a) {} // a == this
6136 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
6139 else if (sa
&& sa
== TemplateTypeParameter
.tdummy
)
6141 /* https://issues.dlang.org/show_bug.cgi?id=2025
6142 * Aggregate Types should preferentially
6143 * match to the template type parameter.
6144 * template X(alias a) {} // a == this
6145 * template X(T) {} // T => sa
6148 else if (ta
&& ta
.ty
!= Tident
)
6150 /* Match any type that's not a TypeIdentifier to alias parameters,
6151 * but prefer type parameter.
6152 * template X(alias a) { } // a == ta
6154 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
6159 return matchArgNoMatch();
6164 if (sa
== TemplateAliasParameter
.sdummy
)
6165 return matchArgNoMatch();
6166 // check specialization if template arg is a symbol
6167 Dsymbol sx
= isDsymbol(sa
);
6168 if (sa
!= tap
.specAlias
&& sx
)
6170 Type talias
= isType(tap
.specAlias
);
6172 return matchArgNoMatch();
6174 TemplateInstance ti
= sx
.isTemplateInstance();
6175 if (!ti
&& sx
.parent
)
6177 ti
= sx
.parent
.isTemplateInstance();
6178 if (ti
&& ti
.name
!= sx
.ident
)
6179 return matchArgNoMatch();
6182 return matchArgNoMatch();
6184 Type t
= new TypeInstance(Loc
.initial
, ti
);
6185 MATCH m2
= deduceType(t
, sc
, talias
, *parameters
, dedtypes
);
6186 if (m2
== MATCH
.nomatch
)
6187 return matchArgNoMatch();
6189 // check specialization if template arg is a type
6192 if (Type tspec
= isType(tap
.specAlias
))
6194 MATCH m2
= ta
.implicitConvTo(tspec
);
6195 if (m2
== MATCH
.nomatch
)
6196 return matchArgNoMatch();
6200 error(tap
.loc
, "template parameter specialization for a type must be a type and not `%s`",
6201 tap
.specAlias
.toChars());
6202 return matchArgNoMatch();
6206 else if (dedtypes
[i
])
6208 // Must match already deduced symbol
6209 RootObject si
= dedtypes
[i
];
6210 if (!sa || si
!= sa
)
6211 return matchArgNoMatch();
6217 if (Dsymbol s
= isDsymbol(sa
))
6219 *psparam
= new AliasDeclaration(tap
.loc
, tap
.ident
, s
);
6221 else if (Type t
= isType(sa
))
6223 *psparam
= new AliasDeclaration(tap
.loc
, tap
.ident
, t
);
6229 // Declare manifest constant
6230 Initializer _init
= new ExpInitializer(tap
.loc
, ea
);
6231 auto v
= new VarDeclaration(tap
.loc
, null, tap
.ident
, _init
);
6232 v
.storage_class
= STC
.manifest
;
6233 v
.dsymbolSemantic(sc
);
6237 return tap
.dependent ? MATCH
.exact
: m
;
6240 MATCH
matchArgTuple(TemplateTupleParameter ttp
)
6242 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
6243 Tuple ovar
= isTuple(oarg
);
6245 return MATCH
.nomatch
;
6248 Tuple tup
= isTuple(dedtypes
[i
]);
6250 return MATCH
.nomatch
;
6251 if (!match(tup
, ovar
))
6252 return MATCH
.nomatch
;
6257 *psparam
= new TupleDeclaration(ttp
.loc
, ttp
.ident
, &ovar
.objects
);
6258 return ttp
.dependent ? MATCH
.exact
: MATCH
.convert
;
6261 if (auto ttp
= tp
.isTemplateTypeParameter())
6262 return matchArgType(ttp
);
6263 else if (auto tvp
= tp
.isTemplateValueParameter())
6264 return matchArgValue(tvp
);
6265 else if (auto tap
= tp
.isTemplateAliasParameter())
6266 return matchArgAlias(tap
);
6267 else if (auto ttp
= tp
.isTemplateTupleParameter())
6268 return matchArgTuple(ttp
);
6274 /***********************************************
6275 * Collect and print statistics on template instantiations.
6277 struct TemplateStats
6279 __gshared TemplateStats
[const void*] stats
;
6281 uint numInstantiations
; // number of instantiations of the template
6282 uint uniqueInstantiations
; // number of unique instantiations of the template
6284 TemplateInstances
* allInstances
;
6286 /*******************************
6289 * td = template declaration
6290 * ti = instance of td
6291 * listInstances = keep track of instances of templates
6293 static void incInstance(const TemplateDeclaration td
,
6294 const TemplateInstance ti
,
6297 void log(ref TemplateStats ts
)
6299 if (ts
.allInstances
is null)
6300 ts
.allInstances
= new TemplateInstances();
6302 ts
.allInstances
.push(cast() ti
);
6305 // message(ti.loc, "incInstance %p %p", td, ti);
6309 if (auto ts
= cast(const void*) td
in stats
)
6312 ++ts
.numInstantiations
;
6316 stats
[cast(const void*) td
] = TemplateStats(1, 0);
6317 log(stats
[cast(const void*) td
]);
6321 /*******************************
6322 * Add this unique instance
6324 static void incUnique(const TemplateDeclaration td
,
6325 const TemplateInstance ti
)
6327 // message(ti.loc, "incUnique %p %p", td, ti);
6331 if (auto ts
= cast(const void*) td
in stats
)
6332 ++ts
.uniqueInstantiations
;
6334 stats
[cast(const void*) td
] = TemplateStats(0, 1);
6338 /********************************
6339 * Print informational statistics on template instantiations.
6341 * listInstances = list instances of templates
6342 * eSink = where the print is sent
6344 void printTemplateStats(bool listInstances
, ErrorSink eSink
)
6346 static struct TemplateDeclarationStats
6348 TemplateDeclaration td
;
6350 static int compare(scope const TemplateDeclarationStats
* a
,
6351 scope const TemplateDeclarationStats
* b
) @safe nothrow @nogc pure
6353 auto diff
= b
.ts
.uniqueInstantiations
- a
.ts
.uniqueInstantiations
;
6357 return b
.ts
.numInstantiations
- a
.ts
.numInstantiations
;
6361 const stats_length
= TemplateStats
.stats
.length
;
6363 return; // nothing to report
6365 Array
!(TemplateDeclarationStats
) sortedStats
;
6366 sortedStats
.reserve(stats_length
);
6367 foreach (td_
, ref ts
; TemplateStats
.stats
)
6369 sortedStats
.push(TemplateDeclarationStats(cast(TemplateDeclaration
) td_
, ts
));
6372 sortedStats
.sort
!(TemplateDeclarationStats
.compare
);
6375 foreach (const ref ss
; sortedStats
[])
6379 hgs
.skipConstraints
= true;
6380 toCharsMaybeConstraints(ss
.td
, buf
, hgs
);
6381 const tchars
= buf
.peekChars();
6382 if (listInstances
&& ss
.ts
.allInstances
)
6384 eSink
.message(ss
.td
.loc
,
6385 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
6386 ss
.ts
.numInstantiations
,
6387 ss
.ts
.uniqueInstantiations
,
6389 foreach (const ti
; (*ss
.ts
.allInstances
)[])
6391 if (ti
.tinst
) // if has enclosing instance
6392 eSink
.message(ti
.loc
, "vtemplate: implicit instance `%s`", ti
.toChars());
6394 eSink
.message(ti
.loc
, "vtemplate: explicit instance `%s`", ti
.toChars());
6399 eSink
.message(ss
.td
.loc
,
6400 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
6401 ss
.ts
.numInstantiations
,
6402 ss
.ts
.uniqueInstantiations
,
6411 MATCH mta
; /// match template parameters by initial template arguments
6412 MATCH mfa
; /// match template parameters by inferred template arguments
6414 debug this(MATCH mta
, MATCH mfa
)
6416 assert(MATCH
.min
<= mta
&& mta
<= MATCH
.max
);
6417 assert(MATCH
.min
<= mfa
&& mfa
<= MATCH
.max
);
6423 void write(ref OutBuffer buf
, RootObject obj
)
6427 buf
.writestring(obj
.toChars());