Index: dsymbol.c
===================================================================
--- dsymbol.c	(revision 240)
+++ dsymbol.c	(working copy)
@@ -1031,7 +1031,7 @@
 ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e)
     : ScopeDsymbol()
 {
-    assert(e->op == TOKindex || e->op == TOKslice);
+    assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray);
     exp = e;
     type = NULL;
     td = NULL;
@@ -1103,6 +1103,66 @@
 	    pvar = &se->lengthVar;
 	    ce = se->e1;
 	}
+	else if (exp->op == TOKarray)
+	{   /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
+	     * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
+	     */
+	    ArrayExp *ae = (ArrayExp *)exp;
+	    AggregateDeclaration *ad=NULL;
+    
+	    Type *t = ae->e1->type->toBasetype();
+	    if (t->ty == Tclass)
+	    {
+		ad = ((TypeClass *)t)->sym;
+	    }
+	    else if (t->ty == Tstruct)
+	    {
+		ad = ((TypeStruct *)t)->sym;
+	    }
+	    assert(ad);
+
+	    Dsymbol *dsym = search_function(ad, Id::opDollar);
+    	    if (!dsym) return NULL; // no dollar exists -- search in higher scope
+	    VarDeclaration *v = ae->lengthVar;
+	    if (!v) {
+	        // $ is lazily initialized. Create it now.
+		TemplateDeclaration *td = dsym->isTemplateDeclaration();
+		if (td) {
+		    // Instantiate opDollar!(dim) with the index as a template argument
+		    Objects *tdargs = new Objects();
+		    tdargs->setDim(1);
+			
+		    Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t);
+		    x = x->semantic(sc);
+		    tdargs->data[0] = x;
+		    
+		    TemplateInstance *ti = new TemplateInstance(loc, td, tdargs);
+		    ti->semantic(sc);
+		    
+		    DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, ti);
+		    
+		    v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte));
+		} else {
+		    /* opDollar exists, but it's a function, not a template.
+		     * This is acceptable ONLY for single-dimension indexing.
+		     * Note that it's impossible to have both template & function opDollar,
+		     * because both take no arguments.
+		     */
+		    if (ae->arguments->dim != 1) {
+		        ae->error("%s only defines opDollar for one dimension", ad->toChars());
+		        return NULL;
+		    }
+		    FuncDeclaration *fd = dsym->isFuncDeclaration();
+		    assert(fd);
+		    Expression * x = new DotVarExp(loc, ae->e1, fd);
+		    
+		    v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x));
+		}
+		v->semantic(sc);
+		ae->lengthVar = v;
+	    }
+	    return v;
+	}
 	else
 	    /* Didn't find $, look in enclosing scope(s).
 	     */
Index: expression.c
===================================================================
--- expression.c	(revision 240)
+++ expression.c	(working copy)
@@ -7904,11 +7904,26 @@
     // Run semantic() on each argument
     for (size_t i = 0; i < arguments->dim; i++)
     {	e = (Expression *)arguments->data[i];
-
+	// Create scope for '$' variable for this dimension
+	ArrayScopeSymbol *sym;
+	sym = new ArrayScopeSymbol(sc, this);
+	sym->loc = loc;
+	sym->parent = sc->scopesym;
+	sc = sc->push(sym);
+	lengthVar = NULL;       // Create it only if required
+        currentDimension = i;   // Dimension for $, if required
+	
 	e = e->semantic(sc);
 	if (!e->type)
 	    error("%s has no value", e->toChars());
+	if (lengthVar) {
+	    // If $ was used, declare it now
+	    Expression *av = new DeclarationExp(loc, lengthVar);		
+	    e = new CommaExp(0, av, e);
+	    e->semantic(sc);
+	}
 	arguments->data[i] = (void *)e;
+	sc=sc->pop();
     }
 
     expandTuples(arguments);
@@ -8305,6 +8320,30 @@
 	    // Rewrite (a[i] = value) to (a.opIndexAssign(value, i))
 	    if (search_function(ad, Id::indexass))
 	    {	Expression *e = new DotIdExp(loc, ae->e1, Id::indexass);
+	        // Deal with $
+		for (size_t i = 0; i < ae->arguments->dim; i++)
+		{   Expression *x = (Expression *)ae->arguments->data[i];
+		    // Create scope for '$' variable for this dimension
+		    ArrayScopeSymbol *sym;
+		    sym = new ArrayScopeSymbol(sc, ae);
+		    sym->loc = loc;
+		    sym->parent = sc->scopesym;
+		    sc = sc->push(sym);
+		    ae->lengthVar = NULL;       // Create it only if required
+		    ae->currentDimension = i;   // Dimension for $, if required
+			
+		    x = x->semantic(sc);
+		    if (!x->type)
+			ae->error("%s has no value", x->toChars());
+		    if (ae->lengthVar) {
+			// If $ was used, declare it now
+			Expression *av = new DeclarationExp(ae->loc, ae->lengthVar);		
+			x = new CommaExp(0, av, x);
+			x->semantic(sc);
+		    }
+		    ae->arguments->data[i] = (void *)x;
+		    sc = sc->pop();
+		}
 		Expressions *a = (Expressions *)ae->arguments->copy();
 
 		a->insert(0, e2);
@@ -8350,7 +8389,7 @@
 	{
 	    ad = ((TypeClass *)t1)->sym;
 	  L2:
-	    // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j))
+	    // Rewrite (a[i..j] = value) to (a.opSliceAssign(value, i, j))
 	    if (search_function(ad, Id::sliceass))
 	    {	Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass);
 		Expressions *a = new Expressions();
Index: expression.h
===================================================================
--- expression.h	(revision 240)
+++ expression.h	(working copy)
@@ -1076,6 +1076,8 @@
 struct ArrayExp : UnaExp
 {
     Expressions *arguments;		// Array of Expression's
+    size_t currentDimension; // for __dollar
+    VarDeclaration *lengthVar;
 
     ArrayExp(Loc loc, Expression *e1, Expressions *arguments);
     Expression *syntaxCopy();
Index: idgen.c
===================================================================
--- idgen.c	(revision 240)
+++ idgen.c	(working copy)
@@ -208,6 +208,7 @@
     { "opStar" },
     { "opDot" },
     { "opImplicitCast" },
+    { "opDollar" },
 
     { "classNew", "new" },
     { "classDelete", "delete" },
