Skip to content

Commit 37ca00c

Browse files
authored
Merge pull request #4502 from unisonweb/travis/tdnr-bug
2 parents 089d366 + 6f21d2a commit 37ca00c

File tree

4 files changed

+125
-35
lines changed

4 files changed

+125
-35
lines changed

parser-typechecker/src/Unison/Typechecker.hs

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ import Control.Monad.State
3232
modify,
3333
)
3434
import Control.Monad.Writer
35+
import Data.Foldable
3536
import Data.Map qualified as Map
3637
import Data.Sequence.NonEmpty qualified as NESeq (toSeq)
38+
import Data.Set qualified as Set
3739
import Data.Text qualified as Text
3840
import Unison.ABT qualified as ABT
3941
import Unison.Blank qualified as B
@@ -229,17 +231,15 @@ typeDirectedNameResolution ppe oldNotes oldType env = do
229231
case catMaybes resolutions of
230232
[] -> pure oldType
231233
rs ->
232-
let goAgain =
233-
any ((== 1) . length . dedupe . filter Context.isExact . suggestions) rs
234-
in if goAgain
235-
then do
236-
traverse_ substSuggestion rs
237-
synthesizeAndResolve ppe tdnrEnv
238-
else do
239-
-- The type hasn't changed
240-
liftResult $ suggest rs
241-
pure oldType
234+
applySuggestions rs >>= \case
235+
True -> do
236+
synthesizeAndResolve ppe tdnrEnv
237+
False -> do
238+
-- The type hasn't changed
239+
liftResult $ suggest rs
240+
pure oldType
242241
where
242+
243243
addTypedComponent :: Context.InfoNote v loc -> State (Env v loc) ()
244244
addTypedComponent (Context.TopLevelComponent vtts) =
245245
for_ vtts $ \(v, typ, _) ->
@@ -268,23 +268,50 @@ typeDirectedNameResolution ppe oldNotes oldType env = do
268268
Var.MissingResult -> v
269269
_ -> Var.named name
270270

271-
substSuggestion :: Resolution v loc -> TDNR f v loc ()
271+
extractSubstitution :: [Context.Suggestion v loc] -> Maybe (Either v Referent)
272+
extractSubstitution suggestions =
273+
let groupedByName :: [([Name.Name], Either v Referent)] =
274+
map (\(a, b) -> (b, a))
275+
. Map.toList
276+
. fmap Set.toList
277+
. foldl'
278+
( \b Context.Suggestion {suggestionName, suggestionReplacement} ->
279+
Map.insertWith
280+
Set.union
281+
suggestionReplacement
282+
(Set.singleton (Name.unsafeFromText suggestionName))
283+
b
284+
)
285+
Map.empty
286+
$ filter Context.isExact suggestions
287+
matches :: Set (Either v Referent) = Name.preferShallowLibDepth groupedByName
288+
in case toList matches of
289+
[x] -> Just x
290+
_ -> Nothing
291+
292+
applySuggestions :: [Resolution v loc] -> TDNR f v loc Bool
293+
applySuggestions = foldlM phi False
294+
where
295+
phi b a = do
296+
didSub <- substSuggestion a
297+
pure $! b || didSub
298+
299+
substSuggestion :: Resolution v loc -> TDNR f v loc Bool
272300
substSuggestion
273301
( Resolution
274302
name
275303
_
276304
loc
277305
v
278-
( filter Context.isExact ->
279-
[Context.Suggestion _ _ replacement Context.Exact]
280-
)
306+
(extractSubstitution -> Just replacement)
281307
) =
282308
do
283309
modify (substBlank (Text.unpack name) loc solved)
284310
lift . btw $ Context.Decision (suggestedVar v name) loc solved
311+
pure True
285312
where
286313
solved = either (Term.var loc) (Term.fromReferent loc) replacement
287-
substSuggestion _ = pure ()
314+
substSuggestion _ = pure False
288315

289316
-- Resolve a `Blank` to a term
290317
substBlank :: String -> loc -> Term v loc -> Term v loc -> Term v loc

unison-core/src/Unison/Name.hs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ module Unison.Name
3535
unqualified,
3636

3737
-- * To organize later
38+
commonPrefix,
3839
libSegment,
39-
sortNames,
40-
sortNamed,
41-
sortByText,
42-
searchBySuffix,
40+
preferShallowLibDepth,
4341
searchByRankedSuffix,
44-
suffixFrom,
42+
searchBySuffix,
4543
shortestUniqueSuffix,
46-
commonPrefix,
44+
sortByText,
45+
sortNamed,
46+
sortNames,
4747
splits,
48+
suffixFrom,
4849

4950
-- * Re-exports
5051
module Unison.Util.Alphabetical,
@@ -333,23 +334,30 @@ searchBySuffix suffix rel =
333334
-- Example: foo.bar shadows lib.foo.bar
334335
-- Example: lib.foo.bar shadows lib.blah.lib.foo.bar
335336
searchByRankedSuffix :: (Ord r) => Name -> R.Relation Name r -> Set r
336-
searchByRankedSuffix suffix rel = case searchBySuffix suffix rel of
337-
rs | Set.size rs <= 1 -> rs
338-
rs -> case Map.lookup 0 byDepth <|> Map.lookup 1 byDepth of
339-
-- anything with more than one lib in it is treated the same
340-
Nothing -> rs
341-
Just rs -> Set.fromList rs
342-
where
343-
byDepth =
344-
List.multimap
345-
[ (minLibs ns, r)
346-
| r <- toList rs,
347-
ns <- [filter ok (toList (R.lookupRan r rel))]
348-
]
337+
searchByRankedSuffix suffix rel =
338+
let rs = searchBySuffix suffix rel
339+
in case Set.size rs <= 1 of
340+
True -> rs
341+
False ->
342+
let ok name = compareSuffix suffix name == EQ
343+
withNames = map (\r -> (filter ok (toList (R.lookupRan r rel)), r)) (toList rs)
344+
in preferShallowLibDepth withNames
345+
346+
-- | precondition: input list is deduped, and so is the Name list in
347+
-- the tuple
348+
preferShallowLibDepth :: Ord r => [([Name], r)] -> Set r
349+
preferShallowLibDepth = \case
350+
[] -> Set.empty
351+
[x] -> Set.singleton (snd x)
352+
rs ->
353+
let
354+
byDepth = List.multimap (map (first minLibs) rs)
349355
libCount = length . filter (== libSegment) . toList . reverseSegments
350356
minLibs [] = 0
351357
minLibs ns = minimum (map libCount ns)
352-
ok name = compareSuffix suffix name == EQ
358+
in case Map.lookup 0 byDepth <|> Map.lookup 1 byDepth of
359+
Nothing -> Set.fromList (map snd rs)
360+
Just rs -> Set.fromList rs
353361

354362
libSegment :: NameSegment
355363
libSegment = NameSegment "lib"

unison-src/transcripts/fix4498.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
```ucm:hide
2+
.> builtins.merge
3+
```
4+
5+
```unison
6+
lib.dep0.bonk.foo = 5
7+
lib.dep0.zonk.foo = "hi"
8+
lib.dep0.lib.dep1.foo = 6
9+
myterm = foo + 2
10+
```
11+
12+
```ucm
13+
.> add
14+
.> view myterm
15+
```
16+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
```unison
2+
lib.dep0.bonk.foo = 5
3+
lib.dep0.zonk.foo = "hi"
4+
lib.dep0.lib.dep1.foo = 6
5+
myterm = foo + 2
6+
```
7+
8+
```ucm
9+
10+
I found and typechecked these definitions in scratch.u. If you
11+
do an `add` or `update`, here's how your codebase would
12+
change:
13+
14+
⍟ These new definitions are ok to `add`:
15+
16+
lib.dep0.bonk.foo : Nat
17+
lib.dep0.lib.dep1.foo : Nat
18+
lib.dep0.zonk.foo : Text
19+
myterm : Nat
20+
21+
```
22+
```ucm
23+
.> add
24+
25+
⍟ I've added these definitions:
26+
27+
lib.dep0.bonk.foo : Nat
28+
lib.dep0.lib.dep1.foo : Nat
29+
lib.dep0.zonk.foo : Text
30+
myterm : Nat
31+
32+
.> view myterm
33+
34+
myterm : Nat
35+
myterm =
36+
use Nat +
37+
bonk.foo + 2
38+
39+
```

0 commit comments

Comments
 (0)