module Unison.Codebase.Editor.HandleInput.TermResolution
  ( lookupTermRefs,
    resolveCon,
    resolveTerm,
    resolveTermRef,
    resolveMainRef,
  )
where

import Control.Monad.Reader (ask)
import Data.Set qualified as Set
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 (NumberedOutput (..), Output (..))
import Unison.Codebase.MainTerm qualified as MainTerm
import Unison.Codebase.Path qualified as Path
import Unison.Codebase.Runtime qualified as Runtime
import Unison.ConstructorReference
import Unison.HashQualified qualified as HQ
import Unison.HashQualifiedPrime qualified as HQ'
import Unison.Name (Name)
import Unison.Names (Names)
import Unison.NamesWithHistory qualified as Names
import Unison.Parser.Ann (Ann)
import Unison.Prelude
import Unison.PrettyPrintEnv.Names qualified as PPE
import Unison.PrettyPrintEnvDecl qualified as PPED
import Unison.Reference (Reference, TermReference)
import Unison.Referent (Referent, pattern Con, pattern Ref)
import Unison.Symbol (Symbol)
import Unison.Term (Term)
import Unison.Type (Type)

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]
Set.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

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 (Output -> Cli Referent)
-> (Either ShortHash (HashQualified Name) -> Output)
-> Either ShortHash (HashQualified Name)
-> Cli Referent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ShortHash -> Output)
-> (HashQualified Name -> Output)
-> Either ShortHash (HashQualified Name)
-> Output
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ShortHash -> Output
TermNotFound' (HashQualified (Split Path') -> Output
TermNotFound (HashQualified (Split Path') -> Output)
-> (HashQualified Name -> HashQualified (Split Path'))
-> HashQualified Name
-> Output
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Name -> Split Path')
-> HashQualified Name -> HashQualified (Split Path')
forall a b. (a -> b) -> HashQualified a -> HashQualified b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Name -> Split Path'
Path.parentOfName) (Either ShortHash (HashQualified Name) -> Cli Referent)
-> Either ShortHash (HashQualified Name) -> Cli Referent
forall a b. (a -> b) -> a -> b
$ HashQualified Name -> Either ShortHash (HashQualified Name)
forall n. HashQualified n -> HashOrHQ n
HQ'.fromHQ 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 (Output -> Cli Referent)
-> (Set Referent -> Output) -> Set Referent -> Cli Referent
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrettyPrintEnv -> HashQualified Name -> Set Referent -> Output
TermAmbiguous PrettyPrintEnv
suffixifiedPPE HashQualified Name
name (Set Referent -> Cli Referent) -> Set Referent -> Cli Referent
forall a b. (a -> b) -> a -> b
$ [Referent] -> Set Referent
forall a. Ord a => [a] -> Set a
Set.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 (Output -> Cli ConstructorReference)
-> (Either ShortHash (HashQualified Name) -> Output)
-> Either ShortHash (HashQualified Name)
-> Cli ConstructorReference
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ShortHash -> Output)
-> (HashQualified Name -> Output)
-> Either ShortHash (HashQualified Name)
-> Output
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ShortHash -> Output
TermNotFound' (HashQualified (Split Path') -> Output
TermNotFound (HashQualified (Split Path') -> Output)
-> (HashQualified Name -> HashQualified (Split Path'))
-> HashQualified Name
-> Output
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Name -> Split Path')
-> HashQualified Name -> HashQualified (Split Path')
forall a b. (a -> b) -> HashQualified a -> HashQualified b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Name -> Split Path'
Path.parentOfName) (Either ShortHash (HashQualified Name) -> Cli ConstructorReference)
-> Either ShortHash (HashQualified Name)
-> Cli ConstructorReference
forall a b. (a -> b) -> a -> b
$ HashQualified Name -> Either ShortHash (HashQualified Name)
forall n. HashQualified n -> HashOrHQ n
HQ'.fromHQ 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 (Output -> Cli ConstructorReference)
-> (Set Referent -> Output)
-> Set Referent
-> Cli ConstructorReference
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrettyPrintEnv -> HashQualified Name -> Set Referent -> Output
TermAmbiguous PrettyPrintEnv
suffixifiedPPE HashQualified Name
name (Set Referent -> Cli ConstructorReference)
-> Set Referent -> Cli ConstructorReference
forall a b. (a -> b) -> a -> b
$ [Referent] -> Set Referent
forall a. Ord a => [a] -> Set a
Set.fromList [Referent]
rfts

resolveTermRef :: HQ.HashQualified Name -> Cli TermReference
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 (Output -> Cli (Reference' Text Hash))
-> (Either ShortHash (HashQualified Name) -> Output)
-> Either ShortHash (HashQualified Name)
-> Cli (Reference' Text Hash)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ShortHash -> Output)
-> (HashQualified Name -> Output)
-> Either ShortHash (HashQualified Name)
-> Output
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ShortHash -> Output
TermNotFound' (HashQualified (Split Path') -> Output
TermNotFound (HashQualified (Split Path') -> Output)
-> (HashQualified Name -> HashQualified (Split Path'))
-> HashQualified Name
-> Output
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Name -> Split Path')
-> HashQualified Name -> HashQualified (Split Path')
forall a b. (a -> b) -> HashQualified a -> HashQualified b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Name -> Split Path'
Path.parentOfName) (Either ShortHash (HashQualified Name)
 -> Cli (Reference' Text Hash))
-> Either ShortHash (HashQualified Name)
-> Cli (Reference' Text Hash)
forall a b. (a -> b) -> a -> b
$ HashQualified Name -> Either ShortHash (HashQualified Name)
forall n. HashQualified n -> HashOrHQ n
HQ'.fromHQ 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 (Output -> Cli (Reference' Text Hash))
-> (Set Referent -> Output)
-> Set Referent
-> Cli (Reference' Text Hash)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PrettyPrintEnv -> HashQualified Name -> Set Referent -> Output
TermAmbiguous PrettyPrintEnv
suffixifiedPPE HashQualified Name
name (Set Referent -> Cli (Reference' Text Hash))
-> Set Referent -> Cli (Reference' Text Hash)
forall a b. (a -> b) -> a -> b
$ [Referent] -> Set Referent
forall a. Ord a => [a] -> Set a
Set.fromList [Referent]
rfts

resolveMainRef :: Text -> HQ.HashQualified Name -> Cli (HQ.HashQualified Name, TermReference, Term Symbol Ann, Type Symbol Ann)
resolveMainRef :: Text
-> HashQualified Name
-> Cli
     (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
      Type Symbol Ann)
resolveMainRef Text
what HashQualified Name
mainName = 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
  let mainType :: Type Symbol Ann
mainType = Runtime Symbol -> Type Symbol Ann
forall e e' v. Runtime e e' v -> Type v Ann
Runtime.mainType Runtime Symbol
runtime
  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 ppe :: PrettyPrintEnv
ppe = PrettyPrintEnvDecl
pped.suffixifiedPPE
  MainTerm Symbol
mainTermResult <-
    (Reference' Text Hash -> Cli (Maybe (Type Symbol Ann)))
-> Names
-> HashQualified Name
-> Type Symbol Ann
-> Cli (MainTerm Symbol)
forall (m :: * -> *) v.
(Monad m, Var v) =>
(Reference' Text Hash -> m (Maybe (Type v Ann)))
-> Names -> HashQualified Name -> Type v Ann -> m (MainTerm v)
MainTerm.getMainTerm
      (IO (Maybe (Type Symbol Ann)) -> Cli (Maybe (Type Symbol Ann))
forall a. IO a -> Cli a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe (Type Symbol Ann)) -> Cli (Maybe (Type Symbol Ann)))
-> (Reference' Text Hash -> IO (Maybe (Type Symbol Ann)))
-> Reference' Text Hash
-> Cli (Maybe (Type Symbol Ann))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Codebase IO Symbol Ann
-> Transaction (Maybe (Type Symbol Ann))
-> IO (Maybe (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 (Maybe (Type Symbol Ann))
 -> IO (Maybe (Type Symbol Ann)))
-> (Reference' Text Hash -> Transaction (Maybe (Type Symbol Ann)))
-> Reference' Text Hash
-> IO (Maybe (Type Symbol Ann))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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)
      Names
names
      HashQualified Name
mainName
      Type Symbol Ann
mainType
  case MainTerm Symbol
mainTermResult of
    MainTerm.Success HashQualified Name
mainName1 Reference' Text Hash
ref Term Symbol Ann
term Type Symbol Ann
ty -> (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
 Type Symbol Ann)
-> Cli
     (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
      Type Symbol Ann)
forall a. a -> Cli a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (HashQualified Name
mainName1, Reference' Text Hash
ref, Term Symbol Ann
term, Type Symbol Ann
ty)
    MainTerm Symbol
MainTerm.NotFound -> Output
-> Cli
     (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
      Type Symbol Ann)
forall a. Output -> Cli a
Cli.returnEarly (HashQualified Name -> PrettyPrintEnv -> [Type Symbol Ann] -> Output
NoMainFunction HashQualified Name
mainName PrettyPrintEnv
ppe [Type Symbol Ann
mainType])
    MainTerm.BadType [(HashQualified Name, Reference' Text Hash, Type Symbol Ann)]
terms ->
      Output
-> Cli
     (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
      Type Symbol Ann)
forall a. Output -> Cli a
Cli.returnEarly (Output
 -> Cli
      (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
       Type Symbol Ann))
-> Output
-> Cli
     (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
      Type Symbol Ann)
forall a b. (a -> b) -> a -> b
$
        Text
-> [(HashQualified Name, Type Symbol Ann)]
-> PrettyPrintEnv
-> [Type Symbol Ann]
-> Output
BadMainFunction
          Text
what
          (((HashQualified Name, Reference' Text Hash, Type Symbol Ann)
 -> (HashQualified Name, Type Symbol Ann))
-> [(HashQualified Name, Reference' Text Hash, Type Symbol Ann)]
-> [(HashQualified Name, Type Symbol Ann)]
forall a b. (a -> b) -> [a] -> [b]
map (\(HashQualified Name
s, Reference' Text Hash
_, Type Symbol Ann
t) -> (HashQualified Name
s, Type Symbol Ann
t)) [(HashQualified Name, Reference' Text Hash, Type Symbol Ann)]
terms)
          PrettyPrintEnv
ppe
          [Type Symbol Ann
mainType]
    MainTerm.Ambiguous [(HashQualified Name, Reference' Text Hash, Type Symbol Ann)]
terms -> do
      NumberedOutput -> Cli ()
Cli.respondNumbered (NumberedOutput -> Cli ()) -> NumberedOutput -> Cli ()
forall a b. (a -> b) -> a -> b
$
        Text
-> [(HashQualified Name, Type Symbol Ann)]
-> PrettyPrintEnv
-> NumberedOutput
AmbiguousMainFunction
          Text
what
          (((HashQualified Name, Reference' Text Hash, Type Symbol Ann)
 -> (HashQualified Name, Type Symbol Ann))
-> [(HashQualified Name, Reference' Text Hash, Type Symbol Ann)]
-> [(HashQualified Name, Type Symbol Ann)]
forall a b. (a -> b) -> [a] -> [b]
map (\(HashQualified Name
s, Reference' Text Hash
_, Type Symbol Ann
t) -> (HashQualified Name
s, Type Symbol Ann
t)) [(HashQualified Name, Reference' Text Hash, Type Symbol Ann)]
terms)
          PrettyPrintEnv
ppe
      Cli
  (HashQualified Name, Reference' Text Hash, Term Symbol Ann,
   Type Symbol Ann)
forall a. Cli a
Cli.returnEarlyWithoutOutput