d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / templatesem.d
blob1942afe44ae23cd3207427c06319d3e944b38269
1 /**
2 * Template semantics.
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;
16 import dmd.aggregate;
17 import dmd.aliasthis;
18 import dmd.arraytypes;
19 import dmd.astenums;
20 import dmd.ast_node;
21 import dmd.attrib;
22 import dmd.dcast;
23 import dmd.dclass;
24 import dmd.declaration;
25 import dmd.dinterpret;
26 import dmd.dmangle;
27 import dmd.dmodule;
28 import dmd.dscope;
29 import dmd.dsymbol;
30 import dmd.dsymbolsem;
31 import dmd.dtemplate;
32 import dmd.errors;
33 import dmd.errorsink;
34 import dmd.expression;
35 import dmd.expressionsem;
36 import dmd.func;
37 import dmd.funcsem;
38 import dmd.globals;
39 import dmd.hdrgen;
40 import dmd.id;
41 import dmd.identifier;
42 import dmd.impcnvtab;
43 import dmd.init;
44 import dmd.initsem;
45 import dmd.location;
46 import dmd.mtype;
47 import dmd.opover;
48 import dmd.optimize;
49 import dmd.root.array;
50 import dmd.common.outbuffer;
51 import dmd.rootobject;
52 import dmd.semantic2;
53 import dmd.semantic3;
54 import dmd.tokens;
55 import dmd.typesem;
56 import dmd.visitor;
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[].
62 * Params:
63 * sc = context
64 * td = template
65 * ti = instance of td
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.
72 public
73 MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag)
75 enum LOGM = 0;
76 static if (LOGM)
78 printf("\n+TemplateDeclaration.matchWithInstance(td = %s, ti = %s, flag = %d)\n", td.toChars(), ti.toChars(), flag);
80 version (none)
82 printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length);
83 if (ti.tiargs.length)
84 printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]);
86 MATCH nomatch()
88 static if (LOGM)
90 printf(" no match\n");
92 return MATCH.nomatch;
94 MATCH m;
95 size_t dedtypes_dim = dedtypes.length;
97 dedtypes.zero();
99 if (td.errors)
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)
108 static if (LOGM)
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);
118 assert(td._scope);
120 // Set up scope for template parameters
121 Scope* paramscope = createScopeForTemplateParameters(td, ti, sc);
123 // Attempt type deduction
124 m = MATCH.exact;
125 for (size_t i = 0; i < dedtypes_dim; i++)
127 MATCH m2;
128 TemplateParameter tp = (*td.parameters)[i];
129 Declaration sparam;
131 //printf("\targument [%d]\n", i);
132 static if (LOGM)
134 //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
135 TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
136 if (ttp)
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)
144 version (none)
146 printf("\tmatchArg() for parameter %i failed\n", i);
148 return nomatch();
151 if (m2 < m)
152 m = m2;
154 if (!flag)
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
160 return nomatch();
164 if (!flag)
166 /* Any parameter left without a type gets the type of
167 * its corresponding arg
169 foreach (i, ref dedtype; dedtypes)
171 if (!dedtype)
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;
183 else
184 ti.parent = td.parent;
186 // Similar to doHeaderInstantiation
187 FuncDeclaration fd = td.onemember ? td.onemember.isFuncDeclaration() : null;
188 if (fd)
190 TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
191 if (argumentList.hasNames)
192 return nomatch();
193 Expressions* fargs = argumentList.arguments;
194 // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null);
195 // if (!fargs)
196 // return nomatch();
198 fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
199 fd.parent = ti;
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;
206 tf.next = null;
207 tf.incomplete = true;
209 // Resolve parameter types and 'auto ref's.
210 tf.fargs = fargs;
211 uint olderrors = global.startGagging();
212 fd.type = tf.typeSemantic(td.loc, paramscope);
213 global.endGagging(olderrors);
214 if (fd.type.ty != Tfunction)
215 return nomatch();
216 fd.originalType = fd.type; // for mangling
219 // TODO: dedtypes => ti.tiargs ?
220 if (!evaluateConstraint(td, ti, sc, paramscope, &dedtypes, fd))
221 return nomatch();
224 static if (LOGM)
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];
235 RootObject oarg;
236 printf(" [%d]", i);
237 if (i < ti.tiargs.length)
238 oarg = (*ti.tiargs)[i];
239 else
240 oarg = null;
241 tp.print(oarg, (*dedtypes)[i]);
244 else
245 return nomatch();
247 static if (LOGM)
249 printf(" match = %d\n", m);
252 paramscope.pop();
253 static if (LOGM)
255 printf("-TemplateDeclaration.matchWithInstance(td = %s, ti = %s) = %d\n", td.toChars(), ti.toChars(), m);
257 return 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))
281 continue;
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
284 * instantiations.
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)
294 return false;
296 /* BUG: should also check for ref param differences
300 TemplatePrevious pr;
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);
307 scx.parent = ti;
308 scx.tinst = null;
309 scx.minst = null;
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;
316 assert(!ti.symtab);
317 if (fd)
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();
324 scx.parent = fd;
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)
342 if (!fparam.ident)
343 continue;
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);
349 if (!ti.symtab)
350 ti.symtab = new DsymbolTable();
351 if (!scx.insert(v))
352 .error(td.loc, "%s `%s` parameter `%s.%s` is already defined", td.kind, td.toPrettyChars, td.toChars(), v.toChars());
353 else
354 v.parent = fd;
356 if (td.isstatic)
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()
369 bool errors;
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);
377 ti.inst = null;
378 ti.symtab = null;
379 scx = scx.pop();
380 td.previous = pr.prev; // unlink from threaded list
381 if (errors)
382 return false;
383 return result;
386 /*******************************************
387 * Append to buf a textual representation of template parameters with their arguments.
388 * Params:
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);
401 size_t i;
402 for (; i < tiargs.length && i < end; i++)
404 if (i)
406 buf.writeByte(',');
407 buf.writenl();
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
415 if (variadic)
417 if (i)
419 buf.writeByte(',');
420 buf.writenl();
421 buf.writestring(" ");
423 write(buf, parameters[end]);
424 buf.writestring(" = ");
425 buf.writeByte('(');
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]);
435 buf.writeByte(')');
437 buf.writeByte('`');
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
445 * paramsym.
446 * Params:
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
450 * Returns:
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;
461 paramscope.stc = 0;
462 return paramscope;
465 /********************************************
466 * Determine partial specialization order of `td` vs `td2`.
467 * Params:
468 * sc = context
469 * td = first template
470 * td2 = second template
471 * argumentList = arguments to template
472 * Returns:
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
486 * instance.
487 * If it works, then this template is at least as specialized
488 * as td2.
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)
497 if (tp.dependent)
498 break;
499 RootObject p = tp.dummyArg();
500 if (!p) //TemplateTupleParameter
501 break;
503 tiargs.push(p);
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
515 * variadic one.
517 TemplateTupleParameter tp = td.isVariadic();
518 if (tp && !tp.dependent && !td2.isVariadic())
519 goto L1;
521 static if (LOG_LEASTAS)
523 printf(" matches %d, so is least as specialized\n", m);
525 return 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.
538 * Params:
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
546 * Returns:
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)
551 version (none)
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());
561 if (tthis)
562 printf("tthis = %s\n", tthis.toChars());
565 assert(td._scope);
567 auto dedargs = new Objects(td.parameters.length);
568 dedargs.zero();
570 Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
571 dedtypes.setDim(td.parameters.length);
572 dedtypes.zero();
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);
580 MATCHpair nomatch()
582 paramscope.pop();
583 //printf("\tnomatch\n");
584 return MATCHpair(MATCH.nomatch, MATCH.nomatch);
587 MATCHpair matcherror()
589 // todo: for the future improvement
590 paramscope.pop();
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;
602 version (none)
604 for (size_t i = 0; i < dedargs.length; i++)
606 printf("\tdedarg[%d] = ", i);
607 RootObject oarg = (*dedargs)[i];
608 if (oarg)
609 printf("%s", oarg.toChars());
610 printf("\n");
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;
624 if (tp)
625 n--;
626 if (ntargs > n)
628 if (!tp)
629 return nomatch();
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);
643 declaredTuple = t;
645 else
646 n = ntargs;
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)
657 return nomatch();
658 if (m < matchTiargs)
659 matchTiargs = m;
661 sparam.dsymbolSemantic(paramscope);
662 if (!paramscope.insert(sparam))
663 return nomatch();
665 if (n < td.parameters.length && !declaredTuple)
667 inferStart = n;
669 else
670 inferStart = td.parameters.length;
671 //printf("tiargs matchTiargs = %d\n", matchTiargs);
673 version (none)
675 for (size_t i = 0; i < dedargs.length; i++)
677 printf("\tdedarg[%d] = ", i);
678 RootObject oarg = (*dedargs)[i];
679 if (oarg)
680 printf("%s", oarg.toChars());
681 printf("\n");
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
705 if (!declaredTuple)
707 auto t = new Tuple();
708 //printf("t = %p\n", t);
709 (*dedargs)[td.parameters.length - 1] = t;
710 td.declareParameter(paramscope, tp, t);
711 declaredTuple = t;
714 else
716 /* Figure out which of the function parameters matches
717 * the tuple template parameter. Do this by matching
718 * type identifiers.
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)
725 continue;
726 TypeIdentifier tid = fparam.type.isTypeIdentifier();
727 if (!tp.ident.equals(tid.ident) || tid.idents.length)
728 continue;
730 if (fparameters.varargs != VarArg.none) // variadic function doesn't
731 return nomatch(); // go with variadic template
733 goto L1;
735 fptupindex = IDX_NOTFOUND;
740 MATCH match = MATCH.exact;
741 if (td.toParent().isModule())
742 tthis = null;
743 if (tthis)
745 bool hasttp = false;
747 // Match 'tthis' to any TemplateThisParameter's
748 foreach (param; *td.parameters)
750 if (auto ttp = param.isTemplateThisParameter())
752 hasttp = true;
754 Type t = new TypeIdentifier(Loc.initial, ttp.ident);
755 MATCH m = deduceType(tthis, paramscope, t, *td.parameters, *dedtypes);
756 if (m == MATCH.nomatch)
757 return nomatch();
758 if (m < match)
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())
770 p = p.parent;
771 AggregateDeclaration ad = p.isAggregateDeclaration();
772 if (ad)
773 stc |= ad.storage_class;
775 ubyte mod = fd.type.mod;
776 if (stc & STC.immutable_)
777 mod = MODFlags.immutable_;
778 else
780 if (stc & (STC.shared_ | STC.synchronized_))
781 mod |= MODFlags.shared_;
782 if (stc & STC.const_)
783 mod |= MODFlags.const_;
784 if (stc & STC.wild)
785 mod |= MODFlags.wild;
788 ubyte thismod = tthis.mod;
789 if (hasttp)
790 mod = MODmerge(thismod, mod);
791 MATCH m = MODmethodConv(thismod, mod);
792 if (m == MATCH.nomatch)
793 return nomatch();
794 if (m < match)
795 match = m;
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);
803 size_t argi = 0;
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);
813 Expression farg;
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();
821 assert(tid);
822 if (!declaredTuple)
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)
833 size_t rem = 0;
834 foreach (j; parami + 1 .. nfparams)
836 Parameter p = fparameters[j];
837 if (p.defaultArg)
839 break;
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;
846 else
847 rem += 1;
849 else
851 ++rem;
855 if (nfargs2 - argi < rem)
856 return nomatch();
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)
864 return nomatch();
866 if (!fparam.isLazy() && farg.type.ty == Tvoid)
867 return nomatch();
869 Type tt;
870 MATCH m;
871 if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
873 inoutMatch |= wm;
874 m = MATCH.constant;
876 else
878 m = deduceTypeHelper(farg.type, tt, tid);
880 if (m == MATCH.nomatch)
881 return nomatch();
882 if (m < match)
883 match = m;
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()))
889 tt = tt.mutableOf();
891 declaredTuple.objects[i] = tt;
893 td.declareParameter(paramscope, tp, declaredTuple);
895 else
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]))
903 return nomatch();
906 assert(declaredTuple);
907 argi += declaredTuple.objects.length;
908 continue;
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)
927 prmtype = p.type;
928 goto Lvarargs;
930 if (argi >= fargs.length)
932 if (p.defaultArg)
933 continue;
935 // https://issues.dlang.org/show_bug.cgi?id=19888
936 if (fparam.defaultArg)
937 break;
939 return nomatch();
941 farg = fargs[argi];
942 if (!farg.implicitConvTo(p.type))
943 return nomatch();
945 continue;
949 if (argi >= fargs.length) // if not enough arguments
951 if (!fparam.defaultArg)
952 goto Lvarargs;
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);
961 * foo(1);
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)
967 * foo([1,2,3]);
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];
988 if (oarg)
989 continue;
991 if (oded)
993 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
995 /* The specialization can work as long as afterwards
996 * the oded == oarg
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)
1002 return 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());
1009 else
1011 if (MATCH.convert < matchTiargs)
1012 matchTiargs = MATCH.convert;
1014 (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded);
1016 else
1018 oded = tparam.defaultArg(instLoc, paramscope);
1019 if (oded)
1020 (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded);
1024 nfargs2 = argi + 1;
1026 /* If prmtype does not depend on any template parameters:
1028 * auto foo(T)(T v, double x = 0);
1029 * foo("str");
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);
1035 * foo([1,2,3]);
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))
1042 ++argi;
1043 continue;
1046 // Deduce prmtype from the defaultArg.
1047 farg = fparam.defaultArg.syntaxCopy();
1048 farg = farg.expressionSemantic(paramscope);
1049 farg = resolveProperties(paramscope, farg);
1051 else
1053 farg = fargs[argi];
1056 // Check invalid arguments to detect errors early.
1057 if (farg.op == EXP.error || farg.type.ty == Terror)
1058 return nomatch();
1060 Type att = null;
1061 Lretry:
1062 version (none)
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_)
1070 return nomatch();
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;
1090 if (inferIndexType)
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))
1103 argtype = tsa;
1107 oarg = argtype;
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);
1125 if (ta != argtype)
1127 Expression ea = farg.copy();
1128 ea.type = ta;
1129 oarg = ea;
1133 if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length)
1134 goto Lvarargs;
1136 uint im = 0;
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);
1139 inoutMatch |= im;
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);
1164 if (sc.func)
1165 sc.func.flags = oldflags;
1166 if (e)
1168 farg = e;
1169 goto Lretry;
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
1186 else
1187 return nomatch();
1190 if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
1192 if (!farg.isLvalue())
1193 return nomatch();
1194 if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
1195 return nomatch();
1197 if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
1198 m = MATCH.convert;
1199 if (m != MATCH.nomatch)
1201 if (m < match)
1202 match = m; // pick worst match
1203 argi++;
1204 continue;
1208 Lvarargs:
1209 /* The following code for variadic arguments closely
1210 * matches TypeFunction.callMatch()
1212 if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
1213 return nomatch();
1215 /* Check for match with function parameter T...
1217 Type tb = prmtype.toBasetype();
1218 switch (tb.ty)
1220 // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
1221 case Tsarray:
1222 case Taarray:
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)
1229 return nomatch();
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)
1238 Expression e;
1239 Type t;
1240 Dsymbol s;
1241 Scope *sco;
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. */
1249 sco = sc;
1250 taa.index.resolve(instLoc, sco, e, t, s);
1251 if (!e)
1253 sco = paramscope;
1254 taa.index.resolve(instLoc, sco, e, t, s);
1256 global.endGagging(errors);
1258 if (!e)
1259 return nomatch();
1261 e = e.ctfeInterpret();
1262 e = e.implicitCastTo(sco, Type.tsize_t);
1263 e = e.optimize(WANTvalue);
1264 if (!dim.equals(e))
1265 return nomatch();
1267 else
1269 // This code matches code in TypeInstance.deduceType()
1270 TemplateParameter tprm = (*td.parameters)[i];
1271 TemplateValueParameter tvp = tprm.isTemplateValueParameter();
1272 if (!tvp)
1273 return nomatch();
1274 Expression e = cast(Expression)(*dedtypes)[i];
1275 if (e)
1277 if (!dim.equals(e))
1278 return nomatch();
1280 else
1282 Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
1283 MATCH m = dim.implicitConvTo(vt);
1284 if (m == MATCH.nomatch)
1285 return nomatch();
1286 (*dedtypes)[i] = dim;
1290 goto case Tarray;
1292 case Tarray:
1294 TypeArray ta = cast(TypeArray)tb;
1295 Type tret = fparam.isLazyArray();
1296 for (; argi < fargs.length; argi++)
1298 Expression arg = fargs[argi];
1299 assert(arg);
1301 MATCH m;
1302 /* If lazy array of delegates,
1303 * convert arg(s) to delegate(s)
1305 if (tret)
1307 if (ta.next.equals(arg.type))
1309 m = MATCH.exact;
1311 else
1313 m = arg.implicitConvTo(tret);
1314 if (m == MATCH.nomatch)
1316 if (tret.toBasetype().ty == Tvoid)
1317 m = MATCH.convert;
1321 else
1323 uint wm = 0;
1324 m = deduceType(arg, paramscope, ta.next, *td.parameters, *dedtypes, &wm, inferStart);
1325 inoutMatch |= wm;
1327 if (m == MATCH.nomatch)
1328 return nomatch();
1329 if (m < match)
1330 match = m;
1332 goto Lmatch;
1334 case Tclass:
1335 case Tident:
1336 goto Lmatch;
1338 default:
1339 return nomatch();
1341 assert(0);
1343 //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
1344 if (argi != nfargs2 && fparameters.varargs == VarArg.none)
1345 return nomatch();
1348 Lmatch:
1349 foreach (ref dedtype; *dedtypes)
1351 if (Type at = isType(dedtype))
1353 if (at.ty == Tnone)
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());
1374 if (oarg)
1375 continue;
1377 if (oded)
1379 if (tparam.specialization() || !tparam.isTemplateTypeParameter())
1381 /* The specialization can work as long as afterwards
1382 * the oded == oarg
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)
1388 return 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());
1394 else
1396 // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
1397 if (MATCH.convert < matchTiargs)
1398 matchTiargs = MATCH.convert;
1401 else
1403 oded = tparam.defaultArg(instLoc, paramscope);
1404 if (!oded)
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)
1409 if (tparam == tp &&
1410 fptupindex == IDX_NOTFOUND &&
1411 ntargs <= dedargs.length - 1)
1413 // make tuple argument an empty tuple
1414 oded = new Tuple();
1416 else
1417 return nomatch();
1419 if (isError(oded))
1420 return matcherror();
1421 ntargs++;
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)
1435 return 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);
1465 sc2 = sc2.push(ti);
1466 sc2.parent = ti;
1467 sc2.tinst = ti;
1468 sc2.minst = sc.minst;
1469 sc2.stc |= fd.storage_class & STC.deprecated_;
1471 fd = td.doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments);
1472 sc2 = sc2.pop();
1473 sc2 = sc2.pop();
1475 if (!fd)
1476 return nomatch();
1479 if (td.constraint)
1481 if (!evaluateConstraint(td, ti, sc, paramscope, dedargs, fd))
1482 return nomatch();
1485 version (none)
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());
1494 paramscope.pop();
1495 //printf("\tmatch %d\n", match);
1496 return MATCHpair(matchTiargs, match);