-- * Generalization

-- |Generalizes a type to produce a quantified type.
generalize :: TNormEnv -> QVar -> ConstraintSet -> NormalQuantType
generalize env qa cs =
  let cs' = calculateClosure cs in
  let reachableQVars = Set.map SomeQVar $ Set.fromList $
                          runReader (runListT $ reachableFromQVar qa) cs' in
  let freeEnvVars = Set.unions $ map openVars $ Map.elems env in
  let quantSet = extractVariables cs' `Set.difference` reachableQVars
                                      `Set.difference` freeEnvVars in
  QuantType quantSet qa cs
  where
    openVars :: NormalQuantType -> Set AnyTVar
    openVars (QuantType bound var cs'') =
      Set.insert (SomeQVar var) (extractVariables cs'') `Set.difference` bound
generalize :: TNormEnv -> QVar -> ConstraintSet -> NormalQuantType
generalize env qa cs =
  let cs' = calculateClosure cs in
  let reachableQVars = Set.map SomeQVar $ Set.fromList $
                          runReader (runListT $ reachableFromQVar qa) cs' in
  let freeEnvVars = Set.unions $ map openVars $ Map.elems env in
  let quantSet = extractVariables cs' `Set.difference` reachableQVars
                                      `Set.difference` freeEnvVars in
  QuantType quantSet qa cs
  where
    openVars :: NormalQuantType -> Set AnyTVar
    openVars (QuantType bound var cs'') =
      Set.insert (SomeQVar var) (extractVariables cs'') `Set.difference` bound
generalize env qa cs =
  let cs' = calculateClosure cs in
  let reachableQVars = Set.map SomeQVar $ Set.fromList $
                          runReader (runListT $ reachableFromQVar qa) cs' in
  let freeEnvVars = Set.unions $ map openVars $ Map.elems env in
  let quantSet = extractVariables cs' `Set.difference` reachableQVars
                                      `Set.difference` freeEnvVars in
  QuantType quantSet qa cs
  where
    openVars :: NormalQuantType -> Set AnyTVar
    openVars (QuantType bound var cs'') =
      Set.insert (SomeQVar var) (extractVariables cs'') `Set.difference` bound