[GHC] #8827: Inferring Safe mode with GeneralizedNewtypeDeriving is wrong

GHC ghc-devs at haskell.org
Sun Aug 16 23:48:54 UTC 2015


#8827: Inferring Safe mode with GeneralizedNewtypeDeriving is wrong
-------------------------------------+-------------------------------------
        Reporter:  goldfire          |                   Owner:
            Type:  bug               |                  Status:  new
        Priority:  normal            |               Milestone:  7.12.1
       Component:  Compiler          |                 Version:  7.9
      Resolution:                    |                Keywords:
Operating System:  Unknown/Multiple  |            Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |               Test Case:
      Blocked By:                    |                Blocking:
 Related Tickets:  #8226, #8745      |  Differential Revisions:
-------------------------------------+-------------------------------------

Comment (by oerjan):

 I think what was wrong with my first attempt was forgetting that ''role
 annotations'' also need the safety check. Also the safety of an explicit
 role annotation has two sides:

 * When ''using'' an explicit role annotation, the recursive check for that
 type is disabled at the use site. I.e. an explicit role annotation is to
 be interpreted as explicit permission to do the implied coercions `Safe`ly
 without further ado thereafter.

 * However, the annotation ''itself'' should not be `Safe` (nor the module
 containing it) unless the coercions implied by it can be written by hand
 using what's in scope in the module, plus `coerce` for other types with
 explicit annotations.  This means a recursive check for all its
 non-`nominal` parameters.

 Putting this together, the recursive check, when it happens, should cut
 off whenever an explicit role annotation is reached. A role annotation for
 a type transfers coercion `Safe`ty responsibility from the module using
 the role to the module declaring it.

 So I'll modify point 5, and add a point 6 that became apparent:

 5. Explicit role annotations, when used, transfer the responsibility for
 the `Safe`ty of `coerce`ing a type to the annotating module.
 6. To avoid breaking code, none of the new restrictions will apply outside
 of `Safe` mode.

 ----

 So, to sum up the modified design:

 * Default inferred role remains `representational`.
 * Explicit role annotations do indeed have subtly different semantics from
 implicitly inferred ones: they are considered stated author permission to
 `coerce` a type, even when not all constructors are in scope at the use
 site.
 * Declaring a role annotation, `coerce`ing types, or GND require checking
 the (non-`nominal`) parameter roles for `Safe`ty. Failure of the check
 means the module is not `Safe`, but has no other semantic effect.

 My non-expert attempt to define the recursive `Safe`ty check, probably
 similar to what GHC used to do:
 * A nominal role is always `Safe`.
 * The role of a parameter from an explicit role annotation is `Safe`.
 * The role of a parameter from a type's implicitly inferred role
 annotation is `Safe` if:
  * The type's data constructors are all in scope, and
  * the roles of all nested type parameters containing the given parameter
 on the right side of the datatype declaration are `Safe`.

 ----

 A few more thoughts/options:

 * As I mentioned, there probably should be an extension to make implicitly
 inferred roles behave as explicit ones for types declared in a module.
 Maybe `RoleAnnotations` itself will do, or at least imply it.
 * Since this proposal makes implicit and explicit role annotations subtly
 different, someone might want to have a way to explicitly declare a role
 annotation that behaves like an inferred one. Maybe the
 `inferredRepresentational` idea from my previous message.
 * By point 6, module encapsulation can still be broken nilly-willy by
 non-`Safe` modules, even by accident. Perhaps this is a bad idea, and an
 explicit extension (`NoScopedRolesRestriction`?) should be required to
 disable the recursive check for non-`Safe` modules. However, this would
 break backwards compatibility, and probably need a deprecation period.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8827#comment:42>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list