Improve error messages for missing opCmp / opEquals (#20806)

This commit is contained in:
Dennis 2025-01-30 23:31:36 +01:00 committed by GitHub
parent 193b71e546
commit 0ecefd78ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 45 additions and 20 deletions

View file

@ -12,6 +12,7 @@
module dmd.errors;
public import core.stdc.stdarg;
public import dmd.root.string: fTuple;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;

View file

@ -13065,12 +13065,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
arrayLowering = al;
}
}
else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
else if (t1.isTypeClass() && t2.isTypeClass())
{
if (t2.ty == Tstruct)
error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
else
error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
return setError();
}
else if (t1.isComplex() || t2.isComplex())

View file

@ -1127,7 +1127,31 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, ref EXP
if (e.isEqualExp() && ad1 == ad2)
return null;
Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop);
return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop);
if (result)
return result;
result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop);
if (result)
return result;
if (s || s_r)
return null;
Expression suggestOverloading(Expression other, AggregateDeclaration ad)
{
error(e.loc, "no operator `%s` for type `%s`", EXPtoString(e.op).ptr, ad.toChars);
string op = e.isEqualExp() ? "bool" : "int";
errorSupplemental(ad.loc, "perhaps overload it with `%.*s %s(%s other) const {}`", op.fTuple.expand, id.toChars, other.type.toChars);
return ErrorExp.get();
}
// Classes have opCmp and opEquals defined in `Object` to fall back on already
if (ad1 && ad1.isStructDeclaration)
return suggestOverloading(e.e2, ad1);
if (ad2 && ad2.isStructDeclaration)
return suggestOverloading(e.e1, ad2);
return null;
}
/***********************************