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-2023 by The D Language Foundation, All Rights Reserved
32 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
33 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
34 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d)
35 * Documentation: https://dlang.org/phobos/dmd_dtemplate.html
36 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d
41 import core
.stdc
.stdio
;
42 import core
.stdc
.string
;
45 import dmd
.arraytypes
;
51 import dmd
.declaration
;
56 import dmd
.dsymbolsem
;
58 import dmd
.expression
;
59 import dmd
.expressionsem
;
64 import dmd
.identifier
;
71 import dmd
.root
.array
;
72 import dmd
.common
.outbuffer
;
73 import dmd
.root
.rootobject
;
80 import dmd
.templateparamsem
;
82 //debug = FindExistingInstance; // print debug stats of findExistingInstance
83 private enum LOG
= false;
85 enum IDX_NOTFOUND
= 0x12345678;
90 /********************************************
91 * These functions substitute for dynamic_cast. dynamic_cast does not work
92 * on earlier versions of gcc.
94 extern (C
++) inout(Expression
) isExpression(inout RootObject o
)
96 //return dynamic_cast<Expression *>(o);
97 if (!o || o
.dyncast() != DYNCAST
.expression
)
99 return cast(inout(Expression
))o
;
102 extern (C
++) inout(Dsymbol
) isDsymbol(inout RootObject o
)
104 //return dynamic_cast<Dsymbol *>(o);
105 if (!o || o
.dyncast() != DYNCAST
.dsymbol
)
107 return cast(inout(Dsymbol
))o
;
110 extern (C
++) inout(Type
) isType(inout RootObject o
)
112 //return dynamic_cast<Type *>(o);
113 if (!o || o
.dyncast() != DYNCAST
.type
)
115 return cast(inout(Type
))o
;
118 extern (C
++) inout(Tuple
) isTuple(inout RootObject o
)
120 //return dynamic_cast<Tuple *>(o);
121 if (!o || o
.dyncast() != DYNCAST
.tuple
)
123 return cast(inout(Tuple
))o
;
126 extern (C
++) inout(Parameter
) isParameter(inout RootObject o
)
128 //return dynamic_cast<Parameter *>(o);
129 if (!o || o
.dyncast() != DYNCAST
.parameter
)
131 return cast(inout(Parameter
))o
;
134 extern (C
++) inout(TemplateParameter
) isTemplateParameter(inout RootObject o
)
136 if (!o || o
.dyncast() != DYNCAST
.templateparameter
)
138 return cast(inout(TemplateParameter
))o
;
141 /**************************************
142 * Is this Object an error?
144 extern (C
++) bool isError(const RootObject o
)
146 if (const t
= isType(o
))
147 return (t
.ty
== Terror
);
148 if (const e
= isExpression(o
))
149 return (e
.op
== EXP
.error ||
!e
.type || e
.type
.ty
== Terror
);
150 if (const v
= isTuple(o
))
151 return arrayObjectIsError(&v
.objects
);
152 const s
= isDsymbol(o
);
156 return s
.parent ?
isError(s
.parent
) : false;
159 /**************************************
160 * Are any of the Objects an error?
162 bool arrayObjectIsError(const Objects
* args
)
164 foreach (const o
; *args
)
172 /***********************
173 * Try to get arg as a type.
175 inout(Type
) getType(inout RootObject o
)
180 if (inout e
= isExpression(o
))
188 Dsymbol
getDsymbol(RootObject oarg
)
190 //printf("getDsymbol()\n");
191 //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
192 if (auto ea
= isExpression(oarg
))
194 // Try to convert Expression to symbol
195 if (auto ve
= ea
.isVarExp())
197 else if (auto fe
= ea
.isFuncExp())
198 return fe
.td ? fe
.td
: fe
.fd
;
199 else if (auto te
= ea
.isTemplateExp())
201 else if (auto te
= ea
.isScopeExp())
208 // Try to convert Type to symbol
209 if (auto ta
= isType(oarg
))
210 return ta
.toDsymbol(null);
212 return isDsymbol(oarg
); // if already a symbol
217 private Expression
getValue(ref Dsymbol s
)
221 if (VarDeclaration v
= s
.isVarDeclaration())
223 if (v
.storage_class
& STC
.manifest
)
224 return v
.getConstInitializer();
230 /***********************
231 * Try to get value from manifest constant
233 private Expression
getValue(Expression e
)
237 if (auto ve
= e
.isVarExp())
239 if (auto v
= ve
.var
.isVarDeclaration())
241 if (v
.storage_class
& STC
.manifest
)
243 e
= v
.getConstInitializer();
250 private Expression
getExpression(RootObject o
)
252 auto s
= isDsymbol(o
);
253 return s ?
.getValue(s
) : .getValue(isExpression(o
));
256 /******************************
257 * If o1 matches o2, return true.
258 * Else, return false.
260 private bool match(RootObject o1
, RootObject o2
)
266 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
267 o1
, o1
.toChars(), o1
.dyncast(), o2
, o2
.toChars(), o2
.dyncast());
270 /* A proper implementation of the various equals() overrides
271 * should make it possible to just do o1.equals(o2), but
272 * we'll do that another day.
274 /* Manifest constants should be compared by their values,
275 * at least in template arguments.
278 if (auto t1
= isType(o1
))
280 auto t2
= isType(o2
);
286 printf("\tt1 = %s\n", t1
.toChars());
287 printf("\tt2 = %s\n", t2
.toChars());
294 if (auto e1
= getExpression(o1
))
296 auto e2
= getExpression(o2
);
302 printf("\te1 = %s '%s' %s\n", e1
.type ? e1
.type
.toChars() : "null", EXPtoString(e1
.op
).ptr
, e1
.toChars());
303 printf("\te2 = %s '%s' %s\n", e2
.type ? e2
.type
.toChars() : "null", EXPtoString(e2
.op
).ptr
, e2
.toChars());
306 // two expressions can be equal although they do not have the same
307 // type; that happens when they have the same value. So check type
308 // as well as expression equality to ensure templates are properly
310 if (!(e1
.type
&& e2
.type
&& e1
.type
.equals(e2
.type
)) ||
!e1
.equals(e2
))
315 if (auto s1
= isDsymbol(o1
))
317 auto s2
= isDsymbol(o2
);
323 printf("\ts1 = %s \n", s1
.kind(), s1
.toChars());
324 printf("\ts2 = %s \n", s2
.kind(), s2
.toChars());
328 if (s1
.parent
!= s2
.parent
&& !s1
.isFuncDeclaration() && !s2
.isFuncDeclaration())
333 if (auto u1
= isTuple(o1
))
335 auto u2
= isTuple(o2
);
341 printf("\tu1 = %s\n", u1
.toChars());
342 printf("\tu2 = %s\n", u2
.toChars());
344 if (!arrayObjectMatch(&u1
.objects
, &u2
.objects
))
351 printf("\t. match\n");
356 printf("\t. nomatch\n");
360 /************************************
361 * Match an array of them.
363 private bool arrayObjectMatch(Objects
* oa1
, Objects
* oa2
)
367 if (oa1
.length
!= oa2
.length
)
369 immutable oa1dim
= oa1
.length
;
370 auto oa1d
= (*oa1
)[].ptr
;
371 auto oa2d
= (*oa2
)[].ptr
;
372 foreach (j
; 0 .. oa1dim
)
374 RootObject o1
= oa1d
[j
];
375 RootObject o2
= oa2d
[j
];
384 /************************************
385 * Return hash of Objects.
387 private size_t
arrayObjectHash(Objects
* oa1
)
389 import dmd
.root
.hash
: mixHash
;
394 /* Must follow the logic of match()
396 if (auto t1
= isType(o1
))
397 hash
= mixHash(hash
, cast(size_t
)t1
.deco
);
398 else if (auto e1
= getExpression(o1
))
399 hash
= mixHash(hash
, expressionHash(e1
));
400 else if (auto s1
= isDsymbol(o1
))
402 auto fa1
= s1
.isFuncAliasDeclaration();
404 s1
= fa1
.toAliasFunc();
405 hash
= mixHash(hash
, mixHash(cast(size_t
)cast(void*)s1
.getIdent(), cast(size_t
)cast(void*)s1
.parent
));
407 else if (auto u1
= isTuple(o1
))
408 hash
= mixHash(hash
, arrayObjectHash(&u1
.objects
));
414 /************************************
415 * Computes hash of expression.
416 * Handles all Expression classes and MUST match their equals method,
417 * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2).
419 private size_t
expressionHash(Expression e
)
421 import dmd
.root
.ctfloat
: CTFloat
;
422 import dmd
.root
.hash
: calcHash
, mixHash
;
427 return cast(size_t
) e
.isIntegerExp().getInteger();
430 return CTFloat
.hash(e
.isRealExp().value
);
433 auto ce
= e
.isComplexExp();
434 return mixHash(CTFloat
.hash(ce
.toReal
), CTFloat
.hash(ce
.toImaginary
));
437 return cast(size_t
)cast(void*) e
.isIdentifierExp().ident
;
440 return cast(size_t
)cast(void*) e
.isNullExp().type
;
443 return calcHash(e
.isStringExp
.peekData());
447 auto te
= e
.isTupleExp();
449 hash
+= te
.e0 ?
expressionHash(te
.e0
) : 0;
450 foreach (elem
; *te
.exps
)
451 hash
= mixHash(hash
, expressionHash(elem
));
455 case EXP
.arrayLiteral
:
457 auto ae
= e
.isArrayLiteralExp();
459 foreach (i
; 0 .. ae
.elements
.length
)
460 hash
= mixHash(hash
, expressionHash(ae
[i
]));
464 case EXP
.assocArrayLiteral
:
466 auto ae
= e
.isAssocArrayLiteralExp();
468 foreach (i
; 0 .. ae
.keys
.length
)
469 // reduction needs associative op as keys are unsorted (use XOR)
470 hash ^
= mixHash(expressionHash((*ae
.keys
)[i
]), expressionHash((*ae
.values
)[i
]));
474 case EXP
.structLiteral
:
476 auto se
= e
.isStructLiteralExp();
478 foreach (elem
; *se
.elements
)
479 hash
= mixHash(hash
, elem ?
expressionHash(elem
) : 0);
484 return cast(size_t
)cast(void*) e
.isVarExp().var
;
487 return cast(size_t
)cast(void*) e
.isFuncExp().fd
;
490 // no custom equals for this expression
491 assert((&e
.equals
).funcptr
is &RootObject
.equals
);
492 // equals based on identity
493 return cast(size_t
)cast(void*) e
;
497 RootObject
objectSyntaxCopy(RootObject o
)
501 if (Type t
= isType(o
))
502 return t
.syntaxCopy();
503 if (Expression e
= isExpression(o
))
504 return e
.syntaxCopy();
508 extern (C
++) final class Tuple
: RootObject
516 numObjects = The initial number of objects.
518 extern (D
) this(size_t numObjects
)
520 objects
.setDim(numObjects
);
523 // kludge for template.isType()
524 override DYNCAST
dyncast() const
526 return DYNCAST
.tuple
;
529 override const(char)* toChars() const
531 return objects
.toChars();
535 struct TemplatePrevious
537 TemplatePrevious
* prev
;
542 /***********************************************************
543 * [mixin] template Identifier (parameters) [Constraint]
544 * https://dlang.org/spec/template.html
545 * https://dlang.org/spec/template-mixin.html
547 extern (C
++) final class TemplateDeclaration
: ScopeDsymbol
549 import dmd
.root
.array
: Array
;
551 TemplateParameters
* parameters
; // array of TemplateParameter's
552 TemplateParameters
* origParameters
; // originals for Ddoc
554 Expression constraint
;
556 // Hash table to look up TemplateInstance's of this TemplateDeclaration
557 TemplateInstance
[TemplateInstanceBox
] instances
;
559 TemplateDeclaration overnext
; // next overloaded TemplateDeclaration
560 TemplateDeclaration overroot
; // first in overnext list
561 FuncDeclaration funcroot
; // first function in unified overload list
563 Dsymbol onemember
; // if !=null then one member of this template
565 bool literal
; // this template declaration is a literal
566 bool ismixin
; // this is a mixin template declaration
567 bool isstatic
; // this is static template declaration
568 bool isTrivialAliasSeq
; /// matches pattern `template AliasSeq(T...) { alias AliasSeq = T; }`
569 bool isTrivialAlias
; /// matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
570 bool deprecated_
; /// this template declaration is deprecated
571 Visibility visibility
;
573 // threaded list of previous instantiation attempts on stack
574 TemplatePrevious
* previous
;
576 private Expression lastConstraint
; /// the constraint after the last failed evaluation
577 private Array
!Expression lastConstraintNegs
; /// its negative parts
578 private Objects
* lastConstraintTiargs
; /// template instance arguments for `lastConstraint`
580 extern (D
) this(const ref Loc loc
, Identifier ident
, TemplateParameters
* parameters
, Expression constraint
, Dsymbols
* decldefs
, bool ismixin
= false, bool literal
= false)
585 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident
.toChars());
590 for (int i
= 0; i
< parameters
.length
; i
++)
592 TemplateParameter tp
= (*parameters
)[i
];
593 //printf("\tparameter[%d] = %p\n", i, tp);
594 TemplateTypeParameter ttp
= tp
.isTemplateTypeParameter();
597 printf("\tparameter[%d] = %s : %s\n", i
, tp
.ident
.toChars(), ttp
.specType ? ttp
.specType
.toChars() : "");
601 this.parameters
= parameters
;
602 this.origParameters
= parameters
;
603 this.constraint
= constraint
;
604 this.members
= decldefs
;
605 this.literal
= literal
;
606 this.ismixin
= ismixin
;
607 this.isstatic
= true;
608 this.visibility
= Visibility(Visibility
.Kind
.undefined
);
610 // Compute in advance for Ddoc's use
611 // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails.
612 if (!members ||
!ident
)
616 if (!Dsymbol
.oneMembers(members
, &s
, ident
) ||
!s
)
622 /* Set isTrivialAliasSeq if this fits the pattern:
623 * template AliasSeq(T...) { alias AliasSeq = T; }
624 * or set isTrivialAlias if this fits the pattern:
625 * template Alias(T) { alias Alias = qualifiers(T); }
627 if (!(parameters
&& parameters
.length
== 1))
630 auto ad
= s
.isAliasDeclaration();
634 auto ti
= ad
.type
.isTypeIdentifier();
636 if (!ti || ti
.idents
.length
!= 0)
639 if (auto ttp
= (*parameters
)[0].isTemplateTupleParameter())
641 if (ti
.ident
is ttp
.ident
&&
644 //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
645 isTrivialAliasSeq
= true;
648 else if (auto ttp
= (*parameters
)[0].isTemplateTypeParameter())
650 if (ti
.ident
is ttp
.ident
)
652 //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
653 isTrivialAlias
= true;
658 override TemplateDeclaration
syntaxCopy(Dsymbol
)
660 //printf("TemplateDeclaration.syntaxCopy()\n");
661 TemplateParameters
* p
= null;
664 p
= new TemplateParameters(parameters
.length
);
665 foreach (i
, ref param
; *p
)
666 param
= (*parameters
)[i
].syntaxCopy();
668 return new TemplateDeclaration(loc
, ident
, p
, constraint ? constraint
.syntaxCopy() : null, Dsymbol
.arraySyntaxCopy(members
), ismixin
, literal
);
671 /**********************************
672 * Overload existing TemplateDeclaration 'this' with the new one 's'.
673 * Return true if successful; i.e. no conflict.
675 override bool overloadInsert(Dsymbol s
)
679 printf("TemplateDeclaration.overloadInsert('%s')\n", s
.toChars());
681 FuncDeclaration fd
= s
.isFuncDeclaration();
685 return funcroot
.overloadInsert(fd
);
687 return funcroot
.overloadInsert(this);
690 // https://issues.dlang.org/show_bug.cgi?id=15795
691 // if candidate is an alias and its sema is not run then
692 // insertion can fail because the thing it alias is not known
693 if (AliasDeclaration ad
= s
.isAliasDeclaration())
696 aliasSemantic(ad
, s
._scope
);
697 if (ad
.aliassym
&& ad
.aliassym
is this)
700 TemplateDeclaration td
= s
.toAlias().isTemplateDeclaration();
704 TemplateDeclaration pthis
= this;
705 TemplateDeclaration
* ptd
;
706 for (ptd
= &pthis
; *ptd
; ptd
= &(*ptd
).overnext
)
714 printf("\ttrue: no conflict\n");
719 override bool hasStaticCtorOrDtor()
721 return false; // don't scan uninstantiated templates
724 override const(char)* kind() const
726 return (onemember
&& onemember
.isAggregateDeclaration()) ? onemember
.kind() : "template";
729 override const(char)* toChars() const
731 return toCharsMaybeConstraints(true);
734 /****************************
735 * Similar to `toChars`, but does not print the template constraints
737 const(char)* toCharsNoConstraints() const
739 return toCharsMaybeConstraints(false);
742 const(char)* toCharsMaybeConstraints(bool includeConstraints
) const
745 return Dsymbol
.toChars();
750 buf
.writestring(ident
.toString());
752 foreach (i
, const tp
; *parameters
)
755 buf
.writestring(", ");
756 .toCBuffer(tp
, &buf
, &hgs
);
762 const FuncDeclaration fd
= onemember
.isFuncDeclaration();
765 TypeFunction tf
= cast(TypeFunction
)fd
.type
;
766 buf
.writestring(parametersTypeToChars(tf
.parameterList
));
770 if (includeConstraints
&&
773 buf
.writestring(" if (");
774 .toCBuffer(constraint
, &buf
, &hgs
);
778 return buf
.extractChars();
781 override Visibility
visible() pure nothrow @nogc @safe
786 /****************************
787 * Check to see if constraint is satisfied.
789 extern (D
) bool evaluateConstraint(TemplateInstance ti
, Scope
* sc
, Scope
* paramscope
, Objects
* dedargs
, FuncDeclaration fd
)
791 /* Detect recursive attempts to instantiate this template declaration,
792 * https://issues.dlang.org/show_bug.cgi?id=4072
793 * void foo(T)(T x) if (is(typeof(foo(x)))) { }
794 * static assert(!is(typeof(foo(7))));
795 * Recursive attempts are regarded as a constraint failure.
797 /* There's a chicken-and-egg problem here. We don't know yet if this template
798 * instantiation will be a local one (enclosing is set), and we won't know until
799 * after selecting the correct template. Thus, function we're nesting inside
800 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
801 * Workaround the problem by setting a flag to relax the checking on frame errors.
804 for (TemplatePrevious
* p
= previous
; p
; p
= p
.prev
)
806 if (!arrayObjectMatch(p
.dedargs
, dedargs
))
808 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
809 /* It must be a subscope of p.sc, other scope chains are not recursive
811 * the chain of enclosing scopes is broken by paramscope (its enclosing
812 * scope is _scope, but paramscope.callsc is the instantiating scope). So
813 * it's good enough to check the chain of callsc
815 for (Scope
* scx
= paramscope
.callsc
; scx
; scx
= scx
.callsc
)
817 // The first scx might be identical for nested eponymeous templates, e.g.
818 // template foo() { void foo()() {...} }
819 if (scx
== p
.sc
&& scx
!is paramscope
.callsc
)
822 /* BUG: should also check for ref param differences
828 pr
.sc
= paramscope
.callsc
;
829 pr
.dedargs
= dedargs
;
830 previous
= &pr
; // add this to threaded list
832 Scope
* scx
= paramscope
.push(ti
);
836 // Set SCOPE.constraint before declaring function parameters for the static condition
837 // (previously, this was immediately before calling evalStaticCondition), so the
838 // semantic pass knows not to issue deprecation warnings for these throw-away decls.
839 // https://issues.dlang.org/show_bug.cgi?id=21831
840 scx
.flags |
= SCOPE
.constraint
;
845 /* Declare all the function parameters as variables and add them to the scope
846 * Making parameters is similar to FuncDeclaration.semantic3
848 auto tf
= fd
.type
.isTypeFunction();
852 Parameters
* fparameters
= tf
.parameterList
.parameters
;
853 const nfparams
= tf
.parameterList
.length
;
854 foreach (i
, fparam
; tf
.parameterList
)
856 fparam
.storageClass
&= (STC
.IOR | STC
.lazy_ | STC
.final_ | STC
.TYPECTOR | STC
.nodtor
);
857 fparam
.storageClass |
= STC
.parameter
;
858 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nfparams
)
860 fparam
.storageClass |
= STC
.variadic
;
861 /* Don't need to set STC.scope_ because this will only
862 * be evaluated at compile time
866 foreach (fparam
; *fparameters
)
870 // don't add it, if it has no name
871 auto v
= new VarDeclaration(loc
, fparam
.type
, fparam
.ident
, null);
872 fparam
.storageClass |
= STC
.parameter
;
873 v
.storage_class
= fparam
.storageClass
;
874 v
.dsymbolSemantic(scx
);
876 ti
.symtab
= new DsymbolTable();
878 error("parameter `%s.%s` is already defined", toChars(), v
.toChars());
883 fd
.storage_class |
= STC
.static_
;
887 lastConstraint
= constraint
.syntaxCopy();
888 lastConstraintTiargs
= ti
.tiargs
;
889 lastConstraintNegs
.setDim(0);
891 import dmd
.staticcond
;
893 assert(ti
.inst
is null);
894 ti
.inst
= ti
; // temporary instantiation to enable genIdent()
896 const bool result
= evalStaticCondition(scx
, constraint
, lastConstraint
, errors
, &lastConstraintNegs
);
897 if (result || errors
)
899 lastConstraint
= null;
900 lastConstraintTiargs
= null;
901 lastConstraintNegs
.setDim(0);
906 previous
= pr
.prev
; // unlink from threaded list
912 /****************************
913 * Destructively get the error message from the last constraint evaluation
915 * tip = tip to show after printing all overloads
917 const(char)* getConstraintEvalError(ref const(char)* tip
)
919 import dmd
.staticcond
;
921 // there will be a full tree view in verbose mode, and more compact list in the usual
922 const full
= global
.params
.verbose
;
924 const msg
= visualizeStaticCondition(constraint
, lastConstraint
, lastConstraintNegs
[], full
, count
);
927 lastConstraint
= null;
928 lastConstraintTiargs
= null;
929 lastConstraintNegs
.setDim(0);
936 assert(parameters
&& lastConstraintTiargs
);
937 if (parameters
.length
> 0)
939 formatParamsWithTiargs(*lastConstraintTiargs
, buf
);
944 // choosing singular/plural
945 const s
= (count
== 1) ?
946 " must satisfy the following constraint:" :
947 " must satisfy one of the following constraints:";
952 buf
.writestring(msg
);
957 buf
.writestring(" whose parameters have the following constraints:");
959 const sep
= " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
960 buf
.writestring(sep
);
964 buf
.writestring(msg
);
966 buf
.writestring(sep
);
967 tip
= "not satisfied constraints are marked with `>`";
969 return buf
.extractChars();
972 private void formatParamsWithTiargs(ref Objects tiargs
, ref OutBuffer buf
)
974 buf
.writestring(" with `");
976 // write usual arguments line-by-line
977 // skips trailing default ones - they are not present in `tiargs`
978 const bool variadic
= isVariadic() !is null;
979 const end
= cast(int)parameters
.length
- (variadic ?
1 : 0);
981 for (; i
< tiargs
.length
&& i
< end
; i
++)
987 buf
.writestring(" ");
989 write(buf
, (*parameters
)[i
]);
990 buf
.writestring(" = ");
991 write(buf
, tiargs
[i
]);
993 // write remaining variadic arguments on the last line
1000 buf
.writestring(" ");
1002 write(buf
, (*parameters
)[end
]);
1003 buf
.writestring(" = ");
1005 if (cast(int)tiargs
.length
- end
> 0)
1007 write(buf
, tiargs
[end
]);
1008 foreach (j
; parameters
.length
.. tiargs
.length
)
1010 buf
.writestring(", ");
1011 write(buf
, tiargs
[j
]);
1019 /******************************
1020 * Create a scope for the parameters of the TemplateInstance
1021 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
1023 * If paramsym is null a new ScopeDsymbol is used in place of
1026 * ti = the TemplateInstance whose parameters to generate the scope for.
1027 * sc = the parent scope of ti
1029 * a scope for the parameters of ti
1031 Scope
* scopeForTemplateParameters(TemplateInstance ti
, Scope
* sc
)
1033 ScopeDsymbol paramsym
= new ScopeDsymbol();
1034 paramsym
.parent
= _scope
.parent
;
1035 Scope
* paramscope
= _scope
.push(paramsym
);
1036 paramscope
.tinst
= ti
;
1037 paramscope
.minst
= sc
.minst
;
1038 paramscope
.callsc
= sc
;
1043 /***************************************
1044 * Given that ti is an instance of this TemplateDeclaration,
1045 * deduce the types of the parameters to this, and store
1046 * those deduced types in dedtypes[].
1048 * flag 1: don't do semantic() because of dummy types
1049 * 2: don't change types in matchArg()
1051 * dedtypes deduced arguments
1052 * Return match level.
1054 extern (D
) MATCH
matchWithInstance(Scope
* sc
, TemplateInstance ti
, Objects
* dedtypes
, ArgumentList argumentList
, int flag
)
1059 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti
.toChars(), flag
);
1063 printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes
.length
, parameters
.length
);
1064 if (ti
.tiargs
.length
)
1065 printf("ti.tiargs.length = %d, [0] = %p\n", ti
.tiargs
.length
, (*ti
.tiargs
)[0]);
1071 printf(" no match\n");
1073 return MATCH
.nomatch
;
1076 size_t dedtypes_dim
= dedtypes
.length
;
1081 return MATCH
.nomatch
;
1083 size_t parameters_dim
= parameters
.length
;
1084 int variadic
= isVariadic() !is null;
1086 // If more arguments than parameters, no match
1087 if (ti
.tiargs
.length
> parameters_dim
&& !variadic
)
1091 printf(" no match: more arguments than parameters\n");
1093 return MATCH
.nomatch
;
1096 assert(dedtypes_dim
== parameters_dim
);
1097 assert(dedtypes_dim
>= ti
.tiargs
.length || variadic
);
1101 // Set up scope for template parameters
1102 Scope
* paramscope
= scopeForTemplateParameters(ti
,sc
);
1104 // Attempt type deduction
1106 for (size_t i
= 0; i
< dedtypes_dim
; i
++)
1109 TemplateParameter tp
= (*parameters
)[i
];
1112 //printf("\targument [%d]\n", i);
1115 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
1116 TemplateTypeParameter ttp
= tp
.isTemplateTypeParameter();
1118 printf("\tparameter[%d] is %s : %s\n", i
, tp
.ident
.toChars(), ttp
.specType ? ttp
.specType
.toChars() : "");
1121 m2
= tp
.matchArg(ti
.loc
, paramscope
, ti
.tiargs
, i
, parameters
, dedtypes
, &sparam
);
1122 //printf("\tm2 = %d\n", m2);
1123 if (m2
== MATCH
.nomatch
)
1127 printf("\tmatchArg() for parameter %i failed\n", i
);
1136 sparam
.dsymbolSemantic(paramscope
);
1137 if (!paramscope
.insert(sparam
)) // TODO: This check can make more early
1139 // in TemplateDeclaration.semantic, and
1140 // then we don't need to make sparam if flags == 0
1147 /* Any parameter left without a type gets the type of
1148 * its corresponding arg
1150 foreach (i
, ref dedtype
; *dedtypes
)
1154 assert(i
< ti
.tiargs
.length
);
1155 dedtype
= cast(Type
)(*ti
.tiargs
)[i
];
1160 if (m
> MATCH
.nomatch
&& constraint
&& !flag
)
1162 if (ti
.hasNestedArgs(ti
.tiargs
, this.isstatic
)) // TODO: should gag error
1163 ti
.parent
= ti
.enclosing
;
1165 ti
.parent
= this.parent
;
1167 // Similar to doHeaderInstantiation
1168 FuncDeclaration fd
= onemember ? onemember
.isFuncDeclaration() : null;
1171 TypeFunction tf
= fd
.type
.isTypeFunction().syntaxCopy();
1172 if (argumentList
.hasNames
)
1174 Expressions
* fargs
= argumentList
.arguments
;
1175 // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
1177 // return nomatch();
1179 fd
= new FuncDeclaration(fd
.loc
, fd
.endloc
, fd
.ident
, fd
.storage_class
, tf
);
1181 fd
.inferRetType
= true;
1183 // Shouldn't run semantic on default arguments and return type.
1184 foreach (ref param
; *tf
.parameterList
.parameters
)
1185 param
.defaultArg
= null;
1188 tf
.incomplete
= true;
1190 // Resolve parameter types and 'auto ref's.
1192 uint olderrors
= global
.startGagging();
1193 fd
.type
= tf
.typeSemantic(loc
, paramscope
);
1194 global
.endGagging(olderrors
);
1195 if (fd
.type
.ty
!= Tfunction
)
1197 fd
.originalType
= fd
.type
; // for mangling
1200 // TODO: dedtypes => ti.tiargs ?
1201 if (!evaluateConstraint(ti
, sc
, paramscope
, dedtypes
, fd
))
1207 // Print out the results
1208 printf("--------------------------\n");
1209 printf("template %s\n", toChars());
1210 printf("instance %s\n", ti
.toChars());
1211 if (m
> MATCH
.nomatch
)
1213 for (size_t i
= 0; i
< dedtypes_dim
; i
++)
1215 TemplateParameter tp
= (*parameters
)[i
];
1218 if (i
< ti
.tiargs
.length
)
1219 oarg
= (*ti
.tiargs
)[i
];
1222 tp
.print(oarg
, (*dedtypes
)[i
]);
1230 printf(" match = %d\n", m
);
1236 printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti
.toChars(), m
);
1241 /********************************************
1242 * Determine partial specialization order of 'this' vs td2.
1244 * match this is at least as specialized as td2
1245 * 0 td2 is more specialized than this
1247 MATCH
leastAsSpecialized(Scope
* sc
, TemplateDeclaration td2
, ArgumentList argumentList
)
1249 enum LOG_LEASTAS
= 0;
1250 static if (LOG_LEASTAS
)
1252 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2
.toChars());
1255 /* This works by taking the template parameters to this template
1256 * declaration and feeding them to td2 as if it were a template
1258 * If it works, then this template is at least as specialized
1262 // Set type arguments to dummy template instance to be types
1263 // generated from the parameters to this template declaration
1264 auto tiargs
= new Objects();
1265 tiargs
.reserve(parameters
.length
);
1266 foreach (tp
; *parameters
)
1270 RootObject p
= tp
.dummyArg();
1271 if (!p
) //TemplateTupleParameter
1276 scope TemplateInstance ti
= new TemplateInstance(Loc
.initial
, ident
, tiargs
); // create dummy template instance
1278 // Temporary Array to hold deduced types
1279 Objects dedtypes
= Objects(td2
.parameters
.length
);
1281 // Attempt a type deduction
1282 MATCH m
= td2
.matchWithInstance(sc
, ti
, &dedtypes
, argumentList
, 1);
1283 if (m
> MATCH
.nomatch
)
1285 /* A non-variadic template is more specialized than a
1288 TemplateTupleParameter tp
= isVariadic();
1289 if (tp
&& !tp
.dependent
&& !td2
.isVariadic())
1292 static if (LOG_LEASTAS
)
1294 printf(" matches %d, so is least as specialized\n", m
);
1299 static if (LOG_LEASTAS
)
1301 printf(" doesn't match, so is not as specialized\n");
1303 return MATCH
.nomatch
;
1306 /*************************************************
1307 * Match function arguments against a specific template function.
1310 * sc instantiation scope
1312 * tthis 'this' argument if !NULL
1313 * argumentList arguments to function
1315 * fd Partially instantiated function declaration
1316 * ti.tdtypes Expression/Type deduced template arguments
1318 * match pair of initial and inferred template arguments
1320 extern (D
) MATCHpair
deduceFunctionTemplateMatch(TemplateInstance ti
, Scope
* sc
, ref FuncDeclaration fd
, Type tthis
, ArgumentList argumentList
)
1324 size_t ntargs
; // array size of tiargs
1325 size_t fptupindex
= IDX_NOTFOUND
;
1326 MATCH match
= MATCH
.exact
;
1327 MATCH matchTiargs
= MATCH
.exact
;
1328 ParameterList fparameters
; // function parameter list
1329 VarArg fvarargs
; // function varargs
1331 size_t inferStart
= 0;
1333 Loc instLoc
= ti
.loc
;
1334 Objects
* tiargs
= ti
.tiargs
;
1335 auto dedargs
= new Objects(parameters
.length
);
1336 Objects
* dedtypes
= &ti
.tdtypes
; // for T:T*, the dedargs is the T*, dedtypes is the T
1340 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
1341 for (size_t i
= 0; i
< (fargs ? fargs
.length
: 0); i
++)
1343 Expression e
= (*fargs
)[i
];
1344 printf("\tfarg[%d] is %s, type is %s\n", cast(int) i
, e
.toChars(), e
.type
.toChars());
1346 printf("fd = %s\n", fd
.toChars());
1347 printf("fd.type = %s\n", fd
.type
.toChars());
1349 printf("tthis = %s\n", tthis
.toChars());
1356 dedtypes
.setDim(parameters
.length
);
1359 if (errors || fd
.errors
)
1360 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
1362 // Set up scope for parameters
1363 Scope
* paramscope
= scopeForTemplateParameters(ti
,sc
);
1368 //printf("\tnomatch\n");
1369 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
1372 MATCHpair
matcherror()
1374 // todo: for the future improvement
1376 //printf("\terror\n");
1377 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
1379 // Mark the parameter scope as deprecated if the templated
1380 // function is deprecated (since paramscope.enclosing is the
1381 // calling scope already)
1382 paramscope
.stc |
= fd
.storage_class
& STC
.deprecated_
;
1384 TemplateTupleParameter tp
= isVariadic();
1385 Tuple declaredTuple
= null;
1389 for (size_t i
= 0; i
< dedargs
.length
; i
++)
1391 printf("\tdedarg[%d] = ", i
);
1392 RootObject oarg
= (*dedargs
)[i
];
1394 printf("%s", oarg
.toChars());
1402 // Set initial template arguments
1403 ntargs
= tiargs
.length
;
1404 size_t n
= parameters
.length
;
1412 /* The extra initial template arguments
1413 * now form the tuple argument.
1415 auto t
= new Tuple(ntargs
- n
);
1416 assert(parameters
.length
);
1417 (*dedargs
)[parameters
.length
- 1] = t
;
1419 for (size_t i
= 0; i
< t
.objects
.length
; i
++)
1421 t
.objects
[i
] = (*tiargs
)[n
+ i
];
1423 declareParameter(paramscope
, tp
, t
);
1429 memcpy(dedargs
.tdata(), tiargs
.tdata(), n
* (*dedargs
.tdata()).sizeof
);
1431 for (size_t i
= 0; i
< n
; i
++)
1433 assert(i
< parameters
.length
);
1434 Declaration sparam
= null;
1435 MATCH m
= (*parameters
)[i
].matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, &sparam
);
1436 //printf("\tdeduceType m = %d\n", m);
1437 if (m
== MATCH
.nomatch
)
1439 if (m
< matchTiargs
)
1442 sparam
.dsymbolSemantic(paramscope
);
1443 if (!paramscope
.insert(sparam
))
1446 if (n
< parameters
.length
&& !declaredTuple
)
1451 inferStart
= parameters
.length
;
1452 //printf("tiargs matchTiargs = %d\n", matchTiargs);
1456 for (size_t i
= 0; i
< dedargs
.length
; i
++)
1458 printf("\tdedarg[%d] = ", i
);
1459 RootObject oarg
= (*dedargs
)[i
];
1461 printf("%s", oarg
.toChars());
1466 fparameters
= fd
.getParameterList();
1467 nfparams
= fparameters
.length
; // number of function parameters
1468 nfargs
= argumentList
.length
; // number of function arguments
1469 if (argumentList
.hasNames
)
1470 return matcherror(); // TODO: resolve named args
1471 Expressions
* fargs
= argumentList
.arguments
; // TODO: resolve named args
1473 /* Check for match of function arguments with variadic template
1474 * parameter, such as:
1476 * void foo(T, A...)(T t, A a);
1477 * void main() { foo(1,2,3); }
1479 if (tp
) // if variadic
1481 // TemplateTupleParameter always makes most lesser matching.
1482 matchTiargs
= MATCH
.convert
;
1484 if (nfparams
== 0 && nfargs
!= 0) // if no function parameters
1488 auto t
= new Tuple();
1489 //printf("t = %p\n", t);
1490 (*dedargs
)[parameters
.length
- 1] = t
;
1491 declareParameter(paramscope
, tp
, t
);
1497 /* Figure out which of the function parameters matches
1498 * the tuple template parameter. Do this by matching
1500 * Set the index of this function parameter to fptupindex.
1502 for (fptupindex
= 0; fptupindex
< nfparams
; fptupindex
++)
1504 auto fparam
= (*fparameters
.parameters
)[fptupindex
]; // fparameters[fptupindex] ?
1505 if (fparam
.type
.ty
!= Tident
)
1507 TypeIdentifier tid
= cast(TypeIdentifier
)fparam
.type
;
1508 if (!tp
.ident
.equals(tid
.ident
) || tid
.idents
.length
)
1511 if (fparameters
.varargs
!= VarArg
.none
) // variadic function doesn't
1512 return nomatch(); // go with variadic template
1516 fptupindex
= IDX_NOTFOUND
;
1521 if (toParent().isModule())
1525 bool hasttp
= false;
1527 // Match 'tthis' to any TemplateThisParameter's
1528 foreach (param
; *parameters
)
1530 if (auto ttp
= param
.isTemplateThisParameter())
1534 Type t
= new TypeIdentifier(Loc
.initial
, ttp
.ident
);
1535 MATCH m
= deduceType(tthis
, paramscope
, t
, parameters
, dedtypes
);
1536 if (m
== MATCH
.nomatch
)
1539 match
= m
; // pick worst match
1543 // Match attributes of tthis against attributes of fd
1544 if (fd
.type
&& !fd
.isCtorDeclaration() && !(_scope
.stc & STC
.static_
))
1546 StorageClass
stc = _scope
.stc | fd
.storage_class2
;
1547 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
1549 while (p
.isTemplateDeclaration() || p
.isTemplateInstance())
1551 AggregateDeclaration ad
= p
.isAggregateDeclaration();
1553 stc |
= ad
.storage_class
;
1555 ubyte mod
= fd
.type
.mod
;
1556 if (stc & STC
.immutable_
)
1557 mod
= MODFlags
.immutable_
;
1560 if (stc & (STC
.shared_ | STC
.synchronized_
))
1561 mod |
= MODFlags
.shared_
;
1562 if (stc & STC
.const_
)
1563 mod |
= MODFlags
.const_
;
1565 mod |
= MODFlags
.wild
;
1568 ubyte thismod
= tthis
.mod
;
1570 mod
= MODmerge(thismod
, mod
);
1571 MATCH m
= MODmethodConv(thismod
, mod
);
1572 if (m
== MATCH
.nomatch
)
1579 // Loop through the function parameters
1581 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
1582 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
1584 size_t nfargs2
= nfargs
; // nfargs + supplied defaultArgs
1585 for (size_t parami
= 0; parami
< nfparams
; parami
++)
1587 Parameter fparam
= fparameters
[parami
];
1589 // Apply function parameter storage classes to parameter types
1590 Type prmtype
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1594 /* See function parameters which wound up
1595 * as part of a template tuple parameter.
1597 if (fptupindex
!= IDX_NOTFOUND
&& parami
== fptupindex
)
1599 assert(prmtype
.ty
== Tident
);
1600 TypeIdentifier tid
= cast(TypeIdentifier
)prmtype
;
1603 /* The types of the function arguments
1604 * now form the tuple argument.
1606 declaredTuple
= new Tuple();
1607 (*dedargs
)[parameters
.length
- 1] = declaredTuple
;
1609 /* Count function parameters with no defaults following a tuple parameter.
1610 * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
1613 for (size_t j
= parami
+ 1; j
< nfparams
; j
++)
1615 Parameter p
= fparameters
[j
];
1620 if (!reliesOnTemplateParameters(p
.type
, (*parameters
)[inferStart
.. parameters
.length
]))
1622 Type pt
= p
.type
.syntaxCopy().typeSemantic(fd
.loc
, paramscope
);
1623 rem
+= pt
.ty
== Ttuple ?
(cast(TypeTuple
)pt
).arguments
.length
: 1;
1631 if (nfargs2
- argi
< rem
)
1633 declaredTuple
.objects
.setDim(nfargs2
- argi
- rem
);
1634 for (size_t i
= 0; i
< declaredTuple
.objects
.length
; i
++)
1636 farg
= (*fargs
)[argi
+ i
];
1638 // Check invalid arguments to detect errors early.
1639 if (farg
.op
== EXP
.error || farg
.type
.ty
== Terror
)
1642 if (!fparam
.isLazy() && farg
.type
.ty
== Tvoid
)
1647 if (ubyte wm
= deduceWildHelper(farg
.type
, &tt
, tid
))
1654 m
= deduceTypeHelper(farg
.type
, &tt
, tid
);
1656 if (m
== MATCH
.nomatch
)
1661 /* Remove top const for dynamic array types and pointer types
1663 if ((tt
.ty
== Tarray || tt
.ty
== Tpointer
) && !tt
.isMutable() && (!(fparam
.storageClass
& STC
.ref_
) ||
(fparam
.storageClass
& STC
.auto_
) && !farg
.isLvalue()))
1665 tt
= tt
.mutableOf();
1667 declaredTuple
.objects
[i
] = tt
;
1669 declareParameter(paramscope
, tp
, declaredTuple
);
1673 // https://issues.dlang.org/show_bug.cgi?id=6810
1674 // If declared tuple is not a type tuple,
1675 // it cannot be function parameter types.
1676 for (size_t i
= 0; i
< declaredTuple
.objects
.length
; i
++)
1678 if (!isType(declaredTuple
.objects
[i
]))
1682 assert(declaredTuple
);
1683 argi
+= declaredTuple
.objects
.length
;
1687 // If parameter type doesn't depend on inferred template parameters,
1688 // semantic it to get actual type.
1689 if (!reliesOnTemplateParameters(prmtype
, (*parameters
)[inferStart
.. parameters
.length
]))
1691 // should copy prmtype to avoid affecting semantic result
1692 prmtype
= prmtype
.syntaxCopy().typeSemantic(fd
.loc
, paramscope
);
1694 if (prmtype
.ty
== Ttuple
)
1696 TypeTuple tt
= cast(TypeTuple
)prmtype
;
1697 size_t tt_dim
= tt
.arguments
.length
;
1698 for (size_t j
= 0; j
< tt_dim
; j
++, ++argi
)
1700 Parameter p
= (*tt
.arguments
)[j
];
1701 if (j
== tt_dim
- 1 && fparameters
.varargs
== VarArg
.typesafe
&&
1702 parami
+ 1 == nfparams
&& argi
< nfargs
)
1712 // https://issues.dlang.org/show_bug.cgi?id=19888
1713 if (fparam
.defaultArg
)
1718 farg
= (*fargs
)[argi
];
1719 if (!farg
.implicitConvTo(p
.type
))
1726 if (argi
>= nfargs
) // if not enough arguments
1728 if (!fparam
.defaultArg
)
1731 /* https://issues.dlang.org/show_bug.cgi?id=2803
1732 * Before the starting of type deduction from the function
1733 * default arguments, set the already deduced parameters into paramscope.
1734 * It's necessary to avoid breaking existing acceptable code. Cases:
1736 * 1. Already deduced template parameters can appear in fparam.defaultArg:
1737 * auto foo(A, B)(A a, B b = A.stringof);
1739 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
1741 * 2. If prmtype depends on default-specified template parameter, the
1742 * default type should be preferred.
1743 * auto foo(N = size_t, R)(R r, N start = 0)
1745 * // at fparam `N start = 0`, N should be 'size_t' before
1746 * // the deduction result from fparam.defaultArg.
1750 foreach (ref dedtype
; *dedtypes
)
1752 Type at
= isType(dedtype
);
1753 if (at
&& at
.ty
== Tnone
)
1755 TypeDeduced xt
= cast(TypeDeduced
)at
;
1756 dedtype
= xt
.tded
; // 'unbox'
1759 for (size_t i
= ntargs
; i
< dedargs
.length
; i
++)
1761 TemplateParameter tparam
= (*parameters
)[i
];
1763 RootObject oarg
= (*dedargs
)[i
];
1764 RootObject oded
= (*dedtypes
)[i
];
1770 if (tparam
.specialization() ||
!tparam
.isTemplateTypeParameter())
1772 /* The specialization can work as long as afterwards
1775 (*dedargs
)[i
] = oded
;
1776 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, null);
1777 //printf("m2 = %d\n", m2);
1778 if (m2
== MATCH
.nomatch
)
1780 if (m2
< matchTiargs
)
1781 matchTiargs
= m2
; // pick worst match
1782 if (!(*dedtypes
)[i
].equals(oded
))
1783 error("specialization not allowed for deduced parameter `%s`", tparam
.ident
.toChars());
1787 if (MATCH
.convert
< matchTiargs
)
1788 matchTiargs
= MATCH
.convert
;
1790 (*dedargs
)[i
] = declareParameter(paramscope
, tparam
, oded
);
1794 oded
= tparam
.defaultArg(instLoc
, paramscope
);
1796 (*dedargs
)[i
] = declareParameter(paramscope
, tparam
, oded
);
1802 /* If prmtype does not depend on any template parameters:
1804 * auto foo(T)(T v, double x = 0);
1806 * // at fparam == 'double x = 0'
1808 * or, if all template parameters in the prmtype are already deduced:
1810 * auto foo(R)(R range, ElementType!R sum = 0);
1812 * // at fparam == 'ElementType!R sum = 0'
1814 * Deducing prmtype from fparam.defaultArg is not necessary.
1816 if (prmtype
.deco || prmtype
.syntaxCopy().trySemantic(loc
, paramscope
))
1822 // Deduce prmtype from the defaultArg.
1823 farg
= fparam
.defaultArg
.syntaxCopy();
1824 farg
= farg
.expressionSemantic(paramscope
);
1825 farg
= resolveProperties(paramscope
, farg
);
1829 farg
= (*fargs
)[argi
];
1832 // Check invalid arguments to detect errors early.
1833 if (farg
.op
== EXP
.error || farg
.type
.ty
== Terror
)
1840 printf("\tfarg.type = %s\n", farg
.type
.toChars());
1841 printf("\tfparam.type = %s\n", prmtype
.toChars());
1843 Type argtype
= farg
.type
;
1845 if (!fparam
.isLazy() && argtype
.ty
== Tvoid
&& farg
.op
!= EXP
.function_
)
1848 // https://issues.dlang.org/show_bug.cgi?id=12876
1849 // Optimize argument to allow CT-known length matching
1850 farg
= farg
.optimize(WANTvalue
, fparam
.isReference());
1851 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
1853 RootObject oarg
= farg
;
1854 if ((fparam
.storageClass
& STC
.ref_
) && (!(fparam
.storageClass
& STC
.auto_
) || farg
.isLvalue()))
1856 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
1859 if (argtype
.ty
== Tarray
&& (prmtype
.ty
== Tsarray || prmtype
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)prmtype
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
1861 if (farg
.op
== EXP
.string_
)
1863 StringExp se
= cast(StringExp
)farg
;
1864 argtype
= se
.type
.nextOf().sarrayOf(se
.len
);
1866 else if (farg
.op
== EXP
.arrayLiteral
)
1868 ArrayLiteralExp ae
= cast(ArrayLiteralExp
)farg
;
1869 argtype
= ae
.type
.nextOf().sarrayOf(ae
.elements
.length
);
1871 else if (farg
.op
== EXP
.slice
)
1873 SliceExp se
= cast(SliceExp
)farg
;
1874 if (Type tsa
= toStaticArrayType(se
))
1881 else if ((fparam
.storageClass
& STC
.out_
) == 0 && (argtype
.ty
== Tarray || argtype
.ty
== Tpointer
) && templateParameterLookup(prmtype
, parameters
) != IDX_NOTFOUND
&& (cast(TypeIdentifier
)prmtype
).idents
.length
== 0)
1883 /* The farg passing to the prmtype always make a copy. Therefore,
1884 * we can shrink the set of the deduced type arguments for prmtype
1885 * by adjusting top-qualifier of the argtype.
1887 * prmtype argtype ta
1888 * T <- const(E)[] const(E)[]
1889 * T <- const(E[]) const(E)[]
1890 * qualifier(T) <- const(E)[] const(E[])
1891 * qualifier(T) <- const(E[]) const(E[])
1893 Type ta
= argtype
.castMod(prmtype
.mod ? argtype
.nextOf().mod
: 0);
1896 Expression ea
= farg
.copy();
1902 if (fparameters
.varargs
== VarArg
.typesafe
&& parami
+ 1 == nfparams
&& argi
+ 1 < nfargs
)
1906 MATCH m
= deduceType(oarg
, paramscope
, prmtype
, parameters
, dedtypes
, &wm
, inferStart
);
1907 //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
1910 /* If no match, see if the argument can be matched by using
1911 * implicit conversions.
1913 if (m
== MATCH
.nomatch
&& prmtype
.deco
)
1914 m
= farg
.implicitConvTo(prmtype
);
1916 if (m
== MATCH
.nomatch
)
1918 AggregateDeclaration ad
= isAggregate(farg
.type
);
1919 if (ad
&& ad
.aliasthis
&& !isRecursiveAliasThis(att
, argtype
))
1921 // https://issues.dlang.org/show_bug.cgi?id=12537
1922 // The isRecursiveAliasThis() call above
1924 /* If a semantic error occurs while doing alias this,
1925 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
1926 * just regard it as not a match.
1928 * We also save/restore sc.func.flags to avoid messing up
1929 * attribute inference in the evaluation.
1931 const oldflags
= sc
.func ? sc
.func
.flags
: 0;
1932 auto e
= resolveAliasThis(sc
, farg
, true);
1934 sc
.func
.flags
= oldflags
;
1943 if (m
> MATCH
.nomatch
&& (fparam
.storageClass
& (STC
.ref_ | STC
.auto_
)) == STC
.ref_
)
1945 if (!farg
.isLvalue())
1947 if ((farg
.op
== EXP
.string_ || farg
.op
== EXP
.slice
) && (prmtype
.ty
== Tsarray || prmtype
.ty
== Taarray
))
1949 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1951 else if (global
.params
.rvalueRefParam
== FeatureState
.enabled
)
1953 // Allow implicit conversion to ref
1959 if (m
> MATCH
.nomatch
&& (fparam
.storageClass
& STC
.out_
))
1961 if (!farg
.isLvalue())
1963 if (!farg
.type
.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1966 if (m
== MATCH
.nomatch
&& fparam
.isLazy() && prmtype
.ty
== Tvoid
&& farg
.type
.ty
!= Tvoid
)
1968 if (m
!= MATCH
.nomatch
)
1971 match
= m
; // pick worst match
1978 /* The following code for variadic arguments closely
1979 * matches TypeFunction.callMatch()
1981 if (!(fparameters
.varargs
== VarArg
.typesafe
&& parami
+ 1 == nfparams
))
1984 /* Check for match with function parameter T...
1986 Type tb
= prmtype
.toBasetype();
1989 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1993 // Perhaps we can do better with this, see TypeFunction.callMatch()
1994 if (tb
.ty
== Tsarray
)
1996 TypeSArray tsa
= cast(TypeSArray
)tb
;
1997 dinteger_t sz
= tsa
.dim
.toInteger();
1998 if (sz
!= nfargs
- argi
)
2001 else if (tb
.ty
== Taarray
)
2003 TypeAArray taa
= cast(TypeAArray
)tb
;
2004 Expression dim
= new IntegerExp(instLoc
, nfargs
- argi
, Type
.tsize_t
);
2006 size_t i
= templateParameterLookup(taa
.index
, parameters
);
2007 if (i
== IDX_NOTFOUND
)
2014 uint errors
= global
.startGagging();
2015 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
2016 * The parameter isn't part of the template
2017 * ones, let's try to find it in the
2018 * instantiation scope 'sc' and the one
2019 * belonging to the template itself. */
2021 taa
.index
.resolve(instLoc
, sco
, e
, t
, s
);
2025 taa
.index
.resolve(instLoc
, sco
, e
, t
, s
);
2027 global
.endGagging(errors
);
2032 e
= e
.ctfeInterpret();
2033 e
= e
.implicitCastTo(sco
, Type
.tsize_t
);
2034 e
= e
.optimize(WANTvalue
);
2040 // This code matches code in TypeInstance.deduceType()
2041 TemplateParameter tprm
= (*parameters
)[i
];
2042 TemplateValueParameter tvp
= tprm
.isTemplateValueParameter();
2045 Expression e
= cast(Expression
)(*dedtypes
)[i
];
2053 Type vt
= tvp
.valType
.typeSemantic(Loc
.initial
, sc
);
2054 MATCH m
= dim
.implicitConvTo(vt
);
2055 if (m
== MATCH
.nomatch
)
2057 (*dedtypes
)[i
] = dim
;
2065 TypeArray ta
= cast(TypeArray
)tb
;
2066 Type tret
= fparam
.isLazyArray();
2067 for (; argi
< nfargs
; argi
++)
2069 Expression arg
= (*fargs
)[argi
];
2073 /* If lazy array of delegates,
2074 * convert arg(s) to delegate(s)
2078 if (ta
.next
.equals(arg
.type
))
2084 m
= arg
.implicitConvTo(tret
);
2085 if (m
== MATCH
.nomatch
)
2087 if (tret
.toBasetype().ty
== Tvoid
)
2095 m
= deduceType(arg
, paramscope
, ta
.next
, parameters
, dedtypes
, &wm
, inferStart
);
2098 if (m
== MATCH
.nomatch
)
2114 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
2115 if (argi
!= nfargs2
&& fparameters
.varargs
== VarArg
.none
)
2120 foreach (ref dedtype
; *dedtypes
)
2122 Type at
= isType(dedtype
);
2127 TypeDeduced xt
= cast(TypeDeduced
)at
;
2128 at
= xt
.tded
; // 'unbox'
2130 dedtype
= at
.merge2();
2133 for (size_t i
= ntargs
; i
< dedargs
.length
; i
++)
2135 TemplateParameter tparam
= (*parameters
)[i
];
2136 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
2138 /* For T:T*, the dedargs is the T*, dedtypes is the T
2139 * But for function templates, we really need them to match
2141 RootObject oarg
= (*dedargs
)[i
];
2142 RootObject oded
= (*dedtypes
)[i
];
2143 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
2144 //if (oarg) printf("oarg: %s\n", oarg.toChars());
2145 //if (oded) printf("oded: %s\n", oded.toChars());
2151 if (tparam
.specialization() ||
!tparam
.isTemplateTypeParameter())
2153 /* The specialization can work as long as afterwards
2156 (*dedargs
)[i
] = oded
;
2157 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, null);
2158 //printf("m2 = %d\n", m2);
2159 if (m2
== MATCH
.nomatch
)
2161 if (m2
< matchTiargs
)
2162 matchTiargs
= m2
; // pick worst match
2163 if (!(*dedtypes
)[i
].equals(oded
))
2164 error("specialization not allowed for deduced parameter `%s`", tparam
.ident
.toChars());
2168 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
2169 if (MATCH
.convert
< matchTiargs
)
2170 matchTiargs
= MATCH
.convert
;
2175 oded
= tparam
.defaultArg(instLoc
, paramscope
);
2178 // if tuple parameter and
2179 // tuple parameter was not in function parameter list and
2180 // we're one or more arguments short (i.e. no tuple argument)
2182 fptupindex
== IDX_NOTFOUND
&&
2183 ntargs
<= dedargs
.length
- 1)
2185 // make tuple argument an empty tuple
2192 return matcherror();
2195 /* At the template parameter T, the picked default template argument
2196 * X!int should be matched to T in order to deduce dependent
2197 * template parameter A.
2198 * auto foo(T : X!A = X!int, A...)() { ... }
2199 * foo(); // T <-- X!int, A <-- (int)
2201 if (tparam
.specialization())
2203 (*dedargs
)[i
] = oded
;
2204 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, null);
2205 //printf("m2 = %d\n", m2);
2206 if (m2
== MATCH
.nomatch
)
2208 if (m2
< matchTiargs
)
2209 matchTiargs
= m2
; // pick worst match
2210 if (!(*dedtypes
)[i
].equals(oded
))
2211 error("specialization not allowed for deduced parameter `%s`", tparam
.ident
.toChars());
2214 oded
= declareParameter(paramscope
, tparam
, oded
);
2215 (*dedargs
)[i
] = oded
;
2218 /* https://issues.dlang.org/show_bug.cgi?id=7469
2219 * As same as the code for 7469 in findBestMatch,
2220 * expand a Tuple in dedargs to normalize template arguments.
2222 if (auto d
= dedargs
.length
)
2224 if (auto va
= isTuple((*dedargs
)[d
- 1]))
2226 dedargs
.setDim(d
- 1);
2227 dedargs
.insert(d
- 1, &va
.objects
);
2230 ti
.tiargs
= dedargs
; // update to the normalized template arguments.
2232 // Partially instantiate function for constraint and fd.leastAsSpecialized()
2234 assert(paramscope
.scopesym
);
2235 Scope
* sc2
= _scope
;
2236 sc2
= sc2
.push(paramscope
.scopesym
);
2240 sc2
.minst
= sc
.minst
;
2241 sc2
.stc |
= fd
.storage_class
& STC
.deprecated_
;
2243 fd
= doHeaderInstantiation(ti
, sc2
, fd
, tthis
, fargs
);
2254 if (!evaluateConstraint(ti
, sc
, paramscope
, dedargs
, fd
))
2260 for (size_t i
= 0; i
< dedargs
.length
; i
++)
2262 RootObject o
= (*dedargs
)[i
];
2263 printf("\tdedargs[%d] = %d, %s\n", i
, o
.dyncast(), o
.toChars());
2268 //printf("\tmatch %d\n", match);
2269 return MATCHpair(matchTiargs
, match
);
2272 /**************************************************
2273 * Declare template parameter tp with value o, and install it in the scope sc.
2275 RootObject
declareParameter(Scope
* sc
, TemplateParameter tp
, RootObject o
)
2277 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
2278 Type ta
= isType(o
);
2279 Expression ea
= isExpression(o
);
2280 Dsymbol sa
= isDsymbol(o
);
2281 Tuple va
= isTuple(o
);
2284 VarDeclaration v
= null;
2286 if (ea
&& ea
.op
== EXP
.type
)
2288 else if (ea
&& ea
.op
== EXP
.scope_
)
2289 sa
= (cast(ScopeExp
)ea
).sds
;
2290 else if (ea
&& (ea
.op
== EXP
.this_ || ea
.op
== EXP
.super_
))
2291 sa
= (cast(ThisExp
)ea
).var
;
2292 else if (ea
&& ea
.op
== EXP
.function_
)
2294 if ((cast(FuncExp
)ea
).td
)
2295 sa
= (cast(FuncExp
)ea
).td
;
2297 sa
= (cast(FuncExp
)ea
).fd
;
2302 //printf("type %s\n", ta.toChars());
2303 auto ad
= new AliasDeclaration(Loc
.initial
, tp
.ident
, ta
);
2304 ad
.storage_class |
= STC
.templateparameter
;
2309 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
2310 auto ad
= new AliasDeclaration(Loc
.initial
, tp
.ident
, sa
);
2311 ad
.storage_class |
= STC
.templateparameter
;
2316 // tdtypes.data[i] always matches ea here
2317 Initializer _init
= new ExpInitializer(loc
, ea
);
2318 TemplateValueParameter tvp
= tp
.isTemplateValueParameter();
2319 Type t
= tvp ? tvp
.valType
: null;
2320 v
= new VarDeclaration(loc
, t
, tp
.ident
, _init
);
2321 v
.storage_class
= STC
.manifest | STC
.templateparameter
;
2326 //printf("\ttuple\n");
2327 d
= new TupleDeclaration(loc
, tp
.ident
, &va
.objects
);
2333 d
.storage_class |
= STC
.templateparameter
;
2338 // consistent with Type.checkDeprecated()
2339 while (t
.ty
!= Tenum
)
2343 t
= (cast(TypeNext
)t
).next
;
2345 if (Dsymbol s
= t
.toDsymbol(sc
))
2347 if (s
.isDeprecated())
2348 d
.storage_class |
= STC
.deprecated_
;
2353 if (sa
.isDeprecated())
2354 d
.storage_class |
= STC
.deprecated_
;
2358 error("declaration `%s` is already defined", tp
.ident
.toChars());
2359 d
.dsymbolSemantic(sc
);
2360 /* So the caller's o gets updated with the result of semantic() being run on o
2363 o
= v
._init
.initializerToExpression();
2367 /*************************************************
2368 * Limited function template instantiation for using fd.leastAsSpecialized()
2370 extern (D
) FuncDeclaration
doHeaderInstantiation(TemplateInstance ti
, Scope
* sc2
, FuncDeclaration fd
, Type tthis
, Expressions
* fargs
)
2375 printf("doHeaderInstantiation this = %s\n", toChars());
2378 // function body and contracts are not need
2379 if (fd
.isCtorDeclaration())
2380 fd
= new CtorDeclaration(fd
.loc
, fd
.endloc
, fd
.storage_class
, fd
.type
.syntaxCopy());
2382 fd
= new FuncDeclaration(fd
.loc
, fd
.endloc
, fd
.ident
, fd
.storage_class
, fd
.type
.syntaxCopy());
2385 assert(fd
.type
.ty
== Tfunction
);
2386 auto tf
= fd
.type
.isTypeFunction();
2391 // Match 'tthis' to any TemplateThisParameter's
2392 bool hasttp
= false;
2393 foreach (tp
; *parameters
)
2395 TemplateThisParameter ttp
= tp
.isTemplateThisParameter();
2401 tf
= cast(TypeFunction
)tf
.addSTC(ModToStc(tthis
.mod
));
2406 Scope
* scx
= sc2
.push();
2408 // Shouldn't run semantic on default arguments and return type.
2409 foreach (ref params
; *tf
.parameterList
.parameters
)
2410 params
.defaultArg
= null;
2411 tf
.incomplete
= true;
2413 if (fd
.isCtorDeclaration())
2415 // For constructors, emitting return type is necessary for
2416 // isReturnIsolated() in functionResolve.
2419 Dsymbol parent
= toParentDecl();
2421 AggregateDeclaration ad
= parent
.isAggregateDeclaration();
2422 if (!ad || parent
.isUnionDeclaration())
2428 tret
= ad
.handleType();
2430 tret
= tret
.addStorageClass(fd
.storage_class | scx
.stc);
2431 tret
= tret
.addMod(tf
.mod
);
2434 if (ad
&& ad
.isStructDeclaration())
2436 //printf("tf = %s\n", tf.toChars());
2441 fd
.type
= fd
.type
.addSTC(scx
.stc);
2442 fd
.type
= fd
.type
.typeSemantic(fd
.loc
, scx
);
2445 if (fd
.type
.ty
!= Tfunction
)
2448 fd
.originalType
= fd
.type
; // for mangling
2449 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
2450 //printf("fd.needThis() = %d\n", fd.needThis());
2455 debug (FindExistingInstance
)
2457 __gshared
uint nFound
, nNotFound
, nAdded
, nRemoved
;
2459 shared static ~this()
2461 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
2462 nFound
, nNotFound
, nAdded
, nRemoved
);
2466 /****************************************************
2467 * Given a new instance tithis of this TemplateDeclaration,
2468 * see if there already exists an instance.
2469 * If so, return that existing instance.
2471 extern (D
) TemplateInstance
findExistingInstance(TemplateInstance tithis
, Expressions
* fargs
)
2473 //printf("findExistingInstance() %s\n", tithis.toChars());
2474 tithis
.fargs
= fargs
;
2475 auto tibox
= TemplateInstanceBox(tithis
);
2476 auto p
= tibox
in instances
;
2477 debug (FindExistingInstance
) ++(p ? nFound
: nNotFound
);
2478 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
2479 return p ?
*p
: null;
2482 /********************************************
2483 * Add instance ti to TemplateDeclaration's table of instances.
2484 * Return a handle we can use to later remove it if it fails instantiation.
2486 extern (D
) TemplateInstance
addInstance(TemplateInstance ti
)
2488 //printf("addInstance() %p %s\n", instances, ti.toChars());
2489 auto tibox
= TemplateInstanceBox(ti
);
2490 instances
[tibox
] = ti
;
2491 debug (FindExistingInstance
) ++nAdded
;
2495 /*******************************************
2496 * Remove TemplateInstance from table of instances.
2498 * handle returned by addInstance()
2500 extern (D
) void removeInstance(TemplateInstance ti
)
2502 //printf("removeInstance() %s\n", ti.toChars());
2503 auto tibox
= TemplateInstanceBox(ti
);
2504 debug (FindExistingInstance
) ++nRemoved
;
2505 instances
.remove(tibox
);
2508 override inout(TemplateDeclaration
) isTemplateDeclaration() inout
2514 * Check if the last template parameter is a tuple one,
2515 * and returns it if so, else returns `null`.
2518 * The last template parameter if it's a `TemplateTupleParameter`
2520 TemplateTupleParameter
isVariadic()
2522 size_t dim
= parameters
.length
;
2525 return (*parameters
)[dim
- 1].isTemplateTupleParameter();
2528 extern(C
++) override bool isDeprecated() const
2530 return this.deprecated_
;
2533 /***********************************
2534 * We can overload templates.
2536 override bool isOverloadable() const
2541 override void accept(Visitor v
)
2547 extern (C
++) final class TypeDeduced
: Type
2550 Expressions argexps
; // corresponding expressions
2551 Types tparams
; // tparams[i].mod
2553 extern (D
) this(Type tt
, Expression e
, Type tparam
)
2558 tparams
.push(tparam
);
2561 void update(Expression e
, Type tparam
)
2564 tparams
.push(tparam
);
2567 void update(Type tt
, Expression e
, Type tparam
)
2571 tparams
.push(tparam
);
2574 MATCH
matchAll(Type tt
)
2576 MATCH match
= MATCH
.exact
;
2577 foreach (j
, e
; argexps
)
2580 if (e
== emptyArrayElement
)
2583 Type t
= tt
.addMod(tparams
[j
].mod
).substWildTo(MODFlags
.const_
);
2585 MATCH m
= e
.implicitConvTo(t
);
2588 if (match
== MATCH
.nomatch
)
2596 /*************************************************
2597 * Given function arguments, figure out which template function
2598 * to expand, and return matching result.
2600 * m = matching result
2601 * dstart = the root of overloaded function templates
2602 * loc = instantiation location
2603 * sc = instantiation scope
2604 * tiargs = initial list of template arguments
2605 * tthis = if !NULL, the 'this' pointer argument
2606 * argumentList= arguments to function
2607 * pMessage = address to store error message, or null
2609 void functionResolve(ref MatchAccumulator m
, Dsymbol dstart
, Loc loc
, Scope
* sc
, Objects
* tiargs
,
2610 Type tthis
, ArgumentList argumentList
, const(char)** pMessage
= null)
2614 printf("functionResolve() dstart = %s\n", dstart
.toChars());
2615 printf(" tiargs:\n");
2618 for (size_t i
= 0; i
< tiargs
.length
; i
++)
2620 RootObject arg
= (*tiargs
)[i
];
2621 printf("\t%s\n", arg
.toChars());
2624 printf(" fargs:\n");
2625 for (size_t i
= 0; i
< (fargs ? fargs
.length
: 0); i
++)
2627 Expression arg
= (*fargs
)[i
];
2628 printf("\t%s %s\n", arg
.type
.toChars(), arg
.toChars());
2629 //printf("\tty = %d\n", arg.type.ty);
2631 //printf("stc = %llx\n", dstart._scope.stc);
2632 //printf("match:t/f = %d/%d\n", ta_last, m.last);
2636 int property
= 0; // 0: uninitialized
2637 // 1: seen @property
2639 size_t ov_index
= 0;
2640 TemplateDeclaration td_best
;
2641 TemplateInstance ti_best
;
2642 MATCH ta_last
= m
.last
!= MATCH
.nomatch ? MATCH
.exact
: MATCH
.nomatch
;
2645 int applyFunction(FuncDeclaration fd
)
2650 // explicitly specified tiargs never match to non template function
2651 if (tiargs
&& tiargs
.length
> 0)
2654 // constructors need a valid scope in order to detect semantic errors
2655 if (!fd
.isCtorDeclaration
&&
2656 fd
.semanticRun
< PASS
.semanticdone
)
2658 Ungag ungag
= fd
.ungagSpeculative();
2659 fd
.dsymbolSemantic(null);
2661 if (fd
.semanticRun
< PASS
.semanticdone
)
2663 .error(loc
, "forward reference to template `%s`", fd
.toChars());
2666 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
2667 auto tf
= cast(TypeFunction
)fd
.type
;
2669 int prop
= tf
.isproperty ?
1 : 2;
2672 else if (property
!= prop
)
2673 error(fd
.loc
, "cannot overload both property and non-property functions");
2675 /* For constructors, qualifier check will be opposite direction.
2676 * Qualified constructor always makes qualified object, then will be checked
2677 * that it is implicitly convertible to tthis.
2679 Type tthis_fd
= fd
.needThis() ? tthis
: null;
2680 bool isCtorCall
= tthis_fd
&& fd
.isCtorDeclaration();
2683 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
2684 // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
2685 if (MODimplicitConv(tf
.mod
, tthis_fd
.mod
) ||
2686 tf
.isWild() && tf
.isShared() == tthis_fd
.isShared() ||
2687 fd
.isReturnIsolated())
2689 /* && tf.isShared() == tthis_fd.isShared()*/
2690 // Uniquely constructed object can ignore shared qualifier.
2691 // TODO: Is this appropriate?
2695 return 0; // MATCH.nomatch
2698 If a struct is declared as shared the dtor is automatically
2699 considered to be shared, but when the struct is instantiated
2700 the instance is no longer considered to be shared when the
2701 function call matching is done. The fix makes it so that if a
2702 struct declaration is shared, when the destructor is called,
2703 the instantiated struct is also considered shared.
2705 if (auto dt = fd
.isDtorDeclaration())
2707 auto dtmod
= dt.type
.toTypeFunction();
2708 auto shared_dtor
= dtmod
.mod
& MODFlags
.shared_
;
2709 auto shared_this
= tthis_fd
!is null ?
2710 tthis_fd
.mod
& MODFlags
.shared_
: 0;
2711 if (shared_dtor
&& !shared_this
)
2713 else if (shared_this
&& !shared_dtor
&& tthis_fd
!is null)
2714 tf
.mod
= tthis_fd
.mod
;
2716 MATCH mfa
= tf
.callMatch(tthis_fd
, argumentList
, 0, pMessage
, sc
);
2717 //printf("test1: mfa = %d\n", mfa);
2718 if (mfa
== MATCH
.nomatch
)
2725 ta_last
= MATCH
.exact
;
2728 tthis_best
= tthis_fd
;
2734 if (mfa
> m
.last
) return firstIsBetter();
2735 if (mfa
< m
.last
) return 0;
2737 /* See if one of the matches overrides the other.
2740 if (m
.lastf
.overrides(fd
)) return 0;
2741 if (fd
.overrides(m
.lastf
)) return firstIsBetter();
2743 /* Try to disambiguate using template-style partial ordering rules.
2744 * In essence, if f() and g() are ambiguous, if f() can call g(),
2745 * but g() cannot call f(), then pick f().
2746 * This is because f() is "more specialized."
2749 MATCH c1
= fd
.leastAsSpecialized(m
.lastf
, argumentList
.names
);
2750 MATCH c2
= m
.lastf
.leastAsSpecialized(fd
, argumentList
.names
);
2751 //printf("c1 = %d, c2 = %d\n", c1, c2);
2752 if (c1
> c2
) return firstIsBetter();
2753 if (c1
< c2
) return 0;
2756 /* The 'overrides' check above does covariant checking only
2757 * for virtual member functions. It should do it for all functions,
2758 * but in order to not risk breaking code we put it after
2759 * the 'leastAsSpecialized' check.
2760 * In the future try moving it before.
2761 * I.e. a not-the-same-but-covariant match is preferred,
2762 * as it is more restrictive.
2764 if (!m
.lastf
.type
.equals(fd
.type
))
2766 //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
2767 const lastCovariant
= m
.lastf
.type
.covariant(fd
.type
);
2768 const firstCovariant
= fd
.type
.covariant(m
.lastf
.type
);
2770 if (lastCovariant
== Covariant
.yes || lastCovariant
== Covariant
.no
)
2772 if (firstCovariant
!= Covariant
.yes
&& firstCovariant
!= Covariant
.no
)
2777 else if (firstCovariant
== Covariant
.yes || firstCovariant
== Covariant
.no
)
2779 return firstIsBetter();
2783 /* If the two functions are the same function, like:
2785 * int foo(int x) { ... }
2786 * then pick the one with the body.
2788 * If none has a body then don't care because the same
2789 * real function would be linked to the decl (e.g from object file)
2791 if (tf
.equals(m
.lastf
.type
) &&
2792 fd
.storage_class
== m
.lastf
.storage_class
&&
2793 fd
.parent
== m
.lastf
.parent
&&
2794 fd
.visibility
== m
.lastf
.visibility
&&
2795 fd
._linkage
== m
.lastf
._linkage
)
2797 if (fd
.fbody
&& !m
.lastf
.fbody
)
2798 return firstIsBetter();
2803 // https://issues.dlang.org/show_bug.cgi?id=14450
2804 // Prefer exact qualified constructor for the creating object type
2805 if (isCtorCall
&& tf
.mod
!= m
.lastf
.type
.mod
)
2807 if (tthis
.mod
== tf
.mod
) return firstIsBetter();
2808 if (tthis
.mod
== m
.lastf
.type
.mod
) return 0;
2816 int applyTemplate(TemplateDeclaration td
)
2818 //printf("applyTemplate(): td = %s\n", td.toChars());
2819 if (td
== td_best
) // skip duplicates
2823 sc
= td
._scope
; // workaround for Type.aliasthisOf
2825 if (td
.semanticRun
== PASS
.initial
&& td
._scope
)
2827 // Try to fix forward reference. Ungag errors while doing so.
2828 Ungag ungag
= td
.ungagSpeculative();
2829 td
.dsymbolSemantic(td
._scope
);
2831 if (td
.semanticRun
== PASS
.initial
)
2833 .error(loc
, "forward reference to template `%s`", td
.toChars());
2837 m
.last
= MATCH
.nomatch
;
2840 //printf("td = %s\n", td.toChars());
2842 if (argumentList
.hasNames
)
2844 .error(loc
, "named arguments with Implicit Function Template Instantiation are not supported yet");
2847 auto f
= td
.onemember ? td
.onemember
.isFuncDeclaration() : null;
2851 tiargs
= new Objects();
2852 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
2853 Objects dedtypes
= Objects(td
.parameters
.length
);
2854 assert(td
.semanticRun
!= PASS
.initial
);
2855 MATCH mta
= td
.matchWithInstance(sc
, ti
, &dedtypes
, argumentList
, 0);
2856 //printf("matchWithInstance = %d\n", mta);
2857 if (mta
== MATCH
.nomatch || mta
< ta_last
) // no match or less match
2860 ti
.templateInstanceSemantic(sc
, argumentList
);
2861 if (!ti
.inst
) // if template failed to expand
2864 Dsymbol s
= ti
.inst
.toAlias();
2866 if (auto tdx
= s
.isTemplateDeclaration())
2868 Objects dedtypesX
; // empty tiargs
2870 // https://issues.dlang.org/show_bug.cgi?id=11553
2871 // Check for recursive instantiation of tdx.
2872 for (TemplatePrevious
* p
= tdx
.previous
; p
; p
= p
.prev
)
2874 if (arrayObjectMatch(p
.dedargs
, &dedtypesX
))
2876 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
2877 /* It must be a subscope of p.sc, other scope chains are not recursive
2880 for (Scope
* scx
= sc
; scx
; scx
= scx
.enclosing
)
2884 error(loc
, "recursive template expansion while looking for `%s.%s`", ti
.toChars(), tdx
.toChars());
2889 /* BUG: should also check for ref param differences
2893 TemplatePrevious pr
;
2894 pr
.prev
= tdx
.previous
;
2896 pr
.dedargs
= &dedtypesX
;
2897 tdx
.previous
= &pr
; // add this to threaded list
2899 fd
= resolveFuncCall(loc
, sc
, s
, null, tthis
, argumentList
, FuncResolveFlag
.quiet
);
2901 tdx
.previous
= pr
.prev
; // unlink from threaded list
2903 else if (s
.isFuncDeclaration())
2905 fd
= resolveFuncCall(loc
, sc
, s
, null, tthis
, argumentList
, FuncResolveFlag
.quiet
);
2913 if (fd
.type
.ty
!= Tfunction
)
2915 m
.lastf
= fd
; // to propagate "error match"
2917 m
.last
= MATCH
.nomatch
;
2921 Type tthis_fd
= fd
.needThis() && !fd
.isCtorDeclaration() ? tthis
: null;
2923 auto tf
= cast(TypeFunction
)fd
.type
;
2924 MATCH mfa
= tf
.callMatch(tthis_fd
, argumentList
, 0, null, sc
);
2928 if (mta
< ta_last
) goto Ltd_best2
;
2929 if (mta
> ta_last
) goto Ltd2
;
2931 if (mfa
< m
.last
) goto Ltd_best2
;
2932 if (mfa
> m
.last
) goto Ltd2
;
2934 // td_best and td are ambiguous
2935 //printf("Lambig2\n");
2944 // td is the new best match
2948 property
= 0; // (backward compatibility)
2952 tthis_best
= tthis_fd
;
2959 //printf("td = %s\n", td.toChars());
2960 for (size_t ovi
= 0; f
; f
= f
.overnext0
, ovi
++)
2962 if (f
.type
.ty
!= Tfunction || f
.errors
)
2965 /* This is a 'dummy' instance to evaluate constraint properly.
2967 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
2968 ti
.parent
= td
.parent
; // Maybe calculating valid 'enclosing' is unnecessary.
2971 MATCHpair x
= td
.deduceFunctionTemplateMatch(ti
, sc
, fd
, tthis
, argumentList
);
2974 //printf("match:t/f = %d/%d\n", mta, mfa);
2975 if (!fd || mfa
== MATCH
.nomatch
)
2978 Type tthis_fd
= fd
.needThis() ? tthis
: null;
2980 bool isCtorCall
= tthis_fd
&& fd
.isCtorDeclaration();
2983 // Constructor call requires additional check.
2984 auto tf
= cast(TypeFunction
)fd
.type
;
2986 if (MODimplicitConv(tf
.mod
, tthis_fd
.mod
) ||
2987 tf
.isWild() && tf
.isShared() == tthis_fd
.isShared() ||
2988 fd
.isReturnIsolated())
2993 continue; // MATCH.nomatch
2995 // need to check here whether the constructor is the member of a struct
2996 // declaration that defines a copy constructor. This is already checked
2997 // in the semantic of CtorDeclaration, however, when matching functions,
2998 // the template instance is not expanded.
2999 // https://issues.dlang.org/show_bug.cgi?id=21613
3000 auto ad
= fd
.isThis();
3001 auto sd
= ad
.isStructDeclaration();
3002 if (checkHasBothRvalueAndCpCtor(sd
, fd
.isCtorDeclaration(), ti
))
3006 if (mta
< ta_last
) goto Ltd_best
;
3007 if (mta
> ta_last
) goto Ltd
;
3009 if (mfa
< m
.last
) goto Ltd_best
;
3010 if (mfa
> m
.last
) goto Ltd
;
3014 // Disambiguate by picking the most specialized TemplateDeclaration
3015 MATCH c1
= td
.leastAsSpecialized(sc
, td_best
, argumentList
);
3016 MATCH c2
= td_best
.leastAsSpecialized(sc
, td
, argumentList
);
3017 //printf("1: c1 = %d, c2 = %d\n", c1, c2);
3018 if (c1
> c2
) goto Ltd
;
3019 if (c1
< c2
) goto Ltd_best
;
3021 assert(fd
&& m
.lastf
);
3023 // Disambiguate by tf.callMatch
3024 auto tf1
= fd
.type
.isTypeFunction();
3025 auto tf2
= m
.lastf
.type
.isTypeFunction();
3026 MATCH c1
= tf1
.callMatch(tthis_fd
, argumentList
, 0, null, sc
);
3027 MATCH c2
= tf2
.callMatch(tthis_best
, argumentList
, 0, null, sc
);
3028 //printf("2: c1 = %d, c2 = %d\n", c1, c2);
3029 if (c1
> c2
) goto Ltd
;
3030 if (c1
< c2
) goto Ltd_best
;
3033 // Disambiguate by picking the most specialized FunctionDeclaration
3034 MATCH c1
= fd
.leastAsSpecialized(m
.lastf
, argumentList
.names
);
3035 MATCH c2
= m
.lastf
.leastAsSpecialized(fd
, argumentList
.names
);
3036 //printf("3: c1 = %d, c2 = %d\n", c1, c2);
3037 if (c1
> c2
) goto Ltd
;
3038 if (c1
< c2
) goto Ltd_best
;
3041 // https://issues.dlang.org/show_bug.cgi?id=14450
3042 // Prefer exact qualified constructor for the creating object type
3043 if (isCtorCall
&& fd
.type
.mod
!= m
.lastf
.type
.mod
)
3045 if (tthis
.mod
== fd
.type
.mod
) goto Ltd
;
3046 if (tthis
.mod
== m
.lastf
.type
.mod
) goto Ltd_best
;
3053 Ltd_best
: // td_best is the best match so far
3054 //printf("Ltd_best\n");
3057 Ltd
: // td is the new best match
3062 property
= 0; // (backward compatibility)
3066 tthis_best
= tthis_fd
;
3075 auto td
= dstart
.isTemplateDeclaration();
3076 if (td
&& td
.funcroot
)
3077 dstart
= td
.funcroot
;
3078 overloadApply(dstart
, (Dsymbol s
)
3082 if (auto fd
= s
.isFuncDeclaration())
3083 return applyFunction(fd
);
3084 if (auto td
= s
.isTemplateDeclaration())
3085 return applyTemplate(td
);
3089 //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf);
3090 if (td_best
&& ti_best
&& m
.count
== 1)
3092 // Matches to template function
3093 assert(td_best
.onemember
&& td_best
.onemember
.isFuncDeclaration());
3094 /* The best match is td_best with arguments tdargs.
3095 * Now instantiate the template.
3097 assert(td_best
._scope
);
3099 sc
= td_best
._scope
; // workaround for Type.aliasthisOf
3101 auto ti
= new TemplateInstance(loc
, td_best
, ti_best
.tiargs
);
3102 ti
.templateInstanceSemantic(sc
, argumentList
);
3104 m
.lastf
= ti
.toAlias().isFuncDeclaration();
3112 m
.last
= MATCH
.nomatch
;
3116 // look forward instantiated overload function
3117 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
3118 // it has filled overnext0d
3121 m
.lastf
= m
.lastf
.overnext0
;
3125 tthis_best
= m
.lastf
.needThis() && !m
.lastf
.isCtorDeclaration() ? tthis
: null;
3127 if (m
.lastf
.type
.ty
== Terror
)
3129 auto tf
= m
.lastf
.type
.isTypeFunction();
3130 if (!tf
.callMatch(tthis_best
, argumentList
, 0, null, sc
))
3133 /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
3134 * a template instance can be matched while instantiating
3135 * that same template. Thus, the function type can be incomplete. Complete it.
3137 * https://issues.dlang.org/show_bug.cgi?id=9208
3138 * For auto function, completion should be deferred to the end of
3139 * its semantic3. Should not complete it in here.
3141 if (tf
.next
&& !m
.lastf
.inferRetType
)
3143 m
.lastf
.type
= tf
.typeSemantic(loc
, sc
);
3148 // Matches to non template function,
3149 // or found matches were ambiguous.
3150 assert(m
.count
>= 1);
3157 m
.last
= MATCH
.nomatch
;
3161 /* ======================== Type ============================================ */
3164 * Given an identifier, figure out which TemplateParameter it is.
3165 * Return IDX_NOTFOUND if not found.
3167 private size_t
templateIdentifierLookup(Identifier id
, TemplateParameters
* parameters
)
3169 for (size_t i
= 0; i
< parameters
.length
; i
++)
3171 TemplateParameter tp
= (*parameters
)[i
];
3172 if (tp
.ident
.equals(id
))
3175 return IDX_NOTFOUND
;
3178 private size_t
templateParameterLookup(Type tparam
, TemplateParameters
* parameters
)
3180 if (tparam
.ty
== Tident
)
3182 TypeIdentifier tident
= cast(TypeIdentifier
)tparam
;
3183 //printf("\ttident = '%s'\n", tident.toChars());
3184 return templateIdentifierLookup(tident
.ident
, parameters
);
3186 return IDX_NOTFOUND
;
3189 private ubyte deduceWildHelper(Type t
, Type
* at
, Type tparam
)
3191 if ((tparam
.mod
& MODFlags
.wild
) == 0)
3196 auto X(T
, U
)(T U
, U T
)
3198 return (U
<< 4) | T
;
3201 switch (X(tparam
.mod
, t
.mod
))
3203 case X(MODFlags
.wild
, 0):
3204 case X(MODFlags
.wild
, MODFlags
.const_
):
3205 case X(MODFlags
.wild
, MODFlags
.shared_
):
3206 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3207 case X(MODFlags
.wild
, MODFlags
.immutable_
):
3208 case X(MODFlags
.wildconst
, 0):
3209 case X(MODFlags
.wildconst
, MODFlags
.const_
):
3210 case X(MODFlags
.wildconst
, MODFlags
.shared_
):
3211 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3212 case X(MODFlags
.wildconst
, MODFlags
.immutable_
):
3213 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_
):
3214 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3215 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.immutable_
):
3216 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_
):
3217 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3218 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.immutable_
):
3220 ubyte wm
= (t
.mod
& ~MODFlags
.shared_
);
3222 wm
= MODFlags
.mutable
;
3223 ubyte m
= (t
.mod
& (MODFlags
.const_ | MODFlags
.immutable_
)) |
(tparam
.mod
& t
.mod
& MODFlags
.shared_
);
3224 *at
= t
.unqualify(m
);
3227 case X(MODFlags
.wild
, MODFlags
.wild
):
3228 case X(MODFlags
.wild
, MODFlags
.wildconst
):
3229 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3230 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3231 case X(MODFlags
.wildconst
, MODFlags
.wild
):
3232 case X(MODFlags
.wildconst
, MODFlags
.wildconst
):
3233 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3234 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3235 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3236 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3237 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3238 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3240 *at
= t
.unqualify(tparam
.mod
& t
.mod
);
3241 return MODFlags
.wild
;
3249 * Returns the common type of the 2 types.
3251 private Type
rawTypeMerge(Type t1
, Type t2
)
3255 if (t1
.equivalent(t2
))
3256 return t1
.castMod(MODmerge(t1
.mod
, t2
.mod
));
3258 auto t1b
= t1
.toBasetype();
3259 auto t2b
= t2
.toBasetype();
3260 if (t1b
.equals(t2b
))
3262 if (t1b
.equivalent(t2b
))
3263 return t1b
.castMod(MODmerge(t1b
.mod
, t2b
.mod
));
3265 auto ty
= implicitConvCommonTy(t1b
.ty
, t2b
.ty
);
3267 return Type
.basic
[ty
];
3272 private MATCH
deduceTypeHelper(Type t
, Type
* at
, Type tparam
)
3276 auto X(T
, U
)(T U
, U T
)
3278 return (U
<< 4) | T
;
3281 switch (X(tparam
.mod
, t
.mod
))
3284 case X(0, MODFlags
.const_
):
3285 case X(0, MODFlags
.wild
):
3286 case X(0, MODFlags
.wildconst
):
3287 case X(0, MODFlags
.shared_
):
3288 case X(0, MODFlags
.shared_ | MODFlags
.const_
):
3289 case X(0, MODFlags
.shared_ | MODFlags
.wild
):
3290 case X(0, MODFlags
.shared_ | MODFlags
.wildconst
):
3291 case X(0, MODFlags
.immutable_
):
3293 // foo(U) const(T) => const(T)
3294 // foo(U) inout(T) => inout(T)
3295 // foo(U) inout(const(T)) => inout(const(T))
3296 // foo(U) shared(T) => shared(T)
3297 // foo(U) shared(const(T)) => shared(const(T))
3298 // foo(U) shared(inout(T)) => shared(inout(T))
3299 // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
3300 // foo(U) immutable(T) => immutable(T)
3305 case X(MODFlags
.const_
, MODFlags
.const_
):
3306 case X(MODFlags
.wild
, MODFlags
.wild
):
3307 case X(MODFlags
.wildconst
, MODFlags
.wildconst
):
3308 case X(MODFlags
.shared_
, MODFlags
.shared_
):
3309 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.const_
):
3310 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3311 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3312 case X(MODFlags
.immutable_
, MODFlags
.immutable_
):
3313 // foo(const(U)) const(T) => T
3314 // foo(inout(U)) inout(T) => T
3315 // foo(inout(const(U))) inout(const(T)) => T
3316 // foo(shared(U)) shared(T) => T
3317 // foo(shared(const(U))) shared(const(T)) => T
3318 // foo(shared(inout(U))) shared(inout(T)) => T
3319 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
3320 // foo(immutable(U)) immutable(T) => T
3322 *at
= t
.mutableOf().unSharedOf();
3325 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.const_
):
3326 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3327 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3328 // foo(const(U)) shared(const(T)) => shared(T)
3329 // foo(inout(U)) shared(inout(T)) => shared(T)
3330 // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
3332 *at
= t
.mutableOf();
3335 case X(MODFlags
.const_
, 0):
3336 case X(MODFlags
.const_
, MODFlags
.wild
):
3337 case X(MODFlags
.const_
, MODFlags
.wildconst
):
3338 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wild
):
3339 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3340 case X(MODFlags
.const_
, MODFlags
.immutable_
):
3341 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.immutable_
):
3342 // foo(const(U)) T => T
3343 // foo(const(U)) inout(T) => T
3344 // foo(const(U)) inout(const(T)) => T
3345 // foo(const(U)) shared(inout(T)) => shared(T)
3346 // foo(const(U)) shared(inout(const(T))) => shared(T)
3347 // foo(const(U)) immutable(T) => T
3348 // foo(shared(const(U))) immutable(T) => T
3350 *at
= t
.mutableOf();
3351 return MATCH
.constant
;
3353 case X(MODFlags
.const_
, MODFlags
.shared_
):
3354 // foo(const(U)) shared(T) => shared(T)
3357 return MATCH
.constant
;
3359 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.const_
):
3360 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.wild
):
3361 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3362 // foo(shared(U)) shared(const(T)) => const(T)
3363 // foo(shared(U)) shared(inout(T)) => inout(T)
3364 // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
3366 *at
= t
.unSharedOf();
3369 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_
):
3370 // foo(shared(const(U))) shared(T) => T
3372 *at
= t
.unSharedOf();
3373 return MATCH
.constant
;
3375 case X(MODFlags
.wildconst
, MODFlags
.immutable_
):
3376 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3377 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.immutable_
):
3378 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3379 // foo(inout(const(U))) immutable(T) => T
3380 // foo(shared(const(U))) shared(inout(const(T))) => T
3381 // foo(shared(inout(const(U)))) immutable(T) => T
3382 // foo(shared(inout(const(U)))) shared(inout(T)) => T
3384 *at
= t
.unSharedOf().mutableOf();
3385 return MATCH
.constant
;
3387 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wild
):
3388 // foo(shared(const(U))) shared(inout(T)) => T
3390 *at
= t
.unSharedOf().mutableOf();
3391 return MATCH
.constant
;
3393 case X(MODFlags
.wild
, 0):
3394 case X(MODFlags
.wild
, MODFlags
.const_
):
3395 case X(MODFlags
.wild
, MODFlags
.wildconst
):
3396 case X(MODFlags
.wild
, MODFlags
.immutable_
):
3397 case X(MODFlags
.wild
, MODFlags
.shared_
):
3398 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3399 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3400 case X(MODFlags
.wildconst
, 0):
3401 case X(MODFlags
.wildconst
, MODFlags
.const_
):
3402 case X(MODFlags
.wildconst
, MODFlags
.wild
):
3403 case X(MODFlags
.wildconst
, MODFlags
.shared_
):
3404 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3405 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3406 case X(MODFlags
.shared_
, 0):
3407 case X(MODFlags
.shared_
, MODFlags
.const_
):
3408 case X(MODFlags
.shared_
, MODFlags
.wild
):
3409 case X(MODFlags
.shared_
, MODFlags
.wildconst
):
3410 case X(MODFlags
.shared_
, MODFlags
.immutable_
):
3411 case X(MODFlags
.shared_ | MODFlags
.const_
, 0):
3412 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.const_
):
3413 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.wild
):
3414 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.wildconst
):
3415 case X(MODFlags
.shared_ | MODFlags
.wild
, 0):
3416 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.const_
):
3417 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.wild
):
3418 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.wildconst
):
3419 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.immutable_
):
3420 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_
):
3421 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3422 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3423 case X(MODFlags
.shared_ | MODFlags
.wildconst
, 0):
3424 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.const_
):
3425 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.wild
):
3426 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.wildconst
):
3427 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_
):
3428 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3429 case X(MODFlags
.immutable_
, 0):
3430 case X(MODFlags
.immutable_
, MODFlags
.const_
):
3431 case X(MODFlags
.immutable_
, MODFlags
.wild
):
3432 case X(MODFlags
.immutable_
, MODFlags
.wildconst
):
3433 case X(MODFlags
.immutable_
, MODFlags
.shared_
):
3434 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.const_
):
3435 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.wild
):
3436 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3437 // foo(inout(U)) T => nomatch
3438 // foo(inout(U)) const(T) => nomatch
3439 // foo(inout(U)) inout(const(T)) => nomatch
3440 // foo(inout(U)) immutable(T) => nomatch
3441 // foo(inout(U)) shared(T) => nomatch
3442 // foo(inout(U)) shared(const(T)) => nomatch
3443 // foo(inout(U)) shared(inout(const(T))) => nomatch
3444 // foo(inout(const(U))) T => nomatch
3445 // foo(inout(const(U))) const(T) => nomatch
3446 // foo(inout(const(U))) inout(T) => nomatch
3447 // foo(inout(const(U))) shared(T) => nomatch
3448 // foo(inout(const(U))) shared(const(T)) => nomatch
3449 // foo(inout(const(U))) shared(inout(T)) => nomatch
3450 // foo(shared(U)) T => nomatch
3451 // foo(shared(U)) const(T) => nomatch
3452 // foo(shared(U)) inout(T) => nomatch
3453 // foo(shared(U)) inout(const(T)) => nomatch
3454 // foo(shared(U)) immutable(T) => nomatch
3455 // foo(shared(const(U))) T => nomatch
3456 // foo(shared(const(U))) const(T) => nomatch
3457 // foo(shared(const(U))) inout(T) => nomatch
3458 // foo(shared(const(U))) inout(const(T)) => nomatch
3459 // foo(shared(inout(U))) T => nomatch
3460 // foo(shared(inout(U))) const(T) => nomatch
3461 // foo(shared(inout(U))) inout(T) => nomatch
3462 // foo(shared(inout(U))) inout(const(T)) => nomatch
3463 // foo(shared(inout(U))) immutable(T) => nomatch
3464 // foo(shared(inout(U))) shared(T) => nomatch
3465 // foo(shared(inout(U))) shared(const(T)) => nomatch
3466 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
3467 // foo(shared(inout(const(U)))) T => nomatch
3468 // foo(shared(inout(const(U)))) const(T) => nomatch
3469 // foo(shared(inout(const(U)))) inout(T) => nomatch
3470 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
3471 // foo(shared(inout(const(U)))) shared(T) => nomatch
3472 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
3473 // foo(immutable(U)) T => nomatch
3474 // foo(immutable(U)) const(T) => nomatch
3475 // foo(immutable(U)) inout(T) => nomatch
3476 // foo(immutable(U)) inout(const(T)) => nomatch
3477 // foo(immutable(U)) shared(T) => nomatch
3478 // foo(immutable(U)) shared(const(T)) => nomatch
3479 // foo(immutable(U)) shared(inout(T)) => nomatch
3480 // foo(immutable(U)) shared(inout(const(T))) => nomatch
3481 return MATCH
.nomatch
;
3488 __gshared Expression emptyArrayElement
= null;
3490 /* These form the heart of template argument deduction.
3491 * Given 'this' being the type argument to the template instance,
3492 * it is matched against the template declaration parameter specialization
3493 * 'tparam' to determine the type to be used for the parameter.
3495 * template Foo(T:T*) // template declaration
3496 * Foo!(int*) // template instantiation
3500 * parameters = [ T:T* ] // Array of TemplateParameter's
3502 * dedtypes = [ int ] // Array of Expression/Type's
3504 MATCH
deduceType(RootObject o
, Scope
* sc
, Type tparam
, TemplateParameters
* parameters
, Objects
* dedtypes
, uint* wm
= null, size_t inferStart
= 0, bool ignoreAliasThis
= false)
3506 extern (C
++) final class DeduceType
: Visitor
3508 alias visit
= Visitor
.visit
;
3512 TemplateParameters
* parameters
;
3516 bool ignoreAliasThis
;
3519 extern (D
) this(Scope
* sc
, Type tparam
, TemplateParameters
* parameters
, Objects
* dedtypes
, uint* wm
, size_t inferStart
, bool ignoreAliasThis
)
3522 this.tparam
= tparam
;
3523 this.parameters
= parameters
;
3524 this.dedtypes
= dedtypes
;
3526 this.inferStart
= inferStart
;
3527 this.ignoreAliasThis
= ignoreAliasThis
;
3528 result
= MATCH
.nomatch
;
3531 override void visit(Type t
)
3539 if (tparam
.ty
== Tident
)
3541 // Determine which parameter tparam is
3542 size_t i
= templateParameterLookup(tparam
, parameters
);
3543 if (i
== IDX_NOTFOUND
)
3548 /* Need a loc to go with the semantic routine.
3551 if (parameters
.length
)
3553 TemplateParameter tp
= (*parameters
)[0];
3557 /* BUG: what if tparam is a template instance, that
3558 * has as an argument another Tident?
3560 tparam
= tparam
.typeSemantic(loc
, sc
);
3561 assert(tparam
.ty
!= Tident
);
3562 result
= deduceType(t
, sc
, tparam
, parameters
, dedtypes
, wm
);
3566 TemplateParameter tp
= (*parameters
)[i
];
3568 TypeIdentifier tident
= cast(TypeIdentifier
)tparam
;
3569 if (tident
.idents
.length
> 0)
3571 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
3572 Dsymbol s
= t
.toDsymbol(sc
);
3573 for (size_t j
= tident
.idents
.length
; j
-- > 0;)
3575 RootObject id
= tident
.idents
[j
];
3576 if (id
.dyncast() == DYNCAST
.identifier
)
3578 if (!s ||
!s
.parent
)
3580 Dsymbol s2
= s
.parent
.search(Loc
.initial
, cast(Identifier
)id
);
3584 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
3587 if (Type tx
= s2
.getType())
3589 if (s
!= tx
.toDsymbol(sc
))
3600 //printf("[e] s = %s\n", s?s.toChars():"(null)");
3601 if (tp
.isTemplateTypeParameter())
3603 Type tt
= s
.getType();
3606 Type at
= cast(Type
)(*dedtypes
)[i
];
3607 if (at
&& at
.ty
== Tnone
)
3608 at
= (cast(TypeDeduced
)at
).tded
;
3609 if (!at || tt
.equals(at
))
3611 (*dedtypes
)[i
] = tt
;
3615 if (tp
.isTemplateAliasParameter())
3617 Dsymbol s2
= cast(Dsymbol
)(*dedtypes
)[i
];
3627 // Found the corresponding parameter tp
3629 https://issues.dlang.org/show_bug.cgi?id=23578
3631 static if (is(S!int == S!av, alias av))
3633 We eventually need to deduce `int` (Tint32 [0]) and `av` (Tident).
3634 Previously this would not get pattern matched at all, but now we check if the
3635 template parameter `av` came from.
3637 This note has been left to serve as a hint for further explorers into
3638 how IsExp matching works.
3640 if (auto ta
= tp
.isTemplateAliasParameter())
3645 // (23578) - ensure previous behaviour for non-alias template params
3646 if (!tp
.isTemplateTypeParameter())
3651 Type at
= cast(Type
)(*dedtypes
)[i
];
3653 if (ubyte wx
= wm ?
deduceWildHelper(t
, &tt
, tparam
) : 0)
3658 (*dedtypes
)[i
] = tt
;
3660 result
= MATCH
.constant
;
3664 // type vs expressions
3667 TypeDeduced xt
= cast(TypeDeduced
)at
;
3668 result
= xt
.matchAll(tt
);
3669 if (result
> MATCH
.nomatch
)
3671 (*dedtypes
)[i
] = tt
;
3672 if (result
> MATCH
.constant
)
3673 result
= MATCH
.constant
; // limit level for inout matches
3681 (*dedtypes
)[i
] = tt
; // Prefer current type match
3684 if (tt
.implicitConvTo(at
.constOf()))
3686 (*dedtypes
)[i
] = at
.constOf().mutableOf();
3687 *wm |
= MODFlags
.const_
;
3690 if (at
.implicitConvTo(tt
.constOf()))
3692 (*dedtypes
)[i
] = tt
.constOf().mutableOf();
3693 *wm |
= MODFlags
.const_
;
3698 else if (MATCH m
= deduceTypeHelper(t
, &tt
, tparam
))
3703 (*dedtypes
)[i
] = tt
;
3708 // type vs expressions
3711 TypeDeduced xt
= cast(TypeDeduced
)at
;
3712 result
= xt
.matchAll(tt
);
3713 if (result
> MATCH
.nomatch
)
3715 (*dedtypes
)[i
] = tt
;
3725 if (tt
.ty
== Tclass
&& at
.ty
== Tclass
)
3727 result
= tt
.implicitConvTo(at
);
3730 if (tt
.ty
== Tsarray
&& at
.ty
== Tarray
&& tt
.nextOf().implicitConvTo(at
.nextOf()) >= MATCH
.constant
)
3738 if (tparam
.ty
== Ttypeof
)
3740 /* Need a loc to go with the semantic routine.
3743 if (parameters
.length
)
3745 TemplateParameter tp
= (*parameters
)[0];
3749 tparam
= tparam
.typeSemantic(loc
, sc
);
3751 if (t
.ty
!= tparam
.ty
)
3753 if (Dsymbol sym
= t
.toDsymbol(sc
))
3755 if (sym
.isforwardRef() && !tparam
.deco
)
3759 MATCH m
= t
.implicitConvTo(tparam
);
3760 if (m
== MATCH
.nomatch
&& !ignoreAliasThis
)
3764 TypeClass tc
= cast(TypeClass
)t
;
3765 if (tc
.sym
.aliasthis
&& !(tc
.att
& AliasThisRec
.tracingDT
))
3767 if (auto ato
= t
.aliasthisOf())
3769 tc
.att
= cast(AliasThisRec
)(tc
.att | AliasThisRec
.tracingDT
);
3770 m
= deduceType(ato
, sc
, tparam
, parameters
, dedtypes
, wm
);
3771 tc
.att
= cast(AliasThisRec
)(tc
.att
& ~AliasThisRec
.tracingDT
);
3775 else if (t
.ty
== Tstruct
)
3777 TypeStruct ts
= cast(TypeStruct
)t
;
3778 if (ts
.sym
.aliasthis
&& !(ts
.att
& AliasThisRec
.tracingDT
))
3780 if (auto ato
= t
.aliasthisOf())
3782 ts
.att
= cast(AliasThisRec
)(ts
.att | AliasThisRec
.tracingDT
);
3783 m
= deduceType(ato
, sc
, tparam
, parameters
, dedtypes
, wm
);
3784 ts
.att
= cast(AliasThisRec
)(ts
.att
& ~AliasThisRec
.tracingDT
);
3795 if (tparam
.deco
&& !tparam
.hasWild())
3797 result
= t
.implicitConvTo(tparam
);
3801 Type tpn
= tparam
.nextOf();
3802 if (wm
&& t
.ty
== Taarray
&& tparam
.isWild())
3804 // https://issues.dlang.org/show_bug.cgi?id=12403
3805 // In IFTI, stop inout matching on transitive part of AA types.
3806 tpn
= tpn
.substWildTo(MODFlags
.mutable
);
3809 result
= deduceType(t
.nextOf(), sc
, tpn
, parameters
, dedtypes
, wm
);
3814 result
= MATCH
.exact
;
3818 result
= MATCH
.nomatch
;
3822 result
= MATCH
.constant
;
3825 override void visit(TypeVector t
)
3827 if (tparam
.ty
== Tvector
)
3829 TypeVector tp
= cast(TypeVector
)tparam
;
3830 result
= deduceType(t
.basetype
, sc
, tp
.basetype
, parameters
, dedtypes
, wm
);
3836 override void visit(TypeDArray t
)
3841 override void visit(TypeSArray t
)
3843 // Extra check that array dimensions must match
3846 if (tparam
.ty
== Tarray
)
3848 MATCH m
= deduceType(t
.next
, sc
, tparam
.nextOf(), parameters
, dedtypes
, wm
);
3849 result
= (m
>= MATCH
.constant
) ? MATCH
.convert
: MATCH
.nomatch
;
3853 TemplateParameter tp
= null;
3854 Expression edim
= null;
3856 if (tparam
.ty
== Tsarray
)
3858 TypeSArray tsa
= cast(TypeSArray
)tparam
;
3859 if (tsa
.dim
.op
== EXP
.variable
&& (cast(VarExp
)tsa
.dim
).var
.storage_class
& STC
.templateparameter
)
3861 Identifier id
= (cast(VarExp
)tsa
.dim
).var
.ident
;
3862 i
= templateIdentifierLookup(id
, parameters
);
3863 assert(i
!= IDX_NOTFOUND
);
3864 tp
= (*parameters
)[i
];
3869 else if (tparam
.ty
== Taarray
)
3871 TypeAArray taa
= cast(TypeAArray
)tparam
;
3872 i
= templateParameterLookup(taa
.index
, parameters
);
3873 if (i
!= IDX_NOTFOUND
)
3874 tp
= (*parameters
)[i
];
3878 // The "type" (it hasn't been resolved yet) of the function parameter
3879 // does not have a location but the parameter it is related to does,
3880 // so we use that for the resolution (better error message).
3881 if (inferStart
< parameters
.length
)
3883 TemplateParameter loctp
= (*parameters
)[inferStart
];
3890 taa
.index
.resolve(loc
, sc
, e
, tx
, s
);
3891 edim
= s ?
getValue(s
) : getValue(e
);
3894 if (tp
&& tp
.matchArg(sc
, t
.dim
, i
, parameters
, dedtypes
, null) || edim
&& edim
.toInteger() == t
.dim
.toInteger())
3896 result
= deduceType(t
.next
, sc
, tparam
.nextOf(), parameters
, dedtypes
, wm
);
3903 override void visit(TypeAArray t
)
3905 // Extra check that index type must match
3906 if (tparam
&& tparam
.ty
== Taarray
)
3908 TypeAArray tp
= cast(TypeAArray
)tparam
;
3909 if (!deduceType(t
.index
, sc
, tp
.index
, parameters
, dedtypes
))
3911 result
= MATCH
.nomatch
;
3918 override void visit(TypeFunction t
)
3920 // Extra check that function characteristics must match
3922 return visit(cast(Type
)t
);
3924 if (auto tp
= tparam
.isTypeFunction())
3926 if (t
.parameterList
.varargs
!= tp
.parameterList
.varargs || t
.linkage
!= tp
.linkage
)
3928 result
= MATCH
.nomatch
;
3932 foreach (fparam
; *tp
.parameterList
.parameters
)
3934 // https://issues.dlang.org/show_bug.cgi?id=2579
3935 // Apply function parameter storage classes to parameter types
3936 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
3937 fparam
.storageClass
&= ~STC
.TYPECTOR
;
3939 // https://issues.dlang.org/show_bug.cgi?id=15243
3940 // Resolve parameter type if it's not related with template parameters
3941 if (!reliesOnTemplateParameters(fparam
.type
, (*parameters
)[inferStart
.. parameters
.length
]))
3943 auto tx
= fparam
.type
.typeSemantic(Loc
.initial
, sc
);
3944 if (tx
.ty
== Terror
)
3946 result
= MATCH
.nomatch
;
3953 size_t nfargs
= t
.parameterList
.length
;
3954 size_t nfparams
= tp
.parameterList
.length
;
3956 /* See if tuple match
3958 if (nfparams
> 0 && nfargs
>= nfparams
- 1)
3960 /* See if 'A' of the template parameter matches 'A'
3961 * of the type of the last function parameter.
3963 Parameter fparam
= tp
.parameterList
[nfparams
- 1];
3965 assert(fparam
.type
);
3966 if (fparam
.type
.ty
!= Tident
)
3968 TypeIdentifier tid
= cast(TypeIdentifier
)fparam
.type
;
3969 if (tid
.idents
.length
)
3972 /* Look through parameters to find tuple matching tid.ident
3977 if (tupi
== parameters
.length
)
3979 TemplateParameter tx
= (*parameters
)[tupi
];
3980 TemplateTupleParameter tup
= tx
.isTemplateTupleParameter();
3981 if (tup
&& tup
.ident
.equals(tid
.ident
))
3985 /* The types of the function arguments [nfparams - 1 .. nfargs]
3986 * now form the tuple argument.
3988 size_t tuple_dim
= nfargs
- (nfparams
- 1);
3990 /* See if existing tuple, and whether it matches or not
3992 RootObject o
= (*dedtypes
)[tupi
];
3995 // Existing deduced argument must be a tuple, and must match
3996 Tuple tup
= isTuple(o
);
3997 if (!tup || tup
.objects
.length
!= tuple_dim
)
3999 result
= MATCH
.nomatch
;
4002 for (size_t i
= 0; i
< tuple_dim
; i
++)
4004 Parameter arg
= t
.parameterList
[nfparams
- 1 + i
];
4005 if (!arg
.type
.equals(tup
.objects
[i
]))
4007 result
= MATCH
.nomatch
;
4015 auto tup
= new Tuple(tuple_dim
);
4016 for (size_t i
= 0; i
< tuple_dim
; i
++)
4018 Parameter arg
= t
.parameterList
[nfparams
- 1 + i
];
4019 tup
.objects
[i
] = arg
.type
;
4021 (*dedtypes
)[tupi
] = tup
;
4023 nfparams
--; // don't consider the last parameter for type deduction
4028 if (nfargs
!= nfparams
)
4030 result
= MATCH
.nomatch
;
4034 assert(nfparams
<= tp
.parameterList
.length
);
4035 foreach (i
, ap
; tp
.parameterList
)
4040 Parameter a
= t
.parameterList
[i
];
4042 if (!a
.isCovariant(t
.isref
, ap
) ||
4043 !deduceType(a
.type
, sc
, ap
.type
, parameters
, dedtypes
))
4045 result
= MATCH
.nomatch
;
4053 override void visit(TypeIdentifier t
)
4056 if (tparam
&& tparam
.ty
== Tident
)
4058 TypeIdentifier tp
= cast(TypeIdentifier
)tparam
;
4059 for (size_t i
= 0; i
< t
.idents
.length
; i
++)
4061 RootObject id1
= t
.idents
[i
];
4062 RootObject id2
= tp
.idents
[i
];
4063 if (!id1
.equals(id2
))
4065 result
= MATCH
.nomatch
;
4073 override void visit(TypeInstance t
)
4076 if (tparam
&& tparam
.ty
== Tinstance
&& t
.tempinst
.tempdecl
)
4078 TemplateDeclaration tempdecl
= t
.tempinst
.tempdecl
.isTemplateDeclaration();
4081 TypeInstance tp
= cast(TypeInstance
)tparam
;
4083 //printf("tempinst.tempdecl = %p\n", tempdecl);
4084 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
4085 if (!tp
.tempinst
.tempdecl
)
4087 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
4090 * template Foo(T : sa!(T), alias sa)
4092 size_t i
= templateIdentifierLookup(tp
.tempinst
.name
, parameters
);
4093 if (i
== IDX_NOTFOUND
)
4095 /* Didn't find it as a parameter identifier. Try looking
4096 * it up and seeing if is an alias.
4097 * https://issues.dlang.org/show_bug.cgi?id=1454
4099 auto tid
= new TypeIdentifier(tp
.loc
, tp
.tempinst
.name
);
4103 tid
.resolve(tp
.loc
, sc
, e
, tx
, s
);
4106 s
= tx
.toDsymbol(sc
);
4107 if (TemplateInstance ti
= s ? s
.parent
.isTemplateInstance() : null)
4109 // https://issues.dlang.org/show_bug.cgi?id=14290
4110 // Try to match with ti.tempecl,
4111 // only when ti is an enclosing instance.
4112 Dsymbol p
= sc
.parent
;
4113 while (p
&& p
!= ti
)
4122 TemplateDeclaration td
= s
.isTemplateDeclaration();
4127 for (; td
; td
= td
.overnext
)
4137 TemplateParameter tpx
= (*parameters
)[i
];
4138 if (!tpx
.matchArg(sc
, tempdecl
, i
, parameters
, dedtypes
, null))
4141 else if (tempdecl
!= tp
.tempinst
.tempdecl
)
4145 for (size_t i
= 0; 1; i
++)
4147 //printf("\ttest: tempinst.tiargs[%zu]\n", i);
4148 RootObject o1
= null;
4149 if (i
< t
.tempinst
.tiargs
.length
)
4150 o1
= (*t
.tempinst
.tiargs
)[i
];
4151 else if (i
< t
.tempinst
.tdtypes
.length
&& i
< tp
.tempinst
.tiargs
.length
)
4153 // Pick up default arg
4154 o1
= t
.tempinst
.tdtypes
[i
];
4156 else if (i
>= tp
.tempinst
.tiargs
.length
)
4158 //printf("\ttest: o1 = %s\n", o1.toChars());
4159 if (i
>= tp
.tempinst
.tiargs
.length
)
4161 size_t dim
= tempdecl
.parameters
.length
- (tempdecl
.isVariadic() ?
1 : 0);
4162 while (i
< dim
&& ((*tempdecl
.parameters
)[i
].dependent ||
(*tempdecl
.parameters
)[i
].hasDefaultArg()))
4167 break; // match if all remained parameters are dependent
4171 RootObject o2
= (*tp
.tempinst
.tiargs
)[i
];
4172 Type t2
= isType(o2
);
4173 //printf("\ttest: o2 = %s\n", o2.toChars());
4174 size_t j
= (t2
&& t2
.ty
== Tident
&& i
== tp
.tempinst
.tiargs
.length
- 1)
4175 ?
templateParameterLookup(t2
, parameters
) : IDX_NOTFOUND
;
4176 if (j
!= IDX_NOTFOUND
&& j
== parameters
.length
- 1 &&
4177 (*parameters
)[j
].isTemplateTupleParameter())
4181 * alias A!(int, float) X;
4182 * static if (is(X Y == A!(Z), Z...)) {}
4183 * deduce that Z is a tuple(int, float)
4186 /* Create tuple from remaining args
4188 size_t vtdim
= (tempdecl
.isVariadic() ? t
.tempinst
.tiargs
.length
: t
.tempinst
.tdtypes
.length
) - i
;
4189 auto vt
= new Tuple(vtdim
);
4190 for (size_t k
= 0; k
< vtdim
; k
++)
4193 if (k
< t
.tempinst
.tiargs
.length
)
4194 o
= (*t
.tempinst
.tiargs
)[i
+ k
];
4195 else // Pick up default arg
4196 o
= t
.tempinst
.tdtypes
[i
+ k
];
4200 Tuple v
= cast(Tuple
)(*dedtypes
)[j
];
4207 (*dedtypes
)[j
] = vt
;
4213 Type t1
= isType(o1
);
4214 Dsymbol s1
= isDsymbol(o1
);
4215 Dsymbol s2
= isDsymbol(o2
);
4216 Expression e1
= s1 ?
getValue(s1
) : getValue(isExpression(o1
));
4217 Expression e2
= isExpression(o2
);
4220 Tuple v1
= isTuple(o1
);
4221 Tuple v2
= isTuple(o2
);
4223 printf("t1 = %s\n", t1
.toChars());
4225 printf("t2 = %s\n", t2
.toChars());
4227 printf("e1 = %s\n", e1
.toChars());
4229 printf("e2 = %s\n", e2
.toChars());
4231 printf("s1 = %s\n", s1
.toChars());
4233 printf("s2 = %s\n", s2
.toChars());
4235 printf("v1 = %s\n", v1
.toChars());
4237 printf("v2 = %s\n", v2
.toChars());
4242 if (!deduceType(t1
, sc
, t2
, parameters
, dedtypes
))
4248 e1
= e1
.ctfeInterpret();
4250 /* If it is one of the template parameters for this template,
4251 * we should not attempt to interpret it. It already has a value.
4253 if (e2
.op
== EXP
.variable
&& ((cast(VarExp
)e2
).var
.storage_class
& STC
.templateparameter
))
4256 * (T:Number!(e2), int e2)
4258 j
= templateIdentifierLookup((cast(VarExp
)e2
).var
.ident
, parameters
);
4259 if (j
!= IDX_NOTFOUND
)
4261 // The template parameter was not from this template
4262 // (it may be from a parent template, for example)
4265 e2
= e2
.expressionSemantic(sc
); // https://issues.dlang.org/show_bug.cgi?id=13417
4266 e2
= e2
.ctfeInterpret();
4268 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
4269 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
4272 if (!e2
.implicitConvTo(e1
.type
))
4275 e2
= e2
.implicitCastTo(sc
, e1
.type
);
4276 e2
= e2
.ctfeInterpret();
4281 else if (e1
&& t2
&& t2
.ty
== Tident
)
4283 j
= templateParameterLookup(t2
, parameters
);
4285 if (j
== IDX_NOTFOUND
)
4287 t2
.resolve((cast(TypeIdentifier
)t2
).loc
, sc
, e2
, t2
, s2
);
4292 if (!(*parameters
)[j
].matchArg(sc
, e1
, j
, parameters
, dedtypes
, null))
4301 else if (s1
&& t2
&& t2
.ty
== Tident
)
4303 j
= templateParameterLookup(t2
, parameters
);
4304 if (j
== IDX_NOTFOUND
)
4306 t2
.resolve((cast(TypeIdentifier
)t2
).loc
, sc
, e2
, t2
, s2
);
4311 if (!(*parameters
)[j
].matchArg(sc
, s1
, j
, parameters
, dedtypes
, null))
4322 //printf("no match\n");
4323 result
= MATCH
.nomatch
;
4326 override void visit(TypeStruct t
)
4328 /* If this struct is a template struct, and we're matching
4329 * it against a template instance, convert the struct type
4330 * to a template instance, too, and try again.
4332 TemplateInstance ti
= t
.sym
.parent
.isTemplateInstance();
4334 if (tparam
&& tparam
.ty
== Tinstance
)
4336 if (ti
&& ti
.toAlias() == t
.sym
)
4338 auto tx
= new TypeInstance(Loc
.initial
, ti
);
4339 auto m
= deduceType(tx
, sc
, tparam
, parameters
, dedtypes
, wm
);
4340 // if we have a no match we still need to check alias this
4341 if (m
!= MATCH
.nomatch
)
4348 /* Match things like:
4351 TypeInstance tpi
= cast(TypeInstance
)tparam
;
4352 if (tpi
.idents
.length
)
4354 RootObject id
= tpi
.idents
[tpi
.idents
.length
- 1];
4355 if (id
.dyncast() == DYNCAST
.identifier
&& t
.sym
.ident
.equals(cast(Identifier
)id
))
4357 Type tparent
= t
.sym
.parent
.getType();
4360 /* Slice off the .foo in S!(T).foo
4362 tpi
.idents
.length
--;
4363 result
= deduceType(tparent
, sc
, tpi
, parameters
, dedtypes
, wm
);
4364 tpi
.idents
.length
++;
4372 if (tparam
&& tparam
.ty
== Tstruct
)
4374 TypeStruct tp
= cast(TypeStruct
)tparam
;
4376 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4377 if (wm
&& t
.deduceWild(tparam
, false))
4379 result
= MATCH
.constant
;
4382 result
= t
.implicitConvTo(tp
);
4388 override void visit(TypeEnum t
)
4391 if (tparam
&& tparam
.ty
== Tenum
)
4393 TypeEnum tp
= cast(TypeEnum
)tparam
;
4394 if (t
.sym
== tp
.sym
)
4397 result
= MATCH
.nomatch
;
4400 Type tb
= t
.toBasetype();
4401 if (tb
.ty
== tparam
.ty || tb
.ty
== Tsarray
&& tparam
.ty
== Taarray
)
4403 result
= deduceType(tb
, sc
, tparam
, parameters
, dedtypes
, wm
);
4404 if (result
== MATCH
.exact
)
4405 result
= MATCH
.convert
;
4411 /* Helper for TypeClass.deduceType().
4412 * Classes can match with implicit conversion to a base class or interface.
4413 * This is complicated, because there may be more than one base class which
4414 * matches. In such cases, one or more parameters remain ambiguous.
4417 * interface I(X, Y) {}
4418 * class C : I(uint, double), I(char, double) {}
4420 * foo(T, U)( I!(T, U) x)
4422 * deduces that U is double, but T remains ambiguous (could be char or uint).
4424 * Given a baseclass b, and initial deduced types 'dedtypes', this function
4425 * tries to match tparam with b, and also tries all base interfaces of b.
4426 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
4427 * types are ANDed with the current 'best' estimate for dedtypes.
4429 static void deduceBaseClassParameters(ref BaseClass b
, Scope
* sc
, Type tparam
, TemplateParameters
* parameters
, Objects
* dedtypes
, Objects
* best
, ref int numBaseClassMatches
)
4431 TemplateInstance parti
= b
.sym ? b
.sym
.parent
.isTemplateInstance() : null;
4434 // Make a temporary copy of dedtypes so we don't destroy it
4435 auto tmpdedtypes
= new Objects(dedtypes
.length
);
4436 memcpy(tmpdedtypes
.tdata(), dedtypes
.tdata(), dedtypes
.length
* (void*).sizeof
);
4438 auto t
= new TypeInstance(Loc
.initial
, parti
);
4439 MATCH m
= deduceType(t
, sc
, tparam
, parameters
, tmpdedtypes
);
4440 if (m
> MATCH
.nomatch
)
4442 // If this is the first ever match, it becomes our best estimate
4443 if (numBaseClassMatches
== 0)
4444 memcpy(best
.tdata(), tmpdedtypes
.tdata(), tmpdedtypes
.length
* (void*).sizeof
);
4446 for (size_t k
= 0; k
< tmpdedtypes
.length
; ++k
)
4448 // If we've found more than one possible type for a parameter,
4449 // mark it as unknown.
4450 if ((*tmpdedtypes
)[k
] != (*best
)[k
])
4451 (*best
)[k
] = (*dedtypes
)[k
];
4453 ++numBaseClassMatches
;
4457 // Now recursively test the inherited interfaces
4458 foreach (ref bi
; b
.baseInterfaces
)
4460 deduceBaseClassParameters(bi
, sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
4464 override void visit(TypeClass t
)
4466 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
4468 /* If this class is a template class, and we're matching
4469 * it against a template instance, convert the class type
4470 * to a template instance, too, and try again.
4472 TemplateInstance ti
= t
.sym
.parent
.isTemplateInstance();
4474 if (tparam
&& tparam
.ty
== Tinstance
)
4476 if (ti
&& ti
.toAlias() == t
.sym
)
4478 auto tx
= new TypeInstance(Loc
.initial
, ti
);
4479 MATCH m
= deduceType(tx
, sc
, tparam
, parameters
, dedtypes
, wm
);
4480 // Even if the match fails, there is still a chance it could match
4482 if (m
!= MATCH
.nomatch
)
4489 /* Match things like:
4492 TypeInstance tpi
= cast(TypeInstance
)tparam
;
4493 if (tpi
.idents
.length
)
4495 RootObject id
= tpi
.idents
[tpi
.idents
.length
- 1];
4496 if (id
.dyncast() == DYNCAST
.identifier
&& t
.sym
.ident
.equals(cast(Identifier
)id
))
4498 Type tparent
= t
.sym
.parent
.getType();
4501 /* Slice off the .foo in S!(T).foo
4503 tpi
.idents
.length
--;
4504 result
= deduceType(tparent
, sc
, tpi
, parameters
, dedtypes
, wm
);
4505 tpi
.idents
.length
++;
4511 // If it matches exactly or via implicit conversion, we're done
4513 if (result
!= MATCH
.nomatch
)
4516 /* There is still a chance to match via implicit conversion to
4517 * a base class or interface. Because there could be more than one such
4518 * match, we need to check them all.
4521 int numBaseClassMatches
= 0; // Have we found an interface match?
4523 // Our best guess at dedtypes
4524 auto best
= new Objects(dedtypes
.length
);
4526 ClassDeclaration s
= t
.sym
;
4527 while (s
&& s
.baseclasses
.length
> 0)
4529 // Test the base class
4530 deduceBaseClassParameters(*(*s
.baseclasses
)[0], sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
4532 // Test the interfaces inherited by the base class
4533 foreach (b
; s
.interfaces
)
4535 deduceBaseClassParameters(*b
, sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
4537 s
= (*s
.baseclasses
)[0].sym
;
4540 if (numBaseClassMatches
== 0)
4542 result
= MATCH
.nomatch
;
4546 // If we got at least one match, copy the known types into dedtypes
4547 memcpy(dedtypes
.tdata(), best
.tdata(), best
.length
* (void*).sizeof
);
4548 result
= MATCH
.convert
;
4553 if (tparam
&& tparam
.ty
== Tclass
)
4555 TypeClass tp
= cast(TypeClass
)tparam
;
4557 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4558 if (wm
&& t
.deduceWild(tparam
, false))
4560 result
= MATCH
.constant
;
4563 result
= t
.implicitConvTo(tp
);
4569 override void visit(Expression e
)
4571 //printf("Expression.deduceType(e = %s)\n", e.toChars());
4572 size_t i
= templateParameterLookup(tparam
, parameters
);
4573 if (i
== IDX_NOTFOUND ||
(cast(TypeIdentifier
)tparam
).idents
.length
> 0)
4575 if (e
== emptyArrayElement
&& tparam
.ty
== Tarray
)
4577 Type tn
= (cast(TypeNext
)tparam
).next
;
4578 result
= deduceType(emptyArrayElement
, sc
, tn
, parameters
, dedtypes
, wm
);
4581 e
.type
.accept(this);
4585 TemplateTypeParameter tp
= (*parameters
)[i
].isTemplateTypeParameter();
4589 if (e
== emptyArrayElement
)
4593 result
= MATCH
.exact
;
4598 tp
.defaultType
.accept(this);
4603 /* Returns `true` if `t` is a reference type, or an array of reference types
4605 bool isTopRef(Type t
)
4607 auto tb
= t
.baseElemOf();
4608 return tb
.ty
== Tclass ||
4610 tb
.ty
== Tstruct
&& tb
.hasPointers();
4613 Type at
= cast(Type
)(*dedtypes
)[i
];
4615 if (ubyte wx
= deduceWildHelper(e
.type
, &tt
, tparam
))
4618 result
= MATCH
.constant
;
4620 else if (MATCH m
= deduceTypeHelper(e
.type
, &tt
, tparam
))
4624 else if (!isTopRef(e
.type
))
4626 /* https://issues.dlang.org/show_bug.cgi?id=15653
4627 * In IFTI, recognize top-qualifier conversions
4628 * through the value copy, e.g.
4629 * int --> immutable(int)
4630 * immutable(string[]) --> immutable(string)[]
4632 tt
= e
.type
.mutableOf();
4633 result
= MATCH
.convert
;
4638 // expression vs (none)
4641 (*dedtypes
)[i
] = new TypeDeduced(tt
, e
, tparam
);
4645 TypeDeduced xt
= null;
4648 xt
= cast(TypeDeduced
)at
;
4652 // From previous matched expressions to current deduced type
4653 MATCH match1
= xt ? xt
.matchAll(tt
) : MATCH
.nomatch
;
4655 // From current expressions to previous deduced type
4656 Type pt
= at
.addMod(tparam
.mod
);
4658 pt
= pt
.substWildTo(*wm
);
4659 MATCH match2
= e
.implicitConvTo(pt
);
4661 if (match1
> MATCH
.nomatch
&& match2
> MATCH
.nomatch
)
4663 if (at
.implicitConvTo(tt
) == MATCH
.nomatch
)
4664 match1
= MATCH
.nomatch
; // Prefer at
4665 else if (tt
.implicitConvTo(at
) == MATCH
.nomatch
)
4666 match2
= MATCH
.nomatch
; // Prefer tt
4667 else if (tt
.isTypeBasic() && tt
.ty
== at
.ty
&& tt
.mod
!= at
.mod
)
4669 if (!tt
.isMutable() && !at
.isMutable())
4670 tt
= tt
.mutableOf().addMod(MODmerge(tt
.mod
, at
.mod
));
4671 else if (tt
.isMutable())
4673 if (at
.mod
== 0) // Prefer unshared
4674 match1
= MATCH
.nomatch
;
4676 match2
= MATCH
.nomatch
;
4678 else if (at
.isMutable())
4680 if (tt
.mod
== 0) // Prefer unshared
4681 match2
= MATCH
.nomatch
;
4683 match1
= MATCH
.nomatch
;
4685 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
4689 match1
= MATCH
.nomatch
;
4690 match2
= MATCH
.nomatch
;
4693 if (match1
> MATCH
.nomatch
)
4695 // Prefer current match: tt
4697 xt
.update(tt
, e
, tparam
);
4699 (*dedtypes
)[i
] = tt
;
4703 if (match2
> MATCH
.nomatch
)
4705 // Prefer previous match: (*dedtypes)[i]
4707 xt
.update(e
, tparam
);
4712 /* Deduce common type
4714 if (Type t
= rawTypeMerge(at
, tt
))
4717 xt
.update(t
, e
, tparam
);
4721 pt
= tt
.addMod(tparam
.mod
);
4723 pt
= pt
.substWildTo(*wm
);
4724 result
= e
.implicitConvTo(pt
);
4728 result
= MATCH
.nomatch
;
4731 MATCH
deduceEmptyArrayElement()
4733 if (!emptyArrayElement
)
4735 emptyArrayElement
= new IdentifierExp(Loc
.initial
, Id
.p
); // dummy
4736 emptyArrayElement
.type
= Type
.tvoid
;
4738 assert(tparam
.ty
== Tarray
);
4740 Type tn
= (cast(TypeNext
)tparam
).next
;
4741 return deduceType(emptyArrayElement
, sc
, tn
, parameters
, dedtypes
, wm
);
4744 override void visit(NullExp e
)
4746 if (tparam
.ty
== Tarray
&& e
.type
.ty
== Tnull
)
4748 // tparam:T[] <- e:null (void[])
4749 result
= deduceEmptyArrayElement();
4752 visit(cast(Expression
)e
);
4755 override void visit(StringExp e
)
4758 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
4760 // Consider compile-time known boundaries
4761 e
.type
.nextOf().sarrayOf(e
.len
).accept(this);
4764 visit(cast(Expression
)e
);
4767 override void visit(ArrayLiteralExp e
)
4769 // https://issues.dlang.org/show_bug.cgi?id=20092
4770 if (e
.elements
&& e
.elements
.length
&& e
.type
.toBasetype().nextOf().ty
== Tvoid
)
4772 result
= deduceEmptyArrayElement();
4775 if ((!e
.elements ||
!e
.elements
.length
) && e
.type
.toBasetype().nextOf().ty
== Tvoid
&& tparam
.ty
== Tarray
)
4777 // tparam:T[] <- e:[] (void[])
4778 result
= deduceEmptyArrayElement();
4782 if (tparam
.ty
== Tarray
&& e
.elements
&& e
.elements
.length
)
4784 Type tn
= (cast(TypeDArray
)tparam
).next
;
4785 result
= MATCH
.exact
;
4788 MATCH m
= deduceType(e
.basis
, sc
, tn
, parameters
, dedtypes
, wm
);
4792 foreach (el
; *e
.elements
)
4794 if (result
== MATCH
.nomatch
)
4798 MATCH m
= deduceType(el
, sc
, tn
, parameters
, dedtypes
, wm
);
4806 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
4808 // Consider compile-time known boundaries
4809 e
.type
.nextOf().sarrayOf(e
.elements
.length
).accept(this);
4812 visit(cast(Expression
)e
);
4815 override void visit(AssocArrayLiteralExp e
)
4817 if (tparam
.ty
== Taarray
&& e
.keys
&& e
.keys
.length
)
4819 TypeAArray taa
= cast(TypeAArray
)tparam
;
4820 result
= MATCH
.exact
;
4821 foreach (i
, key
; *e
.keys
)
4823 MATCH m1
= deduceType(key
, sc
, taa
.index
, parameters
, dedtypes
, wm
);
4826 if (result
== MATCH
.nomatch
)
4828 MATCH m2
= deduceType((*e
.values
)[i
], sc
, taa
.next
, parameters
, dedtypes
, wm
);
4831 if (result
== MATCH
.nomatch
)
4836 visit(cast(Expression
)e
);
4839 override void visit(FuncExp e
)
4841 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
4847 auto tof
= to
.nextOf().isTypeFunction();
4851 // Parameter types inference from 'tof'
4852 assert(e
.td
._scope
);
4853 TypeFunction tf
= cast(TypeFunction
)e
.fd
.type
;
4854 //printf("\ttof = %s\n", tof.toChars());
4855 //printf("\ttf = %s\n", tf.toChars());
4856 const dim
= tf
.parameterList
.length
;
4858 if (tof
.parameterList
.length
!= dim || tof
.parameterList
.varargs
!= tf
.parameterList
.varargs
)
4861 auto tiargs
= new Objects();
4862 tiargs
.reserve(e
.td
.parameters
.length
);
4864 foreach (tp
; *e
.td
.parameters
)
4867 foreach (i
, p
; tf
.parameterList
)
4869 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
4874 Parameter pto
= tof
.parameterList
[u
];
4877 Type t
= pto
.type
.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
4878 if (reliesOnTemplateParameters(t
, (*parameters
)[inferStart
.. parameters
.length
]))
4880 t
= t
.typeSemantic(e
.loc
, sc
);
4886 // Set target of return type inference
4887 if (!tf
.next
&& tof
.next
)
4890 auto ti
= new TemplateInstance(e
.loc
, e
.td
, tiargs
);
4891 Expression ex
= (new ScopeExp(e
.loc
, ti
)).expressionSemantic(e
.td
._scope
);
4893 // Reset inference target for the later re-semantic
4896 if (ex
.op
== EXP
.error
)
4898 if (ex
.op
!= EXP
.function_
)
4906 if (t
.ty
== Tdelegate
&& tparam
.ty
== Tpointer
)
4909 // Allow conversion from implicit function pointer to delegate
4910 if (e
.tok
== TOK
.reserved
&& t
.ty
== Tpointer
&& tparam
.ty
== Tdelegate
)
4912 TypeFunction tf
= cast(TypeFunction
)t
.nextOf();
4913 t
= (new TypeDelegate(tf
)).merge();
4915 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
4919 override void visit(SliceExp e
)
4922 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
4924 // Consider compile-time known boundaries
4925 if (Type tsa
= toStaticArrayType(e
))
4928 if (result
> MATCH
.convert
)
4929 result
= MATCH
.convert
; // match with implicit conversion at most
4933 visit(cast(Expression
)e
);
4936 override void visit(CommaExp e
)
4942 scope DeduceType v
= new DeduceType(sc
, tparam
, parameters
, dedtypes
, wm
, inferStart
, ignoreAliasThis
);
4943 if (Type t
= isType(o
))
4945 else if (Expression e
= isExpression(o
))
4955 /***********************************************************
4956 * Check whether the type t representation relies on one or more the template parameters.
4958 * t = Tested type, if null, returns false.
4959 * tparams = Template parameters.
4960 * iStart = Start index of tparams to limit the tested parameters. If it's
4961 * nonzero, tparams[0..iStart] will be excluded from the test target.
4963 bool reliesOnTident(Type t
, TemplateParameters
* tparams
, size_t iStart
= 0)
4965 return reliesOnTemplateParameters(t
, (*tparams
)[0 .. tparams
.length
]);
4968 /***********************************************************
4969 * Check whether the type t representation relies on one or more the template parameters.
4971 * t = Tested type, if null, returns false.
4972 * tparams = Template parameters.
4974 private bool reliesOnTemplateParameters(Type t
, TemplateParameter
[] tparams
)
4976 bool visitVector(TypeVector t
)
4978 return t
.basetype
.reliesOnTemplateParameters(tparams
);
4981 bool visitAArray(TypeAArray t
)
4983 return t
.next
.reliesOnTemplateParameters(tparams
) ||
4984 t
.index
.reliesOnTemplateParameters(tparams
);
4987 bool visitFunction(TypeFunction t
)
4989 foreach (i
, fparam
; t
.parameterList
)
4991 if (fparam
.type
.reliesOnTemplateParameters(tparams
))
4994 return t
.next
.reliesOnTemplateParameters(tparams
);
4997 bool visitIdentifier(TypeIdentifier t
)
4999 foreach (tp
; tparams
)
5001 if (tp
.ident
.equals(t
.ident
))
5007 bool visitInstance(TypeInstance t
)
5009 foreach (tp
; tparams
)
5011 if (t
.tempinst
.name
== tp
.ident
)
5015 if (t
.tempinst
.tiargs
)
5016 foreach (arg
; *t
.tempinst
.tiargs
)
5018 if (Type ta
= isType(arg
))
5020 if (ta
.reliesOnTemplateParameters(tparams
))
5028 bool visitTypeof(TypeTypeof t
)
5030 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
5031 return t
.exp
.reliesOnTemplateParameters(tparams
);
5034 bool visitTuple(TypeTuple t
)
5037 foreach (arg
; *t
.arguments
)
5039 if (arg
.type
.reliesOnTemplateParameters(tparams
))
5049 Type tb
= t
.toBasetype();
5052 case Tvector
: return visitVector(tb
.isTypeVector());
5053 case Taarray
: return visitAArray(tb
.isTypeAArray());
5054 case Tfunction
: return visitFunction(tb
.isTypeFunction());
5055 case Tident
: return visitIdentifier(tb
.isTypeIdentifier());
5056 case Tinstance
: return visitInstance(tb
.isTypeInstance());
5057 case Ttypeof
: return visitTypeof(tb
.isTypeTypeof());
5058 case Ttuple
: return visitTuple(tb
.isTypeTuple());
5059 case Tenum
: return false;
5060 default: return tb
.nextOf().reliesOnTemplateParameters(tparams
);
5064 /***********************************************************
5065 * Check whether the expression representation relies on one or more the template parameters.
5067 * e = expression to test
5068 * tparams = Template parameters.
5072 private bool reliesOnTemplateParameters(Expression e
, TemplateParameter
[] tparams
)
5074 extern (C
++) final class ReliesOnTemplateParameters
: Visitor
5076 alias visit
= Visitor
.visit
;
5078 TemplateParameter
[] tparams
;
5081 extern (D
) this(TemplateParameter
[] tparams
)
5083 this.tparams
= tparams
;
5086 override void visit(Expression e
)
5088 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
5091 override void visit(IdentifierExp e
)
5093 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5094 foreach (tp
; tparams
)
5096 if (e
.ident
== tp
.ident
)
5104 override void visit(TupleExp e
)
5106 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5109 foreach (ea
; *e
.exps
)
5118 override void visit(ArrayLiteralExp e
)
5120 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5123 foreach (el
; *e
.elements
)
5132 override void visit(AssocArrayLiteralExp e
)
5134 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5135 foreach (ek
; *e
.keys
)
5141 foreach (ev
; *e
.values
)
5149 override void visit(StructLiteralExp e
)
5151 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5154 foreach (ea
; *e
.elements
)
5163 override void visit(TypeExp e
)
5165 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5166 result
= e
.type
.reliesOnTemplateParameters(tparams
);
5169 override void visit(NewExp e
)
5171 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5173 e
.thisexp
.accept(this);
5174 result
= e
.newtype
.reliesOnTemplateParameters(tparams
);
5175 if (!result
&& e
.arguments
)
5177 foreach (ea
; *e
.arguments
)
5186 override void visit(NewAnonClassExp e
)
5188 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5192 override void visit(FuncExp e
)
5194 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5198 override void visit(TypeidExp e
)
5200 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5201 if (auto ea
= isExpression(e
.obj
))
5203 else if (auto ta
= isType(e
.obj
))
5204 result
= ta
.reliesOnTemplateParameters(tparams
);
5207 override void visit(TraitsExp e
)
5209 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5212 foreach (oa
; *e
.args
)
5214 if (auto ea
= isExpression(oa
))
5216 else if (auto ta
= isType(oa
))
5217 result
= ta
.reliesOnTemplateParameters(tparams
);
5224 override void visit(IsExp e
)
5226 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5227 result
= e
.targ
.reliesOnTemplateParameters(tparams
);
5230 override void visit(UnaExp e
)
5232 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5236 override void visit(DotTemplateInstanceExp e
)
5238 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5239 visit(cast(UnaExp
)e
);
5240 if (!result
&& e
.ti
.tiargs
)
5242 foreach (oa
; *e
.ti
.tiargs
)
5244 if (auto ea
= isExpression(oa
))
5246 else if (auto ta
= isType(oa
))
5247 result
= ta
.reliesOnTemplateParameters(tparams
);
5254 override void visit(CallExp e
)
5256 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5257 visit(cast(UnaExp
)e
);
5258 if (!result
&& e
.arguments
)
5260 foreach (ea
; *e
.arguments
)
5269 override void visit(CastExp e
)
5271 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5272 visit(cast(UnaExp
)e
);
5273 // e.to can be null for cast() with no type
5274 if (!result
&& e
.to
)
5275 result
= e
.to
.reliesOnTemplateParameters(tparams
);
5278 override void visit(SliceExp e
)
5280 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5281 visit(cast(UnaExp
)e
);
5282 if (!result
&& e
.lwr
)
5284 if (!result
&& e
.upr
)
5288 override void visit(IntervalExp e
)
5290 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5296 override void visit(ArrayExp e
)
5298 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5299 visit(cast(UnaExp
)e
);
5300 if (!result
&& e
.arguments
)
5302 foreach (ea
; *e
.arguments
)
5307 override void visit(BinExp e
)
5309 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5315 override void visit(CondExp e
)
5317 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5318 e
.econd
.accept(this);
5320 visit(cast(BinExp
)e
);
5324 scope ReliesOnTemplateParameters v
= new ReliesOnTemplateParameters(tparams
);
5329 /***********************************************************
5330 * https://dlang.org/spec/template.html#TemplateParameter
5332 extern (C
++) class TemplateParameter
: ASTNode
5337 /* True if this is a part of precedent parameter specialization pattern.
5339 * template A(T : X!TL, alias X, TL...) {}
5340 * // X and TL are dependent template parameter
5342 * A dependent template parameter should return MATCH.exact in matchArg()
5343 * to respect the match level of the corresponding precedent parameter.
5347 /* ======================== TemplateParameter =============================== */
5348 extern (D
) this(const ref Loc loc
, Identifier ident
)
5354 TemplateTypeParameter
isTemplateTypeParameter()
5359 TemplateValueParameter
isTemplateValueParameter()
5364 TemplateAliasParameter
isTemplateAliasParameter()
5369 TemplateThisParameter
isTemplateThisParameter()
5374 TemplateTupleParameter
isTemplateTupleParameter()
5379 abstract TemplateParameter
syntaxCopy();
5381 abstract bool declareParameter(Scope
* sc
);
5383 abstract void print(RootObject oarg
, RootObject oded
);
5385 abstract RootObject
specialization();
5387 abstract RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
);
5389 abstract bool hasDefaultArg();
5391 override const(char)* toChars() const
5393 return this.ident
.toChars();
5396 override DYNCAST
dyncast() const
5398 return DYNCAST
.templateparameter
;
5401 /* Create dummy argument based on parameter.
5403 abstract RootObject
dummyArg();
5405 override void accept(Visitor v
)
5411 /***********************************************************
5412 * https://dlang.org/spec/template.html#TemplateTypeParameter
5414 * ident : specType = defaultType
5416 extern (C
++) class TemplateTypeParameter
: TemplateParameter
5418 Type specType
; // if !=null, this is the type specialization
5421 extern (D
) __gshared Type tdummy
= null;
5423 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, Type defaultType
)
5426 this.specType
= specType
;
5427 this.defaultType
= defaultType
;
5430 override final TemplateTypeParameter
isTemplateTypeParameter()
5435 override TemplateTypeParameter
syntaxCopy()
5437 return new TemplateTypeParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, defaultType ? defaultType
.syntaxCopy() : null);
5440 override final bool declareParameter(Scope
* sc
)
5442 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
5443 auto ti
= new TypeIdentifier(loc
, ident
);
5444 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
5445 return sc
.insert(ad
) !is null;
5448 override final void print(RootObject oarg
, RootObject oded
)
5450 printf(" %s\n", ident
.toChars());
5452 Type t
= isType(oarg
);
5453 Type ta
= isType(oded
);
5457 printf("\tSpecialization: %s\n", specType
.toChars());
5459 printf("\tDefault: %s\n", defaultType
.toChars());
5460 printf("\tParameter: %s\n", t ? t
.toChars() : "NULL");
5461 printf("\tDeduced Type: %s\n", ta
.toChars());
5464 override final RootObject
specialization()
5469 override final RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5471 Type t
= defaultType
;
5475 t
= t
.typeSemantic(loc
, sc
); // use the parameter loc
5480 override final bool hasDefaultArg()
5482 return defaultType
!is null;
5485 override final RootObject
dummyArg()
5490 // Use this for alias-parameter's too (?)
5492 tdummy
= new TypeIdentifier(loc
, ident
);
5498 override void accept(Visitor v
)
5504 /***********************************************************
5505 * https://dlang.org/spec/template.html#TemplateThisParameter
5507 * this ident : specType = defaultType
5509 extern (C
++) final class TemplateThisParameter
: TemplateTypeParameter
5511 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, Type defaultType
)
5513 super(loc
, ident
, specType
, defaultType
);
5516 override TemplateThisParameter
isTemplateThisParameter()
5521 override TemplateThisParameter
syntaxCopy()
5523 return new TemplateThisParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, defaultType ? defaultType
.syntaxCopy() : null);
5526 override void accept(Visitor v
)
5532 /***********************************************************
5533 * https://dlang.org/spec/template.html#TemplateValueParameter
5535 * valType ident : specValue = defaultValue
5537 extern (C
++) final class TemplateValueParameter
: TemplateParameter
5540 Expression specValue
;
5541 Expression defaultValue
;
5543 extern (D
) __gshared Expression
[void*] edummies
;
5545 extern (D
) this(const ref Loc loc
, Identifier ident
, Type valType
,
5546 Expression specValue
, Expression defaultValue
)
5549 this.valType
= valType
;
5550 this.specValue
= specValue
;
5551 this.defaultValue
= defaultValue
;
5554 override TemplateValueParameter
isTemplateValueParameter()
5559 override TemplateValueParameter
syntaxCopy()
5561 return new TemplateValueParameter(loc
, ident
,
5562 valType
.syntaxCopy(),
5563 specValue ? specValue
.syntaxCopy() : null,
5564 defaultValue ? defaultValue
.syntaxCopy() : null);
5567 override bool declareParameter(Scope
* sc
)
5570 Do type semantic earlier.
5572 This means for certain erroneous value parameters
5573 their "type" can be known earlier and thus a better
5574 error message given.
5577 `template test(x* x) {}`
5578 now yields "undefined identifier" rather than the opaque
5579 "variable `x` is used as a type".
5582 valType
= valType
.typeSemantic(loc
, sc
);
5583 auto v
= new VarDeclaration(loc
, valType
, ident
, null);
5584 v
.storage_class
= STC
.templateparameter
;
5585 return sc
.insert(v
) !is null;
5588 override void print(RootObject oarg
, RootObject oded
)
5590 printf(" %s\n", ident
.toChars());
5591 Expression ea
= isExpression(oded
);
5593 printf("\tSpecialization: %s\n", specValue
.toChars());
5594 printf("\tParameter Value: %s\n", ea ? ea
.toChars() : "NULL");
5597 override RootObject
specialization()
5602 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5604 Expression e
= defaultValue
;
5608 if ((e
= e
.expressionSemantic(sc
)) is null)
5610 if (auto te
= e
.isTemplateExp())
5612 assert(sc
&& sc
.tinst
);
5613 if (te
.td
== sc
.tinst
.tempdecl
)
5615 // defaultValue is a reference to its template declaration
5616 // i.e: `template T(int arg = T)`
5617 // Raise error now before calling resolveProperties otherwise we'll
5618 // start looping on the expansion of the template instance.
5619 sc
.tinst
.tempdecl
.error("recursive template expansion");
5620 return ErrorExp
.get();
5623 if ((e
= resolveProperties(sc
, e
)) is null)
5625 e
= e
.resolveLoc(instLoc
, sc
); // use the instantiated loc
5626 e
= e
.optimize(WANTvalue
);
5631 override bool hasDefaultArg()
5633 return defaultValue
!is null;
5636 override RootObject
dummyArg()
5638 Expression e
= specValue
;
5641 // Create a dummy value
5642 auto pe
= cast(void*)valType
in edummies
;
5645 e
= valType
.defaultInit(Loc
.initial
);
5646 edummies
[cast(void*)valType
] = e
;
5654 override void accept(Visitor v
)
5660 /***********************************************************
5661 * https://dlang.org/spec/template.html#TemplateAliasParameter
5663 * specType ident : specAlias = defaultAlias
5665 extern (C
++) final class TemplateAliasParameter
: TemplateParameter
5668 RootObject specAlias
;
5669 RootObject defaultAlias
;
5671 extern (D
) __gshared Dsymbol sdummy
= null;
5673 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, RootObject specAlias
, RootObject defaultAlias
)
5676 this.specType
= specType
;
5677 this.specAlias
= specAlias
;
5678 this.defaultAlias
= defaultAlias
;
5681 override TemplateAliasParameter
isTemplateAliasParameter()
5686 override TemplateAliasParameter
syntaxCopy()
5688 return new TemplateAliasParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, objectSyntaxCopy(specAlias
), objectSyntaxCopy(defaultAlias
));
5691 override bool declareParameter(Scope
* sc
)
5693 auto ti
= new TypeIdentifier(loc
, ident
);
5694 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
5695 return sc
.insert(ad
) !is null;
5698 override void print(RootObject oarg
, RootObject oded
)
5700 printf(" %s\n", ident
.toChars());
5701 Dsymbol sa
= isDsymbol(oded
);
5703 printf("\tParameter alias: %s\n", sa
.toChars());
5706 override RootObject
specialization()
5711 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5713 RootObject
da = defaultAlias
;
5714 Type ta
= isType(defaultAlias
);
5717 if (ta
.ty
== Tinstance
)
5719 // If the default arg is a template, instantiate for each type
5720 da = ta
.syntaxCopy();
5724 RootObject o
= aliasParameterSemantic(loc
, sc
, da, null); // use the parameter loc
5728 override bool hasDefaultArg()
5730 return defaultAlias
!is null;
5733 override RootObject
dummyArg()
5735 RootObject s
= specAlias
;
5739 sdummy
= new Dsymbol();
5745 override void accept(Visitor v
)
5751 /***********************************************************
5752 * https://dlang.org/spec/template.html#TemplateSequenceParameter
5756 extern (C
++) final class TemplateTupleParameter
: TemplateParameter
5758 extern (D
) this(const ref Loc loc
, Identifier ident
)
5763 override TemplateTupleParameter
isTemplateTupleParameter()
5768 override TemplateTupleParameter
syntaxCopy()
5770 return new TemplateTupleParameter(loc
, ident
);
5773 override bool declareParameter(Scope
* sc
)
5775 auto ti
= new TypeIdentifier(loc
, ident
);
5776 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
5777 return sc
.insert(ad
) !is null;
5780 override void print(RootObject oarg
, RootObject oded
)
5782 printf(" %s... [", ident
.toChars());
5783 Tuple v
= isTuple(oded
);
5786 //printf("|%d| ", v.objects.length);
5787 foreach (i
, o
; v
.objects
)
5792 Dsymbol sa
= isDsymbol(o
);
5794 printf("alias: %s", sa
.toChars());
5795 Type ta
= isType(o
);
5797 printf("type: %s", ta
.toChars());
5798 Expression ea
= isExpression(o
);
5800 printf("exp: %s", ea
.toChars());
5802 assert(!isTuple(o
)); // no nested Tuple arguments
5807 override RootObject
specialization()
5812 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5817 override bool hasDefaultArg()
5822 override RootObject
dummyArg()
5827 override void accept(Visitor v
)
5833 /***********************************************************
5834 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
5840 extern (C
++) class TemplateInstance
: ScopeDsymbol
5844 // Array of Types/Expressions of template
5845 // instance arguments [int*, char, 10*10]
5848 // Array of Types/Expressions corresponding
5849 // to TemplateDeclaration.parameters
5853 // Modules imported by this template instance
5854 Modules importedModules
;
5856 Dsymbol tempdecl
; // referenced by foo.bar.abc
5857 Dsymbol enclosing
; // if referencing local symbols, this is the context
5858 Dsymbol aliasdecl
; // !=null if instance is an alias for its sole member
5859 TemplateInstance inst
; // refer to existing instance
5860 ScopeDsymbol argsym
; // argument symbol table
5861 size_t hash
; // cached result of toHash()
5862 Expressions
* fargs
; // for function template, these are the function arguments
5864 TemplateInstances
* deferred
;
5866 Module memberOf
; // if !null, then this TemplateInstance appears in memberOf.members[]
5868 // Used to determine the instance needs code generation.
5869 // Note that these are inaccurate until semantic analysis phase completed.
5870 TemplateInstance tinst
; // enclosing template instance
5871 TemplateInstance tnext
; // non-first instantiated instances
5872 Module minst
; // the top module that instantiated this instance
5874 private ushort _nest
; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
5875 ubyte inuse
; // for recursive expansion detection
5877 private enum Flag
: uint
5879 semantictiargsdone
= 1u << (_nest
.sizeof
* 8 - 1), // MSB of _nest
5880 havetempdecl
= semantictiargsdone
>> 1,
5881 gagged
= semantictiargsdone
>> 2,
5882 available
= gagged
- 1 // always last flag minus one, 1s for all available bits
5885 extern(D
) final @safe @property pure nothrow @nogc
5887 ushort nest() const { return _nest
& Flag
.available
; }
5888 void nestUp() { assert(nest() < Flag
.available
); ++_nest
; }
5889 void nestDown() { assert(nest() > 0); --_nest
; }
5890 /// has semanticTiargs() been done?
5891 bool semantictiargsdone() const { return (_nest
& Flag
.semantictiargsdone
) != 0; }
5892 void semantictiargsdone(bool x
)
5894 if (x
) _nest |
= Flag
.semantictiargsdone
;
5895 else _nest
&= ~Flag
.semantictiargsdone
;
5897 /// if used second constructor
5898 bool havetempdecl() const { return (_nest
& Flag
.havetempdecl
) != 0; }
5899 void havetempdecl(bool x
)
5901 if (x
) _nest |
= Flag
.havetempdecl
;
5902 else _nest
&= ~Flag
.havetempdecl
;
5904 /// if the instantiation is done with error gagging
5905 bool gagged() const { return (_nest
& Flag
.gagged
) != 0; }
5908 if (x
) _nest |
= Flag
.gagged
;
5909 else _nest
&= ~Flag
.gagged
;
5913 extern (D
) this(const ref Loc loc
, Identifier ident
, Objects
* tiargs
) scope
5918 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident
.toChars() : "null");
5921 this.tiargs
= tiargs
;
5925 * This constructor is only called when we figured out which function
5926 * template to instantiate.
5928 extern (D
) this(const ref Loc loc
, TemplateDeclaration td
, Objects
* tiargs
) scope
5933 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td
.toChars());
5935 this.name
= td
.ident
;
5936 this.tiargs
= tiargs
;
5938 this.semantictiargsdone
= true;
5939 this.havetempdecl
= true;
5940 assert(tempdecl
._scope
);
5943 extern (D
) static Objects
* arraySyntaxCopy(Objects
* objs
)
5948 a
= new Objects(objs
.length
);
5949 foreach (i
, o
; *objs
)
5950 (*a
)[i
] = objectSyntaxCopy(o
);
5955 override TemplateInstance
syntaxCopy(Dsymbol s
)
5957 TemplateInstance ti
= s ?
cast(TemplateInstance
)s
: new TemplateInstance(loc
, name
, null);
5958 ti
.tiargs
= arraySyntaxCopy(tiargs
);
5959 TemplateDeclaration td
;
5960 if (inst
&& tempdecl
&& (td
= tempdecl
.isTemplateDeclaration()) !is null)
5961 td
.ScopeDsymbol
.syntaxCopy(ti
);
5963 ScopeDsymbol
.syntaxCopy(ti
);
5967 // resolve real symbol
5968 override final Dsymbol
toAlias()
5972 printf("TemplateInstance.toAlias()\n");
5976 // Maybe we can resolve it
5979 dsymbolSemantic(this, _scope
);
5983 error("cannot resolve forward reference");
5990 return inst
.toAlias();
5994 return aliasdecl
.toAlias();
6000 override const(char)* kind() const
6002 return "template instance";
6005 override bool oneMember(Dsymbol
* ps
, Identifier ident
)
6011 override const(char)* toChars() const
6014 toCBufferInstance(this, &buf
);
6015 return buf
.extractChars();
6018 override final const(char)* toPrettyCharsHelper()
6021 toCBufferInstance(this, &buf
, true);
6022 return buf
.extractChars();
6025 /**************************************
6026 * Given an error instantiating the TemplateInstance,
6027 * give the nested TemplateInstance instantiations that got
6028 * us here. Those are a list threaded into the nested scopes.
6030 extern(D
) final void printInstantiationTrace(Classification cl
= Classification
.error
)
6035 // Print full trace for verbose mode, otherwise only short traces
6036 const(uint) max_shown
= !global
.params
.verbose ?
6037 (global
.params
.errorSupplementLimit ? global
.params
.errorSupplementLimit
: uint.max
)
6040 const(char)* format
= "instantiated from here: `%s`";
6042 // This returns a function pointer
6043 scope printFn
= () {
6046 case Classification
.error
:
6047 return &errorSupplemental
;
6048 case Classification
.warning
:
6049 return &warningSupplemental
;
6050 case Classification
.deprecation
:
6051 return &deprecationSupplemental
;
6052 case Classification
.gagged
, Classification
.tip
:
6057 // determine instantiation depth and number of recursive instantiations
6058 int n_instantiations
= 1;
6059 int n_totalrecursions
= 0;
6060 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6063 // Set error here as we don't want it to depend on the number of
6064 // entries that are being printed.
6065 if (cl
== Classification
.error ||
6066 (cl
== Classification
.warning
&& global
.params
.warnings
== DiagnosticReporting
.error
) ||
6067 (cl
== Classification
.deprecation
&& global
.params
.useDeprecated
== DiagnosticReporting
.error
))
6070 // If two instantiations use the same declaration, they are recursive.
6071 // (this works even if they are instantiated from different places in the
6073 // In principle, we could also check for multiple-template recursion, but it's
6074 // probably not worthwhile.
6075 if (cur
.tinst
&& cur
.tempdecl
&& cur
.tinst
.tempdecl
&& cur
.tempdecl
.loc
.equals(cur
.tinst
.tempdecl
.loc
))
6076 ++n_totalrecursions
;
6079 if (n_instantiations
<= max_shown
)
6081 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6082 printFn(cur
.loc
, format
, cur
.toChars());
6084 else if (n_instantiations
- n_totalrecursions
<= max_shown
)
6086 // By collapsing recursive instantiations into a single line,
6087 // we can stay under the limit.
6088 int recursionDepth
= 0;
6089 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6091 if (cur
.tinst
&& cur
.tempdecl
&& cur
.tinst
.tempdecl
&& cur
.tempdecl
.loc
.equals(cur
.tinst
.tempdecl
.loc
))
6098 printFn(cur
.loc
, "%d recursive instantiations from here: `%s`", recursionDepth
+ 2, cur
.toChars());
6100 printFn(cur
.loc
, format
, cur
.toChars());
6107 // Even after collapsing the recursions, the depth is too deep.
6108 // Just display the first few and last few instantiations.
6110 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6112 if (i
== max_shown
/ 2)
6113 printFn(cur
.loc
, "... (%d instantiations, -v to show) ...", n_instantiations
- max_shown
);
6115 if (i
< max_shown
/ 2 || i
>= n_instantiations
- max_shown
+ max_shown
/ 2)
6116 printFn(cur
.loc
, format
, cur
.toChars());
6122 /*************************************
6123 * Lazily generate identifier for template instance.
6124 * This is because 75% of the ident's are never needed.
6126 override final Identifier
getIdent()
6128 if (!ident
&& inst
&& !errors
)
6129 ident
= genIdent(tiargs
); // need an identifier for name mangling purposes.
6133 /*************************************
6134 * Compare proposed template instantiation with existing template instantiation.
6135 * Note that this is not commutative because of the auto ref check.
6137 * ti = existing template instantiation
6141 final bool equalsx(TemplateInstance ti
)
6143 //printf("this = %p, ti = %p\n", this, ti);
6144 assert(tdtypes
.length
== ti
.tdtypes
.length
);
6146 // Nesting must match
6147 if (enclosing
!= ti
.enclosing
)
6149 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
6152 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
6154 if (!arrayObjectMatch(&tdtypes
, &ti
.tdtypes
))
6157 /* Template functions may have different instantiations based on
6158 * "auto ref" parameters.
6160 if (auto fd
= ti
.toAlias().isFuncDeclaration())
6164 auto fparameters
= fd
.getParameterList();
6165 size_t nfparams
= fparameters
.length
; // Num function parameters
6166 for (size_t j
= 0; j
< nfparams
; j
++)
6168 Parameter fparam
= fparameters
[j
];
6169 if (fparam
.storageClass
& STC
.autoref
) // if "auto ref"
6171 Expression farg
= fargs
&& j
< fargs
.length ?
(*fargs
)[j
] : fparam
.defaultArg
;
6174 if (farg
.isLvalue())
6176 if (!(fparam
.storageClass
& STC
.ref_
))
6177 goto Lnotequals
; // auto ref's don't match
6181 if (fparam
.storageClass
& STC
.ref_
)
6182 goto Lnotequals
; // auto ref's don't match
6194 final size_t
toHash()
6198 hash
= cast(size_t
)cast(void*)enclosing
;
6199 hash
+= arrayObjectHash(&tdtypes
);
6206 Returns: true if the instances' innards are discardable.
6208 The idea of this function is to see if the template instantiation
6209 can be 100% replaced with its eponymous member. All other members
6210 can be discarded, even in the compiler to free memory (for example,
6211 the template could be expanded in a region allocator, deemed trivial,
6212 the end result copied back out independently and the entire region freed),
6213 and can be elided entirely from the binary.
6215 The current implementation affects code that generally looks like:
6218 template foo(args...) {
6219 some_basic_type_or_string helper() { .... }
6220 enum foo = helper();
6224 since it was the easiest starting point of implementation but it can and
6225 should be expanded more later.
6227 final bool isDiscardable()
6229 if (aliasdecl
is null)
6232 auto v
= aliasdecl
.isVarDeclaration();
6236 if (!(v
.storage_class
& STC
.manifest
))
6239 // Currently only doing basic types here because it is the easiest proof-of-concept
6240 // implementation with minimal risk of side effects, but it could likely be
6241 // expanded to any type that already exists outside this particular instance.
6242 if (!(v
.type
.equals(Type
.tstring
) ||
(v
.type
.isTypeBasic() !is null)))
6245 // Static ctors and dtors, even in an eponymous enum template, are still run,
6246 // so if any of them are in here, we'd better not assume it is trivial lest
6247 // we break useful code
6248 foreach(member
; *members
)
6250 if(member
.hasStaticCtorOrDtor())
6252 if(member
.isStaticDtorDeclaration())
6254 if(member
.isStaticCtorDeclaration())
6258 // but if it passes through this gauntlet... it should be fine. D code will
6259 // see only the eponymous member, outside stuff can never access it, even through
6260 // reflection; the outside world ought to be none the wiser. Even dmd should be
6261 // able to simply free the memory of everything except the final result.
6267 /***********************************************
6268 * Returns true if this is not instantiated in non-root module, and
6269 * is a part of non-speculative instantiatiation.
6271 * Note: minst does not stabilize until semantic analysis is completed,
6272 * so don't call this function during semantic analysis to return precise result.
6274 final bool needsCodegen()
6276 //printf("needsCodegen() %s\n", toChars());
6278 // minst is finalized after the 1st invocation.
6279 // tnext is only needed for the 1st invocation and
6280 // cleared for further invocations.
6281 TemplateInstance tnext
= this.tnext
;
6282 TemplateInstance tinst
= this.tinst
;
6285 // Don't do codegen if the instance has errors,
6286 // is a dummy instance (see evaluateConstraint),
6287 // or is determined to be discardable.
6288 if (errors || inst
is null || inst
.isDiscardable())
6290 minst
= null; // mark as speculative
6294 // This should only be called on the primary instantiation.
6295 assert(this is inst
);
6297 if (global
.params
.allInst
)
6299 // Do codegen if there is an instantiation from a root module, to maximize link-ability.
6300 static ThreeState
needsCodegenAllInst(TemplateInstance tithis
, TemplateInstance tinst
)
6302 // Do codegen if `this` is instantiated from a root module.
6303 if (tithis
.minst
&& tithis
.minst
.isRoot())
6304 return ThreeState
.yes
;
6306 // Do codegen if the ancestor needs it.
6307 if (tinst
&& tinst
.inst
&& tinst
.inst
.needsCodegen())
6309 tithis
.minst
= tinst
.inst
.minst
; // cache result
6310 assert(tithis
.minst
);
6311 assert(tithis
.minst
.isRoot());
6312 return ThreeState
.yes
;
6314 return ThreeState
.none
;
6317 if (const needsCodegen
= needsCodegenAllInst(this, tinst
))
6318 return needsCodegen
== ThreeState
.yes ?
true : false;
6320 // Do codegen if a sibling needs it.
6321 for (; tnext
; tnext
= tnext
.tnext
)
6323 const needsCodegen
= needsCodegenAllInst(tnext
, tnext
.tinst
);
6324 if (needsCodegen
== ThreeState
.yes
)
6326 minst
= tnext
.minst
; // cache result
6328 assert(minst
.isRoot());
6331 else if (!minst
&& tnext
.minst
)
6333 minst
= tnext
.minst
; // cache result from non-speculative sibling
6334 // continue searching
6336 else if (needsCodegen
!= ThreeState
.none
)
6340 // Elide codegen because there's no instantiation from any root modules.
6345 // Prefer instantiations from non-root modules, to minimize object code size.
6347 /* If a TemplateInstance is ever instantiated from a non-root module,
6348 * we do not have to generate code for it,
6349 * because it will be generated when the non-root module is compiled.
6351 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
6353 * The problem is if A imports B, and B imports A, and both A
6354 * and B instantiate the same template, does the compilation of A
6355 * or the compilation of B do the actual instantiation?
6357 * See https://issues.dlang.org/show_bug.cgi?id=2500.
6359 * => Elide codegen if there is at least one instantiation from a non-root module
6360 * which doesn't import any root modules.
6362 static ThreeState
needsCodegenRootOnly(TemplateInstance tithis
, TemplateInstance tinst
)
6364 // If the ancestor isn't speculative,
6365 // 1. do codegen if the ancestor needs it
6366 // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
6367 if (tinst
&& tinst
.inst
)
6370 const needsCodegen
= tinst
.needsCodegen(); // sets tinst.minst
6371 if (tinst
.minst
) // not speculative
6373 tithis
.minst
= tinst
.minst
; // cache result
6374 return needsCodegen ? ThreeState
.yes
: ThreeState
.no
;
6378 // Elide codegen if `this` doesn't need it.
6379 if (tithis
.minst
&& !tithis
.minst
.isRoot() && !tithis
.minst
.rootImports())
6380 return ThreeState
.no
;
6382 return ThreeState
.none
;
6385 if (const needsCodegen
= needsCodegenRootOnly(this, tinst
))
6386 return needsCodegen
== ThreeState
.yes ?
true : false;
6388 // Elide codegen if a (non-speculative) sibling doesn't need it.
6389 for (; tnext
; tnext
= tnext
.tnext
)
6391 const needsCodegen
= needsCodegenRootOnly(tnext
, tnext
.tinst
); // sets tnext.minst
6392 if (tnext
.minst
) // not speculative
6394 if (needsCodegen
== ThreeState
.no
)
6396 minst
= tnext
.minst
; // cache result
6397 assert(!minst
.isRoot() && !minst
.rootImports());
6402 minst
= tnext
.minst
; // cache result from non-speculative sibling
6403 // continue searching
6405 else if (needsCodegen
!= ThreeState
.none
)
6410 // Unless `this` is still speculative (=> all further siblings speculative too),
6411 // do codegen because we found no guaranteed-codegen'd non-root instantiation.
6412 return minst
!is null;
6416 /**********************************************
6417 * Find template declaration corresponding to template instance.
6420 * false if finding fails.
6422 * This function is reentrant against error occurrence. If returns false,
6423 * any members of this object won't be modified, and repetition call will
6424 * reproduce same error.
6426 extern (D
) final bool findTempDecl(Scope
* sc
, WithScopeSymbol
* pwithsym
)
6434 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
6439 * figure out which TemplateDeclaration foo refers to.
6441 Identifier id
= name
;
6443 Dsymbol s
= sc
.search(loc
, id
, &scopesym
);
6446 s
= sc
.search_correct(id
);
6448 error("template `%s` is not defined, did you mean %s?", id
.toChars(), s
.toChars());
6450 error("template `%s` is not defined", id
.toChars());
6455 printf("It's an instance of '%s' kind '%s'\n", s
.toChars(), s
.kind());
6457 printf("s.parent = '%s'\n", s
.parent
.toChars());
6460 *pwithsym
= scopesym
.isWithScopeSymbol();
6462 /* We might have found an alias within a template when
6463 * we really want the template.
6465 TemplateInstance ti
;
6466 if (s
.parent
&& (ti
= s
.parent
.isTemplateInstance()) !is null)
6468 if (ti
.tempdecl
&& ti
.tempdecl
.ident
== id
)
6470 /* This is so that one can refer to the enclosing
6471 * template, even if it has the same name as a member
6472 * of the template, if it has a !(arguments)
6474 TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration();
6476 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
6477 td
= td
.overroot
; // then get the start
6482 // The template might originate from a selective import which implies that
6483 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
6484 // This is the last place where we see the deprecated alias because it is
6485 // stripped below, so check if the selective import was deprecated.
6486 // See https://issues.dlang.org/show_bug.cgi?id=20840.
6487 if (s
.isAliasDeclaration())
6488 s
.checkDeprecated(this.loc
, sc
);
6490 if (!updateTempDecl(sc
, s
))
6497 // Look for forward references
6498 auto tovers
= tempdecl
.isOverloadSet();
6499 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
6501 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
6502 int r
= overloadApply(dstart
, (Dsymbol s
)
6504 auto td
= s
.isTemplateDeclaration();
6508 if (td
.semanticRun
== PASS
.initial
)
6512 // Try to fix forward reference. Ungag errors while doing so.
6513 Ungag ungag
= td
.ungagSpeculative();
6514 td
.dsymbolSemantic(td
._scope
);
6516 if (td
.semanticRun
== PASS
.initial
)
6518 error("`%s` forward references template declaration `%s`",
6519 toChars(), td
.toChars());
6531 /**********************************************
6532 * Confirm s is a valid template, then store it.
6535 * s candidate symbol of template. It may be:
6536 * TemplateDeclaration
6537 * FuncDeclaration with findTemplateDeclRoot() != NULL
6538 * OverloadSet which contains candidates
6540 * true if updating succeeds.
6542 extern (D
) final bool updateTempDecl(Scope
* sc
, Dsymbol s
)
6545 return tempdecl
!is null;
6547 Identifier id
= name
;
6550 /* If an OverloadSet, look for a unique member that is a template declaration
6552 if (OverloadSet os
= s
.isOverloadSet())
6557 if (FuncDeclaration f
= s2
.isFuncDeclaration())
6558 s2
= f
.findTemplateDeclRoot();
6560 s2
= s2
.isTemplateDeclaration();
6573 error("template `%s` is not defined", id
.toChars());
6578 if (OverDeclaration od
= s
.isOverDeclaration())
6580 tempdecl
= od
; // TODO: more strict check
6584 /* It should be a TemplateDeclaration, not some other symbol
6586 if (FuncDeclaration f
= s
.isFuncDeclaration())
6587 tempdecl
= f
.findTemplateDeclRoot();
6589 tempdecl
= s
.isTemplateDeclaration();
6595 // Error already issued, just return `false`
6596 if (!s
.parent
&& global
.errors
)
6599 if (!s
.parent
&& s
.getType())
6601 Dsymbol s2
= s
.getType().toDsymbol(sc
);
6604 .error(loc
, "`%s` is not a valid template instance, because `%s` is not a template declaration but a type (`%s == %s`)", toChars(), id
.toChars(), id
.toChars(), s
.getType
.kind());
6607 // because s can be the alias created for a TemplateParameter
6608 const AliasDeclaration ad
= s
.isAliasDeclaration();
6611 if (ad
&& ad
.isAliasedTemplateParameter())
6612 printf("`%s` is an alias created from a template parameter\n", s
.toChars());
6614 if (!ad ||
!ad
.isAliasedTemplateParameter())
6618 TemplateInstance ti
= s
.parent ? s
.parent
.isTemplateInstance() : null;
6620 /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
6622 static bool matchId(TemplateInstance ti
, Identifier id
)
6624 if (ti
.aliasdecl
&& ti
.aliasdecl
.isVarDeclaration())
6625 return ti
.aliasdecl
.isVarDeclaration().ident
== id
;
6626 return ti
.toAlias().ident
== id
;
6629 if (ti
&& (ti
.name
== s
.ident ||
matchId(ti
, s
.ident
)) && ti
.tempdecl
)
6631 /* This is so that one can refer to the enclosing
6632 * template, even if it has the same name as a member
6633 * of the template, if it has a !(arguments)
6635 TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration();
6637 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
6638 td
= td
.overroot
; // then get the start
6644 error("`%s` is not a template declaration, it is a %s", id
.toChars(), s
.kind());
6649 /**********************************
6650 * Run semantic of tiargs as arguments of template.
6654 * tiargs array of template arguments
6655 * flags 1: replace const variables with their initializers
6656 * 2: don't devolve Parameter to Type
6657 * atd tuple being optimized. If found, it's not expanded here
6658 * but in AliasAssign semantic.
6660 * false if one or more arguments have errors.
6662 extern (D
) static bool semanticTiargs(const ref Loc loc
, Scope
* sc
, Objects
* tiargs
, int flags
, TupleDeclaration atd
= null)
6664 // Run semantic on each argument, place results in tiargs[]
6665 //printf("+TemplateInstance.semanticTiargs()\n");
6669 for (size_t j
= 0; j
< tiargs
.length
; j
++)
6671 RootObject o
= (*tiargs
)[j
];
6672 Type ta
= isType(o
);
6673 Expression ea
= isExpression(o
);
6674 Dsymbol sa
= isDsymbol(o
);
6676 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
6679 //printf("type %s\n", ta.toChars());
6681 // It might really be an Expression or an Alias
6682 ta
.resolve(loc
, sc
, ea
, ta
, sa
, (flags
& 1) != 0);
6689 assert(global
.errors
);
6694 if (ta
.ty
== Ttuple
)
6697 TypeTuple tt
= cast(TypeTuple
)ta
;
6698 size_t dim
= tt
.arguments
.length
;
6702 tiargs
.reserve(dim
);
6703 foreach (i
, arg
; *tt
.arguments
)
6705 if (flags
& 2 && (arg
.storageClass
& STC
.parameter
))
6706 tiargs
.insert(j
+ i
, arg
);
6708 tiargs
.insert(j
+ i
, arg
.type
);
6714 if (ta
.ty
== Terror
)
6719 (*tiargs
)[j
] = ta
.merge2();
6724 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6725 if (flags
& 1) // only used by __traits
6727 ea
= ea
.expressionSemantic(sc
);
6729 // must not interpret the args, excepting template parameters
6730 if (ea
.op
!= EXP
.variable ||
((cast(VarExp
)ea
).var
.storage_class
& STC
.templateparameter
))
6732 ea
= ea
.optimize(WANTvalue
);
6737 sc
= sc
.startCTFE();
6738 ea
= ea
.expressionSemantic(sc
);
6741 if (ea
.op
== EXP
.variable
)
6743 /* If the parameter is a function that is not called
6744 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
6745 * then it is a dsymbol, not the return value of `func()`
6747 Declaration vd
= (cast(VarExp
)ea
).var
;
6748 if (auto fd
= vd
.isFuncDeclaration())
6753 /* Otherwise skip substituting a const var with
6754 * its initializer. The problem is the initializer won't
6755 * match with an 'alias' parameter. Instead, do the
6756 * const substitution in TemplateValueParameter.matchArg().
6759 else if (definitelyValueParameter(ea
))
6761 if (ea
.checkValue()) // check void expression
6762 ea
= ErrorExp
.get();
6763 uint olderrs
= global
.errors
;
6764 ea
= ea
.ctfeInterpret();
6765 if (global
.errors
!= olderrs
)
6766 ea
= ErrorExp
.get();
6769 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6770 if (ea
.op
== EXP
.tuple
)
6773 TupleExp te
= cast(TupleExp
)ea
;
6774 size_t dim
= te
.exps
.length
;
6778 tiargs
.reserve(dim
);
6779 foreach (i
, exp
; *te
.exps
)
6780 tiargs
.insert(j
+ i
, exp
);
6785 if (ea
.op
== EXP
.error
)
6792 if (ea
.op
== EXP
.type
)
6797 if (ea
.op
== EXP
.scope_
)
6799 sa
= (cast(ScopeExp
)ea
).sds
;
6802 if (ea
.op
== EXP
.function_
)
6804 FuncExp fe
= cast(FuncExp
)ea
;
6805 /* A function literal, that is passed to template and
6806 * already semanticed as function pointer, never requires
6807 * outer frame. So convert it to global function is valid.
6809 if (fe
.fd
.tok
== TOK
.reserved
&& fe
.type
.ty
== Tpointer
)
6811 // change to non-nested
6812 fe
.fd
.tok
= TOK
.function_
;
6817 /* If template argument is a template lambda,
6818 * get template declaration itself. */
6823 if (ea
.op
== EXP
.dotVariable
&& !(flags
& 1))
6825 // translate expression to dsymbol.
6826 sa
= (cast(DotVarExp
)ea
).var
;
6829 if (ea
.op
== EXP
.template_
)
6831 sa
= (cast(TemplateExp
)ea
).td
;
6834 if (ea
.op
== EXP
.dotTemplateDeclaration
&& !(flags
& 1))
6836 // translate expression to dsymbol.
6837 sa
= (cast(DotTemplateExp
)ea
).td
;
6840 if (ea
.op
== EXP
.dot
)
6842 if (auto se
= (cast(DotExp
)ea
).e2
.isScopeExp())
6852 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
6859 TupleDeclaration d
= sa
.toAlias().isTupleDeclaration();
6869 tiargs
.insert(j
, d
.objects
);
6873 if (FuncAliasDeclaration fa
= sa
.isFuncAliasDeclaration())
6875 FuncDeclaration f
= fa
.toAliasFunc();
6876 if (!fa
.hasOverloads
&& f
.isUnique())
6878 // Strip FuncAlias only when the aliased function
6879 // does not have any overloads.
6885 TemplateDeclaration td
= sa
.isTemplateDeclaration();
6886 if (td
&& td
.semanticRun
== PASS
.initial
&& td
.literal
)
6888 td
.dsymbolSemantic(sc
);
6890 FuncDeclaration fd
= sa
.isFuncDeclaration();
6892 fd
.functionSemantic();
6894 else if (isParameter(o
))
6901 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
6905 printf("-TemplateInstance.semanticTiargs()\n");
6906 for (size_t j
= 0; j
< tiargs
.length
; j
++)
6908 RootObject o
= (*tiargs
)[j
];
6909 Type ta
= isType(o
);
6910 Expression ea
= isExpression(o
);
6911 Dsymbol sa
= isDsymbol(o
);
6912 Tuple va
= isTuple(o
);
6913 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j
, ta
, ea
, sa
, va
);
6919 /**********************************
6920 * Run semantic on the elements of tiargs.
6924 * false if one or more arguments have errors.
6926 * This function is reentrant against error occurrence. If returns false,
6927 * all elements of tiargs won't be modified.
6929 extern (D
) final bool semanticTiargs(Scope
* sc
)
6931 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
6932 if (semantictiargsdone
)
6934 if (semanticTiargs(loc
, sc
, tiargs
, 0))
6936 // cache the result iff semantic analysis succeeded entirely
6937 semantictiargsdone
= 1;
6943 /**********************************
6944 * Find the TemplateDeclaration that matches this TemplateInstance best.
6947 * sc = the scope this TemplateInstance resides in
6948 * argumentList = function arguments in case of a template function
6951 * `true` if a match was found, `false` otherwise
6953 extern (D
) final bool findBestMatch(Scope
* sc
, ArgumentList argumentList
)
6957 TemplateDeclaration tempdecl
= this.tempdecl
.isTemplateDeclaration();
6959 assert(tempdecl
._scope
);
6961 tdtypes
.setDim(tempdecl
.parameters
.length
);
6962 if (!tempdecl
.matchWithInstance(sc
, this, &tdtypes
, argumentList
, 2))
6964 error("incompatible arguments for template instantiation");
6967 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
6973 printf("TemplateInstance.findBestMatch()\n");
6976 uint errs
= global
.errors
;
6977 TemplateDeclaration td_last
= null;
6980 /* Since there can be multiple TemplateDeclaration's with the same
6981 * name, look for the best match.
6983 auto tovers
= tempdecl
.isOverloadSet();
6984 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
6986 TemplateDeclaration td_best
;
6987 TemplateDeclaration td_ambig
;
6988 MATCH m_best
= MATCH
.nomatch
;
6990 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
6991 overloadApply(dstart
, (Dsymbol s
)
6993 auto td
= s
.isTemplateDeclaration();
6996 if (td
== td_best
) // skip duplicates
6999 //printf("td = %s\n", td.toPrettyChars());
7000 // If more arguments than parameters,
7001 // then this is no match.
7002 if (td
.parameters
.length
< tiargs
.length
)
7004 if (!td
.isVariadic())
7008 dedtypes
.setDim(td
.parameters
.length
);
7010 assert(td
.semanticRun
!= PASS
.initial
);
7012 MATCH m
= td
.matchWithInstance(sc
, this, &dedtypes
, argumentList
, 0);
7013 //printf("matchWithInstance = %d\n", m);
7014 if (m
== MATCH
.nomatch
) // no match at all
7016 if (m
< m_best
) goto Ltd_best
;
7017 if (m
> m_best
) goto Ltd
;
7019 // Disambiguate by picking the most specialized TemplateDeclaration
7021 MATCH c1
= td
.leastAsSpecialized(sc
, td_best
, argumentList
);
7022 MATCH c2
= td_best
.leastAsSpecialized(sc
, td
, argumentList
);
7023 //printf("c1 = %d, c2 = %d\n", c1, c2);
7024 if (c1
> c2
) goto Ltd
;
7025 if (c1
< c2
) goto Ltd_best
;
7032 // td_best is the best match so far
7037 // td is the new best match
7041 tdtypes
.setDim(dedtypes
.length
);
7042 memcpy(tdtypes
.tdata(), dedtypes
.tdata(), tdtypes
.length
* (void*).sizeof
);
7048 .error(loc
, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`",
7049 td_best
.kind(), td_best
.parent
.toPrettyChars(), td_best
.ident
.toChars(),
7050 td_best
.loc
.toChars(), td_best
.toChars(),
7051 td_ambig
.loc
.toChars(), td_ambig
.toChars());
7058 else if (td_last
!= td_best
)
7060 ScopeDsymbol
.multiplyDefined(loc
, td_last
, td_best
);
7068 /* https://issues.dlang.org/show_bug.cgi?id=7469
7069 * Normalize tiargs by using corresponding deduced
7070 * template value parameters and tuples for the correct mangling.
7072 * By doing this before hasNestedArgs, CTFEable local variable will be
7073 * accepted as a value parameter. For example:
7076 * struct S(int n) {} // non-global template
7077 * const int num = 1; // CTFEable local variable
7078 * S!num s; // S!1 is instantiated, not S!num
7081 size_t dim
= td_last
.parameters
.length
- (td_last
.isVariadic() ?
1 : 0);
7082 for (size_t i
= 0; i
< dim
; i
++)
7084 if (tiargs
.length
<= i
)
7085 tiargs
.push(tdtypes
[i
]);
7086 assert(i
< tiargs
.length
);
7088 auto tvp
= (*td_last
.parameters
)[i
].isTemplateValueParameter();
7092 // tdtypes[i] is already normalized to the required type in matchArg
7094 (*tiargs
)[i
] = tdtypes
[i
];
7096 if (td_last
.isVariadic() && tiargs
.length
== dim
&& tdtypes
[dim
])
7098 Tuple va
= isTuple(tdtypes
[dim
]);
7100 tiargs
.pushSlice(va
.objects
[]);
7103 else if (errors
&& inst
)
7105 // instantiation was failed with error reporting
7106 assert(global
.errors
);
7111 auto tdecl
= tempdecl
.isTemplateDeclaration();
7113 if (errs
!= global
.errors
)
7114 errorSupplemental(loc
, "while looking for match for `%s`", toChars());
7115 else if (tdecl
&& !tdecl
.overnext
)
7117 // Only one template, so we can give better error message
7118 const(char)* msg
= "does not match template declaration";
7120 const tmsg
= tdecl
.toCharsNoConstraints();
7121 const cmsg
= tdecl
.getConstraintEvalError(tip
);
7124 error("%s `%s`\n%s", msg
, tmsg
, cmsg
);
7130 error("%s `%s`", msg
, tmsg
);
7132 if (tdecl
.parameters
.length
== tiargs
.length
)
7134 // https://issues.dlang.org/show_bug.cgi?id=7352
7135 // print additional information, e.g. `foo` is not a type
7136 foreach (i
, param
; *tdecl
.parameters
)
7138 MATCH match
= param
.matchArg(loc
, sc
, tiargs
, i
, tdecl
.parameters
, &dedtypes
, null);
7139 auto arg
= (*tiargs
)[i
];
7140 auto sym
= arg
.isDsymbol
;
7141 auto exp
= arg
.isExpression
;
7144 exp
= exp
.optimize(WANTvalue
);
7146 if (match
== MATCH
.nomatch
&&
7147 ((sym
&& sym
.isFuncDeclaration
) ||
7148 (exp
&& exp
.isVarExp
)))
7150 if (param
.isTemplateTypeParameter
)
7151 errorSupplemental(loc
, "`%s` is not a type", arg
.toChars
);
7152 else if (auto tvp
= param
.isTemplateValueParameter
)
7153 errorSupplemental(loc
, "`%s` is not of a value of type `%s`",
7154 arg
.toChars
, tvp
.valType
.toChars
);
7163 .error(loc
, "%s `%s` does not match any template declaration", kind(), toPrettyChars());
7165 overloadApply(tempdecl
, (s
){
7167 errorSupplemental(loc
, "Candidates are:");
7169 errorSupplemental(s
.loc
, "%s", s
.toChars());
7176 /* The best match is td_last
7182 printf("\tIt's a match with template declaration '%s'\n", tempdecl
.toChars());
7184 return (errs
== global
.errors
);
7187 /*****************************************************
7188 * Determine if template instance is really a template function,
7189 * and that template function needs to infer types from the function
7192 * Like findBestMatch, iterate possible template candidates,
7193 * but just looks only the necessity of type inference.
7195 extern (D
) final bool needsTypeInference(Scope
* sc
, int flag
= 0)
7197 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
7198 if (semanticRun
!= PASS
.initial
)
7201 uint olderrs
= global
.errors
;
7205 auto tovers
= tempdecl
.isOverloadSet();
7206 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
7208 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
7209 int r
= overloadApply(dstart
, (Dsymbol s
)
7211 auto td
= s
.isTemplateDeclaration();
7215 /* If any of the overloaded template declarations need inference,
7220 if (auto td2
= td
.onemember
.isTemplateDeclaration())
7222 if (!td2
.onemember ||
!td2
.onemember
.isFuncDeclaration())
7224 if (tiargs
.length
>= td
.parameters
.length
- (td
.isVariadic() ?
1 : 0))
7228 auto fd
= td
.onemember
.isFuncDeclaration();
7229 if (!fd || fd
.type
.ty
!= Tfunction
)
7232 foreach (tp
; *td
.parameters
)
7234 if (tp
.isTemplateThisParameter())
7238 /* Determine if the instance arguments, tiargs, are all that is necessary
7239 * to instantiate the template.
7241 //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
7242 auto tf
= cast(TypeFunction
)fd
.type
;
7243 if (tf
.parameterList
.length
)
7245 auto tp
= td
.isVariadic();
7246 if (tp
&& td
.parameters
.length
> 1)
7249 if (!tp
&& tiargs
.length
< td
.parameters
.length
)
7251 // Can remain tiargs be filled by default arguments?
7252 foreach (size_t i
; tiargs
.length
.. td
.parameters
.length
)
7254 if (!(*td
.parameters
)[i
].hasDefaultArg())
7259 foreach (i
, fparam
; tf
.parameterList
)
7261 // 'auto ref' needs inference.
7262 if (fparam
.storageClass
& STC
.auto_
)
7269 /* Calculate the need for overload resolution.
7270 * When only one template can match with tiargs, inference is not necessary.
7272 dedtypes
.setDim(td
.parameters
.length
);
7274 if (td
.semanticRun
== PASS
.initial
)
7278 // Try to fix forward reference. Ungag errors while doing so.
7279 Ungag ungag
= td
.ungagSpeculative();
7280 td
.dsymbolSemantic(td
._scope
);
7282 if (td
.semanticRun
== PASS
.initial
)
7284 error("`%s` forward references template declaration `%s`", toChars(), td
.toChars());
7288 MATCH m
= td
.matchWithInstance(sc
, this, &dedtypes
, ArgumentList(), 0);
7289 if (m
== MATCH
.nomatch
)
7293 /* If there is more than one function template which matches, we may
7294 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
7296 return ++count
> 1 ?
1 : 0;
7302 if (olderrs
!= global
.errors
)
7306 errorSupplemental(loc
, "while looking for match for `%s`", toChars());
7307 semanticRun
= PASS
.semanticdone
;
7312 //printf("false\n");
7316 /*****************************************
7317 * Determines if a TemplateInstance will need a nested
7318 * generation of the TemplateDeclaration.
7319 * Sets enclosing property if so, and returns != 0;
7321 extern (D
) final bool hasNestedArgs(Objects
* args
, bool isstatic
)
7324 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
7326 // arguments from parent instances are also accessible
7329 if (TemplateInstance ti
= tempdecl
.toParent().isTemplateInstance())
7330 enclosing
= ti
.enclosing
;
7333 /* A nested instance happens when an argument references a local
7334 * symbol that is on the stack.
7338 Expression ea
= isExpression(o
);
7339 Dsymbol sa
= isDsymbol(o
);
7340 Tuple va
= isTuple(o
);
7343 if (ea
.op
== EXP
.variable
)
7345 sa
= (cast(VarExp
)ea
).var
;
7348 if (ea
.op
== EXP
.this_
)
7350 sa
= (cast(ThisExp
)ea
).var
;
7353 if (ea
.op
== EXP
.function_
)
7355 if ((cast(FuncExp
)ea
).td
)
7356 sa
= (cast(FuncExp
)ea
).td
;
7358 sa
= (cast(FuncExp
)ea
).fd
;
7361 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
7362 if (ea
.op
!= EXP
.int64
&& ea
.op
!= EXP
.float64
&& ea
.op
!= EXP
.complex80
&& ea
.op
!= EXP
.null_
&& ea
.op
!= EXP
.string_
&& ea
.op
!= EXP
.arrayLiteral
&& ea
.op
!= EXP
.assocArrayLiteral
&& ea
.op
!= EXP
.structLiteral
)
7364 ea
.error("expression `%s` is not a valid template value argument", ea
.toChars());
7372 TemplateDeclaration td
= sa
.isTemplateDeclaration();
7375 TemplateInstance ti
= sa
.toParent().isTemplateInstance();
7376 if (ti
&& ti
.enclosing
)
7379 TemplateInstance ti
= sa
.isTemplateInstance();
7380 Declaration d
= sa
.isDeclaration();
7381 if ((td
&& td
.literal
) ||
(ti
&& ti
.enclosing
) ||
(d
&& !d
.isDataseg() && !(d
.storage_class
& STC
.manifest
) && (!d
.isFuncDeclaration() || d
.isFuncDeclaration().isNested()) && !isTemplateMixin()))
7383 Dsymbol dparent
= sa
.toParent2();
7384 if (!dparent || dparent
.isModule
)
7386 else if (!enclosing
)
7387 enclosing
= dparent
;
7388 else if (enclosing
!= dparent
)
7390 /* Select the more deeply nested of the two.
7391 * Error if one is not nested inside the other.
7393 for (Dsymbol p
= enclosing
; p
; p
= p
.parent
)
7396 goto L1
; // enclosing is most nested
7398 for (Dsymbol p
= dparent
; p
; p
= p
.parent
)
7402 enclosing
= dparent
;
7403 goto L1
; // dparent is most nested
7406 //https://issues.dlang.org/show_bug.cgi?id=17870
7407 if (dparent
.isClassDeclaration() && enclosing
.isClassDeclaration())
7409 auto pc
= dparent
.isClassDeclaration();
7410 auto ec
= enclosing
.isClassDeclaration();
7411 if (pc
.isBaseOf(ec
, null))
7413 else if (ec
.isBaseOf(pc
, null))
7415 enclosing
= dparent
;
7419 error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing
.toChars(), dparent
.toChars());
7423 //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
7429 nested |
= cast(int)hasNestedArgs(&va
.objects
, isstatic
);
7432 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
7436 /*****************************************
7437 * Append 'this' to the specific module members[]
7439 extern (D
) final Dsymbols
* appendToModuleMember()
7441 Module mi
= minst
; // instantiated . inserted module
7443 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
7445 // enclosing ? enclosing.toPrettyChars() : null,
7446 // mi ? mi.toPrettyChars() : null);
7447 if (global
.params
.allInst ||
!mi || mi
.isRoot())
7449 /* If the instantiated module is speculative or root, insert to the
7450 * member of a root module. Then:
7451 * - semantic3 pass will get called on the instance members.
7452 * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
7454 static Dsymbol
getStrictEnclosing(TemplateInstance ti
)
7459 return ti
.enclosing
;
7460 ti
= ti
.tempdecl
.isInstantiated();
7465 Dsymbol enc
= getStrictEnclosing(this);
7466 // insert target is made stable by using the module
7467 // where tempdecl is declared.
7468 mi
= (enc ? enc
: tempdecl
).getModule();
7471 if (mi
.importedFrom
)
7473 mi
= mi
.importedFrom
;
7474 assert(mi
.isRoot());
7478 // This can happen when using the frontend as a library.
7479 // Append it to the non-root module.
7485 /* If the instantiated module is non-root, insert to the member of the
7486 * non-root module. Then:
7487 * - semantic3 pass won't be called on the instance.
7488 * - codegen pass won't reach to the instance.
7489 * Unless it is re-appended to a root module later (with changed minst).
7492 //printf("\t-. mi = %s\n", mi.toPrettyChars());
7494 assert(!memberOf ||
(!memberOf
.isRoot() && mi
.isRoot()), "can only re-append from non-root to root module");
7496 Dsymbols
* a
= mi
.members
;
7499 if (mi
.semanticRun
>= PASS
.semantic2done
&& mi
.isRoot())
7500 Module
.addDeferredSemantic2(this);
7501 if (mi
.semanticRun
>= PASS
.semantic3done
&& mi
.isRoot())
7502 Module
.addDeferredSemantic3(this);
7506 /****************************************************
7507 * Declare parameters of template instance, initialize them with the
7508 * template instance arguments.
7510 extern (D
) final void declareParameters(Scope
* sc
)
7512 TemplateDeclaration tempdecl
= this.tempdecl
.isTemplateDeclaration();
7515 //printf("TemplateInstance.declareParameters()\n");
7516 foreach (i
, o
; tdtypes
) // initializer for tp
7518 TemplateParameter tp
= (*tempdecl
.parameters
)[i
];
7519 //printf("\ttdtypes[%d] = %p\n", i, o);
7520 tempdecl
.declareParameter(sc
, tp
, o
);
7524 /****************************************
7525 * This instance needs an identifier for name mangling purposes.
7526 * Create one by taking the template declaration name and adding
7527 * the type signature for it.
7529 extern (D
) final Identifier
genIdent(Objects
* args
)
7531 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
7532 assert(args
is tiargs
);
7534 mangleToBuffer(this, &buf
);
7535 //printf("\tgenIdent = %s\n", buf.peekChars());
7536 return Identifier
.idPool(buf
[]);
7539 extern (D
) final void expandMembers(Scope
* sc2
)
7541 members
.foreachDsymbol( (s
) { s
.setScope (sc2
); } );
7543 members
.foreachDsymbol( (s
) { s
.importAll(sc2
); } );
7547 /* static if's are crucial to evaluating aliasdecl correctly. But
7548 * evaluating the if/else bodies may require aliasdecl.
7549 * So, evaluate the condition for static if's, but not their if/else bodies.
7550 * Then try to set aliasdecl.
7551 * Later do the if/else bodies.
7552 * https://issues.dlang.org/show_bug.cgi?id=23598
7553 * It might be better to do this by attaching a lambda to the StaticIfDeclaration
7554 * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
7557 void staticIfDg(Dsymbol s
)
7559 if (done || aliasdecl
)
7561 //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
7562 if (!s
.isStaticIfDeclaration())
7564 //s.dsymbolSemantic(sc2);
7568 auto sid
= s
.isStaticIfDeclaration();
7573 if (Dsymbol
.oneMembers(members
, &sa
, tempdecl
.ident
) && sa
)
7579 members
.foreachDsymbol(&staticIfDg
);
7582 void symbolDg(Dsymbol s
)
7584 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
7585 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
7587 // s.parent = sc.parent;
7588 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7589 s
.dsymbolSemantic(sc2
);
7590 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7591 Module
.runDeferredSemantic();
7594 members
.foreachDsymbol(&symbolDg
);
7597 extern (D
) final void tryExpandMembers(Scope
* sc2
)
7600 // extracted to a function to allow windows SEH to work without destructors in the same function
7601 //printf("%d\n", nest);
7602 if (++nest
> global
.recursionLimit
)
7604 global
.gag
= 0; // ensure error message gets printed
7605 error("recursive expansion exceeded allowed nesting limit");
7614 extern (D
) final void trySemantic3(Scope
* sc2
)
7616 // extracted to a function to allow windows SEH to work without destructors in the same function
7618 //printf("%d\n", nest);
7619 if (++nest
> global
.recursionLimit
)
7621 global
.gag
= 0; // ensure error message gets printed
7622 error("recursive expansion exceeded allowed nesting limit");
7626 semantic3(this, sc2
);
7631 override final inout(TemplateInstance
) isTemplateInstance() inout
7636 override void accept(Visitor v
)
7642 /**************************************
7643 * IsExpression can evaluate the specified type speculatively, and even if
7644 * it instantiates any symbols, they are normally unnecessary for the
7646 * However, if those symbols leak to the actual code, compiler should remark
7647 * them as non-speculative to generate their code and link to the final executable.
7649 void unSpeculative(Scope
* sc
, RootObject o
)
7654 if (Tuple tup
= isTuple(o
))
7656 foreach (obj
; tup
.objects
)
7658 unSpeculative(sc
, obj
);
7663 Dsymbol s
= getDsymbol(o
);
7667 if (Declaration d
= s
.isDeclaration())
7669 if (VarDeclaration vd
= d
.isVarDeclaration())
7671 else if (AliasDeclaration ad
= d
.isAliasDeclaration())
7685 if (TemplateInstance ti
= s
.isTemplateInstance())
7687 // If the instance is already non-speculative,
7688 // or it is leaked to the speculative scope.
7689 if (ti
.minst
!is null || sc
.minst
is null)
7692 // Remark as non-speculative instance.
7693 ti
.minst
= sc
.minst
;
7695 ti
.tinst
= sc
.tinst
;
7697 unSpeculative(sc
, ti
.tempdecl
);
7700 if (TemplateInstance ti
= s
.isInstantiated())
7701 unSpeculative(sc
, ti
);
7704 /**********************************
7705 * Return true if e could be valid only as a template value parameter.
7706 * Return false if it might be an alias or tuple.
7707 * (Note that even in this case, it could still turn out to be a value).
7709 bool definitelyValueParameter(Expression e
)
7711 // None of these can be value parameters
7712 if (e
.op
== EXP
.tuple || e
.op
== EXP
.scope_ ||
7713 e
.op
== EXP
.type || e
.op
== EXP
.dotType ||
7714 e
.op
== EXP
.template_ || e
.op
== EXP
.dotTemplateDeclaration ||
7715 e
.op
== EXP
.function_ || e
.op
== EXP
.error ||
7716 e
.op
== EXP
.this_ || e
.op
== EXP
.super_ ||
7720 if (e
.op
!= EXP
.dotVariable
)
7723 /* Template instantiations involving a DotVar expression are difficult.
7724 * In most cases, they should be treated as a value parameter, and interpreted.
7725 * But they might also just be a fully qualified name, which should be treated
7729 // x.y.f cannot be a value
7730 FuncDeclaration f
= (cast(DotVarExp
)e
).var
.isFuncDeclaration();
7734 while (e
.op
== EXP
.dotVariable
)
7736 e
= (cast(DotVarExp
)e
).e1
;
7738 // this.x.y and super.x.y couldn't possibly be valid values.
7739 if (e
.op
== EXP
.this_ || e
.op
== EXP
.super_
)
7742 // e.type.x could be an alias
7743 if (e
.op
== EXP
.dotType
)
7746 // var.x.y is the only other possible form of alias
7747 if (e
.op
!= EXP
.variable
)
7750 VarDeclaration v
= (cast(VarExp
)e
).var
.isVarDeclaration();
7751 // func.x.y is not an alias
7755 // https://issues.dlang.org/show_bug.cgi?id=16685
7756 // var.x.y where var is a constant available at compile time
7757 if (v
.storage_class
& STC
.manifest
)
7760 // TODO: Should we force CTFE if it is a global constant?
7764 /***********************************************************
7765 * https://dlang.org/spec/template-mixin.html
7767 * mixin MixinTemplateName [TemplateArguments] [Identifier];
7769 extern (C
++) final class TemplateMixin
: TemplateInstance
7771 TypeQualified tqual
;
7773 extern (D
) this(const ref Loc loc
, Identifier ident
, TypeQualified tqual
, Objects
* tiargs
)
7776 tqual
.idents
.length ?
cast(Identifier
)tqual
.idents
[tqual
.idents
.length
- 1] : (cast(TypeIdentifier
)tqual
).ident
,
7777 tiargs ? tiargs
: new Objects());
7778 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
7783 override TemplateInstance
syntaxCopy(Dsymbol s
)
7785 auto tm
= new TemplateMixin(loc
, ident
, tqual
.syntaxCopy(), tiargs
);
7786 return TemplateInstance
.syntaxCopy(tm
);
7789 override const(char)* kind() const
7794 override bool oneMember(Dsymbol
* ps
, Identifier ident
)
7796 return Dsymbol
.oneMember(ps
, ident
);
7799 override bool hasPointers()
7801 //printf("TemplateMixin.hasPointers() %s\n", toChars());
7802 return members
.foreachDsymbol( (s
) { return s
.hasPointers(); } ) != 0;
7805 override void setFieldOffset(AggregateDeclaration ad
, ref FieldState fieldState
, bool isunion
)
7807 //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
7808 if (_scope
) // if fwd reference
7809 dsymbolSemantic(this, null); // try to resolve it
7811 members
.foreachDsymbol( (s
) { s
.setFieldOffset(ad
, fieldState
, isunion
); } );
7814 override const(char)* toChars() const
7817 toCBufferInstance(this, &buf
);
7818 return buf
.extractChars();
7821 extern (D
) bool findTempDecl(Scope
* sc
)
7823 // Follow qualifications to find the TemplateDeclaration
7829 tqual
.resolve(loc
, sc
, e
, t
, s
);
7832 error("is not defined");
7836 tempdecl
= s
.isTemplateDeclaration();
7837 OverloadSet os
= s
.isOverloadSet();
7839 /* If an OverloadSet, look for a unique member that is a template declaration
7844 foreach (i
, sym
; os
.a
)
7846 Dsymbol s2
= sym
.isTemplateDeclaration();
7860 error("- `%s` is a %s, not a template", s
.toChars(), s
.kind());
7866 // Look for forward references
7867 auto tovers
= tempdecl
.isOverloadSet();
7868 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
7870 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
7871 int r
= overloadApply(dstart
, (Dsymbol s
)
7873 auto td
= s
.isTemplateDeclaration();
7877 if (td
.semanticRun
== PASS
.initial
)
7880 td
.dsymbolSemantic(td
._scope
);
7883 semanticRun
= PASS
.initial
;
7895 override inout(TemplateMixin
) isTemplateMixin() inout
7900 override void accept(Visitor v
)
7906 /************************************
7907 * This struct is needed for TemplateInstance to be the key in an associative array.
7908 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
7909 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
7911 struct TemplateInstanceBox
7913 TemplateInstance ti
;
7915 this(TemplateInstance ti
)
7919 assert(this.ti
.hash
);
7922 size_t
toHash() const @trusted pure nothrow
7928 bool opEquals(ref const TemplateInstanceBox s
) @trusted const
7931 if (ti
.inst
&& s
.ti
.inst
)
7933 /* This clause is only used when an instance with errors
7934 * is replaced with a correct instance.
7940 /* Used when a proposed instance is used to see if there's
7941 * an existing instance.
7943 static if (__VERSION__
< 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
7944 res
= (cast()s
.ti
).equalsx(cast()ti
);
7946 res
= (cast()ti
).equalsx(cast()s
.ti
);
7949 debug (FindExistingInstance
) ++(res ? nHits
: nCollisions
);
7953 debug (FindExistingInstance
)
7955 __gshared
uint nHits
, nCollisions
;
7957 shared static ~this()
7959 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
7960 nHits
, nCollisions
);
7965 /*******************************************
7966 * Match to a particular TemplateParameter.
7968 * instLoc location that the template is instantiated.
7969 * tiargs[] actual arguments to template instance
7971 * parameters[] template parameters
7972 * dedtypes[] deduced arguments to template instance
7973 * *psparam set to symbol declared and initialized to dedtypes[i]
7975 MATCH
matchArg(TemplateParameter tp
, Loc instLoc
, Scope
* sc
, Objects
* tiargs
, size_t i
, TemplateParameters
* parameters
, Objects
* dedtypes
, Declaration
* psparam
)
7977 MATCH
matchArgNoMatch()
7981 return MATCH
.nomatch
;
7984 MATCH
matchArgParameter()
7988 if (i
< tiargs
.length
)
7989 oarg
= (*tiargs
)[i
];
7992 // Get default argument instead
7993 oarg
= tp
.defaultArg(instLoc
, sc
);
7996 assert(i
< dedtypes
.length
);
7997 // It might have already been deduced
7998 oarg
= (*dedtypes
)[i
];
8000 return matchArgNoMatch();
8003 return tp
.matchArg(sc
, oarg
, i
, parameters
, dedtypes
, psparam
);
8006 MATCH
matchArgTuple(TemplateTupleParameter ttp
)
8008 /* The rest of the actual arguments (tiargs[]) form the match
8009 * for the variadic parameter.
8011 assert(i
+ 1 == dedtypes
.length
); // must be the last one
8014 if (Tuple u
= isTuple((*dedtypes
)[i
]))
8016 // It has already been deduced
8019 else if (i
+ 1 == tiargs
.length
&& isTuple((*tiargs
)[i
]))
8020 ovar
= isTuple((*tiargs
)[i
]);
8024 //printf("ovar = %p\n", ovar);
8025 if (i
< tiargs
.length
)
8027 //printf("i = %d, tiargs.length = %d\n", i, tiargs.length);
8028 ovar
.objects
.setDim(tiargs
.length
- i
);
8029 foreach (j
, ref obj
; ovar
.objects
)
8030 obj
= (*tiargs
)[i
+ j
];
8033 return ttp
.matchArg(sc
, ovar
, i
, parameters
, dedtypes
, psparam
);
8036 if (auto ttp
= tp
.isTemplateTupleParameter())
8037 return matchArgTuple(ttp
);
8039 return matchArgParameter();
8042 MATCH
matchArg(TemplateParameter tp
, Scope
* sc
, RootObject oarg
, size_t i
, TemplateParameters
* parameters
, Objects
* dedtypes
, Declaration
* psparam
)
8044 MATCH
matchArgNoMatch()
8046 //printf("\tm = %d\n", MATCH.nomatch);
8049 return MATCH
.nomatch
;
8052 MATCH
matchArgType(TemplateTypeParameter ttp
)
8054 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
8055 MATCH m
= MATCH
.exact
;
8056 Type ta
= isType(oarg
);
8059 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
8060 return matchArgNoMatch();
8062 //printf("ta is %s\n", ta.toChars());
8066 if (!ta || ta
== TemplateTypeParameter
.tdummy
)
8067 return matchArgNoMatch();
8069 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
8070 MATCH m2
= deduceType(ta
, sc
, ttp
.specType
, parameters
, dedtypes
);
8071 if (m2
== MATCH
.nomatch
)
8073 //printf("\tfailed deduceType\n");
8074 return matchArgNoMatch();
8081 Type t
= cast(Type
)(*dedtypes
)[i
];
8083 if (ttp
.dependent
&& !t
.equals(ta
)) // https://issues.dlang.org/show_bug.cgi?id=14357
8084 return matchArgNoMatch();
8086 /* This is a self-dependent parameter. For example:
8087 * template X(T : T*) {}
8088 * template X(T : S!T, alias S) {}
8090 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8098 // Must match already deduced type
8099 Type t
= cast(Type
)(*dedtypes
)[i
];
8103 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8104 return matchArgNoMatch();
8109 // So that matches with specializations are better
8113 (*dedtypes
)[i
] = ta
;
8116 *psparam
= new AliasDeclaration(ttp
.loc
, ttp
.ident
, ta
);
8117 //printf("\tm = %d\n", m);
8118 return ttp
.dependent ? MATCH
.exact
: m
;
8121 MATCH
matchArgValue(TemplateValueParameter tvp
)
8123 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
8124 MATCH m
= MATCH
.exact
;
8126 Expression ei
= isExpression(oarg
);
8131 Dsymbol si
= isDsymbol(oarg
);
8132 FuncDeclaration f
= si ? si
.isFuncDeclaration() : null;
8133 if (!f ||
!f
.fbody || f
.needThis())
8134 return matchArgNoMatch();
8136 ei
= new VarExp(tvp
.loc
, f
);
8137 ei
= ei
.expressionSemantic(sc
);
8139 /* If a function is really property-like, and then
8140 * it's CTFEable, ei will be a literal expression.
8142 uint olderrors
= global
.startGagging();
8143 ei
= resolveProperties(sc
, ei
);
8144 ei
= ei
.ctfeInterpret();
8145 if (global
.endGagging(olderrors
) || ei
.op
== EXP
.error
)
8146 return matchArgNoMatch();
8148 /* https://issues.dlang.org/show_bug.cgi?id=14520
8149 * A property-like function can match to both
8150 * TemplateAlias and ValueParameter. But for template overloads,
8151 * it should always prefer alias parameter to be consistent
8152 * template match result.
8154 * template X(alias f) { enum X = 1; }
8155 * template X(int val) { enum X = 2; }
8156 * int f1() { return 0; } // CTFEable
8157 * int f2(); // body-less function is not CTFEable
8158 * enum x1 = X!f1; // should be 1
8159 * enum x2 = X!f2; // should be 1
8161 * e.g. The x1 value must be same even if the f1 definition will be moved
8162 * into di while stripping body code.
8167 if (ei
&& ei
.op
== EXP
.variable
)
8169 // Resolve const variables that we had skipped earlier
8170 ei
= ei
.ctfeInterpret();
8173 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
8174 vt
= tvp
.valType
.typeSemantic(tvp
.loc
, sc
);
8175 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
8176 //printf("vt = %s\n", vt.toChars());
8180 MATCH m2
= ei
.implicitConvTo(vt
);
8181 //printf("m: %d\n", m);
8184 if (m
== MATCH
.nomatch
)
8185 return matchArgNoMatch();
8186 ei
= ei
.implicitCastTo(sc
, vt
);
8187 ei
= ei
.ctfeInterpret();
8192 if (ei
is null ||
(cast(void*)ei
.type
in TemplateValueParameter
.edummies
&&
8193 TemplateValueParameter
.edummies
[cast(void*)ei
.type
] == ei
))
8194 return matchArgNoMatch();
8196 Expression e
= tvp
.specValue
;
8198 sc
= sc
.startCTFE();
8199 e
= e
.expressionSemantic(sc
);
8200 e
= resolveProperties(sc
, e
);
8202 e
= e
.implicitCastTo(sc
, vt
);
8203 e
= e
.ctfeInterpret();
8205 ei
= ei
.syntaxCopy();
8206 sc
= sc
.startCTFE();
8207 ei
= ei
.expressionSemantic(sc
);
8209 ei
= ei
.implicitCastTo(sc
, vt
);
8210 ei
= ei
.ctfeInterpret();
8211 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
8212 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
8214 return matchArgNoMatch();
8220 // Must match already deduced value
8221 Expression e
= cast(Expression
)(*dedtypes
)[i
];
8222 if (!ei ||
!ei
.equals(e
))
8223 return matchArgNoMatch();
8226 (*dedtypes
)[i
] = ei
;
8230 Initializer _init
= new ExpInitializer(tvp
.loc
, ei
);
8231 Declaration sparam
= new VarDeclaration(tvp
.loc
, vt
, tvp
.ident
, _init
);
8232 sparam
.storage_class
= STC
.manifest
;
8235 return tvp
.dependent ? MATCH
.exact
: m
;
8238 MATCH
matchArgAlias(TemplateAliasParameter tap
)
8240 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
8241 MATCH m
= MATCH
.exact
;
8242 Type ta
= isType(oarg
);
8243 RootObject sa
= ta
&& !ta
.deco ?
null : getDsymbol(oarg
);
8244 Expression ea
= isExpression(oarg
);
8245 if (ea
&& (ea
.op
== EXP
.this_ || ea
.op
== EXP
.super_
))
8246 sa
= (cast(ThisExp
)ea
).var
;
8247 else if (ea
&& ea
.op
== EXP
.scope_
)
8248 sa
= (cast(ScopeExp
)ea
).sds
;
8251 if ((cast(Dsymbol
)sa
).isAggregateDeclaration())
8254 /* specType means the alias must be a declaration with a type
8255 * that matches specType.
8259 Declaration d
= (cast(Dsymbol
)sa
).isDeclaration();
8261 return matchArgNoMatch();
8262 if (!d
.type
.equals(tap
.specType
))
8263 return matchArgNoMatch();
8273 if (!ea
.type
.equals(tap
.specType
))
8274 return matchArgNoMatch();
8277 else if (ta
&& ta
.ty
== Tinstance
&& !tap
.specAlias
)
8279 /* Specialized parameter should be preferred
8280 * match to the template type parameter.
8281 * template X(alias a) {} // a == this
8282 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
8285 else if (sa
&& sa
== TemplateTypeParameter
.tdummy
)
8287 /* https://issues.dlang.org/show_bug.cgi?id=2025
8288 * Aggregate Types should preferentially
8289 * match to the template type parameter.
8290 * template X(alias a) {} // a == this
8291 * template X(T) {} // T => sa
8294 else if (ta
&& ta
.ty
!= Tident
)
8296 /* Match any type that's not a TypeIdentifier to alias parameters,
8297 * but prefer type parameter.
8298 * template X(alias a) { } // a == ta
8300 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
8305 return matchArgNoMatch();
8310 if (sa
== TemplateAliasParameter
.sdummy
)
8311 return matchArgNoMatch();
8312 // check specialization if template arg is a symbol
8313 Dsymbol sx
= isDsymbol(sa
);
8314 if (sa
!= tap
.specAlias
&& sx
)
8316 Type talias
= isType(tap
.specAlias
);
8318 return matchArgNoMatch();
8320 TemplateInstance ti
= sx
.isTemplateInstance();
8321 if (!ti
&& sx
.parent
)
8323 ti
= sx
.parent
.isTemplateInstance();
8324 if (ti
&& ti
.name
!= sx
.ident
)
8325 return matchArgNoMatch();
8328 return matchArgNoMatch();
8330 Type t
= new TypeInstance(Loc
.initial
, ti
);
8331 MATCH m2
= deduceType(t
, sc
, talias
, parameters
, dedtypes
);
8332 if (m2
== MATCH
.nomatch
)
8333 return matchArgNoMatch();
8335 // check specialization if template arg is a type
8338 if (Type tspec
= isType(tap
.specAlias
))
8340 MATCH m2
= ta
.implicitConvTo(tspec
);
8341 if (m2
== MATCH
.nomatch
)
8342 return matchArgNoMatch();
8346 error(tap
.loc
, "template parameter specialization for a type must be a type and not `%s`",
8347 tap
.specAlias
.toChars());
8348 return matchArgNoMatch();
8352 else if ((*dedtypes
)[i
])
8354 // Must match already deduced symbol
8355 RootObject si
= (*dedtypes
)[i
];
8356 if (!sa || si
!= sa
)
8357 return matchArgNoMatch();
8359 (*dedtypes
)[i
] = sa
;
8363 if (Dsymbol s
= isDsymbol(sa
))
8365 *psparam
= new AliasDeclaration(tap
.loc
, tap
.ident
, s
);
8367 else if (Type t
= isType(sa
))
8369 *psparam
= new AliasDeclaration(tap
.loc
, tap
.ident
, t
);
8375 // Declare manifest constant
8376 Initializer _init
= new ExpInitializer(tap
.loc
, ea
);
8377 auto v
= new VarDeclaration(tap
.loc
, null, tap
.ident
, _init
);
8378 v
.storage_class
= STC
.manifest
;
8379 v
.dsymbolSemantic(sc
);
8383 return tap
.dependent ? MATCH
.exact
: m
;
8386 MATCH
matchArgTuple(TemplateTupleParameter ttp
)
8388 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
8389 Tuple ovar
= isTuple(oarg
);
8391 return MATCH
.nomatch
;
8394 Tuple tup
= isTuple((*dedtypes
)[i
]);
8396 return MATCH
.nomatch
;
8397 if (!match(tup
, ovar
))
8398 return MATCH
.nomatch
;
8400 (*dedtypes
)[i
] = ovar
;
8403 *psparam
= new TupleDeclaration(ttp
.loc
, ttp
.ident
, &ovar
.objects
);
8404 return ttp
.dependent ? MATCH
.exact
: MATCH
.convert
;
8407 if (auto ttp
= tp
.isTemplateTypeParameter())
8408 return matchArgType(ttp
);
8409 else if (auto tvp
= tp
.isTemplateValueParameter())
8410 return matchArgValue(tvp
);
8411 else if (auto tap
= tp
.isTemplateAliasParameter())
8412 return matchArgAlias(tap
);
8413 else if (auto ttp
= tp
.isTemplateTupleParameter())
8414 return matchArgTuple(ttp
);
8420 /***********************************************
8421 * Collect and print statistics on template instantiations.
8423 struct TemplateStats
8425 __gshared TemplateStats
[const void*] stats
;
8427 uint numInstantiations
; // number of instantiations of the template
8428 uint uniqueInstantiations
; // number of unique instantiations of the template
8430 TemplateInstances
* allInstances
;
8432 /*******************************
8435 static void incInstance(const TemplateDeclaration td
,
8436 const TemplateInstance ti
)
8438 void log(ref TemplateStats ts
)
8440 if (ts
.allInstances
is null)
8441 ts
.allInstances
= new TemplateInstances();
8442 if (global
.params
.vtemplatesListInstances
)
8443 ts
.allInstances
.push(cast() ti
);
8446 // message(ti.loc, "incInstance %p %p", td, ti);
8447 if (!global
.params
.vtemplates
)
8452 if (auto ts
= cast(const void*) td
in stats
)
8455 ++ts
.numInstantiations
;
8459 stats
[cast(const void*) td
] = TemplateStats(1, 0);
8460 log(stats
[cast(const void*) td
]);
8464 /*******************************
8465 * Add this unique instance
8467 static void incUnique(const TemplateDeclaration td
,
8468 const TemplateInstance ti
)
8470 // message(ti.loc, "incUnique %p %p", td, ti);
8471 if (!global
.params
.vtemplates
)
8476 if (auto ts
= cast(const void*) td
in stats
)
8477 ++ts
.uniqueInstantiations
;
8479 stats
[cast(const void*) td
] = TemplateStats(0, 1);
8483 extern (C
++) void printTemplateStats()
8485 static struct TemplateDeclarationStats
8487 TemplateDeclaration td
;
8489 static int compare(scope const TemplateDeclarationStats
* a
,
8490 scope const TemplateDeclarationStats
* b
) @safe nothrow @nogc pure
8492 auto diff
= b
.ts
.uniqueInstantiations
- a
.ts
.uniqueInstantiations
;
8496 return b
.ts
.numInstantiations
- a
.ts
.numInstantiations
;
8500 if (!global
.params
.vtemplates
)
8503 Array
!(TemplateDeclarationStats
) sortedStats
;
8504 sortedStats
.reserve(TemplateStats
.stats
.length
);
8505 foreach (td_
, ref ts
; TemplateStats
.stats
)
8507 sortedStats
.push(TemplateDeclarationStats(cast(TemplateDeclaration
) td_
, ts
));
8510 sortedStats
.sort
!(TemplateDeclarationStats
.compare
);
8512 foreach (const ref ss
; sortedStats
[])
8514 if (global
.params
.vtemplatesListInstances
&&
8518 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
8519 ss
.ts
.numInstantiations
,
8520 ss
.ts
.uniqueInstantiations
,
8521 ss
.td
.toCharsNoConstraints());
8522 foreach (const ti
; (*ss
.ts
.allInstances
)[])
8524 if (ti
.tinst
) // if has enclosing instance
8525 message(ti
.loc
, "vtemplate: implicit instance `%s`", ti
.toChars());
8527 message(ti
.loc
, "vtemplate: explicit instance `%s`", ti
.toChars());
8533 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
8534 ss
.ts
.numInstantiations
,
8535 ss
.ts
.uniqueInstantiations
,
8536 ss
.td
.toCharsNoConstraints());
8542 private struct MATCHpair
8544 MATCH mta
; /// match template parameters by initial template arguments
8545 MATCH mfa
; /// match template parameters by inferred template arguments
8547 debug this(MATCH mta
, MATCH mfa
)
8549 assert(MATCH
.min
<= mta
&& mta
<= MATCH
.max
);
8550 assert(MATCH
.min
<= mfa
&& mfa
<= MATCH
.max
);
8556 private void write(ref OutBuffer buf
, RootObject obj
)
8560 buf
.writestring(obj
.toChars());