Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 4f6a999

Browse files
authored
Merge pull request #666 from github/exceptional-tracing
Exception tracking
2 parents 76eba98 + eecaaa0 commit 4f6a999

11 files changed

Lines changed: 211 additions & 27 deletions

File tree

semantic-analysis/.ghci.repl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
-- GHCI settings, collected by running cabal repl -v and checking out the flags cabal passes to ghc.
2+
-- These live here instead of script/repl for ease of commenting.
3+
-- These live here instead of .ghci so cabal repl remains unaffected.
4+
-- These live here instead of script/ghci-flags so ghcide remains unaffected.
5+
6+
-- Basic verbosity
7+
:set -v1
8+
9+
-- Compile to object code, write interface files.
10+
:set -fwrite-interface -fobject-code
11+
12+
-- Disable breaking on error since it hangs on uncaught exceptions when the sandbox is disabled: https://gitlab.haskell.org/ghc/ghc/issues/17743
13+
-- This was already disabled in .ghci, but it turns out that if your user-wide .ghci file sets -fbreak-on-error, it gets overriden, so we override it back again here.
14+
:set -fno-break-on-error
15+
16+
-- Bonus: silence “add these modules to your .cabal file” warnings for files we :load
17+
:set -Wno-missing-home-modules
18+
19+
-- Warnings for code written in the repl
20+
:seti -Weverything
21+
:seti -Wno-all-missed-specialisations
22+
:seti -Wno-implicit-prelude
23+
:seti -Wno-missed-specialisations
24+
:seti -Wno-missing-import-lists
25+
:seti -Wno-missing-local-signatures
26+
:seti -Wno-monomorphism-restriction
27+
:seti -Wno-name-shadowing
28+
:seti -Wno-safe
29+
:seti -Wno-unsafe
30+
-- 8.8+
31+
:seti -Wno-missing-deriving-strategies
32+
-- 8.10+
33+
:seti -Wno-missing-safe-haskell-mode
34+
:seti -Wno-prepositive-qualified-module
35+
36+
-- We have this one on in the project but not in the REPL to reduce noise
37+
:seti -Wno-type-defaults
38+
:set -Wno-unused-packages
39+
40+
:load Analysis.Concrete Analysis.Exception Analysis.Syntax Analysis.Typecheck

semantic-analysis/cabal.project

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- NB: This file exists solely for development of this single package. For cross-package development, cd to the root of the project and run `script/repl` from there.
2+
3+
-- Local packages
4+
packages: .

semantic-analysis/hie.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
cradle:
2+
cabal:
3+
- path: "."
4+
component: "lib:semantic-analysis"
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/bin/bash
2+
# Computes the flags for ghcide to pass to ghci. You probably won’t be running this yourself, but rather ghcide will via configuration in hie.yaml.
3+
4+
set -e
5+
6+
cd "$(dirname "$0")/.."
7+
8+
ghc_version="$(ghc --numeric-version)"
9+
10+
# recent hie-bios requires us to output to the file at $HIE_BIOS_OUTPUT, but older builds & script/repl don’t set that var, so we default it to stdout
11+
output_file="${HIE_BIOS_OUTPUT:-/dev/stdout}"
12+
13+
build_dir="dist-newstyle/build/x86_64-osx/ghc-$ghc_version"
14+
build_products_dir="$build_dir/build-repl"
15+
16+
cores=$(sysctl -n machdep.cpu.core_count || echo 4)
17+
18+
function flags {
19+
# disable optimizations for faster loading
20+
echo "-O0"
21+
# don’t load .ghci files (for ghcide)
22+
echo "-ignore-dot-ghci"
23+
24+
# use as many jobs as there are physical cores
25+
echo "-j$((cores + 1))"
26+
27+
# where to put build products
28+
echo "-outputdir $build_products_dir"
29+
echo "-odir $build_products_dir"
30+
echo "-hidir $build_products_dir"
31+
echo "-stubdir $build_products_dir"
32+
33+
# preprocessor options, for -XCPP
34+
echo "-optP-include"
35+
echo "-optP$build_dir/semantic-analysis-0.0.0.0/build/autogen/cabal_macros.h"
36+
37+
# autogenerated sources, both .hs and .h (e.g. Foo_paths.hs)
38+
echo "-i$build_dir/semantic-analysis-0.0.0.0/build/autogen"
39+
echo "-I$build_dir/semantic-analysis-0.0.0.0/build/autogen"
40+
41+
# .hs source dirs
42+
echo "-isrc"
43+
44+
# disable automatic selection of packages
45+
echo "-hide-all-packages"
46+
47+
# run cabal and emit package flags from the environment file, removing comments & prefixing with -
48+
cabal v2-exec -v0 bash -- -c 'cat "$GHC_ENVIRONMENT"' | grep -v '^--' | sed -e 's/^/-/'
49+
50+
# default language extensions
51+
echo "-XHaskell2010"
52+
53+
# treat warnings as warnings
54+
echo "-Wwarn"
55+
56+
# default warning flags
57+
echo "-Weverything"
58+
echo "-Wno-all-missed-specialisations"
59+
echo "-Wno-implicit-prelude"
60+
echo "-Wno-missed-specialisations"
61+
echo "-Wno-missing-import-lists"
62+
echo "-Wno-missing-local-signatures"
63+
echo "-Wno-monomorphism-restriction"
64+
echo "-Wno-name-shadowing"
65+
echo "-Wno-safe"
66+
echo "-Wno-unsafe"
67+
[[ "$ghc_version" = 8.8.* ]] || [[ "$ghc_version" = 8.10.* ]] && echo "-Wno-missing-deriving-strategies" || true
68+
[[ "$ghc_version" = 8.10.* ]] && echo "-Wno-missing-safe-haskell-mode" && echo "-Wno-prepositive-qualified-module" && echo "-Wno-unused-packages"
69+
}
70+
71+
flags > "$output_file"

