on master help sign in
Merge pull request #3151 from ahmadsalim/colin-adams-covering

Adds `covering` as an option for `%default` and fixes other inconsistencies with totality annotations

commit81030be2f2953e870fc5dcfcb51e047df76f3f82 authorAhmad Salim Al-Sibahi <asal@itu.dk> dateMon 9 May 2016, 08:30 (10 years ago) parent37aa54aa41ca33
10 files changed+109−69
.gitignore+1 idris.cabal+3 libs/prelude/Prelude/File.idr+2−2 src/Idris/AbsSyntaxTree.hs+9−4 src/Idris/DeepSeq.hs+5−1 src/Idris/Parser.hs+68−61 src/Idris/REPL.hs+1−1 test/directives002/directives002.idr+14 test/directives002/expected+2 test/directives002/run+4
.gitignore+1
@@ -32,6 +32,7 @@ test/output
3232test/*[0-9][0-9][0-9]/output
3333test/*[0-9][0-9][0-9]/*.exe
3434test/runtest.exe
35+test/runtest
3536tags
3637TAGS
3738src/Version_idris.hs
idris.cabal+3
@@ -409,6 +409,9 @@ Extra-source-files:
409409 test/directives001/*.idr
410410 test/directives001/run
411411 test/directives001/expected
412+ test/directives002/*.idr
413+ test/directives002/run
414+ test/directives002/expected
412415
413416 test/delab001/*.idr
414417 test/delab001/run
libs/prelude/Prelude/File.idr+2−2
@@ -233,7 +233,7 @@ fpoll (FHandle h) = do p <- foreign FFI_C "fpoll" (Ptr -> IO Int) h
233233 return (p > 0)
234234
235235||| Read the contents of a file into a string
236−partial -- might be reading something infinitely long like /dev/null ...
236+-- might be reading something infinitely long like /dev/null ...
237237covering export
238238readFile : String -> IO (Either FileError String)
239239readFile fn = do Right h <- openFile fn Read
@@ -242,7 +242,7 @@ readFile fn = do Right h <- openFile fn Read
242242 closeFile h
243243 return c
244244 where
245− partial
245+ covering
246246 readFile' : File -> String -> IO (Either FileError String)
247247 readFile' h contents =
248248 do x <- fEOF h
src/Idris/AbsSyntaxTree.hs+9−4
@@ -181,7 +181,12 @@ data ConsoleWidth = InfinitelyWide -- ^ Have pretty-printer assume that lines sh
181181 | AutomaticWidth -- ^ Attempt to determine width, or 80 otherwise
182182 deriving (Show, Eq)
183183
184−
184+-- | If a function has no totality annotation, what do we assume?
185+data DefaultTotality = DefaultCheckingTotal -- ^ Total
186+ | DefaultCheckingPartial -- ^ Partial
187+ | DefaultCheckingCovering -- ^Total coverage, but may diverge
188+ deriving (Show, Eq)
189+
185190-- | The global state used in the Idris monad
186191data IState = IState {
187192 tt_ctxt :: Context, -- ^ All the currently defined names and their terms
@@ -245,7 +250,7 @@ data IState = IState {
245250 idris_parsedSpan :: Maybe FC,
246251 hide_list :: Ctxt Accessibility,
247252 default_access :: Accessibility,
248− default_total :: Bool,
253+ default_total :: DefaultTotality,
249254 ibc_write :: [IBCWrite],
250255 compiled_so :: Maybe String,
251256 idris_dynamic_libs :: [DynamicLib],
@@ -361,7 +366,7 @@ idrisInit = IState initContext S.empty []
361366 emptyContext emptyContext emptyContext emptyContext
362367 emptyContext
363368 [] [] [] defaultOpts 6 [] [] [] [] emptySyntaxRules [] [] [] [] [] [] []
364− [] [] Nothing [] Nothing [] [] Nothing Nothing emptyContext Private False [] Nothing [] []
369+ [] [] Nothing [] Nothing [] [] Nothing Nothing emptyContext Private DefaultCheckingPartial [] Nothing [] []
365370 (RawOutput stdout) True defaultTheme [] (0, emptyContext) emptyContext M.empty
366371 AutomaticWidth S.empty S.empty [] Nothing Nothing [] [] M.empty [] [] []
367372 emptyContext S.empty M.empty emptyContext
@@ -771,7 +776,7 @@ data Directive = DLib Codegen String
771776 | DHide Name
772777 | DFreeze Name
773778 | DAccess Accessibility
774− | DDefault Bool
779+ | DDefault DefaultTotality
775780 | DLogging Integer
776781 | DDynamicLibs [String]
777782 | DNameHint Name FC [(Name, FC)]
src/Idris/DeepSeq.hs+5−1
@@ -695,7 +695,11 @@ instance NFData OutputMode where
695695 rnf (RawOutput x) = () -- no instance for Handle, so this is a bit wrong
696696 rnf (IdeMode x y) = rnf x `seq` ()
697697
698−
698+instance NFData DefaultTotality where
699+ rnf DefaultCheckingTotal = ()
700+ rnf DefaultCheckingPartial = ()
701+ rnf DefaultCheckingCovering = ()
702+
699703instance NFData IState where
700704 rnf (IState x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 x17 x18 x19 x20
701705 x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 x31 x32 x33 x34 x35 x36 x37 x38 x39 x40
src/Idris/Parser.hs+68−61
@@ -595,18 +595,12 @@ fnDecl' syn = checkFixity $
595595 do (doc, argDocs, fc, opts', n, nfc, acc) <- try (do
596596 pushIndent
597597 (doc, argDocs) <- docstring syn
598− ist <- get
599− let initOpts = if default_total ist
600− then [TotalFn]
601− else []
602− opts <- fnOpts initOpts
603− acc <- accessibility
604− opts' <- fnOpts opts
598+ (opts, acc) <- fnOpts
605599 (n_in, nfc) <- fnName
606600 let n = expandNS syn n_in
607601 fc <- getFC
608602 lchar ':'
609− return (doc, argDocs, fc, opts', n, nfc, acc))
603+ return (doc, argDocs, fc, opts, n, nfc, acc))
610604 ty <- typeExpr (allowImp syn)
611605 terminator
612606 -- If it's a top level function, note the accessibility
@@ -634,10 +628,40 @@ fnDecl' syn = checkFixity $
634628 | otherwise = return True
635629 fixityOK _ = return True
636630
637−{-| Parses function options given initial options
631+{-| Parses a series of function and accessbility options
638632
639633@
640−FnOpts ::= 'total'
634+FnOpts ::= FnOpt* Accessibility FnOpt*
635+@
636+ -}
637+fnOpts :: IdrisParser ([FnOpt], Accessibility)
638+fnOpts = do
639+ opts <- many fnOpt
640+ acc <- accessibility
641+ opts' <- many fnOpt
642+ let allOpts = opts ++ opts'
643+ let existingTotality = allOpts `intersect` [TotalFn, CoveringFn, PartialFn]
644+ opts'' <- addDefaultTotality (nub existingTotality) allOpts
645+ return (opts'', acc)
646+ where prettyTot TotalFn = "total"
647+ prettyTot PartialFn = "partial"
648+ prettyTot CoveringFn = "covering"
649+ addDefaultTotality [] opts = do
650+ ist <- get
651+ case default_total ist of
652+ DefaultCheckingTotal -> return (TotalFn:opts)
653+ DefaultCheckingCovering -> return (CoveringFn:opts)
654+ DefaultCheckingPartial -> return opts -- Don't add partial so that --warn-partial still reports warnings if necessary
655+ addDefaultTotality [tot] opts = return opts
656+ -- Should really be a semantics error instead of a parser error
657+ addDefaultTotality (tot1:tot2:tots) opts =
658+ fail ("Conflicting totality modifiers specified " ++ prettyTot tot1 ++ " and " ++ prettyTot tot2)
659+
660+
661+{-| Parses a function option
662+
663+@
664+FnOpt ::= 'total'
641665 | 'partial'
642666 | 'covering'
643667 | 'implicit'
@@ -660,37 +684,31 @@ NameTimesList ::=
660684 ;
661685@
662686-}
663−-- FIXME: Check compatability for function options (i.e. partal/total)
664−--
665−-- Issue #1574 on the issue tracker.
666−-- https://github.com/idris-lang/Idris-dev/issues/1574
667−fnOpts :: [FnOpt] -> IdrisParser [FnOpt]
668−fnOpts opts
669− = do reservedHL "total"; fnOpts (TotalFn : opts)
670− <|> do reservedHL "partial"; fnOpts (PartialFn : (opts \\ [TotalFn]))
671− <|> do reservedHL "covering"; fnOpts (CoveringFn : (opts \\ [TotalFn]))
672− <|> do try (lchar '%' *> reserved "export"); c <- fmap fst stringLiteral;
673− fnOpts (CExport c : opts)
674− <|> do try (lchar '%' *> reserved "no_implicit");
675− fnOpts (NoImplicit : opts)
676− <|> do try (lchar '%' *> reserved "inline");
677− fnOpts (Inlinable : opts)
678− <|> do try (lchar '%' *> reserved "assert_total");
679− fnOpts (AssertTotal : opts)
680− <|> do try (lchar '%' *> reserved "error_handler");
681− fnOpts (ErrorHandler : opts)
682− <|> do try (lchar '%' *> reserved "error_reverse");
683− fnOpts (ErrorReverse : opts)
684− <|> do try (lchar '%' *> reserved "reflection");
685− fnOpts (Reflection : opts)
686− <|> do try (lchar '%' *> reserved "hint");
687− fnOpts (AutoHint : opts)
688− <|> do lchar '%'; reserved "specialise";
689− lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']'
690− fnOpts (Specialise ns : opts)
691− <|> do reservedHL "implicit"; fnOpts (Implicit : opts)
692− <|> return opts
693− <?> "function modifier"
687+fnOpt :: IdrisParser FnOpt
688+fnOpt = do reservedHL "total"; return TotalFn
689+ <|> do reservedHL "partial"; return PartialFn
690+ <|> do reservedHL "covering"; return CoveringFn
691+ <|> do try (lchar '%' *> reserved "export"); c <- fmap fst stringLiteral;
692+ return $ CExport c
693+ <|> do try (lchar '%' *> reserved "no_implicit");
694+ return NoImplicit
695+ <|> do try (lchar '%' *> reserved "inline");
696+ return Inlinable
697+ <|> do try (lchar '%' *> reserved "assert_total");
698+ return AssertTotal
699+ <|> do try (lchar '%' *> reserved "error_handler");
700+ return ErrorHandler
701+ <|> do try (lchar '%' *> reserved "error_reverse");
702+ return ErrorReverse
703+ <|> do try (lchar '%' *> reserved "reflection");
704+ return Reflection
705+ <|> do try (lchar '%' *> reserved "hint");
706+ return AutoHint
707+ <|> do lchar '%'; reserved "specialise";
708+ lchar '['; ns <- sepBy nameTimes (lchar ','); lchar ']';
709+ return $ Specialise ns
710+ <|> do reservedHL "implicit"; return Implicit
711+ <?> "function modifier"
694712 where nameTimes :: IdrisParser (Name, Maybe Int)
695713 nameTimes = do n <- fst <$> fnName
696714 t <- option Nothing (do reds <- fmap fst natural
@@ -712,12 +730,7 @@ postulate syn = do (doc, ext)
712730 ext <- ppostDecl
713731 return (doc, ext)
714732 ist <- get
715− let initOpts = if default_total ist
716− then [TotalFn]
717− else []
718− opts <- fnOpts initOpts
719− acc <- accessibility
720− opts' <- fnOpts opts
733+ (opts, acc) <- fnOpts
721734 (n_in, nfc) <- fnName
722735 let n = expandNS syn n_in
723736 lchar ':'
@@ -725,7 +738,7 @@ postulate syn = do (doc, ext)
725738 fc <- getFC
726739 terminator
727740 addAcc n acc
728− return (PPostulate ext doc syn fc nfc opts' n ty)
741+ return (PPostulate ext doc syn fc nfc opts n ty)
729742 <?> "postulate"
730743 where ppostDecl = do fc <- reservedHL "postulate"; return False
731744 <|> do lchar '%'; reserved "extern"; return True
@@ -940,15 +953,8 @@ InstanceName ::= '[' Name ']';
940953instance_ :: Bool -> SyntaxInfo -> IdrisParser [PDecl]
941954instance_ kwopt syn
942955 = do ist <- get
943− let initOpts = if default_total ist
944− then [TotalFn]
945− else []
946−
947956 (doc, argDocs) <- docstring syn
948− opts <- fnOpts initOpts
949− acc <- accessibility
950− opts' <- fnOpts opts
951−
957+ (opts, acc) <- fnOpts
952958 if kwopt then optional instanceKeyword
953959 else do instanceKeyword
954960 return (Just ())
@@ -963,7 +969,7 @@ instance_ kwopt syn
963969 let t = bindList (PPi constraint) cs sc
964970 pnames <- instanceUsing
965971 ds <- instanceBlock syn
966− return [PInstance doc argDocs syn fc cs' pnames acc opts' cn cnfc args [] t en ds]
972+ return [PInstance doc argDocs syn fc cs' pnames acc opts cn cnfc args [] t en ds]
967973 <?> "implementation declaration"
968974 where instanceName :: IdrisParser Name
969975 instanceName = do lchar '['; n_in <- fst <$> fnName; lchar ']'
@@ -1424,14 +1430,15 @@ pLangExt = (reserved "TypeProviders" >> return TypeProviders)
14241430{- | Parses a totality
14251431
14261432@
1427−Totality ::= 'partial' | 'total'
1433+Totality ::= 'partial' | 'total' | 'covering'
14281434@
14291435
14301436-}
1431−totality :: IdrisParser Bool
1437+totality :: IdrisParser DefaultTotality
14321438totality
1433− = do reservedHL "total"; return True
1434− <|> do reservedHL "partial"; return False
1439+ = do reservedHL "total"; return DefaultCheckingTotal
1440+ <|> do reservedHL "partial"; return DefaultCheckingPartial
1441+ <|> do reservedHL "covering"; return DefaultCheckingCovering
14351442
14361443{- | Parses a type provider
14371444
src/Idris/REPL.hs+1−1
@@ -1703,7 +1703,7 @@ idrisMain opts =
17031703 let port = getPort opts
17041704
17051705 when (DefaultTotal `elem` opts) $ do i <- getIState
1706− putIState (i { default_total = True })
1706+ putIState (i { default_total = DefaultCheckingTotal })
17071707 tty <- runIO $ isATTY
17081708 setColourise $ not quiet && last (tty : opt getColour opts)
17091709
test/directives002/directives002.idrnew file+14
@@ -0,0 +1,14 @@
1+module directives002
2+
3+%access export
4+%default covering
5+
6+loop : ()
7+loop = loop
8+
9+namespace Main
10+ total
11+ main : IO ()
12+ main = do
13+ pure loop
14+ putStrLn $ "Hello World"
test/directives002/expectednew file+2
@@ -0,0 +1,2 @@
1+directives002.idr:12:3:
2+directives002.Main.main is possibly not total due to: directives002.loop
test/directives002/runnew file+4
@@ -0,0 +1,4 @@
1+#!/usr/bin/env bash
2+${IDRIS:-idris} $@ directives002.idr --check --nocolour
3+
4+rm -f directives002 *.ibc