changeset 19:01cadcfa4842

Implemented CompileExp, ConditionalDeclaration, ModAssignExp, parsingmixin statements, TemplateAliasParameters, TemplateMixins, TypeDArray.
author Robert Clipsham <robert@octarineparrot.com>
date Tue, 06 Apr 2010 02:21:04 +0100
parents f2413c9183d1
children 1628b221808d
files dmd/CompileExp.d dmd/ConditionalDeclaration.d dmd/ModAssignExp.d dmd/Parser.d dmd/TemplateAliasParameter.d dmd/TemplateMixin.d dmd/TypeDArray.d
diffstat 7 files changed, 905 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/CompileExp.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/CompileExp.d	Tue Apr 06 02:21:04 2010 +0100
@@ -7,23 +7,51 @@
 import dmd.Scope;
 import dmd.HdrGenState;
 import dmd.TOK;
+import dmd.PREC;
+import dmd.WANT;
+import dmd.StringExp;
+import dmd.Type;
+import dmd.Parser;
 
-class CompileExp : UnaExp
-{
-	this(Loc loc, Expression e)
-	{
-		assert(false);
-		super(loc, TOK.init, 0, null);
-	}
-
-	Expression semantic(Scope sc)
-	{
-		assert(false);
-	}
-
-	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
-	{
-		assert(false);
-	}
-}
-
+import dmd.expression.Util;
+
+class CompileExp : UnaExp
+{
+	this(Loc loc, Expression e)
+	{
+		super(loc, TOK.TOKmixin, this.sizeof, e);
+	}
+
+	Expression semantic(Scope sc)
+	{
+		version (LOGSEMANTIC) {
+			printf("CompileExp.semantic('%s')\n", toChars());
+		}
+		UnaExp.semantic(sc);
+		e1 = resolveProperties(sc, e1);
+		e1 = e1.optimize(WANT.WANTvalue | WANT.WANTinterpret);
+		if (e1.op != TOK.TOKstring)
+		{	error("argument to mixin must be a string, not (%s)", e1.toChars());
+			type = Type.terror;
+			return this;
+		}
+		StringExp se = cast(StringExp)e1;
+		se = se.toUTF8(sc);
+		Parser p = new Parser(sc.module_, cast(ubyte*)se.string_, se.len, 0);
+		p.loc = loc;
+		p.nextToken();
+		//printf("p.loc.linnum = %d\n", p.loc.linnum);
+		Expression e = p.parseExpression();
+		if (p.token.value != TOK.TOKeof)
+			error("incomplete mixin expression (%s)", se.toChars());
+		return e.semantic(sc);
+	}
+
+	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		buf.writestring("mixin(");
+		expToCBuffer(buf, hgs, e1, PREC.PREC_assign);
+		buf.writeByte(')');
+	}
+}
+
--- a/dmd/ConditionalDeclaration.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/ConditionalDeclaration.d	Tue Apr 06 02:21:04 2010 +0100
@@ -17,31 +17,59 @@
     this(Condition condition, Array decl, Array elsedecl)
 	{
 		super(decl);
-		//printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+		//printf("ConditionalDeclaration.ConditionalDeclaration()\n");
 		this.condition = condition;
 		this.elsedecl = elsedecl;
 	}
 	
     Dsymbol syntaxCopy(Dsymbol s)
 	{
-		assert(false);
+    ConditionalDeclaration dd;
+
+    assert(!s);
+    dd = new ConditionalDeclaration(condition.syntaxCopy(),
+	Dsymbol.arraySyntaxCopy(decl),
+	Dsymbol.arraySyntaxCopy(elsedecl));
+    return dd;
 	}
 	
     bool oneMember(Dsymbol* ps)
 	{
-		assert(false);
+    //printf("ConditionalDeclaration.oneMember(), inc = %d\n", condition.inc);
+    if (condition.inc)
+    {
+	Array d = condition.include(null, null) ? decl : elsedecl;
+	return Dsymbol.oneMembers(d, ps);
+    }
+    *ps = null;
+    return true;
 	}
 	
     void emitComment(Scope sc)
 	{
-		assert(false);
+    //printf("ConditionalDeclaration.emitComment(sc = %p)\n", sc);
+    if (condition.inc)
+    {
+	AttribDeclaration.emitComment(sc);
+    }
+    else if (sc.docbuf)
+    {
+	/* If generating doc comment, be careful because if we're inside
+	 * a template, then include(NULL, NULL) will fail.
+	 */
+	Array d = decl ? decl : elsedecl;
+	for (uint i = 0; i < d.dim; i++)
+	{   Dsymbol s = cast(Dsymbol)d.data[i];
+	    s.emitComment(sc);
+	}
+    }
 	}
 	
 	// Decide if 'then' or 'else' code should be included
 
     Array include(Scope sc, ScopeDsymbol sd)
 	{
-		//printf("ConditionalDeclaration::include()\n");
+		//printf("ConditionalDeclaration.include()\n");
 		assert(condition);
 		return condition.include(sc, sd) ? decl : elsedecl;
 	}
