Changes between Version 12 and Version 13 of GhciDebugger


Ignore:
Timestamp:
Dec 1, 2006 4:08:27 PM (7 years ago)
Author:
mnislaih
Comment:

Several changes in the closure viewer

Legend:

Unmodified
Added
Removed
Modified
  • GhciDebugger

    v12 v13  
    8989Once we have the ability to recover the datacon of a constr and thus its (possibly polymorphic) type, we can construct its tree representation. The payload of a closure is an ordered set of pointers and non pointers (words). For a Constr closure, the non pointers correspond to leafs of the tree, primitive unboxed values, the pointers being the so-called subTerms, references to other closures. 
    9090 
    91 === Type reconstruction === 
    92 `obtainTerm` recursively traverses all the closures that conform a term. Indirections are followed and suspensions are optionally forced. The only problem here is dealing with types. DataCons can have polymorphic types which we would want to instantiate, so the knowledge of the datacon only is not enough. There are two other sources of type information: 
    93  1. The typechecker, via the `Id` argument to `obtainTerm`. 
    94  2. The concrete types of the subterms, if they are sufficiently evaluated. 
    95  
    96 The process followed to reconstruct the types of a value as much as possible is: 
    97  
    98  1. obtain the subTerms of the value recursively calling `obtainTerm` with the available type info (dataCon plus typechecker), discovering new type info in the process. 
    99  2. refine the type of the value. This is accomplished with a step of unification between (1) and (2) above, and matching the result with the type of the datacon, obtaining the tyvars, which are used to instantiate. This step obtains the most concrete type.  
    100    * Note that tyvars need renaming to avoid collisions. 
    101  3. refine the type of the subterms (inductively) with the reconstructed type.  
     91=== Recovering non-pointers === 
     92This happens at `RtClosureInspect.extractUnboxed` and is a bit weak, it might potentially break in some architectures. 
    10293 
    10394=== Compensating Wrapper Constructors === 
     
    115106In addition, the types of the arguments may change, so the closure viewer always consider the final types, not the original ones, since the closure viewer deals with the heap representation of values. 
    116107 
     108 
     109=== Type reconstruction === 
     110Type reconstruction is the process of recovering the full type of a closure which has a polymorphic dataCon.  
     111 
     112The problem is approached as a simplified case of type inference. The set of constraints come from the typechecker and from the concrete types of the children of the closure, if they are evaluated. Constraints are are generated and unified with the previous set, ultimately generating the desired substitution. 
     113 
     114The only tricky issue is that newtypes are gone in the heap representation, so one needs to consider additional equations when doing unification, very similar to the coercions (:=:) of System Fc. For instance, the newtype: 
     115{{{  
     116newtype MkT a = MkT [a] 
     117}}} 
     118 
     119induces an equivalence class: 
     120{{{  
     121MkT a :=: [a]  
     122}}} 
     123 
     124This can be quite tricky to solve if done in full generality, as it amounts to unification modulo a set of equations which is known to be undecidible. The closure viewer uses the simpler trick of scanning every constraint lhs for newtypes and adjusting the rhs correspondingly. This simple trick seems to do it (see `congruenceNewtypes` at  [[GhcFile(compiler/ghci/RtClosureInspect.hs)]]). 
     125 
     126 
    117127=== About handling suspensions in the interactive environment === 
     128Often it is not possible to reconstruct the most concrete type, because children of a value are suspended. When this happens we have a value with polymorphic type, and this is a problem for two reasons. First, for the user, who cannot interact with the value in the usual way. Second, for ghci, because it does not deal well with tyvars in the type of values. 
     129 
     130Ideally, we want to lift this restriction on ghci some day. For now, the tyvars are instantiated to a family of dummy types, indexed by kind arity, which live in GHC.Base: `Unknown`, `Unknown1`,`Unknown2`, etc. 
     131 
    118132The interactive ui uses `GHC.obtainTerm` to implement the :print and :sprint command. The difference is that :print, additionally, binds suspended values. 
    119133Thus, suspensions inside semievaluated terms are bound by `:print` to _t,,xx,, names in the interactive environment, available for the user.  
    120134 
    121 This is done at `InteractiveUI.pprintClosure`. Whenever the suspensions are not sufficiently typed, tyvars are substituted with the type `GHC.Base.Unknown`, which has an associated Show instance that instructs the user to `seq` them to recover the type.  
     135This is done at `InteractiveUI.pprintClosure`, which takes responsibility of instantiating tyvars with  members the `GHC.Base.Unknown` family. A  an associated Show instance is provided that instructs the user to `seq` them to recover the type.  
    122136 
    123137There are two quirks with the current solution: 
    124138 * It does not remember previous bindings. Two consecutive uses of `:print` will generate two separate bindings for the same thing, generating redundancy and potential confusion. But... 
    125  * since type reconstruction (for polymorphic/untyped things) can eventually happen whenever the suspensions are forced, it is necessary to use `:print` again to obtain a properly typed binding 
     139 * since type reconstruction (for polymorphic/untyped things) can eventually happen whenever the suspensions are forced, it is necessary to use `:print` again to obtain a binding with the refined type 
    126140   * It is a future work to make ghci do this type reconstruction implicitly on the existing, polymorphic bindings. This would be ''nice'' for the _t,,xx,, things, but even nicer for the local bindings in the context of a breakpoint. 
     141 
     142=== Type Refinement === 
     143`InteractiveUI.pprintClosure` has some smartness in to update the type of a value as it is refined by forcing evaluation. As an example, look at the following (allegedly extreme) debugging session snippet: 
     144 
     145{{{ 
     146Local bindings in scope: 
     147  r :: a 
     148 
     149Core.hs:335:35-49> :t r 
     150r :: GHC.Base.Unknown 
     151 
     152Core.hs:335:35-49> :p r 
     153r = (_t1::a) 
     154 
     155Core.hs:335:35-49> seq _t1 () 
     156() 
     157 
     158Core.hs:335:35-49> :p r 
     159r = :-> (_t2::a) (_t3::a) 
     160 
     161Core.hs:335:35-49> :t r 
     162r :: RuleG GHC.Base.Unknown 
     163 
     164Core.hs:335:35-49> seq _t2 () 
     165() 
     166 
     167Core.hs:335:35-49> :p r 
     168r = :-> S (_t4::b (GT_ a b c))  (_t5::GT_ a b c) 
     169 
     170Core.hs:335:35-49> :t r 
     171r :: RuleG (GT_ GHC.Base.Unknown 
     172                     GHC.Base.Unknown1 
     173                     GHC.Base.Unknown) 
     174 
     175Core.hs:335:35-49> seq _t4 () 
     176() 
     177 
     178Core.hs:335:35-49> :p r 
     179r = :-> (S T "+" [(_t6::GT_ a TermST b), GenVar 1]) (_t7::GT_ a TermST b) 
     180 
     181Core.hs:335:35-49> :t r 
     182r :: RuleG (GT_ GHC.Base.Unknown TermST GHC.Base.Unknown) 
     183}}} 
     184 
     185Note how the type of the binding `r` gets updated during the debugging session. 
    127186 
    128187=== Pretty printing of terms === 
    129188We want to customize the printing of some stuff, such as Integers, Floats, Doubles, Lists, Tuples, Arrays, and so on. 
    130  At the `RtClosureInspect` module there is some infrastructure to build a custom printer, with a basic custom printer that covers the enumerated types. 
     189At the `RtClosureInspect` module there is some infrastructure to build a custom printer, with a basic custom printer that covers the enumerated types. 
    131190 
    132191In InteractiveUI.hs the function `pprintClosure` takes advantage of this and makes use of a custom printer that uses Show instances if available. 
    133192 
    134 === Recovering non-pointers === 
    135 This happens at `RtClosureInspect.extractUnboxed` and might potentially break in some architectures. 
    136193 
    137194= Breakpoints =