semantic-analysis/script/repl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
# Usage: script/repl [ARGS...]
3+
# Run a repl session capable of loading all of the components. Any passed arguments, e.g. module names or flags, will be passed to ghci.
4+
5+
set -e
6+
7+
cd "$(dirname "$0")/.."
8+
9+
# cabal v2-build all --only-dependencies
10+
11+
cores=$(sysctl -n machdep.cpu.core_count || echo 4)
12+
cabal v2-exec env -- -u GHC_ENVIRONMENT ghci +RTS -N$((cores + 1)) -RTS -ghci-script=.ghci.repl $(script/ghci-flags) -no-ignore-dot-ghci $@

semantic-analysis/semantic-analysis.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ library
4949
Analysis.Carrier.Store.Monovariant
5050
Analysis.Carrier.Store.Precise
5151
Analysis.Concrete
52+
Analysis.Data.Snoc
5253
Analysis.Effect.Domain
5354
Analysis.Effect.Env
5455
Analysis.Effect.Store
56+
Analysis.Exception
5557
Analysis.File
5658
Analysis.FlowInsensitive
5759
Analysis.Functor.Named

semantic-analysis/src/Analysis/Concrete.hs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,10 @@
66
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
77
{-# LANGUAGE LambdaCase #-}
88
{-# LANGUAGE MultiParamTypeClasses #-}
9-
{-# LANGUAGE NamedFieldPuns #-}
109
{-# LANGUAGE OverloadedStrings #-}
1110
{-# LANGUAGE QuantifiedConstraints #-}
1211
{-# LANGUAGE RankNTypes #-}
1312
{-# LANGUAGE ScopedTypeVariables #-}
14-
{-# LANGUAGE StandaloneDeriving #-}
15-
{-# LANGUAGE TypeApplications #-}
1613
{-# LANGUAGE TypeOperators #-}
1714
{-# LANGUAGE UndecidableInstances #-}
1815
module Analysis.Concrete
@@ -22,6 +19,7 @@ module Analysis.Concrete
2219

2320
import Analysis.Carrier.Fail.WithLoc
2421
import qualified Analysis.Carrier.Store.Precise as A
22+
import Analysis.Data.Snoc
2523
import Analysis.Effect.Domain as A
2624
import Analysis.File
2725
import Analysis.Functor.Named
@@ -64,10 +62,6 @@ instance Show Concrete where
6462
showsPrec p = showsPrec p . quote
6563

6664

67-
data Snoc a = Nil | Snoc a :> a
68-
deriving (Foldable, Functor, Traversable)
69-
70-
7165
newtype Elim a = EApp a
7266
deriving (Eq, Foldable, Functor, Ord, Show, Traversable)
7367

@@ -180,9 +174,5 @@ instance ( Has (A.Env A.PAddr) sig m
180174
_ -> fail "expected Bool"
181175
L (DString s) -> pure (String s <$ ctx)
182176
L (DDie msg) -> fail (show (quote msg))
183-
L (DLet n v b) -> do
184-
addr <- A.alloc n
185-
addr A..= v
186-
A.bind n addr $ hdl (b v <$ ctx)
187177

188178
R other -> DomainC (alg (runDomain . hdl) other ctx)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{-# LANGUAGE DeriveTraversable #-}
2+
module Analysis.Data.Snoc
3+
( Snoc(..)
4+
) where
5+
6+
data Snoc a = Nil | Snoc a :> a
7+
deriving (Foldable, Functor, Traversable)

semantic-analysis/src/Analysis/Effect/Domain.hs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ module Analysis.Effect.Domain
2323
, dstring
2424
-- * Exceptions
2525
, ddie
26-
-- * Control flow
27-
, dlet
2826
-- * Domain effect
2927
, Dom(..)
3028
) where
@@ -71,7 +69,7 @@ dfalse = dbool False
7169
dbool :: Has (Dom val) sig m => Bool -> m val
7270
dbool = send . DBool
7371

74-
dif :: Has (Dom val) sig m => val -> m a -> m a -> m a
72+
dif :: Has (Dom val) sig m => val -> m val -> m val -> m val
7573
dif c t e = send $ DIf c t e
7674

7775

@@ -87,12 +85,6 @@ ddie :: Has (Dom val) sig m => val -> m val
8785
ddie = send . DDie
8886

8987

90-
-- Control flow
91-
92-
dlet :: Has (Dom val) sig m => Name -> val -> (val -> m val) -> m val
93-
dlet n v b = send (DLet n v b)
94-
95-
9688
-- Domain effect
9789

9890
data Dom val m k where
@@ -102,7 +94,6 @@ data Dom val m k where
10294
DInt :: Int -> Dom val m val
10395
DUnit :: Dom val m val
10496
DBool :: Bool -> Dom val m val
105-
DIf :: val -> m a -> m a -> Dom val m a
97+
DIf :: val -> m val -> m val -> Dom val m val
10698
DString :: Text -> Dom val m val
10799
DDie :: val -> Dom val m val
108-
DLet :: Name -> val -> (val -> m val) -> Dom val m val
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{-# LANGUAGE FlexibleInstances #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+
{-# LANGUAGE MultiParamTypeClasses #-}
5+
{-# LANGUAGE TypeOperators #-}
6+
{-# LANGUAGE UndecidableInstances #-}
7+
module Analysis.Exception
8+
( Exception(..)
9+
, ExcSet(..)
10+
, fromExceptions
11+
, var
12+
, exc
13+
-- * Exception tracing analysis
14+
, ExcC(..)
15+
) where
16+
17+
import Analysis.Effect.Domain
18+
import Analysis.Name
19+
import Control.Algebra
20+
import Control.Applicative (Alternative (..))
21+
import qualified Data.Foldable as Foldable
22+
import qualified Data.Set as Set
23+
24+
-- | Names of exceptions thrown in the guest language and recorded by this analysis.
25+
--
26+
-- Not to be confused with exceptions thrown in Haskell itself.
27+
newtype Exception = Exception { exceptionName :: Name }
28+
deriving (Eq, Ord, Show)
29+
30+
-- | Sets whose elements are each a variable or an exception.
31+
data ExcSet = ExcSet { freeVariables :: Set.Set Name, exceptions :: Set.Set Exception }
32+
deriving (Eq, Ord, Show)
33+
34+
instance Semigroup ExcSet where
35+
ExcSet v1 e1 <> ExcSet v2 e2 = ExcSet (v1 <> v2) (e1 <> e2)
36+
37+
instance Monoid ExcSet where
38+
mempty = ExcSet mempty mempty
39+
40+
fromExceptions :: Foldable t => t Exception -> ExcSet
41+
fromExceptions = ExcSet mempty . Set.fromList . Foldable.toList
42+
43+
var :: Name -> ExcSet
44+
var v = ExcSet (Set.singleton v) mempty
45+
46+
exc :: Exception -> ExcSet
47+
exc e = ExcSet mempty (Set.singleton e)
48+
49+
50+
newtype ExcC m a = ExcC { runExcC :: m a }
51+
deriving (Alternative, Applicative, Functor, Monad)
52+
53+
instance (Algebra sig m, Alternative m) => Algebra (Dom ExcSet :+: sig) (ExcC m) where
54+
alg hdl sig ctx = ExcC $ case sig of
55+
L dom -> case dom of
56+
DVar n -> pure $ var n <$ ctx
57+
DAbs _ b -> runExcC (hdl (b mempty <$ ctx))
58+
DApp f a -> pure $ f <> a <$ ctx
59+
DInt _ -> pure nil
60+
DUnit -> pure nil
61+
DBool _ -> pure nil
62+
DIf c t e -> fmap (mappend c) <$> runExcC (hdl (t <$ ctx) <|> hdl (e <$ ctx))
63+
DString _ -> pure nil
64+
DDie e -> pure $ e <> fromExceptions [Exception n | n <- Set.toList (freeVariables e)] <$ ctx
65+
where
66+
nil = (mempty :: ExcSet) <$ ctx
67+
68+
R other -> alg (runExcC . hdl) other ctx

0 commit comments

Comments
 (0)