[GHC] #9858: Typeable instances should be kind-aware

GHC ghc-devs at haskell.org
Thu Apr 16 04:40:05 UTC 2015


#9858: Typeable instances should be kind-aware
-------------------------------------+-------------------------------------
        Reporter:  dreixel           |                   Owner:
            Type:  bug               |                  Status:  merge
        Priority:  highest           |               Milestone:  7.10.2
       Component:  Compiler          |                 Version:  7.9
      Resolution:                    |                Keywords:
Operating System:  Unknown/Multiple  |            Architecture:
 Type of failure:  None/Unknown      |  Unknown/Multiple
      Blocked By:                    |               Test Case:
 Related Tickets:                    |  typecheck/should_fail/T9858a,
                                     |  should_run/T9858b
                                     |                Blocking:
                                     |  Differential Revisions:  Phab:D652
-------------------------------------+-------------------------------------

Comment (by oerjan):

 Let me elaborate on my previous comment, especially the first suggestion,
 since my hunch is that it requires the smallest changes to implement to
 get back constraint `Typeable`s:

 * Instead of prohibiting constraint `Typeable`s, ''detect'' the specific
 case of `Typeable (() :: Constraint)` and give it a different instance
 from `Typeable (() :: *)`.

 == Why is this not less secure than the current fix? ==

 As shown in comment [comment:90], the current fix only effectively
 prohibits `Typeable` constraints for ''nullary'' constraint constructors.

 For other constraints, while ordinary users are greatly inconvenienced, an
 attacker can instead get the instances for all the constructors used (only
 the ''exact'' kind of `Constraint` is disallowed, not e.g. `* ->
 Constraint`) and put them together with type application, whose `Typeable`
 instance needs to be polymorphic and therefore cannot reasonably check for
 `Constraint` kinds.

 All nullary constructors ''other'' than `()` are either kind monomorphic
 or have kind parameters to distinguish the `TypeRep`s, so they are useless
 to an attacker.

 == How is it better? ==

 It allows `Typeable` for constraints, which some people think are useful.

 My feeling is that constraints, especially used as type parameters,
 shouldn't be considered impredicative except ''possibly'' if they contain
 `=>`.

 Prohibiting this case was the 3rd suggestion, but my hunch is that this is
 a more complicated change, and might, if desired, be better done with an
 overall overhaul disallowing `=>` more uniformly in the same contexts as
 quantified types, including disallowing splitting `a => b` into a type
 application.

 == How does it still seem a bit awkward? ==

 It still allows some types to have identical `TypeRep`s, like `(,) :: * ->
 * -> *` and `(,) :: Constraint -> Constraint -> Constraint`.  This is no
 change from the current fix, though.

 Fixing this entirely was the 2nd suggestion.  It might perhaps be
 implemented directly, although my hunch is that it requires more work,
 because it needs checking for partial applications and thus more
 complicated kinds.  I assume Edward's suggestion automatically implies
 this.

 == How is it sufficient? ==

 With either my suggestion or the currently implemented fix, although some
 types still have identical `TypeRep`s, I believe they can never have
 identical ''kinds'' as well, and all cast operations require the actual
 kinds of the compared `Typeable`s to be equal.

 '''Proposition''': If two types `t` and `u` have the property:

 * `t` and `u` are distinct as Haskell types, but have the same `TypeRep`
 under the pre-fix system, and ''either'' both have the same kind or one
 has kind `*` and the other has kind `Constraint`;

 then one of the following holds:

 * They have two corresponding type arguments with the same property.
 * They are, in some order, `() :: *` and `() :: Constraint`.

 '''Proof''': If at least one of `t` and `u` does ''not'' have as its tycon
 one of the kind-ambiguous types `(), (,), ..., (->), (=>)`, then to have
 equal `TypeRep`s, their tycons and lists of kindreps must be identical,
 and the types themselves and all their arguments must have corresponding
 kinds. Thus to be different as types two of their corresponding arguments
 must have the property.

 If the tycons ''are'' kind-ambiguous then any arguments must have kind
 either `*` or `Constraint`. With no arguments, with the ''exception'' of
 `()`, the types must have different kinds that are not `*` or
 `Constraint`, a contradiction. Otherwise, the kinds of the tycons are
 determined by the kinds of the first arguments, and for `t` and `u` to be
 distinct, there must be two corresponding arguments with the property.

 ----

 To justify the possibility of the 3rd alternative suggestion as well, the
 above proof can be adjusted to show that if the kinds of `t` and `u` are
 ''equal'', then types of the form `a -> c` and `b => c` must appear as
 corresponding arguments at some step.  This is because all the other
 options preserve whether the kinds of the arguments are equal or
 different.

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


More information about the ghc-tickets mailing list