{-
    Suggest newtype instead of data for type declarations that have
    only one field. Don't suggest newtype for existentially
    quantified data types because it is not valid.

<TEST>
data Foo = Foo Int -- newtype Foo = Foo Int
data Foo = Foo Int deriving (Show, Eq) -- newtype Foo = Foo Int deriving (Show, Eq)
data Foo = Foo { field :: Int } deriving Show -- newtype Foo = Foo { field :: Int } deriving Show
data Foo a b = Foo a -- newtype Foo a b = Foo a
data Foo = Foo { field1, field2 :: Int}
data S a = forall b . Show b => S b
data Color a = Red a | Green a | Blue a
data Pair a b = Pair a b
data Foo = Bar
data Foo a = Eq a => MkFoo a
data X = Y {-# UNPACK #-} !Int -- newtype X = Y Int
data A = A {b :: !C} -- newtype A = A {b :: C}
data A = A Int#
{-# LANGUAGE UnboxedTuples #-}; data WithAnn x = WithAnn (# Ann, x #)
data A = A () -- newtype A = A ()
</TEST>
-}
module Hint.NewType (newtypeHint) where

import Hint.Type

newtypeHint :: DeclHint
newtypeHint :: DeclHint
newtypeHint _ _ = Decl_ -> [Idea]
newtypeHintDecl

newtypeHintDecl :: Decl_ -> [Idea]
newtypeHintDecl :: Decl_ -> [Idea]
newtypeHintDecl x :: Decl_
x
    | Just (DataType s :: S
s, t :: Type_
t, f :: DataOrNew S -> Type_ -> Decl_
f) <- Decl_ -> Maybe (DataOrNew S, Type_, DataOrNew S -> Type_ -> Decl_)
singleSimpleField Decl_
x
    = [(String -> Decl_ -> Decl_ -> Idea
forall (ast :: * -> *) a.
(Annotated ast, Pretty a, Pretty (ast S)) =>
String -> ast S -> a -> Idea
suggestN "Use newtype instead of data" Decl_
x (Decl_ -> Idea) -> Decl_ -> Idea
forall a b. (a -> b) -> a -> b
$ DataOrNew S -> Type_ -> Decl_
f (S -> DataOrNew S
forall l. l -> DataOrNew l
NewType S
s) (Type_ -> Decl_) -> Type_ -> Decl_
forall a b. (a -> b) -> a -> b
$ Type_ -> Type_
forall s. Type s -> Type s
fromTyBang Type_
t)
            {ideaNote :: [Note]
ideaNote = [Note
DecreasesLaziness | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Type_ -> Bool
forall l. Type l -> Bool
isTyBang Type_
t]}]
newtypeHintDecl _ = []


singleSimpleField :: Decl_ -> Maybe (DataOrNew S, Type_, DataOrNew S -> Type_ -> Decl_)
singleSimpleField :: Decl_ -> Maybe (DataOrNew S, Type_, DataOrNew S -> Type_ -> Decl_)
singleSimpleField (DataDecl x1 :: S
x1 dt :: DataOrNew S
dt x2 :: Maybe (Context S)
x2 x3 :: DeclHead S
x3 [QualConDecl y1 :: S
y1 Nothing Nothing ctor :: ConDecl S
ctor] x4 :: [Deriving S]
x4)
    | Just (t :: Type_
t, ft :: Type_ -> ConDecl S
ft) <- ConDecl S -> Maybe (Type_, Type_ -> ConDecl S)
f ConDecl S
ctor = (DataOrNew S, Type_, DataOrNew S -> Type_ -> Decl_)
-> Maybe (DataOrNew S, Type_, DataOrNew S -> Type_ -> Decl_)
forall a. a -> Maybe a
Just (DataOrNew S
dt, Type_
t, \dt :: DataOrNew S
dt t :: Type_
t -> S
-> DataOrNew S
-> Maybe (Context S)
-> DeclHead S
-> [QualConDecl S]
-> [Deriving S]
-> Decl_
forall l.
l
-> DataOrNew l
-> Maybe (Context l)
-> DeclHead l
-> [QualConDecl l]
-> [Deriving l]
-> Decl l
DataDecl S
x1 DataOrNew S
dt Maybe (Context S)
x2 DeclHead S
x3 [S
-> Maybe [TyVarBind S]
-> Maybe (Context S)
-> ConDecl S
-> QualConDecl S
forall l.
l
-> Maybe [TyVarBind l]
-> Maybe (Context l)
-> ConDecl l
-> QualConDecl l
QualConDecl S
y1 Maybe [TyVarBind S]
forall a. Maybe a
Nothing Maybe (Context S)
forall a. Maybe a
Nothing (ConDecl S -> QualConDecl S) -> ConDecl S -> QualConDecl S
forall a b. (a -> b) -> a -> b
$ Type_ -> ConDecl S
ft Type_
t] [Deriving S]
x4)
    where
        f :: ConDecl S -> Maybe (Type_, Type_ -> ConDecl S)
f (ConDecl x1 :: S
x1 x2 :: Name S
x2 [t :: Type_
t]) | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Type_ -> Bool
isKindHash Type_
t = (Type_, Type_ -> ConDecl S) -> Maybe (Type_, Type_ -> ConDecl S)
forall a. a -> Maybe a
Just (Type_
t, \t :: Type_
t -> S -> Name S -> [Type_] -> ConDecl S
forall l. l -> Name l -> [Type l] -> ConDecl l
ConDecl S
x1 Name S
x2 [Type_
t])
        f (RecDecl x1 :: S
x1 x2 :: Name S
x2 [FieldDecl y1 :: S
y1 [y2 :: Name S
y2] t :: Type_
t]) = (Type_, Type_ -> ConDecl S) -> Maybe (Type_, Type_ -> ConDecl S)
forall a. a -> Maybe a
Just (Type_
t, \t :: Type_
t -> S -> Name S -> [FieldDecl S] -> ConDecl S
forall l. l -> Name l -> [FieldDecl l] -> ConDecl l
RecDecl S
x1 Name S
x2 [S -> [Name S] -> Type_ -> FieldDecl S
forall l. l -> [Name l] -> Type l -> FieldDecl l
FieldDecl S
y1 [Name S
y2] Type_
t])
        f _ = Maybe (Type_, Type_ -> ConDecl S)
forall a. Maybe a
Nothing
singleSimpleField _ = Maybe (DataOrNew S, Type_, DataOrNew S -> Type_ -> Decl_)
forall a. Maybe a
Nothing