4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templatesem.d, _templatesem.d)
8 * Documentation: https://dlang.org/phobos/dmd_templatesem.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templatesem.d
12 module dmd
.templatesem
;
14 import core
.stdc
.stdio
;
15 import core
.stdc
.string
;
18 import dmd
.arraytypes
;
24 import dmd
.declaration
;
25 import dmd
.dinterpret
;
30 import dmd
.dsymbolsem
;
34 import dmd
.expression
;
35 import dmd
.expressionsem
;
41 import dmd
.identifier
;
49 import dmd
.root
.array
;
50 import dmd
.common
.outbuffer
;
51 import dmd
.rootobject
;
58 /***************************************
59 * Given that ti is an instance of this TemplateDeclaration,
60 * deduce the types of the parameters to this, and store
61 * those deduced types in dedtypes[].
66 * dedtypes = fill in with deduced types
67 * argumentList = arguments to template instance
68 * flag = 1 - don't do semantic() because of dummy types
69 * 2 - don't change types in matchArg()
70 * Returns: match level.
73 MATCH
matchWithInstance(Scope
* sc
, TemplateDeclaration td
, TemplateInstance ti
, ref Objects dedtypes
, ArgumentList argumentList
, int flag
)
78 printf("\n+TemplateDeclaration.matchWithInstance(td = %s, ti = %s, flag = %d)\n", td
.toChars(), ti
.toChars(), flag
);
82 printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes
.length
, parameters
.length
);
84 printf("ti.tiargs.length = %d, [0] = %p\n", ti
.tiargs
.length
, (*ti
.tiargs
)[0]);
90 printf(" no match\n");
95 size_t dedtypes_dim
= dedtypes
.length
;
100 return MATCH
.nomatch
;
102 size_t parameters_dim
= td
.parameters
.length
;
103 int variadic
= td
.isVariadic() !is null;
105 // If more arguments than parameters, no match
106 if (ti
.tiargs
.length
> parameters_dim
&& !variadic
)
110 printf(" no match: more arguments than parameters\n");
112 return MATCH
.nomatch
;
115 assert(dedtypes_dim
== parameters_dim
);
116 assert(dedtypes_dim
>= ti
.tiargs
.length || variadic
);
120 // Set up scope for template parameters
121 Scope
* paramscope
= createScopeForTemplateParameters(td
, ti
, sc
);
123 // Attempt type deduction
125 for (size_t i
= 0; i
< dedtypes_dim
; i
++)
128 TemplateParameter tp
= (*td
.parameters
)[i
];
131 //printf("\targument [%d]\n", i);
134 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
135 TemplateTypeParameter ttp
= tp
.isTemplateTypeParameter();
137 printf("\tparameter[%d] is %s : %s\n", i
, tp
.ident
.toChars(), ttp
.specType ? ttp
.specType
.toChars() : "");
140 m2
= tp
.matchArg(ti
.loc
, paramscope
, ti
.tiargs
, i
, td
.parameters
, dedtypes
, &sparam
);
141 //printf("\tm2 = %d\n", m2);
142 if (m2
== MATCH
.nomatch
)
146 printf("\tmatchArg() for parameter %i failed\n", i
);
155 sparam
.dsymbolSemantic(paramscope
);
156 if (!paramscope
.insert(sparam
)) // TODO: This check can make more early
158 // in TemplateDeclaration.semantic, and
159 // then we don't need to make sparam if flags == 0
166 /* Any parameter left without a type gets the type of
167 * its corresponding arg
169 foreach (i
, ref dedtype
; dedtypes
)
173 assert(i
< ti
.tiargs
.length
);
174 dedtype
= cast(Type
)(*ti
.tiargs
)[i
];
179 if (m
> MATCH
.nomatch
&& td
.constraint
&& !flag
)
181 if (ti
.hasNestedArgs(ti
.tiargs
, td
.isstatic
)) // TODO: should gag error
182 ti
.parent
= ti
.enclosing
;
184 ti
.parent
= td
.parent
;
186 // Similar to doHeaderInstantiation
187 FuncDeclaration fd
= td
.onemember ? td
.onemember
.isFuncDeclaration() : null;
190 TypeFunction tf
= fd
.type
.isTypeFunction().syntaxCopy();
191 if (argumentList
.hasNames
)
193 Expressions
* fargs
= argumentList
.arguments
;
194 // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
198 fd
= new FuncDeclaration(fd
.loc
, fd
.endloc
, fd
.ident
, fd
.storage_class
, tf
);
200 fd
.inferRetType
= true;
202 // Shouldn't run semantic on default arguments and return type.
203 foreach (ref param
; *tf
.parameterList
.parameters
)
204 param
.defaultArg
= null;
207 tf
.incomplete
= true;
209 // Resolve parameter types and 'auto ref's.
211 uint olderrors
= global
.startGagging();
212 fd
.type
= tf
.typeSemantic(td
.loc
, paramscope
);
213 global
.endGagging(olderrors
);
214 if (fd
.type
.ty
!= Tfunction
)
216 fd
.originalType
= fd
.type
; // for mangling
219 // TODO: dedtypes => ti.tiargs ?
220 if (!evaluateConstraint(td
, ti
, sc
, paramscope
, &dedtypes
, fd
))
226 // Print out the results
227 printf("--------------------------\n");
228 printf("template %s\n", toChars());
229 printf("instance %s\n", ti
.toChars());
230 if (m
> MATCH
.nomatch
)
232 for (size_t i
= 0; i
< dedtypes_dim
; i
++)
234 TemplateParameter tp
= (*parameters
)[i
];
237 if (i
< ti
.tiargs
.length
)
238 oarg
= (*ti
.tiargs
)[i
];
241 tp
.print(oarg
, (*dedtypes
)[i
]);
249 printf(" match = %d\n", m
);
255 printf("-TemplateDeclaration.matchWithInstance(td = %s, ti = %s) = %d\n", td
.toChars(), ti
.toChars(), m
);
260 /****************************
261 * Check to see if constraint is satisfied.
263 bool evaluateConstraint(TemplateDeclaration td
, TemplateInstance ti
, Scope
* sc
, Scope
* paramscope
, Objects
* dedargs
, FuncDeclaration fd
)
265 /* Detect recursive attempts to instantiate this template declaration,
266 * https://issues.dlang.org/show_bug.cgi?id=4072
267 * void foo(T)(T x) if (is(typeof(foo(x)))) { }
268 * static assert(!is(typeof(foo(7))));
269 * Recursive attempts are regarded as a constraint failure.
271 /* There's a chicken-and-egg problem here. We don't know yet if this template
272 * instantiation will be a local one (enclosing is set), and we won't know until
273 * after selecting the correct template. Thus, function we're nesting inside
274 * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
275 * Workaround the problem by setting a flag to relax the checking on frame errors.
278 for (TemplatePrevious
* p
= td
.previous
; p
; p
= p
.prev
)
280 if (!arrayObjectMatch(*p
.dedargs
, *dedargs
))
282 //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
283 /* It must be a subscope of p.sc, other scope chains are not recursive
285 * the chain of enclosing scopes is broken by paramscope (its enclosing
286 * scope is _scope, but paramscope.callsc is the instantiating scope). So
287 * it's good enough to check the chain of callsc
289 for (Scope
* scx
= paramscope
.callsc
; scx
; scx
= scx
.callsc
)
291 // The first scx might be identical for nested eponymeous templates, e.g.
292 // template foo() { void foo()() {...} }
293 if (scx
== p
.sc
&& scx
!is paramscope
.callsc
)
296 /* BUG: should also check for ref param differences
301 pr
.prev
= td
.previous
;
302 pr
.sc
= paramscope
.callsc
;
303 pr
.dedargs
= dedargs
;
304 td
.previous
= &pr
; // add this to threaded list
306 Scope
* scx
= paramscope
.push(ti
);
310 // Set SCOPE.constraint before declaring function parameters for the static condition
311 // (previously, this was immediately before calling evalStaticCondition), so the
312 // semantic pass knows not to issue deprecation warnings for these throw-away decls.
313 // https://issues.dlang.org/show_bug.cgi?id=21831
314 scx
.flags |
= SCOPE
.constraint
;
319 /* Declare all the function parameters as variables and add them to the scope
320 * Making parameters is similar to FuncDeclaration.semantic3
322 auto tf
= fd
.type
.isTypeFunction();
326 Parameters
* fparameters
= tf
.parameterList
.parameters
;
327 const nfparams
= tf
.parameterList
.length
;
328 foreach (i
, fparam
; tf
.parameterList
)
330 fparam
.storageClass
&= (STC
.IOR | STC
.lazy_ | STC
.final_ | STC
.TYPECTOR | STC
.nodtor
);
331 fparam
.storageClass |
= STC
.parameter
;
332 if (tf
.parameterList
.varargs
== VarArg
.typesafe
&& i
+ 1 == nfparams
)
334 fparam
.storageClass |
= STC
.variadic
;
335 /* Don't need to set STC.scope_ because this will only
336 * be evaluated at compile time
340 foreach (fparam
; *fparameters
)
344 // don't add it, if it has no name
345 auto v
= new VarDeclaration(fparam
.loc
, fparam
.type
, fparam
.ident
, null);
346 fparam
.storageClass |
= STC
.parameter
;
347 v
.storage_class
= fparam
.storageClass
;
348 v
.dsymbolSemantic(scx
);
350 ti
.symtab
= new DsymbolTable();
352 .error(td
.loc
, "%s `%s` parameter `%s.%s` is already defined", td
.kind
, td
.toPrettyChars
, td
.toChars(), v
.toChars());
357 fd
.storage_class |
= STC
.static_
;
358 declareThis(fd
, scx
);
361 td
.lastConstraint
= td
.constraint
.syntaxCopy();
362 td
.lastConstraintTiargs
= ti
.tiargs
;
363 td
.lastConstraintNegs
.setDim(0);
365 import dmd
.staticcond
;
367 assert(ti
.inst
is null);
368 ti
.inst
= ti
; // temporary instantiation to enable genIdent()
370 const bool result
= evalStaticCondition(scx
, td
.constraint
, td
.lastConstraint
, errors
, &td
.lastConstraintNegs
);
371 if (result || errors
)
373 td
.lastConstraint
= null;
374 td
.lastConstraintTiargs
= null;
375 td
.lastConstraintNegs
.setDim(0);
380 td
.previous
= pr
.prev
; // unlink from threaded list
386 /*******************************************
387 * Append to buf a textual representation of template parameters with their arguments.
389 * parameters = the template parameters
390 * tiargs = the correspondeing template arguments
391 * variadic = if it's a variadic argument list
392 * buf = where the text output goes
394 void formatParamsWithTiargs(ref TemplateParameters parameters
, ref Objects tiargs
, bool variadic
, ref OutBuffer buf
)
396 buf
.writestring(" with `");
398 // write usual arguments line-by-line
399 // skips trailing default ones - they are not present in `tiargs`
400 const end
= parameters
.length
- (variadic ?
1 : 0);
402 for (; i
< tiargs
.length
&& i
< end
; i
++)
408 buf
.writestring(" ");
410 write(buf
, parameters
[i
]);
411 buf
.writestring(" = ");
412 write(buf
, tiargs
[i
]);
414 // write remaining variadic arguments on the last line
421 buf
.writestring(" ");
423 write(buf
, parameters
[end
]);
424 buf
.writestring(" = ");
426 if (end
< tiargs
.length
)
428 write(buf
, tiargs
[end
]);
429 foreach (j
; parameters
.length
.. tiargs
.length
)
431 buf
.writestring(", ");
432 write(buf
, tiargs
[j
]);
440 /******************************
441 * Create a scope for the parameters of the TemplateInstance
442 * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
444 * If paramsym is null a new ScopeDsymbol is used in place of
447 * td = template that ti is an instance of
448 * ti = the TemplateInstance whose parameters to generate the scope for.
449 * sc = the parent scope of ti
451 * new scope for the parameters of ti
453 Scope
* createScopeForTemplateParameters(TemplateDeclaration td
, TemplateInstance ti
, Scope
* sc
)
455 ScopeDsymbol paramsym
= new ScopeDsymbol();
456 paramsym
.parent
= td
._scope
.parent
;
457 Scope
* paramscope
= td
._scope
.push(paramsym
);
458 paramscope
.tinst
= ti
;
459 paramscope
.minst
= sc
.minst
;
460 paramscope
.callsc
= sc
;
465 /********************************************
466 * Determine partial specialization order of `td` vs `td2`.
469 * td = first template
470 * td2 = second template
471 * argumentList = arguments to template
473 * MATCH - td is at least as specialized as td2
474 * MATCH.nomatch - td2 is more specialized than td
476 MATCH
leastAsSpecialized(Scope
* sc
, TemplateDeclaration td
, TemplateDeclaration td2
, ArgumentList argumentList
)
478 enum LOG_LEASTAS
= 0;
479 static if (LOG_LEASTAS
)
481 printf("%s.leastAsSpecialized(%s)\n", toChars(), td2
.toChars());
484 /* This works by taking the template parameters to this template
485 * declaration and feeding them to td2 as if it were a template
487 * If it works, then this template is at least as specialized
491 // Set type arguments to dummy template instance to be types
492 // generated from the parameters to this template declaration
493 auto tiargs
= new Objects();
494 tiargs
.reserve(td
.parameters
.length
);
495 foreach (tp
; *td
.parameters
)
499 RootObject p
= tp
.dummyArg();
500 if (!p
) //TemplateTupleParameter
505 scope TemplateInstance ti
= new TemplateInstance(Loc
.initial
, td
.ident
, tiargs
); // create dummy template instance
507 // Temporary Array to hold deduced types
508 Objects dedtypes
= Objects(td2
.parameters
.length
);
510 // Attempt a type deduction
511 MATCH m
= matchWithInstance(sc
, td2
, ti
, dedtypes
, argumentList
, 1);
512 if (m
> MATCH
.nomatch
)
514 /* A non-variadic template is more specialized than a
517 TemplateTupleParameter tp
= td
.isVariadic();
518 if (tp
&& !tp
.dependent
&& !td2
.isVariadic())
521 static if (LOG_LEASTAS
)
523 printf(" matches %d, so is least as specialized\n", m
);
528 static if (LOG_LEASTAS
)
530 printf(" doesn't match, so is not as specialized\n");
532 return MATCH
.nomatch
;
535 /*************************************************
536 * Match function arguments against a specific template function.
539 * td = template declaration for template instance
540 * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments
541 * sc = instantiation scope
542 * fd = Partially instantiated function declaration, which is set to an instantiated function declaration
543 * tthis = 'this' argument if !NULL
544 * argumentList = arguments to function
547 * match pair of initial and inferred template arguments
549 extern (D
) MATCHpair
deduceFunctionTemplateMatch(TemplateDeclaration td
, TemplateInstance ti
, Scope
* sc
, ref FuncDeclaration fd
, Type tthis
, ArgumentList argumentList
)
553 printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", td
.toChars());
554 for (size_t i
= 0; i
< (fargs ? fargs
.length
: 0); i
++)
556 Expression e
= (*fargs
)[i
];
557 printf("\tfarg[%d] is %s, type is %s\n", cast(int) i
, e
.toChars(), e
.type
.toChars());
559 printf("fd = %s\n", fd
.toChars());
560 printf("fd.type = %s\n", fd
.type
.toChars());
562 printf("tthis = %s\n", tthis
.toChars());
567 auto dedargs
= new Objects(td
.parameters
.length
);
570 Objects
* dedtypes
= &ti
.tdtypes
; // for T:T*, the dedargs is the T*, dedtypes is the T
571 dedtypes
.setDim(td
.parameters
.length
);
574 if (td
.errors || fd
.errors
)
575 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
577 // Set up scope for parameters
578 Scope
* paramscope
= createScopeForTemplateParameters(td
, ti
,sc
);
583 //printf("\tnomatch\n");
584 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
587 MATCHpair
matcherror()
589 // todo: for the future improvement
591 //printf("\terror\n");
592 return MATCHpair(MATCH
.nomatch
, MATCH
.nomatch
);
594 // Mark the parameter scope as deprecated if the templated
595 // function is deprecated (since paramscope.enclosing is the
596 // calling scope already)
597 paramscope
.stc |
= fd
.storage_class
& STC
.deprecated_
;
599 TemplateTupleParameter tp
= td
.isVariadic();
600 Tuple declaredTuple
= null;
604 for (size_t i
= 0; i
< dedargs
.length
; i
++)
606 printf("\tdedarg[%d] = ", i
);
607 RootObject oarg
= (*dedargs
)[i
];
609 printf("%s", oarg
.toChars());
614 size_t ntargs
= 0; // array size of tiargs
615 size_t inferStart
= 0; // index of first parameter to infer
616 const Loc instLoc
= ti
.loc
;
617 MATCH matchTiargs
= MATCH
.exact
;
619 if (auto tiargs
= ti
.tiargs
)
621 // Set initial template arguments
622 ntargs
= tiargs
.length
;
623 size_t n
= td
.parameters
.length
;
631 /* The extra initial template arguments
632 * now form the tuple argument.
634 auto t
= new Tuple(ntargs
- n
);
635 assert(td
.parameters
.length
);
636 (*dedargs
)[td
.parameters
.length
- 1] = t
;
638 for (size_t i
= 0; i
< t
.objects
.length
; i
++)
640 t
.objects
[i
] = (*tiargs
)[n
+ i
];
642 td
.declareParameter(paramscope
, tp
, t
);
648 memcpy(dedargs
.tdata(), tiargs
.tdata(), n
* (*dedargs
.tdata()).sizeof
);
650 for (size_t i
= 0; i
< n
; i
++)
652 assert(i
< td
.parameters
.length
);
653 Declaration sparam
= null;
654 MATCH m
= (*td
.parameters
)[i
].matchArg(instLoc
, paramscope
, dedargs
, i
, td
.parameters
, *dedtypes
, &sparam
);
655 //printf("\tdeduceType m = %d\n", m);
656 if (m
== MATCH
.nomatch
)
661 sparam
.dsymbolSemantic(paramscope
);
662 if (!paramscope
.insert(sparam
))
665 if (n
< td
.parameters
.length
&& !declaredTuple
)
670 inferStart
= td
.parameters
.length
;
671 //printf("tiargs matchTiargs = %d\n", matchTiargs);
675 for (size_t i
= 0; i
< dedargs
.length
; i
++)
677 printf("\tdedarg[%d] = ", i
);
678 RootObject oarg
= (*dedargs
)[i
];
680 printf("%s", oarg
.toChars());
685 ParameterList fparameters
= fd
.getParameterList(); // function parameter list
686 const nfparams
= fparameters
.length
; // number of function parameters
687 if (argumentList
.hasNames
)
688 return matcherror(); // TODO: resolve named args
689 Expression
[] fargs
= argumentList
.arguments ?
(*argumentList
.arguments
)[] : null;
691 /* Check for match of function arguments with variadic template
692 * parameter, such as:
694 * void foo(T, A...)(T t, A a);
695 * void main() { foo(1,2,3); }
697 size_t fptupindex
= IDX_NOTFOUND
;
698 if (tp
) // if variadic
700 // TemplateTupleParameter always makes most lesser matching.
701 matchTiargs
= MATCH
.convert
;
703 if (nfparams
== 0 && argumentList
.length
!= 0) // if no function parameters
707 auto t
= new Tuple();
708 //printf("t = %p\n", t);
709 (*dedargs
)[td
.parameters
.length
- 1] = t
;
710 td
.declareParameter(paramscope
, tp
, t
);
716 /* Figure out which of the function parameters matches
717 * the tuple template parameter. Do this by matching
719 * Set the index of this function parameter to fptupindex.
721 for (fptupindex
= 0; fptupindex
< nfparams
; fptupindex
++)
723 auto fparam
= (*fparameters
.parameters
)[fptupindex
]; // fparameters[fptupindex] ?
724 if (fparam
.type
.ty
!= Tident
)
726 TypeIdentifier tid
= fparam
.type
.isTypeIdentifier();
727 if (!tp
.ident
.equals(tid
.ident
) || tid
.idents
.length
)
730 if (fparameters
.varargs
!= VarArg
.none
) // variadic function doesn't
731 return nomatch(); // go with variadic template
735 fptupindex
= IDX_NOTFOUND
;
740 MATCH match
= MATCH
.exact
;
741 if (td
.toParent().isModule())
747 // Match 'tthis' to any TemplateThisParameter's
748 foreach (param
; *td
.parameters
)
750 if (auto ttp
= param
.isTemplateThisParameter())
754 Type t
= new TypeIdentifier(Loc
.initial
, ttp
.ident
);
755 MATCH m
= deduceType(tthis
, paramscope
, t
, *td
.parameters
, *dedtypes
);
756 if (m
== MATCH
.nomatch
)
759 match
= m
; // pick worst match
763 // Match attributes of tthis against attributes of fd
764 if (fd
.type
&& !fd
.isCtorDeclaration() && !(td
._scope
.stc & STC
.static_
))
766 StorageClass
stc = td
._scope
.stc | fd
.storage_class2
;
767 // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
768 Dsymbol p
= td
.parent
;
769 while (p
.isTemplateDeclaration() || p
.isTemplateInstance())
771 AggregateDeclaration ad
= p
.isAggregateDeclaration();
773 stc |
= ad
.storage_class
;
775 ubyte mod
= fd
.type
.mod
;
776 if (stc & STC
.immutable_
)
777 mod
= MODFlags
.immutable_
;
780 if (stc & (STC
.shared_ | STC
.synchronized_
))
781 mod |
= MODFlags
.shared_
;
782 if (stc & STC
.const_
)
783 mod |
= MODFlags
.const_
;
785 mod |
= MODFlags
.wild
;
788 ubyte thismod
= tthis
.mod
;
790 mod
= MODmerge(thismod
, mod
);
791 MATCH m
= MODmethodConv(thismod
, mod
);
792 if (m
== MATCH
.nomatch
)
799 // Loop through the function parameters
801 //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
802 //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
804 size_t nfargs2
= fargs
.length
; // nfargs + supplied defaultArgs
805 uint inoutMatch
= 0; // for debugging only
806 for (size_t parami
= 0; parami
< nfparams
; parami
++)
808 Parameter fparam
= fparameters
[parami
];
810 // Apply function parameter storage classes to parameter types
811 Type prmtype
= fparam
.type
.addStorageClass(fparam
.storageClass
);
815 /* See function parameters which wound up
816 * as part of a template tuple parameter.
818 if (fptupindex
!= IDX_NOTFOUND
&& parami
== fptupindex
)
820 TypeIdentifier tid
= prmtype
.isTypeIdentifier();
824 /* The types of the function arguments
825 * now form the tuple argument.
827 declaredTuple
= new Tuple();
828 (*dedargs
)[td
.parameters
.length
- 1] = declaredTuple
;
830 /* Count function parameters with no defaults following a tuple parameter.
831 * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
834 foreach (j
; parami
+ 1 .. nfparams
)
836 Parameter p
= fparameters
[j
];
841 if (!reliesOnTemplateParameters(p
.type
, (*td
.parameters
)[inferStart
.. td
.parameters
.length
]))
843 Type pt
= p
.type
.syntaxCopy().typeSemantic(fd
.loc
, paramscope
);
844 if (auto ptt
= pt
.isTypeTuple())
845 rem
+= ptt
.arguments
.length
;
855 if (nfargs2
- argi
< rem
)
857 declaredTuple
.objects
.setDim(nfargs2
- argi
- rem
);
858 foreach (i
; 0 .. declaredTuple
.objects
.length
)
860 farg
= fargs
[argi
+ i
];
862 // Check invalid arguments to detect errors early.
863 if (farg
.op
== EXP
.error || farg
.type
.ty
== Terror
)
866 if (!fparam
.isLazy() && farg
.type
.ty
== Tvoid
)
871 if (ubyte wm
= deduceWildHelper(farg
.type
, &tt
, tid
))
878 m
= deduceTypeHelper(farg
.type
, tt
, tid
);
880 if (m
== MATCH
.nomatch
)
885 /* Remove top const for dynamic array types and pointer types
887 if ((tt
.ty
== Tarray || tt
.ty
== Tpointer
) && !tt
.isMutable() && (!(fparam
.storageClass
& STC
.ref_
) ||
(fparam
.storageClass
& STC
.auto_
) && !farg
.isLvalue()))
891 declaredTuple
.objects
[i
] = tt
;
893 td
.declareParameter(paramscope
, tp
, declaredTuple
);
897 // https://issues.dlang.org/show_bug.cgi?id=6810
898 // If declared tuple is not a type tuple,
899 // it cannot be function parameter types.
900 for (size_t i
= 0; i
< declaredTuple
.objects
.length
; i
++)
902 if (!isType(declaredTuple
.objects
[i
]))
906 assert(declaredTuple
);
907 argi
+= declaredTuple
.objects
.length
;
911 // If parameter type doesn't depend on inferred template parameters,
912 // semantic it to get actual type.
913 if (!reliesOnTemplateParameters(prmtype
, (*td
.parameters
)[inferStart
.. td
.parameters
.length
]))
915 // should copy prmtype to avoid affecting semantic result
916 prmtype
= prmtype
.syntaxCopy().typeSemantic(fd
.loc
, paramscope
);
918 if (TypeTuple tt
= prmtype
.isTypeTuple())
920 const tt_dim
= tt
.arguments
.length
;
921 for (size_t j
= 0; j
< tt_dim
; j
++, ++argi
)
923 Parameter p
= (*tt
.arguments
)[j
];
924 if (j
== tt_dim
- 1 && fparameters
.varargs
== VarArg
.typesafe
&&
925 parami
+ 1 == nfparams
&& argi
< fargs
.length
)
930 if (argi
>= fargs
.length
)
935 // https://issues.dlang.org/show_bug.cgi?id=19888
936 if (fparam
.defaultArg
)
942 if (!farg
.implicitConvTo(p
.type
))
949 if (argi
>= fargs
.length
) // if not enough arguments
951 if (!fparam
.defaultArg
)
954 /* https://issues.dlang.org/show_bug.cgi?id=2803
955 * Before the starting of type deduction from the function
956 * default arguments, set the already deduced parameters into paramscope.
957 * It's necessary to avoid breaking existing acceptable code. Cases:
959 * 1. Already deduced template parameters can appear in fparam.defaultArg:
960 * auto foo(A, B)(A a, B b = A.stringof);
962 * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
964 * 2. If prmtype depends on default-specified template parameter, the
965 * default type should be preferred.
966 * auto foo(N = size_t, R)(R r, N start = 0)
968 * // at fparam `N start = 0`, N should be 'size_t' before
969 * // the deduction result from fparam.defaultArg.
971 if (argi
== fargs
.length
)
973 foreach (ref dedtype
; *dedtypes
)
975 Type at
= isType(dedtype
);
976 if (at
&& at
.ty
== Tnone
)
978 TypeDeduced xt
= cast(TypeDeduced
)at
;
979 dedtype
= xt
.tded
; // 'unbox'
982 for (size_t i
= ntargs
; i
< dedargs
.length
; i
++)
984 TemplateParameter tparam
= (*td
.parameters
)[i
];
986 RootObject oarg
= (*dedargs
)[i
];
987 RootObject oded
= (*dedtypes
)[i
];
993 if (tparam
.specialization() ||
!tparam
.isTemplateTypeParameter())
995 /* The specialization can work as long as afterwards
998 (*dedargs
)[i
] = oded
;
999 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, td
.parameters
, *dedtypes
, null);
1000 //printf("m2 = %d\n", m2);
1001 if (m2
== MATCH
.nomatch
)
1003 if (m2
< matchTiargs
)
1004 matchTiargs
= m2
; // pick worst match
1005 if (!(*dedtypes
)[i
].equals(oded
))
1006 .error(td
.loc
, "%s `%s` specialization not allowed for deduced parameter `%s`",
1007 td
.kind
, td
.toPrettyChars
, td
.kind
, td
.toPrettyChars
, tparam
.ident
.toChars());
1011 if (MATCH
.convert
< matchTiargs
)
1012 matchTiargs
= MATCH
.convert
;
1014 (*dedargs
)[i
] = td
.declareParameter(paramscope
, tparam
, oded
);
1018 oded
= tparam
.defaultArg(instLoc
, paramscope
);
1020 (*dedargs
)[i
] = td
.declareParameter(paramscope
, tparam
, oded
);
1026 /* If prmtype does not depend on any template parameters:
1028 * auto foo(T)(T v, double x = 0);
1030 * // at fparam == 'double x = 0'
1032 * or, if all template parameters in the prmtype are already deduced:
1034 * auto foo(R)(R range, ElementType!R sum = 0);
1036 * // at fparam == 'ElementType!R sum = 0'
1038 * Deducing prmtype from fparam.defaultArg is not necessary.
1040 if (prmtype
.deco || prmtype
.syntaxCopy().trySemantic(td
.loc
, paramscope
))
1046 // Deduce prmtype from the defaultArg.
1047 farg
= fparam
.defaultArg
.syntaxCopy();
1048 farg
= farg
.expressionSemantic(paramscope
);
1049 farg
= resolveProperties(paramscope
, farg
);
1056 // Check invalid arguments to detect errors early.
1057 if (farg
.op
== EXP
.error || farg
.type
.ty
== Terror
)
1064 printf("\tfarg.type = %s\n", farg
.type
.toChars());
1065 printf("\tfparam.type = %s\n", prmtype
.toChars());
1067 Type argtype
= farg
.type
;
1069 if (!fparam
.isLazy() && argtype
.ty
== Tvoid
&& farg
.op
!= EXP
.function_
)
1072 // https://issues.dlang.org/show_bug.cgi?id=12876
1073 // Optimize argument to allow CT-known length matching
1074 farg
= farg
.optimize(WANTvalue
, fparam
.isReference());
1075 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
1077 RootObject oarg
= farg
;
1078 if ((fparam
.storageClass
& STC
.ref_
) && (!(fparam
.storageClass
& STC
.auto_
) || farg
.isLvalue()))
1080 /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
1082 bool inferIndexType
= (argtype
.ty
== Tarray
) && (prmtype
.ty
== Tsarray || prmtype
.ty
== Taarray
);
1083 if (auto aaType
= prmtype
.isTypeAArray())
1085 if (auto indexType
= aaType
.index
.isTypeIdentifier())
1087 inferIndexType
= indexType
.idents
.length
== 0;
1092 if (StringExp se
= farg
.isStringExp())
1094 argtype
= se
.type
.nextOf().sarrayOf(se
.len
);
1096 else if (ArrayLiteralExp ae
= farg
.isArrayLiteralExp())
1098 argtype
= ae
.type
.nextOf().sarrayOf(ae
.elements
.length
);
1100 else if (SliceExp se
= farg
.isSliceExp())
1102 if (Type tsa
= toStaticArrayType(se
))
1109 else if ((fparam
.storageClass
& STC
.out_
) == 0 &&
1110 (argtype
.ty
== Tarray || argtype
.ty
== Tpointer
) &&
1111 templateParameterLookup(prmtype
, td
.parameters
) != IDX_NOTFOUND
&&
1112 prmtype
.isTypeIdentifier().idents
.length
== 0)
1114 /* The farg passing to the prmtype always make a copy. Therefore,
1115 * we can shrink the set of the deduced type arguments for prmtype
1116 * by adjusting top-qualifier of the argtype.
1118 * prmtype argtype ta
1119 * T <- const(E)[] const(E)[]
1120 * T <- const(E[]) const(E)[]
1121 * qualifier(T) <- const(E)[] const(E[])
1122 * qualifier(T) <- const(E[]) const(E[])
1124 Type ta
= argtype
.castMod(prmtype
.mod ? argtype
.nextOf().mod
: 0);
1127 Expression ea
= farg
.copy();
1133 if (fparameters
.varargs
== VarArg
.typesafe
&& parami
+ 1 == nfparams
&& argi
+ 1 < fargs
.length
)
1137 MATCH m
= deduceType(oarg
, paramscope
, prmtype
, *td
.parameters
, *dedtypes
, &im
, inferStart
);
1138 //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
1141 /* If no match, see if the argument can be matched by using
1142 * implicit conversions.
1144 if (m
== MATCH
.nomatch
&& prmtype
.deco
)
1145 m
= farg
.implicitConvTo(prmtype
);
1147 if (m
== MATCH
.nomatch
)
1149 AggregateDeclaration ad
= isAggregate(farg
.type
);
1150 if (ad
&& ad
.aliasthis
&& !isRecursiveAliasThis(att
, argtype
))
1152 // https://issues.dlang.org/show_bug.cgi?id=12537
1153 // The isRecursiveAliasThis() call above
1155 /* If a semantic error occurs while doing alias this,
1156 * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
1157 * just regard it as not a match.
1159 * We also save/restore sc.func.flags to avoid messing up
1160 * attribute inference in the evaluation.
1162 const oldflags
= sc
.func ? sc
.func
.flags
: 0;
1163 auto e
= resolveAliasThis(sc
, farg
, true);
1165 sc
.func
.flags
= oldflags
;
1174 if (m
> MATCH
.nomatch
&& (fparam
.storageClass
& (STC
.ref_ | STC
.auto_
)) == STC
.ref_
)
1176 if (!farg
.isLvalue())
1178 if ((farg
.op
== EXP
.string_ || farg
.op
== EXP
.slice
) && (prmtype
.ty
== Tsarray || prmtype
.ty
== Taarray
))
1180 // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
1182 else if (global
.params
.rvalueRefParam
== FeatureState
.enabled
)
1184 // Allow implicit conversion to ref
1190 if (m
> MATCH
.nomatch
&& (fparam
.storageClass
& STC
.out_
))
1192 if (!farg
.isLvalue())
1194 if (!farg
.type
.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1197 if (m
== MATCH
.nomatch
&& fparam
.isLazy() && prmtype
.ty
== Tvoid
&& farg
.type
.ty
!= Tvoid
)
1199 if (m
!= MATCH
.nomatch
)
1202 match
= m
; // pick worst match
1209 /* The following code for variadic arguments closely
1210 * matches TypeFunction.callMatch()
1212 if (!(fparameters
.varargs
== VarArg
.typesafe
&& parami
+ 1 == nfparams
))
1215 /* Check for match with function parameter T...
1217 Type tb
= prmtype
.toBasetype();
1220 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1224 // Perhaps we can do better with this, see TypeFunction.callMatch()
1225 if (TypeSArray tsa
= tb
.isTypeSArray())
1227 dinteger_t sz
= tsa
.dim
.toInteger();
1228 if (sz
!= fargs
.length
- argi
)
1231 else if (TypeAArray taa
= tb
.isTypeAArray())
1233 Expression dim
= new IntegerExp(instLoc
, fargs
.length
- argi
, Type
.tsize_t
);
1235 size_t i
= templateParameterLookup(taa
.index
, td
.parameters
);
1236 if (i
== IDX_NOTFOUND
)
1243 uint errors
= global
.startGagging();
1244 /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
1245 * The parameter isn't part of the template
1246 * ones, let's try to find it in the
1247 * instantiation scope 'sc' and the one
1248 * belonging to the template itself. */
1250 taa
.index
.resolve(instLoc
, sco
, e
, t
, s
);
1254 taa
.index
.resolve(instLoc
, sco
, e
, t
, s
);
1256 global
.endGagging(errors
);
1261 e
= e
.ctfeInterpret();
1262 e
= e
.implicitCastTo(sco
, Type
.tsize_t
);
1263 e
= e
.optimize(WANTvalue
);
1269 // This code matches code in TypeInstance.deduceType()
1270 TemplateParameter tprm
= (*td
.parameters
)[i
];
1271 TemplateValueParameter tvp
= tprm
.isTemplateValueParameter();
1274 Expression e
= cast(Expression
)(*dedtypes
)[i
];
1282 Type vt
= tvp
.valType
.typeSemantic(Loc
.initial
, sc
);
1283 MATCH m
= dim
.implicitConvTo(vt
);
1284 if (m
== MATCH
.nomatch
)
1286 (*dedtypes
)[i
] = dim
;
1294 TypeArray ta
= cast(TypeArray
)tb
;
1295 Type tret
= fparam
.isLazyArray();
1296 for (; argi
< fargs
.length
; argi
++)
1298 Expression arg
= fargs
[argi
];
1302 /* If lazy array of delegates,
1303 * convert arg(s) to delegate(s)
1307 if (ta
.next
.equals(arg
.type
))
1313 m
= arg
.implicitConvTo(tret
);
1314 if (m
== MATCH
.nomatch
)
1316 if (tret
.toBasetype().ty
== Tvoid
)
1324 m
= deduceType(arg
, paramscope
, ta
.next
, *td
.parameters
, *dedtypes
, &wm
, inferStart
);
1327 if (m
== MATCH
.nomatch
)
1343 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
1344 if (argi
!= nfargs2
&& fparameters
.varargs
== VarArg
.none
)
1349 foreach (ref dedtype
; *dedtypes
)
1351 if (Type at
= isType(dedtype
))
1355 TypeDeduced xt
= cast(TypeDeduced
)at
;
1356 at
= xt
.tded
; // 'unbox'
1358 dedtype
= at
.merge2();
1361 for (size_t i
= ntargs
; i
< dedargs
.length
; i
++)
1363 TemplateParameter tparam
= (*td
.parameters
)[i
];
1364 //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
1366 /* For T:T*, the dedargs is the T*, dedtypes is the T
1367 * But for function templates, we really need them to match
1369 RootObject oarg
= (*dedargs
)[i
];
1370 RootObject oded
= (*dedtypes
)[i
];
1371 //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
1372 //if (oarg) printf("oarg: %s\n", oarg.toChars());
1373 //if (oded) printf("oded: %s\n", oded.toChars());
1379 if (tparam
.specialization() ||
!tparam
.isTemplateTypeParameter())
1381 /* The specialization can work as long as afterwards
1384 (*dedargs
)[i
] = oded
;
1385 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, td
.parameters
, *dedtypes
, null);
1386 //printf("m2 = %d\n", m2);
1387 if (m2
== MATCH
.nomatch
)
1389 if (m2
< matchTiargs
)
1390 matchTiargs
= m2
; // pick worst match
1391 if (!(*dedtypes
)[i
].equals(oded
))
1392 .error(td
.loc
, "%s `%s` specialization not allowed for deduced parameter `%s`", td
.kind
, td
.toPrettyChars
, tparam
.ident
.toChars());
1396 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
1397 if (MATCH
.convert
< matchTiargs
)
1398 matchTiargs
= MATCH
.convert
;
1403 oded
= tparam
.defaultArg(instLoc
, paramscope
);
1406 // if tuple parameter and
1407 // tuple parameter was not in function parameter list and
1408 // we're one or more arguments short (i.e. no tuple argument)
1410 fptupindex
== IDX_NOTFOUND
&&
1411 ntargs
<= dedargs
.length
- 1)
1413 // make tuple argument an empty tuple
1420 return matcherror();
1423 /* At the template parameter T, the picked default template argument
1424 * X!int should be matched to T in order to deduce dependent
1425 * template parameter A.
1426 * auto foo(T : X!A = X!int, A...)() { ... }
1427 * foo(); // T <-- X!int, A <-- (int)
1429 if (tparam
.specialization())
1431 (*dedargs
)[i
] = oded
;
1432 MATCH m2
= tparam
.matchArg(instLoc
, paramscope
, dedargs
, i
, td
.parameters
, *dedtypes
, null);
1433 //printf("m2 = %d\n", m2);
1434 if (m2
== MATCH
.nomatch
)
1436 if (m2
< matchTiargs
)
1437 matchTiargs
= m2
; // pick worst match
1438 if (!(*dedtypes
)[i
].equals(oded
))
1439 .error(td
.loc
, "%s `%s` specialization not allowed for deduced parameter `%s`", td
.kind
, td
.toPrettyChars
, tparam
.ident
.toChars());
1442 oded
= td
.declareParameter(paramscope
, tparam
, oded
);
1443 (*dedargs
)[i
] = oded
;
1446 /* https://issues.dlang.org/show_bug.cgi?id=7469
1447 * As same as the code for 7469 in findBestMatch,
1448 * expand a Tuple in dedargs to normalize template arguments.
1450 if (auto d
= dedargs
.length
)
1452 if (auto va
= isTuple((*dedargs
)[d
- 1]))
1454 dedargs
.setDim(d
- 1);
1455 dedargs
.insert(d
- 1, &va
.objects
);
1458 ti
.tiargs
= dedargs
; // update to the normalized template arguments.
1460 // Partially instantiate function for constraint and fd.leastAsSpecialized()
1462 assert(paramscope
.scopesym
);
1463 Scope
* sc2
= td
._scope
;
1464 sc2
= sc2
.push(paramscope
.scopesym
);
1468 sc2
.minst
= sc
.minst
;
1469 sc2
.stc |
= fd
.storage_class
& STC
.deprecated_
;
1471 fd
= td
.doHeaderInstantiation(ti
, sc2
, fd
, tthis
, argumentList
.arguments
);
1481 if (!evaluateConstraint(td
, ti
, sc
, paramscope
, dedargs
, fd
))
1487 for (size_t i
= 0; i
< dedargs
.length
; i
++)
1489 RootObject o
= (*dedargs
)[i
];
1490 printf("\tdedargs[%d] = %d, %s\n", i
, o
.dyncast(), o
.toChars());
1495 //printf("\tmatch %d\n", match);
1496 return MATCHpair(matchTiargs
, match
);