module Unison.Codebase.Editor.HandleInput.TermResolution ( lookupTermRefs, lookupTermRefWithType, resolveCon, resolveTerm, resolveTermRef, resolveMainRef, ) where import Control.Monad.Reader (ask) import Control.Monad.Trans (liftIO) import Data.Maybe (catMaybes, fromJust) import Data.Set (fromList, toList) import Unison.Cli.Monad (Cli) import Unison.Cli.Monad qualified as Cli import Unison.Cli.NamesUtils qualified as Cli import Unison.Codebase qualified as Codebase import Unison.Codebase.Editor.Output (Output (..)) import Unison.Codebase.Path (hqSplitFromName') import Unison.Codebase.Runtime qualified as Runtime import Unison.ConstructorReference import Unison.HashQualified qualified as HQ import Unison.Name (Name) import Unison.Names (Names) import Unison.NamesWithHistory qualified as Names import Unison.Parser.Ann (Ann) import Unison.PrettyPrintEnv (PrettyPrintEnv) import Unison.PrettyPrintEnv.Names qualified as PPE import Unison.PrettyPrintEnvDecl qualified as PPED import Unison.PrettyPrintEnvDecl.Names qualified as PPED import Unison.Reference (Reference) import Unison.Referent (Referent, pattern Con, pattern Ref) import Unison.Symbol (Symbol) import Unison.Type (Type) import Unison.Typechecker qualified as Typechecker lookupTerm :: HQ.HashQualified Name -> Names -> [Referent] lookupTerm :: HashQualified Name -> Names -> [Referent] lookupTerm HashQualified Name hq Names parseNames = Set Referent -> [Referent] forall a. Set a -> [a] toList (SearchType -> HashQualified Name -> Names -> Set Referent Names.lookupHQTerm SearchType Names.IncludeSuffixes HashQualified Name hq Names parseNames) lookupCon :: HQ.HashQualified Name -> Names -> ([ConstructorReference], [Referent]) lookupCon :: HashQualified Name -> Names -> ([ConstructorReference], [Referent]) lookupCon HashQualified Name hq Names parseNames = [(ConstructorReference, Referent)] -> ([ConstructorReference], [Referent]) forall a b. [(a, b)] -> ([a], [b]) unzip ([(ConstructorReference, Referent)] -> ([ConstructorReference], [Referent])) -> ([Referent] -> [(ConstructorReference, Referent)]) -> [Referent] -> ([ConstructorReference], [Referent]) forall b c a. (b -> c) -> (a -> b) -> a -> c . [Maybe (ConstructorReference, Referent)] -> [(ConstructorReference, Referent)] forall a. [Maybe a] -> [a] catMaybes ([Maybe (ConstructorReference, Referent)] -> [(ConstructorReference, Referent)]) -> ([Referent] -> [Maybe (ConstructorReference, Referent)]) -> [Referent] -> [(ConstructorReference, Referent)] forall b c a. (b -> c) -> (a -> b) -> a -> c . (Referent -> Maybe (ConstructorReference, Referent)) -> [Referent] -> [Maybe (ConstructorReference, Referent)] forall a b. (a -> b) -> [a] -> [b] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap Referent -> Maybe (ConstructorReference, Referent) extract ([Referent] -> ([ConstructorReference], [Referent])) -> [Referent] -> ([ConstructorReference], [Referent]) forall a b. (a -> b) -> a -> b $ HashQualified Name -> Names -> [Referent] lookupTerm HashQualified Name hq Names parseNames where extract :: Referent -> Maybe (ConstructorReference, Referent) extract rt :: Referent rt@(Con ConstructorReference rf ConstructorType _) = (ConstructorReference, Referent) -> Maybe (ConstructorReference, Referent) forall a. a -> Maybe a Just (ConstructorReference rf, Referent rt) extract Referent _ = Maybe (ConstructorReference, Referent) forall a. Maybe a Nothing lookupTermRefs :: HQ.HashQualified Name -> Names -> ([Reference], [Referent]) lookupTermRefs :: HashQualified Name -> Names -> ([Reference' Text Hash], [Referent]) lookupTermRefs HashQualified Name hq Names parseNames = [(Reference' Text Hash, Referent)] -> ([Reference' Text Hash], [Referent]) forall a b. [(a, b)] -> ([a], [b]) unzip ([(Reference' Text Hash, Referent)] -> ([Reference' Text Hash], [Referent])) -> ([Referent] -> [(Reference' Text Hash, Referent)]) -> [Referent] -> ([Reference' Text Hash], [Referent]) forall b c a. (b -> c) -> (a -> b) -> a -> c . [Maybe (Reference' Text Hash, Referent)] -> [(Reference' Text Hash, Referent)] forall a. [Maybe a] -> [a] catMaybes ([Maybe (Reference' Text Hash, Referent)] -> [(Reference' Text Hash, Referent)]) -> ([Referent] -> [Maybe (Reference' Text Hash, Referent)]) -> [Referent] -> [(Reference' Text Hash, Referent)] forall b c a. (b -> c) -> (a -> b) -> a -> c . (Referent -> Maybe (Reference' Text Hash, Referent)) -> [Referent] -> [Maybe (Reference' Text Hash, Referent)] forall a b. (a -> b) -> [a] -> [b] forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap Referent -> Maybe (Reference' Text Hash, Referent) extract ([Referent] -> ([Reference' Text Hash], [Referent])) -> [Referent] -> ([Reference' Text Hash], [Referent]) forall a b. (a -> b) -> a -> b $ HashQualified Name -> Names -> [Referent] lookupTerm HashQualified Name hq Names parseNames where extract :: Referent -> Maybe (Reference' Text Hash, Referent) extract rt :: Referent rt@(Ref Reference' Text Hash rf) = (Reference' Text Hash, Referent) -> Maybe (Reference' Text Hash, Referent) forall a. a -> Maybe a Just (Reference' Text Hash rf, Referent rt) extract Referent _ = Maybe (Reference' Text Hash, Referent) forall a. Maybe a Nothing lookupTermRefWithType :: Codebase.Codebase IO Symbol Ann -> HQ.HashQualified Name -> Cli [(Reference, Type Symbol Ann)] lookupTermRefWithType :: Codebase IO Symbol Ann -> HashQualified Name -> Cli [(Reference' Text Hash, Type Symbol Ann)] lookupTermRefWithType Codebase IO Symbol Ann codebase HashQualified Name name = do Names names <- Cli Names Cli.currentNames IO [(Reference' Text Hash, Type Symbol Ann)] -> Cli [(Reference' Text Hash, Type Symbol Ann)] forall a. IO a -> Cli a forall (m :: * -> *) a. MonadIO m => IO a -> m a liftIO (IO [(Reference' Text Hash, Type Symbol Ann)] -> Cli [(Reference' Text Hash, Type Symbol Ann)]) -> (([Reference' Text Hash], [Referent]) -> IO [(Reference' Text Hash, Type Symbol Ann)]) -> ([Reference' Text Hash], [Referent]) -> Cli [(Reference' Text Hash, Type Symbol Ann)] forall b c a. (b -> c) -> (a -> b) -> a -> c . Codebase IO Symbol Ann -> Transaction [(Reference' Text Hash, Type Symbol Ann)] -> IO [(Reference' Text Hash, Type Symbol Ann)] forall (m :: * -> *) v a b. MonadIO m => Codebase m v a -> Transaction b -> m b Codebase.runTransaction Codebase IO Symbol Ann codebase (Transaction [(Reference' Text Hash, Type Symbol Ann)] -> IO [(Reference' Text Hash, Type Symbol Ann)]) -> (([Reference' Text Hash], [Referent]) -> Transaction [(Reference' Text Hash, Type Symbol Ann)]) -> ([Reference' Text Hash], [Referent]) -> IO [(Reference' Text Hash, Type Symbol Ann)] forall b c a. (b -> c) -> (a -> b) -> a -> c . ([Maybe (Reference' Text Hash, Type Symbol Ann)] -> [(Reference' Text Hash, Type Symbol Ann)]) -> Transaction [Maybe (Reference' Text Hash, Type Symbol Ann)] -> Transaction [(Reference' Text Hash, Type Symbol Ann)] forall a b. (a -> b) -> Transaction a -> Transaction b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap [Maybe (Reference' Text Hash, Type Symbol Ann)] -> [(Reference' Text Hash, Type Symbol Ann)] forall a. [Maybe a] -> [a] catMaybes (Transaction [Maybe (Reference' Text Hash, Type Symbol Ann)] -> Transaction [(Reference' Text Hash, Type Symbol Ann)]) -> (([Reference' Text Hash], [Referent]) -> Transaction [Maybe (Reference' Text Hash, Type Symbol Ann)]) -> ([Reference' Text Hash], [Referent]) -> Transaction [(Reference' Text Hash, Type Symbol Ann)] forall b c a. (b -> c) -> (a -> b) -> a -> c . (Reference' Text Hash -> Transaction (Maybe (Reference' Text Hash, Type Symbol Ann))) -> [Reference' Text Hash] -> Transaction [Maybe (Reference' Text Hash, Type Symbol Ann)] forall (t :: * -> *) (f :: * -> *) a b. (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b) forall (f :: * -> *) a b. Applicative f => (a -> f b) -> [a] -> f [b] traverse Reference' Text Hash -> Transaction (Maybe (Reference' Text Hash, Type Symbol Ann)) annot ([Reference' Text Hash] -> Transaction [Maybe (Reference' Text Hash, Type Symbol Ann)]) -> (([Reference' Text Hash], [Referent]) -> [Reference' Text Hash]) -> ([Reference' Text Hash], [Referent]) -> Transaction [Maybe (Reference' Text Hash, Type Symbol Ann)] forall b c a. (b -> c) -> (a -> b) -> a -> c . ([Reference' Text Hash], [Referent]) -> [Reference' Text Hash] forall a b. (a, b) -> a fst (([Reference' Text Hash], [Referent]) -> Cli [(Reference' Text Hash, Type Symbol Ann)]) -> ([Reference' Text Hash], [Referent]) -> Cli [(Reference' Text Hash, Type Symbol Ann)] forall a b. (a -> b) -> a -> b $ HashQualified Name -> Names -> ([Reference' Text Hash], [Referent]) lookupTermRefs HashQualified Name name Names names where annot :: Reference' Text Hash -> Transaction (Maybe (Reference' Text Hash, Type Symbol Ann)) annot Reference' Text Hash tm = (Type Symbol Ann -> (Reference' Text Hash, Type Symbol Ann)) -> Maybe (Type Symbol Ann) -> Maybe (Reference' Text Hash, Type Symbol Ann) forall a b. (a -> b) -> Maybe a -> Maybe b forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap ((,) Reference' Text Hash tm) (Maybe (Type Symbol Ann) -> Maybe (Reference' Text Hash, Type Symbol Ann)) -> Transaction (Maybe (Type Symbol Ann)) -> Transaction (Maybe (Reference' Text Hash, Type Symbol Ann)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Codebase IO Symbol Ann -> Reference' Text Hash -> Transaction (Maybe (Type Symbol Ann)) forall a (m :: * -> *). BuiltinAnnotation a => Codebase m Symbol a -> Reference' Text Hash -> Transaction (Maybe (Type Symbol a)) Codebase.getTypeOfTerm Codebase IO Symbol Ann codebase Reference' Text Hash tm resolveTerm :: HQ.HashQualified Name -> Cli Referent resolveTerm :: HashQualified Name -> Cli Referent resolveTerm HashQualified Name name = do Names names <- Cli Names Cli.currentNames let pped :: PrettyPrintEnvDecl pped = Namer -> Suffixifier -> PrettyPrintEnvDecl PPED.makePPED (Int -> Names -> Namer PPE.hqNamer Int 10 Names names) (Names -> Suffixifier PPE.suffixifyByHash Names names) let suffixifiedPPE :: PrettyPrintEnv suffixifiedPPE = PrettyPrintEnvDecl -> PrettyPrintEnv PPED.suffixifiedPPE PrettyPrintEnvDecl pped case HashQualified Name -> Names -> [Referent] lookupTerm HashQualified Name name Names names of [] -> Output -> Cli Referent forall a. Output -> Cli a Cli.returnEarly (HQSplit' -> Output TermNotFound (HQSplit' -> Output) -> HQSplit' -> Output forall a b. (a -> b) -> a -> b $ Maybe HQSplit' -> HQSplit' forall a. HasCallStack => Maybe a -> a fromJust Maybe HQSplit' parsed) where parsed :: Maybe HQSplit' parsed = Name -> HQSplit' hqSplitFromName' (Name -> HQSplit') -> Maybe Name -> Maybe HQSplit' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> HashQualified Name -> Maybe Name forall n. HashQualified n -> Maybe n HQ.toName HashQualified Name name [Referent rf] -> Referent -> Cli Referent forall a. a -> Cli a forall (f :: * -> *) a. Applicative f => a -> f a pure Referent rf [Referent] rfs -> Output -> Cli Referent forall a. Output -> Cli a Cli.returnEarly (PrettyPrintEnv -> HashQualified Name -> Set Referent -> Output TermAmbiguous PrettyPrintEnv suffixifiedPPE HashQualified Name name ([Referent] -> Set Referent forall a. Ord a => [a] -> Set a fromList [Referent] rfs)) resolveCon :: HQ.HashQualified Name -> Cli ConstructorReference resolveCon :: HashQualified Name -> Cli ConstructorReference resolveCon HashQualified Name name = do Names names <- Cli Names Cli.currentNames let pped :: PrettyPrintEnvDecl pped = Namer -> Suffixifier -> PrettyPrintEnvDecl PPED.makePPED (Int -> Names -> Namer PPE.hqNamer Int 10 Names names) (Names -> Suffixifier PPE.suffixifyByHash Names names) let suffixifiedPPE :: PrettyPrintEnv suffixifiedPPE = PrettyPrintEnvDecl -> PrettyPrintEnv PPED.suffixifiedPPE PrettyPrintEnvDecl pped case HashQualified Name -> Names -> ([ConstructorReference], [Referent]) lookupCon HashQualified Name name Names names of ([], [Referent] _) -> Output -> Cli ConstructorReference forall a. Output -> Cli a Cli.returnEarly (HQSplit' -> Output TermNotFound (HQSplit' -> Output) -> HQSplit' -> Output forall a b. (a -> b) -> a -> b $ Maybe HQSplit' -> HQSplit' forall a. HasCallStack => Maybe a -> a fromJust Maybe HQSplit' parsed) where parsed :: Maybe HQSplit' parsed = Name -> HQSplit' hqSplitFromName' (Name -> HQSplit') -> Maybe Name -> Maybe HQSplit' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> HashQualified Name -> Maybe Name forall n. HashQualified n -> Maybe n HQ.toName HashQualified Name name ([ConstructorReference co], [Referent] _) -> ConstructorReference -> Cli ConstructorReference forall a. a -> Cli a forall (f :: * -> *) a. Applicative f => a -> f a pure ConstructorReference co ([ConstructorReference] _, [Referent] rfts) -> Output -> Cli ConstructorReference forall a. Output -> Cli a Cli.returnEarly (PrettyPrintEnv -> HashQualified Name -> Set Referent -> Output TermAmbiguous PrettyPrintEnv suffixifiedPPE HashQualified Name name ([Referent] -> Set Referent forall a. Ord a => [a] -> Set a fromList [Referent] rfts)) resolveTermRef :: HQ.HashQualified Name -> Cli Reference resolveTermRef :: HashQualified Name -> Cli (Reference' Text Hash) resolveTermRef HashQualified Name name = do Names names <- Cli Names Cli.currentNames let pped :: PrettyPrintEnvDecl pped = Namer -> Suffixifier -> PrettyPrintEnvDecl PPED.makePPED (Int -> Names -> Namer PPE.hqNamer Int 10 Names names) (Names -> Suffixifier PPE.suffixifyByHash Names names) let suffixifiedPPE :: PrettyPrintEnv suffixifiedPPE = PrettyPrintEnvDecl -> PrettyPrintEnv PPED.suffixifiedPPE PrettyPrintEnvDecl pped case HashQualified Name -> Names -> ([Reference' Text Hash], [Referent]) lookupTermRefs HashQualified Name name Names names of ([], [Referent] _) -> Output -> Cli (Reference' Text Hash) forall a. Output -> Cli a Cli.returnEarly (HQSplit' -> Output TermNotFound (HQSplit' -> Output) -> HQSplit' -> Output forall a b. (a -> b) -> a -> b $ Maybe HQSplit' -> HQSplit' forall a. HasCallStack => Maybe a -> a fromJust Maybe HQSplit' parsed) where parsed :: Maybe HQSplit' parsed = Name -> HQSplit' hqSplitFromName' (Name -> HQSplit') -> Maybe Name -> Maybe HQSplit' forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> HashQualified Name -> Maybe Name forall n. HashQualified n -> Maybe n HQ.toName HashQualified Name name ([Reference' Text Hash rf], [Referent] _) -> Reference' Text Hash -> Cli (Reference' Text Hash) forall a. a -> Cli a forall (f :: * -> *) a. Applicative f => a -> f a pure Reference' Text Hash rf ([Reference' Text Hash] _, [Referent] rfts) -> Output -> Cli (Reference' Text Hash) forall a. Output -> Cli a Cli.returnEarly (PrettyPrintEnv -> HashQualified Name -> Set Referent -> Output TermAmbiguous PrettyPrintEnv suffixifiedPPE HashQualified Name name ([Referent] -> Set Referent forall a. Ord a => [a] -> Set a fromList [Referent] rfts)) resolveMainRef :: HQ.HashQualified Name -> Cli (Reference, PrettyPrintEnv) resolveMainRef :: HashQualified Name -> Cli (Reference' Text Hash, PrettyPrintEnv) resolveMainRef HashQualified Name main = do Cli.Env {Codebase IO Symbol Ann codebase :: Codebase IO Symbol Ann $sel:codebase:Env :: Env -> Codebase IO Symbol Ann codebase, Runtime Symbol runtime :: Runtime Symbol $sel:runtime:Env :: Env -> Runtime Symbol runtime} <- Cli Env forall r (m :: * -> *). MonadReader r m => m r ask Names names <- Cli Names Cli.currentNames let pped :: PrettyPrintEnvDecl pped = Namer -> Suffixifier -> PrettyPrintEnvDecl PPED.makePPED (Int -> Names -> Namer PPE.hqNamer Int 10 Names names) (Names -> Suffixifier PPE.suffixifyByHash Names names) let suffixifiedPPE :: PrettyPrintEnv suffixifiedPPE = PrettyPrintEnvDecl -> PrettyPrintEnv PPED.suffixifiedPPE PrettyPrintEnvDecl pped let mainType :: Type Symbol Ann mainType = Runtime Symbol -> Type Symbol Ann forall v. Runtime v -> Type v Ann Runtime.mainType Runtime Symbol runtime Codebase IO Symbol Ann -> HashQualified Name -> Cli [(Reference' Text Hash, Type Symbol Ann)] lookupTermRefWithType Codebase IO Symbol Ann codebase HashQualified Name main Cli [(Reference' Text Hash, Type Symbol Ann)] -> ([(Reference' Text Hash, Type Symbol Ann)] -> Cli (Reference' Text Hash, PrettyPrintEnv)) -> Cli (Reference' Text Hash, PrettyPrintEnv) forall a b. Cli a -> (a -> Cli b) -> Cli b forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b >>= \case [(Reference' Text Hash rf, Type Symbol Ann ty)] | Type Symbol Ann -> Type Symbol Ann -> Bool forall v loc. Var v => Type v loc -> Type v loc -> Bool Typechecker.fitsScheme Type Symbol Ann ty Type Symbol Ann mainType -> (Reference' Text Hash, PrettyPrintEnv) -> Cli (Reference' Text Hash, PrettyPrintEnv) forall a. a -> Cli a forall (f :: * -> *) a. Applicative f => a -> f a pure (Reference' Text Hash rf, PrettyPrintEnv suffixifiedPPE) | Bool otherwise -> Output -> Cli (Reference' Text Hash, PrettyPrintEnv) forall a. Output -> Cli a Cli.returnEarly (Text -> HashQualified Name -> Type Symbol Ann -> PrettyPrintEnv -> [Type Symbol Ann] -> Output BadMainFunction Text "main" HashQualified Name main Type Symbol Ann ty PrettyPrintEnv suffixifiedPPE [Type Symbol Ann mainType]) [(Reference' Text Hash, Type Symbol Ann)] _ -> Output -> Cli (Reference' Text Hash, PrettyPrintEnv) forall a. Output -> Cli a Cli.returnEarly (HashQualified Name -> PrettyPrintEnv -> [Type Symbol Ann] -> Output NoMainFunction HashQualified Name main PrettyPrintEnv suffixifiedPPE [Type Symbol Ann mainType])