packages feed

purescript-0.15.0: src/Language/PureScript/Linter/Wildcards.hs

module Language.PureScript.Linter.Wildcards
  ( ignoreWildcardsUnderCompleteTypeSignatures
  ) where

import Protolude hiding (Type)

import Language.PureScript.AST
import Language.PureScript.Types

-- |
-- Replaces `TypeWildcard _ UnnamedWildcard` with
-- `TypeWildcard _ IgnoredWildcard` in places where we don't want to emit a
-- warning about wildcards.
--
-- The guiding principle here is that a wildcard can be ignored if there is a
-- complete (wildcard-free) type signature on a binding somewhere between the
-- type in which the wildcard occurs and the top level of the module. In
-- particular, this means that top-level signatures containing wildcards are
-- always warnings, and a top-level signature always prevents wildcards on
-- inner bindings from emitting warnings.
--
ignoreWildcardsUnderCompleteTypeSignatures :: Declaration -> Declaration
ignoreWildcardsUnderCompleteTypeSignatures = onDecl
  where
  (onDecl, _, _, _, _) = everywhereWithContextOnValues False (,) handleExpr (,) (,) (,)
  handleExpr isCovered = \case
    tv@(TypedValue chk v ty)
      | isCovered -> (True, TypedValue chk v $ ignoreWildcards ty)
      | otherwise -> (isComplete ty, tv)
    other -> (isCovered, other)

ignoreWildcards :: Type a -> Type a
ignoreWildcards = everywhereOnTypes $ \case
  TypeWildcard a UnnamedWildcard -> TypeWildcard a IgnoredWildcard
  other -> other

isComplete :: Type a -> Bool
isComplete = everythingOnTypes (&&) $ \case
  TypeWildcard{} -> False
  _ -> True