Index: interpret.c
===================================================================
--- interpret.c	(revision 192)
+++ interpret.c	(working copy)
@@ -1431,6 +1431,68 @@
 BIN_INTERPRET2(Identity)
 BIN_INTERPRET2(Cmp)
 
+// Helper functions for BinExp::interpretAssignCommon
+//
+//
+
+// Duplicate the elements array, then set field 'indexToChange' = newelem.
+Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem)
+{
+	Expressions *expsx = new Expressions();
+	expsx->setDim(oldelems->dim);
+	for (size_t j = 0; j < expsx->dim; j++)
+	{
+	    if (j == indexToChange)
+		expsx->data[j] = newelem;
+	    else
+		expsx->data[j] = oldelems->data[j];
+	}
+	return expsx;
+}
+
+// Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint..$]
+Expressions *spliceElements(Expressions *oldelems, Expressions *newelems, size_t insertpoint)
+{
+	Expressions *expsx = new Expressions();
+	expsx->setDim(oldelems->dim);
+	for (size_t j = 0; j < expsx->dim; j++)
+	{
+	    if (j >= insertpoint && j < insertpoint +  newelems->dim)
+		expsx->data[j] = newelems->data[j-insertpoint];
+	    else
+		expsx->data[j] = oldelems->data[j];
+	}
+	return expsx;
+}
+
+// Create an array literal consisting of 'elem' duplicated 'dim' times.
+ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, Expression *elem, size_t dim)
+{
+    Expressions *elements = new Expressions();
+	elements->setDim(dim);
+	for (size_t i = 0; i < dim; i++)
+	     elements->data[i] = elem;	           
+    ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
+    ae->type = type;
+	return ae;
+}
+
+// Necessary because defaultInit() for a struct is a VarExp, not a StructLiteralExp.
+StructLiteralExp *createDefaultInitStructLiteral(Loc loc, StructDeclaration *sym)
+{
+	Expressions * structelems = new Expressions();
+	structelems->setDim(sym->fields.dim);
+	for (size_t j = 0; j < structelems->dim; j++)
+	{
+        structelems->data[j] = ((VarDeclaration *)(sym->fields.data[j]))->type->defaultInit();
+	}
+	StructLiteralExp *structinit = new StructLiteralExp(loc, sym, structelems);
+	 // Why doesn't the StructLiteralExp constructor do this, when sym->type!=NULL??
+	structinit->type = sym->type;
+	return structinit;
+}
+
+
 Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post)
 {
 #if LOG
@@ -1521,8 +1583,10 @@
     {	VarExp *ve = (VarExp *)((DotVarExp *)e1)->e1;
 	VarDeclaration *v = ve->var->isVarDeclaration();
 
-	if (v->isDataseg())
+	if (v->isDataseg()) {
+		error("%s cannot be modified at compile time", v->toChars());
 	    return EXP_CANT_INTERPRET;
+	}
 	if (fp && !v->value)
 	{   error("variable %s is used before initialization", v->toChars());
 	    return e;
@@ -1574,15 +1638,7 @@
 
 	/* Create new struct literal reflecting updated fieldi
 	 */
-	Expressions *expsx = new Expressions();
-	expsx->setDim(se->elements->dim);
-	for (size_t j = 0; j < expsx->dim; j++)
-	{
-	    if (j == fieldi)
-		expsx->data[j] = (void *)e2;
-	    else
-		expsx->data[j] = se->elements->data[j];
-	}
+	Expressions *expsx = changeOneElement(se->elements, fieldi, e2);
 	v->value = new StructLiteralExp(se->loc, se->sd, expsx);
 	v->value->type = se->type;
 
@@ -1595,8 +1651,10 @@
     {	SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1;
 	VarDeclaration *v = soe->var->isVarDeclaration();
 
-	if (v->isDataseg())
+	if (v->isDataseg()) {
+		error("%s cannot be modified at compile time", v->toChars());
 	    return EXP_CANT_INTERPRET;
+	}
 	if (fp && !v->value)
 	{   error("variable %s is used before initialization", v->toChars());
 	    return e;
@@ -1636,15 +1694,7 @@
 
 	/* Create new struct literal reflecting updated fieldi
 	 */
-	Expressions *expsx = new Expressions();
-	expsx->setDim(se->elements->dim);
-	for (size_t j = 0; j < expsx->dim; j++)
-	{
-	    if (j == fieldi)
-		expsx->data[j] = (void *)e2;
-	    else
-		expsx->data[j] = se->elements->data[j];
-	}
+	Expressions *expsx = changeOneElement(se->elements, fieldi, e2);
 	v->value = new StructLiteralExp(se->loc, se->sd, expsx);
 	v->value->type = se->type;
 
@@ -1658,8 +1708,10 @@
 	VarExp *ve = (VarExp *)ie->e1;
 	VarDeclaration *v = ve->var->isVarDeclaration();
 
-	if (!v || v->isDataseg())
+	if (!v || v->isDataseg()) {
+		error("%s cannot be modified at compile time", v->toChars());
 	    return EXP_CANT_INTERPRET;
+	}
 	if (!v->value)
 	{
 	    if (fp)
@@ -1677,15 +1729,9 @@
 		 * But we're too lazy at the moment to do it, as that
 		 * involves redoing Index() and whoever calls it.
 		 */
-		Expression *ev = v->type->defaultInit();
+
 		size_t dim = ((TypeSArray *)t)->dim->toInteger();
-		Expressions *elements = new Expressions();
-		elements->setDim(dim);
-		for (size_t i = 0; i < dim; i++)
-		    elements->data[i] = (void *)ev;
-		ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements);
-		ae->type = v->type;
-		v->value = ae;
+        v->value = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim);
 	    }
 	    else
 		return EXP_CANT_INTERPRET;
@@ -1700,9 +1746,18 @@
 	    aae = (AssocArrayLiteralExp *)v->value;
 	else if (v->value->op == TOKstring)
 	    se = (StringExp *)v->value;
-	else
+	else if (v->value->op == TOKnull) {
+		// This would be a runtime segfault
+		error("Cannot index null array %s", v->toChars());
 	    return EXP_CANT_INTERPRET;
-
+	} else
+	    return EXP_CANT_INTERPRET;
+	/* Set the $ variable
+	 */
+	Expression *ee = ArrayLength(Type::tsize_t, v->value);
+	if (ee != EXP_CANT_INTERPRET && ie->lengthVar) {
+	    ie->lengthVar->value = ee;
+	}
 	Expression *index = ie->e2->interpret(istate);
 	if (index == EXP_CANT_INTERPRET)
 	    return EXP_CANT_INTERPRET;
@@ -1739,15 +1794,7 @@
 	    /* Create new array literal reflecting updated elem
 	     */
 	    int elemi = index->toInteger();
-	    Expressions *expsx = new Expressions();
-	    expsx->setDim(ae->elements->dim);
-	    for (size_t j = 0; j < expsx->dim; j++)
-	    {
-		if (j == elemi)
-		    expsx->data[j] = (void *)e2;
-		else
-		    expsx->data[j] = ae->elements->data[j];
-	    }
+		Expressions *expsx = changeOneElement(ae->elements, elemi, e2);
 	    v->value = new ArrayLiteralExp(ae->loc, expsx);
 	    v->value->type = ae->type;
 	}
@@ -1810,8 +1857,205 @@
 
 	e = Cast(type, type, post ? ev : e2);
     }
+	/* Assignment to struct element in array, of the form:
+	*   a[i].var = e2
+	*/
+	else if(e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKindex
+		&& ((IndexExp *)((DotVarExp *)e1)->e1)->e1->op == TOKvar
+		){
+			IndexExp * ie = (IndexExp *)((DotVarExp *)e1)->e1;
+
+	        VarExp *ve = (VarExp *)(ie->e1);
+	        VarDeclaration *v = ve->var->isVarDeclaration();
+			if (!v || v->isDataseg()) {
+				error("%s cannot be modified at compile time", v->toChars());
+				return EXP_CANT_INTERPRET;
+			}
+	        Type *t = ve->type->toBasetype();
+	        ArrayLiteralExp *ae = (ArrayLiteralExp *)v->value;
+			if(!ae) {
+				// assignment to one element in an uninitialized (static) array.
+				// This is quite difficult, because defaultInit() for a struct is a VarExp,
+				// not a StructLiteralExp.
+			    Type *t = v->type->toBasetype();
+				if (t->ty != Tsarray) {
+					error("Cannot index an uninitialized variable");
+					return EXP_CANT_INTERPRET;
+				}
+
+			    Type *telem = ((TypeSArray *)t)->nextOf()->toBasetype();
+			    if (telem->ty != Tstruct) { return EXP_CANT_INTERPRET; }
+
+				// Create a default struct literal...
+			    StructDeclaration *sym = ((TypeStruct *)telem)->sym;
+				StructLiteralExp *structinit = createDefaultInitStructLiteral(v->loc, sym);
+
+				// ... and use to create a blank array literal
+		        size_t dim = ((TypeSArray *)t)->dim->toInteger();
+		        ae = createBlockDuplicatedArrayLiteral(v->type, structinit, dim);
+		        v->value = ae;
+			}
+			if ((Expression *)(ae->elements) == EXP_CANT_INTERPRET) {
+				// Note that this would be a runtime segfault
+				error("Cannot index null array %s", v->toChars());
+				return EXP_CANT_INTERPRET;
+			}
+			// Set the $ variable
+			Expression *ee = ArrayLength(Type::tsize_t, v->value);
+			if (ee != EXP_CANT_INTERPRET && ie->lengthVar) {
+				ie->lengthVar->value = ee;
+			}
+			// Determine the index, and check that it's OK.
+	        Expression *index = ie->e2->interpret(istate);
+	        if (index == EXP_CANT_INTERPRET)
+	            return EXP_CANT_INTERPRET;
+
+	        int elemi = index->toInteger();
+		    if (elemi >= ae->elements->dim) {
+			    error("array index %d is out of bounds %s[0..%d]", elemi, v->toChars(), ae->elements->dim);
+                return EXP_CANT_INTERPRET;
+		    }
+		    // Get old element
+	        Expression *vie = (Expression *)(ae->elements->data[elemi]);
+			if (vie->op != TOKstructliteral) {
+	            return EXP_CANT_INTERPRET;
+			}
+			// Work out which field needs to be changed
+	        StructLiteralExp *se = (StructLiteralExp *)vie;
+	        VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration();
+	        if (!vf)
+	            return EXP_CANT_INTERPRET;
+
+	        int fieldi = se->getFieldIndex(type, vf->offset);
+	        if (fieldi == -1)
+	            return EXP_CANT_INTERPRET;
+			
+	        Expression *ev = se->getField(type, vf->offset);
+	        if (fp)
+	            e2 = (*fp)(type, ev, e2);
+	        else
+	            e2 = Cast(type, type, e2);
+	        if (e2 == EXP_CANT_INTERPRET)
+	            return e2;
+
+            // Create new struct literal reflecting updated field
+	        Expressions *expsx = changeOneElement(se->elements, fieldi, e2);
+	        Expression * newstruct = new StructLiteralExp(se->loc, se->sd, expsx);
+
+            // Create new array literal reflecting updated struct elem
+		    ae->elements = changeOneElement(ae->elements, elemi, newstruct);
+		    return ae;
+	}
+	/* Slice assignment, initialization of static arrays
+	 *   a[] = e
+	 */
+    else if (e1->op == TOKslice && ((SliceExp *)e1)->e1->op==TOKvar) {
+        SliceExp * sexp = (SliceExp *)e1;
+	    VarExp *ve = (VarExp *)(sexp->e1);
+	    VarDeclaration *v = ve->var->isVarDeclaration();
+		if (!v || v->isDataseg()) {
+			error("%s cannot be modified at compile time", v->toChars());
+			return EXP_CANT_INTERPRET;
+		}
+	    /* Set the $ variable
+	     */
+		Expression *ee = v->value? ArrayLength(Type::tsize_t, v->value) : EXP_CANT_INTERPRET;
+	    if (ee != EXP_CANT_INTERPRET && sexp->lengthVar) {
+	        sexp->lengthVar->value = ee;
+        }
+	    Expression *upper = NULL;
+		Expression *lower = NULL;
+		if (sexp->upr) {
+			upper = sexp->upr->interpret(istate);
+			if (upper == EXP_CANT_INTERPRET) {
+				return EXP_CANT_INTERPRET;
+			}
+		}
+		if (sexp->lwr) {
+			lower = sexp->lwr->interpret(istate);
+			if (lower == EXP_CANT_INTERPRET) {
+				return EXP_CANT_INTERPRET;
+			}
+		}
+	    Type *t = v->type->toBasetype();
+        size_t dim;
+	    if (t->ty == Tsarray){			 
+	        dim = ((TypeSArray *)t)->dim->toInteger();
+        } else if (t->ty == Tarray) {
+            if (!v->value || v->value->op == TOKnull) {
+                error("cannot assign to null array %s", v->toChars());
+                return EXP_CANT_INTERPRET;
+            }
+            if (v->value->op == TOKarrayliteral) {
+                dim = ((ArrayLiteralExp *)v->value)->elements->dim;
+            } else if (v->value->op ==TOKstring) {
+                error("String slice assignment is not yet supported in CTFE");
+                return EXP_CANT_INTERPRET;
+            }
+        } else {
+            error("%s cannot be evaluated at compile time", toChars());
+            return EXP_CANT_INTERPRET;
+        }
+		int upperbound = upper? upper->toInteger() : dim;
+		int lowerbound = lower? lower->toInteger() : 0;
+
+		ArrayLiteralExp *existing;
+		if (((int)lowerbound<0) || (upperbound > dim)) {
+            error("Array bounds [0..%d] exceeded in slice [%d..%d]", dim, lowerbound, upperbound);
+            return EXP_CANT_INTERPRET;
+        }
+		if (upperbound-lowerbound !=dim) {
+		    // Only modifying part of the array. Must create a new array literal.
+			// If the existing array is uninitialized (this can only happen 
+            // with static arrays), create it.
+			if (v->value && v->value->op == TOKarrayliteral)
+				existing = (ArrayLiteralExp *)v->value;
+			else {
+                // this can only happen with static arrays
+		        existing = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim);
+			}
+        }
+
+			if (e2->op == TOKarrayliteral) {
+				// Static array assignment from literal
+				ArrayLiteralExp *ae = (ArrayLiteralExp *)e2;				
+				if (ae->elements->dim!= (upperbound-lowerbound)) {
+					error("Array length mismatch assigning [0..%d] to [%d..%d]", ae->elements->dim, lowerbound, upperbound);
+					return e;
+				}
+				if (upperbound-lowerbound ==dim) {
+				    v->value = ae;
+				} else {
+					// value[] = value[0..lower] ~ ae ~ value[upper..$]
+					existing->elements = spliceElements(existing->elements, ae->elements, lowerbound);
+				    v->value = existing;
+				}
+				return e2;
+			} else if (t->nextOf()->ty == e2->type->ty) {
+				 // Static array block assignment
+				if (upperbound-lowerbound ==dim) {
+					v->value = createBlockDuplicatedArrayLiteral(v->type, e2, dim);
+				} else {
+					// value[] = value[0..lower] ~ ae ~ value[upper..$]
+					existing->elements = spliceElements(existing->elements, createBlockDuplicatedArrayLiteral(v->type, e2, upperbound-lowerbound)->elements, lowerbound);
+					v->value = existing;
+				}				
+			    return e2;
+            } 	else if (e2->op == TOKstring) {
+                StringExp *	se = (StringExp *)e2;
+                // This is problematic. char[8] should be storing values as a string literal, not
+                // as an array literal. Then, for static arrays, we could do modifications
+                // in-place, with a dramatic memory and speed improvement.
+                error("String slice assignment is not yet supported in CTFE");
+                return e2;
+            } else {
+                error("Slice operation %s cannot be evaluated at compile time", toChars());
+                return e;
+            }
+	}
     else
     {
+		error("%s cannot be evaluated at compile time", toChars());
 #ifdef DEBUG
 	dump(0);
 #endif
