mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 20:50:41 +03:00
Moved Staticforeach.lowerNonArrayAggregate and Staticforeach.prepare to expressionsem (#20944)
This commit is contained in:
parent
5cd254f9e0
commit
58d3b59dc5
4 changed files with 205 additions and 200 deletions
|
@ -24,7 +24,7 @@ import dmd.dscope;
|
|||
import dmd.dsymbol;
|
||||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem : expressionSemantic, evalStaticCondition, resolveProperties;
|
||||
import dmd.expressionsem : expressionSemantic, evalStaticCondition;
|
||||
import dmd.globals;
|
||||
import dmd.identifier;
|
||||
import dmd.location;
|
||||
|
@ -151,7 +151,7 @@ extern (C++) final class StaticForeach : RootObject
|
|||
* to
|
||||
* static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
|
||||
*/
|
||||
private extern(D) void lowerArrayAggregate(Scope* sc)
|
||||
extern(D) void lowerArrayAggregate(Scope* sc)
|
||||
{
|
||||
auto aggr = aggrfe.aggr;
|
||||
Expression el = new ArrayLengthExp(aggr.loc, aggr);
|
||||
|
@ -198,7 +198,7 @@ extern (C++) final class StaticForeach : RootObject
|
|||
* Returns:
|
||||
* AST of the expression `(){ s; }()` with location loc.
|
||||
*/
|
||||
private extern(D) Expression wrapAndCall(Loc loc, Statement s)
|
||||
extern(D) Expression wrapAndCall(Loc loc, Statement s)
|
||||
{
|
||||
auto tf = new TypeFunction(ParameterList(), null, LINK.default_, STC.none);
|
||||
auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null);
|
||||
|
@ -221,7 +221,7 @@ extern (C++) final class StaticForeach : RootObject
|
|||
* `foreach (parameters; lower .. upper) s;`
|
||||
* Where aggregate/lower, upper are as for the current StaticForeach.
|
||||
*/
|
||||
private extern(D) Statement createForeach(Loc loc, Parameters* parameters, Statement s)
|
||||
extern(D) Statement createForeach(Loc loc, Parameters* parameters, Statement s)
|
||||
{
|
||||
if (aggrfe)
|
||||
{
|
||||
|
@ -254,7 +254,7 @@ extern (C++) final class StaticForeach : RootObject
|
|||
* }
|
||||
*/
|
||||
|
||||
private extern(D) TypeStruct createTupleType(Loc loc, Expressions* e, Scope* sc)
|
||||
extern(D) TypeStruct createTupleType(Loc loc, Expressions* e, Scope* sc)
|
||||
{ // TODO: move to druntime?
|
||||
auto sid = Identifier.generateId("Tuple");
|
||||
auto sdecl = new StructDeclaration(loc, sid, false);
|
||||
|
@ -280,205 +280,11 @@ extern (C++) final class StaticForeach : RootObject
|
|||
* An AST for the expression `Tuple(e)`.
|
||||
*/
|
||||
|
||||
private extern(D) Expression createTuple(Loc loc, TypeStruct type, Expressions* e) @safe
|
||||
extern(D) Expression createTuple(Loc loc, TypeStruct type, Expressions* e) @safe
|
||||
{ // TODO: move to druntime?
|
||||
return new CallExp(loc, new TypeExp(loc, type), e);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Lower any aggregate that is not an array to an array using a
|
||||
* regular foreach loop within CTFE. If there are multiple
|
||||
* `static foreach` loop variables, an array of tuples is
|
||||
* generated. In thise case, the field `needExpansion` is set to
|
||||
* true to indicate that the static foreach loop expansion will
|
||||
* need to expand the tuples into multiple variables.
|
||||
*
|
||||
* For example, `static foreach (x; range) { ... }` is lowered to:
|
||||
*
|
||||
* static foreach (x; {
|
||||
* typeof({
|
||||
* foreach (x; range) return x;
|
||||
* }())[] __res;
|
||||
* foreach (x; range) __res ~= x;
|
||||
* return __res;
|
||||
* }()) { ... }
|
||||
*
|
||||
* Finally, call `lowerArrayAggregate` to turn the produced
|
||||
* array into an expression tuple.
|
||||
*
|
||||
* Params:
|
||||
* sc = The current scope.
|
||||
*/
|
||||
|
||||
private void lowerNonArrayAggregate(Scope* sc)
|
||||
{
|
||||
auto nvars = aggrfe ? aggrfe.parameters.length : 1;
|
||||
auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc;
|
||||
// We need three sets of foreach loop variables because the
|
||||
// lowering contains three foreach loops.
|
||||
Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
|
||||
foreach (i; 0 .. nvars)
|
||||
{
|
||||
foreach (params; pparams)
|
||||
{
|
||||
auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.param;
|
||||
params.push(new Parameter(aloc, p.storageClass, p.type, p.ident, null, null));
|
||||
}
|
||||
}
|
||||
Expression[2] res;
|
||||
TypeStruct tplty = null;
|
||||
if (nvars == 1) // only one `static foreach` variable, generate identifiers.
|
||||
{
|
||||
foreach (i; 0 .. 2)
|
||||
{
|
||||
res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident);
|
||||
}
|
||||
}
|
||||
else // multiple `static foreach` variables, generate tuples.
|
||||
{
|
||||
foreach (i; 0 .. 2)
|
||||
{
|
||||
auto e = new Expressions(pparams[0].length);
|
||||
foreach (j, ref elem; *e)
|
||||
{
|
||||
auto p = (*pparams[i])[j];
|
||||
elem = new IdentifierExp(aloc, p.ident);
|
||||
}
|
||||
if (!tplty)
|
||||
{
|
||||
tplty = createTupleType(aloc, e, sc);
|
||||
}
|
||||
res[i] = createTuple(aloc, tplty, e);
|
||||
}
|
||||
needExpansion = true; // need to expand the tuples later
|
||||
}
|
||||
// generate remaining code for the new aggregate which is an
|
||||
// array (see documentation comment).
|
||||
if (rangefe)
|
||||
{
|
||||
sc = sc.startCTFE();
|
||||
rangefe.lwr = rangefe.lwr.expressionSemantic(sc);
|
||||
rangefe.lwr = resolveProperties(sc, rangefe.lwr);
|
||||
rangefe.upr = rangefe.upr.expressionSemantic(sc);
|
||||
rangefe.upr = resolveProperties(sc, rangefe.upr);
|
||||
sc = sc.endCTFE();
|
||||
rangefe.lwr = rangefe.lwr.optimize(WANTvalue);
|
||||
rangefe.lwr = rangefe.lwr.ctfeInterpret();
|
||||
rangefe.upr = rangefe.upr.optimize(WANTvalue);
|
||||
rangefe.upr = rangefe.upr.ctfeInterpret();
|
||||
}
|
||||
auto s1 = new Statements();
|
||||
auto sfe = new Statements();
|
||||
if (tplty) sfe.push(new ExpStatement(loc, tplty.sym));
|
||||
sfe.push(new ReturnStatement(aloc, res[0]));
|
||||
s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe)));
|
||||
s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
|
||||
Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
|
||||
auto aty = ety.arrayOf();
|
||||
auto idres = Identifier.generateId("__res");
|
||||
auto vard = new VarDeclaration(aloc, aty, idres, null, STC.temp);
|
||||
auto s2 = new Statements();
|
||||
|
||||
// Run 'typeof' gagged to avoid duplicate errors and if it fails just create
|
||||
// an empty foreach to expose them.
|
||||
const olderrors = global.startGagging();
|
||||
ety = ety.typeSemantic(aloc, sc);
|
||||
if (global.endGagging(olderrors))
|
||||
s2.push(createForeach(aloc, pparams[1], null));
|
||||
else
|
||||
{
|
||||
s2.push(new ExpStatement(aloc, vard));
|
||||
auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
|
||||
s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
|
||||
s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
|
||||
}
|
||||
|
||||
Expression aggr = void;
|
||||
Type indexty = void;
|
||||
|
||||
if (rangefe && (indexty = ety).isIntegral())
|
||||
{
|
||||
rangefe.lwr.type = indexty;
|
||||
rangefe.upr.type = indexty;
|
||||
auto lwrRange = getIntRange(rangefe.lwr);
|
||||
auto uprRange = getIntRange(rangefe.upr);
|
||||
|
||||
const lwr = rangefe.lwr.toInteger();
|
||||
auto upr = rangefe.upr.toInteger();
|
||||
size_t length = 0;
|
||||
|
||||
if (lwrRange.imin <= uprRange.imax)
|
||||
length = cast(size_t) (upr - lwr);
|
||||
|
||||
auto exps = new Expressions(length);
|
||||
|
||||
if (rangefe.op == TOK.foreach_)
|
||||
{
|
||||
foreach (i; 0 .. length)
|
||||
(*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
|
||||
}
|
||||
else
|
||||
{
|
||||
--upr;
|
||||
foreach (i; 0 .. length)
|
||||
(*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
|
||||
}
|
||||
aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps);
|
||||
}
|
||||
else
|
||||
{
|
||||
aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
|
||||
sc = sc.startCTFE();
|
||||
aggr = aggr.expressionSemantic(sc);
|
||||
aggr = resolveProperties(sc, aggr);
|
||||
sc = sc.endCTFE();
|
||||
aggr = aggr.optimize(WANTvalue);
|
||||
aggr = aggr.ctfeInterpret();
|
||||
}
|
||||
|
||||
assert(!!aggrfe ^ !!rangefe);
|
||||
aggrfe = new ForeachStatement(loc, TOK.foreach_, pparams[2], aggr,
|
||||
aggrfe ? aggrfe._body : rangefe._body,
|
||||
aggrfe ? aggrfe.endloc : rangefe.endloc);
|
||||
rangefe = null;
|
||||
lowerArrayAggregate(sc); // finally, turn generated array into expression tuple
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Perform `static foreach` lowerings that are necessary in order
|
||||
* to finally expand the `static foreach` using
|
||||
* `dmd.statementsem.makeTupleForeach`.
|
||||
*/
|
||||
extern(D) void prepare(Scope* sc)
|
||||
{
|
||||
assert(sc);
|
||||
|
||||
if (aggrfe)
|
||||
{
|
||||
sc = sc.startCTFE();
|
||||
aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
|
||||
sc = sc.endCTFE();
|
||||
}
|
||||
|
||||
if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ready())
|
||||
{
|
||||
if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray)
|
||||
{
|
||||
lowerArrayAggregate(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
lowerNonArrayAggregate(sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Returns:
|
||||
* `true` iff ready to call `dmd.statementsem.makeTupleForeach`.
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace dmd
|
|||
{
|
||||
// in expressionsem.d
|
||||
Expression *expressionSemantic(Expression *e, Scope *sc);
|
||||
void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc);
|
||||
// in typesem.d
|
||||
Expression *defaultInit(Type *mt, Loc loc, const bool isCfile = false);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import dmd.astcodegen;
|
|||
import dmd.astenums;
|
||||
import dmd.canthrow;
|
||||
import dmd.chkformat;
|
||||
import dmd.cond;
|
||||
import dmd.ctorflow;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
|
@ -17406,3 +17407,198 @@ bool fill(StructDeclaration sd, Loc loc, ref Expressions elements, bool ctorinit
|
|||
|
||||
return !errors;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Lower any aggregate that is not an array to an array using a
|
||||
* regular foreach loop within CTFE. If there are multiple
|
||||
* `static foreach` loop variables, an array of tuples is
|
||||
* generated. In thise case, the field `needExpansion` is set to
|
||||
* true to indicate that the static foreach loop expansion will
|
||||
* need to expand the tuples into multiple variables.
|
||||
*
|
||||
* For example, `static foreach (x; range) { ... }` is lowered to:
|
||||
*
|
||||
* static foreach (x; {
|
||||
* typeof({
|
||||
* foreach (x; range) return x;
|
||||
* }())[] __res;
|
||||
* foreach (x; range) __res ~= x;
|
||||
* return __res;
|
||||
* }()) { ... }
|
||||
*
|
||||
* Finally, call `lowerArrayAggregate` to turn the produced
|
||||
* array into an expression tuple.
|
||||
*
|
||||
* Params:
|
||||
* sfe = The 'static foreach'.
|
||||
* sc = The current scope.
|
||||
*/
|
||||
extern (C++) void lowerNonArrayAggregate(StaticForeach sfe, Scope* sc)
|
||||
{
|
||||
import dmd.statement;
|
||||
|
||||
auto nvars = sfe.aggrfe ? sfe.aggrfe.parameters.length : 1;
|
||||
auto aloc = sfe.aggrfe ? sfe.aggrfe.aggr.loc : sfe.rangefe.lwr.loc;
|
||||
// We need three sets of foreach loop variables because the
|
||||
// lowering contains three foreach loops.
|
||||
Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
|
||||
foreach (i; 0 .. nvars)
|
||||
{
|
||||
foreach (params; pparams)
|
||||
{
|
||||
auto p = sfe.aggrfe ? (*sfe.aggrfe.parameters)[i] : sfe.rangefe.param;
|
||||
params.push(new Parameter(aloc, p.storageClass, p.type, p.ident, null, null));
|
||||
}
|
||||
}
|
||||
Expression[2] res;
|
||||
TypeStruct tplty = null;
|
||||
if (nvars == 1) // only one `static foreach` variable, generate identifiers.
|
||||
{
|
||||
foreach (i; 0 .. 2)
|
||||
{
|
||||
res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident);
|
||||
}
|
||||
}
|
||||
else // multiple `static foreach` variables, generate tuples.
|
||||
{
|
||||
foreach (i; 0 .. 2)
|
||||
{
|
||||
auto e = new Expressions(pparams[0].length);
|
||||
foreach (j, ref elem; *e)
|
||||
{
|
||||
auto p = (*pparams[i])[j];
|
||||
elem = new IdentifierExp(aloc, p.ident);
|
||||
}
|
||||
if (!tplty)
|
||||
{
|
||||
tplty = sfe.createTupleType(aloc, e, sc);
|
||||
}
|
||||
res[i] = sfe.createTuple(aloc, tplty, e);
|
||||
}
|
||||
sfe.needExpansion = true; // need to expand the tuples later
|
||||
}
|
||||
// generate remaining code for the new aggregate which is an
|
||||
// array (see documentation comment).
|
||||
if (sfe.rangefe)
|
||||
{
|
||||
sc = sc.startCTFE();
|
||||
sfe.rangefe.lwr = sfe.rangefe.lwr.expressionSemantic(sc);
|
||||
sfe.rangefe.lwr = resolveProperties(sc, sfe.rangefe.lwr);
|
||||
sfe.rangefe.upr = sfe.rangefe.upr.expressionSemantic(sc);
|
||||
sfe.rangefe.upr = resolveProperties(sc, sfe.rangefe.upr);
|
||||
sc = sc.endCTFE();
|
||||
sfe.rangefe.lwr = sfe.rangefe.lwr.optimize(WANTvalue);
|
||||
sfe.rangefe.lwr = sfe.rangefe.lwr.ctfeInterpret();
|
||||
sfe.rangefe.upr = sfe.rangefe.upr.optimize(WANTvalue);
|
||||
sfe.rangefe.upr = sfe.rangefe.upr.ctfeInterpret();
|
||||
}
|
||||
auto s1 = new Statements();
|
||||
auto stmts = new Statements();
|
||||
if (tplty) stmts.push(new ExpStatement(sfe.loc, tplty.sym));
|
||||
stmts.push(new ReturnStatement(aloc, res[0]));
|
||||
s1.push(sfe.createForeach(aloc, pparams[0], new CompoundStatement(aloc, stmts)));
|
||||
s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
|
||||
Type ety = new TypeTypeof(aloc, sfe.wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
|
||||
auto aty = ety.arrayOf();
|
||||
auto idres = Identifier.generateId("__res");
|
||||
auto vard = new VarDeclaration(aloc, aty, idres, null, STC.temp);
|
||||
auto s2 = new Statements();
|
||||
|
||||
// Run 'typeof' gagged to avoid duplicate errors and if it fails just create
|
||||
// an empty foreach to expose them.
|
||||
const olderrors = global.startGagging();
|
||||
ety = ety.typeSemantic(aloc, sc);
|
||||
if (global.endGagging(olderrors))
|
||||
s2.push(sfe.createForeach(aloc, pparams[1], null));
|
||||
else
|
||||
{
|
||||
s2.push(new ExpStatement(aloc, vard));
|
||||
auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
|
||||
s2.push(sfe.createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
|
||||
s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
|
||||
}
|
||||
|
||||
Expression aggr = void;
|
||||
Type indexty = void;
|
||||
|
||||
if (sfe.rangefe && (indexty = ety).isIntegral())
|
||||
{
|
||||
sfe.rangefe.lwr.type = indexty;
|
||||
sfe.rangefe.upr.type = indexty;
|
||||
auto lwrRange = getIntRange(sfe.rangefe.lwr);
|
||||
auto uprRange = getIntRange(sfe.rangefe.upr);
|
||||
|
||||
const lwr = sfe.rangefe.lwr.toInteger();
|
||||
auto upr = sfe.rangefe.upr.toInteger();
|
||||
size_t length = 0;
|
||||
|
||||
if (lwrRange.imin <= uprRange.imax)
|
||||
length = cast(size_t) (upr - lwr);
|
||||
|
||||
auto exps = new Expressions(length);
|
||||
|
||||
if (sfe.rangefe.op == TOK.foreach_)
|
||||
{
|
||||
foreach (i; 0 .. length)
|
||||
(*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
|
||||
}
|
||||
else
|
||||
{
|
||||
--upr;
|
||||
foreach (i; 0 .. length)
|
||||
(*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
|
||||
}
|
||||
aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps);
|
||||
}
|
||||
else
|
||||
{
|
||||
aggr = sfe.wrapAndCall(aloc, new CompoundStatement(aloc, s2));
|
||||
sc = sc.startCTFE();
|
||||
aggr = aggr.expressionSemantic(sc);
|
||||
aggr = resolveProperties(sc, aggr);
|
||||
sc = sc.endCTFE();
|
||||
aggr = aggr.optimize(WANTvalue);
|
||||
aggr = aggr.ctfeInterpret();
|
||||
}
|
||||
|
||||
assert(!!sfe.aggrfe ^ !!sfe.rangefe);
|
||||
sfe.aggrfe = new ForeachStatement(sfe.loc, TOK.foreach_, pparams[2], aggr,
|
||||
sfe.aggrfe ? sfe.aggrfe._body : sfe.rangefe._body,
|
||||
sfe.aggrfe ? sfe.aggrfe.endloc : sfe.rangefe.endloc);
|
||||
sfe.rangefe = null;
|
||||
sfe.lowerArrayAggregate(sc); // finally, turn generated array into expression tuple
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* Perform `static foreach` lowerings that are necessary in order
|
||||
* to finally expand the `static foreach` using
|
||||
* `dmd.statementsem.makeTupleForeach`.
|
||||
*/
|
||||
extern(D) void prepare(StaticForeach sfe, Scope* sc)
|
||||
{
|
||||
assert(sc);
|
||||
|
||||
if (sfe.aggrfe)
|
||||
{
|
||||
sc = sc.startCTFE();
|
||||
sfe.aggrfe.aggr = sfe.aggrfe.aggr.expressionSemantic(sc);
|
||||
sc = sc.endCTFE();
|
||||
}
|
||||
|
||||
if (sfe.aggrfe && sfe.aggrfe.aggr.type.toBasetype().ty == Terror)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sfe.ready())
|
||||
{
|
||||
if (sfe.aggrfe && sfe.aggrfe.aggr.type.toBasetype().ty == Tarray)
|
||||
{
|
||||
sfe.lowerArrayAggregate(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
sfe.lowerNonArrayAggregate(sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7550,6 +7550,8 @@ public:
|
|||
void visit(StaticForeachDeclaration* sfd) override;
|
||||
};
|
||||
|
||||
extern void lowerNonArrayAggregate(StaticForeach* sfe, Scope* sc);
|
||||
|
||||
class NrvoWalker final : public StatementRewriteWalker
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue