emit a proper resolution result for constructors

This commit is contained in:
Mitchell Rosen 2024-08-23 12:08:22 -04:00
parent f03f784ed8
commit 82d012fdb1
17 changed files with 84 additions and 70 deletions

View File

@ -227,7 +227,7 @@ h2mReferent getCT = \case
hashDataDecls ::
(Var v) =>
Map v (Memory.DD.DataDeclaration v a) ->
ResolutionResult v a [(v, Memory.Reference.Id, Memory.DD.DataDeclaration v a)]
ResolutionResult a [(v, Memory.Reference.Id, Memory.DD.DataDeclaration v a)]
hashDataDecls memDecls = do
let hashingDecls = fmap m2hDecl memDecls
hashingResult <- Hashing.hashDecls Name.unsafeParseVar hashingDecls
@ -239,7 +239,7 @@ hashDataDecls memDecls = do
hashDecls ::
(Var v) =>
Map v (Memory.DD.Decl v a) ->
ResolutionResult v a [(v, Memory.Reference.Id, Memory.DD.Decl v a)]
ResolutionResult a [(v, Memory.Reference.Id, Memory.DD.Decl v a)]
hashDecls memDecls = do
-- want to unwrap the decl before doing the rehashing, and then wrap it back up the same way
let howToReassemble =

View File

