Improve opIndex/opSlice error messages (#20791)

This commit is contained in:
Dennis 2025-01-28 11:44:46 +01:00 committed by GitHub
parent cfd2dde588
commit a55dff5f28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 95 additions and 29 deletions

View file

@ -30,12 +30,26 @@ Error: `app.bar` called with argument types `(string)` matches multiple overload
*/
---
When there's no operator overload found for a type, a new supplemental message points to the declaration.
When there's no index / slice operator overload found for a type, a new supplemental message suggests where to implement it.
---
struct S {}
void main()
{
S s;
const x = s[3 .. "4"];
}
/*
app.d(8): Error: no `[]` operator overload for type `U`
app.d(6): `app.U` declared here
Before:
app.d(6): Error: no `[]` operator overload for type `S`
After:
app.d(6): Error: no `[3.."4"]` operator overload for type `S`
app.d(1): perhaps define `auto opSlice(int lower, string upper) {}` for `app.S`
*/
---

View file

@ -9706,8 +9706,39 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (auto ad = isAggregate(exp.e1.type))
{
error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
errorSupplemental(ad.loc, "`%s` declared here", ad.toPrettyChars());
if (exp.arguments.length == 0)
{
error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
errorSupplemental(ad.loc, "perhaps define `auto opIndex() {}` for `%s`", ad.toPrettyChars());
}
else
{
const(char)* typeString(Expression exp)
{
if (auto e = exp.trySemantic(sc))
return e.type.toChars();
else
return "__error__";
}
if (auto ie = (*exp.arguments)[0].isIntervalExp())
{
error(exp.loc, "no `[%s]` operator overload for type `%s`", ie.toChars(), exp.e1.type.toChars());
errorSupplemental(ad.loc, "perhaps define `auto opSlice(%s lower, %s upper) {}` for `%s`",
typeString(ie.lwr), typeString(ie.upr), ad.toPrettyChars());
}
else
{
OutBuffer buf;
buf.printf("%s", typeString((*exp.arguments)[0]));
foreach (e; (*exp.arguments)[1 .. $])
buf.printf(", %s", typeString(e));
error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
errorSupplemental(ad.loc, "perhaps define `auto opIndex(%s) {}` for `%s`",
buf.extractChars, ad.toPrettyChars());
}
}
}
else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());

View file

@ -403,9 +403,9 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc)
if (result.op == EXP.error)
{
if (!e0 && !search_function(ad, Id.dollar)) {
ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars());
}
if (!e0 && !search_function(ad, Id.dollar))
ad.loc.errorSupplemental("perhaps define `opDollar` for `%s`", ad.toChars());
return result;
}
/* Rewrite a[i..j] as:

View file

@ -2,9 +2,9 @@
TEST_OUTPUT:
---
fail_compilation/fail20616.d(16): Error: undefined identifier `$`
fail_compilation/fail20616.d(16): Aggregate declaration 'X()' does not define 'opDollar'
fail_compilation/fail20616.d(13): perhaps define `opDollar` for `X`
fail_compilation/fail20616.d(18): Error: undefined identifier `$`
fail_compilation/fail20616.d(18): Aggregate declaration 'b' does not define 'opDollar'
fail_compilation/fail20616.d(13): perhaps define `opDollar` for `X`
---
*/
module fail20616;

View file

@ -6,7 +6,7 @@ fail_compilation/fail_arrayexp.d(25): Error: cannot use `[]` operator on express
fail_compilation/fail_arrayexp.d(26): Error: static array of `const(int)[]` with multiple lengths not allowed
fail_compilation/fail_arrayexp.d(27): Error: only one index allowed to index `string`
fail_compilation/fail_arrayexp.d(28): Error: no `[]` operator overload for type `U`
fail_compilation/fail_arrayexp.d(16): `fail_arrayexp.U` declared here
fail_compilation/fail_arrayexp.d(16): perhaps define `auto opIndex() {}` for `fail_arrayexp.U`
fail_compilation/fail_arrayexp.d(29): Error: only one index allowed to index `(int, string)`
---
*/
@ -29,3 +29,24 @@ void test19534() // https://issues.dlang.org/show_bug.cgi?id=19534
auto t = agg[];
auto u = getTuple!(int, string)[1, 2];
}
/*
TEST_OUTPUT:
---
fail_compilation/fail_arrayexp.d(49): Error: no `[3.."4"]` operator overload for type `S`
fail_compilation/fail_arrayexp.d(42): perhaps define `auto opSlice(int lower, string upper) {}` for `fail_arrayexp.S`
fail_compilation/fail_arrayexp.d(50): Error: no `[]` operator overload for type `S`
fail_compilation/fail_arrayexp.d(42): perhaps define `auto opIndex(int, string, char) {}` for `fail_arrayexp.S`
---
*/
struct S
{
}
void testSlice()
{
S s;
const b = s[3 .. "4"];
const c = s[3, "4", 'c'];
}

View file

@ -4,33 +4,33 @@
TEST_OUTPUT:
---
fail_compilation/fail_opover.d(39): Error: no `[]` operator overload for type `object.Object`
$p:object.d$(110): `object.Object` declared here
$p:object.d$(110): perhaps define `auto opIndex() {}` for `object.Object`
fail_compilation/fail_opover.d(43): Error: no `[]` operator overload for type `TestS`
fail_compilation/fail_opover.d(41): `fail_opover.test1.TestS` declared here
fail_compilation/fail_opover.d(41): perhaps define `auto opIndex() {}` for `fail_opover.test1.TestS`
fail_compilation/fail_opover.d(55): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex() {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(56): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(57): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex(int) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(57): Error: no `[1..2]` operator overload for type `S`
fail_compilation/fail_opover.d(48): perhaps define `auto opSlice(int lower, int upper) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(58): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex() {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(59): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(60): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex(int) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(60): Error: no `[1..2]` operator overload for type `S`
fail_compilation/fail_opover.d(48): perhaps define `auto opSlice(int lower, int upper) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(61): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex() {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(62): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(63): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex(int) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(63): Error: no `[1..2]` operator overload for type `S`
fail_compilation/fail_opover.d(48): perhaps define `auto opSlice(int lower, int upper) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(64): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex() {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(65): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(66): Error: no `[]` operator overload for type `S`
fail_compilation/fail_opover.d(48): `fail_opover.test2.S` declared here
fail_compilation/fail_opover.d(48): perhaps define `auto opIndex(int) {}` for `fail_opover.test2.S`
fail_compilation/fail_opover.d(66): Error: no `[1..2]` operator overload for type `S`
fail_compilation/fail_opover.d(48): perhaps define `auto opSlice(int lower, int upper) {}` for `fail_opover.test2.S`
---
*/
void test1()