Merge branch 'trunk' into work/io-sandboxing

This commit is contained in:
Dan Doel 2022-01-25 12:07:31 -05:00
commit d1ae70a48c
21 changed files with 669 additions and 246 deletions

View File

@ -64,3 +64,4 @@ The format for this list: name, GitHub handle, and then optional blurb about wha
* Shawn Bachlet (@shawn-bachlet)
* Solomon Bothwell (@solomon-b)
* Sameer Kolhar (@kolharsam)
* Nicole Prindle (@nprindle)

View File

@ -526,6 +526,15 @@ renderTypeError e env src = case e of
[Type.var () (Var.named "e"), Type.var () (Var.named "a") ])
(Type.var () (Var.named "o"))
Other (C.cause -> C.PatternArityMismatch loc typ num) ->
Pr.lines [
Pr.wrap "This pattern has the wrong number of arguments", "",
annotatedAsErrorSite src loc,
"The constructor has type ", "",
Pr.indentN 2 (stylePretty Type1 (Pr.group (renderType' env typ))), "",
"but you supplied " <> (Pr.shown num) <> " arguments."
]
Other note -> mconcat
[ "Sorry, you hit an error we didn't make a nice message for yet.\n\n"
, "Here is a summary of the Note:\n"
@ -589,52 +598,53 @@ renderTypeError e env src = case e of
, " "
, simpleCause (C.cause note)
, "\n"
, case toList (C.path note) of
[] -> " path: (empty)\n"
l -> " path:\n" <> mconcat (simplePath <$> l)
-- This can be very slow to print in large file. This was taking several minutes to print out the path in a file when the error occurred deep in the file after many other let bindings - stew
-- , case toList (C.path note) of
-- [] -> " path: (empty)\n"
-- l -> " path:\n" <> mconcat (simplePath <$> l)
]
simplePath :: C.PathElement v loc -> Pretty ColorText
simplePath e = " " <> simplePath' e <> "\n"
simplePath' :: C.PathElement v loc -> Pretty ColorText
simplePath' = \case
C.InSynthesize e -> "InSynthesize e=" <> renderTerm env e
C.InEquate t1 t2 ->
"InEquate t1=" <> renderType' env t1 <>
", t2=" <> renderType' env t2
C.InSubtype t1 t2 ->
"InSubtype t1=" <> renderType' env t1 <> ", t2=" <> renderType' env t2
C.InCheck e t ->
"InCheck e=" <> renderTerm env e <> "," <> " t=" <> renderType' env t
C.InInstantiateL v t ->
"InInstantiateL v=" <> renderVar v <> ", t=" <> renderType' env t
C.InInstantiateR t v ->
"InInstantiateR t=" <> renderType' env t <> " v=" <> renderVar v
C.InSynthesizeApp t e n ->
"InSynthesizeApp t="
<> renderType' env t
<> ", e="
<> renderTerm env e
<> ", n="
<> fromString (show n)
C.InFunctionCall vs f ft es ->
"InFunctionCall vs=["
<> commas renderVar vs
<> "]"
<> ", f="
<> renderTerm env f
<> ", ft="
<> renderType' env ft
<> ", es=["
<> commas (renderTerm env) es
<> "]"
C.InIfCond -> "InIfCond"
C.InIfBody loc -> "InIfBody thenBody=" <> annotatedToEnglish loc
C.InAndApp -> "InAndApp"
C.InOrApp -> "InOrApp"
C.InVectorApp loc -> "InVectorApp firstTerm=" <> annotatedToEnglish loc
C.InMatch loc -> "InMatch firstBody=" <> annotatedToEnglish loc
C.InMatchGuard -> "InMatchGuard"
C.InMatchBody -> "InMatchBody"
-- simplePath :: C.PathElement v loc -> Pretty ColorText
-- simplePath e = " " <> simplePath' e <> "\n"
-- simplePath' :: C.PathElement v loc -> Pretty ColorText
-- simplePath' = \case
-- C.InSynthesize e -> "InSynthesize e=" <> renderTerm env e
-- C.InEquate t1 t2 ->
-- "InEquate t1=" <> renderType' env t1 <>
-- ", t2=" <> renderType' env t2
-- C.InSubtype t1 t2 ->
-- "InSubtype t1=" <> renderType' env t1 <> ", t2=" <> renderType' env t2
-- C.InCheck e t ->
-- "InCheck e=" <> renderTerm env e <> "," <> " t=" <> renderType' env t
-- C.InInstantiateL v t ->
-- "InInstantiateL v=" <> renderVar v <> ", t=" <> renderType' env t
-- C.InInstantiateR t v ->
-- "InInstantiateR t=" <> renderType' env t <> " v=" <> renderVar v
-- C.InSynthesizeApp t e n ->
-- "InSynthesizeApp t="
-- <> renderType' env t
-- <> ", e="
-- <> renderTerm env e
-- <> ", n="
-- <> fromString (show n)
-- C.InFunctionCall vs f ft es ->
-- "InFunctionCall vs=["
-- <> commas renderVar vs
-- <> "]"
-- <> ", f="
-- <> renderTerm env f
-- <> ", ft="
-- <> renderType' env ft
-- <> ", es=["
-- <> commas (renderTerm env) es
-- <> "]"
-- C.InIfCond -> "InIfCond"
-- C.InIfBody loc -> "InIfBody thenBody=" <> annotatedToEnglish loc
-- C.InAndApp -> "InAndApp"
-- C.InOrApp -> "InOrApp"
-- C.InVectorApp loc -> "InVectorApp firstTerm=" <> annotatedToEnglish loc
-- C.InMatch loc -> "InMatch firstBody=" <> annotatedToEnglish loc
-- C.InMatchGuard -> "InMatchGuard"
-- C.InMatchBody -> "InMatchBody"
simpleCause :: C.Cause v loc -> Pretty ColorText
simpleCause = \case
C.TypeMismatch c ->

View File

@ -1794,7 +1794,7 @@ declareForeigns = do
declareForeign Tracked "Tls.ServerConfig.default" boxBoxDirect $ mkForeign
$ \(certs :: [X.SignedCertificate], key :: X.PrivKey) ->
pure $ (def :: TLS.ServerParams) { TLS.serverSupported = def { TLS.supportedCiphers = Cipher.ciphersuite_strong }
, TLS.serverShared = def { TLS.sharedCredentials = Credentials [((X.CertificateChain certs), key)] }
, TLS.serverShared = def { TLS.sharedCredentials = Credentials [(X.CertificateChain certs, key)] }
}
let updateClient :: X.CertificateStore -> TLS.ClientParams -> TLS.ClientParams
@ -1843,21 +1843,6 @@ declareForeigns = do
declareForeign Untracked "Ref.write" boxBoxTo0 . mkForeign $
\(r :: IORef Closure, c :: Closure) -> writeIORef r c
let
defaultSupported :: TLS.Supported
defaultSupported = def { TLS.supportedCiphers = Cipher.ciphersuite_strong }
declareForeign Tracked "Tls.Config.defaultClient" boxBoxDirect
. mkForeign $ \(hostName :: Util.Text.Text, serverId:: Bytes.Bytes) -> do
store <- X.getSystemCertificateStore
let shared :: TLS.Shared
shared = def { TLS.sharedCAStore = store }
defaultParams = (defaultParamsClient (Util.Text.unpack hostName) (Bytes.toArray serverId)) { TLS.clientSupported = defaultSupported, TLS.clientShared = shared }
pure defaultParams
declareForeign Tracked "Tls.Config.defaultServer" unitDirect . mkForeign $ \() -> do
pure $ (def :: ServerParams) { TLS.serverSupported = defaultSupported }
declareForeign Tracked "Tls.newClient.impl.v3" boxBoxToEFBox . mkForeignTls $
\(config :: TLS.ClientParams,
socket :: SYS.Socket) -> TLS.contextNew socket config
@ -1866,8 +1851,10 @@ declareForeigns = do
\(config :: TLS.ServerParams,
socket :: SYS.Socket) -> TLS.contextNew socket config
declareForeign Tracked "Tls.handshake.impl.v3" boxToEFBox . mkForeignTls $
\(tls :: TLS.Context) -> TLS.handshake tls
declareForeign Tracked "Tls.handshake.impl.v3" boxToEF0 . mkForeignTls $
\(tls :: TLS.Context) -> do
i <- contextGetInformation tls
traceShow i $ TLS.handshake tls
declareForeign Tracked "Tls.send.impl.v3" boxBoxToEFBox . mkForeignTls $
\(tls :: TLS.Context,
@ -1875,11 +1862,14 @@ declareForeigns = do
let wrapFailure t = Failure Ty.tlsFailureRef (Util.Text.pack t) unitValue
decoded :: Bytes.Bytes -> Either String PEM
decoded bytes = fmap head $ pemParseLBS $ Bytes.toLazyByteString bytes
decoded bytes = case pemParseLBS $ Bytes.toLazyByteString bytes of
Right (pem : _) -> Right pem
Right _ -> Left "no PEM found"
Left l -> Left l
asCert :: PEM -> Either String X.SignedCertificate
asCert pem = X.decodeSignedCertificate $ pemContent pem
in
declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeign $
declareForeign Tracked "Tls.decodeCert.impl.v3" boxToEFBox . mkForeignTls $
\(bytes :: Bytes.Bytes) -> pure $ mapLeft wrapFailure $ (decoded >=> asCert) bytes
declareForeign Tracked "Tls.encodeCert" boxDirect . mkForeign $

View File

@ -284,15 +284,17 @@ intermediateTerm
-> Term Symbol
-> (SuperGroup Symbol, Map.Map Word64 (Term Symbol))
intermediateTerm ppe ref ctx tm
= final
= first ( superNormalize
. splitPatterns (dspec ctx)
. addDefaultCases tmName
)
. memorize
. lamLift
. splitPatterns (dspec ctx)
. addDefaultCases tmName
. saturate (uncurryDspec $ dspec ctx)
. inlineAlias
$ tm
where
final (ll, dcmp) = (superNormalize ll, backrefLifted ll dcmp)
memorize (ll, dcmp) = (ll, backrefLifted ll dcmp)
tmName = HQ.toString . termName ppe $ RF.Ref ref
prepareEvaluation

View File

@ -11,10 +11,20 @@ module Unison.Server.Endpoints.Projects where
import Control.Error (ExceptT, runExceptT)
import Control.Error.Util ((??))
import Data.Aeson
import Data.OpenApi (ToSchema)
import Data.Char
import Data.OpenApi
( ToParamSchema (..),
ToSchema (..),
)
import qualified Data.Text as Text
import Servant (QueryParam, ServerError, throwError, (:>))
import Servant.Docs (ToSample (..))
import Servant.API (FromHttpApiData (..))
import Servant.Docs
( DocQueryParam (..),
ParamKind (Normal),
ToParam (..),
ToSample (..),
)
import Servant.Server (Handler)
import Unison.Codebase (Codebase)
import qualified Unison.Codebase as Codebase
@ -34,6 +44,7 @@ import Unison.Util.Monoid (foldMapM)
type ProjectsAPI =
"projects" :> QueryParam "rootBranch" ShortBranchHash
:> QueryParam "owner" ProjectOwner
:> APIGet [ProjectListing]
instance ToSample ProjectListing where
@ -50,9 +61,33 @@ newtype ProjectOwner = ProjectOwner Text
deriving stock (Generic, Show)
deriving anyclass (ToSchema)
instance ToParam (QueryParam "owner" ProjectOwner) where
toParam _ =
DocQueryParam
"owner"
["unison", "alice", "bob"]
"The name of a project owner"
Normal
instance ToJSON ProjectOwner where
toEncoding = genericToEncoding defaultOptions
deriving anyclass instance ToParamSchema ProjectOwner
instance FromHttpApiData ProjectOwner where
parseUrlPiece = Right . ProjectOwner
-- ProjectOwner is slightly more restrictive than a regular FQN in that we only
-- want alphanumeric characters
projectOwnerFromText :: Text -> Either Text ProjectOwner
projectOwnerFromText raw =
if isAllAlphaNum raw
then Right (ProjectOwner raw)
else Left "Invalid owner name"
where
isAllAlphaNum t =
t & Text.unpack & all isAlphaNum
data ProjectListing = ProjectListing
{ owner :: ProjectOwner,
name :: Text,
@ -90,8 +125,9 @@ serve ::
Handler () ->
Codebase IO Symbol Ann ->
Maybe ShortBranchHash ->
Maybe ProjectOwner ->
Handler (APIHeaders [ProjectListing])
serve tryAuth codebase mayRoot = addHeaders <$> (tryAuth *> projects)
serve tryAuth codebase mayRoot mayOwner = addHeaders <$> (tryAuth *> projects)
where
projects :: Handler [ProjectListing]
projects = do
@ -107,7 +143,11 @@ serve tryAuth codebase mayRoot = addHeaders <$> (tryAuth *> projects)
errFromEither backendError ea
ownerEntries <- findShallow root
let owners = mapMaybe entryToOwner ownerEntries
-- If an owner is provided, we only want projects belonging to them
let owners =
case mayOwner of
Just o -> [o]
Nothing -> mapMaybe entryToOwner ownerEntries
foldMapM (ownerToProjectListings root) owners
ownerToProjectListings :: Branch.Branch IO -> ProjectOwner -> Handler [ProjectListing]

View File

@ -263,32 +263,26 @@ pretty0
<> optSpace <> (fmt S.DelimiterChar $ l "]")
where optSpace = PP.orElse "" " "
If' cond t f -> paren (p >= 2) $
if PP.isMultiLine pt || PP.isMultiLine pf then PP.lines [
(fmt S.ControlKeyword "if ") <> pcond <> (fmt S.ControlKeyword " then") `PP.hang` pt,
(fmt S.ControlKeyword "else") `PP.hang` pf
]
else PP.spaced [
((fmt S.ControlKeyword "if") `PP.hang` pcond) <> ((fmt S.ControlKeyword " then") `PP.hang` pt),
if PP.isMultiLine pcond then PP.lines [
(fmt S.ControlKeyword "if") `PP.hang` pcond,
(fmt S.ControlKeyword "then") `PP.hang` pt,
(fmt S.ControlKeyword "else") `PP.hang` pf
]
else
if PP.isMultiLine pt || PP.isMultiLine pf then PP.lines [
(fmt S.ControlKeyword "if ") <> pcond <> (fmt S.ControlKeyword " then") `PP.hang` pt,
(fmt S.ControlKeyword "else") `PP.hang` pf
]
else PP.spaced [
((fmt S.ControlKeyword "if") `PP.hang` pcond) <> ((fmt S.ControlKeyword " then") `PP.hang` pt),
(fmt S.ControlKeyword "else") `PP.hang` pf
]
where
pcond = pretty0 n (ac 2 Block im doc) cond
pt = branch t
pf = branch f
branch tm = let (im', uses) = calcImports im tm
in uses $ [pretty0 n (ac 0 Block im' doc) tm]
And' x y ->
paren (p >= 10) $ PP.spaced [
pretty0 n (ac 10 Normal im doc) x,
fmt S.ControlKeyword "&&",
pretty0 n (ac 10 Normal im doc) y
]
Or' x y ->
paren (p >= 10) $ PP.spaced [
pretty0 n (ac 10 Normal im doc) x,
fmt S.ControlKeyword "||",
pretty0 n (ac 10 Normal im doc) y
]
LetBlock bs e ->
let (im', uses) = calcImports im term
in printLet elideUnit bc bs e im' uses
@ -356,7 +350,18 @@ pretty0
fmt S.BytesLiteral "0xs" <> (PP.shown $ Bytes.fromWord8s (map fromIntegral bs))
BinaryAppsPred' apps lastArg -> paren (p >= 3) $
binaryApps apps (pretty0 n (ac 3 Normal im doc) lastArg)
-- Note that && and || are at the same precedence, which can cause
-- confusion, so for clarity we do not want to elide the parentheses in a
-- case like `(x || y) && z`.
(Ands' xs lastArg, _) -> paren (p >= 10) $
booleanOps (fmt S.ControlKeyword "&&") xs (pretty0 n (ac 10 Normal im doc) lastArg)
(Ors' xs lastArg, _) -> paren (p >= 10) $
booleanOps (fmt S.ControlKeyword "||") xs (pretty0 n (ac 10 Normal im doc) lastArg)
_ -> case (term, nonForcePred) of
OverappliedBinaryAppPred' f a b r | binaryOpsPred f ->
-- Special case for overapplied binary op
paren True (binaryApps [(f, a)] (pretty0 n (ac 3 Normal im doc) b) `PP.hang`
PP.spacedMap (pretty0 n (ac 10 Normal im doc)) r)
AppsPred' f args ->
paren (p >= 10) $ pretty0 n (ac 10 Normal im doc) f `PP.hang`
PP.spacedMap (pretty0 n (ac 10 Normal im doc)) args
@ -397,13 +402,12 @@ pretty0
Normal -> \x -> (fmt S.ControlKeyword "let") `PP.hang` x
-- This predicate controls which binary functions we render as infix
-- operators. At the moment the policy is just to render symbolic
-- operators as infix - not 'wordy' function names. So we produce
-- "x + y" and "foo x y" but not "x `foo` y".
-- operators. At the moment the policy is just to render symbolic
-- operators as infix.
binaryOpsPred :: Var v => Term3 v PrintAnnotation -> Bool
binaryOpsPred = \case
Ref' r | isSymbolic (PrettyPrintEnv.termName n (Referent.Ref r)) -> True
Var' v | isSymbolic (HQ.unsafeFromVar v) -> True
Ref' r -> isSymbolic $ PrettyPrintEnv.termName n (Referent.Ref r)
Var' v -> isSymbolic $ HQ.unsafeFromVar v
_ -> False
nonForcePred :: Term3 v PrintAnnotation -> Bool
@ -440,6 +444,30 @@ pretty0
, pretty0 n (AmbientContext 10 Normal Infix im doc False) f
]
-- Render sequence of infix &&s or ||s, like [x2, x1],
-- meaning (x1 && x2) && (x3 rendered by the caller), producing
-- "x1 && x2 &&". The result is built from the right.
booleanOps
:: Var v
=> Pretty SyntaxText
-> [Term3 v PrintAnnotation]
-> Pretty SyntaxText
-> Pretty SyntaxText
booleanOps op xs last = unbroken `PP.orElse` broken
where
unbroken = PP.spaced (ps ++ [last])
broken = PP.hang (head ps) . PP.column2 . psCols $ (tail ps ++ [last])
psCols ps = case take 2 ps of
[x, y] -> (x, y) : psCols (drop 2 ps)
[x] -> [(x, "")]
[] -> []
_ -> undefined
ps = r =<< reverse xs
r a =
[ pretty0 n (ac (if isBlock a then 12 else 10) Normal im doc) a
, op
]
prettyPattern
:: forall v loc . Var v
=> PrettyPrintEnv

View File

@ -211,7 +211,7 @@ test = scope "termprinter" $ tests
, tcBreaks 16 "match (if a then\n\
\ b\n\
\else c) with\n\
\ 112 -> x" -- dodgy layout. note #517 and #518
\ 112 -> x" -- dodgy layout. note #517
, tc "handle bar with Pair 1 1"
, tc "handle bar with x -> foo"
, tcDiffRtt True "let\n\
@ -411,7 +411,9 @@ test = scope "termprinter" $ tests
\ b" 80
, tcBreaks 80 "if\n\
\ a = b\n\
\ a then foo else bar" -- missing break before 'then', issue #518
\ a\n\
\then foo\n\
\else bar"
, tcBreaks 80 "Stream.foldLeft 0 (+) t"
, tcBreaks 80 "let\n\
\ delay = 'isEven\n\

View File

@ -1,88 +1,102 @@
{- ORMOLU_DISABLE -} -- Remove this when the file is ready to be auto-formatted
{-# LANGUAGE PatternSynonyms #-}
module Unison.Codebase.Editor.SlurpComponent where
import Unison.Prelude
import Data.Tuple (swap)
import Unison.Reference ( Reference )
import Unison.UnisonFile (TypecheckedUnisonFile)
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.Tuple (swap)
import qualified Unison.DataDeclaration as DD
import Unison.Prelude
import Unison.Reference (Reference)
import qualified Unison.Term as Term
import Unison.UnisonFile (TypecheckedUnisonFile)
import qualified Unison.UnisonFile as UF
data SlurpComponent v =
SlurpComponent { types :: Set v, terms :: Set v }
deriving (Eq,Ord,Show)
data SlurpComponent v = SlurpComponent {types :: Set v, terms :: Set v}
deriving (Eq, Ord, Show)
isEmpty :: SlurpComponent v -> Bool
isEmpty sc = Set.null (types sc) && Set.null (terms sc)
empty :: Ord v => SlurpComponent v
empty = SlurpComponent mempty mempty
empty = SlurpComponent {types = mempty, terms = mempty}
difference :: Ord v => SlurpComponent v -> SlurpComponent v -> SlurpComponent v
difference c1 c2 = SlurpComponent types' terms' where
types' = types c1 `Set.difference` types c2
terms' = terms c1 `Set.difference` terms c2
difference c1 c2 = SlurpComponent {types = types', terms = terms'}
where
types' = types c1 `Set.difference` types c2
terms' = terms c1 `Set.difference` terms c2
intersection :: Ord v => SlurpComponent v -> SlurpComponent v -> SlurpComponent v
intersection c1 c2 = SlurpComponent types' terms' where
types' = types c1 `Set.intersection` types c2
terms' = terms c1 `Set.intersection` terms c2
intersection c1 c2 = SlurpComponent {types = types', terms = terms'}
where
types' = types c1 `Set.intersection` types c2
terms' = terms c1 `Set.intersection` terms c2
instance Ord v => Semigroup (SlurpComponent v) where (<>) = mappend
instance Ord v => Monoid (SlurpComponent v) where
mempty = SlurpComponent mempty mempty
c1 `mappend` c2 = SlurpComponent (types c1 <> types c2)
(terms c1 <> terms c2)
instance Ord v => Monoid (SlurpComponent v) where
mempty = SlurpComponent {types = mempty, terms = mempty}
c1 `mappend` c2 =
SlurpComponent
{ types = types c1 <> types c2,
terms = terms c1 <> terms c2
}
-- I'm calling this `closeWithDependencies` because it doesn't just compute
-- the dependencies of the inputs, it mixes them together. Make sure this
-- is what you want.
closeWithDependencies :: forall v a. Ord v
=> TypecheckedUnisonFile v a -> SlurpComponent v -> SlurpComponent v
closeWithDependencies uf inputs = seenDefns where
seenDefns = foldl' termDeps (SlurpComponent mempty seenTypes) (terms inputs)
seenTypes = foldl' typeDeps mempty (types inputs)
closeWithDependencies ::
forall v a.
Ord v =>
TypecheckedUnisonFile v a ->
SlurpComponent v ->
SlurpComponent v
closeWithDependencies uf inputs = seenDefns
where
seenDefns = foldl' termDeps (SlurpComponent {types = seenTypes, terms = mempty}) (terms inputs)
seenTypes = foldl' typeDeps mempty (types inputs)
termDeps :: SlurpComponent v -> v -> SlurpComponent v
termDeps seen v | Set.member v (terms seen) = seen
termDeps seen v = fromMaybe seen $ do
term <- findTerm v
let -- get the `v`s for the transitive dependency types
-- (the ones for terms are just the `freeVars below`)
-- although this isn't how you'd do it for a term that's already in codebase
tdeps :: [v]
tdeps = resolveTypes $ Term.dependencies term
seenTypes :: Set v
seenTypes = foldl' typeDeps (types seen) tdeps
seenTerms = Set.insert v (terms seen)
pure $ foldl' termDeps (seen { types = seenTypes
, terms = seenTerms})
(Term.freeVars term)
termDeps :: SlurpComponent v -> v -> SlurpComponent v
termDeps seen v | Set.member v (terms seen) = seen
termDeps seen v = fromMaybe seen $ do
term <- findTerm v
let -- get the `v`s for the transitive dependency types
-- (the ones for terms are just the `freeVars below`)
-- although this isn't how you'd do it for a term that's already in codebase
tdeps :: [v]
tdeps = resolveTypes $ Term.dependencies term
seenTypes :: Set v
seenTypes = foldl' typeDeps (types seen) tdeps
seenTerms = Set.insert v (terms seen)
pure $
foldl'
termDeps
( seen
{ types = seenTypes,
terms = seenTerms
}
)
(Term.freeVars term)
typeDeps :: Set v -> v -> Set v
typeDeps seen v | Set.member v seen = seen
typeDeps seen v = fromMaybe seen $ do
dd <- fmap snd (Map.lookup v (UF.dataDeclarations' uf)) <|>
fmap (DD.toDataDecl . snd) (Map.lookup v (UF.effectDeclarations' uf))
pure $ foldl' typeDeps (Set.insert v seen) (resolveTypes $ DD.dependencies dd)
typeDeps :: Set v -> v -> Set v
typeDeps seen v | Set.member v seen = seen
typeDeps seen v = fromMaybe seen $ do
dd <-
fmap snd (Map.lookup v (UF.dataDeclarations' uf))
<|> fmap (DD.toDataDecl . snd) (Map.lookup v (UF.effectDeclarations' uf))
pure $ foldl' typeDeps (Set.insert v seen) (resolveTypes $ DD.dependencies dd)
resolveTypes :: Set Reference -> [v]
resolveTypes rs = [ v | r <- Set.toList rs, Just v <- [Map.lookup r typeNames]]
resolveTypes :: Set Reference -> [v]
resolveTypes rs = [v | r <- Set.toList rs, Just v <- [Map.lookup r typeNames]]
findTerm :: v -> Maybe (Term.Term v a)
findTerm v = Map.lookup v allTerms
findTerm :: v -> Maybe (Term.Term v a)
findTerm v = Map.lookup v allTerms
allTerms = UF.allTerms uf
allTerms = UF.allTerms uf
typeNames :: Map Reference v
typeNames = invert (fst <$> UF.dataDeclarations' uf) <> invert (fst <$> UF.effectDeclarations' uf)
typeNames :: Map Reference v
typeNames = invert (fst <$> UF.dataDeclarations' uf) <> invert (fst <$> UF.effectDeclarations' uf)
invert :: forall k v . Ord k => Ord v => Map k v -> Map v k
invert m = Map.fromList (swap <$> Map.toList m)
invert :: forall k v. Ord k => Ord v => Map k v -> Map v k
invert m = Map.fromList (swap <$> Map.toList m)

View File

@ -428,10 +428,14 @@ pattern Or' x y <- (ABT.out -> ABT.Tm (Or x y))
pattern Handle' h body <- (ABT.out -> ABT.Tm (Handle h body))
pattern Apps' f args <- (unApps -> Just (f, args))
-- begin pretty-printer helper patterns
pattern Ands' ands lastArg <- (unAnds -> Just (ands, lastArg))
pattern Ors' ors lastArg <- (unOrs -> Just (ors, lastArg))
pattern AppsPred' f args <- (unAppsPred -> Just (f, args))
pattern BinaryApp' f arg1 arg2 <- (unBinaryApp -> Just (f, arg1, arg2))
pattern BinaryApps' apps lastArg <- (unBinaryApps -> Just (apps, lastArg))
pattern BinaryAppsPred' apps lastArg <- (unBinaryAppsPred -> Just (apps, lastArg))
pattern OverappliedBinaryAppPred' f arg1 arg2 rest <-
(unOverappliedBinaryAppPred -> Just (f, arg1, arg2, rest))
-- end pretty-printer helper patterns
pattern Ann' x t <- (ABT.out -> ABT.Tm (Ann x t))
pattern List' xs <- (ABT.out -> ABT.Tm (List xs))
@ -761,6 +765,30 @@ unLetRec (unLetRecNamed -> Just (isTop, bs, e)) = Just
)
unLetRec _ = Nothing
unAnds
:: Term2 vt at ap v a
-> Maybe
( [Term2 vt at ap v a]
, Term2 vt at ap v a
)
unAnds t = case t of
And' i o -> case unAnds i of
Just (as, xLast) -> Just (xLast:as, o)
Nothing -> Just ([i], o)
_ -> Nothing
unOrs
:: Term2 vt at ap v a
-> Maybe
( [Term2 vt at ap v a]
, Term2 vt at ap v a
)
unOrs t = case t of
Or' i o -> case unOrs i of
Just (as, xLast) -> Just (xLast:as, o)
Nothing -> Just ([i], o)
_ -> Nothing
unApps
:: Term2 vt at ap v a
-> Maybe (Term2 vt at ap v a, [Term2 vt at ap v a])
@ -783,6 +811,19 @@ unBinaryApp t = case unApps t of
Just (f, [arg1, arg2]) -> Just (f, arg1, arg2)
_ -> Nothing
-- Special case for overapplied binary operators
unOverappliedBinaryAppPred
:: (Term2 vt at ap v a, Term2 vt at ap v a -> Bool)
-> Maybe
( Term2 vt at ap v a
, Term2 vt at ap v a
, Term2 vt at ap v a
, [Term2 vt at ap v a]
)
unOverappliedBinaryAppPred (t, pred) = case unApps t of
Just (f, arg1 : arg2 : rest) | pred f -> Just (f, arg1, arg2, rest)
_ -> Nothing
-- "((a1 `f1` a2) `f2` a3)" becomes "Just ([(a2, f2), (a1, f1)], a3)"
unBinaryApps
:: Term2 vt at ap v a

View File

@ -23,6 +23,14 @@ Exception.toEither.handler = cases
Exception.toEither : '{ε, Exception} a -> {ε} Either Failure a
Exception.toEither a = handle !a with Exception.toEither.handler
Exception.unsafeRun! : '{g, Exception} a ->{g} a
Exception.unsafeRun! e =
h : Request {Exception} a -> a
h = cases
{raise fail -> _} -> bug fail
{ a } -> a
handle !e with h
structural ability Throw e where
throw : e -> a
@ -31,6 +39,17 @@ List.all f = cases
[] -> true
h +: t -> f h && all f t
List.foldLeft : (b ->{g} a ->{g} b) -> b -> [a] ->{g} b
List.foldLeft f b as =
go b i =
match List.at i as with
None -> b
Some a ->
use Nat +
go (f b a) (i + 1)
go b 0
List.filter: (a -> Boolean) -> [a] -> [a]
List.filter f all =
go acc = cases

View File

@ -73,6 +73,14 @@ id x = x
id (sqr 10)
```
also:
```
match 1 with
1 -> "hi"
_ -> "goodbye"
```
To include a typechecked snippet of code without evaluating it, you can do:
@typecheck ```

View File

@ -257,6 +257,14 @@ and the rendered output using `display`:
id (sqr 10)
```
also:
```
match 1 with
1 -> "hi"
_ -> "goodbye"
```
To include a typechecked snippet of code without
evaluating it, you can do:
@ -281,6 +289,14 @@ and the rendered output using `display`:
100
also:
match 1 with
1 -> "hi"
_ -> "goodbye"
"hi"
To include a typechecked snippet of code without evaluating
it, you can do:
@ -626,6 +642,14 @@ Lastly, it's common to build longer documents including subdocuments via `{{ sub
100
also:
match 1 with
1 -> "hi"
_ -> "goodbye"
"hi"
To include a typechecked snippet of code without
evaluating it, you can do:

View File

@ -59,27 +59,27 @@ myServer = unsafeRun! '(hello "127.0.0.1" "0")
structural type Either a b
(also named builtin.Either)
Exception.unsafeRun! : '{g, Exception} a -> '{g} a
bugFail : Failure -> r
hello : Text -> Text ->{IO, Exception} ()
myServer : '{IO} ()
putText : Handle -> Text ->{IO, Exception} ()
reraise : Either Failure b ->{Exception} b
bugFail : Failure -> r
hello : Text -> Text ->{IO, Exception} ()
myServer : '{IO} ()
putText : Handle -> Text ->{IO, Exception} ()
reraise : Either Failure b ->{Exception} b
(also named Exception.reraise)
socketSend : Socket
-> Bytes
->{IO, Exception} ()
toException : Either Failure a ->{Exception} a
socketSend : Socket -> Bytes ->{IO, Exception} ()
toException : Either Failure a ->{Exception} a
(also named Exception.reraise)
⍟ These names already exist. You can `update` them to your
new definition:
closeSocket : Socket ->{IO, Exception} ()
putBytes : Handle -> Bytes ->{IO, Exception} ()
serverSocket : Optional Text
-> Text
->{IO, Exception} Socket
Exception.unsafeRun! : '{g, Exception} a -> '{g} a
closeSocket : Socket ->{IO, Exception} ()
putBytes : Handle
-> Bytes
->{IO, Exception} ()
serverSocket : Optional Text
-> Text
->{IO, Exception} Socket
```
```ucm

View File

@ -1,13 +1,42 @@
# Tests for TLS builtins
```ucm:hide
.> builtins.merge
.> builtins.mergeio
.> cd builtin
.> load unison-src/transcripts-using-base/base.u
.> add
```
```unison:hide
-- generated with:
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 365 -out cert.pem
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 3650 -out cert.pem
self_signed_key_pem = "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBrpp+SxjCz/aQ\nQXT2hKXrT3lZ3Ek1VT/kgNre3J/RUyNZjZnZXCMyNjZ4IxYKxcCAIgGtfFpgvkzT\n5NRGZKLlSX4Y8HayV3gdEXO9hq4w/i/s+I0tOAJkVtHolXrrziZ7/4NZwMTbbqhO\n5hHHhbtBIpvNSw8el3AY3APkQ37+wM3fbvyeuG0ekoLqTa371W+/Z7pOi7QXYGEa\n8YHSNkuRKY46C4Y8oeWHOlSbQKu151GLuyQu74bnecGDN4KBdz9nyyKCCTpBsJpU\ni9Ozq3cps5L8dnN1zUNgaTyWp9kO3vbaTU8MY7p/dc7hNJ8pmGtSiiSs1xvni4Xl\nCBXBesxTAgMBAAECggEAAUtfcPSjh7nIFhK562PbkAUJ9JXKT3bwZGCQFek3kDiU\nBecyXgeFnLJMDuV9IjlMHg8cH8Ky/+6FqOzglk/Z3tps41HIGU0IWnlhYqThySYJ\nv/WxS9oR+gWyhXFqTuUj0LRWdmUZa7YDnfNfrwuvwrGuhOK5iSTN9PyTchUZZi50\ntxcNS/C3rk63c7TZLfuwxwGoUCeJvZZ/rmeVchhsuoo3QdSW0Aee7UtFtnvBfLCK\nXKdz+3q49fLZlDyx9/olJh+TY7GuF+G/LSfyQGi85beQhkXUH8/gIQIRI8INIEPB\n0XeTlv7Sgw5upqplJvHCXjAa+jz/Mo87znXBTMoIIQKBgQDorAlZCjzKxGDIaZoD\nDBXYzhSnnIhthThW4edCQ9/ZnJpX4vdTw4FngW504d8SPStMCYeBeMt8iwTczI4W\nHfK+AlVTlPfH/9NnIVADqqr9kobJW6782MYSW2/758d+L5bq8NGATyh8nPll9joN\nYAk7tNO2bGO2bEk2DbZMf3qnOQKBgQDVGdD005kUT3D+DfgeLTGzwk/2wCCPjoJ5\n6fsjsFAeZWU/qioIB3xHt1w8NsT6O+7XOKp/GRbsvsJR9Z/zmA3Ii5yrHYn48UzM\n+UyGLv+2HCpO+8A3szz/aDhKIxNFpXyZzvOXdtqBwTQbICOW2WRWOOgDrS2W1i9l\nD69xRLqj6wKBgBW0xwJ5hAZen7DSuT2DiR46y45/efLNtN3WIV77OgzxIS0FzZEQ\n8ieX2Zgp4kevUTS8xtl7TXCG/6MhqjfB/31edltf0GXmJfC/GNneuCkD3HM4jHCm\nQIRB54aWrvPEuM2ePc08lUha1KGAgRXyWaoqSn4ASqUgIQxb5x/n3KdxAoGAXlD0\nyMc2Q2T9r5PjMwfxrYvc9GsIfkEmwmqqupr4etuJumnH/JHDkcI30nazK8WG6j6s\nR2CFYvby7m92AcxUnWQdTSbfwAycX0QfeGwoxSMmHpsR8hUkdC5ea4Gmr/aUdUbB\nTVJPV4p5U2AgIE3LONYq6iWlvdLCW0pb7hfrO00CgYAb8bXz9BNow4soEkSbQysg\n4sGAr1+iSPY+ErffKRDpcFRnWcQdnTfI4xd8bgnC6OZwVpLbRZaZf3opDJ+axWqa\nEgAeHErTDY4R8aMecvyQj780sQ35kVq4VK0rSQyiKRBcjEust8UEzwYsUog2ysN0\n3zLHVEvFTfwOSctnEQRw1w==\n-----END PRIVATE KEY-----\n"
join strs = List.foldLeft (a -> b -> b ++ a ++ "\n") "" strs
self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk1rv2Sx5XSK17BZSV4t7gwDQYJKoZIhvcNAQEL\nBQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv\nbjELMAkGA1UEBhMCVVMwHhcNMjEwMTIyMDkxMTE3WhcNMjIwMTIyMDkxMTE3WjA6\nMRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw\nCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGumn5L\nGMLP9pBBdPaEpetPeVncSTVVP+SA2t7cn9FTI1mNmdlcIzI2NngjFgrFwIAiAa18\nWmC+TNPk1EZkouVJfhjwdrJXeB0Rc72GrjD+L+z4jS04AmRW0eiVeuvOJnv/g1nA\nxNtuqE7mEceFu0Eim81LDx6XcBjcA+RDfv7Azd9u/J64bR6SgupNrfvVb79nuk6L\ntBdgYRrxgdI2S5EpjjoLhjyh5Yc6VJtAq7XnUYu7JC7vhud5wYM3goF3P2fLIoIJ\nOkGwmlSL07Ordymzkvx2c3XNQ2BpPJan2Q7e9tpNTwxjun91zuE0nymYa1KKJKzX\nG+eLheUIFcF6zFMCAwEAAaNTMFEwHQYDVR0OBBYEFFE3RQYASDWtwSdXL+qtQrjy\nH4SZMB8GA1UdIwQYMBaAFFE3RQYASDWtwSdXL+qtQrjyH4SZMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH7D8W68cR0QvNNPugCY7lPvA/F94Qam\nwCC2A55edcagfjqFy77xx4Ljrd2TC19yiSzyeeJ+YuohbcipLce90BaaaiYq9aah\n5DICDCUhm1qbhJzqNB2Lqgl4aN+jRMeRVC+rpQBYBNmdPBqdv/k+T2uyghwmLWXe\n/AxCjCLA0zoYzOMytS86veD6CQbF5DpSTZx5dyZTeGhk2izhoM8cgiu+/7YncAbJ\nt7b7UT5Yu3+z1hAdUF5Q21bkEksGBC8UW0G0PMy8XNRMuMsz+2LC39u3u7QyX/+e\nuQGST3aCreV27zd0lrF8LHjwD2XcjVVzHy46VYQvf1r+6gatedDBjqc=\n-----END CERTIFICATE-----\n"
self_signed_key_pem="-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDtV0Lqk9i5DKJG\ne5zwDFuxHxSxhOygCuq6Jl4xonsjl4hdvXxUUiuqxGGbv4x9HSvavpHwyriGiIRQ\noIjanWiNK9Jp6VDYWOvErnTG/+Rfm1vCoUKQvn8lDrD9knSPUoTz3Cz7JS8FE/rr\nFR3IRyXa0gpXmvIwX16SeCS/Lb/Le9o1HJh9DrkxVyoFq3zlX1OE0AVV0a014IDB\nNprqLITwiVzyDPQkP8rbJF9WPI5afzW8+3+v5UanIFknOOPaJl8pf3gmqI5g8fxk\n/SSMlPgnLd1Fi7h90gBygdpJw3do3/ZA1IOvmFQ+LXE1xtqU1Ay3f3At3DiJgTxP\n8mwBYdtdAgMBAAECggEBAMo85QRF3xIvtcchZeUWYrtWpKdvgMIPC1x7fSAGN69o\nXAakg+DF8/ebRyET435o8QmAAZOQ6hOZGEYrxPGj14cTpEQjT4RKoPwDO/al7c+Z\n7mK2TqZP7L+C+UXZGgFWa3vwTVPjp2FIWTMf1zTli1geSjnECkM1wLxGK+nL7fZQ\nesHXPkJJG5AqzA84bJ/fY5OQ/dfcCxnHEv5XpHPq6VFgXg7jtcNbr1R9EBiQfreN\nU7Hd38R77jYjL1fT71HwEUQ0cwavfxTu0jZFXJxEC7CC1J65QXUguZXLf9vwgSB0\nm0gZgeJlQ905bDJrxUcqCFxdROy/SndP6qFnJSCsfwECgYEA+2cld/WCieUGstJd\njsIrJ6f/e+uuOSTnGTtnsBX6KoiHdcg3sVVVK18xI9El9V+YX9SjN37XeGFe/Wzu\ngE3M4A3Jqz7cgdNj/PaKjqQwJWNbcJnL5ku6eQvcAIpc5gAZxXVCPIbY1ZpeYcsh\nMwr3cOEpQu8UVFBbn/OeJ1r07dECgYEA8a5J3Ls5PSxXq8NDrkAxt3vUJIWLGQQJ\nbV2aGDI2XP2N+vh2WML9rlFeyyBOeRxK9TsErVOaEeOcQZV97//fzIGxCU+SXyiC\nnVMXT2U1mzOu5qPfzLO5Ga4sunxqKDman6NM2IPw2NPA7zMWNQMEIHAerwYZzjm5\nB5tFcMA8e80CgYBgF8rwkTz2LD5lN5dfK8SHAeXbnfgYC4zxzg0R9zSJ8WmlkYQI\nGk/VpisIP7c8lO+PIZ3JZohBkSZXw71d+V7n/R0qgXqTfRNo62uGnidxAws+fOq8\n+hEql2feJQThPQScvvc0X26eJsUQqC3mbripwsacuPmSSKzc9Kds741TIQKBgQCd\nXnG2CytATAliTKlbY218HmOKzHJAfcJttk9KhhekAW5cB0F4lq98vHtPJOA0OFoO\nyLlI63EdSOpMQj1Y83IUxjYy699Rmx1BuAMrral0P/kZMYfe0QAsWp/BZpXxT2EB\npeG58l/3sBqnJsrFBgu/24H/UaeoAyoaa96Rhntb2QKBgQCSEkcUnzTvoUyMFN14\n8NttxOUZiSsCmgoXk6Rk2QKyCPsJocGS4BffGt3kOMcotz/0YsvM1TBBLB7vIaAy\nE1eWLBxK4yYeS8dKXwiCZn170yaJyjoBwZC1RgqQiKa5Y22Di7KjJoMa4Da8Tk4z\nFbE5dBApbLhvNTyQ7BHZxlfmdg==\n-----END PRIVATE KEY-----"
self_signed_cert_pem2 = join [
"-----BEGIN CERTIFICATE-----",
"MIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL",
"BQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv",
"bjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6",
"MRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw",
"CQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT",
"2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK",
"uIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl",
"LwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR",
"rTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao",
"jmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c",
"OImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J",
"NbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF",
"MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M",
"P7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U",
"iPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW",
"q+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW",
"uXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ",
"Z4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=",
"-----END CERTIFICATE-----"]
```
```ucm:hide
@ -19,7 +48,7 @@ self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk
First lets make sure we can load our cert and private key
```unison
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
Left (Failure _ t _) -> [Fail t]
Right _ -> [Ok "succesfully decoded self_signed_pem"]
@ -39,7 +68,7 @@ serverThread portVar toSend = 'let
go: '{io2.IO, Exception}()
go = 'let
-- load our self signed cert
cert = decodeCert (toUtf8 self_signed_cert_pem)
cert = decodeCert (toUtf8 self_signed_cert_pem2)
-- assume there is exactly one key decoded from our Bytes
key = match (decodePrivateKey (toUtf8 self_signed_key_pem)) with k +: _ -> k
@ -68,9 +97,13 @@ serverThread portVar toSend = 'let
-- attach TLS to our TCP connection
tls = newServer tlsconfig sock'
printLine "oooooooooooooooo"
-- try to handshake the TLS connection with the client
handshake tls
match handshake.impl tls with
Right _ -> printLine "no error on server side"
Left (Failure _ t _) -> printLine ("error " ++ t)
printLine "iiiiiiiiiiiiiii"
-- send our message over our tls channel
send tls (toUtf8 toSend)
terminate tls
@ -94,17 +127,22 @@ testClient cert hostname portVar _ =
port = take portVar
-- create a tcp connection with the server
watch ("client connecting to port: " ++ (toText port)) ()
sock = clientSocket "127.0.0.1" (Nat.toText port)
-- attach the TLS client to the TCP socket
tls = newClient tlsconfig sock
watch ("client connecting to port: " ++ (toText port)) ()
printLine "5555555555555555555"
-- verify that the server presents us with a certificate chain for
-- test.unison.cloud originating with a certificate we trust, and
-- that the server can use a compatible TLS version and cipher
handshake tls
match handshake.impl tls with
Right _ -> printLine "no eeror on client side"
Left (Failure _ t _) -> printLine ("error " ++ t)
printLine "666666666666666666"
-- receive a message from the server
fromUtf8 (receive tls)
@ -114,14 +152,17 @@ testConnectSelfSigned _ =
-- Server
portVar = !MVar.newEmpty
toSend = "12345"
forkComp (serverThread portVar toSend)
tid = forkComp (serverThread portVar toSend)
-- Client
cert = decodeCert (toUtf8 self_signed_cert_pem)
cert = decodeCert (toUtf8 self_signed_cert_pem2)
received = !(testClient (Some cert) "test.unison.cloud" portVar)
kill.impl tid
expectU "should have reaped what we've sown" toSend received
runTest test
-- this client will trust whatever certs the system trusts
@ -141,11 +182,12 @@ testCAReject _ =
-- Server
portVar = !MVar.newEmpty
toSend = "12345"
forkComp (serverThread portVar toSend)
tid = forkComp (serverThread portVar toSend)
-- Client
testClient None "test.unison.cloud" portVar |> toEither |> checkError |> emit
kill.impl tid
runTest test
@ -164,18 +206,25 @@ testCNReject _ =
-- Server
portVar = !MVar.newEmpty
toSend = "12345"
forkComp (serverThread portVar toSend)
tid = forkComp (serverThread portVar toSend)
unsafeRun! '(printLine "started tid")
-- Client
testClient None "wrong.host.name" portVar |> toEither |> checkError |> emit
unsafeRun! '(printLine "started client")
kill.impl tid
unsafeRun! '(printLine "killed")
runTest test
```
```ucm
.> add
.> io.test testConnectSelfSigned
.> io.test testCAReject
.> io.test testCNReject
--- STU: I'm commenting out this because there is a problem with Tls.handshake, see #2834
--- .> add
--- .> io.test testConnectSelfSigned
--- .> io.test testCAReject
--- .> io.test testCNReject
```

View File

@ -2,12 +2,33 @@
```unison
-- generated with:
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 365 -out cert.pem
-- openssl req -newkey rsa:2048 -subj '/CN=test.unison.cloud/O=Unison/C=US' -nodes -keyout key.pem -x509 -days 3650 -out cert.pem
self_signed_key_pem = "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDBrpp+SxjCz/aQ\nQXT2hKXrT3lZ3Ek1VT/kgNre3J/RUyNZjZnZXCMyNjZ4IxYKxcCAIgGtfFpgvkzT\n5NRGZKLlSX4Y8HayV3gdEXO9hq4w/i/s+I0tOAJkVtHolXrrziZ7/4NZwMTbbqhO\n5hHHhbtBIpvNSw8el3AY3APkQ37+wM3fbvyeuG0ekoLqTa371W+/Z7pOi7QXYGEa\n8YHSNkuRKY46C4Y8oeWHOlSbQKu151GLuyQu74bnecGDN4KBdz9nyyKCCTpBsJpU\ni9Ozq3cps5L8dnN1zUNgaTyWp9kO3vbaTU8MY7p/dc7hNJ8pmGtSiiSs1xvni4Xl\nCBXBesxTAgMBAAECggEAAUtfcPSjh7nIFhK562PbkAUJ9JXKT3bwZGCQFek3kDiU\nBecyXgeFnLJMDuV9IjlMHg8cH8Ky/+6FqOzglk/Z3tps41HIGU0IWnlhYqThySYJ\nv/WxS9oR+gWyhXFqTuUj0LRWdmUZa7YDnfNfrwuvwrGuhOK5iSTN9PyTchUZZi50\ntxcNS/C3rk63c7TZLfuwxwGoUCeJvZZ/rmeVchhsuoo3QdSW0Aee7UtFtnvBfLCK\nXKdz+3q49fLZlDyx9/olJh+TY7GuF+G/LSfyQGi85beQhkXUH8/gIQIRI8INIEPB\n0XeTlv7Sgw5upqplJvHCXjAa+jz/Mo87znXBTMoIIQKBgQDorAlZCjzKxGDIaZoD\nDBXYzhSnnIhthThW4edCQ9/ZnJpX4vdTw4FngW504d8SPStMCYeBeMt8iwTczI4W\nHfK+AlVTlPfH/9NnIVADqqr9kobJW6782MYSW2/758d+L5bq8NGATyh8nPll9joN\nYAk7tNO2bGO2bEk2DbZMf3qnOQKBgQDVGdD005kUT3D+DfgeLTGzwk/2wCCPjoJ5\n6fsjsFAeZWU/qioIB3xHt1w8NsT6O+7XOKp/GRbsvsJR9Z/zmA3Ii5yrHYn48UzM\n+UyGLv+2HCpO+8A3szz/aDhKIxNFpXyZzvOXdtqBwTQbICOW2WRWOOgDrS2W1i9l\nD69xRLqj6wKBgBW0xwJ5hAZen7DSuT2DiR46y45/efLNtN3WIV77OgzxIS0FzZEQ\n8ieX2Zgp4kevUTS8xtl7TXCG/6MhqjfB/31edltf0GXmJfC/GNneuCkD3HM4jHCm\nQIRB54aWrvPEuM2ePc08lUha1KGAgRXyWaoqSn4ASqUgIQxb5x/n3KdxAoGAXlD0\nyMc2Q2T9r5PjMwfxrYvc9GsIfkEmwmqqupr4etuJumnH/JHDkcI30nazK8WG6j6s\nR2CFYvby7m92AcxUnWQdTSbfwAycX0QfeGwoxSMmHpsR8hUkdC5ea4Gmr/aUdUbB\nTVJPV4p5U2AgIE3LONYq6iWlvdLCW0pb7hfrO00CgYAb8bXz9BNow4soEkSbQysg\n4sGAr1+iSPY+ErffKRDpcFRnWcQdnTfI4xd8bgnC6OZwVpLbRZaZf3opDJ+axWqa\nEgAeHErTDY4R8aMecvyQj780sQ35kVq4VK0rSQyiKRBcjEust8UEzwYsUog2ysN0\n3zLHVEvFTfwOSctnEQRw1w==\n-----END PRIVATE KEY-----\n"
join strs = List.foldLeft (a -> b -> b ++ a ++ "\n") "" strs
self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk1rv2Sx5XSK17BZSV4t7gwDQYJKoZIhvcNAQEL\nBQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv\nbjELMAkGA1UEBhMCVVMwHhcNMjEwMTIyMDkxMTE3WhcNMjIwMTIyMDkxMTE3WjA6\nMRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw\nCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGumn5L\nGMLP9pBBdPaEpetPeVncSTVVP+SA2t7cn9FTI1mNmdlcIzI2NngjFgrFwIAiAa18\nWmC+TNPk1EZkouVJfhjwdrJXeB0Rc72GrjD+L+z4jS04AmRW0eiVeuvOJnv/g1nA\nxNtuqE7mEceFu0Eim81LDx6XcBjcA+RDfv7Azd9u/J64bR6SgupNrfvVb79nuk6L\ntBdgYRrxgdI2S5EpjjoLhjyh5Yc6VJtAq7XnUYu7JC7vhud5wYM3goF3P2fLIoIJ\nOkGwmlSL07Ordymzkvx2c3XNQ2BpPJan2Q7e9tpNTwxjun91zuE0nymYa1KKJKzX\nG+eLheUIFcF6zFMCAwEAAaNTMFEwHQYDVR0OBBYEFFE3RQYASDWtwSdXL+qtQrjy\nH4SZMB8GA1UdIwQYMBaAFFE3RQYASDWtwSdXL+qtQrjyH4SZMA8GA1UdEwEB/wQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH7D8W68cR0QvNNPugCY7lPvA/F94Qam\nwCC2A55edcagfjqFy77xx4Ljrd2TC19yiSzyeeJ+YuohbcipLce90BaaaiYq9aah\n5DICDCUhm1qbhJzqNB2Lqgl4aN+jRMeRVC+rpQBYBNmdPBqdv/k+T2uyghwmLWXe\n/AxCjCLA0zoYzOMytS86veD6CQbF5DpSTZx5dyZTeGhk2izhoM8cgiu+/7YncAbJ\nt7b7UT5Yu3+z1hAdUF5Q21bkEksGBC8UW0G0PMy8XNRMuMsz+2LC39u3u7QyX/+e\nuQGST3aCreV27zd0lrF8LHjwD2XcjVVzHy46VYQvf1r+6gatedDBjqc=\n-----END CERTIFICATE-----\n"
self_signed_key_pem="-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDtV0Lqk9i5DKJG\ne5zwDFuxHxSxhOygCuq6Jl4xonsjl4hdvXxUUiuqxGGbv4x9HSvavpHwyriGiIRQ\noIjanWiNK9Jp6VDYWOvErnTG/+Rfm1vCoUKQvn8lDrD9knSPUoTz3Cz7JS8FE/rr\nFR3IRyXa0gpXmvIwX16SeCS/Lb/Le9o1HJh9DrkxVyoFq3zlX1OE0AVV0a014IDB\nNprqLITwiVzyDPQkP8rbJF9WPI5afzW8+3+v5UanIFknOOPaJl8pf3gmqI5g8fxk\n/SSMlPgnLd1Fi7h90gBygdpJw3do3/ZA1IOvmFQ+LXE1xtqU1Ay3f3At3DiJgTxP\n8mwBYdtdAgMBAAECggEBAMo85QRF3xIvtcchZeUWYrtWpKdvgMIPC1x7fSAGN69o\nXAakg+DF8/ebRyET435o8QmAAZOQ6hOZGEYrxPGj14cTpEQjT4RKoPwDO/al7c+Z\n7mK2TqZP7L+C+UXZGgFWa3vwTVPjp2FIWTMf1zTli1geSjnECkM1wLxGK+nL7fZQ\nesHXPkJJG5AqzA84bJ/fY5OQ/dfcCxnHEv5XpHPq6VFgXg7jtcNbr1R9EBiQfreN\nU7Hd38R77jYjL1fT71HwEUQ0cwavfxTu0jZFXJxEC7CC1J65QXUguZXLf9vwgSB0\nm0gZgeJlQ905bDJrxUcqCFxdROy/SndP6qFnJSCsfwECgYEA+2cld/WCieUGstJd\njsIrJ6f/e+uuOSTnGTtnsBX6KoiHdcg3sVVVK18xI9El9V+YX9SjN37XeGFe/Wzu\ngE3M4A3Jqz7cgdNj/PaKjqQwJWNbcJnL5ku6eQvcAIpc5gAZxXVCPIbY1ZpeYcsh\nMwr3cOEpQu8UVFBbn/OeJ1r07dECgYEA8a5J3Ls5PSxXq8NDrkAxt3vUJIWLGQQJ\nbV2aGDI2XP2N+vh2WML9rlFeyyBOeRxK9TsErVOaEeOcQZV97//fzIGxCU+SXyiC\nnVMXT2U1mzOu5qPfzLO5Ga4sunxqKDman6NM2IPw2NPA7zMWNQMEIHAerwYZzjm5\nB5tFcMA8e80CgYBgF8rwkTz2LD5lN5dfK8SHAeXbnfgYC4zxzg0R9zSJ8WmlkYQI\nGk/VpisIP7c8lO+PIZ3JZohBkSZXw71d+V7n/R0qgXqTfRNo62uGnidxAws+fOq8\n+hEql2feJQThPQScvvc0X26eJsUQqC3mbripwsacuPmSSKzc9Kds741TIQKBgQCd\nXnG2CytATAliTKlbY218HmOKzHJAfcJttk9KhhekAW5cB0F4lq98vHtPJOA0OFoO\nyLlI63EdSOpMQj1Y83IUxjYy699Rmx1BuAMrral0P/kZMYfe0QAsWp/BZpXxT2EB\npeG58l/3sBqnJsrFBgu/24H/UaeoAyoaa96Rhntb2QKBgQCSEkcUnzTvoUyMFN14\n8NttxOUZiSsCmgoXk6Rk2QKyCPsJocGS4BffGt3kOMcotz/0YsvM1TBBLB7vIaAy\nE1eWLBxK4yYeS8dKXwiCZn170yaJyjoBwZC1RgqQiKa5Y22Di7KjJoMa4Da8Tk4z\nFbE5dBApbLhvNTyQ7BHZxlfmdg==\n-----END PRIVATE KEY-----"
self_signed_cert_pem2 = join [
"-----BEGIN CERTIFICATE-----",
"MIIDVTCCAj2gAwIBAgIUdMNT5sYMfDJYH48Rh8LrlN+5wwgwDQYJKoZIhvcNAQEL",
"BQAwOjEaMBgGA1UEAwwRdGVzdC51bmlzb24uY2xvdWQxDzANBgNVBAoMBlVuaXNv",
"bjELMAkGA1UEBhMCVVMwHhcNMjIwMTI0MjAxNzQ2WhcNMzIwMTIyMjAxNzQ2WjA6",
"MRowGAYDVQQDDBF0ZXN0LnVuaXNvbi5jbG91ZDEPMA0GA1UECgwGVW5pc29uMQsw",
"CQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO1XQuqT",
"2LkMokZ7nPAMW7EfFLGE7KAK6romXjGieyOXiF29fFRSK6rEYZu/jH0dK9q+kfDK",
"uIaIhFCgiNqdaI0r0mnpUNhY68SudMb/5F+bW8KhQpC+fyUOsP2SdI9ShPPcLPsl",
"LwUT+usVHchHJdrSClea8jBfXpJ4JL8tv8t72jUcmH0OuTFXKgWrfOVfU4TQBVXR",
"rTXggME2muoshPCJXPIM9CQ/ytskX1Y8jlp/Nbz7f6/lRqcgWSc449omXyl/eCao",
"jmDx/GT9JIyU+Cct3UWLuH3SAHKB2knDd2jf9kDUg6+YVD4tcTXG2pTUDLd/cC3c",
"OImBPE/ybAFh210CAwEAAaNTMFEwHQYDVR0OBBYEFIfwxpuqtqxfCpaJGW32jH2J",
"NbnYMB8GA1UdIwQYMBaAFIfwxpuqtqxfCpaJGW32jH2JNbnYMA8GA1UdEwEB/wQF",
"MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKh7EDo5XjSd6J190WGH3V8v49J0Sh8M",
"P7APe1eL8eTkW1Vh7/QCOhRpkSnyCz2OxJjjeFVAsCO3aLxlRM6wQZQKXu45iM2U",
"iPmv7ECS5xUn7LqRZd/JG1P6jvRPtBC1+oqA+NNDe27wzQp3rWyDG3pWZga8jJfW",
"q+2xQ+s6GfzszxYZ/8MLn4zaUSymnOA+70yQ8czXkSO7MT2jJ7QDX8jxuJPZZARW",
"uXeAYPRqD+b4MjdBATEtxgPTDWEi8gtfHFGUgInFhD4hOu+D3NLiE6lfR5brUqpQ",
"Z4v8prCI8OjGSUx1dIJhqQHB5O0vdaxO0hkVdfqDVE93UrGBPwBRDlo=",
"-----END CERTIFICATE-----"]
```
# Using an alternative certificate store
@ -15,7 +36,7 @@ self_signed_cert_pem = "-----BEGIN CERTIFICATE-----\nMIIDVTCCAj2gAwIBAgIUZI9WPZk
First lets make sure we can load our cert and private key
```unison
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
Left (Failure _ t _) -> [Fail t]
Right _ -> [Ok "succesfully decoded self_signed_pem"]
@ -34,7 +55,7 @@ test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
Now evaluating any watch expressions (lines starting with
`>`)... Ctrl+C cancels.
1 | test> match (decodeCert.impl (toUtf8 self_signed_cert_pem) with
1 | test> match (decodeCert.impl (toUtf8 self_signed_cert_pem2) with
✅ Passed succesfully decoded self_signed_pem
@ -53,7 +74,7 @@ serverThread portVar toSend = 'let
go: '{io2.IO, Exception}()
go = 'let
-- load our self signed cert
cert = decodeCert (toUtf8 self_signed_cert_pem)
cert = decodeCert (toUtf8 self_signed_cert_pem2)
-- assume there is exactly one key decoded from our Bytes
key = match (decodePrivateKey (toUtf8 self_signed_key_pem)) with k +: _ -> k
@ -82,9 +103,13 @@ serverThread portVar toSend = 'let
-- attach TLS to our TCP connection
tls = newServer tlsconfig sock'
printLine "oooooooooooooooo"
-- try to handshake the TLS connection with the client
handshake tls
match handshake.impl tls with
Right _ -> printLine "no error on server side"
Left (Failure _ t _) -> printLine ("error " ++ t)
printLine "iiiiiiiiiiiiiii"
-- send our message over our tls channel
send tls (toUtf8 toSend)
terminate tls
@ -108,17 +133,22 @@ testClient cert hostname portVar _ =
port = take portVar
-- create a tcp connection with the server
watch ("client connecting to port: " ++ (toText port)) ()
sock = clientSocket "127.0.0.1" (Nat.toText port)
-- attach the TLS client to the TCP socket
tls = newClient tlsconfig sock
watch ("client connecting to port: " ++ (toText port)) ()
printLine "5555555555555555555"
-- verify that the server presents us with a certificate chain for
-- test.unison.cloud originating with a certificate we trust, and
-- that the server can use a compatible TLS version and cipher
handshake tls
match handshake.impl tls with
Right _ -> printLine "no eeror on client side"
Left (Failure _ t _) -> printLine ("error " ++ t)
printLine "666666666666666666"
-- receive a message from the server
fromUtf8 (receive tls)
@ -128,14 +158,17 @@ testConnectSelfSigned _ =
-- Server
portVar = !MVar.newEmpty
toSend = "12345"
forkComp (serverThread portVar toSend)
tid = forkComp (serverThread portVar toSend)
-- Client
cert = decodeCert (toUtf8 self_signed_cert_pem)
cert = decodeCert (toUtf8 self_signed_cert_pem2)
received = !(testClient (Some cert) "test.unison.cloud" portVar)
kill.impl tid
expectU "should have reaped what we've sown" toSend received
runTest test
-- this client will trust whatever certs the system trusts
@ -155,11 +188,12 @@ testCAReject _ =
-- Server
portVar = !MVar.newEmpty
toSend = "12345"
forkComp (serverThread portVar toSend)
tid = forkComp (serverThread portVar toSend)
-- Client
testClient None "test.unison.cloud" portVar |> toEither |> checkError |> emit
kill.impl tid
runTest test
@ -178,11 +212,16 @@ testCNReject _ =
-- Server
portVar = !MVar.newEmpty
toSend = "12345"
forkComp (serverThread portVar toSend)
tid = forkComp (serverThread portVar toSend)
unsafeRun! '(printLine "started tid")
-- Client
testClient None "wrong.host.name" portVar |> toEither |> checkError |> emit
unsafeRun! '(printLine "started client")
kill.impl tid
unsafeRun! '(printLine "killed")
runTest test
```
@ -206,48 +245,9 @@ testCNReject _ =
```
```ucm
.> add
⍟ I've added these definitions:
serverThread : MVar Nat -> Text -> '{IO} ()
testCAReject : '{IO} [Result]
testCNReject : '{IO} [Result]
testClient : Optional SignedCert
-> Text
-> MVar Nat
-> '{IO, Exception} Text
testConnectSelfSigned : '{IO} [Result]
.> io.test testConnectSelfSigned
New test results:
◉ testConnectSelfSigned should have reaped what we've sown
✅ 1 test(s) passing
Tip: Use view testConnectSelfSigned to view the source of a
test.
.> io.test testCAReject
New test results:
◉ testCAReject correctly rejected self-signed cert
✅ 1 test(s) passing
Tip: Use view testCAReject to view the source of a test.
.> io.test testCNReject
New test results:
◉ testCNReject correctly rejected self-signed cert
✅ 1 test(s) passing
Tip: Use view testCNReject to view the source of a test.
--- STU: I'm commenting out this because there is a problem with Tls.handshake, see #2834
--- .> add
--- .> io.test testConnectSelfSigned
--- .> io.test testCAReject
--- .> io.test testCNReject
```

View File

@ -0,0 +1,18 @@
Regression test for https://github.com/unisonweb/unison/pull/2819
```ucm:hide
.> builtins.merge
```
```unison
hangExample : Boolean
hangExample =
("a long piece of text to hang the line" == "")
&& ("a long piece of text to hang the line" == "")
```
```ucm
.> add
.> view hangExample
```

View File

@ -0,0 +1,35 @@
Regression test for https://github.com/unisonweb/unison/pull/2819
```unison
hangExample : Boolean
hangExample =
("a long piece of text to hang the line" == "")
&& ("a long piece of text to hang the line" == "")
```
```ucm
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These new definitions are ok to `add`:
hangExample : Boolean
```
```ucm
.> add
⍟ I've added these definitions:
hangExample : Boolean
.> view hangExample
hangExample : Boolean
hangExample =
("a long piece of text to hang the line" == "")
&& ("a long piece of text to hang the line" == "")
```

View File

@ -77,6 +77,14 @@ We can display the guide before and after adding it to the codebase:
100
also:
match 1 with
1 -> "hi"
_ -> "goodbye"
"hi"
To include a typechecked snippet of code without
evaluating it, you can do:
@ -278,6 +286,14 @@ We can display the guide before and after adding it to the codebase:
100
also:
match 1 with
1 -> "hi"
_ -> "goodbye"
"hi"
To include a typechecked snippet of code without
evaluating it, you can do:
@ -485,6 +501,14 @@ rendered = Pretty.get (docFormatConsole doc.guide)
100
also:
match 1 with
1 -> "hi"
_ -> "goodbye"
"hi"
To include a typechecked snippet of code without
evaluating it, you can do:
@ -679,6 +703,14 @@ rendered = Pretty.get (docFormatConsole doc.guide)
100
also:
match 1 with
1 -> "hi"
_ -> "goodbye"
"hi"
To include a typechecked snippet of code without
evaluating it, you can do:
@ -1795,6 +1827,29 @@ rendered = Pretty.get (docFormatConsole doc.guide)
!Indent
(!Lit (Right (Plain " ")))
(!Lit (Right (Plain " ")))
(!Annotated.Group
(!Wrap
(!Lit (Right (Plain "also:"))))),
!Lit (Right (Plain "\n")),
!Lit (Right (Plain "\n")),
!Indent
(!Lit (Right (Plain " ")))
(!Lit (Right (Plain " ")))
(!Annotated.Group
(!Lit
(Left
(Eval
(Term.Term
(Any
(_ ->
(match 1 with
1 -> "hi"
_ -> "goodbye")))))))),
!Lit (Right (Plain "\n")),
!Lit (Right (Plain "\n")),
!Indent
(!Lit (Right (Plain " ")))
(!Lit (Right (Plain " ")))
(!Annotated.Group
(!Wrap
(!Annotated.Append

View File

@ -2,12 +2,11 @@
.> display List.map
go f i as acc =
_pattern = List.at i as
match _pattern with
None -> acc
Some _pattern1 ->
match List.at i as with
None -> acc
Some a ->
use Nat +
go f (i + 1) as (acc :+ f _pattern)
go f (i + 1) as (acc :+ f a)
f a -> go f 0 a []
```

View File

@ -0,0 +1,32 @@
# Ensure type dependencies are properly considered in slurping
https://github.com/unisonweb/unison/pull/2821
```ucm:hide
.> builtins.merge
```
Define a type.
```unison:hide
structural type Y = Y
```
```ucm:hide
.> add
```
Now, we update `Y`, and add a new type `Z` which depends on it.
```unison
structural type Z = Z Y
structural type Y = Y Nat
```
Adding should fail for BOTH definitions, `Y` needs an update and `Z` is blocked by `Y`.
```ucm:error
.> add
-- This shouldn't exist, because it should've been blocked.
.> view Z
```

View File

@ -0,0 +1,56 @@
# Ensure type dependencies are properly considered in slurping
https://github.com/unisonweb/unison/pull/2821
Define a type.
```unison
structural type Y = Y
```
Now, we update `Y`, and add a new type `Z` which depends on it.
```unison
structural type Z = Z Y
structural type Y = Y Nat
```
```ucm
I found and typechecked these definitions in scratch.u. If you
do an `add` or `update`, here's how your codebase would
change:
⍟ These new definitions are ok to `add`:
structural type Z
⍟ These names already exist. You can `update` them to your
new definition:
structural type Y
(The old definition is also named builtin.Unit. I'll
update this name too.)
```
Adding should fail for BOTH definitions, `Y` needs an update and `Z` is blocked by `Y`.
```ucm
.> add
x These definitions failed:
Reason
needs update structural type Y
blocked structural type Z
Tip: Use `help filestatus` to learn more.
-- This shouldn't exist, because it should've been blocked.
.> view Z
⚠️
The following names were not found in the codebase. Check your spelling.
Z
```