Track type variables in monadic pretty-printer

This commit is contained in:
Rúnar 2022-10-26 20:41:21 -04:00
parent 52f2632133
commit 2508f40232
12 changed files with 1046 additions and 919 deletions

View File

@ -1,6 +1,7 @@
module U.Util.Monoid where
import Control.Monad (foldM)
import Control.Monad.Extra ((>=>))
import Data.Foldable (toList)
import Data.List (intersperse)
@ -10,6 +11,9 @@ intercalateMap :: (Foldable t, Monoid a) => a -> (b -> a) -> t b -> a
intercalateMap separator renderer elements =
mconcat $ intersperse separator (renderer <$> toList elements)
intercalateMapM :: (Traversable t, Monad m, Monoid a) => a -> (b -> m a) -> t b -> m a
intercalateMapM separator renderer = traverse renderer >=> return . intercalateMap separator id
fromMaybe :: Monoid a => Maybe a -> a
fromMaybe Nothing = mempty
fromMaybe (Just a) = a
@ -24,4 +28,4 @@ isEmpty a = a == mempty
nonEmpty = not . isEmpty
foldMapM :: (Monad m, Foldable f, Monoid b) => (a -> m b) -> f a -> m b
foldMapM f as = foldM (\b a -> fmap (b <>) (f a)) mempty as
foldMapM f = foldM (\b a -> fmap (b <>) (f a)) mempty

View File

@ -102,6 +102,7 @@ module Unison.Util.Pretty
spaceIfNeeded,
spaced,
spacedMap,
spacedTraverse,
spacesIfBreak,
string,
surroundCommas,
@ -406,6 +407,9 @@ spaced = intercalateMap softbreak id
spacedMap :: (Foldable f, IsString s) => (a -> Pretty s) -> f a -> Pretty s
spacedMap f as = spaced . fmap f $ toList as
spacedTraverse :: (Traversable f, IsString s, Applicative m) => (a -> m (Pretty s)) -> f a -> m (Pretty s)
spacedTraverse f as = spaced <$> traverse f as
commas :: (Foldable f, IsString s) => f (Pretty s) -> Pretty s
commas = intercalateMap ("," <> softbreak) id

View File