@ -33,6 +33,7 @@ import Unison.ABT qualified as ABT
import Unison.Builtin.Decls (unitRef, pattern TupleType')
import Unison.ConstructorReference (ConstructorReference, GConstructorReference (..))
import Unison.HashQualified (HashQualified)
import Unison.HashQualified qualified as HQ
import Unison.HashQualifiedPrime qualified as HQ'
import Unison.Kind (Kind)
import Unison.Kind qualified as Kind
@ -1968,11 +1969,11 @@ intLiteralSyntaxTip term expectedType = case (term, expectedType) of
-- | Pretty prints resolution failure annotations, including a table of disambiguation
-- suggestions.
prettyResolutionFailures ::
forall v a.
(Annotated a, Var v, Ord a) =>
forall a.
(Annotated a, Ord a) =>
-- | src
String ->
[Names.ResolutionFailure v a] ->
[Names.ResolutionFailure a] ->
Pretty ColorText
prettyResolutionFailures s allFailures =
Pr.callout "" $
@ -1987,39 +1988,39 @@ prettyResolutionFailures s allFailures =
where
-- Collapses identical failures which may have multiple annotations into a single failure.
-- uniqueFailures
ambiguitiesToTable :: [Names.ResolutionFailure v a] -> Pretty ColorText
ambiguitiesToTable :: [Names.ResolutionFailure a] -> Pretty ColorText
ambiguitiesToTable failures =
let pairs :: ([(v, Maybe (NESet String))])
let pairs :: ([(HQ.HashQualified Name, Maybe (NESet String))])
pairs = nubOrd . fmap toAmbiguityPair $ failures
spacerRow = ("", "")
in Pr.column2Header "Symbol" "Suggestions" $ spacerRow : (intercalateMap [spacerRow] prettyRow pairs)
toAmbiguityPair :: Names.ResolutionFailure v annotation -> (v, Maybe (NESet String))
toAmbiguityPair :: Names.ResolutionFailure annotation -> (HQ.HashQualified Name, Maybe (NESet String))
toAmbiguityPair = \case
(Names.TermResolutionFailure v _ (Names.Ambiguous names refs localNames)) -> do
(Names.TermResolutionFailure name _ (Names.Ambiguous names refs localNames)) -> do
let ppe = ppeFromNames names
in ( v,
in ( name,
Just $
NES.unsafeFromSet
(Set.map (showTermRef ppe) refs <> Set.map (Text.unpack . Name.toText) localNames)
)
(Names.TypeResolutionFailure v _ (Names.Ambiguous names refs localNames)) -> do
(Names.TypeResolutionFailure name _ (Names.Ambiguous names refs localNames)) -> do
let ppe = ppeFromNames names
in ( v,
in ( name,
Just $
NES.unsafeFromSet (Set.map (showTypeRef ppe) refs <> Set.map (Text.unpack . Name.toText) localNames)
)
(Names.TermResolutionFailure v _ Names.NotFound) -> (v, Nothing)
(Names.TypeResolutionFailure v _ Names.NotFound) -> (v, Nothing)
(Names.TermResolutionFailure name _ Names.NotFound) -> (name, Nothing)
(Names.TypeResolutionFailure name _ Names.NotFound) -> (name, Nothing)
ppeFromNames :: Names.Names -> PPE.PrettyPrintEnv
ppeFromNames names =
PPE.makePPE (PPE.hqNamer PPE.todoHashLength names) PPE.dontSuffixify
prettyRow :: (v, Maybe (NESet String)) -> [(Pretty ColorText, Pretty ColorText)]
prettyRow (v, mSet) = case mSet of
Nothing -> [(prettyVar v, Pr.hiBlack "No matches")]
Just suggestions -> zip ([prettyVar v] ++ repeat "") (Pr.string <$> toList suggestions)
prettyRow :: (HQ.HashQualified Name, Maybe (NESet String)) -> [(Pretty ColorText, Pretty ColorText)]
prettyRow (name, mSet) = case mSet of
Nothing -> [(prettyHashQualified0 name, Pr.hiBlack "No matches")]
Just suggestions -> zip ([prettyHashQualified0 name] ++ repeat "") (Pr.string <$> toList suggestions)
useExamples :: Pretty ColorText
useExamples =

View File

@ -18,7 +18,7 @@ type ResultT notes f = MaybeT (WriterT notes f)
data Note v loc
= Parsing (Parser.Err v)
| NameResolutionFailures [Names.ResolutionFailure v loc]
| NameResolutionFailures [Names.ResolutionFailure loc]
| UnknownSymbol v loc
| TypeError (Context.ErrorNote v loc)
| TypeInfo (Context.InfoNote v loc)

View File

@ -44,7 +44,7 @@ import Unison.WatchKind (WatchKind)
import Unison.WatchKind qualified as UF
import Prelude hiding (readFile)
resolutionFailures :: (Ord v) => [Names.ResolutionFailure v Ann] -> P v m x
resolutionFailures :: (Ord v) => [Names.ResolutionFailure Ann] -> P v m x
resolutionFailures es = P.customFailure (ResolutionFailures es)
file :: forall m v. (Monad m, Var v) => P v m (UnisonFile v Ann)

View File

@ -40,6 +40,7 @@ import Unison.Name qualified as Name
import Unison.NameSegment qualified as NameSegment
import Unison.Names (Names)
import Unison.Names qualified as Names
import Unison.Names.ResolutionResult (ResolutionError (..), ResolutionFailure (..))
import Unison.NamesWithHistory qualified as Names
import Unison.Parser.Ann (Ann (Ann))
import Unison.Parser.Ann qualified as Ann
@ -48,6 +49,7 @@ import Unison.Pattern qualified as Pattern
import Unison.Prelude
import Unison.Reference (Reference)
import Unison.Referent (Referent)
import Unison.Referent qualified as Referent
import Unison.Syntax.Lexer.Unison qualified as L
import Unison.Syntax.Name qualified as Name (toText, toVar, unsafeParseVar)
import Unison.Syntax.NameSegment qualified as NameSegment
@ -285,7 +287,10 @@ parsePattern = label "pattern" root
else pure (Pattern.Var (ann v), [tokenToPair v])
unbound :: P v m (Pattern Ann, [(Ann, v)])
unbound = (\tok -> (Pattern.Unbound (ann tok), [])) <$> blank
ctor :: CT.ConstructorType -> (L.Token (HQ.HashQualified Name) -> Set ConstructorReference -> Error v) -> P v m (L.Token ConstructorReference)
ctor ::
CT.ConstructorType ->
(L.Token (HQ.HashQualified Name) -> Set ConstructorReference -> Error v) ->
P v m (L.Token ConstructorReference)
ctor ct err = do
-- this might be a var, so we avoid consuming it at first
tok <- P.try (P.lookAhead hqPrefixId)
@ -294,23 +299,34 @@ parsePattern = label "pattern" root
-- starts with a lowercase
case Names.lookupHQPattern Names.IncludeSuffixes (L.payload tok) ct names of
s
| Set.null s -> die tok s
| Set.size s > 1 -> die tok s
| otherwise -> -- matched ctor name, consume the token
do _ <- anyToken; pure (Set.findMin s <$ tok)
| Set.null s -> die names tok s
| Set.size s > 1 -> die names tok s
| otherwise -> do
-- matched ctor name, consume the token
_ <- anyToken
pure (Set.findMin s <$ tok)
where
isLower = Text.all Char.isLower . Text.take 1 . Name.toText
isIgnored n = Text.take 1 (Name.toText n) == "_"
die hq s = case L.payload hq of
-- if token not hash qualified or uppercase,
die :: Names -> L.Token (HQ.HashQualified Name) -> Set ConstructorReference -> P v m a
die names hq s = case L.payload hq of
-- if token not hash qualified and not uppercase,
-- fail w/out consuming it to allow backtracking
HQ.NameOnly n
| Set.null s
&& (isLower n || isIgnored n) ->
fail $ "not a constructor name: " <> show n
-- it was hash qualified, and wasn't found in the env, that's a failure!
_ -> failCommitted $ err hq s
-- it was hash qualified and/or uppercase, and wasn't found in the env, that's a failure!
_ ->
failCommitted $
ResolutionFailures
[ TermResolutionFailure
(L.payload hq)
(ann hq)
if Set.null s
then NotFound
else Ambiguous names (Set.map (\ref -> Referent.Con ref ct) s) Set.empty
]
unzipPatterns f elems = case unzip elems of (patterns, vs) -> f patterns (join vs)
effectBind0 = do

View File

@ -73,7 +73,7 @@ environmentFor ::
Names ->
Map v (DataDeclaration v a) ->
Map v (EffectDeclaration v a) ->
Names.ResolutionResult v a (Either [Error v a] (Env v a))
Names.ResolutionResult a (Either [Error v a] (Env v a))
environmentFor names dataDecls0 effectDecls0 = do
let locallyBoundTypes = Map.keysSet dataDecls0 <> Map.keysSet effectDecls0

View File

@ -218,7 +218,7 @@ data Output
| NoExactTypeMatches
| TypeAlreadyExists Path.Split' (Set Reference)
| TypeParseError String (Parser.Err Symbol)
| ParseResolutionFailures String [Names.ResolutionFailure Symbol Ann]
| ParseResolutionFailures String [Names.ResolutionFailure Ann]
| TypeHasFreeVars (Type Symbol Ann)
| TermAlreadyExists Path.Split' (Set Referent)
| LabeledReferenceAmbiguous Int (HQ.HashQualified Name) (Set LabeledDependency)

View File

@ -211,7 +211,7 @@ bindReferences ::
Set v ->
Map Name.Name Reference ->
DataDeclaration v a ->
Names.ResolutionResult v a (DataDeclaration v a)
Names.ResolutionResult a (DataDeclaration v a)
bindReferences unsafeVarToName keepFree names (DataDeclaration m a bound constructors) = do
constructors <- for constructors $ \(a, v, ty) ->
(a,v,) <$> Type.bindReferences unsafeVarToName keepFree names ty

View File

@ -53,6 +53,6 @@ bindNames ::
Set v ->
Names ->
DataDeclaration v a ->
Names.ResolutionResult v a (DataDeclaration v a)
Names.ResolutionResult a (DataDeclaration v a)
bindNames unsafeVarToName nameToVar localNames namespaceNames =
traverseOf (#constructors' . traverse . _3) (Type.Names.bindNames unsafeVarToName nameToVar localNames namespaceNames)

View File

@ -3,7 +3,6 @@ module Unison.Names.ResolutionResult
ResolutionFailure (..),
ResolutionResult,
getAnnotation,
getVar,
)
where
@ -12,6 +11,7 @@ import Unison.Names (Names)
import Unison.Prelude
import Unison.Reference (TypeReference)
import Unison.Referent (Referent)
import Unison.HashQualified (HashQualified)
data ResolutionError ref
= NotFound
@ -25,20 +25,15 @@ data ResolutionError ref
Ambiguous Names (Set ref) (Set Name)
deriving (Eq, Ord, Show)
-- | ResolutionFailure represents the failure to resolve a given variable.
data ResolutionFailure var annotation
= TypeResolutionFailure var annotation (ResolutionError TypeReference)
| TermResolutionFailure var annotation (ResolutionError Referent)
-- | ResolutionFailure represents the failure to resolve a given name.
data ResolutionFailure annotation
= TypeResolutionFailure (HashQualified Name) annotation (ResolutionError TypeReference)
| TermResolutionFailure (HashQualified Name) annotation (ResolutionError Referent)
deriving (Eq, Ord, Show, Functor, Foldable, Traversable)
getAnnotation :: ResolutionFailure v a -> a
getAnnotation :: ResolutionFailure a -> a
getAnnotation = \case
TypeResolutionFailure _ a _ -> a
TermResolutionFailure _ a _ -> a
getVar :: ResolutionFailure v a -> v
getVar = \case
TypeResolutionFailure v _ _ -> v
TermResolutionFailure v _ _ -> v
type ResolutionResult v a r = Either (Seq (ResolutionFailure v a)) r
type ResolutionResult a r = Either (Seq (ResolutionFailure a)) r

View File

@ -236,10 +236,6 @@ termName length r names =
hq n = HQ'.take length (HQ'.fromNamedReferent n r)
isConflicted n = R.manyDom n (Names.terms names)
-- Set HashQualified -> Branch m -> Action' m v Names
-- Set HashQualified -> Branch m -> Free (Command m i v) Names
-- Set HashQualified -> Branch m -> Command m i v Names
-- populate historical names
lookupHQPattern ::
SearchType ->
HQ.HashQualified Name ->

View File

@ -156,7 +156,7 @@ bindNames ::
Set v ->
Names ->
Term v a ->
Names.ResolutionResult v a (Term v a)
Names.ResolutionResult a (Term v a)
bindNames unsafeVarToName nameToVar localVars ns term = do
let freeTmVars = ABT.freeVarOccurrences localVars term
freeTyVars =
@ -164,10 +164,9 @@ bindNames unsafeVarToName nameToVar localVars ns term = do
]
localNames = map unsafeVarToName (Set.toList localVars)
okTm :: (v, a) -> Names.ResolutionResult v a (Maybe (v, ResolvesTo Referent))
okTm :: (v, a) -> Names.ResolutionResult a (Maybe (v, ResolvesTo Referent))
okTm (v, a) =
let name = unsafeVarToName v
exactNamespaceMatches = Names.lookupHQTerm Names.ExactName (HQ.NameOnly name) ns
let exactNamespaceMatches = Names.lookupHQTerm Names.ExactName (HQ.NameOnly name) ns
suffixNamespaceMatches = Name.searchByRankedSuffix name (Names.terms ns)
localMatches =
Name.searchBySuffix name (Relation.fromList (map (\name -> (name, name)) localNames))
@ -179,17 +178,20 @@ bindNames unsafeVarToName nameToVar localVars ns term = do
(_, 0, 1) -> good (ResolvesToLocal (Set.findMin localMatches))
_ -> leaveFreeForTdnr
where
name = unsafeVarToName v
good = Right . Just . (v,)
bad = Left . Seq.singleton . Names.TermResolutionFailure v a
bad = Left . Seq.singleton . Names.TermResolutionFailure (HQ.NameOnly name) a
leaveFreeForHoleSuggestions = Right Nothing
leaveFreeForTdnr = Right Nothing
okTy :: (v, a) -> Names.ResolutionResult v a (v, Type v a)
okTy (v, a) = case Names.lookupHQType Names.IncludeSuffixes (HQ.NameOnly $ unsafeVarToName v) ns of
okTy :: (v, a) -> Names.ResolutionResult a (v, Type v a)
okTy (v, a) = case Names.lookupHQType Names.IncludeSuffixes hqName ns of
rs
| Set.size rs == 1 -> pure (v, Type.ref a $ Set.findMin rs)
| Set.size rs == 0 -> Left (pure (Names.TypeResolutionFailure v a Names.NotFound))
| otherwise -> Left (pure (Names.TypeResolutionFailure v a (Names.Ambiguous ns rs Set.empty)))
| Set.size rs == 0 -> Left (Seq.singleton (Names.TypeResolutionFailure hqName a Names.NotFound))
| otherwise -> Left (Seq.singleton (Names.TypeResolutionFailure hqName a (Names.Ambiguous ns rs Set.empty)))
where
hqName = HQ.NameOnly (unsafeVarToName v)
(namespaceTermResolutions, localTermResolutions) <-
partitionResolutions . catMaybes <$> validate okTm freeTmVars
let termSubsts =

View File

@ -8,8 +8,10 @@ import Data.Generics.Sum (_Ctor)
import Data.List.Extra (nubOrd)
import Data.Map qualified as Map
import Data.Monoid (Any (..))
import Data.Sequence qualified as Seq
import Data.Set qualified as Set
import Unison.ABT qualified as ABT
import Unison.HashQualified qualified as HQ
import Unison.Kind qualified as K
import Unison.LabeledDependency qualified as LD
import Unison.Name qualified as Name
@ -71,12 +73,14 @@ bindReferences ::
Set v ->
Map Name.Name TypeReference ->
Type v a ->
Names.ResolutionResult v a (Type v a)
Names.ResolutionResult a (Type v a)
bindReferences unsafeVarToName keepFree ns t =
let fvs = ABT.freeVarOccurrences keepFree t
rs = [(v, a, Map.lookup (unsafeVarToName v) ns) | (v, a) <- fvs]
ok (v, _a, Just r) = pure (v, r)
ok (v, a, Nothing) = Left (pure (Names.TypeResolutionFailure v a Names.NotFound))
ok (v, a, Nothing) =
Left $
Seq.singleton (Names.TypeResolutionFailure (HQ.NameOnly (unsafeVarToName v)) a Names.NotFound)
in List.validate ok rs <&> \es -> bindExternal es t
newtype Monotype v a = Monotype {getPolytype :: Type v a} deriving (Eq)

View File

@ -29,7 +29,7 @@ bindNames ::
Set v ->
Names ->
Type v a ->
Names.ResolutionResult v a (Type v a)
Names.ResolutionResult a (Type v a)
bindNames unsafeVarToName nameToVar localVars namespaceNames ty =
let -- Identify the unresolved variables in the type: those whose names aren't an *exact* match for some locally-bound
-- type.
@ -63,7 +63,7 @@ bindNames unsafeVarToName nameToVar localVars namespaceNames ty =
checkAmbiguity ::
(v, a, (Set TypeReference, Set TypeReference), Set Name) ->
Either (Seq (Names.ResolutionFailure v a)) (v, ResolvesTo TypeReference)
Either (Seq (Names.ResolutionFailure a)) (v, ResolvesTo TypeReference)
checkAmbiguity (v, a, (exactNamespaceMatches, suffixNamespaceMatches), localMatches) =
case (Set.size exactNamespaceMatches, Set.size suffixNamespaceMatches, Set.size localMatches) of
(1, _, _) -> good (ResolvesToNamespace (Set.findMin exactNamespaceMatches))
@ -73,7 +73,7 @@ bindNames unsafeVarToName nameToVar localVars namespaceNames ty =
(_, 0, 1) -> good (ResolvesToLocal (Set.findMin localMatches))
_ -> bad (Names.Ambiguous namespaceNames suffixNamespaceMatches localMatches)
where
bad = Left . Seq.singleton . Names.TypeResolutionFailure v a
bad = Left . Seq.singleton . Names.TypeResolutionFailure (HQ.NameOnly (unsafeVarToName v)) a
good = Right . (v,)
in List.validate checkAmbiguity resolvedVars <&> \resolutions ->
let (namespaceResolutions, localResolutions) = partitionResolutions resolutions

View File

@ -76,7 +76,7 @@ hashDecls ::
(Eq v, Var v, Show v) =>
(v -> Name.Name) ->
Map v (DataDeclaration v a) ->
Names.ResolutionResult v a [(v, ReferenceId, DataDeclaration v a)]
Names.ResolutionResult a [(v, ReferenceId, DataDeclaration v a)]
hashDecls unsafeVarToName decls = do
-- todo: make sure all other external references are resolved before calling this
let varToRef = hashDecls0 (void <$> decls)
@ -96,7 +96,7 @@ bindReferences ::
Set v ->
Map Name.Name Reference ->
DataDeclaration v a ->
Names.ResolutionResult v a (DataDeclaration v a)
Names.ResolutionResult a (DataDeclaration v a)
bindReferences unsafeVarToName keepFree names (DataDeclaration m a bound constructors) = do
constructors <- for constructors $ \(a, v, ty) ->
(a,v,) <$> Type.bindReferences unsafeVarToName keepFree names ty

View File

@ -23,6 +23,7 @@ where
import Data.Map qualified as Map
import Data.Set qualified as Set
import Unison.ABT qualified as ABT
import Unison.HashQualified qualified as HQ
import Unison.Hashing.V2.ABT qualified as ABT
import Unison.Hashing.V2.Kind qualified as K
import Unison.Hashing.V2.Reference (Reference (..), pattern ReferenceDerived)
@ -64,12 +65,12 @@ bindReferences ::
Set v ->
Map Name.Name Reference ->
Type v a ->
Names.ResolutionResult v a (Type v a)
Names.ResolutionResult a (Type v a)
bindReferences unsafeVarToName keepFree ns t =
let fvs = ABT.freeVarOccurrences keepFree t
rs = [(v, a, Map.lookup (unsafeVarToName v) ns) | (v, a) <- fvs]
ok (v, _a, Just r) = pure (v, r)
ok (v, a, Nothing) = Left (pure (Names.TypeResolutionFailure v a Names.NotFound))
ok (v, a, Nothing) = Left (pure (Names.TypeResolutionFailure (HQ.NameOnly (unsafeVarToName v)) a Names.NotFound))
in List.validate ok rs <&> \es -> bindExternal es t
-- some smart patterns

View File

@ -82,7 +82,6 @@ import Unison.HashQualifiedPrime qualified as HQ'
import Unison.Hashable qualified as Hashable
import Unison.Name as Name
import Unison.NameSegment (NameSegment)
import Unison.NameSegment.Internal qualified as INameSegment
import Unison.Names (Names)
import Unison.Names.ResolutionResult qualified as Names
import Unison.Parser.Ann (Ann (..), Annotated (..))
@ -175,7 +174,7 @@ data Error v
MissingTypeModifier (L.Token String) (L.Token v)
| -- | A type was found in a position that requires a term
TypeNotAllowed (L.Token (HQ.HashQualified Name))
| ResolutionFailures [Names.ResolutionFailure v Ann]
| ResolutionFailures [Names.ResolutionFailure Ann]
| DuplicateTypeNames [(v, [Ann])]
| DuplicateTermNames [(v, [Ann])]
| -- | PatternArityMismatch expectedArity actualArity location