diff dmd/TemplateInstance.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 427f8aa74d28 1628b221808d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/TemplateInstance.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,1386 @@
+module dmd.TemplateInstance;
+
+import dmd.ScopeDsymbol;
+import dmd.IntegerExp;
+import dmd.Identifier;
+import dmd.ArrayTypes;
+import dmd.TupleDeclaration;
+import dmd.TemplateParameter;
+import dmd.AliasDeclaration;
+import dmd.TemplateDeclaration;
+import dmd.TupleExp;
+import dmd.WithScopeSymbol;
+import dmd.Dsymbol;
+import dmd.Module;
+import dmd.ArrayTypes;
+import dmd.Loc;
+import dmd.Global;
+import dmd.Util;
+import dmd.Type;
+import dmd.Expression;
+import dmd.Tuple;
+import dmd.STC;
+import dmd.TOK;
+import dmd.TY;
+import dmd.TypeTuple;
+import dmd.Argument;
+import dmd.WANT;
+import dmd.ExpInitializer;
+import dmd.Array;
+import dmd.DsymbolTable;
+import dmd.Scope;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.VarDeclaration;
+import dmd.VarExp;
+import dmd.FuncExp;
+import dmd.Declaration;
+import dmd.MATCH;
+
+import dmd.backend.glue;
+
+Tuple isTuple(Object o)
+{
+    //return dynamic_cast<Tuple *>(o);
+    ///if (!o || o.dyncast() != DYNCAST_TUPLE)
+	///	return null;
+    return cast(Tuple)o;
+}
+
+/******************************
+ * If o1 matches o2, return 1.
+ * Else, return 0.
+ */
+
+bool match(Object o1, Object o2, TemplateDeclaration tempdecl, Scope sc)
+{
+    Type t1 = isType(o1);
+    Type t2 = isType(o2);
+    Expression e1 = isExpression(o1);
+    Expression e2 = isExpression(o2);
+    Dsymbol s1 = isDsymbol(o1);
+    Dsymbol s2 = isDsymbol(o2);
+    Tuple v1 = isTuple(o1);
+    Tuple v2 = isTuple(o2);
+
+    //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2);
+
+    /* A proper implementation of the various equals() overrides
+     * should make it possible to just do o1.equals(o2), but
+     * we'll do that another day.
+     */
+
+    if (t1)
+    {
+		/* if t1 is an instance of ti, then give error
+		 * about recursive expansions.
+		 */
+		Dsymbol s = t1.toDsymbol(sc);
+		if (s && s.parent)
+		{   
+			TemplateInstance ti1 = s.parent.isTemplateInstance();
+			if (ti1 && ti1.tempdecl == tempdecl)
+			{
+				for (Scope sc1 = sc; sc1; sc1 = sc1.enclosing)
+				{
+					if (sc1.scopesym == ti1)
+					{
+						error("recursive template expansion for template argument %s", t1.toChars());
+						return true;	// fake a match
+					}
+				}
+			}
+		}
+
+		//printf("t1 = %s\n", t1.toChars());
+		//printf("t2 = %s\n", t2.toChars());
+		if (!t2 || !t1.equals(t2))
+			goto Lnomatch;
+    }
+    else if (e1)
+    {
+static if (false) {
+		if (e1 && e2)
+		{
+			printf("match %d\n", e1.equals(e2));
+			e1.print();
+			e2.print();
+			e1.type.print();
+			e2.type.print();
+		}
+}
+		if (!e2)
+			goto Lnomatch;
+		if (!e1.equals(e2))
+			goto Lnomatch;
+    }
+    else if (s1)
+    {
+		//printf("%p %s, %p %s\n", s1, s1.toChars(), s2, s2.toChars());
+		if (!s2 || !s1.equals(s2) || s1.parent != s2.parent)
+		{
+			goto Lnomatch;
+		}
+	version (DMDV2) {
+		VarDeclaration vv1 = s1.isVarDeclaration();
+		VarDeclaration vv2 = s2.isVarDeclaration();
+		if (vv1 && vv2 && vv1.storage_class & vv2.storage_class & STCmanifest)
+		{   
+			ExpInitializer ei1 = vv1.init.isExpInitializer();
+			ExpInitializer ei2 = vv2.init.isExpInitializer();
+			if (ei1 && ei2 && !ei1.exp.equals(ei2.exp))
+				goto Lnomatch;
+		}
+	}
+    }
+    else if (v1)
+    {
+		if (!v2)
+			goto Lnomatch;
+
+		if (v1.objects.dim != v2.objects.dim)
+			goto Lnomatch;
+
+		for (size_t i = 0; i < v1.objects.dim; i++)
+		{
+			if (!match(cast(Object)v1.objects.data[i], cast(Object)v2.objects.data[i], tempdecl, sc))
+				goto Lnomatch;
+		}
+    }
+    //printf("match\n");
+    return true;	// match
+
+Lnomatch:
+    //printf("nomatch\n");
+    return false;	// nomatch;
+}
+
+class TemplateInstance : ScopeDsymbol
+{
+    /* Given:
+     *	foo!(args) =>
+     *	    name = foo
+     *	    tiargs = args
+     */
+    Identifier name;
+    //Array idents;
+    Objects tiargs;		// Array of Types/Expressions of template
+				// instance arguments [int*, char, 10*10]
+
+    Objects tdtypes;		// Array of Types/Expressions corresponding
+				// to TemplateDeclaration.parameters
+				// [int, char, 100]
+
+    TemplateDeclaration tempdecl;	// referenced by foo.bar.abc
+    TemplateInstance inst;		// refer to existing instance
+    TemplateInstance tinst;		// enclosing template instance
+    ScopeDsymbol argsym;		// argument symbol table
+    AliasDeclaration aliasdecl;	// !=null if instance is an alias for its
+					// sole member
+    WithScopeSymbol withsym;		// if a member of a with statement
+    int semanticRun;	// has semantic() been done?
+    int semantictiargsdone;	// has semanticTiargs() been done?
+    int nest;		// for recursion detection
+    int havetempdecl;	// 1 if used second constructor
+    Dsymbol isnested;	// if referencing local symbols, this is the context
+    int errors;		// 1 if compiled with errors
+version (IN_GCC) {
+    /* On some targets, it is necessary to know whether a symbol
+       will be emitted in the output or not before the symbol
+       is used.  This can be different from getModule(). */
+    Module objFileModule;
+}
+
+    this(Loc loc, Identifier ident)
+	{
+		super(null);
+		
+	version (LOG) {
+		printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
+	}
+		this.loc = loc;
+		this.name = ident;
+		
+		tdtypes = new Objects();
+	}
+
+	/*****************
+	 * This constructor is only called when we figured out which function
+	 * template to instantiate.
+	 */
+    this(Loc loc, TemplateDeclaration td, Objects tiargs)
+	{
+		super(null);
+		
+	version (LOG) {
+		printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
+	}
+		this.loc = loc;
+		this.name = td.ident;
+		this.tiargs = tiargs;
+		this.tempdecl = td;
+		this.semantictiargsdone = 1;
+		this.havetempdecl = 1;
+
+		assert(cast(size_t)cast(void*)tempdecl.scope_ > 0x10000);
+		
+		tdtypes = new Objects();
+	}
+
+    static Objects arraySyntaxCopy(Objects objs)
+	{
+		assert(false);
+	}
+
+    Dsymbol syntaxCopy(Dsymbol)
+	{
+		assert(false);
+	}
+
+    void semantic(Scope sc)
+	{
+	    if (global.errors)
+		{
+			if (!global.gag)
+			{
+				/* Trying to soldier on rarely generates useful messages
+				 * at this point.
+				 */
+				fatal();
+			}
+			return;
+		}
+
+	version (LOG) {
+		printf("\n+TemplateInstance.semantic('%s', this=%p)\n", toChars(), this);
+	}
+
+		if (inst)		// if semantic() was already run
+		{
+version (LOG) {
+			printf("-TemplateInstance.semantic('%s', this=%p) already run\n", inst.toChars(), inst);
+}
+			return;
+		}
+
+		// get the enclosing template instance from the scope tinst
+		tinst = sc.tinst;
+
+		if (semanticRun != 0)
+		{
+			error(loc, "recursive template expansion");
+		//	inst = this;
+			return;
+		}
+
+		semanticRun = 1;
+
+	version (LOG) {
+		printf("\tdo semantic\n");
+	}
+		if (havetempdecl)
+		{
+			assert(cast(size_t)cast(void*)tempdecl.scope_ > 0x10000);
+
+			// Deduce tdtypes
+			tdtypes.setDim(tempdecl.parameters.dim);
+			if (!tempdecl.matchWithInstance(this, tdtypes, 2))
+			{
+				error("incompatible arguments for template instantiation");
+				inst = this;
+				return;
+			}
+		}
+		else
+		{
+			/* Run semantic on each argument, place results in tiargs[]
+			 * (if we havetempdecl, then tiargs is already evaluated)
+			 */
+			semanticTiargs(sc);
+
+			tempdecl = findTemplateDeclaration(sc);
+			if (tempdecl)
+				tempdecl = findBestMatch(sc);
+
+			if (!tempdecl || global.errors)
+			{   
+				inst = this;
+				//printf("error return %p, %d\n", tempdecl, global.errors);
+				return;		// error recovery
+			}
+		}
+
+		hasNestedArgs(tiargs);
+
+		/* See if there is an existing TemplateInstantiation that already
+		 * implements the typeargs. If so, just refer to that one instead.
+		 */
+
+		for (size_t i = 0; i < tempdecl.instances.dim; i++)
+		{
+			TemplateInstance ti = cast(TemplateInstance)tempdecl.instances.data[i];
+		version (LOG) {
+			printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti.toChars());
+		}
+			assert(tdtypes.dim == ti.tdtypes.dim);
+
+			// Nesting must match
+			if (isnested !is ti.isnested)
+			{
+				//printf("test2 isnested %s ti.isnested %s\n", isnested ? isnested.toChars() : "", ti.isnested ? ti.isnested.toChars() : "");
+				continue;
+			}
+		static if (false) {
+			if (isnested && sc.parent != ti.parent)
+				continue;
+		}
+			for (size_t j = 0; j < tdtypes.dim; j++)
+			{   
+				Object o1 = cast(Object)tdtypes.data[j];
+				Object o2 = cast(Object)ti.tdtypes.data[j];
+				if (!match(o1, o2, tempdecl, sc))
+				{
+					goto L1;
+				}
+			}
+
+			// It's a match
+			inst = ti;
+			parent = ti.parent;
+		version (LOG) {
+			printf("\tit's a match with instance %p\n", inst);
+		}
+			return;
+
+		L1:
+			;
+		}
+
+		/* So, we need to implement 'this' instance.
+		 */
+	version (LOG) {
+		printf("\timplement template instance '%s'\n", toChars());
+	}
+		uint errorsave = global.errors;
+		inst = this;
+		int tempdecl_instance_idx = tempdecl.instances.dim;
+		tempdecl.instances.push(cast(void*)this);
+		parent = tempdecl.parent;
+		//printf("parent = '%s'\n", parent.kind());
+
+		ident = genIdent();		// need an identifier for name mangling purposes.
+
+	static if (true) {
+		if (isnested)
+			parent = isnested;
+	}
+		//printf("parent = '%s'\n", parent.kind());
+
+		// Add 'this' to the enclosing scope's members[] so the semantic routines
+		// will get called on the instance members
+	static if (true) {
+		int dosemantic3 = 0;
+		{	
+			Array a;
+
+			Scope scx = sc;
+	static if (false) {
+			for (scx = sc; scx; scx = scx.enclosing)
+				if (scx.scopesym)
+					break;
+	}
+
+			//if (scx && scx.scopesym) printf("3: scx is %s %s\n", scx.scopesym.kind(), scx.scopesym.toChars());
+			if (scx && scx.scopesym &&
+				scx.scopesym.members && !scx.scopesym.isTemplateMixin()
+
+///	static if (false) {	// removed because it bloated compile times
+///				/* The problem is if A imports B, and B imports A, and both A
+///				 * and B instantiate the same template, does the compilation of A
+///				 * or the compilation of B do the actual instantiation?
+///				 *
+///				 * see bugzilla 2500.
+///				 */
+///				&& !scx.module.selfImports()
+///	}
+			   )
+			{
+				//printf("\t1: adding to %s %s\n", scx.scopesym.kind(), scx.scopesym.toChars());
+				a = scx.scopesym.members;
+			}
+			else
+			{   Module m = sc.module_.importedFrom;
+				//printf("\t2: adding to module %s instead of module %s\n", m.toChars(), sc.module.toChars());
+				a = m.members;
+				if (m.semanticRun >= 3)
+					dosemantic3 = 1;
+			}
+
+			for (int i = 0; 1; i++)
+			{
+				if (i == a.dim)
+				{
+					a.push(cast(void*)this);
+					break;
+				}
+
+				if (this is cast(Dsymbol)a.data[i])	// if already in Array
+					break;
+			}
+		}
+	}
+
+		// Copy the syntax trees from the TemplateDeclaration
+		members = Dsymbol.arraySyntaxCopy(tempdecl.members);
+
+		// Create our own scope for the template parameters
+		Scope scope_ = tempdecl.scope_;
+		if (!tempdecl.semanticRun)
+		{
+			error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl.toChars());
+			return;
+		}
+
+	version (LOG) {
+		printf("\tcreate scope for template parameters '%s'\n", toChars());
+	}
+		argsym = new ScopeDsymbol();
+		argsym.parent = scope_.parent;
+		scope_ = scope_.push(argsym);
+	//    scope.stc = 0;
+
+		// Declare each template parameter as an alias for the argument type
+		Scope paramscope = scope_.push();
+		paramscope.stc = STCundefined;
+		declareParameters(paramscope);
+		paramscope.pop();
+
+		// Add members of template instance to template instance symbol table
+	//    parent = scope.scopesym;
+		symtab = new DsymbolTable();
+		int memnum = 0;
+		for (int i = 0; i < members.dim; i++)
+		{
+			Dsymbol s = cast(Dsymbol)members.data[i];
+	version (LOG) {
+			printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s.toChars(), s, s.kind(), this.toChars(), memnum);
+	}
+			memnum |= s.addMember(scope_, this, memnum);
+		}
+
+	version (LOG) {
+		printf("adding members done\n");
+	}
+
+		/* See if there is only one member of template instance, and that
+		 * member has the same name as the template instance.
+		 * If so, this template instance becomes an alias for that member.
+		 */
+		//printf("members.dim = %d\n", members.dim);
+		if (members.dim)
+		{
+			Dsymbol s;
+			if (Dsymbol.oneMembers(members, &s) && s)
+			{
+				//printf("s.kind = '%s'\n", s.kind());
+				//s.print();
+				//printf("'%s', '%s'\n", s.ident.toChars(), tempdecl.ident.toChars());
+				if (s.ident && s.ident.equals(tempdecl.ident))
+				{
+					//printf("setting aliasdecl\n");
+					aliasdecl = new AliasDeclaration(loc, s.ident, s);
+				}
+			}
+		}
+
+		// Do semantic() analysis on template instance members
+	version (LOG) {
+		printf("\tdo semantic() on template instance members '%s'\n", toChars());
+	}
+		Scope sc2;
+		sc2 = scope_.push(this);
+		//printf("isnested = %d, sc.parent = %s\n", isnested, sc.parent.toChars());
+		sc2.parent = /*isnested ? sc.parent :*/ this;
+		sc2.tinst = this;
+
+		try
+		{
+			static int nest;
+			//printf("%d\n", nest);
+			if (++nest > 500)
+			{
+				global.gag = 0;			// ensure error message gets printed
+				error("recursive expansion");
+				fatal();
+			}
+			for (int i = 0; i < members.dim; i++)
+			{
+				Dsymbol s = cast(Dsymbol)members.data[i];
+				//printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s.toChars(), s, s.kind(), this.toChars());
+				//printf("test: isnested = %d, sc2.parent = %s\n", isnested, sc2.parent.toChars());
+				//	if (isnested)
+				//	    s.parent = sc.parent;
+				//printf("test3: isnested = %d, s.parent = %s\n", isnested, s.parent.toChars());
+				s.semantic(sc2);
+				//printf("test4: isnested = %d, s.parent = %s\n", isnested, s.parent.toChars());
+				sc2.module_.runDeferredSemantic();
+			}
+			--nest;
+		}
+		catch
+		{
+			global.gag = 0;			// ensure error message gets printed
+			error("recursive expansion");
+			fatal();
+		}
+
+		/* If any of the instantiation members didn't get semantic() run
+		 * on them due to forward references, we cannot run semantic2()
+		 * or semantic3() yet.
+		 */
+		for (size_t i = 0; i < Module.deferred.dim; i++)
+		{	
+			Dsymbol sd = cast(Dsymbol)Module.deferred.data[i];
+
+			if (sd.parent is this)
+				goto Laftersemantic;
+		}
+
+		/* The problem is when to parse the initializer for a variable.
+		 * Perhaps VarDeclaration.semantic() should do it like it does
+		 * for initializers inside a function.
+		 */
+		//    if (sc.parent.isFuncDeclaration())
+
+		/* BUG 782: this has problems if the classes this depends on
+		 * are forward referenced. Find a way to defer semantic()
+		 * on this template.
+		 */
+		semantic2(sc2);
+
+		if (sc.func || dosemantic3)
+		{
+			semantic3(sc2);
+		}
+
+	Laftersemantic:
+		sc2.pop();
+
+		scope_.pop();
+
+		// Give additional context info if error occurred during instantiation
+		if (global.errors != errorsave)
+		{
+			error("error instantiating");
+			if (tinst && !global.gag)
+			{   
+				tinst.printInstantiationTrace();
+				fatal();
+			}
+			errors = 1;
+			if (global.gag)
+				tempdecl.instances.remove(tempdecl_instance_idx);
+		}
+
+	version (LOG) {
+		printf("-TemplateInstance.semantic('%s', this=%p)\n", toChars(), this);
+	}
+	}
+
+    void semantic2(Scope sc)
+	{
+		int i;
+
+		if (semanticRun >= 2)
+			return;
+
+		semanticRun = 2;
+	version (LOG) {
+		printf("+TemplateInstance::semantic2('%s')\n", toChars());
+	}
+
+		if (!errors && members)
+		{
+			sc = tempdecl.scope_;
+			assert(sc);
+			sc = sc.push(argsym);
+			sc = sc.push(this);
+			sc.tinst = this;
+
+			for (i = 0; i < members.dim; i++)
+			{
+				Dsymbol s = cast(Dsymbol)members.data[i];
+	version (LOG) {
+				printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
+	}
+				s.semantic2(sc);
+			}
+
+			sc = sc.pop();
+			sc.pop();
+		}
+
+	version (LOG) {
+		printf("-TemplateInstance::semantic2('%s')\n", toChars());
+	}
+	}
+
+    void semantic3(Scope sc)
+	{
+	version (LOG) {
+		printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", toChars(), semanticRun);
+	}
+	//if (toChars()[0] == 'D') *(char*)0=0;
+		if (semanticRun >= 3)
+			return;
+		semanticRun = 3;
+		if (!errors && members)
+		{
+			sc = tempdecl.scope_;
+			sc = sc.push(argsym);
+			sc = sc.push(this);
+			sc.tinst = this;
+			for (int i = 0; i < members.dim; i++)
+			{
+				Dsymbol s = cast(Dsymbol)members.data[i];
+				s.semantic3(sc);
+			}
+			sc = sc.pop();
+			sc.pop();
+		}
+	}
+
+    void inlineScan()
+	{
+	version (LOG) {
+		printf("TemplateInstance.inlineScan('%s')\n", toChars());
+	}
+		if (!errors && members)
+		{
+			for (int i = 0; i < members.dim; i++)
+			{
+				Dsymbol s = cast(Dsymbol)members.data[i];
+				s.inlineScan();
+			}
+		}
+	}
+	
+    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		int i;
+
+		Identifier id = name;
+		buf.writestring(id.toChars());
+		buf.writestring("!(");
+		if (nest)
+			buf.writestring("...");
+		else
+		{
+			nest++;
+			Objects args = tiargs;
+			for (i = 0; i < args.dim; i++)
+			{
+				if (i)
+					buf.writeByte(',');
+				Object oarg = cast(Object)args.data[i];
+				ObjectToCBuffer(buf, hgs, oarg);
+			}
+			nest--;
+		}
+		buf.writeByte(')');
+	}
+	
+    Dsymbol toAlias()			// resolve real symbol
+	{
+	version (LOG) {
+		printf("TemplateInstance::toAlias()\n");
+	}
+		if (!inst)
+		{	
+			error("cannot resolve forward reference");
+			return this;
+		}
+
+		if (inst !is this)
+			return inst.toAlias();
+
+		if (aliasdecl)
+		{
+			return aliasdecl.toAlias();
+		}
+
+		return inst;
+	}
+	
+    string kind()
+	{
+		assert(false);
+	}
+	
+    bool oneMember(Dsymbol* ps)
+	{
+		assert(false);
+	}
+	
+    string toChars()
+	{
+		scope OutBuffer buf = new OutBuffer();
+		HdrGenState hgs;
+
+		toCBuffer(buf, &hgs);
+		return buf.extractString();
+	}
+	
+    string mangle()
+	{
+		assert(false);
+	}
+	
+    void printInstantiationTrace()
+	{
+		assert(false);
+	}
+
+    void toObjFile(int multiobj)			// compile to .obj file
+	{
+	version (LOG) {
+		printf("TemplateInstance.toObjFile('%s', this = %p)\n", toChars(), this);
+	}
+		if (!errors && members)
+		{
+			if (multiobj)
+				// Append to list of object files to be written later
+				obj_append(this);
+			else
+			{
+				for (int i = 0; i < members.dim; i++)
+				{
+					Dsymbol s = cast(Dsymbol)members.data[i];
+					s.toObjFile(multiobj);
+				}
+			}
+		}
+	}
+
+    // Internal
+	/**********************************
+	 * Input:
+	 *	flags	1: replace const variables with their initializers
+	 */
+    static void semanticTiargs(Loc loc, Scope sc, Objects tiargs, int flags)
+	{
+		// Run semantic on each argument, place results in tiargs[]
+		//printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
+		if (!tiargs)
+			return;
+		for (size_t j = 0; j < tiargs.dim; j++)
+		{
+			Object o = cast(Object)tiargs.data[j];
+			Type ta = isType(o);
+			Expression ea = isExpression(o);
+			Dsymbol sa = isDsymbol(o);
+
+			//printf("1: tiargs.data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
+			if (ta)
+			{
+				//printf("type %s\n", ta.toChars());
+				// It might really be an Expression or an Alias
+				ta.resolve(loc, sc, &ea, &ta, &sa);
+				if (ea)
+				{
+					ea = ea.semantic(sc);
+					/* This test is to skip substituting a const var with
+					 * its initializer. The problem is the initializer won't
+					 * match with an 'alias' parameter. Instead, do the
+					 * const substitution in TemplateValueParameter.matchArg().
+					 */
+					if (ea.op != TOKvar || flags & 1)
+						ea = ea.optimize(WANTvalue | WANTinterpret);
+
+					tiargs.data[j] = cast(void*)ea;
+				}
+				else if (sa)
+				{	
+					tiargs.data[j] = cast(void*)sa;
+					TupleDeclaration d = sa.toAlias().isTupleDeclaration();
+					if (d)
+					{
+						size_t dim = d.objects.dim;
+						tiargs.remove(j);
+						tiargs.insert(j, d.objects);
+						j--;
+					}
+				}
+				else if (ta)
+				{
+				Ltype:
+					if (ta.ty == Ttuple)
+					{   
+						// Expand tuple
+						TypeTuple tt = cast(TypeTuple)ta;
+						size_t dim = tt.arguments.dim;
+						tiargs.remove(j);
+						if (dim)
+						{	
+							tiargs.reserve(dim);
+							for (size_t i = 0; i < dim; i++)
+							{   
+								Argument arg = cast(Argument)tt.arguments.data[i];
+								tiargs.insert(j + i, cast(void*)arg.type);
+							}
+						}
+						j--;
+					}
+					else
+						tiargs.data[j] = cast(void*)ta;
+				}
+				else
+				{
+					assert(global.errors);
+					tiargs.data[j] = cast(void*)Type.terror;
+				}
+			}
+			else if (ea)
+			{
+				if (!ea)
+				{	
+					assert(global.errors);
+					ea = new IntegerExp(0);
+				}
+				assert(ea);
+				ea = ea.semantic(sc);
+				if (ea.op != TOKvar || flags & 1)
+					ea = ea.optimize(WANTvalue | WANTinterpret);
+				tiargs.data[j] = cast(void*)ea;
+				if (ea.op == TOKtype)
+				{	
+					ta = ea.type;
+					goto Ltype;
+				}
+				if (ea.op == TOKtuple)
+				{   
+					// Expand tuple
+					TupleExp te = cast(TupleExp)ea;
+					size_t dim = te.exps.dim;
+					tiargs.remove(j);
+					if (dim)
+					{   
+						tiargs.reserve(dim);
+						for (size_t i = 0; i < dim; i++)
+						tiargs.insert(j + i, te.exps.data[i]);
+					}
+					j--;
+				}
+			}
+			else if (sa)
+			{
+				TemplateDeclaration td = sa.isTemplateDeclaration();
+				if (td && !td.semanticRun && td.literal)
+					td.semantic(sc);
+			}
+			else
+			{
+				assert(0);
+			}
+			//printf("1: tiargs.data[%d] = %p\n", j, tiargs.data[j]);
+		}
+
+static if (false) {
+		printf("-TemplateInstance.semanticTiargs('%s', this=%p)\n", toChars(), this);
+		for (size_t j = 0; j < tiargs.dim; j++)
+		{
+			Object o = cast(Object)tiargs.data[j];
+			Type ta = isType(o);
+			Expression ea = isExpression(o);
+			Dsymbol sa = isDsymbol(o);
+			Tuple va = isTuple(o);
+
+			printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
+		}
+}
+	}
+
+    void semanticTiargs(Scope sc)
+	{
+		//printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
+		if (semantictiargsdone)
+			return;
+
+		semantictiargsdone = 1;
+		semanticTiargs(loc, sc, tiargs, 0);
+	}
+
+	/**********************************************
+	 * Find template declaration corresponding to template instance.
+	*/
+	TemplateDeclaration findTemplateDeclaration(Scope sc)
+	{
+		//printf("TemplateInstance.findTemplateDeclaration() %s\n", toChars());
+		if (!tempdecl)
+		{
+			/* Given:
+			 *    foo!( ... )
+			 * figure out which TemplateDeclaration foo refers to.
+			 */
+			Dsymbol s;
+			Dsymbol scopesym;
+			int i;
+
+			Identifier id = name;
+			s = sc.search(loc, id, &scopesym);
+			if (!s)
+			{   
+				error("identifier '%s' is not defined", id.toChars());
+				return null;
+			}
+		version (LOG) {
+			printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
+			if (s.parent)
+				printf("s.parent = '%s'\n", s.parent.toChars());
+		}
+			withsym = scopesym.isWithScopeSymbol();
+
+			/* We might have found an alias within a template when
+			 * we really want the template.
+			 */
+			TemplateInstance ti;
+			if (s.parent &&
+				(ti = s.parent.isTemplateInstance()) !is null)
+			{
+				if (
+					(ti.name == id ||
+					ti.toAlias().ident == id)
+					&&
+					ti.tempdecl
+				  )
+				{
+					/* This is so that one can refer to the enclosing
+					 * template, even if it has the same name as a member
+					 * of the template, if it has a !(arguments)
+					 */
+					tempdecl = ti.tempdecl;
+					if (tempdecl.overroot)		// if not start of overloaded list of TemplateDeclaration's
+						tempdecl = tempdecl.overroot; // then get the start
+
+					s = tempdecl;
+				}
+			}
+
+			s = s.toAlias();
+
+			/* It should be a TemplateDeclaration, not some other symbol
+			 */
+			tempdecl = s.isTemplateDeclaration();
+			if (!tempdecl)
+			{
+				if (!s.parent && global.errors)
+				return null;
+				if (!s.parent && s.getType())
+				{	
+					Dsymbol s2 = s.getType().toDsymbol(sc);
+					if (!s2)
+					{
+						error("%s is not a template declaration, it is a %s", id.toChars(), s.kind());
+						return null;
+					}
+					s = s2;
+				}
+		debug {
+				//if (!s.parent) printf("s = %s %s\n", s.kind(), s.toChars());
+		}
+				//assert(s.parent);
+				TemplateInstance ti2 = s.parent ? s.parent.isTemplateInstance() : null;
+				if (ti2 &&
+					(ti2.name == id ||
+					ti2.toAlias().ident == id)
+					&&
+					ti2.tempdecl
+				  )
+				{
+					/* This is so that one can refer to the enclosing
+					 * template, even if it has the same name as a member
+					 * of the template, if it has a !(arguments)
+					 */
+					tempdecl = ti2.tempdecl;
+					if (tempdecl.overroot)		// if not start of overloaded list of TemplateDeclaration's
+						tempdecl = tempdecl.overroot; // then get the start
+				}
+				else
+				{
+					error("%s is not a template declaration, it is a %s", id.toChars(), s.kind());
+					return null;
+				}
+			}
+		}
+		else
+			assert(tempdecl.isTemplateDeclaration());
+
+		return tempdecl;
+	}
+
+    TemplateDeclaration findBestMatch(Scope sc)
+	{
+		/* Since there can be multiple TemplateDeclaration's with the same
+		 * name, look for the best match.
+		 */
+		TemplateDeclaration td_ambig = null;
+		TemplateDeclaration td_best = null;
+		MATCH m_best = MATCHnomatch;
+		scope Objects dedtypes = new Objects();
+
+	version (LOG) {
+		printf("TemplateInstance.findBestMatch()\n");
+	}
+		// First look for forward references
+		for (TemplateDeclaration td = tempdecl; td; td = td.overnext)
+		{
+			if (!td.semanticRun)
+			{
+				if (td.scope_)
+				{	
+					// Try to fix forward reference
+					td.semantic(td.scope_);
+				}
+				if (!td.semanticRun)
+				{
+					error("%s forward references template declaration %s\n", toChars(), td.toChars());
+					return null;
+				}
+			}
+		}
+
+		for (TemplateDeclaration td = tempdecl; td; td = td.overnext)
+		{
+			MATCH m;
+
+		//if (tiargs.dim) printf("2: tiargs.dim = %d, data[0] = %p\n", tiargs.dim, tiargs.data[0]);
+
+			// If more arguments than parameters,
+			// then this is no match.
+			if (td.parameters.dim < tiargs.dim)
+			{
+				if (!td.isVariadic())
+					continue;
+			}
+
+			dedtypes.setDim(td.parameters.dim);
+			dedtypes.zero();
+			assert(td.semanticRun);
+			m = td.matchWithInstance(this, dedtypes, 0);
+			//printf("matchWithInstance = %d\n", m);
+			if (!m)			// no match at all
+				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;
+			td_best = td;
+			m_best = m;
+			tdtypes.setDim(dedtypes.dim);
+			memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * (void*).sizeof);
+			continue;
+		}
+
+		if (!td_best)
+		{
+			if (tempdecl && !tempdecl.overnext)
+				// Only one template, so we can give better error message
+				error("%s does not match template declaration %s", toChars(), tempdecl.toChars());
+			else
+				error("%s does not match any template declaration", toChars());
+			return null;
+		}
+
+		if (td_ambig)
+		{
+			error("%s matches more than one template declaration, %s and %s",
+				toChars(), td_best.toChars(), td_ambig.toChars());
+		}
+
+		/* The best match is td_best
+		 */
+		tempdecl = td_best;
+
+	static if (false) {
+		/* Cast any value arguments to be same type as value parameter
+		 */
+		for (size_t i = 0; i < tiargs.dim; i++)
+		{	
+			Object o = cast(Object)tiargs.data[i];
+			Expression ea = isExpression(o);	// value argument
+			TemplateParameter tp = cast(TemplateParameter)tempdecl.parameters.data[i];
+			assert(tp);
+			TemplateValueParameter tvp = tp.isTemplateValueParameter();
+			if (tvp)
+			{
+				assert(ea);
+				ea = ea.castTo(tvp.valType);
+				ea = ea.optimize(WANTvalue | WANTinterpret);
+				tiargs.data[i] = cast(Object)ea;
+			}
+		}
+	}
+
+	version (LOG) {
+		printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
+	}
+		return tempdecl;
+	}
+
+	/****************************************************
+	 * Declare parameters of template instance, initialize them with the
+	 * template instance arguments.
+	 */
+    void declareParameters(Scope sc)
+	{
+		//printf("TemplateInstance::declareParameters()\n");
+		for (int i = 0; i < tdtypes.dim; i++)
+		{
+			TemplateParameter tp = cast(TemplateParameter)tempdecl.parameters.data[i];
+			//Object o = cast(Object)tiargs.data[i];
+			Object o = cast(Object)tdtypes.data[i];		// initializer for tp
+
+			//printf("\ttdtypes[%d] = %p\n", i, o);
+			tempdecl.declareParameter(sc, tp, o);
+		}
+	}
+
+	/*****************************************
+	 * Determines if a TemplateInstance will need a nested
+	 * generation of the TemplateDeclaration.
+	 */
+    bool hasNestedArgs(Objects args)
+	{
+		bool nested = false;
+		//printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl.ident.toChars());
+
+		/* A nested instance happens when an argument references a local
+		 * symbol that is on the stack.
+		 */
+		for (size_t i = 0; i < args.dim; i++)
+		{   
+			Object o = cast(Object)args.data[i];
+			Expression ea = isExpression(o);
+			Dsymbol sa = isDsymbol(o);
+			Tuple va = isTuple(o);
+			if (ea)
+			{
+				if (ea.op == TOKvar)
+				{
+					sa = (cast(VarExp)ea).var;
+					goto Lsa;
+				}
+				if (ea.op == TOKfunction)
+				{
+					sa = (cast(FuncExp)ea).fd;
+					goto Lsa;
+				}
+			}
+			else if (sa)
+			{
+			  Lsa:
+				Declaration d = null;
+				TemplateDeclaration td = sa.isTemplateDeclaration();
+				if (td && td.literal)
+				{
+					goto L2;
+				}
+				d = sa.isDeclaration();
+				if (d && !d.isDataseg() &&
+///		version (DMDV2) {
+					!(d.storage_class & STCmanifest) &&
+///		}
+					(!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) &&
+					!isTemplateMixin())
+				{
+					 L2:
+					// if module level template
+					if (tempdecl.toParent().isModule())
+					{   
+						Dsymbol dparent = sa.toParent();
+						if (!isnested)
+							isnested = dparent;
+						else if (isnested != dparent)
+						{
+							/* Select the more deeply nested of the two.
+							 * Error if one is not nested inside the other.
+							 */
+							for (Dsymbol p = isnested; p; p = p.parent)
+							{
+								if (p == dparent)
+									goto L1;	// isnested is most nested
+							}
+							for (Dsymbol p = dparent; p; p = p.parent)
+							{
+								if (p == isnested)
+								{	
+									isnested = dparent;
+									goto L1;	// dparent is most nested
+								}
+							}
+							error("%s is nested in both %s and %s",
+								toChars(), isnested.toChars(), dparent.toChars());
+						}
+					  L1:
+						//printf("\tnested inside %s\n", isnested.toChars());
+						nested |= 1;
+					}
+					else
+						error("cannot use local '%s' as parameter to non-global template %s", d.toChars(), tempdecl.toChars());
+				}
+			}
+			else if (va)
+			{
+				nested |= hasNestedArgs(va.objects);
+			}
+		}
+		return nested;
+	}
+
+	/****************************************
+	 * This instance needs an identifier for name mangling purposes.
+	 * Create one by taking the template declaration name and adding
+	 * the type signature for it.
+	 */
+    Identifier genIdent()
+	{
+		scope OutBuffer buf = new OutBuffer();
+		string id;
+		Objects args;
+
+		//printf("TemplateInstance::genIdent('%s')\n", tempdecl.ident.toChars());
+		id = tempdecl.ident.toChars();
+		buf.printf("__T%d%s", id.length, id);	///!
+		args = tiargs;
+		for (int i = 0; i < args.dim; i++)
+		{   
+			Object o = cast(Object)args.data[i];
+			Type ta = isType(o);
+			Expression ea = isExpression(o);
+			Dsymbol sa = isDsymbol(o);
+			Tuple va = isTuple(o);
+			//printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
+			if (ta)
+			{
+				buf.writeByte('T');
+				if (ta.deco)
+					buf.writestring(ta.deco);
+				else
+				{
+					debug writef("ta = %d, %s\n", ta.ty, ta.toChars());
+					assert(global.errors);
+				}
+			}
+			else if (ea)
+			{
+			  Lea:
+				long v;
+				real r;
+
+				ea = ea.optimize(WANTvalue | WANTinterpret);
+				if (ea.op == TOKvar)
+				{
+					sa = (cast(VarExp)ea).var;
+					ea = null;
+					goto Lsa;
+				}
+				if (ea.op == TOKfunction)
+				{
+					sa = (cast(FuncExp)ea).fd;
+					ea = null;
+					goto Lsa;
+				}
+				buf.writeByte('V');
+				if (ea.op == TOKtuple)
+				{	
+					ea.error("tuple is not a valid template value argument");
+					continue;
+				}
+		static if (true) {
+				/* Use deco that matches what it would be for a function parameter
+				 */
+				buf.writestring(ea.type.deco);
+		} else {
+				// Use type of parameter, not type of argument
+				TemplateParameter tp = cast(TemplateParameter)tempdecl.parameters.data[i];
+				assert(tp);
+				TemplateValueParameter tvp = tp.isTemplateValueParameter();
+				assert(tvp);
+				buf.writestring(tvp.valType.deco);
+		}
+				ea.toMangleBuffer(buf);
+			}
+			else if (sa)
+			{
+			  Lsa:
+				buf.writeByte('S');
+				Declaration d = sa.isDeclaration();
+				if (d && (!d.type || !d.type.deco))
+				{	
+					error("forward reference of %s", d.toChars());
+					continue;
+				}
+		static if (false) {
+				VarDeclaration v = sa.isVarDeclaration();
+				if (v && v.storage_class & STCmanifest)
+				{	
+					ExpInitializer ei = v.init.isExpInitializer();
+					if (ei)
+					{
+						ea = ei.exp;
+						goto Lea;
+					}
+				}
+		}
+				string p = sa.mangle();
+				buf.printf("%zu%s", p.length, p);
+			}
+			else if (va)
+			{
+				assert(i + 1 == args.dim);		// must be last one
+				args = va.objects;
+				i = -1;
+			}
+			else
+				assert(0);
+		}
+		buf.writeByte('Z');
+		id = buf.toChars();
+		buf.data = null;
+		//printf("\tgenIdent = %s\n", id);
+		return new Identifier(id, TOKidentifier);
+	}
+
+    TemplateInstance isTemplateInstance() { return this; }
+
+    AliasDeclaration isAliasDeclaration()
+	{
+		assert(false);
+	}
+}
\ No newline at end of file