opover.d: remove goto, reduce indentation (#20748)

This commit is contained in:
Dennis 2025-01-21 13:24:16 +01:00 committed by GitHub
parent f05ccbd0e7
commit ff2543f768
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -517,6 +517,61 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return result; return result;
} }
// When no operator overload functions are found for `e`, recursively try with `alias this`
// Returns: `null` when still no overload found, otherwise resolved lowering
Expression binAliasThis(BinExp e, AggregateDeclaration ad1, AggregateDeclaration ad2)
{
Expression rewrittenLhs;
if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
if (Expression result = checkAliasThisForLhs(ad1, sc, e))
{
/* https://issues.dlang.org/show_bug.cgi?id=19441
*
* alias this may not be used for partial assignment.
* If a struct has a single member which is aliased this
* directly or aliased to a ref getter function that returns
* the mentioned member, then alias this may be
* used since the object will be fully initialised.
* If the struct is nested, the context pointer is considered
* one of the members, hence the `ad1.fields.length == 2 && ad1.vthis`
* condition.
*/
if (result.op != EXP.assign)
return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)`
auto ae = result.isAssignExp();
if (ae.e1.op != EXP.dotVariable)
return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2`
auto dve = ae.e1.isDotVarExp();
if (auto ad = dve.var.isMember2())
{
// i.e: Rewrote `e1 = e2` -> `e1.some.var = e2`
// Ensure that `var` is the only field member in `ad`
if (ad.fields.length == 1 || (ad.fields.length == 2 && ad.vthis))
{
if (dve.var == ad.aliasthis.sym)
return result;
}
}
rewrittenLhs = ae.e1;
}
}
if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
if (Expression result = checkAliasThisForRhs(ad2, sc, e))
return result;
}
if (rewrittenLhs)
{
error(e.loc, "cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`",
e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars());
return ErrorExp.get();
}
return null;
}
Expression visitBin(BinExp e) Expression visitBin(BinExp e)
{ {
//printf("BinExp::op_overload() (%s)\n", e.toChars()); //printf("BinExp::op_overload() (%s)\n", e.toChars());
@ -602,13 +657,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
} }
Expressions* args1 = new Expressions(); Expressions* args1 = new Expressions();
Expressions* args2 = new Expressions(); Expressions* args2 = new Expressions();
if (s || s_r) if (!s && !s_r)
{ return binAliasThis(e, ad1, ad2);
/* Try:
* a.opfunc(b) // Try opBinary and opBinaryRight and see which is better.
* b.opfunc_r(a)
* and see which is better.
*/
args1.setDim(1); args1.setDim(1);
(*args1)[0] = e.e1; (*args1)[0] = e.e1;
expandTuples(args1); expandTuples(args1);
@ -642,7 +694,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
else if (m.last == MATCH.nomatch) else if (m.last == MATCH.nomatch)
{ {
if (tiargs) if (tiargs)
goto L1; return binAliasThis(e, ad1, ad2);
m.lastf = null; m.lastf = null;
} }
if (e.op == EXP.plusPlus || e.op == EXP.minusMinus) if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
@ -664,58 +716,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r); return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
} }
} }
L1:
Expression rewrittenLhs;
if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
if (Expression result = checkAliasThisForLhs(ad1, sc, e))
{
/* https://issues.dlang.org/show_bug.cgi?id=19441
*
* alias this may not be used for partial assignment.
* If a struct has a single member which is aliased this
* directly or aliased to a ref getter function that returns
* the mentioned member, then alias this may be
* used since the object will be fully initialised.
* If the struct is nested, the context pointer is considered
* one of the members, hence the `ad1.fields.length == 2 && ad1.vthis`
* condition.
*/
if (result.op != EXP.assign)
return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)`
auto ae = result.isAssignExp();
if (ae.e1.op != EXP.dotVariable)
return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2`
auto dve = ae.e1.isDotVarExp();
if (auto ad = dve.var.isMember2())
{
// i.e: Rewrote `e1 = e2` -> `e1.some.var = e2`
// Ensure that `var` is the only field member in `ad`
if (ad.fields.length == 1 || (ad.fields.length == 2 && ad.vthis))
{
if (dve.var == ad.aliasthis.sym)
return result;
}
}
rewrittenLhs = ae.e1;
}
}
if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
if (Expression result = checkAliasThisForRhs(ad2, sc, e))
return result;
}
if (rewrittenLhs)
{
error(e.loc, "cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`",
e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars());
return ErrorExp.get();
}
return null;
}
Expression visitEqual(EqualExp e) Expression visitEqual(EqualExp e)
{ {