Skip to content

Commit

Permalink
fix Bugzilla 24353 - add mutability check for foreach with opApply
Browse files Browse the repository at this point in the history
Signed-off-by: royalpinto007 <royalpinto007@gmail.com>
  • Loading branch information
royalpinto007 committed Nov 16, 2024
1 parent 73d56d0 commit 7ce408a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
38 changes: 32 additions & 6 deletions compiler/src/dmd/statementsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -779,14 +779,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)

Dsymbol sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors

/* Check for inference errors
*/
/* Check for inference errors and apply mutability checks inline */
if (!inferApplyArgTypes(fs, sc, sapply))
{
/**
Try and extract the parameter count of the opApply callback function, e.g.:
int opApply(int delegate(int, float)) => 2 args
*/
bool foundMismatch = false;
size_t foreachParamCount = 0;
if (sapplyOld)
Expand All @@ -806,6 +801,19 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
auto tf = fparam.type.nextOf().isTypeFunction();
foreachParamCount = tf.parameterList.length;
foundMismatch = true;

// Mutability check
if (fs.aggr && fs.aggr.type && fd.type && fs.aggr.type.isConst() && !fd.type.isConst())
{
// First error: The call site
error(fs.loc, "mutable method `%s.%s` is not callable using a `const` object",
fd.parent ? fd.parent.toPrettyChars() : "unknown", fd.toChars());

Check warning on line 810 in compiler/src/dmd/statementsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/statementsem.d#L809-L810

Added lines #L809 - L810 were not covered by tests

// Second error: Suggest how to fix
errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");

Check warning on line 813 in compiler/src/dmd/statementsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/statementsem.d#L813

Added line #L813 was not covered by tests

return setError();

Check warning on line 815 in compiler/src/dmd/statementsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/statementsem.d#L815

Added line #L815 was not covered by tests
}
}
}
}
Expand All @@ -824,6 +832,24 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
return setError();
}

// If inference succeeds, proceed with post-checks
if (sapply && sapply.isFuncDeclaration())
{
FuncDeclaration fd = sapply.isFuncDeclaration();

if (fs.aggr && fs.aggr.type && fd.type && fs.aggr.type.isConst() && !fd.type.isConst())
{
// First error: The call site
error(fs.loc, "mutable method `%s.%s` is not callable using a `const` object",
fd.parent ? fd.parent.toPrettyChars() : "unknown", fd.toChars());

Check warning on line 844 in compiler/src/dmd/statementsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/statementsem.d#L843-L844

Added lines #L843 - L844 were not covered by tests

// Second error: Suggest how to fix
errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");

Check warning on line 847 in compiler/src/dmd/statementsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/statementsem.d#L847

Added line #L847 was not covered by tests

return setError();

Check warning on line 849 in compiler/src/dmd/statementsem.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/statementsem.d#L849

Added line #L849 was not covered by tests
}
}

Type tab = fs.aggr.type.toBasetype();

if (tab.ty == Ttuple) // don't generate new scope for tuple loops
Expand Down
24 changes: 24 additions & 0 deletions compiler/test/fail_compilation/test24353.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// https://issues.dlang.org/show_bug.cgi?id=24353

/**
TEST_OUTPUT:
---
fail_compilation/test24353.d(23): Error: mutable method `test24353.S.opApply` is not callable using a `const` object
fail_compilation/test24353.d(14): Consider adding `const` or `inout` here
---
*/


struct S
{
int opApply(int delegate(int) dg)
{
return 0;
}
}

void example()
{
const S s;
foreach (e; s) {} // Error expected here
}

0 comments on commit 7ce408a

Please sign in to comment.