-isGoodRecEv :: EvVar -> EvVar -> TcS Bool
--- In a call (isGoodRecEv ev wv), we are considering solving wv
--- using some term that involves ev, such as:
--- by setting wv = ev
--- or wv = EvCast x |> ev
--- etc.
--- But that would be Very Bad if the evidence for 'ev' mentions 'wv',
--- in an "unguarded" way. So isGoodRecEv looks at the evidence ev
--- recursively through the evidence binds, to see if uses of 'wv' are guarded.
---
--- Guarded means: more instance calls than superclass selections. We
--- compute this by chasing the evidence, adding +1 for every instance
--- call (constructor) and -1 for every superclass selection (destructor).
---
--- See Note [Superclasses and recursive dictionaries] in TcInteract
-isGoodRecEv ev_var wv
- = do { tc_evbinds <- getTcEvBindsBag
- ; mb <- chase_ev_var tc_evbinds wv 0 [] ev_var
- ; return $ case mb of
- Nothing -> True
- Just min_guardedness -> min_guardedness > 0
- }
-
- where chase_ev_var :: EvBindMap -- Evidence binds
- -> EvVar -- Target variable whose gravity we want to return
- -> Int -- Current gravity
- -> [EvVar] -- Visited nodes
- -> EvVar -- Current node
- -> TcS (Maybe Int)
- chase_ev_var assocs trg curr_grav visited orig
- | trg == orig = return $ Just curr_grav
- | orig `elem` visited = return $ Nothing
- | Just (EvBind _ ev_trm) <- lookupEvBind assocs orig
- = chase_ev assocs trg curr_grav (orig:visited) ev_trm
-
- | otherwise = return Nothing
-
- chase_ev assocs trg curr_grav visited (EvId v)
- = chase_ev_var assocs trg curr_grav visited v
- chase_ev assocs trg curr_grav visited (EvSuperClass d_id _)
- = chase_ev_var assocs trg (curr_grav-1) visited d_id
- chase_ev assocs trg curr_grav visited (EvCast v co)
- = do { m1 <- chase_ev_var assocs trg curr_grav visited v
- ; m2 <- chase_co assocs trg curr_grav visited co
- ; return (comb_chase_res Nothing [m1,m2]) }
-
- chase_ev assocs trg curr_grav visited (EvCoercion co)
- = chase_co assocs trg curr_grav visited co
- chase_ev assocs trg curr_grav visited (EvDFunApp _ _ ev_deps)
- = do { chase_results <- mapM (chase_ev_var assocs trg (curr_grav+1) visited) ev_deps
- ; return (comb_chase_res Nothing chase_results) }
-
- chase_co assocs trg curr_grav visited co
- = -- Look for all the coercion variables in the coercion
- -- chase them, and combine the results. This is OK since the
- -- coercion will not contain any superclass terms -- anything
- -- that involves dictionaries will be bound in assocs.
- let co_vars = foldVarSet (\v vrs -> if isCoVar v then (v:vrs) else vrs) []
- (tyVarsOfType co)
- in do { chase_results <- mapM (chase_ev_var assocs trg curr_grav visited) co_vars
- ; return (comb_chase_res Nothing chase_results) }
-
- comb_chase_res f [] = f
- comb_chase_res f (Nothing:rest) = comb_chase_res f rest
- comb_chase_res Nothing (Just n:rest) = comb_chase_res (Just n) rest
- comb_chase_res (Just m) (Just n:rest) = comb_chase_res (Just (min n m)) rest
-
-