Show some details in InvalidType error output (#824)

This commit is contained in:
Javier Neira 2019-02-23 18:49:14 +01:00 committed by Gabriel Gonzalez
parent 5b0686b01c
commit d714754e14
6 changed files with 101 additions and 10 deletions

View File

@ -464,6 +464,7 @@ Test-Suite tasty
Main-Is: Dhall/Test/Main.hs Main-Is: Dhall/Test/Main.hs
GHC-Options: -Wall GHC-Options: -Wall
Other-Modules: Other-Modules:
Dhall.Test.Dhall
Dhall.Test.Format Dhall.Test.Format
Dhall.Test.Import Dhall.Test.Import
Dhall.Test.Lint Dhall.Test.Lint

View File

@ -105,6 +105,7 @@ import Data.Monoid ((<>))
import Data.Scientific (Scientific) import Data.Scientific (Scientific)
import Data.Sequence (Seq) import Data.Sequence (Seq)
import Data.Text (Text) import Data.Text (Text)
import Data.Text.Prettyprint.Doc (Pretty)
import Data.Typeable (Typeable) import Data.Typeable (Typeable)
import Data.Vector (Vector) import Data.Vector (Vector)
import Data.Word (Word8, Word16, Word32, Word64) import Data.Word (Word8, Word16, Word32, Word64)
@ -141,6 +142,7 @@ import qualified Dhall.Map
import qualified Dhall.Parser import qualified Dhall.Parser
import qualified Dhall.Pretty.Internal import qualified Dhall.Pretty.Internal
import qualified Dhall.TypeCheck import qualified Dhall.TypeCheck
import qualified Dhall.Util
-- $setup -- $setup
-- >>> :set -XOverloadedStrings -- >>> :set -XOverloadedStrings
@ -156,19 +158,36 @@ throws (Right r) = return r
This exception indicates that an invalid `Type` was provided to the `input` This exception indicates that an invalid `Type` was provided to the `input`
function function
-} -}
data InvalidType = InvalidType deriving (Typeable) data InvalidType s a = InvalidType
{ invalidTypeExpected :: Expr s a
, invalidTypeExpression :: Expr s a
}
deriving (Typeable)
_ERROR :: String _ERROR :: String
_ERROR = "\ESC[1;31mError\ESC[0m" _ERROR = "\ESC[1;31mError\ESC[0m"
instance Show InvalidType where instance (Pretty s, Pretty a, Typeable s, Typeable a) => Show (InvalidType s a) where
show InvalidType = show InvalidType { .. } =
_ERROR <> ": Invalid Dhall.Type \n\ _ERROR <> ": Invalid Dhall.Type \n\
\ \n\ \ \n\
\Every Type must provide an extract function that succeeds if an expression \n\ \Every Type must provide an extract function that succeeds if an expression \n\
\matches the expected type. You provided a Type that disobeys this contract \n" \matches the expected type. You provided a Type that disobeys this contract \n\
\ \n\
\The Type provided has the expected dhall type: \n\
\ \n\
\" <> show txt0 <> "\n\
\ \n\
\and it couldn't extract a value from the well-typed expression: \n\
\ \n\
\" <> show txt1 <> "\n\
\ \n"
where
txt0 = Dhall.Util.insert invalidTypeExpected
txt1 = Dhall.Util.insert invalidTypeExpression
instance Exception InvalidType instance (Pretty s, Pretty a, Typeable s, Typeable a) => Exception (InvalidType s a)
-- | @since 1.16 -- | @since 1.16
data InputSettings = InputSettings data InputSettings = InputSettings
@ -341,9 +360,14 @@ inputWithSettings settings (Type {..}) txt = do
_ -> _ ->
Annot expr' expected Annot expr' expected
_ <- throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot) _ <- throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)
case extract (Dhall.Core.normalizeWith (Dhall.Core.getReifiedNormalizer (view normalizer settings)) expr') of let normExpr = Dhall.Core.normalizeWith
(Dhall.Core.getReifiedNormalizer
(view normalizer settings))
expr'
case extract normExpr of
Just x -> return x Just x -> return x
Nothing -> Control.Exception.throwIO InvalidType Nothing -> Control.Exception.throwIO
(InvalidType expected expr')
{-| Type-check and evaluate a Dhall program that is read from the {-| Type-check and evaluate a Dhall program that is read from the
file-system. file-system.

View File

@ -947,8 +947,7 @@ _NOT :: Doc ann
_NOT = "\ESC[1mnot\ESC[0m" _NOT = "\ESC[1mnot\ESC[0m"
insert :: Pretty a => a -> Doc Ann insert :: Pretty a => a -> Doc Ann
insert expression = insert = Dhall.Util.insert
"" <> Pretty.align (Dhall.Util.snipDoc (Pretty.pretty expression))
prettyDiff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Doc Ann prettyDiff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Doc Ann
prettyDiff exprL exprR = Dhall.Diff.diffNormalized exprL exprR prettyDiff exprL exprR = Dhall.Diff.diffNormalized exprL exprR

View File

@ -5,11 +5,12 @@
module Dhall.Util module Dhall.Util
( snip ( snip
, snipDoc , snipDoc
, insert
) where ) where
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.Text (Text) import Data.Text (Text)
import Data.Text.Prettyprint.Doc (Doc) import Data.Text.Prettyprint.Doc (Doc, Pretty)
import Dhall.Pretty (Ann) import Dhall.Pretty (Ann)
import qualified Data.Text import qualified Data.Text
@ -67,3 +68,8 @@ takeEnd n l = go (drop n l) l
where where
go (_:xs) (_:ys) = go xs ys go (_:xs) (_:ys) = go xs ys
go _ r = r go _ r = r
-- | Function to insert an aligned pretty expression
insert :: Pretty a => a -> Doc Ann
insert expression =
"" <> Pretty.align (snipDoc (Pretty.pretty expression))

View File

@ -0,0 +1,59 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Dhall.Test.Dhall where
import Control.Exception (SomeException, try)
import Numeric.Natural (Natural)
import Test.Tasty
import Test.Tasty.HUnit
import qualified Dhall
import qualified Dhall.Core
import qualified Dhall.Map
tests :: TestTree
tests =
testGroup "Input"
[ shouldShowDetailedTypeError ]
data MyType = MyType { foo :: String , bar :: Natural }
wrongDhallType :: Dhall.Type MyType
wrongDhallType = Dhall.Type { .. }
where expected =
Dhall.Core.Record
( Dhall.Map.fromList
[ ( "bar", Dhall.Core.Natural)
, ( "foo", Dhall.Core.Text )
]
)
extract _ = Nothing
shouldShowDetailedTypeError :: TestTree
shouldShowDetailedTypeError = testCase "detailed TypeError" $ do
inputEx :: Either SomeException MyType <-
try ( Dhall.input wrongDhallType "{ bar = 0, foo = \"foo\" }")
let expectedMsg =
"\ESC[1;31mError\ESC[0m: Invalid Dhall.Type \n\
\ \n\
\Every Type must provide an extract function that succeeds if an expression \n\
\matches the expected type. You provided a Type that disobeys this contract \n\
\ \n\
\The Type provided has the expected dhall type: \n\
\ \n\
\ { bar : Natural, foo : Text }\n\
\ \n\
\and it couldn't extract a value from the well-typed expression: \n\
\ \n\
\ { bar = 0, foo = \"foo\" }\n\
\ \n"
let assertMsg = "The exception message did not match the expected output"
case inputEx of
Left ex -> assertEqual assertMsg expectedMsg (show ex)
Right _ -> fail "The extraction using a wrong type succeded"

View File

@ -2,6 +2,7 @@ module Main where
import Test.Tasty (TestTree) import Test.Tasty (TestTree)
import qualified Dhall.Test.Dhall
import qualified Dhall.Test.Format import qualified Dhall.Test.Format
import qualified Dhall.Test.Import import qualified Dhall.Test.Import
import qualified Dhall.Test.Lint import qualified Dhall.Test.Lint
@ -31,6 +32,7 @@ allTests =
, Dhall.Test.Import.tests , Dhall.Test.Import.tests
, Dhall.Test.QuickCheck.tests , Dhall.Test.QuickCheck.tests
, Dhall.Test.Lint.tests , Dhall.Test.Lint.tests
, Dhall.Test.Dhall.tests
] ]
main :: IO () main :: IO ()