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
;
52 import dmd
.dinterpret
;
57 import dmd
.dsymbolsem
;
59 import dmd
.expression
;
60 import dmd
.expressionsem
;
65 import dmd
.identifier
;
73 import dmd
.root
.array
;
74 import dmd
.common
.outbuffer
;
75 import dmd
.rootobject
;
82 import dmd
.templateparamsem
;
84 //debug = FindExistingInstance; // print debug stats of findExistingInstance
85 private enum LOG
= false;
87 enum IDX_NOTFOUND
= 0x12345678;
89 pure nothrow @nogc @safe
92 /********************************************
93 * These functions substitute for dynamic_cast. dynamic_cast does not work
94 * on earlier versions of gcc.
96 extern (C
++) inout(Expression
) isExpression(inout RootObject o
)
98 //return dynamic_cast<Expression *>(o);
99 if (!o || o
.dyncast() != DYNCAST
.expression
)
101 return cast(inout(Expression
))o
;
104 extern (C
++) inout(Dsymbol
) isDsymbol(inout RootObject o
)
106 //return dynamic_cast<Dsymbol *>(o);
107 if (!o || o
.dyncast() != DYNCAST
.dsymbol
)
109 return cast(inout(Dsymbol
))o
;
112 extern (C
++) inout(Type
) isType(inout RootObject o
)
114 //return dynamic_cast<Type *>(o);
115 if (!o || o
.dyncast() != DYNCAST
.type
)
117 return cast(inout(Type
))o
;
120 extern (C
++) inout(Tuple
) isTuple(inout RootObject o
)
122 //return dynamic_cast<Tuple *>(o);
123 if (!o || o
.dyncast() != DYNCAST
.tuple
)
125 return cast(inout(Tuple
))o
;
128 extern (C
++) inout(Parameter
) isParameter(inout RootObject o
)
130 //return dynamic_cast<Parameter *>(o);
131 if (!o || o
.dyncast() != DYNCAST
.parameter
)
133 return cast(inout(Parameter
))o
;
136 extern (C
++) inout(TemplateParameter
) isTemplateParameter(inout RootObject o
)
138 if (!o || o
.dyncast() != DYNCAST
.templateparameter
)
140 return cast(inout(TemplateParameter
))o
;
143 /**************************************
144 * Is this Object an error?
146 extern (C
++) bool isError(const RootObject o
)
148 if (const t
= isType(o
))
149 return (t
.ty
== Terror
);
150 if (const e
= isExpression(o
))
151 return (e
.op
== EXP
.error ||
!e
.type || e
.type
.ty
== Terror
);
152 if (const v
= isTuple(o
))
153 return arrayObjectIsError(&v
.objects
);
154 const s
= isDsymbol(o
);
158 return s
.parent ?
isError(s
.parent
) : false;
161 /**************************************
162 * Are any of the Objects an error?
164 bool arrayObjectIsError(const Objects
* args
)
166 foreach (const o
; *args
)
174 /***********************
175 * Try to get arg as a type.
177 inout(Type
) getType(inout RootObject o
)
182 if (inout e
= isExpression(o
))
190 Dsymbol
getDsymbol(RootObject oarg
)
192 //printf("getDsymbol()\n");
193 //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
194 if (auto ea
= isExpression(oarg
))
196 // Try to convert Expression to symbol
197 if (auto ve
= ea
.isVarExp())
199 else if (auto fe
= ea
.isFuncExp())
200 return fe
.td ? fe
.td
: fe
.fd
;
201 else if (auto te
= ea
.isTemplateExp())
203 else if (auto te
= ea
.isScopeExp())
210 // Try to convert Type to symbol
211 if (auto ta
= isType(oarg
))
212 return ta
.toDsymbol(null);
214 return isDsymbol(oarg
); // if already a symbol
219 private Expression
getValue(ref Dsymbol s
)
223 if (VarDeclaration v
= s
.isVarDeclaration())
225 if (v
.storage_class
& STC
.manifest
)
226 return v
.getConstInitializer();
232 /***********************
233 * Try to get value from manifest constant
235 private Expression
getValue(Expression e
)
239 if (auto ve
= e
.isVarExp())
241 if (auto v
= ve
.var
.isVarDeclaration())
243 if (v
.storage_class
& STC
.manifest
)
245 e
= v
.getConstInitializer();
252 private Expression
getExpression(RootObject o
)
254 auto s
= isDsymbol(o
);
255 return s ?
.getValue(s
) : .getValue(isExpression(o
));
258 /******************************
259 * If o1 matches o2, return true.
260 * Else, return false.
262 private bool match(RootObject o1
, RootObject o2
)
268 printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
269 o1
, o1
.toChars(), o1
.dyncast(), o2
, o2
.toChars(), o2
.dyncast());
272 /* A proper implementation of the various equals() overrides
273 * should make it possible to just do o1.equals(o2), but
274 * we'll do that another day.
276 /* Manifest constants should be compared by their values,
277 * at least in template arguments.
280 if (auto t1
= isType(o1
))
282 auto t2
= isType(o2
);
288 printf("\tt1 = %s\n", t1
.toChars());
289 printf("\tt2 = %s\n", t2
.toChars());
296 if (auto e1
= getExpression(o1
))
298 auto e2
= getExpression(o2
);
304 printf("\te1 = %s '%s' %s\n", e1
.type ? e1
.type
.toChars() : "null", EXPtoString(e1
.op
).ptr
, e1
.toChars());
305 printf("\te2 = %s '%s' %s\n", e2
.type ? e2
.type
.toChars() : "null", EXPtoString(e2
.op
).ptr
, e2
.toChars());
308 // two expressions can be equal although they do not have the same
309 // type; that happens when they have the same value. So check type
310 // as well as expression equality to ensure templates are properly
312 if (!(e1
.type
&& e2
.type
&& e1
.type
.equals(e2
.type
)) ||
!e1
.equals(e2
))
317 if (auto s1
= isDsymbol(o1
))
319 auto s2
= isDsymbol(o2
);
325 printf("\ts1 = %s \n", s1
.kind(), s1
.toChars());
326 printf("\ts2 = %s \n", s2
.kind(), s2
.toChars());
330 if (s1
.parent
!= s2
.parent
&& !s1
.isFuncDeclaration() && !s2
.isFuncDeclaration())
335 if (auto u1
= isTuple(o1
))
337 auto u2
= isTuple(o2
);
343 printf("\tu1 = %s\n", u1
.toChars());
344 printf("\tu2 = %s\n", u2
.toChars());
346 if (!arrayObjectMatch(&u1
.objects
, &u2
.objects
))
353 printf("\t. match\n");
358 printf("\t. nomatch\n");
362 /************************************
363 * Match an array of them.
365 private bool arrayObjectMatch(Objects
* oa1
, Objects
* oa2
)
369 if (oa1
.length
!= oa2
.length
)
371 immutable oa1dim
= oa1
.length
;
372 auto oa1d
= (*oa1
)[].ptr
;
373 auto oa2d
= (*oa2
)[].ptr
;
374 foreach (j
; 0 .. oa1dim
)
376 RootObject o1
= oa1d
[j
];
377 RootObject o2
= oa2d
[j
];
386 /************************************
387 * Return hash of Objects.
389 private size_t
arrayObjectHash(Objects
* oa1
)
391 import dmd
.root
.hash
: mixHash
;
396 /* Must follow the logic of match()
398 if (auto t1
= isType(o1
))
399 hash
= mixHash(hash
, cast(size_t
)t1
.deco
);
400 else if (auto e1
= getExpression(o1
))
401 hash
= mixHash(hash
, expressionHash(e1
));
402 else if (auto s1
= isDsymbol(o1
))
404 auto fa1
= s1
.isFuncAliasDeclaration();
406 s1
= fa1
.toAliasFunc();
407 hash
= mixHash(hash
, mixHash(cast(size_t
)cast(void*)s1
.getIdent(), cast(size_t
)cast(void*)s1
.parent
));
409 else if (auto u1
= isTuple(o1
))
410 hash
= mixHash(hash
, arrayObjectHash(&u1
.objects
));
416 /************************************
417 * Computes hash of expression.
418 * Handles all Expression classes and MUST match their equals method,
419 * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2).
421 private size_t
expressionHash(Expression e
)
423 import dmd
.root
.ctfloat
: CTFloat
;
424 import dmd
.root
.hash
: calcHash
, mixHash
;
429 return cast(size_t
) e
.isIntegerExp().getInteger();
432 return CTFloat
.hash(e
.isRealExp().value
);
435 auto ce
= e
.isComplexExp();
436 return mixHash(CTFloat
.hash(ce
.toReal
), CTFloat
.hash(ce
.toImaginary
));
439 return cast(size_t
)cast(void*) e
.isIdentifierExp().ident
;
442 return cast(size_t
)cast(void*) e
.isNullExp().type
;
445 return calcHash(e
.isStringExp
.peekData());
449 auto te
= e
.isTupleExp();
451 hash
+= te
.e0 ?
expressionHash(te
.e0
) : 0;
452 foreach (elem
; *te
.exps
)
453 hash
= mixHash(hash
, expressionHash(elem
));
457 case EXP
.arrayLiteral
:
459 auto ae
= e
.isArrayLiteralExp();
461 foreach (i
; 0 .. ae
.elements
.length
)
462 hash
= mixHash(hash
, expressionHash(ae
[i
]));
466 case EXP
.assocArrayLiteral
:
468 auto ae
= e
.isAssocArrayLiteralExp();
470 foreach (i
; 0 .. ae
.keys
.length
)
471 // reduction needs associative op as keys are unsorted (use XOR)
472 hash ^
= mixHash(expressionHash((*ae
.keys
)[i
]), expressionHash((*ae
.values
)[i
]));
476 case EXP
.structLiteral
:
478 auto se
= e
.isStructLiteralExp();
480 foreach (elem
; *se
.elements
)
481 hash
= mixHash(hash
, elem ?
expressionHash(elem
) : 0);
486 return cast(size_t
)cast(void*) e
.isVarExp().var
;
489 return cast(size_t
)cast(void*) e
.isFuncExp().fd
;
492 // no custom equals for this expression
493 assert((&e
.equals
).funcptr
is &RootObject
.equals
);
494 // equals based on identity
495 return cast(size_t
)cast(void*) e
;
499 RootObject
objectSyntaxCopy(RootObject o
)
503 if (Type t
= isType(o
))
504 return t
.syntaxCopy();
505 if (Expression e
= isExpression(o
))
506 return e
.syntaxCopy();
510 extern (C
++) final class Tuple
: RootObject
518 numObjects = The initial number of objects.
520 extern (D
) this(size_t numObjects
)
522 objects
.setDim(numObjects
);
525 // kludge for template.isType()
526 override DYNCAST
dyncast() const
528 return DYNCAST
.tuple
;
531 override const(char)* toChars() const
533 return objects
.toChars();
537 struct TemplatePrevious
539 TemplatePrevious
* prev
;
544 /***********************************************************
545 * [mixin] template Identifier (parameters) [Constraint]
546 * https://dlang.org/spec/template.html
547 * https://dlang.org/spec/template-mixin.html
549 extern (C
++) final class TemplateDeclaration
: ScopeDsymbol
551 import dmd
.root
.array
: Array
;
553 TemplateParameters
* parameters
; // array of TemplateParameter's
554 TemplateParameters
* origParameters
; // originals for Ddoc
556 Expression constraint
;
558 // Hash table to look up TemplateInstance's of this TemplateDeclaration
559 TemplateInstance
[TemplateInstanceBox
] instances
;
561 TemplateDeclaration overnext
; // next overloaded TemplateDeclaration
562 TemplateDeclaration overroot
; // first in overnext list
563 FuncDeclaration funcroot
; // first function in unified overload list
565 Dsymbol onemember
; // if !=null then one member of this template
567 bool literal
; // this template declaration is a literal
568 bool ismixin
; // this is a mixin template declaration
569 bool isstatic
; // this is static template declaration
570 bool isTrivialAliasSeq
; /// matches pattern `template AliasSeq(T...) { alias AliasSeq = T; }`
571 bool isTrivialAlias
; /// matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
572 bool deprecated_
; /// this template declaration is deprecated
573 Visibility visibility
;
575 // threaded list of previous instantiation attempts on stack
576 TemplatePrevious
* previous
;
578 private Expression lastConstraint
; /// the constraint after the last failed evaluation
579 private Array
!Expression lastConstraintNegs
; /// its negative parts
580 private Objects
* lastConstraintTiargs
; /// template instance arguments for `lastConstraint`
582 extern (D
) this(const ref Loc loc
, Identifier ident
, TemplateParameters
* parameters
, Expression constraint
, Dsymbols
* decldefs
, bool ismixin
= false, bool literal
= false)
587 printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident
.toChars());
592 for (int i
= 0; i
< parameters
.length
; i
++)
594 TemplateParameter tp
= (*parameters
)[i
];
595 //printf("\tparameter[%d] = %p\n", i, tp);
596 TemplateTypeParameter ttp
= tp
.isTemplateTypeParameter();
599 printf("\tparameter[%d] = %s : %s\n", i
, tp
.ident
.toChars(), ttp
.specType ? ttp
.specType
.toChars() : "");
603 this.parameters
= parameters
;
604 this.origParameters
= parameters
;
605 this.constraint
= constraint
;
606 this.members
= decldefs
;
607 this.literal
= literal
;
608 this.ismixin
= ismixin
;
609 this.isstatic
= true;
610 this.visibility
= Visibility(Visibility
.Kind
.undefined
);
612 // Compute in advance for Ddoc's use
613 // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails.
614 if (!members ||
!ident
)
618 if (!Dsymbol
.oneMembers(members
, &s
, ident
) ||
!s
)
624 /* Set isTrivialAliasSeq if this fits the pattern:
625 * template AliasSeq(T...) { alias AliasSeq = T; }
626 * or set isTrivialAlias if this fits the pattern:
627 * template Alias(T) { alias Alias = qualifiers(T); }
629 if (!(parameters
&& parameters
.length
== 1))
632 auto ad
= s
.isAliasDeclaration();
636 auto ti
= ad
.type
.isTypeIdentifier();
638 if (!ti || ti
.idents
.length
!= 0)
641 if (auto ttp
= (*parameters
)[0].isTemplateTupleParameter())
643 if (ti
.ident
is ttp
.ident
&&
646 //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
647 isTrivialAliasSeq
= true;
650 else if (auto ttp
= (*parameters
)[0].isTemplateTypeParameter())
652 if (ti
.ident
is ttp
.ident
)
654 //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
655 isTrivialAlias
= true;
660 override TemplateDeclaration
syntaxCopy(Dsymbol
)
662 //printf("TemplateDeclaration.syntaxCopy()\n");
663 TemplateParameters
* p
= null;
666 p
= new TemplateParameters(parameters
.length
);
667 foreach (i
, ref param
; *p
)
668 param
= (*parameters
)[i
].syntaxCopy();
670 return new TemplateDeclaration(loc
, ident
, p
, constraint ? constraint
.syntaxCopy() : null, Dsymbol
.arraySyntaxCopy(members
), ismixin
, literal
);
673 /**********************************
674 * Overload existing TemplateDeclaration 'this' with the new one 's'.
675 * Return true if successful; i.e. no conflict.
677 override bool overloadInsert(Dsymbol s
)
681 printf("TemplateDeclaration.overloadInsert('%s')\n", s
.toChars());
683 FuncDeclaration fd
= s
.isFuncDeclaration();
687 return funcroot
.overloadInsert(fd
);
689 return funcroot
.overloadInsert(this);
692 // https://issues.dlang.org/show_bug.cgi?id=15795
693 // if candidate is an alias and its sema is not run then
694 // insertion can fail because the thing it alias is not known
695 if (AliasDeclaration ad
= s
.isAliasDeclaration())
698 aliasSemantic(ad
, s
._scope
);
699 if (ad
.aliassym
&& ad
.aliassym
is this)
702 TemplateDeclaration td
= s
.toAlias().isTemplateDeclaration();
706 TemplateDeclaration pthis
= this;
707 TemplateDeclaration
* ptd
;
708 for (ptd
= &pthis
; *ptd
; ptd
= &(*ptd
).overnext
)
716 printf("\ttrue: no conflict\n");
721 override bool hasStaticCtorOrDtor()
723 return false; // don't scan uninstantiated templates
726 override const(char)* kind() const
728 return (onemember
&& onemember
.isAggregateDeclaration()) ? onemember
.kind() : "template";
731 override const(char)* toChars() const
733 return toCharsMaybeConstraints(true);
736 /****************************
737 * Similar to `toChars`, but does not print the template constraints
739 const(char)* toCharsNoConstraints() const
741 return toCharsMaybeConstraints(false);
744 const(char)* toCharsMaybeConstraints(bool includeConstraints
) const
749 buf
.writestring(ident
== Id
.ctor ?
"this" : ident
.toString());
751 foreach (i
, const tp
; *parameters
)
754 buf
.writestring(", ");
755 toCBuffer(tp
, buf
, hgs
);
761 const FuncDeclaration fd
= onemember
.isFuncDeclaration();
764 TypeFunction tf
= cast(TypeFunction
)fd
.type
;
765 buf
.writestring(parametersTypeToChars(tf
.parameterList
));
769 buf
.MODtoBuffer(tf
.mod
);
774 if (includeConstraints
&&
777 buf
.writestring(" if (");
778 toCBuffer(constraint
, buf
, hgs
);
782 return buf
.extractChars();
785 override Visibility
visible() pure nothrow @nogc @safe
790 /****************************
791 * Check to see if constraint is satisfied.
793 extern (D
) bool evaluateConstraint(TemplateInstance ti
, Scope
* sc
, Scope
* paramscope
, Objects
* dedargs
, FuncDeclaration fd
)
795 /* Detect recursive attempts to instantiate this template declaration,
796 * https://issues.dlang.org/show_bug.cgi?id=4072
797 * void foo(T)(T x) if (is(typeof(foo(x)))) { }
798 * static assert(!is(typeof(foo(7))));
799 * Recursive attempts are regarded as a constraint failure.
801 /* There's a chicken-and-egg problem here. We don't know yet if this template
802 * instantiation will be a local one (enclosing is set), and we won't know until
803 * after selecting the correct template. Thus, function we're nesting inside
804 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
805 * Workaround the problem by setting a flag to relax the checking on frame errors.
808 for (TemplatePrevious
* p
= previous
; p
; p
= p
.prev
)
810 if (!arrayObjectMatch(p
.dedargs
, dedargs
))
812 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
813 /* It must be a subscope of p.sc, other scope chains are not recursive
815 * the chain of enclosing scopes is broken by paramscope (its enclosing
816 * scope is _scope, but paramscope.callsc is the instantiating scope). So
817 * it's good enough to check the chain of callsc
819 for (Scope
* scx
= paramscope
.callsc
; scx
; scx
= scx
.callsc
)
821 // The first scx might be identical for nested eponymeous templates, e.g.
822 // template foo() { void foo()() {...} }
823 if (scx
== p
.sc
&& scx
!is paramscope
.callsc
)
826 /* BUG: should also check for ref param differences
832 pr
.sc
= paramscope
.callsc
;
833 pr
.dedargs
= dedargs
;
834 previous
= &pr
; // add this to threaded list
836 Scope
* scx
= paramscope
.push(ti
);
840 // Set SCOPE.constraint before declaring function parameters for the static condition
841 // (previously, this was immediately before calling evalStaticCondition), so the
842 // semantic pass knows not to issue deprecation warnings for these throw-away decls.
843 // https://issues.dlang.org/show_bug.cgi?id=21831
844 scx
.flags |
= SCOPE
.constraint
;
849 /* Declare all the function parameters as variables and add them to the scope
850 * Making parameters is similar to FuncDeclaration.semantic3
852 auto tf
= fd
.type
.isTypeFunction();
856 Parameters
* fparameters
= tf
.parameterList
.parameters
;
857 const nfparams
= tf
.parameterList
.length
;
858 foreach (i
, fparam
; tf
.parameterList
)
860 fparam
.storageClass
&= (STC
.IOR | STC
.lazy_ | STC
.final_ | STC
.TYPECTOR | STC
.nodtor
);
861 fparam
.storageClass |
= STC
.parameter
;
862 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nfparams
)
864 fparam
.storageClass |
= STC
.variadic
;
865 /* Don't need to set STC.scope_ because this will only
866 * be evaluated at compile time
870 foreach (fparam
; *fparameters
)
874 // don't add it, if it has no name
875 auto v
= new VarDeclaration(fparam
.loc
, fparam
.type
, fparam
.ident
, null);
876 fparam
.storageClass |
= STC
.parameter
;
877 v
.storage_class
= fparam
.storageClass
;
878 v
.dsymbolSemantic(scx
);
880 ti
.symtab
= new DsymbolTable();
882 .error(loc
, "%s `%s` parameter `%s.%s` is already defined", kind
, toPrettyChars
, toChars(), v
.toChars());
887 fd
.storage_class |
= STC
.static_
;
891 lastConstraint
= constraint
.syntaxCopy();
892 lastConstraintTiargs
= ti
.tiargs
;
893 lastConstraintNegs
.setDim(0);
895 import dmd
.staticcond
;
897 assert(ti
.inst
is null);
898 ti
.inst
= ti
; // temporary instantiation to enable genIdent()
900 const bool result
= evalStaticCondition(scx
, constraint
, lastConstraint
, errors
, &lastConstraintNegs
);
901 if (result || errors
)
903 lastConstraint
= null;
904 lastConstraintTiargs
= null;
905 lastConstraintNegs
.setDim(0);
910 previous
= pr
.prev
; // unlink from threaded list
916 /****************************
917 * Destructively get the error message from the last constraint evaluation
919 * tip = tip to show after printing all overloads
921 const(char)* getConstraintEvalError(ref const(char)* tip
)
923 import dmd
.staticcond
;
925 // there will be a full tree view in verbose mode, and more compact list in the usual
926 const full
= global
.params
.v
.verbose
;
928 const msg
= visualizeStaticCondition(constraint
, lastConstraint
, lastConstraintNegs
[], full
, count
);
931 lastConstraint
= null;
932 lastConstraintTiargs
= null;
933 lastConstraintNegs
.setDim(0);
940 assert(parameters
&& lastConstraintTiargs
);
941 if (parameters
.length
> 0)
943 formatParamsWithTiargs(*lastConstraintTiargs
, buf
);
948 // choosing singular/plural
949 const s
= (count
== 1) ?
950 " must satisfy the following constraint:" :
951 " must satisfy one of the following constraints:";
956 buf
.writestring(msg
);
961 buf
.writestring(" whose parameters have the following constraints:");
963 const sep
= " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
964 buf
.writestring(sep
);
968 buf
.writestring(msg
);
970 buf
.writestring(sep
);
971 tip
= "not satisfied constraints are marked with `>`";
973 return buf
.extractChars();
976 private void formatParamsWithTiargs(ref Objects tiargs
, ref OutBuffer buf
)
978 buf
.writestring(" with `");
980 // write usual arguments line-by-line
981 // skips trailing default ones - they are not present in `tiargs`
982 const bool variadic
= isVariadic() !is null;
983 const end
= cast(int)parameters
.length
- (variadic ?
1 : 0);
985 for (; i
< tiargs
.length
&& i
< end
; i
++)
991 buf
.writestring(" ");
993 write(buf
, (*parameters
)[i
]);
994 buf
.writestring(" = ");
995 write(buf
, tiargs
[i
]);
997 // write remaining variadic arguments on the last line
1004 buf
.writestring(" ");
1006 write(buf
, (*parameters
)[end
]);
1007 buf
.writestring(" = ");
1009 if (cast(int)tiargs
.length
- end
> 0)
1011 write(buf
, tiargs
[end
]);
1012 foreach (j
; parameters
.length
.. tiargs
.length
)
1014 buf
.writestring(", ");
1015 write(buf
, tiargs
[j
]);
1023 /******************************
1024 * Create a scope for the parameters of the TemplateInstance
1025 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
1027 * If paramsym is null a new ScopeDsymbol is used in place of
1030 * ti = the TemplateInstance whose parameters to generate the scope for.
1031 * sc = the parent scope of ti
1033 * a scope for the parameters of ti
1035 Scope
* scopeForTemplateParameters(TemplateInstance ti
, Scope
* sc
)
1037 ScopeDsymbol paramsym
= new ScopeDsymbol();
1038 paramsym
.parent
= _scope
.parent
;
1039 Scope
* paramscope
= _scope
.push(paramsym
);
1040 paramscope
.tinst
= ti
;
1041 paramscope
.minst
= sc
.minst
;
1042 paramscope
.callsc
= sc
;
1047 /***************************************
1048 * Given that ti is an instance of this TemplateDeclaration,
1049 * deduce the types of the parameters to this, and store
1050 * those deduced types in dedtypes[].
1052 * flag 1: don't do semantic() because of dummy types
1053 * 2: don't change types in matchArg()
1055 * dedtypes deduced arguments
1056 * Return match level.
1058 extern (D
) MATCH
matchWithInstance(Scope
* sc
, TemplateInstance ti
, Objects
* dedtypes
, ArgumentList argumentList
, int flag
)
1063 printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti
.toChars(), flag
);
1067 printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes
.length
, parameters
.length
);
1068 if (ti
.tiargs
.length
)
1069 printf("ti.tiargs.length = %d, [0] = %p\n", ti
.tiargs
.length
, (*ti
.tiargs
)[0]);
1075 printf(" no match\n");
1077 return MATCH
.nomatch
;
1080 size_t dedtypes_dim
= dedtypes
.length
;
1085 return MATCH
.nomatch
;
1087 size_t parameters_dim
= parameters
.length
;
1088 int variadic
= isVariadic() !is null;
1090 // If more arguments than parameters, no match
1091 if (ti
.tiargs
.length
> parameters_dim
&& !variadic
)
1095 printf(" no match: more arguments than parameters\n");
1097 return MATCH
.nomatch
;
1100 assert(dedtypes_dim
== parameters_dim
);
1101 assert(dedtypes_dim
>= ti
.tiargs
.length || variadic
);
1105 // Set up scope for template parameters
1106 Scope
* paramscope
= scopeForTemplateParameters(ti
,sc
);
1108 // Attempt type deduction
1110 for (size_t i
= 0; i
< dedtypes_dim
; i
++)
1113 TemplateParameter tp
= (*parameters
)[i
];
1116 //printf("\targument [%d]\n", i);
1119 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
1120 TemplateTypeParameter ttp
= tp
.isTemplateTypeParameter();
1122 printf("\tparameter[%d] is %s : %s\n", i
, tp
.ident
.toChars(), ttp
.specType ? ttp
.specType
.toChars() : "");
1125 m2
= tp
.matchArg(ti
.loc
, paramscope
, ti
.tiargs
, i
, parameters
, dedtypes
, &sparam
);
1126 //printf("\tm2 = %d\n", m2);
1127 if (m2
== MATCH
.nomatch
)
1131 printf("\tmatchArg() for parameter %i failed\n", i
);
1140 sparam
.dsymbolSemantic(paramscope
);
1141 if (!paramscope
.insert(sparam
)) // TODO: This check can make more early
1143 // in TemplateDeclaration.semantic, and
1144 // then we don't need to make sparam if flags == 0
1151 /* Any parameter left without a type gets the type of
1152 * its corresponding arg
1154 foreach (i
, ref dedtype
; *dedtypes
)
1158 assert(i
< ti
.tiargs
.length
);
1159 dedtype
= cast(Type
)(*ti
.tiargs
)[i
];
1164 if (m
> MATCH
.nomatch
&& constraint
&& !flag
)
1166 if (ti
.hasNestedArgs(ti
.tiargs
, this.isstatic
)) // TODO: should gag error
1167 ti
.parent
= ti
.enclosing
;
1169 ti
.parent
= this.parent
;
1171 // Similar to doHeaderInstantiation
1172 FuncDeclaration fd
= onemember ? onemember
.isFuncDeclaration() : null;
1175 TypeFunction tf
= fd
.type
.isTypeFunction().syntaxCopy();
1176 if (argumentList
.hasNames
)
1178 Expressions
* fargs
= argumentList
.arguments
;
1179 // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
1181 // return nomatch();
1183 fd
= new FuncDeclaration(fd
.loc
, fd
.endloc
, fd
.ident
, fd
.storage_class
, tf
);
1185 fd
.inferRetType
= true;
1187 // Shouldn't run semantic on default arguments and return type.
1188 foreach (ref param
; *tf
.parameterList
.parameters
)
1189 param
.defaultArg
= null;
1192 tf
.incomplete
= true;
1194 // Resolve parameter types and 'auto ref's.
1196 uint olderrors
= global
.startGagging();
1197 fd
.type
= tf
.typeSemantic(loc
, paramscope
);
1198 global
.endGagging(olderrors
);
1199 if (fd
.type
.ty
!= Tfunction
)
1201 fd
.originalType
= fd
.type
; // for mangling
1204 // TODO: dedtypes => ti.tiargs ?
1205 if (!evaluateConstraint(ti
, sc
, paramscope
, dedtypes
, fd
))
1211 // Print out the results
1212 printf("--------------------------\n");
1213 printf("template %s\n", toChars());
1214 printf("instance %s\n", ti
.toChars());
1215 if (m
> MATCH
.nomatch
)
1217 for (size_t i
= 0; i
< dedtypes_dim
; i
++)
1219 TemplateParameter tp
= (*parameters
)[i
];
1222 if (i
< ti
.tiargs
.length
)
1223 oarg
= (*ti
.tiargs
)[i
];
1226 tp
.print(oarg
, (*dedtypes
)[i
]);
1234 printf(" match = %d\n", m
);
1240 printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti
.toChars(), m
);
1245 /********************************************
1246 * Determine partial specialization order of 'this' vs td2.
1248 * match this is at least as specialized as td2
1249 * 0 td2 is more specialized than this
1251 extern (D
) MATCH
leastAsSpecialized(Scope
* sc
, TemplateDeclaration td2
, ArgumentList argumentList
)
1253 enum LOG_LEASTAS
= 0;
1254 static if (LOG_LEASTAS
)
1256 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2
.toChars());
1259 /* This works by taking the template parameters to this template
1260 * declaration and feeding them to td2 as if it were a template
1262 * If it works, then this template is at least as specialized
1266 // Set type arguments to dummy template instance to be types
1267 // generated from the parameters to this template declaration
1268 auto tiargs
= new Objects();
1269 tiargs
.reserve(parameters
.length
);
1270 foreach (tp
; *parameters
)
1274 RootObject p
= tp
.dummyArg();
1275 if (!p
) //TemplateTupleParameter
1280 scope TemplateInstance ti
= new TemplateInstance(Loc
.initial
, ident
, tiargs
); // create dummy template instance
1282 // Temporary Array to hold deduced types
1283 Objects dedtypes
= Objects(td2
.parameters
.length
);
1285 // Attempt a type deduction
1286 MATCH m
= td2
.matchWithInstance(sc
, ti
, &dedtypes
, argumentList
, 1);
1287 if (m
> MATCH
.nomatch
)
1289 /* A non-variadic template is more specialized than a
1292 TemplateTupleParameter tp
= isVariadic();
1293 if (tp
&& !tp
.dependent
&& !td2
.isVariadic())
1296 static if (LOG_LEASTAS
)
1298 printf(" matches %d, so is least as specialized\n", m
);
1303 static if (LOG_LEASTAS
)
1305 printf(" doesn't match, so is not as specialized\n");
1307 return MATCH
.nomatch
;
1310 /*************************************************
1311 * Match function arguments against a specific template function.
1314 * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments
1315 * sc = instantiation scope
1316 * fd = Partially instantiated function declaration, which is set to an instantiated function declaration
1317 * tthis = 'this' argument if !NULL
1318 * argumentList = arguments to function
1321 * match pair of initial and inferred template arguments
1323 extern (D
) MATCHpair
deduceFunctionTemplateMatch(TemplateInstance ti
, Scope
* sc
, ref FuncDeclaration fd
, Type tthis
, ArgumentList argumentList
)
1327 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
1328 for (size_t i
= 0; i
< (fargs ? fargs
.length
: 0); i
++)
1330 Expression e
= (*fargs
)[i
];
1331 printf("\tfarg[%d] is %s, type is %s\n", cast(int) i
, e
.toChars(), e
.type
.toChars());
1333 printf("fd = %s\n", fd
.toChars());
1334 printf("fd.type = %s\n", fd
.type
.toChars());
1336 printf("tthis = %s\n", tthis
.toChars());
1341 auto dedargs
= new Objects(parameters
.length
);
1344 Objects
* dedtypes
= &ti
.tdtypes
; // for T:T*, the dedargs is the T*, dedtypes is the T
1345 dedtypes
.setDim(parameters
.length
);
1348 if (errors || fd
.errors
)
1349 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
1351 // Set up scope for parameters
1352 Scope
* paramscope
= scopeForTemplateParameters(ti
,sc
);
1357 //printf("\tnomatch\n");
1358 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
1361 MATCHpair
matcherror()
1363 // todo: for the future improvement
1365 //printf("\terror\n");
1366 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
1368 // Mark the parameter scope as deprecated if the templated
1369 // function is deprecated (since paramscope.enclosing is the
1370 // calling scope already)
1371 paramscope
.stc |
= fd
.storage_class
& STC
.deprecated_
;
1373 TemplateTupleParameter tp
= isVariadic();
1374 Tuple declaredTuple
= null;
1378 for (size_t i
= 0; i
< dedargs
.length
; i
++)
1380 printf("\tdedarg[%d] = ", i
);
1381 RootObject oarg
= (*dedargs
)[i
];
1383 printf("%s", oarg
.toChars());
1388 size_t ntargs
= 0; // array size of tiargs
1389 size_t inferStart
= 0; // index of first parameter to infer
1390 const Loc instLoc
= ti
.loc
;
1391 MATCH matchTiargs
= MATCH
.exact
;
1393 if (auto tiargs
= ti
.tiargs
)
1395 // Set initial template arguments
1396 ntargs
= tiargs
.length
;
1397 size_t n
= parameters
.length
;
1405 /* The extra initial template arguments
1406 * now form the tuple argument.
1408 auto t
= new Tuple(ntargs
- n
);
1409 assert(parameters
.length
);
1410 (*dedargs
)[parameters
.length
- 1] = t
;
1412 for (size_t i
= 0; i
< t
.objects
.length
; i
++)
1414 t
.objects
[i
] = (*tiargs
)[n
+ i
];
1416 declareParameter(paramscope
, tp
, t
);
1422 memcpy(dedargs
.tdata(), tiargs
.tdata(), n
* (*dedargs
.tdata()).sizeof
);
1424 for (size_t i
= 0; i
< n
; i
++)
1426 assert(i
< parameters
.length
);
1427 Declaration sparam
= null;
1428 MATCH m
= (*parameters
)[i
].matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, &sparam
);
1429 //printf("\tdeduceType m = %d\n", m);
1430 if (m
== MATCH
.nomatch
)
1432 if (m
< matchTiargs
)
1435 sparam
.dsymbolSemantic(paramscope
);
1436 if (!paramscope
.insert(sparam
))
1439 if (n
< parameters
.length
&& !declaredTuple
)
1444 inferStart
= parameters
.length
;
1445 //printf("tiargs matchTiargs = %d\n", matchTiargs);
1449 for (size_t i
= 0; i
< dedargs
.length
; i
++)
1451 printf("\tdedarg[%d] = ", i
);
1452 RootObject oarg
= (*dedargs
)[i
];
1454 printf("%s", oarg
.toChars());
1459 ParameterList fparameters
= fd
.getParameterList(); // function parameter list
1460 const nfparams
= fparameters
.length
; // number of function parameters
1461 const nfargs
= argumentList
.length
; // number of function arguments
1462 if (argumentList
.hasNames
)
1463 return matcherror(); // TODO: resolve named args
1464 Expressions
* fargs
= argumentList
.arguments
; // TODO: resolve named args
1466 /* Check for match of function arguments with variadic template
1467 * parameter, such as:
1469 * void foo(T, A...)(T t, A a);
1470 * void main() { foo(1,2,3); }
1472 size_t fptupindex
= IDX_NOTFOUND
;
1473 if (tp
) // if variadic
1475 // TemplateTupleParameter always makes most lesser matching.
1476 matchTiargs
= MATCH
.convert
;
1478 if (nfparams
== 0 && nfargs
!= 0) // if no function parameters
1482 auto t
= new Tuple();
1483 //printf("t = %p\n", t);
1484 (*dedargs
)[parameters
.length
- 1] = t
;
1485 declareParameter(paramscope
, tp
, t
);
1491 /* Figure out which of the function parameters matches
1492 * the tuple template parameter. Do this by matching
1494 * Set the index of this function parameter to fptupindex.
1496 for (fptupindex
= 0; fptupindex
< nfparams
; fptupindex
++)
1498 auto fparam
= (*fparameters
.parameters
)[fptupindex
]; // fparameters[fptupindex] ?
1499 if (fparam
.type
.ty
!= Tident
)
1501 TypeIdentifier tid
= cast(TypeIdentifier
)fparam
.type
;
1502 if (!tp
.ident
.equals(tid
.ident
) || tid
.idents
.length
)
1505 if (fparameters
.varargs
!= VarArg
.none
) // variadic function doesn't
1506 return nomatch(); // go with variadic template
1510 fptupindex
= IDX_NOTFOUND
;
1515 MATCH match
= MATCH
.exact
;
1516 if (toParent().isModule())
1520 bool hasttp
= false;
1522 // Match 'tthis' to any TemplateThisParameter's
1523 foreach (param
; *parameters
)
1525 if (auto ttp
= param
.isTemplateThisParameter())
1529 Type t
= new TypeIdentifier(Loc
.initial
, ttp
.ident
);
1530 MATCH m
= deduceType(tthis
, paramscope
, t
, parameters
, dedtypes
);
1531 if (m
== MATCH
.nomatch
)
1534 match
= m
; // pick worst match
1538 // Match attributes of tthis against attributes of fd
1539 if (fd
.type
&& !fd
.isCtorDeclaration() && !(_scope
.stc & STC
.static_
))
1541 StorageClass
stc = _scope
.stc | fd
.storage_class2
;
1542 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
1544 while (p
.isTemplateDeclaration() || p
.isTemplateInstance())
1546 AggregateDeclaration ad
= p
.isAggregateDeclaration();
1548 stc |
= ad
.storage_class
;
1550 ubyte mod
= fd
.type
.mod
;
1551 if (stc & STC
.immutable_
)
1552 mod
= MODFlags
.immutable_
;
1555 if (stc & (STC
.shared_ | STC
.synchronized_
))
1556 mod |
= MODFlags
.shared_
;
1557 if (stc & STC
.const_
)
1558 mod |
= MODFlags
.const_
;
1560 mod |
= MODFlags
.wild
;
1563 ubyte thismod
= tthis
.mod
;
1565 mod
= MODmerge(thismod
, mod
);
1566 MATCH m
= MODmethodConv(thismod
, mod
);
1567 if (m
== MATCH
.nomatch
)
1574 // Loop through the function parameters
1576 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
1577 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
1579 size_t nfargs2
= nfargs
; // nfargs + supplied defaultArgs
1580 uint inoutMatch
= 0; // for debugging only
1581 for (size_t parami
= 0; parami
< nfparams
; parami
++)
1583 Parameter fparam
= fparameters
[parami
];
1585 // Apply function parameter storage classes to parameter types
1586 Type prmtype
= fparam
.type
.addStorageClass(fparam
.storageClass
);
1590 /* See function parameters which wound up
1591 * as part of a template tuple parameter.
1593 if (fptupindex
!= IDX_NOTFOUND
&& parami
== fptupindex
)
1595 assert(prmtype
.ty
== Tident
);
1596 TypeIdentifier tid
= cast(TypeIdentifier
)prmtype
;
1599 /* The types of the function arguments
1600 * now form the tuple argument.
1602 declaredTuple
= new Tuple();
1603 (*dedargs
)[parameters
.length
- 1] = declaredTuple
;
1605 /* Count function parameters with no defaults following a tuple parameter.
1606 * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
1609 for (size_t j
= parami
+ 1; j
< nfparams
; j
++)
1611 Parameter p
= fparameters
[j
];
1616 if (!reliesOnTemplateParameters(p
.type
, (*parameters
)[inferStart
.. parameters
.length
]))
1618 Type pt
= p
.type
.syntaxCopy().typeSemantic(fd
.loc
, paramscope
);
1619 rem
+= pt
.ty
== Ttuple ?
(cast(TypeTuple
)pt
).arguments
.length
: 1;
1627 if (nfargs2
- argi
< rem
)
1629 declaredTuple
.objects
.setDim(nfargs2
- argi
- rem
);
1630 for (size_t i
= 0; i
< declaredTuple
.objects
.length
; i
++)
1632 farg
= (*fargs
)[argi
+ i
];
1634 // Check invalid arguments to detect errors early.
1635 if (farg
.op
== EXP
.error || farg
.type
.ty
== Terror
)
1638 if (!fparam
.isLazy() && farg
.type
.ty
== Tvoid
)
1643 if (ubyte wm
= deduceWildHelper(farg
.type
, &tt
, tid
))
1650 m
= deduceTypeHelper(farg
.type
, &tt
, tid
);
1652 if (m
== MATCH
.nomatch
)
1657 /* Remove top const for dynamic array types and pointer types
1659 if ((tt
.ty
== Tarray || tt
.ty
== Tpointer
) && !tt
.isMutable() && (!(fparam
.storageClass
& STC
.ref_
) ||
(fparam
.storageClass
& STC
.auto_
) && !farg
.isLvalue()))
1661 tt
= tt
.mutableOf();
1663 declaredTuple
.objects
[i
] = tt
;
1665 declareParameter(paramscope
, tp
, declaredTuple
);
1669 // https://issues.dlang.org/show_bug.cgi?id=6810
1670 // If declared tuple is not a type tuple,
1671 // it cannot be function parameter types.
1672 for (size_t i
= 0; i
< declaredTuple
.objects
.length
; i
++)
1674 if (!isType(declaredTuple
.objects
[i
]))
1678 assert(declaredTuple
);
1679 argi
+= declaredTuple
.objects
.length
;
1683 // If parameter type doesn't depend on inferred template parameters,
1684 // semantic it to get actual type.
1685 if (!reliesOnTemplateParameters(prmtype
, (*parameters
)[inferStart
.. parameters
.length
]))
1687 // should copy prmtype to avoid affecting semantic result
1688 prmtype
= prmtype
.syntaxCopy().typeSemantic(fd
.loc
, paramscope
);
1690 if (prmtype
.ty
== Ttuple
)
1692 TypeTuple tt
= cast(TypeTuple
)prmtype
;
1693 size_t tt_dim
= tt
.arguments
.length
;
1694 for (size_t j
= 0; j
< tt_dim
; j
++, ++argi
)
1696 Parameter p
= (*tt
.arguments
)[j
];
1697 if (j
== tt_dim
- 1 && fparameters
.varargs
== VarArg
.typesafe
&&
1698 parami
+ 1 == nfparams
&& argi
< nfargs
)
1708 // https://issues.dlang.org/show_bug.cgi?id=19888
1709 if (fparam
.defaultArg
)
1714 farg
= (*fargs
)[argi
];
1715 if (!farg
.implicitConvTo(p
.type
))
1722 if (argi
>= nfargs
) // if not enough arguments
1724 if (!fparam
.defaultArg
)
1727 /* https://issues.dlang.org/show_bug.cgi?id=2803
1728 * Before the starting of type deduction from the function
1729 * default arguments, set the already deduced parameters into paramscope.
1730 * It's necessary to avoid breaking existing acceptable code. Cases:
1732 * 1. Already deduced template parameters can appear in fparam.defaultArg:
1733 * auto foo(A, B)(A a, B b = A.stringof);
1735 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
1737 * 2. If prmtype depends on default-specified template parameter, the
1738 * default type should be preferred.
1739 * auto foo(N = size_t, R)(R r, N start = 0)
1741 * // at fparam `N start = 0`, N should be 'size_t' before
1742 * // the deduction result from fparam.defaultArg.
1746 foreach (ref dedtype
; *dedtypes
)
1748 Type at
= isType(dedtype
);
1749 if (at
&& at
.ty
== Tnone
)
1751 TypeDeduced xt
= cast(TypeDeduced
)at
;
1752 dedtype
= xt
.tded
; // 'unbox'
1755 for (size_t i
= ntargs
; i
< dedargs
.length
; i
++)
1757 TemplateParameter tparam
= (*parameters
)[i
];
1759 RootObject oarg
= (*dedargs
)[i
];
1760 RootObject oded
= (*dedtypes
)[i
];
1766 if (tparam
.specialization() ||
!tparam
.isTemplateTypeParameter())
1768 /* The specialization can work as long as afterwards
1771 (*dedargs
)[i
] = oded
;
1772 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, null);
1773 //printf("m2 = %d\n", m2);
1774 if (m2
== MATCH
.nomatch
)
1776 if (m2
< matchTiargs
)
1777 matchTiargs
= m2
; // pick worst match
1778 if (!(*dedtypes
)[i
].equals(oded
))
1779 .error(loc
, "%s `%s` specialization not allowed for deduced parameter `%s`", kind
, toPrettyChars
, kind
, toPrettyChars
, tparam
.ident
.toChars());
1783 if (MATCH
.convert
< matchTiargs
)
1784 matchTiargs
= MATCH
.convert
;
1786 (*dedargs
)[i
] = declareParameter(paramscope
, tparam
, oded
);
1790 oded
= tparam
.defaultArg(instLoc
, paramscope
);
1792 (*dedargs
)[i
] = declareParameter(paramscope
, tparam
, oded
);
1798 /* If prmtype does not depend on any template parameters:
1800 * auto foo(T)(T v, double x = 0);
1802 * // at fparam == 'double x = 0'
1804 * or, if all template parameters in the prmtype are already deduced:
1806 * auto foo(R)(R range, ElementType!R sum = 0);
1808 * // at fparam == 'ElementType!R sum = 0'
1810 * Deducing prmtype from fparam.defaultArg is not necessary.
1812 if (prmtype
.deco || prmtype
.syntaxCopy().trySemantic(loc
, paramscope
))
1818 // Deduce prmtype from the defaultArg.
1819 farg
= fparam
.defaultArg
.syntaxCopy();
1820 farg
= farg
.expressionSemantic(paramscope
);
1821 farg
= resolveProperties(paramscope
, farg
);
1825 farg
= (*fargs
)[argi
];
1828 // Check invalid arguments to detect errors early.
1829 if (farg
.op
== EXP
.error || farg
.type
.ty
== Terror
)
1836 printf("\tfarg.type = %s\n", farg
.type
.toChars());
1837 printf("\tfparam.type = %s\n", prmtype
.toChars());
1839 Type argtype
= farg
.type
;
1841 if (!fparam
.isLazy() && argtype
.ty
== Tvoid
&& farg
.op
!= EXP
.function_
)
1844 // https://issues.dlang.org/show_bug.cgi?id=12876
1845 // Optimize argument to allow CT-known length matching
1846 farg
= farg
.optimize(WANTvalue
, fparam
.isReference());
1847 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
1849 RootObject oarg
= farg
;
1850 if ((fparam
.storageClass
& STC
.ref_
) && (!(fparam
.storageClass
& STC
.auto_
) || farg
.isLvalue()))
1852 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
1855 if (argtype
.ty
== Tarray
&& (prmtype
.ty
== Tsarray || prmtype
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)prmtype
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
1857 if (StringExp se
= farg
.isStringExp())
1859 argtype
= se
.type
.nextOf().sarrayOf(se
.len
);
1861 else if (ArrayLiteralExp ae
= farg
.isArrayLiteralExp())
1863 argtype
= ae
.type
.nextOf().sarrayOf(ae
.elements
.length
);
1865 else if (SliceExp se
= farg
.isSliceExp())
1867 if (Type tsa
= toStaticArrayType(se
))
1874 else if ((fparam
.storageClass
& STC
.out_
) == 0 && (argtype
.ty
== Tarray || argtype
.ty
== Tpointer
) && templateParameterLookup(prmtype
, parameters
) != IDX_NOTFOUND
&& (cast(TypeIdentifier
)prmtype
).idents
.length
== 0)
1876 /* The farg passing to the prmtype always make a copy. Therefore,
1877 * we can shrink the set of the deduced type arguments for prmtype
1878 * by adjusting top-qualifier of the argtype.
1880 * prmtype argtype ta
1881 * T <- const(E)[] const(E)[]
1882 * T <- const(E[]) const(E)[]
1883 * qualifier(T) <- const(E)[] const(E[])
1884 * qualifier(T) <- const(E[]) const(E[])
1886 Type ta
= argtype
.castMod(prmtype
.mod ? argtype
.nextOf().mod
: 0);
1889 Expression ea
= farg
.copy();
1895 if (fparameters
.varargs
== VarArg
.typesafe
&& parami
+ 1 == nfparams
&& argi
+ 1 < nfargs
)
1899 MATCH m
= deduceType(oarg
, paramscope
, prmtype
, parameters
, dedtypes
, &im
, inferStart
);
1900 //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
1903 /* If no match, see if the argument can be matched by using
1904 * implicit conversions.
1906 if (m
== MATCH
.nomatch
&& prmtype
.deco
)
1907 m
= farg
.implicitConvTo(prmtype
);
1909 if (m
== MATCH
.nomatch
)
1911 AggregateDeclaration ad
= isAggregate(farg
.type
);
1912 if (ad
&& ad
.aliasthis
&& !isRecursiveAliasThis(att
, argtype
))
1914 // https://issues.dlang.org/show_bug.cgi?id=12537
1915 // The isRecursiveAliasThis() call above
1917 /* If a semantic error occurs while doing alias this,
1918 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
1919 * just regard it as not a match.
1921 * We also save/restore sc.func.flags to avoid messing up
1922 * attribute inference in the evaluation.
1924 const oldflags
= sc
.func ? sc
.func
.flags
: 0;
1925 auto e
= resolveAliasThis(sc
, farg
, true);
1927 sc
.func
.flags
= oldflags
;
1936 if (m
> MATCH
.nomatch
&& (fparam
.storageClass
& (STC
.ref_ | STC
.auto_
)) == STC
.ref_
)
1938 if (!farg
.isLvalue())
1940 if ((farg
.op
== EXP
.string_ || farg
.op
== EXP
.slice
) && (prmtype
.ty
== Tsarray || prmtype
.ty
== Taarray
))
1942 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1944 else if (global
.params
.rvalueRefParam
== FeatureState
.enabled
)
1946 // Allow implicit conversion to ref
1952 if (m
> MATCH
.nomatch
&& (fparam
.storageClass
& STC
.out_
))
1954 if (!farg
.isLvalue())
1956 if (!farg
.type
.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1959 if (m
== MATCH
.nomatch
&& fparam
.isLazy() && prmtype
.ty
== Tvoid
&& farg
.type
.ty
!= Tvoid
)
1961 if (m
!= MATCH
.nomatch
)
1964 match
= m
; // pick worst match
1971 /* The following code for variadic arguments closely
1972 * matches TypeFunction.callMatch()
1974 if (!(fparameters
.varargs
== VarArg
.typesafe
&& parami
+ 1 == nfparams
))
1977 /* Check for match with function parameter T...
1979 Type tb
= prmtype
.toBasetype();
1982 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1986 // Perhaps we can do better with this, see TypeFunction.callMatch()
1987 if (tb
.ty
== Tsarray
)
1989 TypeSArray tsa
= cast(TypeSArray
)tb
;
1990 dinteger_t sz
= tsa
.dim
.toInteger();
1991 if (sz
!= nfargs
- argi
)
1994 else if (tb
.ty
== Taarray
)
1996 TypeAArray taa
= cast(TypeAArray
)tb
;
1997 Expression dim
= new IntegerExp(instLoc
, nfargs
- argi
, Type
.tsize_t
);
1999 size_t i
= templateParameterLookup(taa
.index
, parameters
);
2000 if (i
== IDX_NOTFOUND
)
2007 uint errors
= global
.startGagging();
2008 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
2009 * The parameter isn't part of the template
2010 * ones, let's try to find it in the
2011 * instantiation scope 'sc' and the one
2012 * belonging to the template itself. */
2014 taa
.index
.resolve(instLoc
, sco
, e
, t
, s
);
2018 taa
.index
.resolve(instLoc
, sco
, e
, t
, s
);
2020 global
.endGagging(errors
);
2025 e
= e
.ctfeInterpret();
2026 e
= e
.implicitCastTo(sco
, Type
.tsize_t
);
2027 e
= e
.optimize(WANTvalue
);
2033 // This code matches code in TypeInstance.deduceType()
2034 TemplateParameter tprm
= (*parameters
)[i
];
2035 TemplateValueParameter tvp
= tprm
.isTemplateValueParameter();
2038 Expression e
= cast(Expression
)(*dedtypes
)[i
];
2046 Type vt
= tvp
.valType
.typeSemantic(Loc
.initial
, sc
);
2047 MATCH m
= dim
.implicitConvTo(vt
);
2048 if (m
== MATCH
.nomatch
)
2050 (*dedtypes
)[i
] = dim
;
2058 TypeArray ta
= cast(TypeArray
)tb
;
2059 Type tret
= fparam
.isLazyArray();
2060 for (; argi
< nfargs
; argi
++)
2062 Expression arg
= (*fargs
)[argi
];
2066 /* If lazy array of delegates,
2067 * convert arg(s) to delegate(s)
2071 if (ta
.next
.equals(arg
.type
))
2077 m
= arg
.implicitConvTo(tret
);
2078 if (m
== MATCH
.nomatch
)
2080 if (tret
.toBasetype().ty
== Tvoid
)
2088 m
= deduceType(arg
, paramscope
, ta
.next
, parameters
, dedtypes
, &wm
, inferStart
);
2091 if (m
== MATCH
.nomatch
)
2107 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
2108 if (argi
!= nfargs2
&& fparameters
.varargs
== VarArg
.none
)
2113 foreach (ref dedtype
; *dedtypes
)
2115 Type at
= isType(dedtype
);
2120 TypeDeduced xt
= cast(TypeDeduced
)at
;
2121 at
= xt
.tded
; // 'unbox'
2123 dedtype
= at
.merge2();
2126 for (size_t i
= ntargs
; i
< dedargs
.length
; i
++)
2128 TemplateParameter tparam
= (*parameters
)[i
];
2129 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
2131 /* For T:T*, the dedargs is the T*, dedtypes is the T
2132 * But for function templates, we really need them to match
2134 RootObject oarg
= (*dedargs
)[i
];
2135 RootObject oded
= (*dedtypes
)[i
];
2136 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
2137 //if (oarg) printf("oarg: %s\n", oarg.toChars());
2138 //if (oded) printf("oded: %s\n", oded.toChars());
2144 if (tparam
.specialization() ||
!tparam
.isTemplateTypeParameter())
2146 /* The specialization can work as long as afterwards
2149 (*dedargs
)[i
] = oded
;
2150 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, null);
2151 //printf("m2 = %d\n", m2);
2152 if (m2
== MATCH
.nomatch
)
2154 if (m2
< matchTiargs
)
2155 matchTiargs
= m2
; // pick worst match
2156 if (!(*dedtypes
)[i
].equals(oded
))
2157 .error(loc
, "%s `%s` specialization not allowed for deduced parameter `%s`", kind
, toPrettyChars
, tparam
.ident
.toChars());
2161 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
2162 if (MATCH
.convert
< matchTiargs
)
2163 matchTiargs
= MATCH
.convert
;
2168 oded
= tparam
.defaultArg(instLoc
, paramscope
);
2171 // if tuple parameter and
2172 // tuple parameter was not in function parameter list and
2173 // we're one or more arguments short (i.e. no tuple argument)
2175 fptupindex
== IDX_NOTFOUND
&&
2176 ntargs
<= dedargs
.length
- 1)
2178 // make tuple argument an empty tuple
2185 return matcherror();
2188 /* At the template parameter T, the picked default template argument
2189 * X!int should be matched to T in order to deduce dependent
2190 * template parameter A.
2191 * auto foo(T : X!A = X!int, A...)() { ... }
2192 * foo(); // T <-- X!int, A <-- (int)
2194 if (tparam
.specialization())
2196 (*dedargs
)[i
] = oded
;
2197 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, parameters
, dedtypes
, null);
2198 //printf("m2 = %d\n", m2);
2199 if (m2
== MATCH
.nomatch
)
2201 if (m2
< matchTiargs
)
2202 matchTiargs
= m2
; // pick worst match
2203 if (!(*dedtypes
)[i
].equals(oded
))
2204 .error(loc
, "%s `%s` specialization not allowed for deduced parameter `%s`", kind
, toPrettyChars
, tparam
.ident
.toChars());
2207 oded
= declareParameter(paramscope
, tparam
, oded
);
2208 (*dedargs
)[i
] = oded
;
2211 /* https://issues.dlang.org/show_bug.cgi?id=7469
2212 * As same as the code for 7469 in findBestMatch,
2213 * expand a Tuple in dedargs to normalize template arguments.
2215 if (auto d
= dedargs
.length
)
2217 if (auto va
= isTuple((*dedargs
)[d
- 1]))
2219 dedargs
.setDim(d
- 1);
2220 dedargs
.insert(d
- 1, &va
.objects
);
2223 ti
.tiargs
= dedargs
; // update to the normalized template arguments.
2225 // Partially instantiate function for constraint and fd.leastAsSpecialized()
2227 assert(paramscope
.scopesym
);
2228 Scope
* sc2
= _scope
;
2229 sc2
= sc2
.push(paramscope
.scopesym
);
2233 sc2
.minst
= sc
.minst
;
2234 sc2
.stc |
= fd
.storage_class
& STC
.deprecated_
;
2236 fd
= doHeaderInstantiation(ti
, sc2
, fd
, tthis
, fargs
);
2247 if (!evaluateConstraint(ti
, sc
, paramscope
, dedargs
, fd
))
2253 for (size_t i
= 0; i
< dedargs
.length
; i
++)
2255 RootObject o
= (*dedargs
)[i
];
2256 printf("\tdedargs[%d] = %d, %s\n", i
, o
.dyncast(), o
.toChars());
2261 //printf("\tmatch %d\n", match);
2262 return MATCHpair(matchTiargs
, match
);
2265 /**************************************************
2266 * Declare template parameter tp with value o, and install it in the scope sc.
2268 extern (D
) RootObject
declareParameter(Scope
* sc
, TemplateParameter tp
, RootObject o
)
2270 //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
2271 Type ta
= isType(o
);
2272 Expression ea
= isExpression(o
);
2273 Dsymbol sa
= isDsymbol(o
);
2274 Tuple va
= isTuple(o
);
2277 VarDeclaration v
= null;
2281 if (ea
.op
== EXP
.type
)
2283 else if (auto se
= ea
.isScopeExp())
2285 else if (auto te
= ea
.isThisExp())
2287 else if (auto se
= ea
.isSuperExp())
2289 else if (auto fe
= ea
.isFuncExp())
2300 //printf("type %s\n", ta.toChars());
2301 auto ad
= new AliasDeclaration(Loc
.initial
, tp
.ident
, ta
);
2302 ad
.storage_class |
= STC
.templateparameter
;
2307 //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
2308 auto ad
= new AliasDeclaration(Loc
.initial
, tp
.ident
, sa
);
2309 ad
.storage_class |
= STC
.templateparameter
;
2314 // tdtypes.data[i] always matches ea here
2315 Initializer _init
= new ExpInitializer(loc
, ea
);
2316 TemplateValueParameter tvp
= tp
.isTemplateValueParameter();
2317 Type t
= tvp ? tvp
.valType
: null;
2318 v
= new VarDeclaration(loc
, t
, tp
.ident
, _init
);
2319 v
.storage_class
= STC
.manifest | STC
.templateparameter
;
2324 //printf("\ttuple\n");
2325 d
= new TupleDeclaration(loc
, tp
.ident
, &va
.objects
);
2331 d
.storage_class |
= STC
.templateparameter
;
2336 // consistent with Type.checkDeprecated()
2337 while (t
.ty
!= Tenum
)
2341 t
= (cast(TypeNext
)t
).next
;
2343 if (Dsymbol s
= t
.toDsymbol(sc
))
2345 if (s
.isDeprecated())
2346 d
.storage_class |
= STC
.deprecated_
;
2351 if (sa
.isDeprecated())
2352 d
.storage_class |
= STC
.deprecated_
;
2356 .error(loc
, "%s `%s` declaration `%s` is already defined", kind
, toPrettyChars
, tp
.ident
.toChars());
2357 d
.dsymbolSemantic(sc
);
2358 /* So the caller's o gets updated with the result of semantic() being run on o
2361 o
= v
._init
.initializerToExpression();
2365 /*************************************************
2366 * Limited function template instantiation for using fd.leastAsSpecialized()
2368 extern (D
) FuncDeclaration
doHeaderInstantiation(TemplateInstance ti
, Scope
* sc2
, FuncDeclaration fd
, Type tthis
, Expressions
* fargs
)
2373 printf("doHeaderInstantiation this = %s\n", toChars());
2376 // function body and contracts are not need
2377 if (fd
.isCtorDeclaration())
2378 fd
= new CtorDeclaration(fd
.loc
, fd
.endloc
, fd
.storage_class
, fd
.type
.syntaxCopy());
2380 fd
= new FuncDeclaration(fd
.loc
, fd
.endloc
, fd
.ident
, fd
.storage_class
, fd
.type
.syntaxCopy());
2383 assert(fd
.type
.ty
== Tfunction
);
2384 auto tf
= fd
.type
.isTypeFunction();
2389 // Match 'tthis' to any TemplateThisParameter's
2390 bool hasttp
= false;
2391 foreach (tp
; *parameters
)
2393 TemplateThisParameter ttp
= tp
.isTemplateThisParameter();
2399 tf
= cast(TypeFunction
)tf
.addSTC(ModToStc(tthis
.mod
));
2404 Scope
* scx
= sc2
.push();
2406 // Shouldn't run semantic on default arguments and return type.
2407 foreach (ref params
; *tf
.parameterList
.parameters
)
2408 params
.defaultArg
= null;
2409 tf
.incomplete
= true;
2411 if (fd
.isCtorDeclaration())
2413 // For constructors, emitting return type is necessary for
2414 // isReturnIsolated() in functionResolve.
2417 Dsymbol parent
= toParentDecl();
2419 AggregateDeclaration ad
= parent
.isAggregateDeclaration();
2420 if (!ad || parent
.isUnionDeclaration())
2426 tret
= ad
.handleType();
2428 tret
= tret
.addStorageClass(fd
.storage_class | scx
.stc);
2429 tret
= tret
.addMod(tf
.mod
);
2432 if (ad
&& ad
.isStructDeclaration())
2434 //printf("tf = %s\n", tf.toChars());
2439 fd
.type
= fd
.type
.addSTC(scx
.stc);
2440 fd
.type
= fd
.type
.typeSemantic(fd
.loc
, scx
);
2443 if (fd
.type
.ty
!= Tfunction
)
2446 fd
.originalType
= fd
.type
; // for mangling
2447 //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
2448 //printf("fd.needThis() = %d\n", fd.needThis());
2453 debug (FindExistingInstance
)
2455 __gshared
uint nFound
, nNotFound
, nAdded
, nRemoved
;
2457 shared static ~this()
2459 printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
2460 nFound
, nNotFound
, nAdded
, nRemoved
);
2464 /****************************************************
2465 * Given a new instance tithis of this TemplateDeclaration,
2466 * see if there already exists an instance.
2467 * If so, return that existing instance.
2469 extern (D
) TemplateInstance
findExistingInstance(TemplateInstance tithis
, Expressions
* fargs
)
2471 //printf("findExistingInstance() %s\n", tithis.toChars());
2472 tithis
.fargs
= fargs
;
2473 auto tibox
= TemplateInstanceBox(tithis
);
2474 auto p
= tibox
in instances
;
2475 debug (FindExistingInstance
) ++(p ? nFound
: nNotFound
);
2476 //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
2477 return p ?
*p
: null;
2480 /********************************************
2481 * Add instance ti to TemplateDeclaration's table of instances.
2482 * Return a handle we can use to later remove it if it fails instantiation.
2484 extern (D
) TemplateInstance
addInstance(TemplateInstance ti
)
2486 //printf("addInstance() %p %s\n", instances, ti.toChars());
2487 auto tibox
= TemplateInstanceBox(ti
);
2488 instances
[tibox
] = ti
;
2489 debug (FindExistingInstance
) ++nAdded
;
2493 /*******************************************
2494 * Remove TemplateInstance from table of instances.
2496 * handle returned by addInstance()
2498 extern (D
) void removeInstance(TemplateInstance ti
)
2500 //printf("removeInstance() %s\n", ti.toChars());
2501 auto tibox
= TemplateInstanceBox(ti
);
2502 debug (FindExistingInstance
) ++nRemoved
;
2503 instances
.remove(tibox
);
2506 override inout(TemplateDeclaration
) isTemplateDeclaration() inout
2512 * Check if the last template parameter is a tuple one,
2513 * and returns it if so, else returns `null`.
2516 * The last template parameter if it's a `TemplateTupleParameter`
2518 extern (D
) TemplateTupleParameter
isVariadic()
2520 size_t dim
= parameters
.length
;
2523 return (*parameters
)[dim
- 1].isTemplateTupleParameter();
2526 extern(C
++) override bool isDeprecated() const
2528 return this.deprecated_
;
2531 /***********************************
2532 * We can overload templates.
2534 override bool isOverloadable() const
2539 override void accept(Visitor v
)
2545 extern (C
++) final class TypeDeduced
: Type
2548 Expressions argexps
; // corresponding expressions
2549 Types tparams
; // tparams[i].mod
2551 extern (D
) this(Type tt
, Expression e
, Type tparam
)
2556 tparams
.push(tparam
);
2559 void update(Expression e
, Type tparam
)
2562 tparams
.push(tparam
);
2565 void update(Type tt
, Expression e
, Type tparam
)
2569 tparams
.push(tparam
);
2572 MATCH
matchAll(Type tt
)
2574 MATCH match
= MATCH
.exact
;
2575 foreach (j
, e
; argexps
)
2578 if (e
== emptyArrayElement
)
2581 Type t
= tt
.addMod(tparams
[j
].mod
).substWildTo(MODFlags
.const_
);
2583 MATCH m
= e
.implicitConvTo(t
);
2586 if (match
== MATCH
.nomatch
)
2594 /*************************************************
2595 * Given function arguments, figure out which template function
2596 * to expand, and return matching result.
2598 * m = matching result
2599 * dstart = the root of overloaded function templates
2600 * loc = instantiation location
2601 * sc = instantiation scope
2602 * tiargs = initial list of template arguments
2603 * tthis = if !NULL, the 'this' pointer argument
2604 * argumentList= arguments to function
2605 * pMessage = address to store error message, or null
2607 void functionResolve(ref MatchAccumulator m
, Dsymbol dstart
, Loc loc
, Scope
* sc
, Objects
* tiargs
,
2608 Type tthis
, ArgumentList argumentList
, const(char)** pMessage
= null)
2612 printf("functionResolve() dstart = %s\n", dstart
.toChars());
2613 printf(" tiargs:\n");
2616 for (size_t i
= 0; i
< tiargs
.length
; i
++)
2618 RootObject arg
= (*tiargs
)[i
];
2619 printf("\t%s\n", arg
.toChars());
2622 printf(" fargs:\n");
2623 for (size_t i
= 0; i
< (fargs ? fargs
.length
: 0); i
++)
2625 Expression arg
= (*fargs
)[i
];
2626 printf("\t%s %s\n", arg
.type
.toChars(), arg
.toChars());
2627 //printf("\tty = %d\n", arg.type.ty);
2629 //printf("stc = %llx\n", dstart._scope.stc);
2630 //printf("match:t/f = %d/%d\n", ta_last, m.last);
2634 int property
= 0; // 0: uninitialized
2635 // 1: seen @property
2637 size_t ov_index
= 0;
2638 TemplateDeclaration td_best
;
2639 TemplateInstance ti_best
;
2640 MATCH ta_last
= m
.last
!= MATCH
.nomatch ? MATCH
.exact
: MATCH
.nomatch
;
2643 int applyFunction(FuncDeclaration fd
)
2648 // explicitly specified tiargs never match to non template function
2649 if (tiargs
&& tiargs
.length
> 0)
2652 // constructors need a valid scope in order to detect semantic errors
2653 if (!fd
.isCtorDeclaration
&&
2654 fd
.semanticRun
< PASS
.semanticdone
)
2656 Ungag ungag
= fd
.ungagSpeculative();
2657 fd
.dsymbolSemantic(null);
2659 if (fd
.semanticRun
< PASS
.semanticdone
)
2661 .error(loc
, "forward reference to template `%s`", fd
.toChars());
2664 //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
2665 auto tf
= cast(TypeFunction
)fd
.type
;
2667 int prop
= tf
.isproperty ?
1 : 2;
2670 else if (property
!= prop
)
2671 error(fd
.loc
, "cannot overload both property and non-property functions");
2673 /* For constructors, qualifier check will be opposite direction.
2674 * Qualified constructor always makes qualified object, then will be checked
2675 * that it is implicitly convertible to tthis.
2677 Type tthis_fd
= fd
.needThis() ? tthis
: null;
2678 bool isCtorCall
= tthis_fd
&& fd
.isCtorDeclaration();
2681 //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
2682 // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
2683 if (MODimplicitConv(tf
.mod
, tthis_fd
.mod
) ||
2684 tf
.isWild() && tf
.isShared() == tthis_fd
.isShared() ||
2685 fd
.isReturnIsolated())
2687 /* && tf.isShared() == tthis_fd.isShared()*/
2688 // Uniquely constructed object can ignore shared qualifier.
2689 // TODO: Is this appropriate?
2693 return 0; // MATCH.nomatch
2696 If a struct is declared as shared the dtor is automatically
2697 considered to be shared, but when the struct is instantiated
2698 the instance is no longer considered to be shared when the
2699 function call matching is done. The fix makes it so that if a
2700 struct declaration is shared, when the destructor is called,
2701 the instantiated struct is also considered shared.
2703 if (auto dt = fd
.isDtorDeclaration())
2705 auto dtmod
= dt.type
.toTypeFunction();
2706 auto shared_dtor
= dtmod
.mod
& MODFlags
.shared_
;
2707 auto shared_this
= tthis_fd
!is null ?
2708 tthis_fd
.mod
& MODFlags
.shared_
: 0;
2709 if (shared_dtor
&& !shared_this
)
2711 else if (shared_this
&& !shared_dtor
&& tthis_fd
!is null)
2712 tf
.mod
= tthis_fd
.mod
;
2714 MATCH mfa
= tf
.callMatch(tthis_fd
, argumentList
, 0, pMessage
, sc
);
2715 //printf("test1: mfa = %d\n", mfa);
2716 if (mfa
== MATCH
.nomatch
)
2723 ta_last
= MATCH
.exact
;
2726 tthis_best
= tthis_fd
;
2732 if (mfa
> m
.last
) return firstIsBetter();
2733 if (mfa
< m
.last
) return 0;
2735 /* See if one of the matches overrides the other.
2738 if (m
.lastf
.overrides(fd
)) return 0;
2739 if (fd
.overrides(m
.lastf
)) return firstIsBetter();
2741 /* Try to disambiguate using template-style partial ordering rules.
2742 * In essence, if f() and g() are ambiguous, if f() can call g(),
2743 * but g() cannot call f(), then pick f().
2744 * This is because f() is "more specialized."
2747 MATCH c1
= fd
.leastAsSpecialized(m
.lastf
, argumentList
.names
);
2748 MATCH c2
= m
.lastf
.leastAsSpecialized(fd
, argumentList
.names
);
2749 //printf("c1 = %d, c2 = %d\n", c1, c2);
2750 if (c1
> c2
) return firstIsBetter();
2751 if (c1
< c2
) return 0;
2754 /* The 'overrides' check above does covariant checking only
2755 * for virtual member functions. It should do it for all functions,
2756 * but in order to not risk breaking code we put it after
2757 * the 'leastAsSpecialized' check.
2758 * In the future try moving it before.
2759 * I.e. a not-the-same-but-covariant match is preferred,
2760 * as it is more restrictive.
2762 if (!m
.lastf
.type
.equals(fd
.type
))
2764 //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
2765 const lastCovariant
= m
.lastf
.type
.covariant(fd
.type
);
2766 const firstCovariant
= fd
.type
.covariant(m
.lastf
.type
);
2768 if (lastCovariant
== Covariant
.yes || lastCovariant
== Covariant
.no
)
2770 if (firstCovariant
!= Covariant
.yes
&& firstCovariant
!= Covariant
.no
)
2775 else if (firstCovariant
== Covariant
.yes || firstCovariant
== Covariant
.no
)
2777 return firstIsBetter();
2781 /* If the two functions are the same function, like:
2783 * int foo(int x) { ... }
2784 * then pick the one with the body.
2786 * If none has a body then don't care because the same
2787 * real function would be linked to the decl (e.g from object file)
2789 if (tf
.equals(m
.lastf
.type
) &&
2790 fd
.storage_class
== m
.lastf
.storage_class
&&
2791 fd
.parent
== m
.lastf
.parent
&&
2792 fd
.visibility
== m
.lastf
.visibility
&&
2793 fd
._linkage
== m
.lastf
._linkage
)
2795 if (fd
.fbody
&& !m
.lastf
.fbody
)
2796 return firstIsBetter();
2801 // https://issues.dlang.org/show_bug.cgi?id=14450
2802 // Prefer exact qualified constructor for the creating object type
2803 if (isCtorCall
&& tf
.mod
!= m
.lastf
.type
.mod
)
2805 if (tthis
.mod
== tf
.mod
) return firstIsBetter();
2806 if (tthis
.mod
== m
.lastf
.type
.mod
) return 0;
2814 int applyTemplate(TemplateDeclaration td
)
2816 //printf("applyTemplate(): td = %s\n", td.toChars());
2817 if (td
== td_best
) // skip duplicates
2821 sc
= td
._scope
; // workaround for Type.aliasthisOf
2823 if (td
.semanticRun
== PASS
.initial
&& td
._scope
)
2825 // Try to fix forward reference. Ungag errors while doing so.
2826 Ungag ungag
= td
.ungagSpeculative();
2827 td
.dsymbolSemantic(td
._scope
);
2829 if (td
.semanticRun
== PASS
.initial
)
2831 .error(loc
, "forward reference to template `%s`", td
.toChars());
2835 m
.last
= MATCH
.nomatch
;
2838 //printf("td = %s\n", td.toChars());
2840 if (argumentList
.hasNames
)
2842 .error(loc
, "named arguments with Implicit Function Template Instantiation are not supported yet");
2845 auto f
= td
.onemember ? td
.onemember
.isFuncDeclaration() : null;
2849 tiargs
= new Objects();
2850 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
2851 Objects dedtypes
= Objects(td
.parameters
.length
);
2852 assert(td
.semanticRun
!= PASS
.initial
);
2853 MATCH mta
= td
.matchWithInstance(sc
, ti
, &dedtypes
, argumentList
, 0);
2854 //printf("matchWithInstance = %d\n", mta);
2855 if (mta
== MATCH
.nomatch || mta
< ta_last
) // no match or less match
2858 ti
.templateInstanceSemantic(sc
, argumentList
);
2859 if (!ti
.inst
) // if template failed to expand
2862 Dsymbol s
= ti
.inst
.toAlias();
2864 if (auto tdx
= s
.isTemplateDeclaration())
2866 Objects dedtypesX
; // empty tiargs
2868 // https://issues.dlang.org/show_bug.cgi?id=11553
2869 // Check for recursive instantiation of tdx.
2870 for (TemplatePrevious
* p
= tdx
.previous
; p
; p
= p
.prev
)
2872 if (arrayObjectMatch(p
.dedargs
, &dedtypesX
))
2874 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
2875 /* It must be a subscope of p.sc, other scope chains are not recursive
2878 for (Scope
* scx
= sc
; scx
; scx
= scx
.enclosing
)
2882 error(loc
, "recursive template expansion while looking for `%s.%s`", ti
.toChars(), tdx
.toChars());
2887 /* BUG: should also check for ref param differences
2891 TemplatePrevious pr
;
2892 pr
.prev
= tdx
.previous
;
2894 pr
.dedargs
= &dedtypesX
;
2895 tdx
.previous
= &pr
; // add this to threaded list
2897 fd
= resolveFuncCall(loc
, sc
, s
, null, tthis
, argumentList
, FuncResolveFlag
.quiet
);
2899 tdx
.previous
= pr
.prev
; // unlink from threaded list
2901 else if (s
.isFuncDeclaration())
2903 fd
= resolveFuncCall(loc
, sc
, s
, null, tthis
, argumentList
, FuncResolveFlag
.quiet
);
2911 if (fd
.type
.ty
!= Tfunction
)
2913 m
.lastf
= fd
; // to propagate "error match"
2915 m
.last
= MATCH
.nomatch
;
2919 Type tthis_fd
= fd
.needThis() && !fd
.isCtorDeclaration() ? tthis
: null;
2921 auto tf
= cast(TypeFunction
)fd
.type
;
2922 MATCH mfa
= tf
.callMatch(tthis_fd
, argumentList
, 0, null, sc
);
2926 if (mta
< ta_last
) goto Ltd_best2
;
2927 if (mta
> ta_last
) goto Ltd2
;
2929 if (mfa
< m
.last
) goto Ltd_best2
;
2930 if (mfa
> m
.last
) goto Ltd2
;
2932 // td_best and td are ambiguous
2933 //printf("Lambig2\n");
2942 // td is the new best match
2946 property
= 0; // (backward compatibility)
2950 tthis_best
= tthis_fd
;
2957 //printf("td = %s\n", td.toChars());
2958 for (size_t ovi
= 0; f
; f
= f
.overnext0
, ovi
++)
2960 if (f
.type
.ty
!= Tfunction || f
.errors
)
2963 /* This is a 'dummy' instance to evaluate constraint properly.
2965 auto ti
= new TemplateInstance(loc
, td
, tiargs
);
2966 ti
.parent
= td
.parent
; // Maybe calculating valid 'enclosing' is unnecessary.
2969 MATCHpair x
= td
.deduceFunctionTemplateMatch(ti
, sc
, fd
, tthis
, argumentList
);
2972 //printf("match:t/f = %d/%d\n", mta, mfa);
2973 if (!fd || mfa
== MATCH
.nomatch
)
2976 Type tthis_fd
= fd
.needThis() ? tthis
: null;
2978 bool isCtorCall
= tthis_fd
&& fd
.isCtorDeclaration();
2981 // Constructor call requires additional check.
2982 auto tf
= cast(TypeFunction
)fd
.type
;
2984 if (MODimplicitConv(tf
.mod
, tthis_fd
.mod
) ||
2985 tf
.isWild() && tf
.isShared() == tthis_fd
.isShared() ||
2986 fd
.isReturnIsolated())
2991 continue; // MATCH.nomatch
2993 // need to check here whether the constructor is the member of a struct
2994 // declaration that defines a copy constructor. This is already checked
2995 // in the semantic of CtorDeclaration, however, when matching functions,
2996 // the template instance is not expanded.
2997 // https://issues.dlang.org/show_bug.cgi?id=21613
2998 auto ad
= fd
.isThis();
2999 auto sd
= ad
.isStructDeclaration();
3000 if (checkHasBothRvalueAndCpCtor(sd
, fd
.isCtorDeclaration(), ti
))
3004 if (mta
< ta_last
) goto Ltd_best
;
3005 if (mta
> ta_last
) goto Ltd
;
3007 if (mfa
< m
.last
) goto Ltd_best
;
3008 if (mfa
> m
.last
) goto Ltd
;
3012 // Disambiguate by picking the most specialized TemplateDeclaration
3013 MATCH c1
= td
.leastAsSpecialized(sc
, td_best
, argumentList
);
3014 MATCH c2
= td_best
.leastAsSpecialized(sc
, td
, argumentList
);
3015 //printf("1: c1 = %d, c2 = %d\n", c1, c2);
3016 if (c1
> c2
) goto Ltd
;
3017 if (c1
< c2
) goto Ltd_best
;
3019 assert(fd
&& m
.lastf
);
3021 // Disambiguate by tf.callMatch
3022 auto tf1
= fd
.type
.isTypeFunction();
3023 auto tf2
= m
.lastf
.type
.isTypeFunction();
3024 MATCH c1
= tf1
.callMatch(tthis_fd
, argumentList
, 0, null, sc
);
3025 MATCH c2
= tf2
.callMatch(tthis_best
, argumentList
, 0, null, sc
);
3026 //printf("2: c1 = %d, c2 = %d\n", c1, c2);
3027 if (c1
> c2
) goto Ltd
;
3028 if (c1
< c2
) goto Ltd_best
;
3031 // Disambiguate by picking the most specialized FunctionDeclaration
3032 MATCH c1
= fd
.leastAsSpecialized(m
.lastf
, argumentList
.names
);
3033 MATCH c2
= m
.lastf
.leastAsSpecialized(fd
, argumentList
.names
);
3034 //printf("3: c1 = %d, c2 = %d\n", c1, c2);
3035 if (c1
> c2
) goto Ltd
;
3036 if (c1
< c2
) goto Ltd_best
;
3039 // https://issues.dlang.org/show_bug.cgi?id=14450
3040 // Prefer exact qualified constructor for the creating object type
3041 if (isCtorCall
&& fd
.type
.mod
!= m
.lastf
.type
.mod
)
3043 if (tthis
.mod
== fd
.type
.mod
) goto Ltd
;
3044 if (tthis
.mod
== m
.lastf
.type
.mod
) goto Ltd_best
;
3051 Ltd_best
: // td_best is the best match so far
3052 //printf("Ltd_best\n");
3055 Ltd
: // td is the new best match
3060 property
= 0; // (backward compatibility)
3064 tthis_best
= tthis_fd
;
3073 auto td
= dstart
.isTemplateDeclaration();
3074 if (td
&& td
.funcroot
)
3075 dstart
= td
.funcroot
;
3076 overloadApply(dstart
, (Dsymbol s
)
3080 if (auto fd
= s
.isFuncDeclaration())
3081 return applyFunction(fd
);
3082 if (auto td
= s
.isTemplateDeclaration())
3083 return applyTemplate(td
);
3087 //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf);
3088 if (td_best
&& ti_best
&& m
.count
== 1)
3090 // Matches to template function
3091 assert(td_best
.onemember
&& td_best
.onemember
.isFuncDeclaration());
3092 /* The best match is td_best with arguments tdargs.
3093 * Now instantiate the template.
3095 assert(td_best
._scope
);
3097 sc
= td_best
._scope
; // workaround for Type.aliasthisOf
3099 auto ti
= new TemplateInstance(loc
, td_best
, ti_best
.tiargs
);
3100 ti
.templateInstanceSemantic(sc
, argumentList
);
3102 m
.lastf
= ti
.toAlias().isFuncDeclaration();
3110 m
.last
= MATCH
.nomatch
;
3114 // look forward instantiated overload function
3115 // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
3116 // it has filled overnext0d
3119 m
.lastf
= m
.lastf
.overnext0
;
3123 tthis_best
= m
.lastf
.needThis() && !m
.lastf
.isCtorDeclaration() ? tthis
: null;
3125 if (m
.lastf
.type
.ty
== Terror
)
3127 auto tf
= m
.lastf
.type
.isTypeFunction();
3128 if (!tf
.callMatch(tthis_best
, argumentList
, 0, null, sc
))
3131 /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
3132 * a template instance can be matched while instantiating
3133 * that same template. Thus, the function type can be incomplete. Complete it.
3135 * https://issues.dlang.org/show_bug.cgi?id=9208
3136 * For auto function, completion should be deferred to the end of
3137 * its semantic3. Should not complete it in here.
3139 if (tf
.next
&& !m
.lastf
.inferRetType
)
3141 m
.lastf
.type
= tf
.typeSemantic(loc
, sc
);
3146 // Matches to non template function,
3147 // or found matches were ambiguous.
3148 assert(m
.count
>= 1);
3155 m
.last
= MATCH
.nomatch
;
3159 /* ======================== Type ============================================ */
3162 * Given an identifier, figure out which TemplateParameter it is.
3163 * Return IDX_NOTFOUND if not found.
3165 private size_t
templateIdentifierLookup(Identifier id
, TemplateParameters
* parameters
)
3167 for (size_t i
= 0; i
< parameters
.length
; i
++)
3169 TemplateParameter tp
= (*parameters
)[i
];
3170 if (tp
.ident
.equals(id
))
3173 return IDX_NOTFOUND
;
3176 private size_t
templateParameterLookup(Type tparam
, TemplateParameters
* parameters
)
3178 if (tparam
.ty
== Tident
)
3180 TypeIdentifier tident
= cast(TypeIdentifier
)tparam
;
3181 //printf("\ttident = '%s'\n", tident.toChars());
3182 return templateIdentifierLookup(tident
.ident
, parameters
);
3184 return IDX_NOTFOUND
;
3187 private ubyte deduceWildHelper(Type t
, Type
* at
, Type tparam
)
3189 if ((tparam
.mod
& MODFlags
.wild
) == 0)
3194 auto X(T
, U
)(T U
, U T
)
3196 return (U
<< 4) | T
;
3199 switch (X(tparam
.mod
, t
.mod
))
3201 case X(MODFlags
.wild
, 0):
3202 case X(MODFlags
.wild
, MODFlags
.const_
):
3203 case X(MODFlags
.wild
, MODFlags
.shared_
):
3204 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3205 case X(MODFlags
.wild
, MODFlags
.immutable_
):
3206 case X(MODFlags
.wildconst
, 0):
3207 case X(MODFlags
.wildconst
, MODFlags
.const_
):
3208 case X(MODFlags
.wildconst
, MODFlags
.shared_
):
3209 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3210 case X(MODFlags
.wildconst
, MODFlags
.immutable_
):
3211 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_
):
3212 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3213 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.immutable_
):
3214 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_
):
3215 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3216 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.immutable_
):
3218 ubyte wm
= (t
.mod
& ~MODFlags
.shared_
);
3220 wm
= MODFlags
.mutable
;
3221 ubyte m
= (t
.mod
& (MODFlags
.const_ | MODFlags
.immutable_
)) |
(tparam
.mod
& t
.mod
& MODFlags
.shared_
);
3222 *at
= t
.unqualify(m
);
3225 case X(MODFlags
.wild
, MODFlags
.wild
):
3226 case X(MODFlags
.wild
, MODFlags
.wildconst
):
3227 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3228 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3229 case X(MODFlags
.wildconst
, MODFlags
.wild
):
3230 case X(MODFlags
.wildconst
, MODFlags
.wildconst
):
3231 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3232 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3233 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3234 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3235 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3236 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3238 *at
= t
.unqualify(tparam
.mod
& t
.mod
);
3239 return MODFlags
.wild
;
3247 * Returns the common type of the 2 types.
3249 private Type
rawTypeMerge(Type t1
, Type t2
)
3253 if (t1
.equivalent(t2
))
3254 return t1
.castMod(MODmerge(t1
.mod
, t2
.mod
));
3256 auto t1b
= t1
.toBasetype();
3257 auto t2b
= t2
.toBasetype();
3258 if (t1b
.equals(t2b
))
3260 if (t1b
.equivalent(t2b
))
3261 return t1b
.castMod(MODmerge(t1b
.mod
, t2b
.mod
));
3263 auto ty
= implicitConvCommonTy(t1b
.ty
, t2b
.ty
);
3265 return Type
.basic
[ty
];
3270 private MATCH
deduceTypeHelper(Type t
, Type
* at
, Type tparam
)
3274 auto X(T
, U
)(T U
, U T
)
3276 return (U
<< 4) | T
;
3279 switch (X(tparam
.mod
, t
.mod
))
3282 case X(0, MODFlags
.const_
):
3283 case X(0, MODFlags
.wild
):
3284 case X(0, MODFlags
.wildconst
):
3285 case X(0, MODFlags
.shared_
):
3286 case X(0, MODFlags
.shared_ | MODFlags
.const_
):
3287 case X(0, MODFlags
.shared_ | MODFlags
.wild
):
3288 case X(0, MODFlags
.shared_ | MODFlags
.wildconst
):
3289 case X(0, MODFlags
.immutable_
):
3291 // foo(U) const(T) => const(T)
3292 // foo(U) inout(T) => inout(T)
3293 // foo(U) inout(const(T)) => inout(const(T))
3294 // foo(U) shared(T) => shared(T)
3295 // foo(U) shared(const(T)) => shared(const(T))
3296 // foo(U) shared(inout(T)) => shared(inout(T))
3297 // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
3298 // foo(U) immutable(T) => immutable(T)
3303 case X(MODFlags
.const_
, MODFlags
.const_
):
3304 case X(MODFlags
.wild
, MODFlags
.wild
):
3305 case X(MODFlags
.wildconst
, MODFlags
.wildconst
):
3306 case X(MODFlags
.shared_
, MODFlags
.shared_
):
3307 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.const_
):
3308 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3309 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3310 case X(MODFlags
.immutable_
, MODFlags
.immutable_
):
3311 // foo(const(U)) const(T) => T
3312 // foo(inout(U)) inout(T) => T
3313 // foo(inout(const(U))) inout(const(T)) => T
3314 // foo(shared(U)) shared(T) => T
3315 // foo(shared(const(U))) shared(const(T)) => T
3316 // foo(shared(inout(U))) shared(inout(T)) => T
3317 // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
3318 // foo(immutable(U)) immutable(T) => T
3320 *at
= t
.mutableOf().unSharedOf();
3323 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.const_
):
3324 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wild
):
3325 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wildconst
):
3326 // foo(const(U)) shared(const(T)) => shared(T)
3327 // foo(inout(U)) shared(inout(T)) => shared(T)
3328 // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
3330 *at
= t
.mutableOf();
3333 case X(MODFlags
.const_
, 0):
3334 case X(MODFlags
.const_
, MODFlags
.wild
):
3335 case X(MODFlags
.const_
, MODFlags
.wildconst
):
3336 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wild
):
3337 case X(MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3338 case X(MODFlags
.const_
, MODFlags
.immutable_
):
3339 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.immutable_
):
3340 // foo(const(U)) T => T
3341 // foo(const(U)) inout(T) => T
3342 // foo(const(U)) inout(const(T)) => T
3343 // foo(const(U)) shared(inout(T)) => shared(T)
3344 // foo(const(U)) shared(inout(const(T))) => shared(T)
3345 // foo(const(U)) immutable(T) => T
3346 // foo(shared(const(U))) immutable(T) => T
3348 *at
= t
.mutableOf();
3349 return MATCH
.constant
;
3351 case X(MODFlags
.const_
, MODFlags
.shared_
):
3352 // foo(const(U)) shared(T) => shared(T)
3355 return MATCH
.constant
;
3357 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.const_
):
3358 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.wild
):
3359 case X(MODFlags
.shared_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3360 // foo(shared(U)) shared(const(T)) => const(T)
3361 // foo(shared(U)) shared(inout(T)) => inout(T)
3362 // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
3364 *at
= t
.unSharedOf();
3367 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_
):
3368 // foo(shared(const(U))) shared(T) => T
3370 *at
= t
.unSharedOf();
3371 return MATCH
.constant
;
3373 case X(MODFlags
.wildconst
, MODFlags
.immutable_
):
3374 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3375 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.immutable_
):
3376 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3377 // foo(inout(const(U))) immutable(T) => T
3378 // foo(shared(const(U))) shared(inout(const(T))) => T
3379 // foo(shared(inout(const(U)))) immutable(T) => T
3380 // foo(shared(inout(const(U)))) shared(inout(T)) => T
3382 *at
= t
.unSharedOf().mutableOf();
3383 return MATCH
.constant
;
3385 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.shared_ | MODFlags
.wild
):
3386 // foo(shared(const(U))) shared(inout(T)) => T
3388 *at
= t
.unSharedOf().mutableOf();
3389 return MATCH
.constant
;
3391 case X(MODFlags
.wild
, 0):
3392 case X(MODFlags
.wild
, MODFlags
.const_
):
3393 case X(MODFlags
.wild
, MODFlags
.wildconst
):
3394 case X(MODFlags
.wild
, MODFlags
.immutable_
):
3395 case X(MODFlags
.wild
, MODFlags
.shared_
):
3396 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3397 case X(MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3398 case X(MODFlags
.wildconst
, 0):
3399 case X(MODFlags
.wildconst
, MODFlags
.const_
):
3400 case X(MODFlags
.wildconst
, MODFlags
.wild
):
3401 case X(MODFlags
.wildconst
, MODFlags
.shared_
):
3402 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3403 case X(MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.wild
):
3404 case X(MODFlags
.shared_
, 0):
3405 case X(MODFlags
.shared_
, MODFlags
.const_
):
3406 case X(MODFlags
.shared_
, MODFlags
.wild
):
3407 case X(MODFlags
.shared_
, MODFlags
.wildconst
):
3408 case X(MODFlags
.shared_
, MODFlags
.immutable_
):
3409 case X(MODFlags
.shared_ | MODFlags
.const_
, 0):
3410 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.const_
):
3411 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.wild
):
3412 case X(MODFlags
.shared_ | MODFlags
.const_
, MODFlags
.wildconst
):
3413 case X(MODFlags
.shared_ | MODFlags
.wild
, 0):
3414 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.const_
):
3415 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.wild
):
3416 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.wildconst
):
3417 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.immutable_
):
3418 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_
):
3419 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.const_
):
3420 case X(MODFlags
.shared_ | MODFlags
.wild
, MODFlags
.shared_ | MODFlags
.wildconst
):
3421 case X(MODFlags
.shared_ | MODFlags
.wildconst
, 0):
3422 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.const_
):
3423 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.wild
):
3424 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.wildconst
):
3425 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_
):
3426 case X(MODFlags
.shared_ | MODFlags
.wildconst
, MODFlags
.shared_ | MODFlags
.const_
):
3427 case X(MODFlags
.immutable_
, 0):
3428 case X(MODFlags
.immutable_
, MODFlags
.const_
):
3429 case X(MODFlags
.immutable_
, MODFlags
.wild
):
3430 case X(MODFlags
.immutable_
, MODFlags
.wildconst
):
3431 case X(MODFlags
.immutable_
, MODFlags
.shared_
):
3432 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.const_
):
3433 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.wild
):
3434 case X(MODFlags
.immutable_
, MODFlags
.shared_ | MODFlags
.wildconst
):
3435 // foo(inout(U)) T => nomatch
3436 // foo(inout(U)) const(T) => nomatch
3437 // foo(inout(U)) inout(const(T)) => nomatch
3438 // foo(inout(U)) immutable(T) => nomatch
3439 // foo(inout(U)) shared(T) => nomatch
3440 // foo(inout(U)) shared(const(T)) => nomatch
3441 // foo(inout(U)) shared(inout(const(T))) => nomatch
3442 // foo(inout(const(U))) T => nomatch
3443 // foo(inout(const(U))) const(T) => nomatch
3444 // foo(inout(const(U))) inout(T) => nomatch
3445 // foo(inout(const(U))) shared(T) => nomatch
3446 // foo(inout(const(U))) shared(const(T)) => nomatch
3447 // foo(inout(const(U))) shared(inout(T)) => nomatch
3448 // foo(shared(U)) T => nomatch
3449 // foo(shared(U)) const(T) => nomatch
3450 // foo(shared(U)) inout(T) => nomatch
3451 // foo(shared(U)) inout(const(T)) => nomatch
3452 // foo(shared(U)) immutable(T) => nomatch
3453 // foo(shared(const(U))) T => nomatch
3454 // foo(shared(const(U))) const(T) => nomatch
3455 // foo(shared(const(U))) inout(T) => nomatch
3456 // foo(shared(const(U))) inout(const(T)) => nomatch
3457 // foo(shared(inout(U))) T => nomatch
3458 // foo(shared(inout(U))) const(T) => nomatch
3459 // foo(shared(inout(U))) inout(T) => nomatch
3460 // foo(shared(inout(U))) inout(const(T)) => nomatch
3461 // foo(shared(inout(U))) immutable(T) => nomatch
3462 // foo(shared(inout(U))) shared(T) => nomatch
3463 // foo(shared(inout(U))) shared(const(T)) => nomatch
3464 // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
3465 // foo(shared(inout(const(U)))) T => nomatch
3466 // foo(shared(inout(const(U)))) const(T) => nomatch
3467 // foo(shared(inout(const(U)))) inout(T) => nomatch
3468 // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
3469 // foo(shared(inout(const(U)))) shared(T) => nomatch
3470 // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
3471 // foo(immutable(U)) T => nomatch
3472 // foo(immutable(U)) const(T) => nomatch
3473 // foo(immutable(U)) inout(T) => nomatch
3474 // foo(immutable(U)) inout(const(T)) => nomatch
3475 // foo(immutable(U)) shared(T) => nomatch
3476 // foo(immutable(U)) shared(const(T)) => nomatch
3477 // foo(immutable(U)) shared(inout(T)) => nomatch
3478 // foo(immutable(U)) shared(inout(const(T))) => nomatch
3479 return MATCH
.nomatch
;
3486 __gshared Expression emptyArrayElement
= null;
3488 /* These form the heart of template argument deduction.
3489 * Given 'this' being the type argument to the template instance,
3490 * it is matched against the template declaration parameter specialization
3491 * 'tparam' to determine the type to be used for the parameter.
3493 * template Foo(T:T*) // template declaration
3494 * Foo!(int*) // template instantiation
3498 * parameters = [ T:T* ] // Array of TemplateParameter's
3500 * dedtypes = [ int ] // Array of Expression/Type's
3502 MATCH
deduceType(RootObject o
, Scope
* sc
, Type tparam
, TemplateParameters
* parameters
, Objects
* dedtypes
, uint* wm
= null, size_t inferStart
= 0, bool ignoreAliasThis
= false)
3504 extern (C
++) final class DeduceType
: Visitor
3506 alias visit
= Visitor
.visit
;
3510 TemplateParameters
* parameters
;
3514 bool ignoreAliasThis
;
3517 extern (D
) this(Scope
* sc
, Type tparam
, TemplateParameters
* parameters
, Objects
* dedtypes
, uint* wm
, size_t inferStart
, bool ignoreAliasThis
) @safe
3520 this.tparam
= tparam
;
3521 this.parameters
= parameters
;
3522 this.dedtypes
= dedtypes
;
3524 this.inferStart
= inferStart
;
3525 this.ignoreAliasThis
= ignoreAliasThis
;
3526 result
= MATCH
.nomatch
;
3529 override void visit(Type t
)
3537 if (tparam
.ty
== Tident
)
3539 // Determine which parameter tparam is
3540 size_t i
= templateParameterLookup(tparam
, parameters
);
3541 if (i
== IDX_NOTFOUND
)
3546 /* Need a loc to go with the semantic routine.
3549 if (parameters
.length
)
3551 TemplateParameter tp
= (*parameters
)[0];
3555 /* BUG: what if tparam is a template instance, that
3556 * has as an argument another Tident?
3558 tparam
= tparam
.typeSemantic(loc
, sc
);
3559 assert(tparam
.ty
!= Tident
);
3560 result
= deduceType(t
, sc
, tparam
, parameters
, dedtypes
, wm
);
3564 TemplateParameter tp
= (*parameters
)[i
];
3566 TypeIdentifier tident
= cast(TypeIdentifier
)tparam
;
3567 if (tident
.idents
.length
> 0)
3569 //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
3570 Dsymbol s
= t
.toDsymbol(sc
);
3571 for (size_t j
= tident
.idents
.length
; j
-- > 0;)
3573 RootObject id
= tident
.idents
[j
];
3574 if (id
.dyncast() == DYNCAST
.identifier
)
3576 if (!s ||
!s
.parent
)
3578 Dsymbol s2
= s
.parent
.search(Loc
.initial
, cast(Identifier
)id
);
3582 //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
3585 if (Type tx
= s2
.getType())
3587 if (s
!= tx
.toDsymbol(sc
))
3598 //printf("[e] s = %s\n", s?s.toChars():"(null)");
3599 if (tp
.isTemplateTypeParameter())
3601 Type tt
= s
.getType();
3604 Type at
= cast(Type
)(*dedtypes
)[i
];
3605 if (at
&& at
.ty
== Tnone
)
3606 at
= (cast(TypeDeduced
)at
).tded
;
3607 if (!at || tt
.equals(at
))
3609 (*dedtypes
)[i
] = tt
;
3613 if (tp
.isTemplateAliasParameter())
3615 Dsymbol s2
= cast(Dsymbol
)(*dedtypes
)[i
];
3625 // Found the corresponding parameter tp
3627 https://issues.dlang.org/show_bug.cgi?id=23578
3629 static if (is(S!int == S!av, alias av))
3631 We eventually need to deduce `int` (Tint32 [0]) and `av` (Tident).
3632 Previously this would not get pattern matched at all, but now we check if the
3633 template parameter `av` came from.
3635 This note has been left to serve as a hint for further explorers into
3636 how IsExp matching works.
3638 if (auto ta
= tp
.isTemplateAliasParameter())
3643 // (23578) - ensure previous behaviour for non-alias template params
3644 if (!tp
.isTemplateTypeParameter())
3649 Type at
= cast(Type
)(*dedtypes
)[i
];
3651 if (ubyte wx
= wm ?
deduceWildHelper(t
, &tt
, tparam
) : 0)
3656 (*dedtypes
)[i
] = tt
;
3658 result
= MATCH
.constant
;
3662 // type vs expressions
3665 TypeDeduced xt
= cast(TypeDeduced
)at
;
3666 result
= xt
.matchAll(tt
);
3667 if (result
> MATCH
.nomatch
)
3669 (*dedtypes
)[i
] = tt
;
3670 if (result
> MATCH
.constant
)
3671 result
= MATCH
.constant
; // limit level for inout matches
3679 (*dedtypes
)[i
] = tt
; // Prefer current type match
3682 if (tt
.implicitConvTo(at
.constOf()))
3684 (*dedtypes
)[i
] = at
.constOf().mutableOf();
3685 *wm |
= MODFlags
.const_
;
3688 if (at
.implicitConvTo(tt
.constOf()))
3690 (*dedtypes
)[i
] = tt
.constOf().mutableOf();
3691 *wm |
= MODFlags
.const_
;
3696 else if (MATCH m
= deduceTypeHelper(t
, &tt
, tparam
))
3701 (*dedtypes
)[i
] = tt
;
3706 // type vs expressions
3709 TypeDeduced xt
= cast(TypeDeduced
)at
;
3710 result
= xt
.matchAll(tt
);
3711 if (result
> MATCH
.nomatch
)
3713 (*dedtypes
)[i
] = tt
;
3723 if (tt
.ty
== Tclass
&& at
.ty
== Tclass
)
3725 result
= tt
.implicitConvTo(at
);
3728 if (tt
.ty
== Tsarray
&& at
.ty
== Tarray
&& tt
.nextOf().implicitConvTo(at
.nextOf()) >= MATCH
.constant
)
3736 if (tparam
.ty
== Ttypeof
)
3738 /* Need a loc to go with the semantic routine.
3741 if (parameters
.length
)
3743 TemplateParameter tp
= (*parameters
)[0];
3747 tparam
= tparam
.typeSemantic(loc
, sc
);
3749 if (t
.ty
!= tparam
.ty
)
3751 if (Dsymbol sym
= t
.toDsymbol(sc
))
3753 if (sym
.isforwardRef() && !tparam
.deco
)
3757 MATCH m
= t
.implicitConvTo(tparam
);
3758 if (m
== MATCH
.nomatch
&& !ignoreAliasThis
)
3762 TypeClass tc
= cast(TypeClass
)t
;
3763 if (tc
.sym
.aliasthis
&& !(tc
.att
& AliasThisRec
.tracingDT
))
3765 if (auto ato
= t
.aliasthisOf())
3767 tc
.att
= cast(AliasThisRec
)(tc
.att | AliasThisRec
.tracingDT
);
3768 m
= deduceType(ato
, sc
, tparam
, parameters
, dedtypes
, wm
);
3769 tc
.att
= cast(AliasThisRec
)(tc
.att
& ~AliasThisRec
.tracingDT
);
3773 else if (t
.ty
== Tstruct
)
3775 TypeStruct ts
= cast(TypeStruct
)t
;
3776 if (ts
.sym
.aliasthis
&& !(ts
.att
& AliasThisRec
.tracingDT
))
3778 if (auto ato
= t
.aliasthisOf())
3780 ts
.att
= cast(AliasThisRec
)(ts
.att | AliasThisRec
.tracingDT
);
3781 m
= deduceType(ato
, sc
, tparam
, parameters
, dedtypes
, wm
);
3782 ts
.att
= cast(AliasThisRec
)(ts
.att
& ~AliasThisRec
.tracingDT
);
3793 if (tparam
.deco
&& !tparam
.hasWild())
3795 result
= t
.implicitConvTo(tparam
);
3799 Type tpn
= tparam
.nextOf();
3800 if (wm
&& t
.ty
== Taarray
&& tparam
.isWild())
3802 // https://issues.dlang.org/show_bug.cgi?id=12403
3803 // In IFTI, stop inout matching on transitive part of AA types.
3804 tpn
= tpn
.substWildTo(MODFlags
.mutable
);
3807 result
= deduceType(t
.nextOf(), sc
, tpn
, parameters
, dedtypes
, wm
);
3812 result
= MATCH
.exact
;
3816 result
= MATCH
.nomatch
;
3820 result
= MATCH
.constant
;
3823 override void visit(TypeVector t
)
3825 if (tparam
.ty
== Tvector
)
3827 TypeVector tp
= cast(TypeVector
)tparam
;
3828 result
= deduceType(t
.basetype
, sc
, tp
.basetype
, parameters
, dedtypes
, wm
);
3834 override void visit(TypeDArray t
)
3839 override void visit(TypeSArray t
)
3841 // Extra check that array dimensions must match
3844 if (tparam
.ty
== Tarray
)
3846 MATCH m
= deduceType(t
.next
, sc
, tparam
.nextOf(), parameters
, dedtypes
, wm
);
3847 result
= (m
>= MATCH
.constant
) ? MATCH
.convert
: MATCH
.nomatch
;
3851 TemplateParameter tp
= null;
3852 Expression edim
= null;
3854 if (tparam
.ty
== Tsarray
)
3856 TypeSArray tsa
= cast(TypeSArray
)tparam
;
3857 if (tsa
.dim
.isVarExp() && tsa
.dim
.isVarExp().var
.storage_class
& STC
.templateparameter
)
3859 Identifier id
= tsa
.dim
.isVarExp().var
.ident
;
3860 i
= templateIdentifierLookup(id
, parameters
);
3861 assert(i
!= IDX_NOTFOUND
);
3862 tp
= (*parameters
)[i
];
3867 else if (tparam
.ty
== Taarray
)
3869 TypeAArray taa
= cast(TypeAArray
)tparam
;
3870 i
= templateParameterLookup(taa
.index
, parameters
);
3871 if (i
!= IDX_NOTFOUND
)
3872 tp
= (*parameters
)[i
];
3876 // The "type" (it hasn't been resolved yet) of the function parameter
3877 // does not have a location but the parameter it is related to does,
3878 // so we use that for the resolution (better error message).
3879 if (inferStart
< parameters
.length
)
3881 TemplateParameter loctp
= (*parameters
)[inferStart
];
3888 taa
.index
.resolve(loc
, sc
, e
, tx
, s
);
3889 edim
= s ?
getValue(s
) : getValue(e
);
3892 if (tp
&& tp
.matchArg(sc
, t
.dim
, i
, parameters
, dedtypes
, null) || edim
&& edim
.toInteger() == t
.dim
.toInteger())
3894 result
= deduceType(t
.next
, sc
, tparam
.nextOf(), parameters
, dedtypes
, wm
);
3901 override void visit(TypeAArray t
)
3903 // Extra check that index type must match
3904 if (tparam
&& tparam
.ty
== Taarray
)
3906 TypeAArray tp
= cast(TypeAArray
)tparam
;
3907 if (!deduceType(t
.index
, sc
, tp
.index
, parameters
, dedtypes
))
3909 result
= MATCH
.nomatch
;
3916 override void visit(TypeFunction t
)
3918 // Extra check that function characteristics must match
3920 return visit(cast(Type
)t
);
3922 if (auto tp
= tparam
.isTypeFunction())
3924 if (t
.parameterList
.varargs
!= tp
.parameterList
.varargs || t
.linkage
!= tp
.linkage
)
3926 result
= MATCH
.nomatch
;
3930 foreach (fparam
; *tp
.parameterList
.parameters
)
3932 // https://issues.dlang.org/show_bug.cgi?id=2579
3933 // Apply function parameter storage classes to parameter types
3934 fparam
.type
= fparam
.type
.addStorageClass(fparam
.storageClass
);
3935 fparam
.storageClass
&= ~STC
.TYPECTOR
;
3937 // https://issues.dlang.org/show_bug.cgi?id=15243
3938 // Resolve parameter type if it's not related with template parameters
3939 if (!reliesOnTemplateParameters(fparam
.type
, (*parameters
)[inferStart
.. parameters
.length
]))
3941 auto tx
= fparam
.type
.typeSemantic(Loc
.initial
, sc
);
3942 if (tx
.ty
== Terror
)
3944 result
= MATCH
.nomatch
;
3951 size_t nfargs
= t
.parameterList
.length
;
3952 size_t nfparams
= tp
.parameterList
.length
;
3954 /* See if tuple match
3956 if (nfparams
> 0 && nfargs
>= nfparams
- 1)
3958 /* See if 'A' of the template parameter matches 'A'
3959 * of the type of the last function parameter.
3961 Parameter fparam
= tp
.parameterList
[nfparams
- 1];
3963 assert(fparam
.type
);
3964 if (fparam
.type
.ty
!= Tident
)
3966 TypeIdentifier tid
= cast(TypeIdentifier
)fparam
.type
;
3967 if (tid
.idents
.length
)
3970 /* Look through parameters to find tuple matching tid.ident
3975 if (tupi
== parameters
.length
)
3977 TemplateParameter tx
= (*parameters
)[tupi
];
3978 TemplateTupleParameter tup
= tx
.isTemplateTupleParameter();
3979 if (tup
&& tup
.ident
.equals(tid
.ident
))
3983 /* The types of the function arguments [nfparams - 1 .. nfargs]
3984 * now form the tuple argument.
3986 size_t tuple_dim
= nfargs
- (nfparams
- 1);
3988 /* See if existing tuple, and whether it matches or not
3990 RootObject o
= (*dedtypes
)[tupi
];
3993 // Existing deduced argument must be a tuple, and must match
3994 Tuple tup
= isTuple(o
);
3995 if (!tup || tup
.objects
.length
!= tuple_dim
)
3997 result
= MATCH
.nomatch
;
4000 for (size_t i
= 0; i
< tuple_dim
; i
++)
4002 Parameter arg
= t
.parameterList
[nfparams
- 1 + i
];
4003 if (!arg
.type
.equals(tup
.objects
[i
]))
4005 result
= MATCH
.nomatch
;
4013 auto tup
= new Tuple(tuple_dim
);
4014 for (size_t i
= 0; i
< tuple_dim
; i
++)
4016 Parameter arg
= t
.parameterList
[nfparams
- 1 + i
];
4017 tup
.objects
[i
] = arg
.type
;
4019 (*dedtypes
)[tupi
] = tup
;
4021 nfparams
--; // don't consider the last parameter for type deduction
4026 if (nfargs
!= nfparams
)
4028 result
= MATCH
.nomatch
;
4032 assert(nfparams
<= tp
.parameterList
.length
);
4033 foreach (i
, ap
; tp
.parameterList
)
4038 Parameter a
= t
.parameterList
[i
];
4040 if (!a
.isCovariant(t
.isref
, ap
) ||
4041 !deduceType(a
.type
, sc
, ap
.type
, parameters
, dedtypes
))
4043 result
= MATCH
.nomatch
;
4051 override void visit(TypeIdentifier t
)
4054 if (tparam
&& tparam
.ty
== Tident
)
4056 TypeIdentifier tp
= cast(TypeIdentifier
)tparam
;
4057 for (size_t i
= 0; i
< t
.idents
.length
; i
++)
4059 RootObject id1
= t
.idents
[i
];
4060 RootObject id2
= tp
.idents
[i
];
4061 if (!id1
.equals(id2
))
4063 result
= MATCH
.nomatch
;
4071 override void visit(TypeInstance t
)
4074 if (tparam
&& tparam
.ty
== Tinstance
&& t
.tempinst
.tempdecl
)
4076 TemplateDeclaration tempdecl
= t
.tempinst
.tempdecl
.isTemplateDeclaration();
4079 TypeInstance tp
= cast(TypeInstance
)tparam
;
4081 //printf("tempinst.tempdecl = %p\n", tempdecl);
4082 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
4083 if (!tp
.tempinst
.tempdecl
)
4085 //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
4088 * template Foo(T : sa!(T), alias sa)
4090 size_t i
= templateIdentifierLookup(tp
.tempinst
.name
, parameters
);
4091 if (i
== IDX_NOTFOUND
)
4093 /* Didn't find it as a parameter identifier. Try looking
4094 * it up and seeing if is an alias.
4095 * https://issues.dlang.org/show_bug.cgi?id=1454
4097 auto tid
= new TypeIdentifier(tp
.loc
, tp
.tempinst
.name
);
4101 tid
.resolve(tp
.loc
, sc
, e
, tx
, s
);
4104 s
= tx
.toDsymbol(sc
);
4105 if (TemplateInstance ti
= s ? s
.parent
.isTemplateInstance() : null)
4107 // https://issues.dlang.org/show_bug.cgi?id=14290
4108 // Try to match with ti.tempecl,
4109 // only when ti is an enclosing instance.
4110 Dsymbol p
= sc
.parent
;
4111 while (p
&& p
!= ti
)
4120 TemplateDeclaration td
= s
.isTemplateDeclaration();
4125 for (; td
; td
= td
.overnext
)
4135 TemplateParameter tpx
= (*parameters
)[i
];
4136 if (!tpx
.matchArg(sc
, tempdecl
, i
, parameters
, dedtypes
, null))
4139 else if (tempdecl
!= tp
.tempinst
.tempdecl
)
4143 if (!resolveTemplateInstantiation(t
.tempinst
.tiargs
, &t
.tempinst
.tdtypes
, tempdecl
, tp
, dedtypes
))
4150 //printf("no match\n");
4151 result
= MATCH
.nomatch
;
4154 /********************
4155 * Match template `parameters` to the target template instance.
4157 * struct Temp(U, int Z) {}
4158 * void foo(T)(Temp!(T, 3));
4159 * foo(Temp!(int, 3)());
4161 * this.parameters = template params of foo -> [T]
4162 * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3]
4163 * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3]
4164 * tempdecl = <struct Temp!(T, int Z)> -> [T, Z]
4165 * tp = <Temp!(T, 3)>
4167 * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int]
4169 private bool resolveTemplateInstantiation(Objects
* tiargs
, Objects
* tdtypes
, TemplateDeclaration tempdecl
, TypeInstance tp
, Objects
* dedtypes
)
4171 for (size_t i
= 0; 1; i
++)
4173 //printf("\ttest: tempinst.tiargs[%zu]\n", i);
4174 RootObject o1
= null;
4175 if (i
< tiargs
.length
)
4177 else if (i
< tdtypes
.length
&& i
< tp
.tempinst
.tiargs
.length
)
4179 // Pick up default arg
4182 else if (i
>= tp
.tempinst
.tiargs
.length
)
4184 //printf("\ttest: o1 = %s\n", o1.toChars());
4185 if (i
>= tp
.tempinst
.tiargs
.length
)
4187 size_t dim
= tempdecl
.parameters
.length
- (tempdecl
.isVariadic() ?
1 : 0);
4188 while (i
< dim
&& ((*tempdecl
.parameters
)[i
].dependent ||
(*tempdecl
.parameters
)[i
].hasDefaultArg()))
4193 break; // match if all remained parameters are dependent
4197 RootObject o2
= (*tp
.tempinst
.tiargs
)[i
];
4198 Type t2
= isType(o2
);
4199 //printf("\ttest: o2 = %s\n", o2.toChars());
4200 size_t j
= (t2
&& t2
.ty
== Tident
&& i
== tp
.tempinst
.tiargs
.length
- 1)
4201 ?
templateParameterLookup(t2
, parameters
) : IDX_NOTFOUND
;
4202 if (j
!= IDX_NOTFOUND
&& j
== parameters
.length
- 1 &&
4203 (*parameters
)[j
].isTemplateTupleParameter())
4207 * alias A!(int, float) X;
4208 * static if (is(X Y == A!(Z), Z...)) {}
4209 * deduce that Z is a tuple(int, float)
4212 /* Create tuple from remaining args
4214 size_t vtdim
= (tempdecl
.isVariadic() ? tiargs
.length
: tdtypes
.length
) - i
;
4215 auto vt
= new Tuple(vtdim
);
4216 for (size_t k
= 0; k
< vtdim
; k
++)
4219 if (k
< tiargs
.length
)
4220 o
= (*tiargs
)[i
+ k
];
4221 else // Pick up default arg
4222 o
= (*tdtypes
)[i
+ k
];
4226 Tuple v
= cast(Tuple
)(*dedtypes
)[j
];
4233 (*dedtypes
)[j
] = vt
;
4239 Type t1
= isType(o1
);
4240 Dsymbol s1
= isDsymbol(o1
);
4241 Dsymbol s2
= isDsymbol(o2
);
4242 Expression e1
= s1 ?
getValue(s1
) : getValue(isExpression(o1
));
4243 Expression e2
= isExpression(o2
);
4246 Tuple v1
= isTuple(o1
);
4247 Tuple v2
= isTuple(o2
);
4249 printf("t1 = %s\n", t1
.toChars());
4251 printf("t2 = %s\n", t2
.toChars());
4253 printf("e1 = %s\n", e1
.toChars());
4255 printf("e2 = %s\n", e2
.toChars());
4257 printf("s1 = %s\n", s1
.toChars());
4259 printf("s2 = %s\n", s2
.toChars());
4261 printf("v1 = %s\n", v1
.toChars());
4263 printf("v2 = %s\n", v2
.toChars());
4268 if (!deduceType(t1
, sc
, t2
, parameters
, dedtypes
))
4274 e1
= e1
.ctfeInterpret();
4276 /* If it is one of the template parameters for this template,
4277 * we should not attempt to interpret it. It already has a value.
4279 if (e2
.op
== EXP
.variable
&& (e2
.isVarExp().var
.storage_class
& STC
.templateparameter
))
4282 * (T:Number!(e2), int e2)
4284 j
= templateIdentifierLookup(e2
.isVarExp().var
.ident
, parameters
);
4285 if (j
!= IDX_NOTFOUND
)
4287 // The template parameter was not from this template
4288 // (it may be from a parent template, for example)
4291 e2
= e2
.expressionSemantic(sc
); // https://issues.dlang.org/show_bug.cgi?id=13417
4292 e2
= e2
.ctfeInterpret();
4294 //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
4295 //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
4298 if (!e2
.implicitConvTo(e1
.type
))
4301 e2
= e2
.implicitCastTo(sc
, e1
.type
);
4302 e2
= e2
.ctfeInterpret();
4307 else if (e1
&& t2
&& t2
.ty
== Tident
)
4309 j
= templateParameterLookup(t2
, parameters
);
4311 if (j
== IDX_NOTFOUND
)
4313 t2
.resolve((cast(TypeIdentifier
)t2
).loc
, sc
, e2
, t2
, s2
);
4318 if (!(*parameters
)[j
].matchArg(sc
, e1
, j
, parameters
, dedtypes
, null))
4327 else if (s1
&& t2
&& t2
.ty
== Tident
)
4329 j
= templateParameterLookup(t2
, parameters
);
4330 if (j
== IDX_NOTFOUND
)
4332 t2
.resolve((cast(TypeIdentifier
)t2
).loc
, sc
, e2
, t2
, s2
);
4337 if (!(*parameters
)[j
].matchArg(sc
, s1
, j
, parameters
, dedtypes
, null))
4346 override void visit(TypeStruct t
)
4348 /* If this struct is a template struct, and we're matching
4349 * it against a template instance, convert the struct type
4350 * to a template instance, too, and try again.
4352 TemplateInstance ti
= t
.sym
.parent
.isTemplateInstance();
4354 if (tparam
&& tparam
.ty
== Tinstance
)
4356 if (ti
&& ti
.toAlias() == t
.sym
)
4358 auto tx
= new TypeInstance(Loc
.initial
, ti
);
4359 auto m
= deduceType(tx
, sc
, tparam
, parameters
, dedtypes
, wm
);
4360 // if we have a no match we still need to check alias this
4361 if (m
!= MATCH
.nomatch
)
4368 /* Match things like:
4371 TypeInstance tpi
= cast(TypeInstance
)tparam
;
4372 if (tpi
.idents
.length
)
4374 RootObject id
= tpi
.idents
[tpi
.idents
.length
- 1];
4375 if (id
.dyncast() == DYNCAST
.identifier
&& t
.sym
.ident
.equals(cast(Identifier
)id
))
4377 Type tparent
= t
.sym
.parent
.getType();
4380 /* Slice off the .foo in S!(T).foo
4382 tpi
.idents
.length
--;
4383 result
= deduceType(tparent
, sc
, tpi
, parameters
, dedtypes
, wm
);
4384 tpi
.idents
.length
++;
4392 if (tparam
&& tparam
.ty
== Tstruct
)
4394 TypeStruct tp
= cast(TypeStruct
)tparam
;
4396 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4397 if (wm
&& t
.deduceWild(tparam
, false))
4399 result
= MATCH
.constant
;
4402 result
= t
.implicitConvTo(tp
);
4408 override void visit(TypeEnum t
)
4411 if (tparam
&& tparam
.ty
== Tenum
)
4413 TypeEnum tp
= cast(TypeEnum
)tparam
;
4414 if (t
.sym
== tp
.sym
)
4417 result
= MATCH
.nomatch
;
4420 Type tb
= t
.toBasetype();
4421 if (tb
.ty
== tparam
.ty || tb
.ty
== Tsarray
&& tparam
.ty
== Taarray
)
4423 result
= deduceType(tb
, sc
, tparam
, parameters
, dedtypes
, wm
);
4424 if (result
== MATCH
.exact
)
4425 result
= MATCH
.convert
;
4431 /* Helper for TypeClass.deduceType().
4432 * Classes can match with implicit conversion to a base class or interface.
4433 * This is complicated, because there may be more than one base class which
4434 * matches. In such cases, one or more parameters remain ambiguous.
4437 * interface I(X, Y) {}
4438 * class C : I(uint, double), I(char, double) {}
4440 * foo(T, U)( I!(T, U) x)
4442 * deduces that U is double, but T remains ambiguous (could be char or uint).
4444 * Given a baseclass b, and initial deduced types 'dedtypes', this function
4445 * tries to match tparam with b, and also tries all base interfaces of b.
4446 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
4447 * types are ANDed with the current 'best' estimate for dedtypes.
4449 static void deduceBaseClassParameters(ref BaseClass b
, Scope
* sc
, Type tparam
, TemplateParameters
* parameters
, Objects
* dedtypes
, Objects
* best
, ref int numBaseClassMatches
)
4451 TemplateInstance parti
= b
.sym ? b
.sym
.parent
.isTemplateInstance() : null;
4454 // Make a temporary copy of dedtypes so we don't destroy it
4455 auto tmpdedtypes
= new Objects(dedtypes
.length
);
4456 memcpy(tmpdedtypes
.tdata(), dedtypes
.tdata(), dedtypes
.length
* (void*).sizeof
);
4458 auto t
= new TypeInstance(Loc
.initial
, parti
);
4459 MATCH m
= deduceType(t
, sc
, tparam
, parameters
, tmpdedtypes
);
4460 if (m
> MATCH
.nomatch
)
4462 // If this is the first ever match, it becomes our best estimate
4463 if (numBaseClassMatches
== 0)
4464 memcpy(best
.tdata(), tmpdedtypes
.tdata(), tmpdedtypes
.length
* (void*).sizeof
);
4466 for (size_t k
= 0; k
< tmpdedtypes
.length
; ++k
)
4468 // If we've found more than one possible type for a parameter,
4469 // mark it as unknown.
4470 if ((*tmpdedtypes
)[k
] != (*best
)[k
])
4471 (*best
)[k
] = (*dedtypes
)[k
];
4473 ++numBaseClassMatches
;
4477 // Now recursively test the inherited interfaces
4478 foreach (ref bi
; b
.baseInterfaces
)
4480 deduceBaseClassParameters(bi
, sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
4484 override void visit(TypeClass t
)
4486 //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
4488 /* If this class is a template class, and we're matching
4489 * it against a template instance, convert the class type
4490 * to a template instance, too, and try again.
4492 TemplateInstance ti
= t
.sym
.parent
.isTemplateInstance();
4494 if (tparam
&& tparam
.ty
== Tinstance
)
4496 if (ti
&& ti
.toAlias() == t
.sym
)
4498 auto tx
= new TypeInstance(Loc
.initial
, ti
);
4499 MATCH m
= deduceType(tx
, sc
, tparam
, parameters
, dedtypes
, wm
);
4500 // Even if the match fails, there is still a chance it could match
4502 if (m
!= MATCH
.nomatch
)
4509 /* Match things like:
4512 TypeInstance tpi
= cast(TypeInstance
)tparam
;
4513 if (tpi
.idents
.length
)
4515 RootObject id
= tpi
.idents
[tpi
.idents
.length
- 1];
4516 if (id
.dyncast() == DYNCAST
.identifier
&& t
.sym
.ident
.equals(cast(Identifier
)id
))
4518 Type tparent
= t
.sym
.parent
.getType();
4521 /* Slice off the .foo in S!(T).foo
4523 tpi
.idents
.length
--;
4524 result
= deduceType(tparent
, sc
, tpi
, parameters
, dedtypes
, wm
);
4525 tpi
.idents
.length
++;
4531 // If it matches exactly or via implicit conversion, we're done
4533 if (result
!= MATCH
.nomatch
)
4536 /* There is still a chance to match via implicit conversion to
4537 * a base class or interface. Because there could be more than one such
4538 * match, we need to check them all.
4541 int numBaseClassMatches
= 0; // Have we found an interface match?
4543 // Our best guess at dedtypes
4544 auto best
= new Objects(dedtypes
.length
);
4546 ClassDeclaration s
= t
.sym
;
4547 while (s
&& s
.baseclasses
.length
> 0)
4549 // Test the base class
4550 deduceBaseClassParameters(*(*s
.baseclasses
)[0], sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
4552 // Test the interfaces inherited by the base class
4553 foreach (b
; s
.interfaces
)
4555 deduceBaseClassParameters(*b
, sc
, tparam
, parameters
, dedtypes
, best
, numBaseClassMatches
);
4557 s
= (*s
.baseclasses
)[0].sym
;
4560 if (numBaseClassMatches
== 0)
4562 result
= MATCH
.nomatch
;
4566 // If we got at least one match, copy the known types into dedtypes
4567 memcpy(dedtypes
.tdata(), best
.tdata(), best
.length
* (void*).sizeof
);
4568 result
= MATCH
.convert
;
4573 if (tparam
&& tparam
.ty
== Tclass
)
4575 TypeClass tp
= cast(TypeClass
)tparam
;
4577 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
4578 if (wm
&& t
.deduceWild(tparam
, false))
4580 result
= MATCH
.constant
;
4583 result
= t
.implicitConvTo(tp
);
4589 override void visit(Expression e
)
4591 //printf("Expression.deduceType(e = %s)\n", e.toChars());
4592 size_t i
= templateParameterLookup(tparam
, parameters
);
4593 if (i
== IDX_NOTFOUND ||
(cast(TypeIdentifier
)tparam
).idents
.length
> 0)
4595 if (e
== emptyArrayElement
&& tparam
.ty
== Tarray
)
4597 Type tn
= (cast(TypeNext
)tparam
).next
;
4598 result
= deduceType(emptyArrayElement
, sc
, tn
, parameters
, dedtypes
, wm
);
4601 e
.type
.accept(this);
4605 TemplateTypeParameter tp
= (*parameters
)[i
].isTemplateTypeParameter();
4609 if (e
== emptyArrayElement
)
4613 result
= MATCH
.exact
;
4618 tp
.defaultType
.accept(this);
4623 /* Returns `true` if `t` is a reference type, or an array of reference types
4625 bool isTopRef(Type t
)
4627 auto tb
= t
.baseElemOf();
4628 return tb
.ty
== Tclass ||
4630 tb
.ty
== Tstruct
&& tb
.hasPointers();
4633 Type at
= cast(Type
)(*dedtypes
)[i
];
4635 if (ubyte wx
= deduceWildHelper(e
.type
, &tt
, tparam
))
4638 result
= MATCH
.constant
;
4640 else if (MATCH m
= deduceTypeHelper(e
.type
, &tt
, tparam
))
4644 else if (!isTopRef(e
.type
))
4646 /* https://issues.dlang.org/show_bug.cgi?id=15653
4647 * In IFTI, recognize top-qualifier conversions
4648 * through the value copy, e.g.
4649 * int --> immutable(int)
4650 * immutable(string[]) --> immutable(string)[]
4652 tt
= e
.type
.mutableOf();
4653 result
= MATCH
.convert
;
4658 // expression vs (none)
4661 (*dedtypes
)[i
] = new TypeDeduced(tt
, e
, tparam
);
4665 TypeDeduced xt
= null;
4668 xt
= cast(TypeDeduced
)at
;
4672 // From previous matched expressions to current deduced type
4673 MATCH match1
= xt ? xt
.matchAll(tt
) : MATCH
.nomatch
;
4675 // From current expressions to previous deduced type
4676 Type pt
= at
.addMod(tparam
.mod
);
4678 pt
= pt
.substWildTo(*wm
);
4679 MATCH match2
= e
.implicitConvTo(pt
);
4681 if (match1
> MATCH
.nomatch
&& match2
> MATCH
.nomatch
)
4683 if (at
.implicitConvTo(tt
) == MATCH
.nomatch
)
4684 match1
= MATCH
.nomatch
; // Prefer at
4685 else if (tt
.implicitConvTo(at
) == MATCH
.nomatch
)
4686 match2
= MATCH
.nomatch
; // Prefer tt
4687 else if (tt
.isTypeBasic() && tt
.ty
== at
.ty
&& tt
.mod
!= at
.mod
)
4689 if (!tt
.isMutable() && !at
.isMutable())
4690 tt
= tt
.mutableOf().addMod(MODmerge(tt
.mod
, at
.mod
));
4691 else if (tt
.isMutable())
4693 if (at
.mod
== 0) // Prefer unshared
4694 match1
= MATCH
.nomatch
;
4696 match2
= MATCH
.nomatch
;
4698 else if (at
.isMutable())
4700 if (tt
.mod
== 0) // Prefer unshared
4701 match2
= MATCH
.nomatch
;
4703 match1
= MATCH
.nomatch
;
4705 //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
4709 match1
= MATCH
.nomatch
;
4710 match2
= MATCH
.nomatch
;
4713 if (match1
> MATCH
.nomatch
)
4715 // Prefer current match: tt
4717 xt
.update(tt
, e
, tparam
);
4719 (*dedtypes
)[i
] = tt
;
4723 if (match2
> MATCH
.nomatch
)
4725 // Prefer previous match: (*dedtypes)[i]
4727 xt
.update(e
, tparam
);
4732 /* Deduce common type
4734 if (Type t
= rawTypeMerge(at
, tt
))
4737 xt
.update(t
, e
, tparam
);
4741 pt
= tt
.addMod(tparam
.mod
);
4743 pt
= pt
.substWildTo(*wm
);
4744 result
= e
.implicitConvTo(pt
);
4748 result
= MATCH
.nomatch
;
4751 MATCH
deduceEmptyArrayElement()
4753 if (!emptyArrayElement
)
4755 emptyArrayElement
= new IdentifierExp(Loc
.initial
, Id
.p
); // dummy
4756 emptyArrayElement
.type
= Type
.tvoid
;
4758 assert(tparam
.ty
== Tarray
);
4760 Type tn
= (cast(TypeNext
)tparam
).next
;
4761 return deduceType(emptyArrayElement
, sc
, tn
, parameters
, dedtypes
, wm
);
4764 override void visit(NullExp e
)
4766 if (tparam
.ty
== Tarray
&& e
.type
.ty
== Tnull
)
4768 // tparam:T[] <- e:null (void[])
4769 result
= deduceEmptyArrayElement();
4772 visit(cast(Expression
)e
);
4775 override void visit(StringExp e
)
4778 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
4780 // Consider compile-time known boundaries
4781 e
.type
.nextOf().sarrayOf(e
.len
).accept(this);
4784 visit(cast(Expression
)e
);
4787 override void visit(ArrayLiteralExp e
)
4789 // https://issues.dlang.org/show_bug.cgi?id=20092
4790 if (e
.elements
&& e
.elements
.length
&& e
.type
.toBasetype().nextOf().ty
== Tvoid
)
4792 result
= deduceEmptyArrayElement();
4795 if ((!e
.elements ||
!e
.elements
.length
) && e
.type
.toBasetype().nextOf().ty
== Tvoid
&& tparam
.ty
== Tarray
)
4797 // tparam:T[] <- e:[] (void[])
4798 result
= deduceEmptyArrayElement();
4802 if (tparam
.ty
== Tarray
&& e
.elements
&& e
.elements
.length
)
4804 Type tn
= (cast(TypeDArray
)tparam
).next
;
4805 result
= MATCH
.exact
;
4808 MATCH m
= deduceType(e
.basis
, sc
, tn
, parameters
, dedtypes
, wm
);
4812 foreach (el
; *e
.elements
)
4814 if (result
== MATCH
.nomatch
)
4818 MATCH m
= deduceType(el
, sc
, tn
, parameters
, dedtypes
, wm
);
4826 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
4828 // Consider compile-time known boundaries
4829 e
.type
.nextOf().sarrayOf(e
.elements
.length
).accept(this);
4832 visit(cast(Expression
)e
);
4835 override void visit(AssocArrayLiteralExp e
)
4837 if (tparam
.ty
== Taarray
&& e
.keys
&& e
.keys
.length
)
4839 TypeAArray taa
= cast(TypeAArray
)tparam
;
4840 result
= MATCH
.exact
;
4841 foreach (i
, key
; *e
.keys
)
4843 MATCH m1
= deduceType(key
, sc
, taa
.index
, parameters
, dedtypes
, wm
);
4846 if (result
== MATCH
.nomatch
)
4848 MATCH m2
= deduceType((*e
.values
)[i
], sc
, taa
.next
, parameters
, dedtypes
, wm
);
4851 if (result
== MATCH
.nomatch
)
4856 visit(cast(Expression
)e
);
4859 override void visit(FuncExp e
)
4861 //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
4867 auto tof
= to
.nextOf().isTypeFunction();
4871 // Parameter types inference from 'tof'
4872 assert(e
.td
._scope
);
4873 TypeFunction tf
= cast(TypeFunction
)e
.fd
.type
;
4874 //printf("\ttof = %s\n", tof.toChars());
4875 //printf("\ttf = %s\n", tf.toChars());
4876 const dim
= tf
.parameterList
.length
;
4878 if (tof
.parameterList
.length
!= dim || tof
.parameterList
.varargs
!= tf
.parameterList
.varargs
)
4881 auto tiargs
= new Objects();
4882 tiargs
.reserve(e
.td
.parameters
.length
);
4884 foreach (tp
; *e
.td
.parameters
)
4887 foreach (i
, p
; tf
.parameterList
)
4889 if (p
.type
.ty
== Tident
&& (cast(TypeIdentifier
)p
.type
).ident
== tp
.ident
)
4894 Parameter pto
= tof
.parameterList
[u
];
4897 Type t
= pto
.type
.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
4898 if (reliesOnTemplateParameters(t
, (*parameters
)[inferStart
.. parameters
.length
]))
4900 t
= t
.typeSemantic(e
.loc
, sc
);
4906 // Set target of return type inference
4907 if (!tf
.next
&& tof
.next
)
4910 auto ti
= new TemplateInstance(e
.loc
, e
.td
, tiargs
);
4911 Expression ex
= (new ScopeExp(e
.loc
, ti
)).expressionSemantic(e
.td
._scope
);
4913 // Reset inference target for the later re-semantic
4916 if (ex
.op
== EXP
.error
)
4918 if (ex
.op
!= EXP
.function_
)
4926 if (t
.ty
== Tdelegate
&& tparam
.ty
== Tpointer
)
4929 // Allow conversion from implicit function pointer to delegate
4930 if (e
.tok
== TOK
.reserved
&& t
.ty
== Tpointer
&& tparam
.ty
== Tdelegate
)
4932 TypeFunction tf
= cast(TypeFunction
)t
.nextOf();
4933 t
= (new TypeDelegate(tf
)).merge();
4935 //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
4939 override void visit(SliceExp e
)
4942 if (e
.type
.ty
== Tarray
&& (tparam
.ty
== Tsarray || tparam
.ty
== Taarray
&& (taai
= (cast(TypeAArray
)tparam
).index
).ty
== Tident
&& (cast(TypeIdentifier
)taai
).idents
.length
== 0))
4944 // Consider compile-time known boundaries
4945 if (Type tsa
= toStaticArrayType(e
))
4948 if (result
> MATCH
.convert
)
4949 result
= MATCH
.convert
; // match with implicit conversion at most
4953 visit(cast(Expression
)e
);
4956 override void visit(CommaExp e
)
4962 scope DeduceType v
= new DeduceType(sc
, tparam
, parameters
, dedtypes
, wm
, inferStart
, ignoreAliasThis
);
4963 if (Type t
= isType(o
))
4965 else if (Expression e
= isExpression(o
))
4975 /***********************************************************
4976 * Check whether the type t representation relies on one or more the template parameters.
4978 * t = Tested type, if null, returns false.
4979 * tparams = Template parameters.
4980 * iStart = Start index of tparams to limit the tested parameters. If it's
4981 * nonzero, tparams[0..iStart] will be excluded from the test target.
4983 bool reliesOnTident(Type t
, TemplateParameters
* tparams
, size_t iStart
= 0)
4985 return reliesOnTemplateParameters(t
, (*tparams
)[0 .. tparams
.length
]);
4988 /***********************************************************
4989 * Check whether the type t representation relies on one or more the template parameters.
4991 * t = Tested type, if null, returns false.
4992 * tparams = Template parameters.
4994 private bool reliesOnTemplateParameters(Type t
, TemplateParameter
[] tparams
)
4996 bool visitVector(TypeVector t
)
4998 return t
.basetype
.reliesOnTemplateParameters(tparams
);
5001 bool visitAArray(TypeAArray t
)
5003 return t
.next
.reliesOnTemplateParameters(tparams
) ||
5004 t
.index
.reliesOnTemplateParameters(tparams
);
5007 bool visitFunction(TypeFunction t
)
5009 foreach (i
, fparam
; t
.parameterList
)
5011 if (fparam
.type
.reliesOnTemplateParameters(tparams
))
5014 return t
.next
.reliesOnTemplateParameters(tparams
);
5017 bool visitIdentifier(TypeIdentifier t
)
5019 foreach (tp
; tparams
)
5021 if (tp
.ident
.equals(t
.ident
))
5027 bool visitInstance(TypeInstance t
)
5029 foreach (tp
; tparams
)
5031 if (t
.tempinst
.name
== tp
.ident
)
5035 if (t
.tempinst
.tiargs
)
5036 foreach (arg
; *t
.tempinst
.tiargs
)
5038 if (Type ta
= isType(arg
))
5040 if (ta
.reliesOnTemplateParameters(tparams
))
5048 bool visitTypeof(TypeTypeof t
)
5050 //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
5051 return t
.exp
.reliesOnTemplateParameters(tparams
);
5054 bool visitTuple(TypeTuple t
)
5057 foreach (arg
; *t
.arguments
)
5059 if (arg
.type
.reliesOnTemplateParameters(tparams
))
5069 Type tb
= t
.toBasetype();
5072 case Tvector
: return visitVector(tb
.isTypeVector());
5073 case Taarray
: return visitAArray(tb
.isTypeAArray());
5074 case Tfunction
: return visitFunction(tb
.isTypeFunction());
5075 case Tident
: return visitIdentifier(tb
.isTypeIdentifier());
5076 case Tinstance
: return visitInstance(tb
.isTypeInstance());
5077 case Ttypeof
: return visitTypeof(tb
.isTypeTypeof());
5078 case Ttuple
: return visitTuple(tb
.isTypeTuple());
5079 case Tenum
: return false;
5080 default: return tb
.nextOf().reliesOnTemplateParameters(tparams
);
5084 /***********************************************************
5085 * Check whether the expression representation relies on one or more the template parameters.
5087 * e = expression to test
5088 * tparams = Template parameters.
5092 private bool reliesOnTemplateParameters(Expression e
, TemplateParameter
[] tparams
)
5094 extern (C
++) final class ReliesOnTemplateParameters
: Visitor
5096 alias visit
= Visitor
.visit
;
5098 TemplateParameter
[] tparams
;
5101 extern (D
) this(TemplateParameter
[] tparams
) @safe
5103 this.tparams
= tparams
;
5106 override void visit(Expression e
)
5108 //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
5111 override void visit(IdentifierExp e
)
5113 //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5114 foreach (tp
; tparams
)
5116 if (e
.ident
== tp
.ident
)
5124 override void visit(TupleExp e
)
5126 //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5129 foreach (ea
; *e
.exps
)
5138 override void visit(ArrayLiteralExp e
)
5140 //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5143 foreach (el
; *e
.elements
)
5152 override void visit(AssocArrayLiteralExp e
)
5154 //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5155 foreach (ek
; *e
.keys
)
5161 foreach (ev
; *e
.values
)
5169 override void visit(StructLiteralExp e
)
5171 //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5174 foreach (ea
; *e
.elements
)
5183 override void visit(TypeExp e
)
5185 //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5186 result
= e
.type
.reliesOnTemplateParameters(tparams
);
5189 override void visit(NewExp e
)
5191 //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5193 e
.thisexp
.accept(this);
5194 result
= e
.newtype
.reliesOnTemplateParameters(tparams
);
5195 if (!result
&& e
.arguments
)
5197 foreach (ea
; *e
.arguments
)
5206 override void visit(NewAnonClassExp e
)
5208 //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5212 override void visit(FuncExp e
)
5214 //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5218 override void visit(TypeidExp e
)
5220 //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5221 if (auto ea
= isExpression(e
.obj
))
5223 else if (auto ta
= isType(e
.obj
))
5224 result
= ta
.reliesOnTemplateParameters(tparams
);
5227 override void visit(TraitsExp e
)
5229 //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5232 foreach (oa
; *e
.args
)
5234 if (auto ea
= isExpression(oa
))
5236 else if (auto ta
= isType(oa
))
5237 result
= ta
.reliesOnTemplateParameters(tparams
);
5244 override void visit(IsExp e
)
5246 //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5247 result
= e
.targ
.reliesOnTemplateParameters(tparams
);
5250 override void visit(UnaExp e
)
5252 //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5256 override void visit(DotTemplateInstanceExp e
)
5258 //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5259 visit(e
.isUnaExp());
5260 if (!result
&& e
.ti
.tiargs
)
5262 foreach (oa
; *e
.ti
.tiargs
)
5264 if (auto ea
= isExpression(oa
))
5266 else if (auto ta
= isType(oa
))
5267 result
= ta
.reliesOnTemplateParameters(tparams
);
5274 override void visit(CallExp e
)
5276 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5277 visit(e
.isUnaExp());
5278 if (!result
&& e
.arguments
)
5280 foreach (ea
; *e
.arguments
)
5289 override void visit(CastExp e
)
5291 //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5292 visit(e
.isUnaExp());
5293 // e.to can be null for cast() with no type
5294 if (!result
&& e
.to
)
5295 result
= e
.to
.reliesOnTemplateParameters(tparams
);
5298 override void visit(SliceExp e
)
5300 //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5301 visit(e
.isUnaExp());
5302 if (!result
&& e
.lwr
)
5304 if (!result
&& e
.upr
)
5308 override void visit(IntervalExp e
)
5310 //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5316 override void visit(ArrayExp e
)
5318 //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5319 visit(e
.isUnaExp());
5320 if (!result
&& e
.arguments
)
5322 foreach (ea
; *e
.arguments
)
5327 override void visit(BinExp e
)
5329 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5335 override void visit(CondExp e
)
5337 //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
5338 e
.econd
.accept(this);
5340 visit(e
.isBinExp());
5344 scope ReliesOnTemplateParameters v
= new ReliesOnTemplateParameters(tparams
);
5349 /***********************************************************
5350 * https://dlang.org/spec/template.html#TemplateParameter
5352 extern (C
++) class TemplateParameter
: ASTNode
5357 /* True if this is a part of precedent parameter specialization pattern.
5359 * template A(T : X!TL, alias X, TL...) {}
5360 * // X and TL are dependent template parameter
5362 * A dependent template parameter should return MATCH.exact in matchArg()
5363 * to respect the match level of the corresponding precedent parameter.
5367 /* ======================== TemplateParameter =============================== */
5368 extern (D
) this(const ref Loc loc
, Identifier ident
) @safe
5374 TemplateTypeParameter
isTemplateTypeParameter()
5379 TemplateValueParameter
isTemplateValueParameter()
5384 TemplateAliasParameter
isTemplateAliasParameter()
5389 TemplateThisParameter
isTemplateThisParameter()
5394 TemplateTupleParameter
isTemplateTupleParameter()
5399 abstract TemplateParameter
syntaxCopy();
5401 abstract bool declareParameter(Scope
* sc
);
5403 abstract void print(RootObject oarg
, RootObject oded
);
5405 abstract RootObject
specialization();
5407 abstract RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
);
5409 abstract bool hasDefaultArg();
5411 override const(char)* toChars() const
5413 return this.ident
.toChars();
5416 override DYNCAST
dyncast() const
5418 return DYNCAST
.templateparameter
;
5421 /* Create dummy argument based on parameter.
5423 abstract RootObject
dummyArg();
5425 override void accept(Visitor v
)
5431 /***********************************************************
5432 * https://dlang.org/spec/template.html#TemplateTypeParameter
5434 * ident : specType = defaultType
5436 extern (C
++) class TemplateTypeParameter
: TemplateParameter
5438 Type specType
; // if !=null, this is the type specialization
5441 extern (D
) __gshared Type tdummy
= null;
5443 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, Type defaultType
) @safe
5446 this.specType
= specType
;
5447 this.defaultType
= defaultType
;
5450 override final TemplateTypeParameter
isTemplateTypeParameter()
5455 override TemplateTypeParameter
syntaxCopy()
5457 return new TemplateTypeParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, defaultType ? defaultType
.syntaxCopy() : null);
5460 override final bool declareParameter(Scope
* sc
)
5462 //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
5463 auto ti
= new TypeIdentifier(loc
, ident
);
5464 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
5465 return sc
.insert(ad
) !is null;
5468 override final void print(RootObject oarg
, RootObject oded
)
5470 printf(" %s\n", ident
.toChars());
5472 Type t
= isType(oarg
);
5473 Type ta
= isType(oded
);
5477 printf("\tSpecialization: %s\n", specType
.toChars());
5479 printf("\tDefault: %s\n", defaultType
.toChars());
5480 printf("\tParameter: %s\n", t ? t
.toChars() : "NULL");
5481 printf("\tDeduced Type: %s\n", ta
.toChars());
5484 override final RootObject
specialization()
5489 override final RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5491 Type t
= defaultType
;
5495 t
= t
.typeSemantic(loc
, sc
); // use the parameter loc
5500 override final bool hasDefaultArg()
5502 return defaultType
!is null;
5505 override final RootObject
dummyArg()
5510 // Use this for alias-parameter's too (?)
5512 tdummy
= new TypeIdentifier(loc
, ident
);
5518 override void accept(Visitor v
)
5524 /***********************************************************
5525 * https://dlang.org/spec/template.html#TemplateThisParameter
5527 * this ident : specType = defaultType
5529 extern (C
++) final class TemplateThisParameter
: TemplateTypeParameter
5531 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, Type defaultType
) @safe
5533 super(loc
, ident
, specType
, defaultType
);
5536 override TemplateThisParameter
isTemplateThisParameter()
5541 override TemplateThisParameter
syntaxCopy()
5543 return new TemplateThisParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, defaultType ? defaultType
.syntaxCopy() : null);
5546 override void accept(Visitor v
)
5552 /***********************************************************
5553 * https://dlang.org/spec/template.html#TemplateValueParameter
5555 * valType ident : specValue = defaultValue
5557 extern (C
++) final class TemplateValueParameter
: TemplateParameter
5560 Expression specValue
;
5561 Expression defaultValue
;
5563 extern (D
) __gshared Expression
[void*] edummies
;
5565 extern (D
) this(const ref Loc loc
, Identifier ident
, Type valType
,
5566 Expression specValue
, Expression defaultValue
) @safe
5569 this.valType
= valType
;
5570 this.specValue
= specValue
;
5571 this.defaultValue
= defaultValue
;
5574 override TemplateValueParameter
isTemplateValueParameter()
5579 override TemplateValueParameter
syntaxCopy()
5581 return new TemplateValueParameter(loc
, ident
,
5582 valType
.syntaxCopy(),
5583 specValue ? specValue
.syntaxCopy() : null,
5584 defaultValue ? defaultValue
.syntaxCopy() : null);
5587 override bool declareParameter(Scope
* sc
)
5590 Do type semantic earlier.
5592 This means for certain erroneous value parameters
5593 their "type" can be known earlier and thus a better
5594 error message given.
5597 `template test(x* x) {}`
5598 now yields "undefined identifier" rather than the opaque
5599 "variable `x` is used as a type".
5602 valType
= valType
.typeSemantic(loc
, sc
);
5603 auto v
= new VarDeclaration(loc
, valType
, ident
, null);
5604 v
.storage_class
= STC
.templateparameter
;
5605 return sc
.insert(v
) !is null;
5608 override void print(RootObject oarg
, RootObject oded
)
5610 printf(" %s\n", ident
.toChars());
5611 Expression ea
= isExpression(oded
);
5613 printf("\tSpecialization: %s\n", specValue
.toChars());
5614 printf("\tParameter Value: %s\n", ea ? ea
.toChars() : "NULL");
5617 override RootObject
specialization()
5622 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5624 Expression e
= defaultValue
;
5628 if ((e
= e
.expressionSemantic(sc
)) is null)
5630 if (auto te
= e
.isTemplateExp())
5632 assert(sc
&& sc
.tinst
);
5633 if (te
.td
== sc
.tinst
.tempdecl
)
5635 // defaultValue is a reference to its template declaration
5636 // i.e: `template T(int arg = T)`
5637 // Raise error now before calling resolveProperties otherwise we'll
5638 // start looping on the expansion of the template instance.
5639 auto td
= sc
.tinst
.tempdecl
;
5640 .error(td
.loc
, "%s `%s` recursive template expansion", td
.kind
, td
.toPrettyChars
);
5641 return ErrorExp
.get();
5644 if ((e
= resolveProperties(sc
, e
)) is null)
5646 e
= e
.resolveLoc(instLoc
, sc
); // use the instantiated loc
5647 e
= e
.optimize(WANTvalue
);
5652 override bool hasDefaultArg()
5654 return defaultValue
!is null;
5657 override RootObject
dummyArg()
5659 Expression e
= specValue
;
5662 // Create a dummy value
5663 auto pe
= cast(void*)valType
in edummies
;
5666 e
= valType
.defaultInit(Loc
.initial
);
5667 edummies
[cast(void*)valType
] = e
;
5675 override void accept(Visitor v
)
5681 /***********************************************************
5682 * https://dlang.org/spec/template.html#TemplateAliasParameter
5684 * specType ident : specAlias = defaultAlias
5686 extern (C
++) final class TemplateAliasParameter
: TemplateParameter
5689 RootObject specAlias
;
5690 RootObject defaultAlias
;
5692 extern (D
) __gshared Dsymbol sdummy
= null;
5694 extern (D
) this(const ref Loc loc
, Identifier ident
, Type specType
, RootObject specAlias
, RootObject defaultAlias
) @safe
5697 this.specType
= specType
;
5698 this.specAlias
= specAlias
;
5699 this.defaultAlias
= defaultAlias
;
5702 override TemplateAliasParameter
isTemplateAliasParameter()
5707 override TemplateAliasParameter
syntaxCopy()
5709 return new TemplateAliasParameter(loc
, ident
, specType ? specType
.syntaxCopy() : null, objectSyntaxCopy(specAlias
), objectSyntaxCopy(defaultAlias
));
5712 override bool declareParameter(Scope
* sc
)
5714 auto ti
= new TypeIdentifier(loc
, ident
);
5715 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
5716 return sc
.insert(ad
) !is null;
5719 override void print(RootObject oarg
, RootObject oded
)
5721 printf(" %s\n", ident
.toChars());
5722 Dsymbol sa
= isDsymbol(oded
);
5724 printf("\tParameter alias: %s\n", sa
.toChars());
5727 override RootObject
specialization()
5732 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5734 RootObject
da = defaultAlias
;
5735 if (auto ta
= isType(defaultAlias
))
5739 // If the default arg is a template, instantiate for each type
5741 // same if the default arg is a mixin, traits, typeof
5742 // since the content might rely on a previous parameter
5743 // (https://issues.dlang.org/show_bug.cgi?id=23686)
5744 case Tmixin
, Ttypeof
, Ttraits
:
5745 da = ta
.syntaxCopy();
5751 RootObject o
= aliasParameterSemantic(loc
, sc
, da, null); // use the parameter loc
5755 override bool hasDefaultArg()
5757 return defaultAlias
!is null;
5760 override RootObject
dummyArg()
5762 RootObject s
= specAlias
;
5766 sdummy
= new Dsymbol();
5772 override void accept(Visitor v
)
5778 /***********************************************************
5779 * https://dlang.org/spec/template.html#TemplateSequenceParameter
5783 extern (C
++) final class TemplateTupleParameter
: TemplateParameter
5785 extern (D
) this(const ref Loc loc
, Identifier ident
) @safe
5790 override TemplateTupleParameter
isTemplateTupleParameter()
5795 override TemplateTupleParameter
syntaxCopy()
5797 return new TemplateTupleParameter(loc
, ident
);
5800 override bool declareParameter(Scope
* sc
)
5802 auto ti
= new TypeIdentifier(loc
, ident
);
5803 Declaration ad
= new AliasDeclaration(loc
, ident
, ti
);
5804 return sc
.insert(ad
) !is null;
5807 override void print(RootObject oarg
, RootObject oded
)
5809 printf(" %s... [", ident
.toChars());
5810 Tuple v
= isTuple(oded
);
5813 //printf("|%d| ", v.objects.length);
5814 foreach (i
, o
; v
.objects
)
5819 Dsymbol sa
= isDsymbol(o
);
5821 printf("alias: %s", sa
.toChars());
5822 Type ta
= isType(o
);
5824 printf("type: %s", ta
.toChars());
5825 Expression ea
= isExpression(o
);
5827 printf("exp: %s", ea
.toChars());
5829 assert(!isTuple(o
)); // no nested Tuple arguments
5834 override RootObject
specialization()
5839 override RootObject
defaultArg(const ref Loc instLoc
, Scope
* sc
)
5844 override bool hasDefaultArg()
5849 override RootObject
dummyArg()
5854 override void accept(Visitor v
)
5860 /***********************************************************
5861 * https://dlang.org/spec/template.html#explicit_tmp_instantiation
5867 extern (C
++) class TemplateInstance
: ScopeDsymbol
5871 // Array of Types/Expressions of template
5872 // instance arguments [int*, char, 10*10]
5875 // Array of Types/Expressions corresponding
5876 // to TemplateDeclaration.parameters
5880 // Modules imported by this template instance
5881 Modules importedModules
;
5883 Dsymbol tempdecl
; // referenced by foo.bar.abc
5884 Dsymbol enclosing
; // if referencing local symbols, this is the context
5885 Dsymbol aliasdecl
; // !=null if instance is an alias for its sole member
5886 TemplateInstance inst
; // refer to existing instance
5887 ScopeDsymbol argsym
; // argument symbol table
5888 size_t hash
; // cached result of toHash()
5889 Expressions
* fargs
; // for function template, these are the function arguments
5891 TemplateInstances
* deferred
;
5893 Module memberOf
; // if !null, then this TemplateInstance appears in memberOf.members[]
5895 // Used to determine the instance needs code generation.
5896 // Note that these are inaccurate until semantic analysis phase completed.
5897 TemplateInstance tinst
; // enclosing template instance
5898 TemplateInstance tnext
; // non-first instantiated instances
5899 Module minst
; // the top module that instantiated this instance
5901 private ushort _nest
; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
5902 ubyte inuse
; // for recursive expansion detection
5904 private enum Flag
: uint
5906 semantictiargsdone
= 1u << (_nest
.sizeof
* 8 - 1), // MSB of _nest
5907 havetempdecl
= semantictiargsdone
>> 1,
5908 gagged
= semantictiargsdone
>> 2,
5909 available
= gagged
- 1 // always last flag minus one, 1s for all available bits
5912 extern(D
) final @safe @property pure nothrow @nogc
5914 ushort nest() const { return _nest
& Flag
.available
; }
5915 void nestUp() { assert(nest() < Flag
.available
); ++_nest
; }
5916 void nestDown() { assert(nest() > 0); --_nest
; }
5917 /// has semanticTiargs() been done?
5918 bool semantictiargsdone() const { return (_nest
& Flag
.semantictiargsdone
) != 0; }
5919 void semantictiargsdone(bool x
)
5921 if (x
) _nest |
= Flag
.semantictiargsdone
;
5922 else _nest
&= ~Flag
.semantictiargsdone
;
5924 /// if used second constructor
5925 bool havetempdecl() const { return (_nest
& Flag
.havetempdecl
) != 0; }
5926 void havetempdecl(bool x
)
5928 if (x
) _nest |
= Flag
.havetempdecl
;
5929 else _nest
&= ~Flag
.havetempdecl
;
5931 /// if the instantiation is done with error gagging
5932 bool gagged() const { return (_nest
& Flag
.gagged
) != 0; }
5935 if (x
) _nest |
= Flag
.gagged
;
5936 else _nest
&= ~Flag
.gagged
;
5940 extern (D
) this(const ref Loc loc
, Identifier ident
, Objects
* tiargs
) scope
5945 printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident
.toChars() : "null");
5948 this.tiargs
= tiargs
;
5952 * This constructor is only called when we figured out which function
5953 * template to instantiate.
5955 extern (D
) this(const ref Loc loc
, TemplateDeclaration td
, Objects
* tiargs
) scope
5960 printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td
.toChars());
5962 this.name
= td
.ident
;
5963 this.tiargs
= tiargs
;
5965 this.semantictiargsdone
= true;
5966 this.havetempdecl
= true;
5967 assert(tempdecl
._scope
);
5970 extern (D
) static Objects
* arraySyntaxCopy(Objects
* objs
)
5975 a
= new Objects(objs
.length
);
5976 foreach (i
, o
; *objs
)
5977 (*a
)[i
] = objectSyntaxCopy(o
);
5982 override TemplateInstance
syntaxCopy(Dsymbol s
)
5984 TemplateInstance ti
= s ?
cast(TemplateInstance
)s
: new TemplateInstance(loc
, name
, null);
5985 ti
.tiargs
= arraySyntaxCopy(tiargs
);
5986 TemplateDeclaration td
;
5987 if (inst
&& tempdecl
&& (td
= tempdecl
.isTemplateDeclaration()) !is null)
5988 td
.ScopeDsymbol
.syntaxCopy(ti
);
5990 ScopeDsymbol
.syntaxCopy(ti
);
5994 // resolve real symbol
5995 override final Dsymbol
toAlias()
5999 printf("TemplateInstance.toAlias()\n");
6003 // Maybe we can resolve it
6006 dsymbolSemantic(this, _scope
);
6010 .error(loc
, "%s `%s` cannot resolve forward reference", kind
, toPrettyChars
);
6017 return inst
.toAlias();
6021 return aliasdecl
.toAlias();
6027 override const(char)* kind() const
6029 return "template instance";
6032 override bool oneMember(Dsymbol
* ps
, Identifier ident
)
6038 override const(char)* toChars() const
6041 toCBufferInstance(this, buf
);
6042 return buf
.extractChars();
6045 override final const(char)* toPrettyCharsHelper()
6048 toCBufferInstance(this, buf
, true);
6049 return buf
.extractChars();
6052 /**************************************
6053 * Given an error instantiating the TemplateInstance,
6054 * give the nested TemplateInstance instantiations that got
6055 * us here. Those are a list threaded into the nested scopes.
6057 * cl = classification of this trace as printing either errors or deprecations
6058 * max_shown = maximum number of trace elements printed (controlled with -v/-verror-limit)
6060 extern(D
) final void printInstantiationTrace(Classification cl
= Classification
.error
,
6061 const(uint) max_shown
= global
.params
.v
.errorSupplementCount())
6066 // Print full trace for verbose mode, otherwise only short traces
6067 const(char)* format
= "instantiated from here: `%s`";
6069 // This returns a function pointer
6070 scope printFn
= () {
6073 case Classification
.error
:
6074 return &errorSupplemental
;
6075 case Classification
.deprecation
:
6076 return &deprecationSupplemental
;
6077 case Classification
.gagged
, Classification
.tip
, Classification
.warning
:
6082 // determine instantiation depth and number of recursive instantiations
6083 int n_instantiations
= 1;
6084 int n_totalrecursions
= 0;
6085 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6088 // Set error here as we don't want it to depend on the number of
6089 // entries that are being printed.
6090 if (cl
== Classification
.error ||
6091 (cl
== Classification
.warning
&& global
.params
.warnings
== DiagnosticReporting
.error
) ||
6092 (cl
== Classification
.deprecation
&& global
.params
.useDeprecated
== DiagnosticReporting
.error
))
6095 // If two instantiations use the same declaration, they are recursive.
6096 // (this works even if they are instantiated from different places in the
6098 // In principle, we could also check for multiple-template recursion, but it's
6099 // probably not worthwhile.
6100 if (cur
.tinst
&& cur
.tempdecl
&& cur
.tinst
.tempdecl
&& cur
.tempdecl
.loc
.equals(cur
.tinst
.tempdecl
.loc
))
6101 ++n_totalrecursions
;
6104 if (n_instantiations
<= max_shown
)
6106 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6107 printFn(cur
.loc
, format
, cur
.toChars());
6109 else if (n_instantiations
- n_totalrecursions
<= max_shown
)
6111 // By collapsing recursive instantiations into a single line,
6112 // we can stay under the limit.
6113 int recursionDepth
= 0;
6114 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6116 if (cur
.tinst
&& cur
.tempdecl
&& cur
.tinst
.tempdecl
&& cur
.tempdecl
.loc
.equals(cur
.tinst
.tempdecl
.loc
))
6123 printFn(cur
.loc
, "%d recursive instantiations from here: `%s`", recursionDepth
+ 2, cur
.toChars());
6125 printFn(cur
.loc
, format
, cur
.toChars());
6132 // Even after collapsing the recursions, the depth is too deep.
6133 // Just display the first few and last few instantiations.
6135 for (TemplateInstance cur
= this; cur
; cur
= cur
.tinst
)
6137 if (i
== max_shown
/ 2)
6138 printFn(cur
.loc
, "... (%d instantiations, -v to show) ...", n_instantiations
- max_shown
);
6140 if (i
< max_shown
/ 2 || i
>= n_instantiations
- max_shown
+ max_shown
/ 2)
6141 printFn(cur
.loc
, format
, cur
.toChars());
6147 /*************************************
6148 * Lazily generate identifier for template instance.
6149 * This is because 75% of the ident's are never needed.
6151 override final Identifier
getIdent()
6153 if (!ident
&& inst
&& !errors
)
6154 ident
= genIdent(tiargs
); // need an identifier for name mangling purposes.
6158 /*************************************
6159 * Compare proposed template instantiation with existing template instantiation.
6160 * Note that this is not commutative because of the auto ref check.
6162 * ti = existing template instantiation
6166 final bool equalsx(TemplateInstance ti
)
6168 //printf("this = %p, ti = %p\n", this, ti);
6169 assert(tdtypes
.length
== ti
.tdtypes
.length
);
6171 // Nesting must match
6172 if (enclosing
!= ti
.enclosing
)
6174 //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
6177 //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
6179 if (!arrayObjectMatch(&tdtypes
, &ti
.tdtypes
))
6182 /* Template functions may have different instantiations based on
6183 * "auto ref" parameters.
6185 if (auto fd
= ti
.toAlias().isFuncDeclaration())
6189 auto fparameters
= fd
.getParameterList();
6190 size_t nfparams
= fparameters
.length
; // Num function parameters
6191 for (size_t j
= 0; j
< nfparams
; j
++)
6193 Parameter fparam
= fparameters
[j
];
6194 if (fparam
.storageClass
& STC
.autoref
) // if "auto ref"
6196 Expression farg
= fargs
&& j
< fargs
.length ?
(*fargs
)[j
] : fparam
.defaultArg
;
6199 if (farg
.isLvalue())
6201 if (!(fparam
.storageClass
& STC
.ref_
))
6202 goto Lnotequals
; // auto ref's don't match
6206 if (fparam
.storageClass
& STC
.ref_
)
6207 goto Lnotequals
; // auto ref's don't match
6219 extern (D
) final size_t
toHash()
6223 hash
= cast(size_t
)cast(void*)enclosing
;
6224 hash
+= arrayObjectHash(&tdtypes
);
6231 Returns: true if the instances' innards are discardable.
6233 The idea of this function is to see if the template instantiation
6234 can be 100% replaced with its eponymous member. All other members
6235 can be discarded, even in the compiler to free memory (for example,
6236 the template could be expanded in a region allocator, deemed trivial,
6237 the end result copied back out independently and the entire region freed),
6238 and can be elided entirely from the binary.
6240 The current implementation affects code that generally looks like:
6243 template foo(args...) {
6244 some_basic_type_or_string helper() { .... }
6245 enum foo = helper();
6249 since it was the easiest starting point of implementation but it can and
6250 should be expanded more later.
6252 final bool isDiscardable()
6254 if (aliasdecl
is null)
6257 auto v
= aliasdecl
.isVarDeclaration();
6261 if (!(v
.storage_class
& STC
.manifest
))
6264 // Currently only doing basic types here because it is the easiest proof-of-concept
6265 // implementation with minimal risk of side effects, but it could likely be
6266 // expanded to any type that already exists outside this particular instance.
6267 if (!(v
.type
.equals(Type
.tstring
) ||
(v
.type
.isTypeBasic() !is null)))
6270 // Static ctors and dtors, even in an eponymous enum template, are still run,
6271 // so if any of them are in here, we'd better not assume it is trivial lest
6272 // we break useful code
6273 foreach(member
; *members
)
6275 if(member
.hasStaticCtorOrDtor())
6277 if(member
.isStaticDtorDeclaration())
6279 if(member
.isStaticCtorDeclaration())
6283 // but if it passes through this gauntlet... it should be fine. D code will
6284 // see only the eponymous member, outside stuff can never access it, even through
6285 // reflection; the outside world ought to be none the wiser. Even dmd should be
6286 // able to simply free the memory of everything except the final result.
6292 /***********************************************
6293 * Returns true if this is not instantiated in non-root module, and
6294 * is a part of non-speculative instantiatiation.
6296 * Note: minst does not stabilize until semantic analysis is completed,
6297 * so don't call this function during semantic analysis to return precise result.
6299 final bool needsCodegen()
6301 //printf("needsCodegen() %s\n", toChars());
6303 // minst is finalized after the 1st invocation.
6304 // tnext is only needed for the 1st invocation and
6305 // cleared for further invocations.
6306 TemplateInstance tnext
= this.tnext
;
6307 TemplateInstance tinst
= this.tinst
;
6310 // Don't do codegen if the instance has errors,
6311 // is a dummy instance (see evaluateConstraint),
6312 // or is determined to be discardable.
6313 if (errors || inst
is null || inst
.isDiscardable())
6315 minst
= null; // mark as speculative
6319 // This should only be called on the primary instantiation.
6320 assert(this is inst
);
6322 if (global
.params
.allInst
)
6324 // Do codegen if there is an instantiation from a root module, to maximize link-ability.
6325 static ThreeState
needsCodegenAllInst(TemplateInstance tithis
, TemplateInstance tinst
)
6327 // Do codegen if `this` is instantiated from a root module.
6328 if (tithis
.minst
&& tithis
.minst
.isRoot())
6329 return ThreeState
.yes
;
6331 // Do codegen if the ancestor needs it.
6332 if (tinst
&& tinst
.inst
&& tinst
.inst
.needsCodegen())
6334 tithis
.minst
= tinst
.inst
.minst
; // cache result
6335 assert(tithis
.minst
);
6336 assert(tithis
.minst
.isRoot());
6337 return ThreeState
.yes
;
6339 return ThreeState
.none
;
6342 if (const needsCodegen
= needsCodegenAllInst(this, tinst
))
6343 return needsCodegen
== ThreeState
.yes ?
true : false;
6345 // Do codegen if a sibling needs it.
6346 for (; tnext
; tnext
= tnext
.tnext
)
6348 const needsCodegen
= needsCodegenAllInst(tnext
, tnext
.tinst
);
6349 if (needsCodegen
== ThreeState
.yes
)
6351 minst
= tnext
.minst
; // cache result
6353 assert(minst
.isRoot());
6356 else if (!minst
&& tnext
.minst
)
6358 minst
= tnext
.minst
; // cache result from non-speculative sibling
6359 // continue searching
6361 else if (needsCodegen
!= ThreeState
.none
)
6365 // Elide codegen because there's no instantiation from any root modules.
6370 // Prefer instantiations from non-root modules, to minimize object code size.
6372 /* If a TemplateInstance is ever instantiated from a non-root module,
6373 * we do not have to generate code for it,
6374 * because it will be generated when the non-root module is compiled.
6376 * But, if the non-root 'minst' imports any root modules, it might still need codegen.
6378 * The problem is if A imports B, and B imports A, and both A
6379 * and B instantiate the same template, does the compilation of A
6380 * or the compilation of B do the actual instantiation?
6382 * See https://issues.dlang.org/show_bug.cgi?id=2500.
6384 * => Elide codegen if there is at least one instantiation from a non-root module
6385 * which doesn't import any root modules.
6387 static ThreeState
needsCodegenRootOnly(TemplateInstance tithis
, TemplateInstance tinst
)
6389 // If the ancestor isn't speculative,
6390 // 1. do codegen if the ancestor needs it
6391 // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
6392 if (tinst
&& tinst
.inst
)
6395 const needsCodegen
= tinst
.needsCodegen(); // sets tinst.minst
6396 if (tinst
.minst
) // not speculative
6398 tithis
.minst
= tinst
.minst
; // cache result
6399 return needsCodegen ? ThreeState
.yes
: ThreeState
.no
;
6403 // Elide codegen if `this` doesn't need it.
6404 if (tithis
.minst
&& !tithis
.minst
.isRoot() && !tithis
.minst
.rootImports())
6405 return ThreeState
.no
;
6407 return ThreeState
.none
;
6410 if (const needsCodegen
= needsCodegenRootOnly(this, tinst
))
6411 return needsCodegen
== ThreeState
.yes ?
true : false;
6413 // Elide codegen if a (non-speculative) sibling doesn't need it.
6414 for (; tnext
; tnext
= tnext
.tnext
)
6416 const needsCodegen
= needsCodegenRootOnly(tnext
, tnext
.tinst
); // sets tnext.minst
6417 if (tnext
.minst
) // not speculative
6419 if (needsCodegen
== ThreeState
.no
)
6421 minst
= tnext
.minst
; // cache result
6422 assert(!minst
.isRoot() && !minst
.rootImports());
6427 minst
= tnext
.minst
; // cache result from non-speculative sibling
6428 // continue searching
6430 else if (needsCodegen
!= ThreeState
.none
)
6435 // Unless `this` is still speculative (=> all further siblings speculative too),
6436 // do codegen because we found no guaranteed-codegen'd non-root instantiation.
6437 return minst
!is null;
6441 /**********************************************
6442 * Find template declaration corresponding to template instance.
6445 * false if finding fails.
6447 * This function is reentrant against error occurrence. If returns false,
6448 * any members of this object won't be modified, and repetition call will
6449 * reproduce same error.
6451 extern (D
) final bool findTempDecl(Scope
* sc
, WithScopeSymbol
* pwithsym
)
6459 //printf("TemplateInstance.findTempDecl() %s\n", toChars());
6464 * figure out which TemplateDeclaration foo refers to.
6466 Identifier id
= name
;
6468 Dsymbol s
= sc
.search(loc
, id
, scopesym
);
6471 s
= sc
.search_correct(id
);
6473 .error(loc
, "%s `%s` template `%s` is not defined, did you mean %s?", kind
, toPrettyChars
, id
.toChars(), s
.toChars());
6475 .error(loc
, "%s `%s` template `%s` is not defined", kind
, toPrettyChars
, id
.toChars());
6480 printf("It's an instance of '%s' kind '%s'\n", s
.toChars(), s
.kind());
6482 printf("s.parent = '%s'\n", s
.parent
.toChars());
6485 *pwithsym
= scopesym
.isWithScopeSymbol();
6487 /* We might have found an alias within a template when
6488 * we really want the template.
6490 TemplateInstance ti
;
6491 if (s
.parent
&& (ti
= s
.parent
.isTemplateInstance()) !is null)
6493 if (ti
.tempdecl
&& ti
.tempdecl
.ident
== id
)
6495 /* This is so that one can refer to the enclosing
6496 * template, even if it has the same name as a member
6497 * of the template, if it has a !(arguments)
6499 TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration();
6501 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
6502 td
= td
.overroot
; // then get the start
6507 // The template might originate from a selective import which implies that
6508 // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
6509 // This is the last place where we see the deprecated alias because it is
6510 // stripped below, so check if the selective import was deprecated.
6511 // See https://issues.dlang.org/show_bug.cgi?id=20840.
6512 if (s
.isAliasDeclaration())
6513 s
.checkDeprecated(this.loc
, sc
);
6515 if (!updateTempDecl(sc
, s
))
6522 // Look for forward references
6523 auto tovers
= tempdecl
.isOverloadSet();
6524 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
6526 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
6527 int r
= overloadApply(dstart
, (Dsymbol s
)
6529 auto td
= s
.isTemplateDeclaration();
6533 if (td
.semanticRun
== PASS
.initial
)
6537 // Try to fix forward reference. Ungag errors while doing so.
6538 Ungag ungag
= td
.ungagSpeculative();
6539 td
.dsymbolSemantic(td
._scope
);
6541 if (td
.semanticRun
== PASS
.initial
)
6543 .error(loc
, "%s `%s` `%s` forward references template declaration `%s`", kind
, toPrettyChars
,
6544 toChars(), td
.toChars());
6556 /**********************************************
6557 * Confirm s is a valid template, then store it.
6560 * s candidate symbol of template. It may be:
6561 * TemplateDeclaration
6562 * FuncDeclaration with findTemplateDeclRoot() != NULL
6563 * OverloadSet which contains candidates
6565 * true if updating succeeds.
6567 extern (D
) final bool updateTempDecl(Scope
* sc
, Dsymbol s
)
6570 return tempdecl
!is null;
6572 Identifier id
= name
;
6575 /* If an OverloadSet, look for a unique member that is a template declaration
6577 if (OverloadSet os
= s
.isOverloadSet())
6582 if (FuncDeclaration f
= s2
.isFuncDeclaration())
6583 s2
= f
.findTemplateDeclRoot();
6585 s2
= s2
.isTemplateDeclaration();
6598 .error(loc
, "%s `%s` template `%s` is not defined", kind
, toPrettyChars
, id
.toChars());
6603 if (OverDeclaration od
= s
.isOverDeclaration())
6605 tempdecl
= od
; // TODO: more strict check
6609 /* It should be a TemplateDeclaration, not some other symbol
6611 if (FuncDeclaration f
= s
.isFuncDeclaration())
6612 tempdecl
= f
.findTemplateDeclRoot();
6614 tempdecl
= s
.isTemplateDeclaration();
6620 // Error already issued, just return `false`
6621 if (!s
.parent
&& global
.errors
)
6624 if (!s
.parent
&& s
.getType())
6626 Dsymbol s2
= s
.getType().toDsymbol(sc
);
6629 .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());
6632 // because s can be the alias created for a TemplateParameter
6633 const AliasDeclaration ad
= s
.isAliasDeclaration();
6636 if (ad
&& ad
.isAliasedTemplateParameter())
6637 printf("`%s` is an alias created from a template parameter\n", s
.toChars());
6639 if (!ad ||
!ad
.isAliasedTemplateParameter())
6643 TemplateInstance ti
= s
.parent ? s
.parent
.isTemplateInstance() : null;
6645 /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
6647 static bool matchId(TemplateInstance ti
, Identifier id
)
6649 if (ti
.aliasdecl
&& ti
.aliasdecl
.isVarDeclaration())
6650 return ti
.aliasdecl
.isVarDeclaration().ident
== id
;
6651 return ti
.toAlias().ident
== id
;
6654 if (ti
&& (ti
.name
== s
.ident ||
matchId(ti
, s
.ident
)) && ti
.tempdecl
)
6656 /* This is so that one can refer to the enclosing
6657 * template, even if it has the same name as a member
6658 * of the template, if it has a !(arguments)
6660 TemplateDeclaration td
= ti
.tempdecl
.isTemplateDeclaration();
6662 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
6663 td
= td
.overroot
; // then get the start
6669 .error(loc
, "%s `%s` `%s` is not a template declaration, it is a %s", kind
, toPrettyChars
, id
.toChars(), s
.kind());
6674 /**********************************
6675 * Run semantic of tiargs as arguments of template.
6679 * tiargs array of template arguments
6680 * flags 1: replace const variables with their initializers
6681 * 2: don't devolve Parameter to Type
6682 * atd tuple being optimized. If found, it's not expanded here
6683 * but in AliasAssign semantic.
6685 * false if one or more arguments have errors.
6687 extern (D
) static bool semanticTiargs(const ref Loc loc
, Scope
* sc
, Objects
* tiargs
, int flags
, TupleDeclaration atd
= null)
6689 // Run semantic on each argument, place results in tiargs[]
6690 //printf("+TemplateInstance.semanticTiargs()\n");
6694 for (size_t j
= 0; j
< tiargs
.length
; j
++)
6696 RootObject o
= (*tiargs
)[j
];
6697 Type ta
= isType(o
);
6698 Expression ea
= isExpression(o
);
6699 Dsymbol sa
= isDsymbol(o
);
6701 //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
6704 //printf("type %s\n", ta.toChars());
6706 // It might really be an Expression or an Alias
6707 ta
.resolve(loc
, sc
, ea
, ta
, sa
, (flags
& 1) != 0);
6714 assert(global
.errors
);
6719 if (ta
.ty
== Ttuple
)
6722 TypeTuple tt
= cast(TypeTuple
)ta
;
6723 size_t dim
= tt
.arguments
.length
;
6727 tiargs
.reserve(dim
);
6728 foreach (i
, arg
; *tt
.arguments
)
6730 if (flags
& 2 && (arg
.storageClass
& STC
.parameter
))
6731 tiargs
.insert(j
+ i
, arg
);
6733 tiargs
.insert(j
+ i
, arg
.type
);
6739 if (ta
.ty
== Terror
)
6744 (*tiargs
)[j
] = ta
.merge2();
6749 //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6750 if (flags
& 1) // only used by __traits
6752 ea
= ea
.expressionSemantic(sc
);
6754 // must not interpret the args, excepting template parameters
6755 if (!ea
.isVarExp() ||
(ea
.isVarExp().var
.storage_class
& STC
.templateparameter
))
6757 ea
= ea
.optimize(WANTvalue
);
6762 sc
= sc
.startCTFE();
6763 ea
= ea
.expressionSemantic(sc
);
6766 if (auto varExp
= ea
.isVarExp())
6768 /* If the parameter is a function that is not called
6769 * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
6770 * then it is a dsymbol, not the return value of `func()`
6772 Declaration vd
= varExp
.var
;
6773 if (auto fd
= vd
.isFuncDeclaration())
6778 /* Otherwise skip substituting a const var with
6779 * its initializer. The problem is the initializer won't
6780 * match with an 'alias' parameter. Instead, do the
6781 * const substitution in TemplateValueParameter.matchArg().
6784 else if (definitelyValueParameter(ea
))
6786 if (ea
.checkValue()) // check void expression
6787 ea
= ErrorExp
.get();
6788 uint olderrs
= global
.errors
;
6789 ea
= ea
.ctfeInterpret();
6790 if (global
.errors
!= olderrs
)
6791 ea
= ErrorExp
.get();
6794 //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
6795 if (TupleExp te
= ea
.isTupleExp())
6798 size_t dim
= te
.exps
.length
;
6802 tiargs
.reserve(dim
);
6803 foreach (i
, exp
; *te
.exps
)
6804 tiargs
.insert(j
+ i
, exp
);
6809 if (ea
.op
== EXP
.error
)
6816 if (ea
.op
== EXP
.type
)
6821 if (ea
.op
== EXP
.scope_
)
6823 sa
= ea
.isScopeExp().sds
;
6826 if (FuncExp fe
= ea
.isFuncExp())
6828 /* A function literal, that is passed to template and
6829 * already semanticed as function pointer, never requires
6830 * outer frame. So convert it to global function is valid.
6832 if (fe
.fd
.tok
== TOK
.reserved
&& fe
.type
.ty
== Tpointer
)
6834 // change to non-nested
6835 fe
.fd
.tok
= TOK
.function_
;
6840 /* If template argument is a template lambda,
6841 * get template declaration itself. */
6846 if (ea
.op
== EXP
.dotVariable
&& !(flags
& 1))
6848 // translate expression to dsymbol.
6849 sa
= ea
.isDotVarExp().var
;
6852 if (auto te
= ea
.isTemplateExp())
6857 if (ea
.op
== EXP
.dotTemplateDeclaration
&& !(flags
& 1))
6859 // translate expression to dsymbol.
6860 sa
= ea
.isDotTemplateExp().td
;
6863 if (auto de = ea
.isDotExp())
6865 if (auto se
= de.e2
.isScopeExp())
6875 //printf("dsym %s %s\n", sa.kind(), sa.toChars());
6882 TupleDeclaration d
= sa
.toAlias().isTupleDeclaration();
6892 tiargs
.insert(j
, d
.objects
);
6896 if (FuncAliasDeclaration fa
= sa
.isFuncAliasDeclaration())
6898 FuncDeclaration f
= fa
.toAliasFunc();
6899 if (!fa
.hasOverloads
&& f
.isUnique())
6901 // Strip FuncAlias only when the aliased function
6902 // does not have any overloads.
6908 TemplateDeclaration td
= sa
.isTemplateDeclaration();
6909 if (td
&& td
.semanticRun
== PASS
.initial
&& td
.literal
)
6911 td
.dsymbolSemantic(sc
);
6913 FuncDeclaration fd
= sa
.isFuncDeclaration();
6915 fd
.functionSemantic();
6917 else if (isParameter(o
))
6924 //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
6928 printf("-TemplateInstance.semanticTiargs()\n");
6929 for (size_t j
= 0; j
< tiargs
.length
; j
++)
6931 RootObject o
= (*tiargs
)[j
];
6932 Type ta
= isType(o
);
6933 Expression ea
= isExpression(o
);
6934 Dsymbol sa
= isDsymbol(o
);
6935 Tuple va
= isTuple(o
);
6936 printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j
, ta
, ea
, sa
, va
);
6942 /**********************************
6943 * Run semantic on the elements of tiargs.
6947 * false if one or more arguments have errors.
6949 * This function is reentrant against error occurrence. If returns false,
6950 * all elements of tiargs won't be modified.
6952 extern (D
) final bool semanticTiargs(Scope
* sc
)
6954 //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
6955 if (semantictiargsdone
)
6957 if (semanticTiargs(loc
, sc
, tiargs
, 0))
6959 // cache the result iff semantic analysis succeeded entirely
6960 semantictiargsdone
= 1;
6966 /**********************************
6967 * Find the TemplateDeclaration that matches this TemplateInstance best.
6970 * sc = the scope this TemplateInstance resides in
6971 * argumentList = function arguments in case of a template function
6974 * `true` if a match was found, `false` otherwise
6976 extern (D
) final bool findBestMatch(Scope
* sc
, ArgumentList argumentList
)
6980 TemplateDeclaration tempdecl
= this.tempdecl
.isTemplateDeclaration();
6982 assert(tempdecl
._scope
);
6984 tdtypes
.setDim(tempdecl
.parameters
.length
);
6985 if (!tempdecl
.matchWithInstance(sc
, this, &tdtypes
, argumentList
, 2))
6987 .error(loc
, "%s `%s` incompatible arguments for template instantiation", kind
, toPrettyChars
);
6990 // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
6996 printf("TemplateInstance.findBestMatch()\n");
6999 uint errs
= global
.errors
;
7000 TemplateDeclaration td_last
= null;
7003 /* Since there can be multiple TemplateDeclaration's with the same
7004 * name, look for the best match.
7006 auto tovers
= tempdecl
.isOverloadSet();
7007 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
7009 TemplateDeclaration td_best
;
7010 TemplateDeclaration td_ambig
;
7011 MATCH m_best
= MATCH
.nomatch
;
7013 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
7014 overloadApply(dstart
, (Dsymbol s
)
7016 auto td
= s
.isTemplateDeclaration();
7019 if (td
== td_best
) // skip duplicates
7022 //printf("td = %s\n", td.toPrettyChars());
7023 // If more arguments than parameters,
7024 // then this is no match.
7025 if (td
.parameters
.length
< tiargs
.length
)
7027 if (!td
.isVariadic())
7031 dedtypes
.setDim(td
.parameters
.length
);
7033 assert(td
.semanticRun
!= PASS
.initial
);
7035 MATCH m
= td
.matchWithInstance(sc
, this, &dedtypes
, argumentList
, 0);
7036 //printf("matchWithInstance = %d\n", m);
7037 if (m
== MATCH
.nomatch
) // no match at all
7039 if (m
< m_best
) goto Ltd_best
;
7040 if (m
> m_best
) goto Ltd
;
7042 // Disambiguate by picking the most specialized TemplateDeclaration
7044 MATCH c1
= td
.leastAsSpecialized(sc
, td_best
, argumentList
);
7045 MATCH c2
= td_best
.leastAsSpecialized(sc
, td
, argumentList
);
7046 //printf("c1 = %d, c2 = %d\n", c1, c2);
7047 if (c1
> c2
) goto Ltd
;
7048 if (c1
< c2
) goto Ltd_best
;
7055 // td_best is the best match so far
7060 // td is the new best match
7064 tdtypes
.setDim(dedtypes
.length
);
7065 memcpy(tdtypes
.tdata(), dedtypes
.tdata(), tdtypes
.length
* (void*).sizeof
);
7071 .error(loc
, "%s `%s.%s` matches more than one template declaration:",
7072 td_best
.kind(), td_best
.parent
.toPrettyChars(), td_best
.ident
.toChars());
7073 .errorSupplemental(td_best
.loc
, "`%s`\nand:", td_best
.toChars());
7074 .errorSupplemental(td_ambig
.loc
, "`%s`", td_ambig
.toChars());
7081 else if (td_last
!= td_best
)
7083 ScopeDsymbol
.multiplyDefined(loc
, td_last
, td_best
);
7091 /* https://issues.dlang.org/show_bug.cgi?id=7469
7092 * Normalize tiargs by using corresponding deduced
7093 * template value parameters and tuples for the correct mangling.
7095 * By doing this before hasNestedArgs, CTFEable local variable will be
7096 * accepted as a value parameter. For example:
7099 * struct S(int n) {} // non-global template
7100 * const int num = 1; // CTFEable local variable
7101 * S!num s; // S!1 is instantiated, not S!num
7104 size_t dim
= td_last
.parameters
.length
- (td_last
.isVariadic() ?
1 : 0);
7105 for (size_t i
= 0; i
< dim
; i
++)
7107 if (tiargs
.length
<= i
)
7108 tiargs
.push(tdtypes
[i
]);
7109 assert(i
< tiargs
.length
);
7111 auto tvp
= (*td_last
.parameters
)[i
].isTemplateValueParameter();
7115 // tdtypes[i] is already normalized to the required type in matchArg
7117 (*tiargs
)[i
] = tdtypes
[i
];
7119 if (td_last
.isVariadic() && tiargs
.length
== dim
&& tdtypes
[dim
])
7121 Tuple va
= isTuple(tdtypes
[dim
]);
7123 tiargs
.pushSlice(va
.objects
[]);
7126 else if (errors
&& inst
)
7128 // instantiation was failed with error reporting
7129 assert(global
.errors
);
7134 auto tdecl
= tempdecl
.isTemplateDeclaration();
7136 if (errs
!= global
.errors
)
7137 errorSupplemental(loc
, "while looking for match for `%s`", toChars());
7138 else if (tdecl
&& !tdecl
.overnext
)
7140 // Only one template, so we can give better error message
7141 const(char)* msg
= "does not match template declaration";
7143 const tmsg
= tdecl
.toCharsNoConstraints();
7144 const cmsg
= tdecl
.getConstraintEvalError(tip
);
7147 .error(loc
, "%s `%s` %s `%s`\n%s", kind
, toPrettyChars
, msg
, tmsg
, cmsg
);
7153 .error(loc
, "%s `%s` %s `%s`", kind
, toPrettyChars
, msg
, tmsg
);
7155 if (tdecl
.parameters
.length
== tiargs
.length
)
7157 // https://issues.dlang.org/show_bug.cgi?id=7352
7158 // print additional information, e.g. `foo` is not a type
7159 foreach (i
, param
; *tdecl
.parameters
)
7161 MATCH match
= param
.matchArg(loc
, sc
, tiargs
, i
, tdecl
.parameters
, &dedtypes
, null);
7162 auto arg
= (*tiargs
)[i
];
7163 auto sym
= arg
.isDsymbol
;
7164 auto exp
= arg
.isExpression
;
7167 exp
= exp
.optimize(WANTvalue
);
7169 if (match
== MATCH
.nomatch
&&
7170 ((sym
&& sym
.isFuncDeclaration
) ||
7171 (exp
&& exp
.isVarExp
)))
7173 if (param
.isTemplateTypeParameter
)
7174 errorSupplemental(loc
, "`%s` is not a type", arg
.toChars
);
7175 else if (auto tvp
= param
.isTemplateValueParameter
)
7176 errorSupplemental(loc
, "`%s` is not of a value of type `%s`",
7177 arg
.toChars
, tvp
.valType
.toChars
);
7186 .error(loc
, "%s `%s` does not match any template declaration", kind(), toPrettyChars());
7188 overloadApply(tempdecl
, (s
){
7190 errorSupplemental(loc
, "Candidates are:");
7192 errorSupplemental(s
.loc
, "%s", s
.toChars());
7199 /* The best match is td_last
7205 printf("\tIt's a match with template declaration '%s'\n", tempdecl
.toChars());
7207 return (errs
== global
.errors
);
7210 /*****************************************************
7211 * Determine if template instance is really a template function,
7212 * and that template function needs to infer types from the function
7215 * Like findBestMatch, iterate possible template candidates,
7216 * but just looks only the necessity of type inference.
7218 extern (D
) final bool needsTypeInference(Scope
* sc
, int flag
= 0)
7220 //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
7221 if (semanticRun
!= PASS
.initial
)
7224 uint olderrs
= global
.errors
;
7228 auto tovers
= tempdecl
.isOverloadSet();
7229 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
7231 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
7232 int r
= overloadApply(dstart
, (Dsymbol s
)
7234 auto td
= s
.isTemplateDeclaration();
7238 /* If any of the overloaded template declarations need inference,
7243 if (auto td2
= td
.onemember
.isTemplateDeclaration())
7245 if (!td2
.onemember ||
!td2
.onemember
.isFuncDeclaration())
7247 if (tiargs
.length
>= td
.parameters
.length
- (td
.isVariadic() ?
1 : 0))
7251 auto fd
= td
.onemember
.isFuncDeclaration();
7252 if (!fd || fd
.type
.ty
!= Tfunction
)
7255 foreach (tp
; *td
.parameters
)
7257 if (tp
.isTemplateThisParameter())
7261 /* Determine if the instance arguments, tiargs, are all that is necessary
7262 * to instantiate the template.
7264 //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
7265 auto tf
= cast(TypeFunction
)fd
.type
;
7266 if (tf
.parameterList
.length
)
7268 auto tp
= td
.isVariadic();
7269 if (tp
&& td
.parameters
.length
> 1)
7272 if (!tp
&& tiargs
.length
< td
.parameters
.length
)
7274 // Can remain tiargs be filled by default arguments?
7275 foreach (size_t i
; tiargs
.length
.. td
.parameters
.length
)
7277 if (!(*td
.parameters
)[i
].hasDefaultArg())
7282 foreach (i
, fparam
; tf
.parameterList
)
7284 // 'auto ref' needs inference.
7285 if (fparam
.storageClass
& STC
.auto_
)
7292 /* Calculate the need for overload resolution.
7293 * When only one template can match with tiargs, inference is not necessary.
7295 dedtypes
.setDim(td
.parameters
.length
);
7297 if (td
.semanticRun
== PASS
.initial
)
7301 // Try to fix forward reference. Ungag errors while doing so.
7302 Ungag ungag
= td
.ungagSpeculative();
7303 td
.dsymbolSemantic(td
._scope
);
7305 if (td
.semanticRun
== PASS
.initial
)
7307 .error(loc
, "%s `%s` `%s` forward references template declaration `%s`", kind
, toPrettyChars
, toChars(), td
.toChars());
7311 MATCH m
= td
.matchWithInstance(sc
, this, &dedtypes
, ArgumentList(), 0);
7312 if (m
== MATCH
.nomatch
)
7316 /* If there is more than one function template which matches, we may
7317 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
7319 return ++count
> 1 ?
1 : 0;
7325 if (olderrs
!= global
.errors
)
7329 errorSupplemental(loc
, "while looking for match for `%s`", toChars());
7330 semanticRun
= PASS
.semanticdone
;
7335 //printf("false\n");
7339 /*****************************************
7340 * Determines if a TemplateInstance will need a nested
7341 * generation of the TemplateDeclaration.
7342 * Sets enclosing property if so, and returns != 0;
7344 extern (D
) final bool hasNestedArgs(Objects
* args
, bool isstatic
)
7347 //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
7349 // arguments from parent instances are also accessible
7352 if (TemplateInstance ti
= tempdecl
.toParent().isTemplateInstance())
7353 enclosing
= ti
.enclosing
;
7356 /* A nested instance happens when an argument references a local
7357 * symbol that is on the stack.
7361 Expression ea
= isExpression(o
);
7362 Dsymbol sa
= isDsymbol(o
);
7363 Tuple va
= isTuple(o
);
7366 if (auto ve
= ea
.isVarExp())
7371 if (auto te
= ea
.isThisExp())
7376 if (auto fe
= ea
.isFuncExp())
7384 // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
7385 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
)
7387 if (!ea
.type
.isTypeError())
7388 .error(ea
.loc
, "%s `%s` expression `%s` is not a valid template value argument", kind
, toPrettyChars
, ea
.toChars());
7396 TemplateDeclaration td
= sa
.isTemplateDeclaration();
7399 TemplateInstance ti
= sa
.toParent().isTemplateInstance();
7400 if (ti
&& ti
.enclosing
)
7403 TemplateInstance ti
= sa
.isTemplateInstance();
7404 Declaration d
= sa
.isDeclaration();
7405 if ((td
&& td
.literal
) ||
(ti
&& ti
.enclosing
) ||
(d
&& !d
.isDataseg() && !(d
.storage_class
& STC
.manifest
) && (!d
.isFuncDeclaration() || d
.isFuncDeclaration().isNested()) && !isTemplateMixin()))
7407 Dsymbol dparent
= sa
.toParent2();
7408 if (!dparent || dparent
.isModule
)
7410 else if (!enclosing
)
7411 enclosing
= dparent
;
7412 else if (enclosing
!= dparent
)
7414 /* Select the more deeply nested of the two.
7415 * Error if one is not nested inside the other.
7417 for (Dsymbol p
= enclosing
; p
; p
= p
.parent
)
7420 goto L1
; // enclosing is most nested
7422 for (Dsymbol p
= dparent
; p
; p
= p
.parent
)
7426 enclosing
= dparent
;
7427 goto L1
; // dparent is most nested
7430 //https://issues.dlang.org/show_bug.cgi?id=17870
7431 if (dparent
.isClassDeclaration() && enclosing
.isClassDeclaration())
7433 auto pc
= dparent
.isClassDeclaration();
7434 auto ec
= enclosing
.isClassDeclaration();
7435 if (pc
.isBaseOf(ec
, null))
7437 else if (ec
.isBaseOf(pc
, null))
7439 enclosing
= dparent
;
7443 .error(loc
, "%s `%s` `%s` is nested in both `%s` and `%s`", kind
, toPrettyChars
, toChars(), enclosing
.toChars(), dparent
.toChars());
7447 //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
7453 nested |
= cast(int)hasNestedArgs(&va
.objects
, isstatic
);
7456 //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
7460 /*****************************************
7461 * Append 'this' to the specific module members[]
7463 extern (D
) final Dsymbols
* appendToModuleMember()
7465 Module mi
= minst
; // instantiated . inserted module
7467 //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
7469 // enclosing ? enclosing.toPrettyChars() : null,
7470 // mi ? mi.toPrettyChars() : null);
7471 if (global
.params
.allInst ||
!mi || mi
.isRoot())
7473 /* If the instantiated module is speculative or root, insert to the
7474 * member of a root module. Then:
7475 * - semantic3 pass will get called on the instance members.
7476 * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
7478 static Dsymbol
getStrictEnclosing(TemplateInstance ti
)
7483 return ti
.enclosing
;
7484 ti
= ti
.tempdecl
.isInstantiated();
7489 Dsymbol enc
= getStrictEnclosing(this);
7490 // insert target is made stable by using the module
7491 // where tempdecl is declared.
7492 mi
= (enc ? enc
: tempdecl
).getModule();
7495 if (mi
.importedFrom
)
7497 mi
= mi
.importedFrom
;
7498 assert(mi
.isRoot());
7502 // This can happen when using the frontend as a library.
7503 // Append it to the non-root module.
7509 /* If the instantiated module is non-root, insert to the member of the
7510 * non-root module. Then:
7511 * - semantic3 pass won't be called on the instance.
7512 * - codegen pass won't reach to the instance.
7513 * Unless it is re-appended to a root module later (with changed minst).
7516 //printf("\t-. mi = %s\n", mi.toPrettyChars());
7518 if (memberOf
) // already appended to some module
7520 assert(mi
.isRoot(), "can only re-append to a root module");
7521 if (memberOf
.isRoot())
7522 return null; // no need to move to another root module
7525 Dsymbols
* a
= mi
.members
;
7528 if (mi
.semanticRun
>= PASS
.semantic2done
&& mi
.isRoot())
7529 Module
.addDeferredSemantic2(this);
7530 if (mi
.semanticRun
>= PASS
.semantic3done
&& mi
.isRoot())
7531 Module
.addDeferredSemantic3(this);
7535 /****************************************************
7536 * Declare parameters of template instance, initialize them with the
7537 * template instance arguments.
7539 extern (D
) final void declareParameters(Scope
* sc
)
7541 TemplateDeclaration tempdecl
= this.tempdecl
.isTemplateDeclaration();
7544 //printf("TemplateInstance.declareParameters()\n");
7545 foreach (i
, o
; tdtypes
) // initializer for tp
7547 TemplateParameter tp
= (*tempdecl
.parameters
)[i
];
7548 //printf("\ttdtypes[%d] = %p\n", i, o);
7549 tempdecl
.declareParameter(sc
, tp
, o
);
7553 /****************************************
7554 * This instance needs an identifier for name mangling purposes.
7555 * Create one by taking the template declaration name and adding
7556 * the type signature for it.
7558 extern (D
) final Identifier
genIdent(Objects
* args
)
7560 //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
7561 assert(args
is tiargs
);
7563 mangleToBuffer(this, buf
);
7564 //printf("\tgenIdent = %s\n", buf.peekChars());
7565 return Identifier
.idPool(buf
[]);
7568 extern (D
) final void expandMembers(Scope
* sc2
)
7570 members
.foreachDsymbol( (s
) { s
.setScope (sc2
); } );
7572 members
.foreachDsymbol( (s
) { s
.importAll(sc2
); } );
7576 /* static if's are crucial to evaluating aliasdecl correctly. But
7577 * evaluating the if/else bodies may require aliasdecl.
7578 * So, evaluate the condition for static if's, but not their if/else bodies.
7579 * Then try to set aliasdecl.
7580 * Later do the if/else bodies.
7581 * https://issues.dlang.org/show_bug.cgi?id=23598
7582 * It might be better to do this by attaching a lambda to the StaticIfDeclaration
7583 * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
7586 void staticIfDg(Dsymbol s
)
7588 if (done || aliasdecl
)
7590 //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
7591 if (!s
.isStaticIfDeclaration())
7593 //s.dsymbolSemantic(sc2);
7597 auto sid
= s
.isStaticIfDeclaration();
7602 if (Dsymbol
.oneMembers(members
, &sa
, tempdecl
.ident
) && sa
)
7608 members
.foreachDsymbol(&staticIfDg
);
7611 void symbolDg(Dsymbol s
)
7613 //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
7614 //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
7616 // s.parent = sc.parent;
7617 //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7618 s
.dsymbolSemantic(sc2
);
7619 //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
7620 Module
.runDeferredSemantic();
7623 members
.foreachDsymbol(&symbolDg
);
7626 extern (D
) final void tryExpandMembers(Scope
* sc2
)
7629 // extracted to a function to allow windows SEH to work without destructors in the same function
7630 //printf("%d\n", nest);
7631 if (++nest
> global
.recursionLimit
)
7633 global
.gag
= 0; // ensure error message gets printed
7634 .error(loc
, "%s `%s` recursive expansion exceeded allowed nesting limit", kind
, toPrettyChars
);
7643 extern (D
) final void trySemantic3(Scope
* sc2
)
7645 // extracted to a function to allow windows SEH to work without destructors in the same function
7647 //printf("%d\n", nest);
7648 if (++nest
> global
.recursionLimit
)
7650 global
.gag
= 0; // ensure error message gets printed
7651 .error(loc
, "%s `%s` recursive expansion exceeded allowed nesting limit", kind
, toPrettyChars
);
7655 semantic3(this, sc2
);
7660 override final inout(TemplateInstance
) isTemplateInstance() inout
7665 override void accept(Visitor v
)
7671 /**************************************
7672 * IsExpression can evaluate the specified type speculatively, and even if
7673 * it instantiates any symbols, they are normally unnecessary for the
7675 * However, if those symbols leak to the actual code, compiler should remark
7676 * them as non-speculative to generate their code and link to the final executable.
7678 void unSpeculative(Scope
* sc
, RootObject o
)
7683 if (Tuple tup
= isTuple(o
))
7685 foreach (obj
; tup
.objects
)
7687 unSpeculative(sc
, obj
);
7692 Dsymbol s
= getDsymbol(o
);
7696 if (Declaration d
= s
.isDeclaration())
7698 if (VarDeclaration vd
= d
.isVarDeclaration())
7700 else if (AliasDeclaration ad
= d
.isAliasDeclaration())
7714 if (TemplateInstance ti
= s
.isTemplateInstance())
7716 // If the instance is already non-speculative,
7717 // or it is leaked to the speculative scope.
7718 if (ti
.minst
!is null || sc
.minst
is null)
7721 // Remark as non-speculative instance.
7722 ti
.minst
= sc
.minst
;
7724 ti
.tinst
= sc
.tinst
;
7726 unSpeculative(sc
, ti
.tempdecl
);
7729 if (TemplateInstance ti
= s
.isInstantiated())
7730 unSpeculative(sc
, ti
);
7733 /**********************************
7734 * Return true if e could be valid only as a template value parameter.
7735 * Return false if it might be an alias or tuple.
7736 * (Note that even in this case, it could still turn out to be a value).
7738 bool definitelyValueParameter(Expression e
) @safe
7740 // None of these can be value parameters
7741 if (e
.op
== EXP
.tuple || e
.op
== EXP
.scope_ ||
7742 e
.op
== EXP
.type || e
.op
== EXP
.dotType ||
7743 e
.op
== EXP
.template_ || e
.op
== EXP
.dotTemplateDeclaration ||
7744 e
.op
== EXP
.function_ || e
.op
== EXP
.error ||
7745 e
.op
== EXP
.this_ || e
.op
== EXP
.super_ ||
7749 if (e
.op
!= EXP
.dotVariable
)
7752 /* Template instantiations involving a DotVar expression are difficult.
7753 * In most cases, they should be treated as a value parameter, and interpreted.
7754 * But they might also just be a fully qualified name, which should be treated
7758 // x.y.f cannot be a value
7759 FuncDeclaration f
= e
.isDotVarExp().var
.isFuncDeclaration();
7763 while (e
.op
== EXP
.dotVariable
)
7765 e
= e
.isDotVarExp().e1
;
7767 // this.x.y and super.x.y couldn't possibly be valid values.
7768 if (e
.op
== EXP
.this_ || e
.op
== EXP
.super_
)
7771 // e.type.x could be an alias
7772 if (e
.op
== EXP
.dotType
)
7775 // var.x.y is the only other possible form of alias
7776 if (e
.op
!= EXP
.variable
)
7779 VarDeclaration v
= e
.isVarExp().var
.isVarDeclaration();
7780 // func.x.y is not an alias
7784 // https://issues.dlang.org/show_bug.cgi?id=16685
7785 // var.x.y where var is a constant available at compile time
7786 if (v
.storage_class
& STC
.manifest
)
7789 // TODO: Should we force CTFE if it is a global constant?
7793 /***********************************************************
7794 * https://dlang.org/spec/template-mixin.html
7796 * mixin MixinTemplateName [TemplateArguments] [Identifier];
7798 extern (C
++) final class TemplateMixin
: TemplateInstance
7800 TypeQualified tqual
;
7802 extern (D
) this(const ref Loc loc
, Identifier ident
, TypeQualified tqual
, Objects
* tiargs
)
7805 tqual
.idents
.length ?
cast(Identifier
)tqual
.idents
[tqual
.idents
.length
- 1] : (cast(TypeIdentifier
)tqual
).ident
,
7806 tiargs ? tiargs
: new Objects());
7807 //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
7812 override TemplateInstance
syntaxCopy(Dsymbol s
)
7814 auto tm
= new TemplateMixin(loc
, ident
, tqual
.syntaxCopy(), tiargs
);
7815 return TemplateInstance
.syntaxCopy(tm
);
7818 override const(char)* kind() const
7823 override bool oneMember(Dsymbol
* ps
, Identifier ident
)
7825 return Dsymbol
.oneMember(ps
, ident
);
7828 override bool hasPointers()
7830 //printf("TemplateMixin.hasPointers() %s\n", toChars());
7831 return members
.foreachDsymbol( (s
) { return s
.hasPointers(); } ) != 0;
7834 override const(char)* toChars() const
7837 toCBufferInstance(this, buf
);
7838 return buf
.extractChars();
7841 extern (D
) bool findTempDecl(Scope
* sc
)
7843 // Follow qualifications to find the TemplateDeclaration
7849 tqual
.resolve(loc
, sc
, e
, t
, s
);
7852 .error(loc
, "%s `%s` is not defined", kind
, toPrettyChars
);
7856 tempdecl
= s
.isTemplateDeclaration();
7857 OverloadSet os
= s
.isOverloadSet();
7859 /* If an OverloadSet, look for a unique member that is a template declaration
7864 foreach (i
, sym
; os
.a
)
7866 Dsymbol s2
= sym
.isTemplateDeclaration();
7880 .error(loc
, "%s `%s` - `%s` is a %s, not a template", kind
, toPrettyChars
, s
.toChars(), s
.kind());
7886 // Look for forward references
7887 auto tovers
= tempdecl
.isOverloadSet();
7888 foreach (size_t oi
; 0 .. tovers ? tovers
.a
.length
: 1)
7890 Dsymbol dstart
= tovers ? tovers
.a
[oi
] : tempdecl
;
7891 int r
= overloadApply(dstart
, (Dsymbol s
)
7893 auto td
= s
.isTemplateDeclaration();
7897 if (td
.semanticRun
== PASS
.initial
)
7900 td
.dsymbolSemantic(td
._scope
);
7903 semanticRun
= PASS
.initial
;
7915 override inout(TemplateMixin
) isTemplateMixin() inout
7920 override void accept(Visitor v
)
7926 /************************************
7927 * This struct is needed for TemplateInstance to be the key in an associative array.
7928 * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
7929 * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
7931 struct TemplateInstanceBox
7933 TemplateInstance ti
;
7935 this(TemplateInstance ti
)
7939 assert(this.ti
.hash
);
7942 size_t
toHash() const @trusted pure nothrow
7948 bool opEquals(ref const TemplateInstanceBox s
) @trusted const
7951 if (ti
.inst
&& s
.ti
.inst
)
7953 /* This clause is only used when an instance with errors
7954 * is replaced with a correct instance.
7960 /* Used when a proposed instance is used to see if there's
7961 * an existing instance.
7963 static if (__VERSION__
< 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
7964 res
= (cast()s
.ti
).equalsx(cast()ti
);
7966 res
= (cast()ti
).equalsx(cast()s
.ti
);
7969 debug (FindExistingInstance
) ++(res ? nHits
: nCollisions
);
7973 debug (FindExistingInstance
)
7975 __gshared
uint nHits
, nCollisions
;
7977 shared static ~this()
7979 printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
7980 nHits
, nCollisions
);
7985 /*******************************************
7986 * Match to a particular TemplateParameter.
7988 * instLoc location that the template is instantiated.
7989 * tiargs[] actual arguments to template instance
7991 * parameters[] template parameters
7992 * dedtypes[] deduced arguments to template instance
7993 * *psparam set to symbol declared and initialized to dedtypes[i]
7995 MATCH
matchArg(TemplateParameter tp
, Loc instLoc
, Scope
* sc
, Objects
* tiargs
, size_t i
, TemplateParameters
* parameters
, Objects
* dedtypes
, Declaration
* psparam
)
7997 MATCH
matchArgNoMatch()
8001 return MATCH
.nomatch
;
8004 MATCH
matchArgParameter()
8008 if (i
< tiargs
.length
)
8009 oarg
= (*tiargs
)[i
];
8012 // Get default argument instead
8013 oarg
= tp
.defaultArg(instLoc
, sc
);
8016 assert(i
< dedtypes
.length
);
8017 // It might have already been deduced
8018 oarg
= (*dedtypes
)[i
];
8020 return matchArgNoMatch();
8023 return tp
.matchArg(sc
, oarg
, i
, parameters
, dedtypes
, psparam
);
8026 MATCH
matchArgTuple(TemplateTupleParameter ttp
)
8028 /* The rest of the actual arguments (tiargs[]) form the match
8029 * for the variadic parameter.
8031 assert(i
+ 1 == dedtypes
.length
); // must be the last one
8034 if (Tuple u
= isTuple((*dedtypes
)[i
]))
8036 // It has already been deduced
8039 else if (i
+ 1 == tiargs
.length
&& isTuple((*tiargs
)[i
]))
8040 ovar
= isTuple((*tiargs
)[i
]);
8044 //printf("ovar = %p\n", ovar);
8045 if (i
< tiargs
.length
)
8047 //printf("i = %d, tiargs.length = %d\n", i, tiargs.length);
8048 ovar
.objects
.setDim(tiargs
.length
- i
);
8049 foreach (j
, ref obj
; ovar
.objects
)
8050 obj
= (*tiargs
)[i
+ j
];
8053 return ttp
.matchArg(sc
, ovar
, i
, parameters
, dedtypes
, psparam
);
8056 if (auto ttp
= tp
.isTemplateTupleParameter())
8057 return matchArgTuple(ttp
);
8059 return matchArgParameter();
8062 MATCH
matchArg(TemplateParameter tp
, Scope
* sc
, RootObject oarg
, size_t i
, TemplateParameters
* parameters
, Objects
* dedtypes
, Declaration
* psparam
)
8064 MATCH
matchArgNoMatch()
8066 //printf("\tm = %d\n", MATCH.nomatch);
8069 return MATCH
.nomatch
;
8072 MATCH
matchArgType(TemplateTypeParameter ttp
)
8074 //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
8075 MATCH m
= MATCH
.exact
;
8076 Type ta
= isType(oarg
);
8079 //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
8080 return matchArgNoMatch();
8082 //printf("ta is %s\n", ta.toChars());
8086 if (!ta || ta
== TemplateTypeParameter
.tdummy
)
8087 return matchArgNoMatch();
8089 //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
8090 MATCH m2
= deduceType(ta
, sc
, ttp
.specType
, parameters
, dedtypes
);
8091 if (m2
== MATCH
.nomatch
)
8093 //printf("\tfailed deduceType\n");
8094 return matchArgNoMatch();
8101 Type t
= cast(Type
)(*dedtypes
)[i
];
8103 if (ttp
.dependent
&& !t
.equals(ta
)) // https://issues.dlang.org/show_bug.cgi?id=14357
8104 return matchArgNoMatch();
8106 /* This is a self-dependent parameter. For example:
8107 * template X(T : T*) {}
8108 * template X(T : S!T, alias S) {}
8110 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8118 // Must match already deduced type
8119 Type t
= cast(Type
)(*dedtypes
)[i
];
8123 //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
8124 return matchArgNoMatch();
8129 // So that matches with specializations are better
8133 (*dedtypes
)[i
] = ta
;
8136 *psparam
= new AliasDeclaration(ttp
.loc
, ttp
.ident
, ta
);
8137 //printf("\tm = %d\n", m);
8138 return ttp
.dependent ? MATCH
.exact
: m
;
8141 MATCH
matchArgValue(TemplateValueParameter tvp
)
8143 //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
8144 MATCH m
= MATCH
.exact
;
8146 Expression ei
= isExpression(oarg
);
8151 Dsymbol si
= isDsymbol(oarg
);
8152 FuncDeclaration f
= si ? si
.isFuncDeclaration() : null;
8153 if (!f ||
!f
.fbody || f
.needThis())
8154 return matchArgNoMatch();
8156 ei
= new VarExp(tvp
.loc
, f
);
8157 ei
= ei
.expressionSemantic(sc
);
8159 /* If a function is really property-like, and then
8160 * it's CTFEable, ei will be a literal expression.
8162 uint olderrors
= global
.startGagging();
8163 ei
= resolveProperties(sc
, ei
);
8164 ei
= ei
.ctfeInterpret();
8165 if (global
.endGagging(olderrors
) || ei
.op
== EXP
.error
)
8166 return matchArgNoMatch();
8168 /* https://issues.dlang.org/show_bug.cgi?id=14520
8169 * A property-like function can match to both
8170 * TemplateAlias and ValueParameter. But for template overloads,
8171 * it should always prefer alias parameter to be consistent
8172 * template match result.
8174 * template X(alias f) { enum X = 1; }
8175 * template X(int val) { enum X = 2; }
8176 * int f1() { return 0; } // CTFEable
8177 * int f2(); // body-less function is not CTFEable
8178 * enum x1 = X!f1; // should be 1
8179 * enum x2 = X!f2; // should be 1
8181 * e.g. The x1 value must be same even if the f1 definition will be moved
8182 * into di while stripping body code.
8187 if (ei
&& ei
.op
== EXP
.variable
)
8189 // Resolve const variables that we had skipped earlier
8190 ei
= ei
.ctfeInterpret();
8193 //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
8194 vt
= tvp
.valType
.typeSemantic(tvp
.loc
, sc
);
8195 //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
8196 //printf("vt = %s\n", vt.toChars());
8200 MATCH m2
= ei
.implicitConvTo(vt
);
8201 //printf("m: %d\n", m);
8204 if (m
== MATCH
.nomatch
)
8205 return matchArgNoMatch();
8206 ei
= ei
.implicitCastTo(sc
, vt
);
8207 ei
= ei
.ctfeInterpret();
8212 if (ei
is null ||
(cast(void*)ei
.type
in TemplateValueParameter
.edummies
&&
8213 TemplateValueParameter
.edummies
[cast(void*)ei
.type
] == ei
))
8214 return matchArgNoMatch();
8216 Expression e
= tvp
.specValue
;
8218 sc
= sc
.startCTFE();
8219 e
= e
.expressionSemantic(sc
);
8220 e
= resolveProperties(sc
, e
);
8222 e
= e
.implicitCastTo(sc
, vt
);
8223 e
= e
.ctfeInterpret();
8225 ei
= ei
.syntaxCopy();
8226 sc
= sc
.startCTFE();
8227 ei
= ei
.expressionSemantic(sc
);
8229 ei
= ei
.implicitCastTo(sc
, vt
);
8230 ei
= ei
.ctfeInterpret();
8231 //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
8232 //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
8234 return matchArgNoMatch();
8240 // Must match already deduced value
8241 Expression e
= cast(Expression
)(*dedtypes
)[i
];
8242 if (!ei ||
!ei
.equals(e
))
8243 return matchArgNoMatch();
8246 (*dedtypes
)[i
] = ei
;
8250 Initializer _init
= new ExpInitializer(tvp
.loc
, ei
);
8251 Declaration sparam
= new VarDeclaration(tvp
.loc
, vt
, tvp
.ident
, _init
);
8252 sparam
.storage_class
= STC
.manifest
;
8255 return tvp
.dependent ? MATCH
.exact
: m
;
8258 MATCH
matchArgAlias(TemplateAliasParameter tap
)
8260 //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
8261 MATCH m
= MATCH
.exact
;
8262 Type ta
= isType(oarg
);
8263 RootObject sa
= ta
&& !ta
.deco ?
null : getDsymbol(oarg
);
8264 Expression ea
= isExpression(oarg
);
8267 if (auto te
= ea
.isThisExp())
8269 else if (auto se
= ea
.isSuperExp())
8271 else if (auto se
= ea
.isScopeExp())
8276 if ((cast(Dsymbol
)sa
).isAggregateDeclaration())
8279 /* specType means the alias must be a declaration with a type
8280 * that matches specType.
8284 tap
.specType
= typeSemantic(tap
.specType
, tap
.loc
, sc
);
8285 Declaration d
= (cast(Dsymbol
)sa
).isDeclaration();
8287 return matchArgNoMatch();
8288 if (!d
.type
.equals(tap
.specType
))
8289 return matchArgNoMatch();
8299 if (!ea
.type
.equals(tap
.specType
))
8300 return matchArgNoMatch();
8303 else if (ta
&& ta
.ty
== Tinstance
&& !tap
.specAlias
)
8305 /* Specialized parameter should be preferred
8306 * match to the template type parameter.
8307 * template X(alias a) {} // a == this
8308 * template X(alias a : B!A, alias B, A...) {} // B!A => ta
8311 else if (sa
&& sa
== TemplateTypeParameter
.tdummy
)
8313 /* https://issues.dlang.org/show_bug.cgi?id=2025
8314 * Aggregate Types should preferentially
8315 * match to the template type parameter.
8316 * template X(alias a) {} // a == this
8317 * template X(T) {} // T => sa
8320 else if (ta
&& ta
.ty
!= Tident
)
8322 /* Match any type that's not a TypeIdentifier to alias parameters,
8323 * but prefer type parameter.
8324 * template X(alias a) { } // a == ta
8326 * TypeIdentifiers are excluded because they might be not yet resolved aliases.
8331 return matchArgNoMatch();
8336 if (sa
== TemplateAliasParameter
.sdummy
)
8337 return matchArgNoMatch();
8338 // check specialization if template arg is a symbol
8339 Dsymbol sx
= isDsymbol(sa
);
8340 if (sa
!= tap
.specAlias
&& sx
)
8342 Type talias
= isType(tap
.specAlias
);
8344 return matchArgNoMatch();
8346 TemplateInstance ti
= sx
.isTemplateInstance();
8347 if (!ti
&& sx
.parent
)
8349 ti
= sx
.parent
.isTemplateInstance();
8350 if (ti
&& ti
.name
!= sx
.ident
)
8351 return matchArgNoMatch();
8354 return matchArgNoMatch();
8356 Type t
= new TypeInstance(Loc
.initial
, ti
);
8357 MATCH m2
= deduceType(t
, sc
, talias
, parameters
, dedtypes
);
8358 if (m2
== MATCH
.nomatch
)
8359 return matchArgNoMatch();
8361 // check specialization if template arg is a type
8364 if (Type tspec
= isType(tap
.specAlias
))
8366 MATCH m2
= ta
.implicitConvTo(tspec
);
8367 if (m2
== MATCH
.nomatch
)
8368 return matchArgNoMatch();
8372 error(tap
.loc
, "template parameter specialization for a type must be a type and not `%s`",
8373 tap
.specAlias
.toChars());
8374 return matchArgNoMatch();
8378 else if ((*dedtypes
)[i
])
8380 // Must match already deduced symbol
8381 RootObject si
= (*dedtypes
)[i
];
8382 if (!sa || si
!= sa
)
8383 return matchArgNoMatch();
8385 (*dedtypes
)[i
] = sa
;
8389 if (Dsymbol s
= isDsymbol(sa
))
8391 *psparam
= new AliasDeclaration(tap
.loc
, tap
.ident
, s
);
8393 else if (Type t
= isType(sa
))
8395 *psparam
= new AliasDeclaration(tap
.loc
, tap
.ident
, t
);
8401 // Declare manifest constant
8402 Initializer _init
= new ExpInitializer(tap
.loc
, ea
);
8403 auto v
= new VarDeclaration(tap
.loc
, null, tap
.ident
, _init
);
8404 v
.storage_class
= STC
.manifest
;
8405 v
.dsymbolSemantic(sc
);
8409 return tap
.dependent ? MATCH
.exact
: m
;
8412 MATCH
matchArgTuple(TemplateTupleParameter ttp
)
8414 //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
8415 Tuple ovar
= isTuple(oarg
);
8417 return MATCH
.nomatch
;
8420 Tuple tup
= isTuple((*dedtypes
)[i
]);
8422 return MATCH
.nomatch
;
8423 if (!match(tup
, ovar
))
8424 return MATCH
.nomatch
;
8426 (*dedtypes
)[i
] = ovar
;
8429 *psparam
= new TupleDeclaration(ttp
.loc
, ttp
.ident
, &ovar
.objects
);
8430 return ttp
.dependent ? MATCH
.exact
: MATCH
.convert
;
8433 if (auto ttp
= tp
.isTemplateTypeParameter())
8434 return matchArgType(ttp
);
8435 else if (auto tvp
= tp
.isTemplateValueParameter())
8436 return matchArgValue(tvp
);
8437 else if (auto tap
= tp
.isTemplateAliasParameter())
8438 return matchArgAlias(tap
);
8439 else if (auto ttp
= tp
.isTemplateTupleParameter())
8440 return matchArgTuple(ttp
);
8446 /***********************************************
8447 * Collect and print statistics on template instantiations.
8449 struct TemplateStats
8451 __gshared TemplateStats
[const void*] stats
;
8453 uint numInstantiations
; // number of instantiations of the template
8454 uint uniqueInstantiations
; // number of unique instantiations of the template
8456 TemplateInstances
* allInstances
;
8458 /*******************************
8461 static void incInstance(const TemplateDeclaration td
,
8462 const TemplateInstance ti
)
8464 void log(ref TemplateStats ts
)
8466 if (ts
.allInstances
is null)
8467 ts
.allInstances
= new TemplateInstances();
8468 if (global
.params
.v
.templatesListInstances
)
8469 ts
.allInstances
.push(cast() ti
);
8472 // message(ti.loc, "incInstance %p %p", td, ti);
8473 if (!global
.params
.v
.templates
)
8478 if (auto ts
= cast(const void*) td
in stats
)
8481 ++ts
.numInstantiations
;
8485 stats
[cast(const void*) td
] = TemplateStats(1, 0);
8486 log(stats
[cast(const void*) td
]);
8490 /*******************************
8491 * Add this unique instance
8493 static void incUnique(const TemplateDeclaration td
,
8494 const TemplateInstance ti
)
8496 // message(ti.loc, "incUnique %p %p", td, ti);
8497 if (!global
.params
.v
.templates
)
8502 if (auto ts
= cast(const void*) td
in stats
)
8503 ++ts
.uniqueInstantiations
;
8505 stats
[cast(const void*) td
] = TemplateStats(0, 1);
8509 extern (C
++) void printTemplateStats()
8511 static struct TemplateDeclarationStats
8513 TemplateDeclaration td
;
8515 static int compare(scope const TemplateDeclarationStats
* a
,
8516 scope const TemplateDeclarationStats
* b
) @safe nothrow @nogc pure
8518 auto diff
= b
.ts
.uniqueInstantiations
- a
.ts
.uniqueInstantiations
;
8522 return b
.ts
.numInstantiations
- a
.ts
.numInstantiations
;
8526 if (!global
.params
.v
.templates
)
8529 Array
!(TemplateDeclarationStats
) sortedStats
;
8530 sortedStats
.reserve(TemplateStats
.stats
.length
);
8531 foreach (td_
, ref ts
; TemplateStats
.stats
)
8533 sortedStats
.push(TemplateDeclarationStats(cast(TemplateDeclaration
) td_
, ts
));
8536 sortedStats
.sort
!(TemplateDeclarationStats
.compare
);
8538 foreach (const ref ss
; sortedStats
[])
8540 if (global
.params
.v
.templatesListInstances
&&
8544 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
8545 ss
.ts
.numInstantiations
,
8546 ss
.ts
.uniqueInstantiations
,
8547 ss
.td
.toCharsNoConstraints());
8548 foreach (const ti
; (*ss
.ts
.allInstances
)[])
8550 if (ti
.tinst
) // if has enclosing instance
8551 message(ti
.loc
, "vtemplate: implicit instance `%s`", ti
.toChars());
8553 message(ti
.loc
, "vtemplate: explicit instance `%s`", ti
.toChars());
8559 "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
8560 ss
.ts
.numInstantiations
,
8561 ss
.ts
.uniqueInstantiations
,
8562 ss
.td
.toCharsNoConstraints());
8568 private struct MATCHpair
8570 MATCH mta
; /// match template parameters by initial template arguments
8571 MATCH mfa
; /// match template parameters by inferred template arguments
8573 debug this(MATCH mta
, MATCH mfa
)
8575 assert(MATCH
.min
<= mta
&& mta
<= MATCH
.max
);
8576 assert(MATCH
.min
<= mfa
&& mfa
<= MATCH
.max
);
8582 private void write(ref OutBuffer buf
, RootObject obj
)
8586 buf
.writestring(obj
.toChars());