@@ -65,7 +93,7 @@
 					for (uint i = 0; i < d.dim; i++)
 					{   
 						Dsymbol s = cast(Dsymbol)d.data[i];
-						//printf("ConditionalDeclaration::addComment %s\n", s->toChars());
+						//printf("ConditionalDeclaration::addComment %s\n", s.toChars());
 						s.addComment(comment);
 					}
 				}
@@ -76,6 +104,42 @@
 	
     void toCBuffer(OutBuffer buf, HdrGenState* hgs)
 	{
-		assert(false);
+    condition.toCBuffer(buf, hgs);
+    if (decl || elsedecl)
+    {
+	buf.writenl();
+	buf.writeByte('{');
+	buf.writenl();
+	if (decl)
+	{
+	    for (uint i = 0; i < decl.dim; i++)
+	    {
+		Dsymbol s = cast(Dsymbol)decl.data[i];
+
+		buf.writestring("    ");
+		s.toCBuffer(buf, hgs);
+	    }
 	}
-}
\ No newline at end of file
+	buf.writeByte('}');
+	if (elsedecl)
+	{
+	    buf.writenl();
+	    buf.writestring("else");
+	    buf.writenl();
+	    buf.writeByte('{');
+	    buf.writenl();
+	    for (uint i = 0; i < elsedecl.dim; i++)
+	    {
+		Dsymbol s = cast(Dsymbol)elsedecl.data[i];
+
+		buf.writestring("    ");
+		s.toCBuffer(buf, hgs);
+	    }
+	    buf.writeByte('}');
+	}
+    }
+    else
+	buf.writeByte(':');
+    buf.writenl();
+	}
+}
--- a/dmd/ModAssignExp.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/ModAssignExp.d	Tue Apr 06 02:21:04 2010 +0100
@@ -17,13 +17,12 @@
 {
     this(Loc loc, Expression e1, Expression e2)
 	{
-		assert(false);
-		super(loc, TOK.init, 0, e1, e2);
+		super(loc, TOK.TOKmodass, this.sizeof, e1, e2);
 	}
 	
     Expression semantic(Scope sc)
 	{
-		assert(false);
+    		return commonSemanticAssign(sc);
 	}
 	
     Expression interpret(InterState* istate)
@@ -50,4 +49,4 @@
 	{
 		assert(false);
 	}
-}
\ No newline at end of file
+}
--- a/dmd/Parser.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/Parser.d	Tue Apr 06 02:21:04 2010 +0100
@@ -46,6 +46,7 @@
 import dmd.AssertExp;
 import dmd.CompileExp;
 import dmd.FileExp;
+import dmd.TemplateMixin;
 import dmd.TemplateParameter;
 import dmd.TemplateTypeParameter;
 import dmd.TypeidExp;
@@ -1075,10 +1076,96 @@
 	Lerr:
 		return tpl;
 	}
