@@ -146,6 +146,11 @@ public:
146146
147147 enum asStatements = is (Result == Statement);
148148
149+ static if (asStatements)
150+ alias StatementsResult = Statements;
151+ else
152+ alias StatementsResult = Expression;
153+
149154 extern (D ) this (InlineDoState ids) scope
150155 {
151156 this .ids = ids;
@@ -175,100 +180,173 @@ public:
175180 result = exp;
176181 }
177182
178- override void visit (CompoundStatement s )
183+ static Result buildConditional (Loc loc, Expression econd, Result e1, Result e2, Loc endloc )
179184 {
180- // printf("CompoundStatement.doInlineAs!%s() %d\n", Result.stringof.ptr, s.statements.length);
181185 static if (asStatements)
182186 {
183- auto as = Statements();
184- as.reserve (s.statements.length);
187+ return new IfStatement(loc, null , econd, e1, e2, endloc);
185188 }
186-
187- foreach (i, sx; s.statements)
189+ else
188190 {
189- if (! sx)
190- continue ;
191- static if (asStatements)
192- {
193- as.push(doInlineAs! Statement(sx, ids));
194- }
195- else
191+ if (e1 && e2)
196192 {
197- /* Specifically allow:
198- * if (condition)
199- * return exp1;
200- * return exp2;
201- */
202- IfStatement ifs;
203- Statement s3;
204- if ((ifs = sx.isIfStatement()) ! is null &&
205- ifs.ifbody &&
206- ifs.ifbody.endsWithReturnStatement() &&
207- ! ifs.elsebody &&
208- i + 1 < s.statements.length &&
209- (s3 = s.statements[i + 1 ]) ! is null &&
210- s3.endsWithReturnStatement()
211- )
212- {
213- /* Rewrite as ?:
214- */
215- auto econd = doInlineAs! Expression(ifs.condition, ids);
216- assert (econd);
217- auto e1 = doInlineAs! Expression(ifs.ifbody, ids);
218- assert (ids.foundReturn);
219- auto e2 = doInlineAs! Expression(s3, ids);
220- assert (e2);
221- Expression e = new CondExp(econd.loc, econd, e1, e2);
222- e.type = e1.type;
223- if (e.type.ty == Ttuple)
224- {
225- e1.type = Type.tvoid;
226- e2.type = Type.tvoid;
227- e.type = Type.tvoid;
228- }
229- result = combineInlineSequence(result, e);
230- }
193+ auto ce = new CondExp(loc, econd, e1, e2);
194+
195+ if (e1.type.ty == Tvoid || e2.type.ty == Tvoid)
196+ ce.type = Type.tvoid;
197+ else if (e1.type.ty == Tnoreturn)
198+ ce.type = e2.type;
231199 else
200+ ce.type = e1.type;
201+
202+ if (ce.type.ty == Ttuple)
232203 {
233- ids.foundReturn = false ;
234- auto e = doInlineAs ! Expression(sx, ids) ;
235- result = combineInlineSequence(result, e) ;
204+ ce.e1.type = Type.tvoid ;
205+ ce.e2.type = Type.tvoid ;
206+ ce.type = Type.tvoid ;
236207 }
208+
209+ return ce;
210+ }
211+ else if (e1)
212+ {
213+ auto le = new LogicalExp(loc, EXP .andAnd, econd, e1);
214+ le.type = Type.tvoid;
215+ return le;
216+ }
217+ else if (e2)
218+ {
219+ auto le = new LogicalExp(loc, EXP .orOr, econd, e2);
220+ le.type = Type.tvoid;
221+ return le;
237222 }
238223
239- if (ids.foundReturn)
240- break ;
224+ return econd;
241225 }
242-
243- static if (asStatements)
244- result = new CompoundStatement(s.loc, as.move());
245226 }
246227
247- override void visit (UnrolledLoopStatement s )
228+ StatementsResult statementsDoInline ( ref scope Statements stmts )
248229 {
249- // printf("UnrolledLoopStatement.doInlineAs!%s() %d\n", Result.stringof.ptr, s.statements.length);
250230 static if (asStatements)
251231 {
252- auto as = Statements();
253- as.reserve (s.statements.length);
232+ Statements result;
233+ result.reserve (stmts.length);
234+ }
235+ else
236+ {
237+ Expression result;
254238 }
255239
256- foreach (sx; s.statements )
240+ foreach (i, sx; stmts )
257241 {
258242 if (! sx)
259243 continue ;
260- auto r = doInlineAs! Result(sx, ids);
244+
245+ Result r;
246+
247+ if (auto ifs = sx.isIfStatement())
248+ {
249+ assert (! ifs.param);
250+ auto econd = doInlineAs! Expression(ifs.condition, ids);
251+ assert (econd);
252+
253+ ids.foundReturn = false ;
254+ auto ifbody = doInlineAs! Result(ifs.ifbody, ids);
255+ bool ifReturned = ids.foundReturn;
256+
257+ ids.foundReturn = false ;
258+ auto elsebody = doInlineAs! Result(ifs.elsebody, ids);
259+ bool elseReturned = ids.foundReturn;
260+
261+ ids.foundReturn = ifReturned && elseReturned;
262+
263+ if (ifReturned != elseReturned)
264+ {
265+ /* One branch returns, but the other does not.
266+ * Merge the remaining statements in stmts into
267+ * the branch that does not return, and recurse.
268+ */
269+
270+ if (elseReturned)
271+ {
272+ /* Rewrite
273+ * if (cond) stmt; else return exp;
274+ * into
275+ * if (!cond) return exp; else stmt;
276+ */
277+ econd = new NotExp(econd.loc, econd);
278+ econd.type = Type.tbool;
279+
280+ auto tmp = ifbody;
281+ ifbody = elsebody;
282+ elsebody = tmp;
283+ }
284+
285+ if (i < stmts.length - 1 )
286+ {
287+ ids.foundReturn = false ;
288+ scope rem = Statements(stmts[i + 1 .. $]);
289+ auto rembody = statementsDoInline(rem);
290+
291+ static if (asStatements)
292+ {
293+ /* Rewrite
294+ * if (cond) return exp; else stmt1; stmt2;
295+ * into
296+ * if (cond) return exp; else { { stmt1; } stmt2; }
297+ */
298+ auto ss = new ScopeStatement(ifs.loc, elsebody, ifs.endloc);
299+ auto cs = new CompoundStatement(ifs.loc, ss);
300+ cs.statements.append(&rembody);
301+ elsebody = cs;
302+ }
303+ else
304+ {
305+ elsebody = combineInlineSequence(elsebody, rembody);
306+ }
307+ }
308+
309+ ids.foundReturn = true ;
310+ }
311+
312+ r = buildConditional(ifs.loc, econd, ifbody, elsebody, ifs.endloc);
313+ }
314+ else
315+ {
316+ ids.foundReturn = false ;
317+ r = doInlineAs! Result(sx, ids);
318+ }
319+
261320 static if (asStatements)
262- as .push(r);
321+ result .push(r);
263322 else
264323 result = combineInlineSequence(result, r);
265324
266325 if (ids.foundReturn)
267326 break ;
268327 }
269328
329+ return result;
330+ }
331+
332+ override void visit (CompoundStatement s)
333+ {
334+ // printf("CompoundStatement.doInlineAs!%s() %d\n", Result.stringof.ptr, s.statements.length);
335+ auto r = statementsDoInline(s.statements);
270336 static if (asStatements)
271- result = new UnrolledLoopStatement(s.loc, as.move());
337+ result = new CompoundStatement(s.loc, r.move());
338+ else
339+ result = r;
340+ }
341+
342+ override void visit (UnrolledLoopStatement s)
343+ {
344+ // printf("UnrolledLoopStatement.doInlineAs!%s() %d\n", Result.stringof.ptr, s.statements.length);
345+ auto r = statementsDoInline(s.statements);
346+ static if (asStatements)
347+ result = new UnrolledLoopStatement(s.loc, r.move());
348+ else
349+ result = r;
272350 }
273351
274352 override void visit (ScopeStatement s)
@@ -287,47 +365,19 @@ public:
287365 auto econd = doInlineAs! Expression(s.condition, ids);
288366 assert (econd);
289367
368+ ids.foundReturn = false ;
290369 auto ifbody = doInlineAs! Result(s.ifbody, ids);
291- bool bodyReturn = ids.foundReturn;
370+ bool ifReturned = ids.foundReturn;
292371
293372 ids.foundReturn = false ;
294373 auto elsebody = doInlineAs! Result(s.elsebody, ids);
374+ bool elseReturned = ids.foundReturn;
295375
296- static if (asStatements)
297- {
298- result = new IfStatement(s.loc, s.param, econd, ifbody, elsebody, s.endloc);
299- }
300- else
301- {
302- alias e1 = ifbody;
303- alias e2 = elsebody;
304- if (e1 && e2)
305- {
306- result = new CondExp(econd.loc, econd, e1, e2);
307- result.type = e1.type;
308- if (result.type.ty == Ttuple)
309- {
310- e1.type = Type.tvoid;
311- e2.type = Type.tvoid;
312- result.type = Type.tvoid;
313- }
314- }
315- else if (e1)
316- {
317- result = new LogicalExp(econd.loc, EXP .andAnd, econd, e1);
318- result.type = Type.tvoid;
319- }
320- else if (e2)
321- {
322- result = new LogicalExp(econd.loc, EXP .orOr, econd, e2);
323- result.type = Type.tvoid;
324- }
325- else
326- {
327- result = econd;
328- }
329- }
330- ids.foundReturn = ids.foundReturn && bodyReturn;
376+ // Top-level if statements should have been handled in statementsDoInline().
377+ // Here we're handling nested if statements, which must be symmetrical.
378+ assert (ifReturned == elseReturned);
379+ ids.foundReturn = ifReturned && elseReturned;
380+ result = buildConditional(s.loc, econd, ifbody, elsebody, s.endloc);
331381 }
332382
333383 override void visit (ReturnStatement s)
0 commit comments