@ -0,0 +1,47 @@
{-# LANGUAGE ConstraintKinds #-}
module Unison.PrettyPrintEnv.MonadPretty where
import Control.Lens (over, set, view, views, _1, _2)
import Control.Monad.Reader (MonadReader, Reader, local, runReader)
import qualified Data.Set as Set
import Unison.Prelude (Set)
import Unison.PrettyPrintEnv (PrettyPrintEnv)
import Unison.Var (Var)
type MonadPretty v m = (Var v, MonadReader (PrettyPrintEnv, Set v) m)
getPPE :: MonadPretty v m => m PrettyPrintEnv
getPPE = view _1
-- | Run a computation with a modified PrettyPrintEnv, restoring the original
withPPE :: MonadPretty v m => PrettyPrintEnv -> m a -> m a
withPPE p = local (set _1 p)
applyPPE :: MonadPretty v m => (PrettyPrintEnv -> a) -> m a
applyPPE = views _1
applyPPE2 :: MonadPretty v m => (PrettyPrintEnv -> a -> b) -> a -> m b
applyPPE2 f a = views _1 (`f` a)
applyPPE3 :: MonadPretty v m => (PrettyPrintEnv -> a -> b -> c) -> a -> b -> m c
applyPPE3 f a b = views _1 (\ppe -> f ppe a b)
-- | Run a computation with a modified PrettyPrintEnv, restoring the original
modifyPPE :: MonadPretty v m => (PrettyPrintEnv -> PrettyPrintEnv) -> m a -> m a
modifyPPE = local . over _1
modifyTypeVars :: MonadPretty v m => (Set v -> Set v) -> m a -> m a
modifyTypeVars = local . over _2
-- | Add type variables to the set of variables that need to be avoided
addTypeVars :: MonadPretty v m => [v] -> m a -> m a
addTypeVars = modifyTypeVars . Set.union . Set.fromList
-- | Check if a list of type variables contains any variables that need to be
-- avoided
willCapture :: MonadPretty v m => [v] -> m Bool
willCapture vs = views _2 (not . Set.null . Set.intersection (Set.fromList vs))
runPretty :: Var v => PrettyPrintEnv -> Reader (PrettyPrintEnv, Set v) a -> a
runPretty ppe m = runReader m (ppe, mempty)

View File

@ -17,6 +17,7 @@ import qualified Unison.Name as Name
import Unison.Prelude
import Unison.PrettyPrintEnv (PrettyPrintEnv)
import qualified Unison.PrettyPrintEnv as PPE
import Unison.PrettyPrintEnv.MonadPretty (runPretty)
import Unison.PrettyPrintEnvDecl (PrettyPrintEnvDecl (..))
import Unison.Reference (Reference (DerivedId))
import qualified Unison.Referent as Referent
@ -73,9 +74,9 @@ prettyGADT env ctorType r name dd =
where
constructor (n, (_, _, t)) =
prettyPattern env ctorType name (ConstructorReference r n)
<> (fmt S.TypeAscriptionColon " :")
`P.hang` TypePrinter.pretty0 env Map.empty (-1) t
header = prettyEffectHeader name (DD.EffectDeclaration dd) <> (fmt S.ControlKeyword " where")
<> fmt S.TypeAscriptionColon " :"
`P.hang` TypePrinter.prettySyntax env t
header = prettyEffectHeader name (DD.EffectDeclaration dd) <> fmt S.ControlKeyword " where"
prettyPattern ::
PrettyPrintEnv ->
@ -86,7 +87,7 @@ prettyPattern ::
prettyPattern env ctorType namespace ref =
styleHashQualified''
(fmt (S.TermReference conRef))
( HQ.stripNamespace (fromMaybe "" $ Name.toText <$> HQ.toName namespace) $
( HQ.stripNamespace (maybe "" Name.toText (HQ.toName namespace)) $
PPE.termName env conRef
)
where
@ -106,26 +107,26 @@ prettyDataDecl (PrettyPrintEnvDecl unsuffixifiedPPE suffixifiedPPE) r name dd =
[0 ..]
(DD.constructors' dd)
where
constructor (n, (_, _, (Type.ForallsNamed' _ t))) = constructor' n t
constructor (n, (_, _, Type.ForallsNamed' _ t)) = constructor' n t
constructor (n, (_, _, t)) = constructor' n t
constructor' n t = case Type.unArrows t of
Nothing -> prettyPattern suffixifiedPPE CT.Data name (ConstructorReference r n)
Just ts -> case fieldNames unsuffixifiedPPE r name dd of
Nothing ->
P.group . P.hang' (prettyPattern suffixifiedPPE CT.Data name (ConstructorReference r n)) " " $
P.spaced (TypePrinter.prettyRaw suffixifiedPPE Map.empty 10 <$> init ts)
P.spaced (runPretty suffixifiedPPE (traverse (TypePrinter.prettyRaw Map.empty 10) (init ts)))
Just fs ->
P.group $
(fmt S.DelimiterChar "{ ")
fmt S.DelimiterChar "{ "
<> P.sep
((fmt S.DelimiterChar ",") <> " " `P.orElse` "\n ")
(fmt S.DelimiterChar "," <> " " `P.orElse` "\n ")
(field <$> zip fs (init ts))
<> (fmt S.DelimiterChar " }")
<> fmt S.DelimiterChar " }"
field (fname, typ) =
P.group $
styleHashQualified'' (fmt (S.TypeReference r)) fname
<> (fmt S.TypeAscriptionColon " :") `P.hang` TypePrinter.prettyRaw suffixifiedPPE Map.empty (-1) typ
header = prettyDataHeader name dd <> (fmt S.DelimiterChar (" = " `P.orElse` "\n = "))
<> fmt S.TypeAscriptionColon " :" `P.hang` runPretty suffixifiedPPE (TypePrinter.prettyRaw Map.empty (-1) typ)
header = prettyDataHeader name dd <> fmt S.DelimiterChar (" = " `P.orElse` "\n = ")
-- Comes up with field names for a data declaration which has the form of a
-- record, like `type Pt = { x : Int, y : Int }`. Works by generating the

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Unison.Syntax.TypePrinter
( pretty,
@ -23,6 +24,7 @@ import Unison.Prelude
import Unison.PrettyPrintEnv (PrettyPrintEnv)
import qualified Unison.PrettyPrintEnv as PrettyPrintEnv
import Unison.PrettyPrintEnv.FQN (Imports, elideFQN)
import Unison.PrettyPrintEnv.MonadPretty (MonadPretty, getPPE, runPretty, willCapture)
import Unison.Reference (Reference, pattern Builtin)
import Unison.Referent (Referent)
import Unison.Syntax.NamePrinter (styleHashQualified'')
@ -36,17 +38,17 @@ import qualified Unison.Var as Var
type SyntaxText = S.SyntaxText' Reference
pretty :: forall v a. (Var v) => PrettyPrintEnv -> Type v a -> Pretty ColorText
pretty ppe = PP.syntaxToColor . prettySyntax ppe
pretty :: Var v => PrettyPrintEnv -> Type v a -> Pretty ColorText
pretty ppe t = PP.syntaxToColor $ prettySyntax ppe t
prettySyntax :: forall v a. (Var v) => PrettyPrintEnv -> Type v a -> Pretty SyntaxText
prettySyntax ppe = pretty0 ppe mempty (-1)
prettySyntax :: Var v => PrettyPrintEnv -> Type v a -> Pretty SyntaxText
prettySyntax ppe = runPretty ppe . pretty0 Map.empty (-1)
prettyStr :: Var v => Maybe Width -> PrettyPrintEnv -> Type v a -> String
prettyStr (Just width) n t =
toPlain $ PP.render width $ PP.syntaxToColor $ pretty0 n Map.empty (-1) t
prettyStr Nothing n t =
toPlain $ PP.render maxBound $ PP.syntaxToColor $ pretty0 n Map.empty (-1) t
prettyStr (Just width) ppe t =
toPlain . PP.render width . PP.syntaxToColor . runPretty ppe $ pretty0 Map.empty (-1) t
prettyStr Nothing ppe t =
toPlain . PP.render maxBound . PP.syntaxToColor . runPretty ppe $ pretty0 Map.empty (-1) t
{- Explanation of precedence handling
@ -71,90 +73,103 @@ prettyStr Nothing n t =
-}
pretty0 ::
forall v a.
(Var v) =>
PrettyPrintEnv ->
forall v a m.
MonadPretty v m =>
Imports ->
Int ->
Type v a ->
Pretty SyntaxText
pretty0 n im p tp = prettyRaw n im p (cleanup (removePureEffects tp))
m (Pretty SyntaxText)
pretty0 im p tp = prettyRaw im p (cleanup (removePureEffects tp))
prettyRaw ::
forall v a.
(Var v) =>
PrettyPrintEnv ->
forall v a m.
MonadPretty v m =>
Imports ->
Int ->
Type v a ->
Pretty SyntaxText
m (Pretty SyntaxText)
-- p is the operator precedence of the enclosing context (a number from 0 to
-- 11, or -1 to avoid outer parentheses unconditionally). Function
-- application has precedence 10.
prettyRaw n im p tp = go n im p tp
prettyRaw im p tp = go im p tp
where
go :: PrettyPrintEnv -> Imports -> Int -> Type v a -> Pretty SyntaxText
go n im p tp = case stripIntroOuters tp of
Var' v -> fmt S.Var $ PP.text (Var.name v)
DD.TupleType' xs | length xs /= 1 -> PP.parenthesizeCommas $ map (go n im 0) xs
go :: Imports -> Int -> Type v a -> m (Pretty SyntaxText)
go im p tp = case stripIntroOuters tp of
Var' v -> pure . fmt S.Var $ PP.text (Var.name v)
DD.TupleType' xs | length xs /= 1 -> PP.parenthesizeCommas <$> traverse (go im 0) xs
-- Would be nice to use a different SyntaxHighlights color if the reference is an ability.
Ref' r -> styleHashQualified'' (fmt $ S.TypeReference r) $ elideFQN im (PrettyPrintEnv.typeName n r)
Cycle' _ _ -> fromString "error: TypeParser does not currently emit Cycle"
Abs' _ -> fromString "error: TypeParser does not currently emit Abs"
Ann' _ _ -> fromString "error: TypeParser does not currently emit Ann"
App' (Ref' (Builtin "Sequence")) x ->
PP.group $ (fmt S.DelimiterChar "[") <> go n im (-1) x <> (fmt S.DelimiterChar "]")
Ref' r -> do
n <- getPPE
pure $ styleHashQualified'' (fmt $ S.TypeReference r) $ elideFQN im (PrettyPrintEnv.typeName n r)
Cycle' _ _ -> pure $ fromString "bug: TypeParser does not currently emit Cycle"
Abs' _ -> pure $ fromString "bug: TypeParser does not currently emit Abs"
Ann' _ _ -> pure $ fromString "bug: TypeParser does not currently emit Ann"
App' (Ref' (Builtin "Sequence")) x -> do
x' <- go im (-1) x
pure $ PP.group $ fmt S.DelimiterChar "[" <> x' <> fmt S.DelimiterChar "]"
Apps' f xs ->
PP.parenthesizeIf (p >= 10) $
go n im 9 f
`PP.hang` PP.spaced
(go n im 10 <$> xs)
PP.parenthesizeIf (p >= 10)
<$> ( PP.hang <$> go im 9 f <*> (PP.spaced <$> traverse (go im 10) xs)
)
Effect1' e t ->
PP.parenthesizeIf (p >= 10) $ go n im 9 e <> " " <> go n im 10 t
PP.parenthesizeIf (p >= 10) <$> ((\x y -> x <> " " <> y) <$> go im 9 e <*> go im 10 t)
Effects' es -> effects (Just es)
ForallsNamed' vs' body ->
let vs = filter (\v -> Var.name v /= "()") vs'
in if p < 0 && all Var.universallyQuantifyIfFree vs
then go n im p body
else
paren (p >= 0) $
let vformatted = PP.sep " " (fmt S.Var . PP.text . Var.name <$> vs)
in (fmt S.TypeOperator "" <> vformatted <> fmt S.TypeOperator ".")
`PP.hang` go n im (-1) body
prettyForall p = do
let vformatted = PP.sep " " (fmt S.Var . PP.text . Var.name <$> vs)
PP.hang (fmt S.TypeOperator "" <> vformatted <> fmt S.TypeOperator ".") <$> go im p body
in -- if we're printing a type signature, and all the type variables
-- are universally quantified, then we can omit the `forall` keyword
-- only if the type variables are not bound in an outer scope
if p < 0 && all Var.universallyQuantifyIfFree vs
then ifM (willCapture vs) (prettyForall p) (go im p body)
else paren (p >= 0) <$> prettyForall (-1)
t@(Arrow' _ _) -> case t of
EffectfulArrows' (Ref' DD.UnitRef) rest ->
PP.parenthesizeIf (p >= 10) $ arrows True True rest
PP.parenthesizeIf (p >= 10) <$> arrows True True rest
EffectfulArrows' fst rest ->
case fst of
Var' v
| Var.name v == "()" ->
PP.parenthesizeIf (p >= 10) $ arrows True True rest
PP.parenthesizeIf (p >= 10) <$> arrows True True rest
_ ->
PP.parenthesizeIf (p >= 0) $
go n im 0 fst <> arrows False False rest
_ -> "error"
_ -> "error"
effects Nothing = mempty
effects (Just es) = PP.group $ fmt S.AbilityBraces "{" <> PP.commas (go n im 0 <$> es) <> (fmt S.AbilityBraces "}")
PP.parenthesizeIf (p >= 0)
<$> ((<>) <$> go im 0 fst <*> arrows False False rest)
_ -> pure . fromString $ "bug: unexpected Arrow form in prettyRaw: " <> show t
_ -> pure . fromString $ "bug: unexpected form in prettyRaw: " <> show tp
effects Nothing = pure mempty
effects (Just es) =
PP.group . (fmt S.AbilityBraces "{" <>) . (<> fmt S.AbilityBraces "}")
<$> (PP.commas <$> traverse (go im 0) es)
-- `first`: is this the first argument?
-- `mes`: list of effects
arrow delay first mes =
(if first then mempty else PP.softbreak <> fmt S.TypeOperator "->")
<> (if delay then (if first then fmt S.DelayForceChar "'" else fmt S.DelayForceChar " '") else mempty)
<> effects mes
<> if isJust mes || not delay && not first then " " else mempty
arrow delay first mes = do
es <- effects mes
pure $
(if first then mempty else PP.softbreak <> fmt S.TypeOperator "->")
<> (if delay then (if first then fmt S.DelayForceChar "'" else fmt S.DelayForceChar " '") else mempty)
<> es
<> if isJust mes || not delay && not first then " " else mempty
arrows delay first [(mes, Ref' DD.UnitRef)] = arrow delay first mes <> fmt S.Unit "()"
arrows delay first ((mes, Ref' DD.UnitRef) : rest) =
arrow delay first mes <> parenNoGroup delay (arrows True True rest)
arrows delay first ((mes, arg) : rest) =
arrow delay first mes
<> parenNoGroup
(delay && not (null rest))
(go n im 0 arg <> arrows False False rest)
arrows False False [] = mempty
arrows False True [] = mempty -- not reachable
arrows True _ [] = mempty -- not reachable
arrows ::
Bool ->
Bool ->
[(Maybe [Type v a], Type v a)] ->
m (Pretty SyntaxText)
arrows delay first [(mes, Ref' DD.UnitRef)] = (<> fmt S.Unit "()") <$> arrow delay first mes
arrows delay first ((mes, Ref' DD.UnitRef) : rest) = do
es <- arrow delay first mes
rest' <- arrows True True rest
pure $ es <> parenNoGroup delay rest'
arrows delay first ((mes, arg) : rest) = do
es <- arrow delay first mes
arg' <- go im 0 arg
rest' <- arrows False False rest
pure $ es <> parenNoGroup (delay && not (null rest)) (arg' <> rest')
arrows False False [] = pure mempty
arrows False True [] = pure mempty -- not reachable
arrows True _ [] = pure mempty -- not reachable
paren True s = PP.group $ fmt S.Parenthesis "(" <> s <> fmt S.Parenthesis ")"
paren False s = PP.group s
@ -166,61 +181,62 @@ fmt = PP.withSyntax
-- todo: provide sample output in comment
prettySignaturesCT ::
Var v =>
PrettyPrintEnv ->
MonadPretty v m =>
[(Referent, HashQualified Name, Type v a)] ->
[Pretty ColorText]
prettySignaturesCT env ts = map PP.syntaxToColor $ prettySignaturesST env ts
m [Pretty ColorText]
prettySignaturesCT ts = map PP.syntaxToColor <$> prettySignaturesST ts
prettySignaturesCTCollapsed ::
Var v =>
PrettyPrintEnv ->
MonadPretty v m =>
[(Referent, HashQualified Name, Type v a)] ->
Pretty ColorText
prettySignaturesCTCollapsed env ts =
PP.lines $
PP.group <$> prettySignaturesCT env ts
m (Pretty ColorText)
prettySignaturesCTCollapsed ts =
PP.lines
. map PP.group
<$> prettySignaturesCT ts
prettySignaturesST ::
Var v =>
PrettyPrintEnv ->
MonadPretty v m =>
[(Referent, HashQualified Name, Type v a)] ->
[Pretty SyntaxText]
prettySignaturesST env ts =
PP.align [(name r hq, sig typ) | (r, hq, typ) <- ts]
m [Pretty SyntaxText]
prettySignaturesST ts =
PP.align <$> traverse (\(r, hq, typ) -> (name r hq,) <$> sig typ) ts
where
name r hq =
styleHashQualified'' (fmt $ S.TermReference r) hq
sig typ =
(fmt S.TypeAscriptionColon ": " <> pretty0 env Map.empty (-1) typ)
`PP.orElse` (fmt S.TypeAscriptionColon ": " <> PP.indentNAfterNewline 2 (pretty0 env Map.empty (-1) typ))
sig typ = do
t <- pretty0 Map.empty (-1) typ
let col = fmt S.TypeAscriptionColon ": "
pure $ (col <> t) `PP.orElse` (col <> PP.indentNAfterNewline 2 t)
-- todo: provide sample output in comment; different from prettySignatures'
prettySignaturesAlt' ::
Var v =>
PrettyPrintEnv ->
forall a v m.
MonadPretty v m =>
[([HashQualified Name], Type v a)] ->
[Pretty ColorText]
prettySignaturesAlt' env ts =
map PP.syntaxToColor $
PP.align
[ ( PP.commas . fmap (\name -> styleHashQualified'' (fmt $ S.HashQualifier name) name) $ names,
(fmt S.TypeAscriptionColon ": " <> pretty0 env Map.empty (-1) typ)
`PP.orElse` ( fmt S.TypeAscriptionColon ": "
<> PP.indentNAfterNewline 2 (pretty0 env Map.empty (-1) typ)
)
m [Pretty ColorText]
prettySignaturesAlt' ts =
do
ts' <- traverse f ts
pure $ map PP.syntaxToColor $ PP.align ts'
where
f :: ([HashQualified Name], Type v a) -> m (Pretty SyntaxText, Pretty SyntaxText)
f (names, typ) = do
typ' <- pretty0 Map.empty (-1) typ
let col = fmt S.TypeAscriptionColon ": "
pure
( PP.commas . fmap (\name -> styleHashQualified'' (fmt $ S.HashQualifier name) name) $ names,
(col <> typ') `PP.orElse` (col <> PP.indentNAfterNewline 2 typ')
)
| (names, typ) <- ts
]
-- prettySignatures'' :: Var v => PrettyPrintEnv -> [(Name, Type v a)] -> [Pretty ColorText]
-- prettySignatures'' :: Var v => [(Name, Type v a)] -> [Pretty ColorText]
-- prettySignatures'' env ts = prettySignatures' env (first HQ.fromName <$> ts)
prettySignaturesAlt ::
Var v =>
PrettyPrintEnv ->
MonadPretty v m =>
[([HashQualified Name], Type v a)] ->
Pretty ColorText
prettySignaturesAlt env ts =
PP.lines $
PP.group <$> prettySignaturesAlt' env ts
m (Pretty ColorText)
prettySignaturesAlt ts =
PP.lines
. map PP.group
<$> prettySignaturesAlt' ts

View File

@ -326,13 +326,13 @@ removeSyntheticTypeVars typ =
go v
| Var.User _ <- Var.typeOf v = pure v -- user-provided type variables left alone
| otherwise = do
(used, curMappings) <- get
case Map.lookup v curMappings of
Nothing -> do
let v' = pickName used (Var.typeOf v)
put (Set.insert v' used, Map.insert v v' curMappings)
pure v'
Just v' -> pure v'
(used, curMappings) <- get
case Map.lookup v curMappings of
Nothing -> do
let v' = pickName used (Var.typeOf v)
put (Set.insert v' used, Map.insert v v' curMappings)
pure v'
Just v' -> pure v'
pickName used vt = ABT.freshIn used . Var.named $ case vt of
-- for each type of variable, we have some preferred variable
-- names that we like, if they aren't already being used
@ -671,21 +671,21 @@ extend' e c@(Context ctx) = Context . (: ctx) . (e,) <$> i'
| Set.member v vs -> crash $ "variable " <> show v <> " already defined in the context"
| not (wellformedType c t) -> crash $ "type " <> show t <> " is not well-formed wrt the context"
| otherwise ->
pure $
Info (Set.insert v es) (Map.insert v sa ses) us uas (Set.insert v vs) pvs
pure $
Info (Set.insert v es) (Map.insert v sa ses) us uas (Set.insert v vs) pvs
-- VarCtx - ensure `v` is fresh, and annotation is well-formed wrt the context
Ann v t
| Set.member v vs -> crash $ "variable " <> show v <> " already defined in the context"
| not (wellformedType c t) -> crash $ "type " <> show t <> " is not well-formed wrt the context"
| otherwise ->
pure $
Info
es
ses
us
(Map.insert v t uas)
(Set.insert v vs)
((if Set.null (Type.freeVars t) then Set.insert v else id) pvs)
pure $
Info
es
ses
us
(Map.insert v t uas)
(Set.insert v vs)
((if Set.null (Type.freeVars t) then Set.insert v else id) pvs)
-- MarkerCtx - note that since a Marker is always the first mention of a variable, suffices to
-- just check that `v` is not previously mentioned
Marker v ->
@ -874,7 +874,7 @@ synthesizeApp ::
M v loc (Type v loc, Wanted v loc)
synthesizeApp _ ft arg
| debugEnabled && traceShow ("synthesizeApp" :: String, ft, arg) False =
undefined
undefined
synthesizeApp fun (Type.stripIntroOuters -> Type.Effect'' es ft) argp@(arg, argNum) =
scope (InSynthesizeApp ft arg argNum) $ do
(t, w) <- go ft
@ -1051,10 +1051,10 @@ synthesizeWanted (Term.Ann' (Term.Ref' _) t)
--
-- Top level references don't have their own effects.
| Set.null s = do
t <- existentializeArrows t
-- See note about ungeneralizing above in the Var case.
t <- ungeneralize t
pure (discard t, [])
t <- existentializeArrows t
-- See note about ungeneralizing above in the Var case.
t <- ungeneralize t
pure (discard t, [])
| otherwise = compilerCrash $ FreeVarsInTypeAnnotation s
where
s = ABT.freeVars t
@ -1158,59 +1158,59 @@ synthesizeWanted e
| Term.TermLink' _ <- e = pure (Type.termLink l, [])
| Term.TypeLink' _ <- e = pure (Type.typeLink l, [])
| Term.Blank' blank <- e = do
v <- freshenVar Var.blank
appendContext [Var (TypeVar.Existential blank v)]
pure (existential' l blank v, [])
v <- freshenVar Var.blank
appendContext [Var (TypeVar.Existential blank v)]
pure (existential' l blank v, [])
| Term.List' v <- e = do
ft <- vectorConstructorOfArity l (Foldable.length v)
case Foldable.toList v of
[] -> pure (ft, [])
v1 : _ ->
scope (InVectorApp (ABT.annotation v1)) $
synthesizeApps e ft v
ft <- vectorConstructorOfArity l (Foldable.length v)
case Foldable.toList v of
[] -> pure (ft, [])
v1 : _ ->
scope (InVectorApp (ABT.annotation v1)) $
synthesizeApps e ft v
-- ->I=> (Full Damas Milner rule)
| Term.Lam' body <- e = do
-- arya: are there more meaningful locations we could put into and
-- pull out of the abschain?)
[arg, i, e, o] <-
sequence
[ ABT.freshen body freshenVar,
freshenVar (ABT.variable body),
freshenVar Var.inferAbility,
freshenVar Var.inferOutput
]
let it = existential' l B.Blank i
ot = existential' l B.Blank o
et = existential' l B.Blank e
appendContext $
[existential i, existential e, existential o, Ann arg it]
body' <- pure $ ABT.bindInheritAnnotation body (Term.var () arg)
if Term.isLam body'
then checkWithAbilities [] body' ot
else checkWithAbilities [et] body' ot
ctx <- getContext
let t = apply ctx $ Type.arrow l it (Type.effect l [et] ot)
pure (t, [])
-- arya: are there more meaningful locations we could put into and
-- pull out of the abschain?)
[arg, i, e, o] <-
sequence
[ ABT.freshen body freshenVar,
freshenVar (ABT.variable body),
freshenVar Var.inferAbility,
freshenVar Var.inferOutput
]
let it = existential' l B.Blank i
ot = existential' l B.Blank o
et = existential' l B.Blank e
appendContext $
[existential i, existential e, existential o, Ann arg it]
body' <- pure $ ABT.bindInheritAnnotation body (Term.var () arg)
if Term.isLam body'
then checkWithAbilities [] body' ot
else checkWithAbilities [et] body' ot
ctx <- getContext
let t = apply ctx $ Type.arrow l it (Type.effect l [et] ot)
pure (t, [])
| Term.If' cond t f <- e = do
cwant <- scope InIfCond $ check cond (Type.boolean l)
(ty, bwant) <-
scope (InIfBody $ ABT.annotation t) $
synthesizeApps e (Type.iff2 l) [t, f]
(ty,) <$> coalesceWanted bwant cwant
cwant <- scope InIfCond $ check cond (Type.boolean l)
(ty, bwant) <-
scope (InIfBody $ ABT.annotation t) $
synthesizeApps e (Type.iff2 l) [t, f]
(ty,) <$> coalesceWanted bwant cwant
| Term.And' a b <- e =
scope InAndApp $ synthesizeApps e (Type.andor' l) [a, b]
scope InAndApp $ synthesizeApps e (Type.andor' l) [a, b]
| Term.Or' a b <- e =
scope InOrApp $ synthesizeApps e (Type.andor' l) [a, b]
scope InOrApp $ synthesizeApps e (Type.andor' l) [a, b]
| Term.Match' scrutinee cases <- e = do
(scrutineeType, swant) <- synthesize scrutinee
outputTypev <- freshenVar (Var.named "match-output")
let outputType = existential' l B.Blank outputTypev
appendContext [existential outputTypev]
cwant <- checkCases scrutineeType outputType cases
want <- coalesceWanted cwant swant
ctx <- getContext
pure $ (apply ctx outputType, want)
(scrutineeType, swant) <- synthesize scrutinee
outputTypev <- freshenVar (Var.named "match-output")
let outputType = existential' l B.Blank outputTypev
appendContext [existential outputTypev]
cwant <- checkCases scrutineeType outputType cases
want <- coalesceWanted cwant swant
ctx <- getContext
pure $ (apply ctx outputType, want)
where
l = loc e
synthesizeWanted _e = compilerCrash PatternMatchFailure
@ -1427,17 +1427,17 @@ checkPattern scrutineeType p =
-- 'otherwise' still needs to be covered for exhaustivity, however.
| Type.Apps' (Type.Ref' req) [_, r] <- scrutineeType,
req == Type.effectRef ->
checkPattern r p
checkPattern r p
| otherwise -> do
vt <- lift $ do
v <- freshenVar Var.inferPatternPureV
e <- freshenVar Var.inferPatternPureE
let vt = existentialp loc v
let et = existentialp loc e
appendContext [existential v, existential e]
subtype (Type.effectV loc (loc, et) (loc, vt)) scrutineeType
applyM vt
checkPattern vt p
vt <- lift $ do
v <- freshenVar Var.inferPatternPureV
e <- freshenVar Var.inferPatternPureE
let vt = existentialp loc v
let et = existentialp loc e
appendContext [existential v, existential e]
subtype (Type.effectV loc (loc, et) (loc, vt)) scrutineeType
applyM vt
checkPattern vt p
-- ex: { Stream.emit x -> k } -> ...
Pattern.EffectBind loc ref args k -> do
-- scrutineeType should be a supertype of `Effect e vt`
@ -1460,15 +1460,15 @@ checkPattern scrutineeType p =
Type.Effect'' [et] it
-- expecting scrutineeType to be `Effect et vt`
| Type.Apps' _ [eff, vt] <- st -> do
-- ensure that the variables in `et` unify with those from
-- the scrutinee.
lift $ abilityCheck' [eff] [et]
let kt =
Type.arrow
(Pattern.loc k)
it
(Type.effect (Pattern.loc k) [eff] vt)
(vs ++) <$> checkPattern kt k
-- ensure that the variables in `et` unify with those from
-- the scrutinee.
lift $ abilityCheck' [eff] [et]
let kt =
Type.arrow
(Pattern.loc k)
it
(Type.effect (Pattern.loc k) [eff] vt)
(vs ++) <$> checkPattern kt k
| otherwise -> lift . compilerCrash $ PatternMatchFailure
_ ->
lift . compilerCrash $
@ -1646,12 +1646,12 @@ tweakEffects ::
M v loc ([v], Type v loc)
tweakEffects v0 t0
| isEffectVar v0 t0 && isVariant v0 t0 =
rewrite (Just False) t0 >>= \case
([], ty) ->
freshenTypeVar v0 >>= \out -> finish [out] ty
(vs, ty) -> finish vs ty
rewrite (Just False) t0 >>= \case
([], ty) ->
freshenTypeVar v0 >>= \out -> finish [out] ty
(vs, ty) -> finish vs ty
| otherwise =
freshenTypeVar v0 >>= \out -> finish [out] t0
freshenTypeVar v0 >>= \out -> finish [out] t0
where
negative = fromMaybe False
@ -1665,27 +1665,27 @@ tweakEffects v0 t0
rewrite p ty
| Type.ForallNamed' v t <- ty,
v0 /= v =
second (Type.forall a v) <$> rewrite p t
second (Type.forall a v) <$> rewrite p t
| Type.Arrow' i o <- ty = do
(vis, i) <- rewrite (not <$> p) i
(vos, o) <- rewrite p o
pure (vis ++ vos, Type.arrow a i o)
(vis, i) <- rewrite (not <$> p) i
(vos, o) <- rewrite p o
pure (vis ++ vos, Type.arrow a i o)
| Type.Effect1' e t <- ty = do
(ves, e) <- rewrite p e
(vts, t) <- rewrite p t
pure (ves ++ vts, Type.effect1 a e t)
(ves, e) <- rewrite p e
(vts, t) <- rewrite p t
pure (ves ++ vts, Type.effect1 a e t)
| Type.Effects' es <- ty = do
ess <- traverse (rewrite p) es
let es = snd <$> ess; ves = fst =<< ess
pure (ves, Type.effects a es)
ess <- traverse (rewrite p) es
let es = snd <$> ess; ves = fst =<< ess
pure (ves, Type.effects a es)
| Type.Var' v <- ty,
v0 == v && negative p = do
u <- freshenTypeVar v0
pure ([u], existential' (loc ty) B.Blank u)
u <- freshenTypeVar v0
pure ([u], existential' (loc ty) B.Blank u)
| Type.App' f x <- ty = do
(vfs, f) <- rewrite p f
(vxs, x) <- rewrite Nothing x
pure (vfs ++ vxs, Type.app (loc ty) f x)
(vfs, f) <- rewrite p f
(vxs, x) <- rewrite Nothing x
pure (vfs ++ vxs, Type.app (loc ty) f x)
| otherwise = pure ([], ty)
where
a = loc ty
@ -1759,7 +1759,7 @@ generalizeExistentials ctx ty0 = generalizeP pred ctx ty
pred e
| pe@(Just (tv, _)) <- existentialP e,
tv `Set.member` fvs =
pe
pe
| otherwise = Nothing
generalizeP ::
@ -1775,13 +1775,13 @@ generalizeP p ctx0 ty = foldr gen (applyCtx ctx0 ty) ctx
gen (tv, v) t
| tv `ABT.isFreeIn` t =
-- location of the forall is just the location of the input type
-- and the location of each quantified variable is just inherited
-- from its source location
Type.forall
(loc t)
(TypeVar.Universal v)
(ABT.substInheritAnnotation tv (universal' () v) t)
-- location of the forall is just the location of the input type
-- and the location of each quantified variable is just inherited
-- from its source location
Type.forall
(loc t)
(TypeVar.Universal v)
(ABT.substInheritAnnotation tv (universal' () v) t)
-- don't bother introducing a forall if type variable is unused
| otherwise = t
@ -1867,20 +1867,20 @@ coalesceWanted' ::
coalesceWanted' _ [] old = pure old
coalesceWanted' keep ((loc, n) : new) old
| Just (_, o) <- find (headMatch n . snd) old = do
equate n o
coalesceWanted new old
equate n o
coalesceWanted new old
| Type.Var' u <- n = do
(new, old) <-
-- Only add existential variables to the wanted list if they
-- occur in a type we're trying to infer in the context. If
-- they don't, they were added as instantiations of polymorphic
-- types that might as well just be instantiated to {}.
if keep u
then pure (new, (loc, n) : old)
else do
defaultAbility n
pure (new, old)
coalesceWanted new old
(new, old) <-
-- Only add existential variables to the wanted list if they
-- occur in a type we're trying to infer in the context. If
-- they don't, they were added as instantiations of polymorphic
-- types that might as well just be instantiated to {}.
if keep u
then pure (new, (loc, n) : old)
else do
defaultAbility n
pure (new, old)
coalesceWanted new old
| otherwise = coalesceWanted' keep new ((loc, n) : old)
-- Wrapper for coalesceWanted' that ensures both lists are fully
@ -1922,10 +1922,10 @@ pruneWanted ::
pruneWanted acc [] _ = pure acc
pruneWanted acc ((loc, w) : want) handled
| Just h <- find (headMatch w) handled = do
subtype w h
want <- expandWanted want
handled <- expandAbilities handled
pruneWanted acc want handled
subtype w h
want <- expandWanted want
handled <- expandAbilities handled
pruneWanted acc want handled
| otherwise = pruneWanted ((loc, w) : acc) want handled
-- | Processes wanted effects with respect to a portion of context
@ -1947,7 +1947,7 @@ substAndDefaultWanted want ctx
| want <- (fmap . fmap) (applyCtx ctx) want,
want <- filter q want,
repush <- filter keep ctx =
appendContext repush *> coalesceWanted want []
appendContext repush *> coalesceWanted want []
where
isExistential TypeVar.Existential {} = True
isExistential _ = False
@ -2064,14 +2064,14 @@ relax t = relax' True v t
relax' :: Var v => Ord loc => Bool -> v -> Type v loc -> Type v loc
relax' nonArrow v t
| Type.Arrow' i o <- t =
Type.arrow (ABT.annotation t) i $ relax' nonArrow v o
Type.arrow (ABT.annotation t) i $ relax' nonArrow v o
| Type.ForallsNamed' vs b <- t =
Type.foralls loc vs $ relax' nonArrow v b
Type.foralls loc vs $ relax' nonArrow v b
| Type.Effect' es r <- t,
Type.Arrow' i o <- r =
Type.effect loc es . Type.arrow (ABT.annotation t) i $ relax' nonArrow v o
Type.effect loc es . Type.arrow (ABT.annotation t) i $ relax' nonArrow v o
| Type.Effect' es r <- t =
if any open es then t else Type.effect loc (tv : es) r
if any open es then t else Type.effect loc (tv : es) r
| nonArrow = Type.effect loc [tv] t
| otherwise = t
where
@ -2165,11 +2165,11 @@ check m0 t0 = scope (InCheck m0 t0) $ do
Left m -> failWith $ DuplicateDefinitions m
Right m
| not (wellformedType ctx t0) ->
failWith $ IllFormedType ctx
failWith $ IllFormedType ctx
| Type.Var' TypeVar.Existential {} <- t0 ->
applyM t0 >>= checkWanted [] m
applyM t0 >>= checkWanted [] m
| otherwise ->
checkWanted [] m (Type.stripIntroOuters t0)
checkWanted [] m (Type.stripIntroOuters t0)
-- | `subtype ctx t1 t2` returns successfully if `t1` is a subtype of `t2`.
-- This may have the effect of altering the context.
@ -2184,10 +2184,10 @@ subtype tx ty = scope (InSubtype tx ty) $ do
go _ (Type.Ref' r) (Type.Ref' r2) | r == r2 = pure () -- `Unit`
go ctx t1@(Type.Var' (TypeVar.Universal v1)) t2@(Type.Var' (TypeVar.Universal v2)) -- `Var`
| v1 == v2 && wellformedType ctx t1 && wellformedType ctx t2 =
pure ()
pure ()
go ctx t1@(Type.Var' (TypeVar.Existential _ v1)) t2@(Type.Var' (TypeVar.Existential _ v2)) -- `Exvar`
| v1 == v2 && wellformedType ctx t1 && wellformedType ctx t2 =
pure ()
pure ()
go _ (Type.Arrow' i1 o1) (Type.Arrow' i2 o2) = do
-- `-->`
subtype i2 i1
@ -2226,13 +2226,13 @@ subtype tx ty = scope (InSubtype tx ty) $ do
go ctx (Type.Var' (TypeVar.Existential b v)) t -- `InstantiateL`
| Set.member v (existentials ctx)
&& notMember v (Type.freeVars t) = do
e <- extendExistential Var.inferAbility
instantiateL b v (relax' False e t)
e <- extendExistential Var.inferAbility
instantiateL b v (relax' False e t)
go ctx t (Type.Var' (TypeVar.Existential b v)) -- `InstantiateR`
| Set.member v (existentials ctx)
&& notMember v (Type.freeVars t) = do
e <- extendExistential Var.inferAbility
instantiateR (relax' False e t) b v
e <- extendExistential Var.inferAbility
instantiateR (relax' False e t) b v
go _ (Type.Effects' es1) (Type.Effects' es2) =
subAbilities ((,) Nothing <$> es1) es2
go _ t t2@(Type.Effects' _) | expand t = subtype (Type.effects (loc t) [t]) t2
@ -2255,7 +2255,7 @@ equate t1 t2 = scope (InEquate t1 t2) $ do
where
guardWF ctx t@(Type.Var' _)
| not $ wellformedType ctx t =
failWith (TypeMismatch ctx)
failWith (TypeMismatch ctx)
guardWF _ _ = pure ()
equate0 ::
@ -2269,20 +2269,20 @@ equate0 t1@(Type.Var' tv1) t2@(Type.Var' tv2)
| TypeVar.Universal v1 <- tv1,
TypeVar.Universal v2 <- tv2,
v1 == v2 =
pure ()
pure ()
| TypeVar.Existential b1 v1 <- tv1,
TypeVar.Existential b2 v2 <- tv2 =
if v1 == v2
then pure ()
else do
ctx <- getContext
if ordered ctx v1 v2
then instantiateL b2 v2 t1
else instantiateL b1 v1 t2
if v1 == v2
then pure ()
else do
ctx <- getContext
if ordered ctx v1 v2
then instantiateL b2 v2 t1
else instantiateL b1 v1 t2
| TypeVar.Existential b v1 <- tv1 =
instantiateL b v1 t2
instantiateL b v1 t2
| TypeVar.Existential b v2 <- tv2 =
instantiateL b v2 t1
instantiateL b v2 t1
equate0 (Type.Forall' t01) (Type.Forall' t02) = do
v <- ABT.freshen t02 freshenTypeVar
markThenRetract0 v $ do
@ -2307,12 +2307,12 @@ equate0 (Type.Effect1' e1 a1) (Type.Effect1' e2 a2) = do
equate a1 a2
equate0 (Type.Var' (TypeVar.Existential b v)) t
| notMember v (Type.freeVars t) =
-- subtyping relaxes here, should equality
instantiateL b v t
-- subtyping relaxes here, should equality
instantiateL b v t
equate0 t (Type.Var' (TypeVar.Existential b v))
| notMember v (Type.freeVars t) =
-- subtyping relaxes here, should equality
instantiateL b v t
-- subtyping relaxes here, should equality
instantiateL b v t
equate0 (Type.Effects' es1) (Type.Effects' es2) =
equateAbilities es1 es2
equate0 y1 y2 = do
@ -2340,8 +2340,8 @@ instantiateL blank v (Type.stripIntroOuters -> t) =
go ctx = case t of
Type.Var' (TypeVar.Existential _ v2)
| ordered ctx v v2 -> -- InstLReach (both are existential, set v2 = v)
solve ctx v2 (Type.Monotype (existentialp (loc t) v))
>>= maybe (failWith $ TypeMismatch ctx) setContext
solve ctx v2 (Type.Monotype (existentialp (loc t) v))
>>= maybe (failWith $ TypeMismatch ctx) setContext
Type.Arrow' i o -> do
-- InstLArr
[i', o'] <- traverse freshenVar [nameFrom Var.inferInput i, nameFrom Var.inferOutput o]
@ -2431,18 +2431,18 @@ refineEffectVar _ [] _ _ _ = pure ()
refineEffectVar l es blank v tv
| ev <- TypeVar.Existential blank v,
any (\e -> ev `Set.member` Type.freeVars e) es =
getContext >>= failWith . AbilityCheckFailure [tv] es
getContext >>= failWith . AbilityCheckFailure [tv] es
| otherwise = do
slack <- freshenVar Var.inferAbility
evs <- traverse (\e -> freshenVar (nameFrom Var.inferAbility e)) es
let locs = loc <$> es
es' = zipWith existentialp locs evs
t' = Type.effects l (existentialp l slack : es')
s = Solved blank v (Type.Monotype t')
vs = existential slack : fmap existential evs
replaceContext (existential v) (vs ++ [s])
Foldable.for_ (es `zip` evs) $ \(e, ev) ->
getContext >>= \ctx -> instantiateR (apply ctx e) B.Blank ev
slack <- freshenVar Var.inferAbility
evs <- traverse (\e -> freshenVar (nameFrom Var.inferAbility e)) es
let locs = loc <$> es
es' = zipWith existentialp locs evs
t' = Type.effects l (existentialp l slack : es')
s = Solved blank v (Type.Monotype t')
vs = existential slack : fmap existential evs
replaceContext (existential v) (vs ++ [s])
Foldable.for_ (es `zip` evs) $ \(e, ev) ->
getContext >>= \ctx -> instantiateR (apply ctx e) B.Blank ev
-- | Instantiate the given existential such that it is
-- a supertype of the given type, updating the context
@ -2461,8 +2461,8 @@ instantiateR (Type.stripIntroOuters -> t) blank v =
go ctx = case t of
Type.Var' (TypeVar.Existential _ v2)
| ordered ctx v v2 -> -- InstRReach (both are existential, set v2 = v)
solve ctx v2 (Type.Monotype (existentialp (loc t) v))
>>= maybe (failWith $ TypeMismatch ctx) setContext
solve ctx v2 (Type.Monotype (existentialp (loc t) v))
>>= maybe (failWith $ TypeMismatch ctx) setContext
Type.Arrow' i o -> do
-- InstRArrow
[i', o'] <- traverse freshenVar [nameFrom Var.inferInput i, nameFrom Var.inferOutput o]
@ -2570,15 +2570,15 @@ matchConcrete ::
matchConcrete common acc [] _ = pure (reverse acc, common)
matchConcrete common acc (l : ls) rs
| Just v <- find (headMatch l) common = do
equate v l
ls <- expandAbilities ls
rs <- expandAbilities rs
matchConcrete common acc ls rs
equate v l
ls <- expandAbilities ls
rs <- expandAbilities rs
matchConcrete common acc ls rs
| Just v <- find (headMatch l) rs = do
equate v l
ls <- expandAbilities ls
rs <- expandAbilities rs
matchConcrete (l : common) acc ls rs
equate v l
ls <- expandAbilities ls
rs <- expandAbilities rs
matchConcrete (l : common) acc ls rs
| otherwise = matchConcrete common (l : acc) ls rs
pruneConcrete ::
@ -2592,10 +2592,10 @@ pruneConcrete ::
pruneConcrete _ acc [] _ = pure (reverse acc)
pruneConcrete missing acc ((loc, w) : ws) have
| Just v <- find (headMatch w) have = do
subtype v w `orElse` missing loc w
ws <- expandWanted ws
have <- expandAbilities have
pruneConcrete missing acc ws have
subtype v w `orElse` missing loc w
ws <- expandWanted ws
have <- expandAbilities have
pruneConcrete missing acc ws have
| otherwise = pruneConcrete missing ((loc, w) : acc) ws have
matchVariables ::
@ -2608,7 +2608,7 @@ matchVariables ::
([Type v loc], [Type v loc], [Type v loc])
matchVariables com acc (l : ls) rs
| isExistential l && any (== l) rs =
matchVariables (l : com) acc (filter (/= l) ls) (filter (/= l) rs)
matchVariables (l : com) acc (filter (/= l) ls) (filter (/= l) rs)
| otherwise = matchVariables com (l : acc) ls rs
where
isExistential (Type.Var' TypeVar.Existential {}) = True
@ -2693,11 +2693,11 @@ equateAbilities ls rs =
(vrs, crs) = partition isExistential rs
mlSlack
| [t@(Type.Var' (TypeVar.Existential b v))] <- vls =
Just (loc t, b, v)
Just (loc t, b, v)
| otherwise = Nothing
mrSlack
| [t@(Type.Var' (TypeVar.Existential b v))] <- vrs =
Just (loc t, b, v)
Just (loc t, b, v)
| otherwise = Nothing
in case liftA2 (,) mlSlack mrSlack of
Just ((ll, bl, lSlack), (lr, br, rSlack)) ->
@ -2706,7 +2706,7 @@ equateAbilities ls rs =
| [t@(Type.Var' (TypeVar.Existential bc cv))] <- com,
null vls,
null vrs ->
refine True [(loc t, bc, cv)] [cls ++ crs]
refine True [(loc t, bc, cv)] [cls ++ crs]
| [] <- com, null rs, null cls -> for_ vls defaultAbility
| [] <- com, null ls, null crs -> for_ vrs defaultAbility
| [] <- com, Just pl <- mlSlack, null cls -> refine False [pl] [rs]
@ -2738,7 +2738,8 @@ equateAbilities ls rs =
| u == v = EQ
| ordered ctx u v = LT
| otherwise = GT
cn | common = [Var.inferAbility] | otherwise = []
cn | common = [Var.inferAbility]
| otherwise = []
subAbilities ::
Var v =>
@ -2787,10 +2788,10 @@ subAmbient ::
subAmbient die ambient r
-- find unsolved existential, 'e, that appears in ambient
| (b, e') : _ <- unsolveds = do
-- introduce fresh existential 'e2 to context
e2' <- extendExistential e'
let et2 = Type.effects (loc r) [r, existentialp (loc r) e2']
instantiateR et2 b e' `orElse` die
-- introduce fresh existential 'e2 to context
e2' <- extendExistential e'
let et2 = Type.effects (loc r) [r, existentialp (loc r) e2']
instantiateR et2 b e' `orElse` die
| otherwise = die
where
unsolveds = (ambient >>= Type.flattenEffects >>= vars)
@ -2811,19 +2812,19 @@ abilityCheckSingle die ambient r
-- Ex: given `a`, where there's an exact variable
-- If yes for `a` in ambient, do `subtype a r` and done.
| Just a <- find (headMatch r) ambient =
subtype a r `orElse` die
subtype a r `orElse` die
-- It's an unsolved existential, instantiate it to all of ambient
| Type.Var' tv@(TypeVar.Existential b v) <- r =
let et2 = Type.effects (loc r) ambient
acyclic
| Set.member tv (Type.freeVars et2) =
-- just need to trigger `orElse` in this case
getContext >>= failWith . TypeMismatch
| otherwise = instantiateR et2 b v
in -- instantiate it to `{}` if can't cover all of ambient
acyclic
`orElse` instantiateR (Type.effects (loc r) []) b v
`orElse` die
let et2 = Type.effects (loc r) ambient
acyclic
| Set.member tv (Type.freeVars et2) =
-- just need to trigger `orElse` in this case
getContext >>= failWith . TypeMismatch
| otherwise = instantiateR et2 b v
in -- instantiate it to `{}` if can't cover all of ambient
acyclic
`orElse` instantiateR (Type.effects (loc r) []) b v
`orElse` die
| otherwise = subAmbient die ambient r
headMatch :: Var v => Ord loc => Type v loc -> Type v loc -> Bool

View File

@ -1,6 +1,6 @@
cabal-version: 1.12
-- This file has been generated from package.yaml by hpack version 0.34.4.
-- This file has been generated from package.yaml by hpack version 0.35.0.
--
-- see: https://github.com/sol/hpack
@ -93,6 +93,7 @@ library
Unison.Parsers
Unison.PrettyPrintEnv
Unison.PrettyPrintEnv.FQN
Unison.PrettyPrintEnv.MonadPretty
Unison.PrettyPrintEnv.Names
Unison.PrettyPrintEnv.Util
Unison.PrettyPrintEnvDecl
@ -298,9 +299,9 @@ library
, x509-system
, yaml
, zlib
default-language: Haskell2010
if flag(optimized)
ghc-options: -funbox-strict-fields -O2
default-language: Haskell2010
test-suite parser-typechecker-tests
type: exitcode-stdio-1.0
@ -486,6 +487,6 @@ test-suite parser-typechecker-tests
, x509-system
, yaml
, zlib
default-language: Haskell2010
if flag(optimized)
ghc-options: -funbox-strict-fields -O2
default-language: Haskell2010

View File

@ -1,5 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
module Unison.CommandLine.DisplayValues where
@ -17,6 +16,7 @@ import qualified Unison.ConstructorType as CT
import qualified Unison.DataDeclaration as DD
import Unison.Prelude
import qualified Unison.PrettyPrintEnv as PPE
import Unison.PrettyPrintEnv.MonadPretty (runPretty)
import qualified Unison.PrettyPrintEnv.Util as PPE
import qualified Unison.PrettyPrintEnvDecl as PPE
import Unison.Reference (Reference)
@ -246,10 +246,9 @@ displayPretty pped terms typeOf eval types tm = go tm
typeOf r >>= \case
Nothing -> pure $ termName (PPE.suffixifiedPPE pped) r
Just typ ->
pure . P.group $
TypePrinter.prettySignaturesCTCollapsed
(PPE.suffixifiedPPE pped)
[(r, PPE.termName (PPE.suffixifiedPPE pped) r, typ)]
pure . P.group
. runPretty (PPE.suffixifiedPPE pped)
$ TypePrinter.prettySignaturesCTCollapsed [(r, PPE.termName (PPE.suffixifiedPPE pped) r, typ)]
goColor c = case c of
DD.AnsiColorBlack -> P.black
@ -311,9 +310,8 @@ displayDoc pped terms typeOf evaluated types = go
typeOf r >>= \case
Nothing -> pure $ termName (PPE.unsuffixifiedPPE pped) r
Just typ ->
pure . P.group $
pure . P.group . runPretty (PPE.suffixifiedPPE pped) $
TypePrinter.prettySignaturesCTCollapsed
(PPE.suffixifiedPPE pped)
[(r, PPE.termName (PPE.unsuffixifiedPPE pped) r, typ)]
prettyEval terms r = case r of
Referent.Ref (Reference.Builtin n) -> pure . P.syntaxToColor $ P.text n
@ -329,7 +327,7 @@ displayDoc pped terms typeOf evaluated types = go
let ppe = PPE.declarationPPE pped ref
in terms ref >>= \case
Nothing -> pure $ "😶 Missing term source for: " <> termName ppe r
Just tm -> pure . P.syntaxToColor $ P.group $ TP.prettyBinding ppe (PPE.termName ppe r) tm
Just tm -> pure . P.syntaxToColor . P.group . runPretty ppe $ TP.prettyBinding (PPE.termName ppe r) tm
Referent.Con (ConstructorReference r _) _ -> prettyType r
prettyType r =
let ppe = PPE.declarationPPE pped r

View File

@ -102,6 +102,7 @@ import qualified Unison.NamesWithHistory as Names
import Unison.Parser.Ann (Ann, startingLine)
import Unison.Prelude
import qualified Unison.PrettyPrintEnv as PPE
import Unison.PrettyPrintEnv.MonadPretty (runPretty)
import qualified Unison.PrettyPrintEnv.Util as PPE
import qualified Unison.PrettyPrintEnvDecl as PPED
import Unison.PrettyTerminal
@ -299,21 +300,20 @@ notifyNumbered o = case o of
else
first
( \p ->
( P.lines
[ P.wrap $
"The changes summarized below are available for you to review,"
<> "using the following command:",
"",
P.indentN 2 $
IP.makeExampleNoBackticks
IP.loadPullRequest
[ (prettyReadRemoteNamespace baseRepo),
(prettyReadRemoteNamespace headRepo)
],
"",
p
]
)
P.lines
[ P.wrap $
"The changes summarized below are available for you to review,"
<> "using the following command:",
"",
P.indentN 2 $
IP.makeExampleNoBackticks
IP.loadPullRequest
[ prettyReadRemoteNamespace baseRepo,
prettyReadRemoteNamespace headRepo
],
"",
p
]
)
(showDiffNamespace HideNumbers ppe (absPathToBranchId Path.absoluteEmpty) (absPathToBranchId Path.absoluteEmpty) diff)
-- todo: these numbers aren't going to work,
@ -689,7 +689,7 @@ notifyUser dir o = case o of
TestIncrementalOutputStart ppe (n, total) r _src -> do
putPretty' $
P.shown (total - n) <> " tests left to run, current test: "
<> (P.syntaxToColor $ prettyHashQualified (PPE.termName ppe $ Referent.Ref r))
<> P.syntaxToColor (prettyHashQualified (PPE.termName ppe $ Referent.Ref r))
pure mempty
TestIncrementalOutputEnd _ppe (_n, _total) _r result -> do
clearCurrentLine
@ -1039,7 +1039,7 @@ notifyUser dir o = case o of
P.bracket . P.lines $
P.wrap "The watch expression(s) reference these definitions:" :
"" :
[ (P.syntaxToColor $ TermPrinter.prettyBinding ppe (HQ.unsafeFromVar v) b)
[ P.syntaxToColor . runPretty ppe $ TermPrinter.prettyBinding (HQ.unsafeFromVar v) b
| (v, b) <- bindings
]
prettyWatches =
@ -1815,7 +1815,7 @@ notifyUser dir o = case o of
let referenceText = P.text . Reference.toText . Cv.reference2to1
pure $
P.columnNHeader
["Kind", "Name", "Change", "Ref"]
["Kind", "Name", "Change", "Ref"]
( (termNameAdds <&> \(n, ref) -> ["Term", prettyName n, "Added", referentText ref])
<> (termNameRemovals <&> \(n, ref) -> ["Term", prettyName n, "Removed", referentText ref])
<> (typeNameAdds <&> \(n, ref) -> ["Type", prettyName n, "Added", referenceText ref])
@ -1976,7 +1976,7 @@ displayDefinitions' ppe0 types terms = P.syntaxToColor $ P.sep "\n\n" (prettyTyp
P.hang
("builtin " <> prettyHashQualified n <> " :")
(TypePrinter.prettySyntax (ppeBody r) typ)
UserObject tm -> TermPrinter.prettyBinding (ppeBody r) n tm
UserObject tm -> runPretty (ppeBody r) $ TermPrinter.prettyBinding n tm
go2 ((n, r), dt) =
case dt of
MissingObject r -> missing n r
@ -2081,7 +2081,7 @@ displayDefinitions outputLoc ppe types terms =
P.hang
("builtin " <> prettyHashQualified n <> " :")
(TypePrinter.prettySyntax (ppeBody n r) typ)
UserObject tm -> TermPrinter.prettyBinding (ppeBody n r) n tm
UserObject tm -> runPretty (ppeBody n r) $ TermPrinter.prettyBinding n tm
go2 ((n, r), dt) =
case dt of
MissingObject r -> missing n r
@ -2148,7 +2148,7 @@ unsafePrettyTermResultSig' ::
Pretty
unsafePrettyTermResultSig' ppe = \case
SR'.TermResult' name (Just typ) r _aliases ->
head (TypePrinter.prettySignaturesCT ppe [(r, name, typ)])
head (runPretty ppe $ TypePrinter.prettySignaturesCT [(r, name, typ)])
_ -> error "Don't pass Nothing"
-- produces:
@ -2165,7 +2165,7 @@ unsafePrettyTermResultSigFull' ppe = \case
[ P.hiBlack "-- " <> greyHash (HQ.fromReferent r),
P.group $
P.commas (fmap greyHash $ hq : map HQ'.toHQ (toList aliases)) <> " : "
<> (P.syntaxToColor $ TypePrinter.pretty0 ppe mempty (-1) typ),
<> P.syntaxToColor (TypePrinter.prettySyntax ppe typ),
mempty
]
_ -> error "Don't pass Nothing"
@ -2396,7 +2396,7 @@ todoOutput ppe todo = runNumbered do
termNumbers <- for filteredTerms \(ref, _, _) -> do
n <- addNumberedArg (HQ.toString $ PPE.termName ppeu ref)
pure $ formatNum n
let formattedTerms = TypePrinter.prettySignaturesCT ppes filteredTerms
let formattedTerms = runPretty ppes $ TypePrinter.prettySignaturesCT filteredTerms
numberedTerms = zipWith (<>) termNumbers formattedTerms
pure $
Monoid.unlessM (TO.noEdits todo) . P.callout "🚧" . P.sep "\n\n" . P.nonEmpty $
@ -2407,7 +2407,7 @@ todoOutput ppe todo = runNumbered do
),
P.indentN 2 . P.lines $
( (prettyDeclPair ppeu <$> toList frontierTypes)
++ TypePrinter.prettySignaturesCT ppes (goodTerms frontierTerms)
++ runPretty ppes (TypePrinter.prettySignaturesCT (goodTerms frontierTerms))
),
P.wrap "I recommend working on them in the following order:",
P.lines $ numberedTypes ++ numberedTerms,

View File

@ -73,6 +73,7 @@ import qualified Unison.NamesWithHistory as NamesWithHistory
import Unison.Parser.Ann (Ann)
import Unison.Prelude
import qualified Unison.PrettyPrintEnv as PPE
import Unison.PrettyPrintEnv.MonadPretty (runPretty)
import qualified Unison.PrettyPrintEnv.Util as PPE
import qualified Unison.PrettyPrintEnvDecl as PPED
import qualified Unison.PrettyPrintEnvDecl.Names as PPED
@ -144,7 +145,7 @@ data BackendError
| MissingSignatureForTerm Reference
| NoSuchDefinition (HQ.HashQualified Name)
data BackendEnv = BackendEnv
newtype BackendEnv = BackendEnv
{ -- | Whether to use the sqlite name-lookup table to generate Names objects rather than building Names from the root branch.
useNamesIndex :: Bool
}
@ -265,7 +266,7 @@ termEntryDisplayName :: TermEntry v a -> Text
termEntryDisplayName = HQ'.toText . termEntryHQName
termEntryHQName :: TermEntry v a -> HQ'.HashQualified NameSegment
termEntryHQName (TermEntry {termEntryName, termEntryConflicted, termEntryHash}) =
termEntryHQName TermEntry {termEntryName, termEntryConflicted, termEntryHash} =
if termEntryConflicted
then HQ'.HashQualified termEntryName termEntryHash
else HQ'.NameOnly termEntryName
@ -283,7 +284,7 @@ typeEntryDisplayName :: TypeEntry -> Text
typeEntryDisplayName = HQ'.toText . typeEntryHQName
typeEntryHQName :: TypeEntry -> HQ'.HashQualified NameSegment
typeEntryHQName (TypeEntry {typeEntryName, typeEntryConflicted, typeEntryReference}) =
typeEntryHQName TypeEntry {typeEntryName, typeEntryConflicted, typeEntryReference} =
if typeEntryConflicted
then HQ'.HashQualified typeEntryName (Reference.toShortHash typeEntryReference)
else HQ'.NameOnly typeEntryName
@ -528,7 +529,7 @@ formatTypeName' ppe r =
termEntryToNamedTerm ::
Var v => PPE.PrettyPrintEnv -> Maybe Width -> TermEntry v a -> NamedTerm
termEntryToNamedTerm ppe typeWidth te@(TermEntry {termEntryType = mayType, termEntryTag = tag, termEntryHash}) =
termEntryToNamedTerm ppe typeWidth te@TermEntry {termEntryType = mayType, termEntryTag = tag, termEntryHash} =
NamedTerm
{ termName = termEntryHQName te,
termHash = termEntryHash,
@ -537,7 +538,7 @@ termEntryToNamedTerm ppe typeWidth te@(TermEntry {termEntryType = mayType, termE
}
typeEntryToNamedType :: TypeEntry -> NamedType
typeEntryToNamedType te@(TypeEntry {typeEntryTag, typeEntryHash}) =
typeEntryToNamedType te@TypeEntry {typeEntryTag, typeEntryHash} =
NamedType
{ typeName = typeEntryHQName $ te,
typeHash = typeEntryHash,
@ -672,7 +673,7 @@ makeTypeSearch :: Int -> NamesWithHistory -> Search Reference
makeTypeSearch len names =
Search
{ lookupNames = \ref -> NamesWithHistory.typeName len ref names,
lookupRelativeHQRefs' = \name -> NamesWithHistory.lookupRelativeHQType' name names,
lookupRelativeHQRefs' = (`NamesWithHistory.lookupRelativeHQType'` names),
matchesNamedRef = HQ'.matchesNamedReference,
makeResult = SR.typeResult
}
@ -682,7 +683,7 @@ makeTermSearch :: Int -> NamesWithHistory -> Search Referent
makeTermSearch len names =
Search
{ lookupNames = \ref -> NamesWithHistory.termName len ref names,
lookupRelativeHQRefs' = \name -> NamesWithHistory.lookupRelativeHQTerm' name names,
lookupRelativeHQRefs' = (`NamesWithHistory.lookupRelativeHQTerm'` names),
matchesNamedRef = HQ'.matchesNamedReferent,
makeResult = SR.termResult
}
@ -721,7 +722,7 @@ hqNameQuery ::
NameSearch ->
[HQ.HashQualified Name] ->
m QueryResult
hqNameQuery codebase (NameSearch {typeSearch, termSearch}) hqs = do
hqNameQuery codebase NameSearch {typeSearch, termSearch} hqs = do
-- Split the query into hash-only and hash-qualified-name queries.
let (hashes, hqnames) = partitionEithers (map HQ'.fromHQ2 hqs)
-- Find the terms with those hashes.
@ -747,8 +748,12 @@ hqNameQuery codebase (NameSearch {typeSearch, termSearch}) hqs = do
-- Now do the actual name query
resultss = map (\name -> applySearch typeSearch name <> applySearch termSearch name) hqnames
(misses, hits) =
zip hqnames resultss
& map (\(hqname, results) -> if null results then Left hqname else Right results)
zipWith
( \hqname results ->
(if null results then Left hqname else Right results)
)
hqnames
resultss
& partitionEithers
-- Handle query misses correctly
missingRefs =
@ -776,7 +781,7 @@ data DefinitionResults v = DefinitionResults
}
expandShortBranchHash ::
Monad m => Codebase m v a -> ShortBranchHash -> Backend m (Branch.CausalHash)
Monad m => Codebase m v a -> ShortBranchHash -> Backend m Branch.CausalHash
expandShortBranchHash codebase hash = do
hashSet <- lift $ Codebase.branchHashesByPrefix codebase hash
len <- lift $ Codebase.branchHashLength codebase
@ -787,18 +792,17 @@ expandShortBranchHash codebase hash = do
throwError . AmbiguousBranchHash hash $ Set.map (SBH.fromHash len) hashSet
-- | Efficiently resolve a root hash and path to a shallow branch's causal.
getShallowCausalAtPathFromRootHash :: Monad m => Codebase m v a -> Maybe (Branch.CausalHash) -> Path -> Backend m (V2Branch.CausalBranch m)
getShallowCausalAtPathFromRootHash :: Monad m => Codebase m v a -> Maybe Branch.CausalHash -> Path -> Backend m (V2Branch.CausalBranch m)
getShallowCausalAtPathFromRootHash codebase mayRootHash path = do
shallowRoot <- case mayRootHash of
Nothing -> lift (Codebase.getShallowRootCausal codebase)
Just h -> do
lift $ Codebase.getShallowCausalForHash codebase (Cv.causalHash1to2 h)
causal <- lift $ Codebase.getShallowCausalAtPath codebase path (Just shallowRoot)
pure causal
lift $ Codebase.getShallowCausalAtPath codebase path (Just shallowRoot)
formatType' :: Var v => PPE.PrettyPrintEnv -> Width -> Type v a -> SyntaxText
formatType' ppe w =
Pretty.render w . TypePrinter.pretty0 ppe mempty (-1)
Pretty.render w . TypePrinter.prettySyntax ppe
formatType :: Var v => PPE.PrettyPrintEnv -> Width -> Type v a -> Syntax.SyntaxText
formatType ppe w = mungeSyntaxText . formatType' ppe w
@ -822,7 +826,7 @@ prettyDefinitionsForHQName ::
-- this path.
Path ->
-- | The root branch to use
Maybe (Branch.CausalHash) ->
Maybe Branch.CausalHash ->
Maybe Width ->
-- | Whether to suffixify bindings in the rendered syntax
Suffixify ->
@ -995,7 +999,7 @@ docsInBranchToHtmlFiles runtime codebase root currentPath directory = do
let currentBranch = Branch.getAt' currentPath root
let allTerms = (R.toList . Branch.deepTerms . Branch.head) currentBranch
-- ignores docs inside lib namespace, recursively
let notLib (_, name) = all (/= "lib") (Name.segments name)
let notLib (_, name) = "lib" `notElem` Name.segments name
docTermsWithNames <- filterM (isDoc codebase . fst) (filter notLib allTerms)
let docNamesByRef = Map.fromList docTermsWithNames
hqLength <- Codebase.hashLength codebase
@ -1069,7 +1073,8 @@ bestNameForTerm ppe width =
Text.pack
. Pretty.render width
. fmap UST.toPlain
. TermPrinter.pretty0 @v ppe TermPrinter.emptyAc
. runPretty ppe
. TermPrinter.pretty0 @v TermPrinter.emptyAc
. Term.fromReferent mempty
bestNameForType ::
@ -1078,7 +1083,7 @@ bestNameForType ppe width =
Text.pack
. Pretty.render width
. fmap UST.toPlain
. TypePrinter.pretty0 @v ppe mempty (-1)
. TypePrinter.prettySyntax @v ppe
. Type.ref ()
-- | Returns (parse, pretty, local, ppe) where:
@ -1096,9 +1101,9 @@ scopedNamesForBranchHash codebase mbh path = do
Nothing
| shouldUseNamesIndex -> indexNames
| otherwise -> do
rootBranch <- lift $ Codebase.getRootBranch codebase
let (parseNames, _prettyNames, localNames) = namesForBranch rootBranch (AllNames path)
pure (parseNames, localNames)
rootBranch <- lift $ Codebase.getRootBranch codebase
let (parseNames, _prettyNames, localNames) = namesForBranch rootBranch (AllNames path)
pure (parseNames, localNames)
Just rootCausal -> do
let ch = V2Causal.causalHash rootCausal
let v1CausalHash = Cv.causalHash2to1 ch
@ -1255,8 +1260,8 @@ termsToSyntax suff width ppe0 terms =
DisplayObject.UserObject tm ->
DisplayObject.UserObject
. Pretty.render width
. TermPrinter.prettyBinding (ppeBody r) n
$ tm
. runPretty (ppeBody r)
$ TermPrinter.prettyBinding n tm
typesToSyntax ::
Var v =>
@ -1296,8 +1301,8 @@ typesToSyntax suff width ppe0 types =
typeToSyntaxHeader ::
Width ->
HQ.HashQualified Name ->
(DisplayObject () (DD.Decl Symbol Ann)) ->
(DisplayObject SyntaxText SyntaxText)
DisplayObject () (DD.Decl Symbol Ann) ->
DisplayObject SyntaxText SyntaxText
typeToSyntaxHeader width hqName obj =
case obj of
BuiltinObject _ ->

View File

@ -1,6 +1,4 @@
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
@ -32,6 +30,7 @@ import qualified Unison.Codebase.Editor.DisplayObject as DO
import qualified Unison.ConstructorReference as ConstructorReference
import qualified Unison.DataDeclaration as DD
import qualified Unison.PrettyPrintEnv as PPE
import Unison.PrettyPrintEnv.MonadPretty (runPretty)
import qualified Unison.PrettyPrintEnvDecl as PPE
import Unison.Reference (Reference)
import qualified Unison.Reference as Reference
@ -183,16 +182,15 @@ renderDoc pped terms typeOf eval types tm =
formatPrettyType ppe typ = formatPretty (TypePrinter.prettySyntax ppe typ)
source :: Term v () -> m SyntaxText
source tm = (pure . formatPretty . TermPrinter.prettyBlock' True (PPE.suffixifiedPPE pped)) tm
source tm = pure . formatPretty $ TermPrinter.prettyBlock' True (PPE.suffixifiedPPE pped) tm
goSignatures :: [Referent] -> m [P.Pretty SSyntaxText]
goSignatures rs =
runMaybeT (traverse (MaybeT . typeOf) rs) >>= \case
Nothing -> pure ["🆘 codebase is missing type signature for these definitions"]
Just types ->
pure . fmap P.group $
pure . fmap P.group . runPretty (PPE.suffixifiedPPE pped) $
TypePrinter.prettySignaturesST
(PPE.suffixifiedPPE pped)
[(r, PPE.termName (PPE.suffixifiedPPE pped) r, ty) | (r, ty) <- zip rs types]
goSpecial :: Term v () -> m SpecialForm
@ -314,12 +312,12 @@ renderDoc pped terms typeOf eval types tm =
typ <- fromMaybe (Type.builtin () "unknown") <$> typeOf (Referent.Ref ref)
let name = PPE.termName ppe (Referent.Ref ref)
let folded =
formatPretty . P.lines $
TypePrinter.prettySignaturesST ppe [(Referent.Ref ref, name, typ)]
formatPretty . P.lines . runPretty ppe $
TypePrinter.prettySignaturesST [(Referent.Ref ref, name, typ)]
let full tm@(Term.Ann' _ _) _ =
formatPretty (TermPrinter.prettyBinding ppe name tm)
formatPretty (runPretty ppe $ TermPrinter.prettyBinding name tm)
full tm typ =
formatPretty (TermPrinter.prettyBinding ppe name (Term.ann () tm typ))
formatPretty (runPretty ppe $ TermPrinter.prettyBinding name (Term.ann () tm typ))
pure (DO.UserObject (Src folded (full tm typ)))
Term.RequestOrCtor' (view ConstructorReference.reference_ -> r) | Set.notMember r seen -> (: acc) <$> goType r
_ -> pure acc