Mercurial > projects > ddmd
diff dmd/TemplateDeclaration.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | d42cd5917df4 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/TemplateDeclaration.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1143 @@ +module dmd.TemplateDeclaration; + +import dmd.Loc; +import dmd.ScopeDsymbol; +import dmd.ArrayTypes; +import dmd.Dsymbol; +import dmd.STC; +import dmd.TemplateThisParameter; +import dmd.Global; +import dmd.Array; +import dmd.Identifier; +import dmd.TypeArray; +import dmd.Expression; +import dmd.Scope; +import dmd.TypeIdentifier; +import dmd.TypeDelegate; +import dmd.IntegerExp; +import dmd.TypeSArray; +import dmd.StringExp; +import dmd.TOK; +import dmd.Argument; +import dmd.CtorDeclaration; +import dmd.TypeFunction; +import dmd.TY; +import dmd.OutBuffer; +import dmd.Declaration; +import dmd.HdrGenState; +import dmd.TemplateInstance; +import dmd.WANT; +import dmd.FuncDeclaration; +import dmd.TemplateTupleParameter; +import dmd.MATCH; +import dmd.Type; +import dmd.Tuple; +import dmd.TupleDeclaration; +import dmd.Initializer; +import dmd.ExpInitializer; +import dmd.TemplateValueParameter; +import dmd.AliasDeclaration; +import dmd.VarDeclaration; +import dmd.TemplateParameter; +import dmd.TemplateTypeParameter; + +import dmd.expression.Util; + +import std.stdio; + +/************************************** + * Determine if TemplateDeclaration is variadic. + */ + +TemplateTupleParameter isVariadic(TemplateParameters parameters) +{ + size_t dim = parameters.dim; + TemplateTupleParameter tp = null; + + if (dim) + tp = (cast(TemplateParameter)parameters.data[dim - 1]).isTemplateTupleParameter(); + + return tp; +} + +void ObjectToCBuffer(OutBuffer buf, HdrGenState* hgs, Object oarg) +{ + //printf("ObjectToCBuffer()\n"); + Type t = isType(oarg); + Expression e = isExpression(oarg); + Dsymbol s = isDsymbol(oarg); + Tuple v = isTuple(oarg); + if (t) + { + //printf("\tt: %s ty = %d\n", t.toChars(), t.ty); + t.toCBuffer(buf, null, hgs); + } + else if (e) + e.toCBuffer(buf, hgs); + else if (s) + { + string p = s.ident ? s.ident.toChars() : s.toChars(); + buf.writestring(p); + } + else if (v) + { + Objects args = v.objects; + for (size_t i = 0; i < args.dim; i++) + { + if (i) + buf.writeByte(','); + Object o = cast(Object)args.data[i]; + ObjectToCBuffer(buf, hgs, o); + } + } + else if (!oarg) + { + buf.writestring("null"); + } + else + { + debug writef("bad Object = %p\n", oarg); + assert(0); + } +} + +class TemplateDeclaration : ScopeDsymbol +{ + TemplateParameters parameters; // array of TemplateParameter's + + TemplateParameters origParameters; // originals for Ddoc + Expression constraint; + Array instances; // array of TemplateInstance's + + TemplateDeclaration overnext; // next overloaded TemplateDeclaration + TemplateDeclaration overroot; // first in overnext list + + int semanticRun; // 1 semantic() run + + Dsymbol onemember; // if !=NULL then one member of this template + + int literal; // this template declaration is a literal + + this(Loc loc, Identifier id, TemplateParameters parameters, Expression constraint, Array decldefs) + { + super(id); + + version (LOG) { + printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id.toChars()); + } + static if (false) { + if (parameters) + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + //printf("\tparameter[%d] = %p\n", i, tp); + TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); + + if (ttp) + { + printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + } + } + + this.loc = loc; + this.parameters = parameters; + this.origParameters = parameters; + this.constraint = constraint; + this.members = decldefs; + + instances = new Array(); + } + + Dsymbol syntaxCopy(Dsymbol) + { + assert(false); + } + + void semantic(Scope sc) + { + version (LOG) { + printf("TemplateDeclaration.semantic(this = %p, id = '%s')\n", this, ident.toChars()); + } + if (semanticRun) + return; // semantic() already run + semanticRun = 1; + + if (sc.func) + { + version (DMDV1) { + error("cannot declare template at function scope %s", sc.func.toChars()); + } + } + + if (/*global.params.useArrayBounds &&*/ sc.module_) + { + // Generate this function as it may be used + // when template is instantiated in other modules + sc.module_.toModuleArray(); + } + + if (/*global.params.useAssert &&*/ sc.module_) + { + // Generate this function as it may be used + // when template is instantiated in other modules + sc.module_.toModuleAssert(); + } + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + this.scope_ = new Scope(sc); /// A light copy + this.scope_.setNoFree(); + + // Set up scope for parameters + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = sc.parent; + Scope paramscope = sc.push(paramsym); + paramscope.parameterSpecialization = 1; + paramscope.stc = STCundefined; + + if (!parent) + parent = sc.parent; + + if (global.params.doDocComments) + { + origParameters = new TemplateParameters(); + origParameters.setDim(parameters.dim); + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + origParameters.data[i] = cast(void*)tp.syntaxCopy(); + } + } + + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + tp.declareParameter(paramscope); + } + + for (int i = 0; i < parameters.dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + + tp.semantic(paramscope); + if (i + 1 != parameters.dim && tp.isTemplateTupleParameter()) + error("template tuple parameter must be last one"); + } + + paramscope.pop(); + + if (members) + { + Dsymbol s; + if (Dsymbol.oneMembers(members, &s)) + { + if (s && s.ident && s.ident.equals(ident)) + { + onemember = s; + s.parent = this; + } + } + } + + /* BUG: should check: + * o no virtual functions or non-static data members of classes + */ + } + + bool overloadInsert(Dsymbol s) + { + assert(false); + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + assert(false); + } + + string kind() + { + assert(false); + } + + string toChars() + { + assert(false); + } + + void emitComment(Scope sc) + { + assert(false); + } + +// void toDocBuffer(OutBuffer *buf); + + /*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Input: + * flag 1: don't do semantic() because of dummy types + * 2: don't change types in matchArg() + * Output: + * dedtypes deduced arguments + * Return match level. + */ + MATCH matchWithInstance(TemplateInstance ti, Objects dedtypes, int flag) + { + MATCH m; + int dedtypes_dim = dedtypes.dim; + + version (LOGM) { + printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); + } + + static if (false) { + printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes_dim, parameters.dim); + if (ti.tiargs.dim) + printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, ti.tiargs.data[0]); + } + dedtypes.zero(); + + int parameters_dim = parameters.dim; + int variadic = isVariadic() !is null; + + // If more arguments than parameters, no match + if (ti.tiargs.dim > parameters_dim && !variadic) + { + version (LOGM) { + printf(" no match: more arguments than parameters\n"); + } + return MATCHnomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti.tiargs.dim || variadic); + + // Set up scope for parameters + assert(cast(size_t)cast(void*)scope_ > 0x10000); + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = scope_.parent; + Scope paramscope = scope_.push(paramsym); + paramscope.stc = STCundefined; + + // Attempt type deduction + m = MATCHexact; + for (int i = 0; i < dedtypes_dim; i++) + { + MATCH m2; + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + Declaration sparam; + + //printf("\targument [%d]\n", i); + version (LOGM) { + //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); + TemplateTypeParameter *ttp = tp.isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + + version (DMDV1) { + m2 = tp.matchArg(paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); + } else { + m2 = tp.matchArg(paramscope, ti.tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); + } + //printf("\tm2 = %d\n", m2); + + if (m2 == MATCHnomatch) + { + static if (false) { + printf("\tmatchArg() for parameter %i failed\n", i); + } + goto Lnomatch; + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam.semantic(paramscope); + if (!paramscope.insert(sparam)) + goto Lnomatch; + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + for (int i = 0; i < dedtypes_dim; i++) + { + if (!dedtypes.data[i]) + { + assert(i < ti.tiargs.dim); + dedtypes.data[i] = ti.tiargs.data[i]; + } + } + } + + version (DMDV2) { + if (m && constraint && !(flag & 1)) + { /* Check to see if constraint is satisfied. + */ + Expression e = constraint.syntaxCopy(); + paramscope.flags |= SCOPE.SCOPEstaticif; + e = e.semantic(paramscope); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.isBool(true)) { + ; + } else if (e.isBool(false)) + goto Lnomatch; + else + { + e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); + } + } + } + + version (LOGM) { + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti.toChars()); + if (m) + { + for (int i = 0; i < dedtypes_dim; i++) + { + TemplateParameter tp = cast(TemplateParameter)parameters.data[i]; + Object oarg; + + printf(" [%d]", i); + + if (i < ti.tiargs.dim) + oarg = cast(Object)ti.tiargs.data[i]; + else + oarg = null; + tp.print(oarg, cast(Object)dedtypes.data[i]); + } + } + else + goto Lnomatch; + } + + version (LOGM) { + printf(" match = %d\n", m); + } + goto Lret; + + Lnomatch: + version (LOGM) { + printf(" no match\n"); + } + m = MATCHnomatch; + + Lret: + paramscope.pop(); + version (LOGM) { + printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); + } + return m; + } + + MATCH leastAsSpecialized(TemplateDeclaration td2) + { + assert(false); + } + + /************************************************* + * Match function arguments against a specific template function. + * Input: + * loc instantiation location + * targsi Expression/Type initial list of template arguments + * ethis 'this' argument if !null + * fargs arguments to function + * Output: + * dedargs Expression/Type deduced template arguments + * Returns: + * match level + */ + MATCH deduceFunctionTemplateMatch(Loc loc, Objects targsi, Expression ethis, Expressions fargs, Objects dedargs) + { + size_t nfparams; + size_t nfargs; + size_t nargsi; // array size of targsi + int fptupindex = -1; + int tuple_dim = 0; + MATCH match = MATCHexact; + FuncDeclaration fd = onemember.toAlias().isFuncDeclaration(); + Arguments fparameters; // function parameter list + int fvarargs; // function varargs + scope Objects dedtypes = new Objects(); // for T:T*, the dedargs is the T*, dedtypes is the T + + static if (false) { + printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); + for (i = 0; i < fargs.dim; i++) + { + Expression e = cast(Expression)fargs.data[i]; + printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars()); + } + printf("fd = %s\n", fd.toChars()); + printf("fd.type = %p\n", fd.type); + } + + assert(cast(size_t)cast(void*)scope_ > 0x10000); + + dedargs.setDim(parameters.dim); + dedargs.zero(); + + dedtypes.setDim(parameters.dim); + dedtypes.zero(); + + // Set up scope for parameters + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = scope_.parent; + Scope paramscope = scope_.push(paramsym); + + TemplateTupleParameter tp = isVariadic(); + + static if (false) { + for (i = 0; i < dedargs.dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object oarg = cast(Object)dedargs.data[i]; + if (oarg) printf("%s", oarg.toChars()); + printf("\n"); + } + } + + + nargsi = 0; + if (targsi) + { // Set initial template arguments + size_t n; + + nargsi = targsi.dim; + n = parameters.dim; + if (tp) + n--; + if (nargsi > n) + { + if (!tp) + goto Lnomatch; + + /* The extra initial template arguments + * now form the tuple argument. + */ + Tuple t = new Tuple(); + assert(parameters.dim); + dedargs.data[parameters.dim - 1] = cast(void*)t; + + tuple_dim = nargsi - n; + t.objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + t.objects.data[i] = cast(void*)targsi.data[n + i]; + } + declareParameter(paramscope, tp, t); + } + else + n = nargsi; + + memcpy(dedargs.data, targsi.data, n * (*dedargs.data).sizeof); + + for (size_t i = 0; i < n; i++) + { + assert(i < parameters.dim); + TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; + MATCH m; + Declaration sparam = null; + + m = tp2.matchArg(paramscope, dedargs, i, parameters, dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + + sparam.semantic(paramscope); + if (!paramscope.insert(sparam)) + goto Lnomatch; + } + } + static if (false) { + for (i = 0; i < dedargs.dim; i++) + { + printf("\tdedarg[%d] = ", i); + Object oarg = cast(Object)dedargs.data[i]; + if (oarg) printf("%s", oarg.toChars()); + printf("\n"); + } + } + + if (fd.type) + { + assert(fd.type.ty == Tfunction); + TypeFunction fdtype = cast(TypeFunction)fd.type; + fparameters = fdtype.parameters; + fvarargs = fdtype.varargs; + } + else + { + CtorDeclaration fctor = fd.isCtorDeclaration(); + assert(fctor); + fparameters = fctor.arguments; + fvarargs = fctor.varargs; + } + + nfparams = Argument.dim(fparameters); // number of function parameters + nfargs = fargs ? fargs.dim : 0; // number of function arguments + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * template Foo(T, A...) { void Foo(T t, A a); } + * void main() { Foo(1,2,3); } + */ + if (tp) // if variadic + { + if (nfparams == 0) // if no function parameters + { + Tuple t = new Tuple(); + //printf("t = %p\n", t); + dedargs.data[parameters.dim - 1] = cast(void*)t; + declareParameter(paramscope, tp, t); + goto L2; + } + else if (nfargs < nfparams - 1) + goto L1; + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + Argument fparam = cast(Argument)fparameters.data[fptupindex]; + if (fparam.type.ty != Tident) + continue; + TypeIdentifier tid = cast(TypeIdentifier)fparam.type; + if (!tp.ident.equals(tid.ident) || tid.idents.dim) + continue; + + if (fvarargs) // variadic function doesn't + goto Lnomatch; // go with variadic template + + /* The types of the function arguments + * now form the tuple argument. + */ + Tuple t = new Tuple(); + dedargs.data[parameters.dim - 1] = cast(void*)t; + + tuple_dim = nfargs - (nfparams - 1); + t.objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + Expression farg = cast(Expression)fargs.data[fptupindex + i]; + t.objects.data[i] = cast(void*)farg.type; + } + declareParameter(paramscope, tp, t); + goto L2; + } + fptupindex = -1; + } + } + + L1: + if (nfparams == nfargs) { + ; + } else if (nfargs > nfparams) { + if (fvarargs == 0) + goto Lnomatch; // too many args, no match + match = MATCHconvert; // match ... with a conversion + } + + L2: + version (DMDV2) { + // Match 'ethis' to any TemplateThisParameter's + if (ethis) + { + for (size_t i = 0; i < parameters.dim; i++) + { + TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; + TemplateThisParameter ttp = tp2.isTemplateThisParameter(); + if (ttp) + { + MATCH m; + + Type t = new TypeIdentifier(Loc(0), ttp.ident); + m = ethis.type.deduceType(paramscope, t, parameters, dedtypes); + if (!m) + goto Lnomatch; + if (m < match) + match = m; // pick worst match + } + } + } + } + + // Loop through the function parameters + for (size_t i = 0; i < nfparams; i++) + { + /* Skip over function parameters which wound up + * as part of a template tuple parameter. + */ + if (i == fptupindex) + { + if (fptupindex == nfparams - 1) + break; + i += tuple_dim - 1; + continue; + } + + Argument fparam = Argument.getNth(fparameters, i); + + if (i >= nfargs) // if not enough arguments + { + if (fparam.defaultArg) + { + /* Default arguments do not participate in template argument + * deduction. + */ + goto Lmatch; + } + } + else + { + Expression farg = cast(Expression)fargs.data[i]; + static if (false) { + printf("\tfarg.type = %s\n", farg.type.toChars()); + printf("\tfparam.type = %s\n", fparam.type.toChars()); + } + Type argtype = farg.type; + + version (DMDV2) { + /* Allow string literals which are type [] to match with [dim] + */ + if (farg.op == TOKstring) + { + StringExp se = cast(StringExp)farg; + if (!se.committed && argtype.ty == Tarray && + fparam.type.toBasetype().ty == Tsarray) + { + argtype = new TypeSArray(argtype.nextOf(), new IntegerExp(se.loc, se.len, Type.tindex)); + argtype = argtype.semantic(se.loc, null); + argtype = argtype.invariantOf(); + } + } + } + + MATCH m; + m = argtype.deduceType(paramscope, fparam.type, parameters, dedtypes); + //printf("\tdeduceType m = %d\n", m); + + /* If no match, see if there's a conversion to a delegate + */ + if (!m && fparam.type.toBasetype().ty == Tdelegate) + { + TypeDelegate td = cast(TypeDelegate)fparam.type.toBasetype(); + TypeFunction tf = cast(TypeFunction)td.next; + + if (!tf.varargs && Argument.dim(tf.parameters) == 0) + { + m = farg.type.deduceType(paramscope, tf.next, parameters, dedtypes); + if (!m && tf.next.toBasetype().ty == Tvoid) + m = MATCHconvert; + } + //printf("\tm2 = %d\n", m); + } + + if (m) + { + if (m < match) + match = m; // pick worst match + continue; + } + } + + /* The following code for variadic arguments closely + * matches TypeFunction.callMatch() + */ + if (!(fvarargs == 2 && i + 1 == nfparams)) + goto Lnomatch; + + /* Check for match with function parameter T... + */ + Type tb = fparam.type.toBasetype(); + switch (tb.ty) + { + // Perhaps we can do better with this, see TypeFunction.callMatch() + case Tsarray: + { + TypeSArray tsa = cast(TypeSArray)tb; + ulong sz = tsa.dim.toInteger(); + if (sz != nfargs - i) + goto Lnomatch; + } + case Tarray: + { + TypeArray ta = cast(TypeArray)tb; + for (; i < nfargs; i++) + { + Expression arg = cast(Expression)fargs.data[i]; + assert(arg); + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = fparam.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + { + m = MATCHexact; + } + else + { + m = arg.implicitConvTo(tret); + if (m == MATCHnomatch) + { + if (tret.toBasetype().ty == Tvoid) + m = MATCHconvert; + } + } + } + else + { + m = arg.type.deduceType(paramscope, ta.next, parameters, dedtypes); + //m = arg.implicitConvTo(ta.next); + } + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + goto Lnomatch; + } + } + + Lmatch: + + /* Fill in any missing arguments with their defaults. + */ + for (size_t i = nargsi; i < dedargs.dim; i++) + { + TemplateParameter tp2 = cast(TemplateParameter)parameters.data[i]; + //printf("tp2[%d] = %s\n", i, tp2.ident.toChars()); + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + Object oarg = cast(Object)dedargs.data[i]; + Object oded = cast(Object)dedtypes.data[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg.toChars()); + //if (oded) printf("oded: %s\n", oded.toChars()); + if (!oarg) + { + if (oded) + { + if (tp2.specialization()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + Declaration sparam; + dedargs.data[i] = cast(void*)oded; + MATCH m2 = tp2.matchArg(paramscope, dedargs, i, parameters, dedtypes, &sparam, 0); + //printf("m2 = %d\n", m2); + if (!m2) + goto Lnomatch; + if (m2 < match) + match = m2; // pick worst match + if (dedtypes.data[i] !is cast(void*)oded) + error("specialization not allowed for deduced parameter %s", tp2.ident.toChars()); + } + } + else + { + oded = tp2.defaultArg(loc, paramscope); + if (!oded) + goto Lnomatch; + } + declareParameter(paramscope, tp2, oded); + dedargs.data[i] = cast(void*)oded; + } + } + + version (DMDV2) { + if (constraint) + { /* Check to see if constraint is satisfied. + */ + Expression e = constraint.syntaxCopy(); + paramscope.flags |= SCOPE.SCOPEstaticif; + e = e.semantic(paramscope); + e = e.optimize(WANTvalue | WANTinterpret); + if (e.isBool(true)) { + ; + } else if (e.isBool(false)) + goto Lnomatch; + else + { + e.error("constraint %s is not constant or does not evaluate to a bool", e.toChars()); + } + } + } + + static if (false) { + for (i = 0; i < dedargs.dim; i++) + { + Type t = cast(Type)dedargs.data[i]; + printf("\tdedargs[%d] = %d, %s\n", i, t.dyncast(), t.toChars()); + } + } + + paramscope.pop(); + //printf("\tmatch %d\n", match); + return match; + + Lnomatch: + paramscope.pop(); + //printf("\tnomatch\n"); + return MATCHnomatch; + } + + /************************************************* + * Given function arguments, figure out which template function + * to expand, and return that function. + * If no match, give error message and return null. + * Input: + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !null, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return null + */ + FuncDeclaration deduceFunctionTemplate(Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions fargs, int flags = 0) + { + MATCH m_best = MATCHnomatch; + TemplateDeclaration td_ambig = null; + TemplateDeclaration td_best = null; + Objects tdargs = new Objects(); + TemplateInstance ti; + FuncDeclaration fd; + + static if (false) { + printf("TemplateDeclaration.deduceFunctionTemplate() %s\n", toChars()); + printf(" targsi:\n"); + if (targsi) + { + for (int i = 0; i < targsi.dim; i++) + { + Object arg = cast(Object)targsi.data[i]; + printf("\t%s\n", arg.toChars()); + } + } + printf(" fargs:\n"); + for (int i = 0; i < fargs.dim; i++) + { + Expression arg = cast(Expression)fargs.data[i]; + printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); + //printf("\tty = %d\n", arg.type.ty); + } + } + + for (TemplateDeclaration td = this; td; td = td.overnext) + { + if (!td.semanticRun) + { + error("forward reference to template %s", td.toChars()); + goto Lerror; + } + if (!td.onemember || !td.onemember.toAlias().isFuncDeclaration()) + { + error("is not a function template"); + goto Lerror; + } + + MATCH m; + scope Objects dedargs = new Objects(); + + m = td.deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, dedargs); + //printf("deduceFunctionTemplateMatch = %d\n", m); + if (!m) // if no match + continue; + + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td.leastAsSpecialized(td_best); + MATCH c2 = td_best.leastAsSpecialized(td); + //printf("c1 = %d, c2 = %d\n", c1, c2); + + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } + + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; + + Ltd_best: // td_best is the best match so far + td_ambig = null; + continue; + + Ltd: // td is the new best match + td_ambig = null; + assert(cast(size_t)cast(void*)td.scope_ > 0x10000); + td_best = td; + m_best = m; + tdargs.setDim(dedargs.dim); + memcpy(tdargs.data, dedargs.data, tdargs.dim * (void*).sizeof); + continue; + } + if (!td_best) + { + if (!(flags & 1)) + error(loc, "does not match any function template declaration"); + goto Lerror; + } + if (td_ambig) + { + error(loc, "matches more than one function template declaration:\n %s\nand:\n %s", + td_best.toChars(), td_ambig.toChars()); + } + + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert(cast(size_t)cast(void*)td_best.scope_ > 0x10000); + ti = new TemplateInstance(loc, td_best, tdargs); + ti.semantic(sc); + fd = ti.toAlias().isFuncDeclaration(); + if (!fd) + goto Lerror; + return fd; + + Lerror: +/// version (DMDV2) { + if (!(flags & 1)) +/// } + { + HdrGenState hgs; + + scope OutBuffer bufa = new OutBuffer(); + Objects args = targsi; + if (args) + { + for (int i = 0; i < args.dim; i++) + { + if (i) + bufa.writeByte(','); + Object oarg = cast(Object)args.data[i]; + ObjectToCBuffer(bufa, &hgs, oarg); + } + } + + scope OutBuffer buf = new OutBuffer(); + argExpTypesToCBuffer(buf, fargs, &hgs); + error(loc, "cannot deduce template function from argument types !(%s)(%s)", bufa.toChars(), buf.toChars()); + } + return null; + } + + /************************************************** + * Declare template parameter tp with value o, and install it in the scope sc. + */ + void declareParameter(Scope sc, TemplateParameter tp, Object o) + { + //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o); + + Type targ = isType(o); + Expression ea = isExpression(o); + Dsymbol sa = isDsymbol(o); + Tuple va = isTuple(o); + + Dsymbol s; + + // See if tp.ident already exists with a matching definition + Dsymbol scopesym; + s = sc.search(loc, tp.ident, &scopesym); + if (s && scopesym == sc.scopesym) + { + TupleDeclaration td = s.isTupleDeclaration(); + if (va && td) + { + Tuple tup = new Tuple(); + assert(false); // < not implemented + ///tup.objects = *td.objects; + if (match(va, tup, this, sc)) + { + return; + } + } + } + + if (targ) + { + //printf("type %s\n", targ.toChars()); + s = new AliasDeclaration(Loc(0), tp.ident, targ); + } + else if (sa) + { + //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars()); + s = new AliasDeclaration(Loc(0), tp.ident, sa); + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer init = new ExpInitializer(loc, ea); + TemplateValueParameter tvp = tp.isTemplateValueParameter(); + + Type t = tvp ? tvp.valType : null; + + VarDeclaration v = new VarDeclaration(loc, t, tp.ident, init); + v.storage_class = STCmanifest; + s = v; + } + else if (va) + { + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp.ident, va.objects); + } + else + { + debug writefln(o.toString()); + assert(0); + } + + if (!sc.insert(s)) + error("declaration %s is already defined", tp.ident.toChars()); + + s.semantic(sc); + } + + TemplateDeclaration isTemplateDeclaration() { return this; } + + TemplateTupleParameter isVariadic() + { + return .isVariadic(parameters); + } + + bool isOverloadable() + { + assert(false); + } +} \ No newline at end of file