Thread overview
[Issue 15624] opApply with @safe and @system variants can't be used with foreach syntax
Jun 07, 2016
Walter Bright
Mar 16, 2018
Walter Bright
Mar 17, 2018
Walter Bright
Mar 18, 2018
Carsten Blüggel
Oct 08, 2018
Bolpat
Nov 06, 2021
Dlang Bot
June 07, 2016
https://issues.dlang.org/show_bug.cgi?id=15624

Walter Bright <bugzilla@digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |safe
                 CC|                            |bugzilla@digitalmars.com

--
March 16, 2018
https://issues.dlang.org/show_bug.cgi?id=15624

--- Comment #1 from Walter Bright <bugzilla@digitalmars.com> ---
The foreach delegate is correctly constructed and its @safe-ty is correctly inferred. The overloading of opApply() is correct.

The trouble is that the opApply() is selected by inferApplyArgTypes() before
the foreach delegate is constructed.

--
March 17, 2018
https://issues.dlang.org/show_bug.cgi?id=15624

--- Comment #2 from Walter Bright <bugzilla@digitalmars.com> ---
https://github.com/dlang/dmd/pull/8047

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=15624

Carsten Blüggel <chilli@posteo.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |chilli@posteo.net

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=15624

--- Comment #3 from github-bugzilla@puremagic.com ---
Commits pushed to master at https://github.com/dlang/dmd

https://github.com/dlang/dmd/commit/70fb7cb46698ec6d6fba7efc64331cb76f73ef07 fix Issue 15624 - opApply with @safe and @system variants can't be used with foreach syntax

https://github.com/dlang/dmd/commit/5bfa34232d104d75b189a84cc88f3dd4fc885daf Merge pull request #8047 from WalterBright/fix15624

fix Issue 15624 - opApply with @safe and @system variants can't be us… merged-on-behalf-of: Walter Bright <WalterBright@users.noreply.github.com>

--
March 18, 2018
https://issues.dlang.org/show_bug.cgi?id=15624

github-bugzilla@puremagic.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |FIXED

--
October 08, 2018
https://issues.dlang.org/show_bug.cgi?id=15624

Bolpat <qs.il.paperinik@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |qs.il.paperinik@gmail.com

--- Comment #4 from Bolpat <qs.il.paperinik@gmail.com> ---
*** Issue 15859 has been marked as a duplicate of this issue. ***

--
November 06, 2021
https://issues.dlang.org/show_bug.cgi?id=15624

--- Comment #5 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #13226 "Rework fix for attribute based opApply overloads (issue 15624)" was merged into master:

- a28680a845a06d0cac476442c25e7c7fe8e0d16d by MoonlightSentinel:
  Rework fix for attribute based opApply overloads (issue 15624)

  The old implementation uses `Type.covariant` to suppress overzealous
  ambiguity errors for `opApply` specialisations. Deferring the ambiguity
  checks after the attribute inference on the loop body allows for
  `opApply` overloads with different attributes, e.g. `@safe / @system` for
  `@safe / @system` delegates.

  Example:
  ```d
  struct Collection
  {
      /* A. */ int opApply(int delegate(int) @safe dg) @safe;

      /* B. */ int opApply(int delegate(int) @system dg) @system;
  }

  void main() @safe
  {
      Collection col;
      foreach (entry; col) {} // Resolves to A.
  }
  ```

  The previous code achieved this by checking whether the previously
  selected `opApply` and the current overload are covariant in any
  direction (i.e. `A.covariant(B)` or `B.covariant(A)`).

  This implementation builds on the flawed assumption that the `opApply`
  functions in this example are covariant - which they are not
  (falsely reported due to a bug in `Type.covariant`).

  Consider the types of the `opApply` overloads:
  ```d
  A: int function(int delegate(int) @safe dg) @safe;
  B: int function(int delegate(int) @system dg) @system;
  ```

  Neither of those is an appropriate substitute for the other:

  - A <= B is invalid due to the `opApply`'s attributes. A `@system`
      function may not appear in place of a `@safe` function
  - A => B is invalid due to the parameter types (`dg` attributes).
      A function expecting a `@safe` delegate may not be treated as a
      function accepting `@system` callbacks. Otherwise it could silently
      execute a `@system` callback which is disallowed in `@safe` functions.

  Note that `Type.covariant` already rejects covariance when using
  `function` instead of `delegate` for the callbacks in the example.

  ---

  The new implementation does not rely on the buggy behaviour of
  `Type.covariant`. It checks two different aspects to defer the
  `opApply` resolution:

  1. different attributes on the `opApply` function
  2. different attributes on the `opApply` function
  3. covariance of the callbacks receiving the foreach body

  (2) should handle different qualifiers on the foreach body
  because missmatched parameter types are usually rejected by
  `matchParamsToOpApply`.

  ---

  This patch enables us to fix the aforementioned bug without breaking
  existing code. It also enables the code added the test case wich
  is valid despite being utterly useless.

https://github.com/dlang/dmd/pull/13226

--