Expand Up
@@ -11468,7 +11468,9 @@ public:
// printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op));
if (type)
return this ;
Expression e1old = e1;
if (e2.op == TOKcomma)
{
/* Rewrite to get rid of the comma from rvalue
Expand All
@@ -11478,6 +11480,7 @@ public:
Expression e = Expression.combine(e0, this );
return e.semantic(sc);
}
/* Look for operator overloading of a[arguments] = e2.
* Do it before e1->semantic() otherwise the ArrayExp will have been
* converted to unary operator overloading already.
Expand All
@@ -11488,8 +11491,12 @@ public:
ArrayExp ae = cast (ArrayExp)e1;
ae.e1 = ae.e1.semantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
Expression ae1old = ae.e1;
const (bool ) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (* ae.arguments)[0 ].op == TOKinterval);
const (bool ) maybeSlice =
(ae.arguments.dim == 0 ||
ae.arguments.dim == 1 && (* ae.arguments)[0 ].op == TOKinterval);
IntervalExp ie = null ;
if (maybeSlice && ae.arguments.dim)
{
Expand All
@@ -11503,6 +11510,7 @@ public:
Expression e0 = null ;
Expression ae1save = ae.e1;
ae.lengthVar = null ;
Type t1b = ae.e1.type.toBasetype();
AggregateDeclaration ad = isAggregate(t1b);
if (! ad)
Expand All
@@ -11515,10 +11523,12 @@ public:
goto Lfallback;
if (result.op == TOKerror)
return result;
result = e2.semantic(sc);
if (result.op == TOKerror)
return result;
e2 = result;
/* Rewrite (a[arguments] = e2) as:
* a.opIndexAssign(e2, arguments)
*/
Expand All
@@ -11536,17 +11546,20 @@ public:
return result;
}
}
Lfallback:
if (maybeSlice && search_function(ad, Id.sliceass))
{
// Deal with $
result = resolveOpDollar(sc, ae, ie, &e0);
if (result.op == TOKerror)
return result;
result = e2.semantic(sc);
if (result.op == TOKerror)
return result;
e2 = result;
/* Rewrite (a[i..j] = e2) as:
* a.opSliceAssign(e2, i, j)
*/
Expand All
@@ -11563,6 +11576,7 @@ public:
result = Expression.combine(e0, result);
return result;
}
// No operator overloading member function found yet, but
// there might be an alias this to try.
if (ad.aliasthis && t1b != ae.att1)
Expand All
@@ -11581,10 +11595,12 @@ public:
ae.e1 = ae1old; // recovery
ae.lengthVar = null ;
}
/* Run this->e1 semantic.
*/
{
Expression e1x = e1;
/* With UFCS, e.f = value
* Could mean:
* .f(e, value)
Expand Down
Expand Up
@@ -11618,6 +11634,7 @@ public:
}
else
e1x = e1x.semantic(sc);
/* We have f = value.
* Could mean:
* f(value)
Expand All
@@ -11632,6 +11649,7 @@ public:
assert (e1.type);
}
Type t1 = e1.type.toBasetype();
/* Run this->e2 semantic.
* Different from other binary expressions, the analysis of e2
* depends on the result of e1 in assignments.
Expand All
@@ -11646,10 +11664,12 @@ public:
return new ErrorExp();
e2 = e2x;
}
/* Rewrite tuple assignment as a tuple of assignments.
*/
{
Expression e2x = e2;
Ltupleassign:
if (e1.op == TOKtuple && e2x.op == TOKtuple)
{
Expand Down
Expand Up
@@ -11682,15 +11702,18 @@ public:
}
return e.semantic(sc);
}
/* Look for form: e1 = e2->aliasthis.
*/
if (e1.op == TOKtuple)
{
TupleDeclaration td = isAliasThisTuple(e2x);
if (! td)
goto Lnomatch;
assert (e1.type.ty == Ttuple);
TypeTuple tt = cast (TypeTuple)e1.type;
Identifier id = Identifier.generateId(" __tup" );
auto ei = new ExpInitializer(e2x.loc, e2x);
auto v = new VarDeclaration(e2x.loc, null , id, ei);
Expand All
@@ -11700,16 +11723,19 @@ public:
Expression e0 = new DeclarationExp(e2x.loc, v);
Expression ev = new VarExp(e2x.loc, v);
ev.type = e2x.type;
auto iexps = new Expressions();
iexps.push(ev);
for (size_t u = 0 ; u < iexps.dim; u++ )
{
Lexpand:
Expression e = (* iexps)[u];
Parameter arg = Parameter.getNth(tt.arguments, u);
// printf("[%d] iexps->dim = %d, ", u, iexps->dim);
// printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
// printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
if (! arg || ! e.type.implicitConvTo(arg.type))
{
// expand initializer to tuple
Expand All
@@ -11731,19 +11757,22 @@ public:
}
Lnomatch:
}
/* Inside constructor, if this is the first assignment of object field,
* rewrite this to initializing the field.
*/
if (op == TOKassign && e1.checkModifiable(sc) == 2 )
{
// printf("[%s] change to init - %s\n", loc.toChars(), toChars());
op = TOKconstruct;
if (e1.op == TOKvar && (cast (VarExp)e1).var.storage_class & (STCout | STCref))
{
// Bugzilla 14944, even if e1 is a ref variable,
// make an initialization of referenced memory.
ismemset |= 2 ;
}
// Bugzilla 13515: set Index::modifiable flag for complex AA element initialization
if (e1.op == TOKindex)
{
Expand All
@@ -11752,10 +11781,13 @@ public:
return e1x;
}
}
/* If it is an assignment from a 'foreign' type,
* check for operator overloading.
*/
if (op == TOKconstruct && e1.op == TOKvar && (cast (VarExp)e1).var.storage_class & (STCout | STCref) && ! (ismemset & 2 ))
if (op == TOKconstruct && e1.op == TOKvar &&
(cast (VarExp)e1).var.storage_class & (STCout | STCref) &&
! (ismemset & 2 ))
{
// If this is an initialization of a reference,
// do nothing
Expand All
@@ -11765,18 +11797,24 @@ public:
Expression e1x = e1;
Expression e2x = e2;
StructDeclaration sd = (cast (TypeStruct)t1).sym;
if (op == TOKconstruct)
{
Type t2 = e2x.type.toBasetype();
if (t2.ty == Tstruct && sd == (cast (TypeStruct)t2).sym)
{
CallExp ce;
DotVarExp dve;
if (sd.ctor && e2x.op == TOKcall && (ce = cast (CallExp)e2x, ce.e1.op == TOKdotvar) && (dve = cast (DotVarExp)ce.e1, dve.var.isCtorDeclaration()) && e2x.type.implicitConvTo(t1))
if (sd.ctor &&
e2x.op == TOKcall &&
(ce = cast (CallExp)e2x, ce.e1.op == TOKdotvar) &&
(dve = cast (DotVarExp)ce.e1, dve.var.isCtorDeclaration()) &&
e2x.type.implicitConvTo(t1))
{
/* Look for form of constructor call which is:
* __ctmp.ctor(arguments...)
*/
/* Before calling the constructor, initialize
* variable with a bit copy of the default
* initializer
Expand All
@@ -11793,6 +11831,7 @@ public:
ae.e2 = sd.isNested() ? t1.defaultInitLiteral(loc) : t1.defaultInit(loc);
}
ae.type = e1x.type;
/* Replace __ctmp being constructed with e1.
* We need to copy constructor call expression,
* because it may be used in other place.
Expand All
@@ -11801,6 +11840,7 @@ public:
dvx.e1 = e1x;
CallExp cx = cast (CallExp)ce.copy();
cx.e1 = dvx;
Expression e = new CommaExp(loc, ae, cx);
e = e.semantic(sc);
return e;
Expand All
@@ -11820,13 +11860,16 @@ public:
Expression e = new CondExp(loc, econd.econd, ea1, ea2);
return e.semantic(sc);
}
if (e2x.isLvalue())
{
if (! e2x.type.implicitConvTo(e1x.type))
{
error(" conversion error from %s to %s" , e2x.type.toChars(), e1x.type.toChars());
error(" conversion error from %s to %s" ,
e2x.type.toChars(), e1x.type.toChars());
return new ErrorExp();
}
/* Rewrite as:
* (e1 = e2).postblit();
*
Expand Down
Expand Up
@@ -11860,6 +11903,7 @@ public:
Expression einit;
einit = new BlitExp(loc, e1x, e1x.type.defaultInit(loc));
einit.type = e1x.type;
Expression e;
e = new DotIdExp(loc, e1x, Id.ctor);
e = new CallExp(loc, e, e2x);
Expand All
@@ -11876,6 +11920,7 @@ public:
*/
e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
e2x = new CallExp(loc, e2x, this .e2);
e2x = e2x.semantic(sc);
e2x = resolveProperties(sc, e2x);
if (e2x.op == TOKerror)
Expand Down
Expand Up
@@ -11917,35 +11962,46 @@ public:
IndexExp ie = cast (IndexExp)e1x;
Type t2 = e2x.type.toBasetype();
Expression e0 = null ;
Expression ea = ie.e1;
Expression ek = ie.e2;
Expression ev = e2x;
if (! isTrivialExp(ea))
{
auto v = new VarDeclaration(loc, ie.e1.type, Identifier.generateId(" __aatmp" ), new ExpInitializer(loc, ie.e1));
v.storage_class |= STCtemp | STCctfe | (ea.isLvalue() ? STCforeach | STCref : STCrvalue);
auto v = new VarDeclaration(loc, ie.e1.type,
Identifier.generateId(" __aatmp" ),
new ExpInitializer (loc, ie.e1));
v.storage_class |= STCtemp | STCctfe
| (ea.isLvalue() ? STCforeach | STCref : STCrvalue);
v.semantic(sc);
e0 = combine(e0, new DeclarationExp(loc, v));
ea = new VarExp(loc, v);
}
if (! isTrivialExp(ek))
{
auto v = new VarDeclaration(loc, ie.e2.type, Identifier.generateId(" __aakey" ), new ExpInitializer(loc, ie.e2));
v.storage_class |= STCtemp | STCctfe | (ek.isLvalue() ? STCforeach | STCref : STCrvalue);
auto v = new VarDeclaration(loc, ie.e2.type,
Identifier.generateId(" __aakey" ),
new ExpInitializer (loc, ie.e2));
v.storage_class |= STCtemp | STCctfe
| (ek.isLvalue() ? STCforeach | STCref : STCrvalue);
v.semantic(sc);
e0 = combine(e0, new DeclarationExp(loc, v));
ek = new VarExp(loc, v);
}
if (! isTrivialExp(ev))
{
auto v = new VarDeclaration(loc, e2x.type, Identifier.generateId(" __aaval" ), new ExpInitializer(loc, e2x));
v.storage_class |= STCtemp | STCctfe | (ev.isLvalue() ? STCforeach | STCref : STCrvalue);
auto v = new VarDeclaration(loc, e2x.type,
Identifier.generateId(" __aaval" ),
new ExpInitializer (loc, e2x));
v.storage_class |= STCtemp | STCctfe
| (ev.isLvalue() ? STCforeach | STCref : STCrvalue);
v.semantic(sc);
e0 = combine(e0, new DeclarationExp(loc, v));
ev = new VarExp(loc, v);
}
if (e0)
e0 = e0.semantic(sc);
AssignExp ae = cast (AssignExp)copy();
ae.e1 = new IndexExp(loc, ea, ek);
ae.e1 = ae.e1.semantic(sc);
Expand Down
Expand Up
@@ -11975,11 +12031,13 @@ public:
ex = ex.semantic(sc);
ex = ex.optimize(WANTvalue);
ex = ex.modifiableLvalue(sc, ex); // allocate new slot
ey = new ConstructExp(loc, ex, ey);
ey = ey.semantic(sc);
if (ey.op == TOKerror)
return ey;
ex = e;
// Bugzilla 14144: The whole expression should have the common type
// of opAssign() return and assigned AA entry.
// Even if there's no common type, expression should be typed as void.
Expand All
@@ -12005,6 +12063,7 @@ public:
}
else
assert (op == TOKblit);
e1 = e1x;
e2 = e2x;
}
Expand Down
Expand Up
@@ -12142,16 +12201,21 @@ public:
return e1x;
e1 = e1x;
}
/* Tweak e2 based on the type of e1.
*/
Expression e2x = e2;
Type t2 = e2x.type.toBasetype();
// If it is a array, get the element type. Note that it may be
// multi-dimensional.
Type telem = t1;
while (telem.ty == Tarray)
telem = telem.nextOf();
if (e1.op == TOKslice && t1.nextOf() && (telem.ty != Tvoid || e2x.op == TOKnull) && e2x.implicitConvTo(t1.nextOf()))
if (e1.op == TOKslice && t1.nextOf() &&
(telem.ty != Tvoid || e2x.op == TOKnull) &&
e2x.implicitConvTo(t1.nextOf()))
{
// Check for block assignment. If it is of type void[], void[][], etc,
// '= null' is the only allowable block assignment (Bug 7493)
Expand All
@@ -12163,9 +12227,12 @@ public:
return new ErrorExp();
}
}
else if (e1.op == TOKslice && (t2.ty == Tarray || t2.ty == Tsarray) && t2.nextOf().implicitConvTo(t1.nextOf()))
else if (e1.op == TOKslice &&
(t2.ty == Tarray || t2.ty == Tsarray) &&
t2.nextOf().implicitConvTo(t1.nextOf()))
{
// Check element-wise assignment.
/* If assigned elements number is known at compile time,
* check the mismatch.
*/
Expand All
@@ -12188,21 +12255,36 @@ public:
return new ErrorExp();
}
}
if (op != TOKblit && (e2x.op == TOKslice && (cast (UnaExp)e2x).e1.isLvalue() || e2x.op == TOKcast && (cast (UnaExp)e2x).e1.isLvalue() || e2x.op != TOKslice && e2x.isLvalue()))
if (op != TOKblit &&
(e2x.op == TOKslice && (cast (UnaExp)e2x).e1.isLvalue() ||
e2x.op == TOKcast && (cast (UnaExp)e2x).e1.isLvalue() ||
e2x.op != TOKslice && e2x.isLvalue()))
{
if (e1.checkPostblit(sc, t1.nextOf()))
return new ErrorExp();
}
if (0 && global.params.warnings && ! global.gag && op == TOKassign && e2x.op != TOKslice && e2x.op != TOKassign && e2x.op != TOKarrayliteral && e2x.op != TOKstring && ! (e2x.op == TOKadd || e2x.op == TOKmin || e2x.op == TOKmul || e2x.op == TOKdiv || e2x.op == TOKmod || e2x.op == TOKxor || e2x.op == TOKand || e2x.op == TOKor || e2x.op == TOKpow || e2x.op == TOKtilde || e2x.op == TOKneg))
if (0 && global.params.warnings && ! global.gag && op == TOKassign &&
e2x.op != TOKslice && e2x.op != TOKassign &&
e2x.op != TOKarrayliteral && e2x.op != TOKstring &&
! (e2x.op == TOKadd || e2x.op == TOKmin ||
e2x.op == TOKmul || e2x.op == TOKdiv ||
e2x.op == TOKmod || e2x.op == TOKxor ||
e2x.op == TOKand || e2x.op == TOKor ||
e2x.op == TOKpow ||
e2x.op == TOKtilde || e2x.op == TOKneg))
{
const (char )* e1str = e1.toChars();
const (char )* e2str = e2x.toChars();
warning(" explicit element-wise assignment %s = (%s)[] is better than %s = %s" , e1str, e2str, e1str, e2str);
}
Type t2n = t2.nextOf();
Type t1n = t1.nextOf();
int offset;
if (t2n.equivalent(t1n) || t1n.isBaseOf(t2n, &offset) && offset == 0 )
if (t2n.equivalent(t1n) ||
t1n.isBaseOf(t2n, &offset) && offset == 0 )
{
/* Allow copy of distinct qualifier elements.
* eg.
Expand All
@@ -12227,7 +12309,10 @@ public:
}
else
{
if (0 && global.params.warnings && ! global.gag && op == TOKassign && t1.ty == Tarray && t2.ty == Tsarray && e2x.op != TOKslice && t2.implicitConvTo(t1))
if (0 && global.params.warnings && ! global.gag && op == TOKassign &&
t1.ty == Tarray && t2.ty == Tsarray &&
e2x.op != TOKslice &&
t2.implicitConvTo(t1))
{
// Disallow ar[] = sa (Converted to ar[] = sa[])
// Disallow da = sa (Converted to da = sa[])
Expand All
@@ -12245,33 +12330,41 @@ public:
return e2x;
e2 = e2x;
t2 = e2.type.toBasetype();
/* Look for array operations
*/
if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(e2))
{
// Look for valid array operations
if (! (ismemset & 1 ) && e1.op == TOKslice && (isUnaArrayOp(e2.op) || isBinArrayOp(e2.op)))
if (! (ismemset & 1 ) &&
e1.op == TOKslice &&
(isUnaArrayOp(e2.op) || isBinArrayOp(e2.op)))
{
type = e1.type;
if (op == TOKconstruct) // Bugzilla 10282: tweak mutability of e1 element
e1.type = e1.type.nextOf().mutableOf().arrayOf();
return arrayOp (this , sc);
}
// Drop invalid array operations in e2
// d = a[] + b[], d = (a[] + b[])[0..2], etc
if (checkNonAssignmentArrayOp(e2, ! (ismemset & 1 ) && op == TOKassign))
return new ErrorExp();
// Remains valid array assignments
// d = d[], d = [1,2,3], etc
}
if (e1.op == TOKvar && ((cast (VarExp)e1).var.storage_class & STCscope) && op == TOKassign)
if (e1.op == TOKvar &&
((cast (VarExp)e1).var.storage_class & STCscope) &&
op == TOKassign)
{
error(" cannot rebind scope variables" );
}
if (e1.op == TOKvar && (cast (VarExp)e1).var.ident == Id.ctfe)
{
error(" cannot modify compiler-generated variable __ctfe" );
}
type = e1.type;
assert (type);
return op == TOKassign ? reorderSettingAAElem(sc) : this ;
Expand Down