-	
+
+/******************************************
+ * Parse template mixin.
+ *	mixin Foo;
+ *	mixin Foo!(args);
+ *	mixin a.b.c!(args).Foo!(args);
+ *	mixin Foo!(args) identifier;
+ *	mixin typeof(expr).identifier!(args);
+ */
+
     Dsymbol parseMixin()
 	{
-		assert(false);
+    TemplateMixin tm;
+    Identifier id;
+    Type tqual;
+    Objects tiargs;
+    Array idents;
+
+    //printf("parseMixin()\n");
+    nextToken();
+    tqual = null;
+    if (token.value == TOK.TOKdot)
+    {
+	id = Id.empty;
+    }
+    else
+    {
+	if (token.value == TOK.TOKtypeof)
+	{
+	    tqual = parseTypeof();
+	    check(TOKdot);
+	}
+	if (token.value != TOK.TOKidentifier)
+	{
+	    error("identifier expected, not %s", token.toChars());
+	    id = Id.empty;
+	}
+	else
+	    id = token.ident;
+	nextToken();
+    }
+
+    idents = new Array();
+    while (1)
+    {
+	tiargs = null;
+	if (token.value == TOK.TOKnot)
+	{
+	    nextToken();
+	    if (token.value == TOK.TOKlparen)
+		tiargs = parseTemplateArgumentList();
+	    else
+		tiargs = parseTemplateArgument();
+	}
+
+	if (token.value != TOK.TOKdot)
+	    break;
+
+	if (tiargs)
+	{   TemplateInstance tempinst = new TemplateInstance(loc, id);
+	    tempinst.tiargs = tiargs;
+	    id = cast(Identifier)tempinst;
+	    tiargs = null;
+	}
+	idents.push(cast(void*)id);
+
+	nextToken();
+	if (token.value != TOK.TOKidentifier)
+	{   error("identifier expected following '.' instead of '%s'", token.toChars());
+	    break;
+	}
+	id = token.ident;
+	nextToken();
+    }
+    idents.push(cast(void*)id);
+
+    if (token.value == TOK.TOKidentifier)
+    {
+	id = token.ident;
+	nextToken();
+    }
+    else
+	id = null;
+
+    tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
+    if (token.value != TOK.TOKsemicolon)
+	error("';' expected after mixin");
+    nextToken();
+
+    return tm;
 	}
 	
 	/******************************************
@@ -6024,4 +6111,4 @@
 		s.addComment(combineComments(blockComment, token.lineComment));
 		token.lineComment = null;
 	}
-}
\ No newline at end of file
+}
--- a/dmd/TemplateAliasParameter.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/TemplateAliasParameter.d	Tue Apr 06 02:21:04 2010 +0100
@@ -11,22 +11,54 @@
 import dmd.OutBuffer;
 import dmd.HdrGenState;
 import dmd.Dsymbol;
+import dmd.WANT;
+import dmd.Expression;
+import dmd.TypeIdentifier;
+import dmd.Initializer;
+import dmd.ExpInitializer;
+import dmd.AliasDeclaration;
+import dmd.VarDeclaration;
+import dmd.TemplateDeclaration;
+import dmd.STC;
+import dmd.Util;
 
 import dmd.templates.Util;
 
+Object aliasParameterSemantic(Loc loc, Scope sc, Object o)
+{
+	if (o)
+	{
+		Expression ea = isExpression(o);
+		Type ta = isType(o);
+		if (ta)
+		{   Dsymbol s = ta.toDsymbol(sc);
+			if (s)
+				o = s;
+			else
+				o = ta.semantic(loc, sc);
+		}
+		else if (ea)
+		{
+			ea = ea.semantic(sc);
+			o = ea.optimize(WANT.WANTvalue | WANT.WANTinterpret);
+		}
+	}
+	return o;
+}
+
 class TemplateAliasParameter : TemplateParameter
 {
-    /* Syntax:
-     *	specType ident : specAlias = defaultAlias
-     */
+	/* Syntax:
+	 *	specType ident : specAlias = defaultAlias
+	 */
 
-    Type specType;
-    Object specAlias;
-    Object defaultAlias;
+	Type specType;
+	Object specAlias;
+	Object defaultAlias;
 
-    static Dsymbol sdummy;
+	static Dsymbol sdummy;
 
-    this(Loc loc, Identifier ident, Type specType, Object specAlias, Object defaultAlias)
+	this(Loc loc, Identifier ident, Type specType, Object specAlias, Object defaultAlias)
 	{
 		super(loc, ident);
 
@@ -35,12 +67,12 @@
 		this.defaultAlias = defaultAlias;
 	}
 
-    TemplateAliasParameter isTemplateAliasParameter()
+	TemplateAliasParameter isTemplateAliasParameter()
 	{
 		return this;
 	}
-	
-    TemplateParameter syntaxCopy()
+
+	TemplateParameter syntaxCopy()
 	{
 		TemplateAliasParameter tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias);
 		if (tp.specType)
@@ -49,49 +81,186 @@
 		tp.defaultAlias = objectSyntaxCopy(defaultAlias);
 		return tp;
 	}
-	
-    void declareParameter(Scope sc)
+
+	void declareParameter(Scope sc)
 	{
-		assert(false);
+		TypeIdentifier ti = new TypeIdentifier(loc, ident);
+		sparam = new AliasDeclaration(loc, ident, ti);
+		if (!sc.insert(sparam))
+			error(loc, "parameter '%s' multiply defined", ident.toChars());
 	}
-	
-    void semantic(Scope)
+
+	void semantic(Scope sc)
 	{
-		assert(false);
+		if (specType)
+		{
+			specType = specType.semantic(loc, sc);
+		}
+		specAlias = aliasParameterSemantic(loc, sc, specAlias);
+		static if (0) { // Don't do semantic() until instantiation
+			if (defaultAlias)
+				defaultAlias = defaultAlias.semantic(loc, sc);
+		}
+	}
+
+	void print(Object oarg, Object oded)
+	{
+		printf(" %s\n", ident.toChars());
+
+		Dsymbol sa = isDsymbol(oded);
+		assert(sa);
+
+		printf("\tArgument alias: %s\n", sa.toChars());
 	}
-	
-    void print(Object oarg, Object oded)
+
+	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
 	{
-		assert(false);
+		buf.writestring("alias ");
+		if (specType)
+		{	HdrGenState hg;
+			specType.toCBuffer(buf, ident, &hg);
+		}
+		else
+			buf.writestring(ident.toChars());
+		if (specAlias)
+		{
+			buf.writestring(" : ");
+			ObjectToCBuffer(buf, hgs, specAlias);
+		}
+		if (defaultAlias)
+		{
+			buf.writestring(" = ");
+			ObjectToCBuffer(buf, hgs, defaultAlias);
+		}
 	}
-	
-    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+
+	Object specialization()
+	{
+		return specAlias;
+	}
+
+	Object defaultArg(Loc loc, Scope sc)
+	{
+		Object o = aliasParameterSemantic(loc, sc, defaultAlias);
+		return o;
+	}
+
+	bool overloadMatch(TemplateParameter tp)
 	{
-		assert(false);
+		TemplateAliasParameter tap = tp.isTemplateAliasParameter();
+
+		if (tap)
+		{
+			if (specAlias != tap.specAlias)
+				goto Lnomatch;
+
+			return true;			// match
+		}
+
+Lnomatch:
+		return false;
 	}
