Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move prepare, lowerNonArrayAggregate and lowerArrayAggregate methods to statementsem #17011

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dmd/attrib.d
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import dmd.mtype;
import dmd.objc; // for objc.addSymbols
import dmd.common.outbuffer;
import dmd.root.array; // for each
import dmd.statementsem : prepare;
import dmd.visitor;

/***********************************************************
Expand Down
249 changes: 5 additions & 244 deletions compiler/src/dmd/cond.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import dmd.dscope;
import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem : expressionSemantic, evalStaticCondition, resolveProperties;
import dmd.globals;
import dmd.identifier;
import dmd.location;
Expand Down Expand Up @@ -144,51 +143,6 @@ extern (C++) final class StaticForeach : RootObject
);
}

/*****************************************
* Turn an aggregate which is an array into an expression tuple
* of its elements. I.e., lower
* static foreach (x; [1, 2, 3, 4]) { ... }
* to
* static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
*/
private extern(D) void lowerArrayAggregate(Scope* sc)
{
auto aggr = aggrfe.aggr;
Expression el = new ArrayLengthExp(aggr.loc, aggr);
sc = sc.startCTFE();
el = el.expressionSemantic(sc);
sc = sc.endCTFE();
el = el.optimize(WANTvalue);
el = el.ctfeInterpret();
if (el.op != EXP.int64)
{
aggrfe.aggr = ErrorExp.get();
return;
}

Expressions *es;
if (auto ale = aggr.isArrayLiteralExp())
{
// Directly use the elements of the array for the TupleExp creation
es = ale.elements;
}
else
{
const length = cast(size_t)el.toInteger();
es = new Expressions(length);
foreach (i; 0 .. length)
{
auto index = new IntegerExp(loc, i, Type.tsize_t);
auto value = new IndexExp(aggr.loc, aggr, index);
(*es)[i] = value;
}
}
aggrfe.aggr = new TupleExp(aggr.loc, es);
aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
}

/*****************************************
* Wrap a statement into a function literal and call it.
*
Expand All @@ -198,7 +152,7 @@ extern (C++) final class StaticForeach : RootObject
* Returns:
* AST of the expression `(){ s; }()` with location loc.
*/
private extern(D) Expression wrapAndCall(const ref Loc loc, Statement s)
extern(D) Expression wrapAndCall(const ref Loc loc, Statement s)
{
auto tf = new TypeFunction(ParameterList(), null, LINK.default_, 0);
auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null);
Expand All @@ -221,7 +175,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(const ref Loc loc, Parameters* parameters, Statement s)
extern(D) Statement createForeach(const ref Loc loc, Parameters* parameters, Statement s)
{
if (aggrfe)
{
Expand Down Expand Up @@ -254,7 +208,7 @@ extern (C++) final class StaticForeach : RootObject
* }
*/

private extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc)
extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc)
{ // TODO: move to druntime?
auto sid = Identifier.generateId("Tuple");
auto sdecl = new StructDeclaration(loc, sid, false);
Expand All @@ -280,205 +234,11 @@ extern (C++) final class StaticForeach : RootObject
* An AST for the expression `Tuple(e)`.
*/

private extern(D) Expression createTuple(const ref Loc loc, TypeStruct type, Expressions* e) @safe
extern(D) Expression createTuple(const ref 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.prm;
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`.
Expand Down Expand Up @@ -944,6 +704,7 @@ extern (C++) final class StaticIfCondition : Condition
import dmd.staticcond;
bool errors;

import dmd.expressionsem;
bool result = evalStaticCondition(sc, exp, exp, errors);

// Prevent repeated condition evaluation.
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import dmd.staticassert;
import dmd.tokens;
import dmd.utils;
import dmd.statement;
import dmd.statementsem : prepare;
import dmd.target;
import dmd.templateparamsem;
import dmd.templatesem;
Expand Down
Loading
Loading