-	
-    Object specialization()
+
+	MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags)
 	{
-		assert(false);
-	}
-	
-    Object defaultArg(Loc loc, Scope sc)
-	{
-		assert(false);
-	}
-	
-    bool overloadMatch(TemplateParameter)
-	{
-		assert(false);
+		Object sa;
+		Object oarg;
+		Expression ea;
+		Dsymbol s;
+
+		//printf("TemplateAliasParameter.matchArg()\n");
+
+		if (i < tiargs.dim)
+			oarg = cast(Object)tiargs.data[i];
+		else
+		{	// Get default argument instead
+			oarg = defaultArg(loc, sc);
+			if (!oarg)
+			{   assert(i < dedtypes.dim);
+				// It might have already been deduced
+				oarg = cast(Object)dedtypes.data[i];
+				if (!oarg)
+					goto Lnomatch;
+			}
+		}
+
+		sa = getDsymbol(oarg);
+		if (sa)
+		{
+			/* specType means the alias must be a declaration with a type
+			 * that matches specType.
+			 */
+			if (specType)
+			{   Declaration d = (cast(Dsymbol)sa).isDeclaration();
+					if (!d)
+					goto Lnomatch;
+					if (!d.type.equals(specType))
+					goto Lnomatch;
+					}
+					}
+					else
+					{
+					sa = oarg;
+					ea = isExpression(oarg);
+					if (ea)
+					{   if (specType)
+					{
+					if (!ea.type.equals(specType))
+					goto Lnomatch;
+					}
+					}
+					else
+					goto Lnomatch;
+					}	
+			if (specAlias)
+			{
+				if (sa == sdummy)
+					goto Lnomatch;
+				if (sa != specAlias)
+					goto Lnomatch;
+			}
+			else if (dedtypes.data[i])
+			{   // Must match already deduced symbol
+				Object s_ = cast(Object)dedtypes.data[i];
+
+				if (!sa || s_ != sa)
+					goto Lnomatch;
+			}
+			dedtypes.data[i] = cast(void*)sa;
+
+			s = isDsymbol(sa);
+			if (s)
+				*psparam = new AliasDeclaration(loc, ident, s);
+			else
+			{
+				assert(ea);
+
+				// Declare manifest constant
+				Initializer init = new ExpInitializer(loc, ea);
+				VarDeclaration v = new VarDeclaration(loc, null, ident, init);
+				v.storage_class = STC.STCmanifest;
+				v.semantic(sc);
+				*psparam = v;
+			}
+			return MATCHexact;
+
+Lnomatch:
+			*psparam = null;
+			//printf("\tm = %d\n", MATCHnomatch);
+			return MATCHnomatch;
 	}
-	
-    MATCH matchArg(Scope sc, Objects tiargs, int i, TemplateParameters parameters, Objects dedtypes, Declaration* psparam, int flags)
+
+	void* dummyArg()
 	{
-		assert(false);
+		Object s;
+
+		s = specAlias;
+		if (!s)
+		{
+			if (!sdummy)
+				sdummy = new Dsymbol();
+			s = sdummy;
+		}
+		return cast(void*)s;
 	}
-	
-    void* dummyArg()
-	{
-		assert(false);
-	}
-}
\ No newline at end of file
+}
--- a/dmd/TemplateMixin.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/TemplateMixin.d	Tue Apr 06 02:21:04 2010 +0100
@@ -10,72 +10,492 @@
 import dmd.Scope;
 import dmd.OutBuffer;
 import dmd.HdrGenState;
+import dmd.DYNCAST;
+import dmd.AggregateDeclaration;
+import dmd.TemplateDeclaration;
+import dmd.Expression;
+import dmd.DsymbolTable;
+import dmd.PROT;
+import dmd.ScopeDsymbol;
+import dmd.Global;
+import dmd.Util;
+
+extern(C++) void util_progress();
 
 class TemplateMixin : TemplateInstance
 {
-    Array idents;
-    Type tqual;
+	Array idents;
+	Type tqual;
 
-    this(Loc loc, Identifier ident, Type tqual, Array idents, Objects tiargs)
-	{
-		assert(false);
-		super(loc, ident);
-	}
-	
-    Dsymbol syntaxCopy(Dsymbol s)
+	this(Loc loc, Identifier ident, Type tqual, Array idents, Objects tiargs)
 	{
-		assert(false);
-	}
-	
-    void semantic(Scope sc)
-	{
-		assert(false);
-	}
-	
-    void semantic2(Scope sc)
-	{
-		assert(false);
-	}
-	
-    void semantic3(Scope sc)
-	{
-		assert(false);
+		super(loc, cast(Identifier)idents.data[idents.dim - 1]);
+		//printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
+		this.ident = ident;
+		this.tqual = tqual;
+		this.idents = idents;
+		this.tiargs = tiargs ? tiargs : new Objects();
 	}
-	
-    void inlineScan()
-	{
-		assert(false);
-	}
-	
-    string kind()
-	{
-		assert(false);
-	}
-	
-    bool oneMember(Dsymbol* ps)
+
+	Dsymbol syntaxCopy(Dsymbol s)
 	{
-		assert(false);
-	}
-	
-    bool hasPointers()
-	{
-		assert(false);
-	}
-	
-    string toChars()
-	{
-		assert(false);
-	}
-	
-    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
-	{
-		assert(false);
+		TemplateMixin tm;
+
+		Array ids = new Array();
+		ids.setDim(idents.dim);
+		for (int i = 0; i < idents.dim; i++)
+		{	// Matches TypeQualified.syntaxCopyHelper()
+			Identifier id = cast(Identifier)idents.data[i];
+			if (id.dyncast() == DYNCAST.DYNCAST_DSYMBOL)
+			{
+				TemplateInstance ti = cast(TemplateInstance)id;
+
+				ti = cast(TemplateInstance)ti.syntaxCopy(null);
+				id = cast(Identifier)ti;
+			}
+			ids.data[i] = cast(void*)id;
+		}
+
+		tm = new TemplateMixin(loc, ident,
+				cast(Type)(tqual ? tqual.syntaxCopy() : null),
+				ids, tiargs);
+		TemplateInstance.syntaxCopy(tm);
+		return tm;
 	}
 
-    void toObjFile(int multiobj)			// compile to .obj file
+	void semantic(Scope sc)
 	{
-		assert(false);
+		version (LOG) {
+			printf("+TemplateMixin.semantic('%s', this=%p)\n", toChars(), this);
+			fflush(stdout);
+		}
+		if (semanticRun &&
+				// This for when a class/struct contains mixin members, and
+				// is done over because of forward references
+				(!parent || !toParent().isAggregateDeclaration()))
+		{
+			version (LOG) {
+				printf("\tsemantic done\n");
+			}
+			return;
+		}
+		if (!semanticRun)
+			semanticRun = 1;
+		version (LOG) {
+			printf("\tdo semantic\n");
+		}
+		util_progress();
+
+		Scope scx = null;
+		if (scope_)
+		{	sc = scope_;
+			scx = scope_;		// save so we don't make redundant copies
+			scope_ = null;
+		}
+
+		// Follow qualifications to find the TemplateDeclaration
+		if (!tempdecl)
+		{	Dsymbol s;
+			int i;
+			Identifier id;
+
+			if (tqual)
+			{   s = tqual.toDsymbol(sc);
+				i = 0;
+			}
+			else
+			{
+				i = 1;
+				id = cast(Identifier)idents.data[0];
+				switch (id.dyncast())
+				{
+					case DYNCAST.DYNCAST_IDENTIFIER:
+						s = sc.search(loc, id, null);
+						break;
+
+					case DYNCAST.DYNCAST_DSYMBOL:
+						{
+							TemplateInstance ti = cast(TemplateInstance)id;
+							ti.semantic(sc);
+							s = ti;
+							break;
+						}
+					default:
+						assert(0);
+				}
+			}
+
+			for (; i < idents.dim; i++)
+			{
+				if (!s)
+					break;
+				id = cast(Identifier)idents.data[i];
+				s = s.searchX(loc, sc, id);
+			}
+			if (!s)
+			{
+				error("is not defined");
+				inst = this;
+				return;
+			}
+			tempdecl = s.toAlias().isTemplateDeclaration();
+			if (!tempdecl)
+			{
+				error("%s isn't a template", s.toChars());
+				inst = this;
+				return;
+			}
+		}
+
+		// Look for forward reference
+		assert(tempdecl);
+		for (TemplateDeclaration td = tempdecl; td; td = td.overnext)
+		{
+			if (!td.semanticRun)
+			{
+				/* Cannot handle forward references if mixin is a struct member,
+				 * because addField must happen during struct's semantic, not
+				 * during the mixin semantic.
+				 * runDeferred will re-run mixin's semantic outside of the struct's
+				 * semantic.
+				 */
+				semanticRun = 0;
+				AggregateDeclaration ad = toParent().isAggregateDeclaration();
+				if (ad)
+					ad.sizeok = 2;
+				else
+				{
+					// Forward reference
+					//printf("forward reference - deferring\n");
+					scope_ = scx ? scx : new Scope(sc);
+					scope_.setNoFree();
+					scope_.module_.addDeferredSemantic(this);
+				}
+				return;
+			}
+		}
+
+		// Run semantic on each argument, place results in tiargs[]
+		semanticTiargs(sc);
+
+		tempdecl = findBestMatch(sc);
+		if (!tempdecl)
+		{	inst = this;
+			return;		// error recovery
+		}
+
+		if (!ident)
+			ident = genIdent();
+
+		inst = this;
+		parent = sc.parent;
+
+		/* Detect recursive mixin instantiations.
+		 */
+		for (Dsymbol s = parent; s; s = s.parent)
+		{
+			//printf("\ts = '%s'\n", s.toChars());
+			TemplateMixin tm = s.isTemplateMixin();
+			if (!tm || tempdecl != tm.tempdecl)
+				continue;
+
+			/* Different argument list lengths happen with variadic args
+			 */
+			if (tiargs.dim != tm.tiargs.dim)
+				continue;
+
+			for (int i = 0; i < tiargs.dim; i++)
+			{   Object o = cast(Object)tiargs.data[i];
+				Type ta = isType(o);
+				Expression ea = isExpression(o);
+				Dsymbol sa = isDsymbol(o);
+				Object tmo = cast(Object)tm.tiargs.data[i];
+				if (ta)
+				{
+					Type tmta = isType(tmo);
+					if (!tmta)
+						goto Lcontinue;
+					if (!ta.equals(tmta))
+						goto Lcontinue;
+				}
+				else if (ea)
+				{	Expression tme = isExpression(tmo);
+					if (!tme || !ea.equals(tme))
+						goto Lcontinue;
+				}
+				else if (sa)
+				{
+					Dsymbol tmsa = isDsymbol(tmo);
+					if (sa != tmsa)
+						goto Lcontinue;
+				}
+				else
+					assert(0);
+			}
+			error("recursive mixin instantiation");
+			return;
+
+Lcontinue:
+			continue;
+		}
+
+
+		// Copy the syntax trees from the TemplateDeclaration
+		members = Dsymbol.arraySyntaxCopy(tempdecl.members);
+		if (!members)
+			return;
+
+		symtab = new DsymbolTable();
+
+		for (Scope sce = sc; 1; sce = sce.enclosing)
+		{
+			ScopeDsymbol sds = cast(ScopeDsymbol)sce.scopesym;
+			if (sds)
+			{
+				sds.importScope(this, PROT.PROTpublic);
+				break;
+			}
+		}
+
+		version (LOG) {
+			printf("\tcreate scope for template parameters '%s'\n", toChars());
+		}
+		Scope scy = sc;
+		scy = sc.push(this);
+		scy.parent = this;
+
+		argsym = new ScopeDsymbol();
+		argsym.parent = scy.parent;
+		Scope argscope = scy.push(argsym);
+
+		uint errorsave = global.errors;
+
+		// Declare each template parameter as an alias for the argument type
+		declareParameters(argscope);
+
+		// Add members to enclosing scope, as well as this scope
+		for (uint i = 0; i < members.dim; i++)
+		{   Dsymbol s;
+
+			s = cast(Dsymbol)members.data[i];
+			s.addMember(argscope, this, i);
+			//sc.insert(s);
+			//printf("sc.parent = %p, sc.scopesym = %p\n", sc.parent, sc.scopesym);
+			//printf("s.parent = %s\n", s.parent.toChars());
+		}
+
+		// Do semantic() analysis on template instance members
+		version (LOG) {
+			printf("\tdo semantic() on template instance members '%s'\n", toChars());
+		}
+		Scope sc2;
+		sc2 = argscope.push(this);
+		sc2.offset = sc.offset;
+
+
+		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];
+			s.semantic(sc2);
+		}
+
+		nest--;
+
+		sc.offset = sc2.offset;
+
+		/* 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())
+
+		semantic2(sc2);
+
+		if (sc.func)
+		{
+			semantic3(sc2);
+		}
+
+		// Give additional context info if error occurred during instantiation
+		if (global.errors != errorsave)
+		{
+			error("error instantiating");
+		}
+
+		sc2.pop();
+
+		argscope.pop();
+
+		//    if (!isAnonymous())
+		{
+			scy.pop();
+		}
+		version (LOG) {
+			printf("-TemplateMixin.semantic('%s', this=%p)\n", toChars(), this);
+		}
 	}
 
-    TemplateMixin isTemplateMixin() { return this; }
-}
\ No newline at end of file
+	void semantic2(Scope sc)
+	{
+		int i;
+
+		if (semanticRun >= 2)
+			return;
+		semanticRun = 2;
+		version (LOG) {
+			printf("+TemplateMixin.semantic2('%s')\n", toChars());
+		}
+		if (members)
+		{
+			assert(sc);
+			sc = sc.push(argsym);
+			sc = sc.push(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("-TemplateMixin.semantic2('%s')\n", toChars());
+		}
+	}
+
+	void semantic3(Scope sc)
+	{
+		int i;
+
+		if (semanticRun >= 3)
+			return;
+		semanticRun = 3;
+		version (LOG) {
+			printf("TemplateMixin.semantic3('%s')\n", toChars());
+		}
+		if (members)
+		{
+			sc = sc.push(argsym);
+			sc = sc.push(this);
+			for (i = 0; i < members.dim; i++)
+			{
+				Dsymbol s = cast(Dsymbol)members.data[i];
+				s.semantic3(sc);
+			}
+			sc = sc.pop();
+			sc.pop();
+		}
+	}
+
+	void inlineScan()
+	{
+		TemplateInstance.inlineScan();
+	}
+
+	string kind()
+	{
+		return "mixin";
+	}
+
+	bool oneMember(Dsymbol* ps)
+	{
+		return Dsymbol.oneMember(ps);
+	}
+
+	bool hasPointers()
+	{
+		//printf("TemplateMixin.hasPointers() %s\n", toChars());
+		for (size_t i = 0; i < members.dim; i++)
+		{
+			Dsymbol s = cast(Dsymbol)members.data[i];
+			//printf(" s = %s %s\n", s.kind(), s.toChars());
+			if (s.hasPointers())
+			{
+				return 1;
+			}
+		}
+		return 0;
+	}
+
+	string toChars()
+	{
+		OutBuffer buf;
+		HdrGenState hgs;
+		string s;
+
+		TemplateInstance.toCBuffer(buf, &hgs);
+		s = buf.toChars();
+		buf.data = null;
+		return s;
+	}
+
+	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		buf.writestring("mixin ");
+
+		for (int i = 0; i < idents.dim; i++)
+		{   Identifier id = cast(Identifier)idents.data[i];
+
+			if (i)
+				buf.writeByte('.');
+			buf.writestring(id.toChars());
+		}
+		buf.writestring("!(");
+		if (tiargs)
+		{
+			for (int i = 0; i < tiargs.dim; i++)
+			{   if (i)
+				buf.writebyte(',');
+				Object oarg = cast(Object)tiargs.data[i];
+				Type t = isType(oarg);
+				Expression e = isExpression(oarg);
+				Dsymbol s = isDsymbol(oarg);
+				if (t)
+					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 (!oarg)
+				{
+					buf.writestring("null");
+				}
+				else
+				{
+					assert(0);
+				}
+			}
+		}
+		buf.writebyte(')');
+		if (ident)
+		{
+			buf.writebyte(' ');
+			buf.writestring(ident.toChars());
+		}
+		buf.writebyte(';');
+		buf.writenl();
+	}
+
+	void toObjFile(int multiobj)			// compile to .obj file
+	{
+		//printf("TemplateMixin.toObjFile('%s')\n", toChars());
+		TemplateInstance.toObjFile(multiobj);
+	}
+
+	TemplateMixin isTemplateMixin() { return this; }
+}
--- a/dmd/TypeDArray.d	Mon Apr 05 19:16:14 2010 +0100
+++ b/dmd/TypeDArray.d	Tue Apr 06 02:21:04 2010 +0100
@@ -161,7 +161,8 @@
 	
     int isString()
 	{
-		assert(false);
+    TY nty = next.toBasetype().ty;
+    return nty == TY.Tchar || nty == TY.Twchar || nty == TY.Tdchar;
 	}
 	
     bool isZeroInit(Loc loc)