Skip to content

Commit 95fc3aa

Browse files
authored
Merge pull request #5124 from unisonweb/24-06-24-todo-dependents
2 parents 1e72750 + 3e229d5 commit 95fc3aa

File tree

10 files changed

+345
-167
lines changed

10 files changed

+345
-167
lines changed

codebase2/codebase-sqlite/U/Codebase/Sqlite/Operations.hs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ module U.Codebase.Sqlite.Operations
6666
directDependenciesOfScope,
6767
dependents,
6868
dependentsOfComponent,
69-
dependentsWithinScope,
69+
directDependentsWithinScope,
70+
transitiveDependentsWithinScope,
7071

7172
-- ** type index
7273
Q.addTypeToIndexForTerm,
@@ -1154,19 +1155,43 @@ dependents selector r = do
11541155
sIds <- Q.getDependentsForDependency selector r'
11551156
Set.traverse s2cReferenceId sIds
11561157

1157-
-- | `dependentsWithinScope scope query` returns all of transitive dependents of `query` that are in `scope` (not
1158-
-- including `query` itself). Each dependent is also tagged with whether it is a term or decl.
1159-
dependentsWithinScope :: Set C.Reference.Id -> Set C.Reference -> Transaction (Map C.Reference.Id C.ReferenceType)
1160-
dependentsWithinScope scope query = do
1161-
scope' <- Set.traverse c2sReferenceId scope
1162-
query' <- Set.traverse c2sReference query
1163-
Q.getDependentsWithinScope scope' query'
1164-
>>= Map.bitraverse s2cReferenceId (pure . objectTypeToReferenceType)
1165-
where
1166-
objectTypeToReferenceType = \case
1167-
ObjectType.TermComponent -> C.RtTerm
1168-
ObjectType.DeclComponent -> C.RtType
1169-
_ -> error "Q.getDependentsWithinScope shouldn't return any other types"
1158+
-- | `directDependentsWithinScope scope query` returns all direct dependents of `query` that are in `scope` (not
1159+
-- including `query` itself).
1160+
directDependentsWithinScope ::
1161+
Set C.Reference.Id ->
1162+
Set C.Reference ->
1163+
Transaction (DefnsF Set C.TermReferenceId C.TypeReferenceId)
1164+
directDependentsWithinScope scope0 query0 = do
1165+
-- Convert C -> S
1166+
scope1 <- Set.traverse c2sReferenceId scope0
1167+
query1 <- Set.traverse c2sReference query0
1168+
1169+
-- Do the query
1170+
dependents0 <- Q.getDirectDependentsWithinScope scope1 query1
1171+
1172+
-- Convert S -> C
1173+
dependents1 <- bitraverse (Set.traverse s2cReferenceId) (Set.traverse s2cReferenceId) dependents0
1174+
1175+
pure dependents1
1176+
1177+
-- | `transitiveDependentsWithinScope scope query` returns all transitive dependents of `query` that are in `scope` (not
1178+
-- including `query` itself).
1179+
transitiveDependentsWithinScope ::
1180+
Set C.Reference.Id ->
1181+
Set C.Reference ->
1182+
Transaction (DefnsF Set C.TermReferenceId C.TypeReferenceId)
1183+
transitiveDependentsWithinScope scope0 query0 = do
1184+
-- Convert C -> S
1185+
scope1 <- Set.traverse c2sReferenceId scope0
1186+
query1 <- Set.traverse c2sReference query0
1187+
1188+
-- Do the query
1189+
dependents0 <- Q.getTransitiveDependentsWithinScope scope1 query1
1190+
1191+
-- Convert S -> C
1192+
dependents1 <- bitraverse (Set.traverse s2cReferenceId) (Set.traverse s2cReferenceId) dependents0
1193+
1194+
pure dependents1
11701195

11711196
-- | returns a list of known definitions referencing `h`
11721197
dependentsOfComponent :: H.Hash -> Transaction (Set C.Reference.Id)

codebase2/codebase-sqlite/U/Codebase/Sqlite/Queries.hs

Lines changed: 121 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ module U.Codebase.Sqlite.Queries
166166
getDependencyIdsForDependent,
167167
getDependenciesBetweenTerms,
168168
getDirectDependenciesOfScope,
169-
getDependentsWithinScope,
169+
getDirectDependentsWithinScope,
170+
getTransitiveDependentsWithinScope,
170171

171172
-- ** type index
172173
addToTypeIndex,
@@ -1913,28 +1914,68 @@ getDirectDependenciesOfScope scope = do
19131914

19141915
pure dependencies1
19151916

1916-
{- ORMOLU_DISABLE -}
1917+
-- | `getDirectDependentsWithinScope scope query` returns all direct dependents of `query` that are in `scope` (not
1918+
-- including `query` itself).
1919+
getDirectDependentsWithinScope ::
1920+
Set S.Reference.Id ->
1921+
Set S.Reference ->
1922+
Transaction (DefnsF Set S.TermReferenceId S.TypeReferenceId)
1923+
getDirectDependentsWithinScope scope query = do
1924+
-- Populate a temporary table with all of the references in `scope`
1925+
let scopeTableName = [sql| dependents_search_scope |]
1926+
createTemporaryTableOfReferenceIds scopeTableName scope
1927+
1928+
-- Populate a temporary table with all of the references in `query`
1929+
let queryTableName = [sql| dependencies_query |]
1930+
createTemporaryTableOfReferences queryTableName query
1931+
1932+
-- Get their direct dependents (tagged with object type)
1933+
dependents0 <-
1934+
queryListRow @(S.Reference.Id :. Only ObjectType)
1935+
[sql|
1936+
SELECT s.object_id, s.component_index, o.type_id
1937+
FROM $queryTableName q
1938+
JOIN dependents_index d
1939+
ON q.builtin IS d.dependency_builtin
1940+
AND q.object_id IS d.dependency_object_id
1941+
AND q.component_index IS d.dependency_component_index
1942+
JOIN $scopeTableName s
1943+
ON d.dependent_object_id = s.object_id
1944+
AND d.dependent_component_index = s.component_index
1945+
JOIN object o ON s.object_id = o.id
1946+
|]
1947+
1948+
-- Drop the temporary tables
1949+
execute [sql| DROP TABLE $scopeTableName |]
1950+
execute [sql| DROP TABLE $queryTableName |]
1951+
1952+
-- Post-process the query result
1953+
let dependents1 =
1954+
List.foldl'
1955+
( \deps -> \case
1956+
dep :. Only TermComponent -> Defns (Set.insert dep deps.terms) deps.types
1957+
dep :. Only DeclComponent -> Defns deps.terms (Set.insert dep deps.types)
1958+
_ -> deps -- impossible; could error here
1959+
)
1960+
(Defns Set.empty Set.empty)
1961+
dependents0
1962+
1963+
pure dependents1
19171964

1918-
-- | `getDependentsWithinScope scope query` returns all of transitive dependents of `query` that are in `scope` (not
1919-
-- including `query` itself). Each dependent is also tagged with whether it is a term or decl.
1920-
getDependentsWithinScope :: Set S.Reference.Id -> Set S.Reference -> Transaction (Map S.Reference.Id ObjectType)
1921-
getDependentsWithinScope scope query = do
1965+
-- | `getTransitiveDependentsWithinScope scope query` returns all transitive dependents of `query` that are in `scope`
1966+
-- (not including `query` itself).
1967+
getTransitiveDependentsWithinScope ::
1968+
Set S.Reference.Id ->
1969+
Set S.Reference ->
1970+
Transaction (DefnsF Set S.TermReferenceId S.TypeReferenceId)
1971+
getTransitiveDependentsWithinScope scope query = do
19221972
-- Populate a temporary table with all of the references in `scope`
1923-
createTemporaryTableOfReferenceIds [sql| dependents_search_scope |] scope
1973+
let scopeTableName = [sql| dependents_search_scope |]
1974+
createTemporaryTableOfReferenceIds scopeTableName scope
19241975

19251976
-- Populate a temporary table with all of the references in `query`
1926-
execute
1927-
[sql|
1928-
CREATE TEMPORARY TABLE dependencies_query (
1929-
dependency_builtin INTEGER NULL,
1930-
dependency_object_id INTEGER NULL,
1931-
dependency_component_index INTEGER NULL,
1932-
CHECK ((dependency_builtin IS NULL) = (dependency_object_id IS NOT NULL)),
1933-
CHECK ((dependency_object_id IS NULL) = (dependency_component_index IS NULL))
1934-
)
1935-
|]
1936-
for_ query \r ->
1937-
execute [sql|INSERT INTO dependencies_query VALUES (@r, @, @)|]
1977+
let queryTableName = [sql| dependencies_query |]
1978+
createTemporaryTableOfReferences queryTableName query
19381979

19391980
-- Say the query set is { #foo, #bar }, and the scope set is { #foo, #bar, #baz, #qux, #honk }.
19401981
--
@@ -1954,34 +1995,65 @@ getDependentsWithinScope scope query = do
19541995
-- We use `UNION` rather than `UNION ALL` so as to not track down the transitive dependents of any particular
19551996
-- reference more than once.
19561997

1957-
result :: [S.Reference.Id :. Only ObjectType] <- queryListRow [sql|
1958-
WITH RECURSIVE transitive_dependents (dependent_object_id, dependent_component_index, type_id) AS (
1959-
SELECT d.dependent_object_id, d.dependent_component_index, object.type_id
1960-
FROM dependents_index d
1961-
JOIN object ON d.dependent_object_id = object.id
1962-
JOIN dependencies_query q
1963-
ON q.dependency_builtin IS d.dependency_builtin
1964-
AND q.dependency_object_id IS d.dependency_object_id
1965-
AND q.dependency_component_index IS d.dependency_component_index
1966-
JOIN dependents_search_scope s
1967-
ON s.object_id = d.dependent_object_id
1968-
AND s.component_index = d.dependent_component_index
1969-
1970-
UNION SELECT d.dependent_object_id, d.dependent_component_index, object.type_id
1971-
FROM dependents_index d
1972-
JOIN object ON d.dependent_object_id = object.id
1973-
JOIN transitive_dependents t
1974-
ON t.dependent_object_id = d.dependency_object_id
1975-
AND t.dependent_component_index = d.dependency_component_index
1976-
JOIN dependents_search_scope s
1977-
ON s.object_id = d.dependent_object_id
1978-
AND s.component_index = d.dependent_component_index
1979-
)
1980-
SELECT * FROM transitive_dependents
1981-
|]
1982-
execute [sql| DROP TABLE dependents_search_scope |]
1983-
execute [sql| DROP TABLE dependencies_query |]
1984-
pure . Map.fromList $ [(r, t) | r :. Only t <- result]
1998+
result0 :: [S.Reference.Id :. Only ObjectType] <-
1999+
queryListRow
2000+
[sql|
2001+
WITH RECURSIVE transitive_dependents (dependent_object_id, dependent_component_index, type_id) AS (
2002+
SELECT d.dependent_object_id, d.dependent_component_index, object.type_id
2003+
FROM dependents_index d
2004+
JOIN object ON d.dependent_object_id = object.id
2005+
JOIN $queryTableName q
2006+
ON q.builtin IS d.dependency_builtin
2007+
AND q.object_id IS d.dependency_object_id
2008+
AND q.component_index IS d.dependency_component_index
2009+
JOIN $scopeTableName s
2010+
ON s.object_id = d.dependent_object_id
2011+
AND s.component_index = d.dependent_component_index
2012+
2013+
UNION SELECT d.dependent_object_id, d.dependent_component_index, object.type_id
2014+
FROM dependents_index d
2015+
JOIN object ON d.dependent_object_id = object.id
2016+
JOIN transitive_dependents t
2017+
ON t.dependent_object_id = d.dependency_object_id
2018+
AND t.dependent_component_index = d.dependency_component_index
2019+
JOIN $scopeTableName s
2020+
ON s.object_id = d.dependent_object_id
2021+
AND s.component_index = d.dependent_component_index
2022+
)
2023+
SELECT * FROM transitive_dependents
2024+
|]
2025+
2026+
execute [sql| DROP TABLE $scopeTableName |]
2027+
execute [sql| DROP TABLE $queryTableName |]
2028+
2029+
-- Post-process the query result
2030+
let result1 =
2031+
List.foldl'
2032+
( \deps -> \case
2033+
dep :. Only TermComponent -> Defns (Set.insert dep deps.terms) deps.types
2034+
dep :. Only DeclComponent -> Defns deps.terms (Set.insert dep deps.types)
2035+
_ -> deps -- impossible; could error here
2036+
)
2037+
(Defns Set.empty Set.empty)
2038+
result0
2039+
2040+
pure result1
2041+
2042+
createTemporaryTableOfReferences :: Sql -> Set S.Reference -> Transaction ()
2043+
createTemporaryTableOfReferences tableName refs = do
2044+
execute
2045+
[sql|
2046+
CREATE TEMPORARY TABLE $tableName (
2047+
builtin INTEGER NULL,
2048+
object_id INTEGER NULL,
2049+
component_index INTEGER NULL
2050+
CHECK ((builtin IS NULL) = (object_id IS NOT NULL)),
2051+
CHECK ((object_id IS NULL) = (component_index IS NULL))
2052+
)
2053+
|]
2054+
2055+
for_ refs \ref ->
2056+
execute [sql| INSERT INTO $tableName VALUES (@ref, @, @) |]
19852057

19862058
createTemporaryTableOfReferenceIds :: Sql -> Set S.Reference.Id -> Transaction ()
19872059
createTemporaryTableOfReferenceIds tableName refs = do
@@ -1996,6 +2068,8 @@ createTemporaryTableOfReferenceIds tableName refs = do
19962068
for_ refs \ref ->
19972069
execute [sql| INSERT INTO $tableName VALUES (@ref, @) |]
19982070

2071+
{- ORMOLU_DISABLE -}
2072+
19992073
objectIdByBase32Prefix :: ObjectType -> Text -> Transaction [ObjectId]
20002074
objectIdByBase32Prefix objType prefix =
20012075
queryListCol

unison-cli/src/Unison/Codebase/Editor/HandleInput/Todo.hs

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ where
66

77
import Data.Set qualified as Set
88
import U.Codebase.Sqlite.Operations qualified as Operations
9+
import Unison.Builtin qualified as Builtin
910
import Unison.Cli.Monad (Cli)
1011
import Unison.Cli.Monad qualified as Cli
1112
import Unison.Cli.MonadUtils qualified as Cli
@@ -14,9 +15,12 @@ import Unison.Codebase qualified as Codebase
1415
import Unison.Codebase.Branch qualified as Branch
1516
import Unison.Codebase.Branch.Names qualified as Branch
1617
import Unison.Codebase.Editor.Output
17-
import Unison.Codebase.Editor.TodoOutput qualified as TO
1818
import Unison.Names qualified as Names
19+
import Unison.Prelude
20+
import Unison.Reference (TermReference)
21+
import Unison.Syntax.Name qualified as Name
1922
import Unison.Util.Defns (Defns (..))
23+
import Unison.Util.Set qualified as Set
2024

2125
handleTodo :: Cli ()
2226
handleTodo = do
@@ -25,27 +29,42 @@ handleTodo = do
2529
currentNamespace <- Cli.getCurrentBranch0
2630
let currentNamespaceWithoutLibdeps = Branch.deleteLibdeps currentNamespace
2731

28-
(hashLen, directDependencies) <-
32+
(dependentsOfTodo, directDependencies, hashLen) <-
2933
Cli.runTransaction do
30-
hashLen <- Codebase.hashLength
34+
let todoReference :: TermReference
35+
todoReference =
36+
Set.asSingleton (Names.refTermsNamed Builtin.names (Name.unsafeParseText "todo"))
37+
& fromMaybe (error (reportBug "E260496" "No reference for builtin named 'todo'"))
38+
39+
-- All type-and-term dependents of the `todo` builtin, but we know they're all terms.
40+
dependentsOfTodo <-
41+
Operations.directDependentsWithinScope
42+
(Branch.deepTermReferenceIds currentNamespaceWithoutLibdeps)
43+
(Set.singleton todoReference)
44+
3145
directDependencies <-
3246
Operations.directDependenciesOfScope
3347
Defns
3448
{ terms = Branch.deepTermReferenceIds currentNamespaceWithoutLibdeps,
3549
types = Branch.deepTypeReferenceIds currentNamespaceWithoutLibdeps
3650
}
37-
pure (hashLen, directDependencies)
3851

39-
let todo =
40-
TO.TodoOutput
41-
{ directDependenciesWithoutNames =
42-
Defns
43-
{ terms = Set.difference directDependencies.terms (Branch.deepTermReferences currentNamespace),
44-
types = Set.difference directDependencies.types (Branch.deepTypeReferences currentNamespace)
45-
},
46-
nameConflicts = Names.conflicts (Branch.toNames currentNamespaceWithoutLibdeps)
47-
}
52+
hashLen <- Codebase.hashLength
53+
54+
pure (dependentsOfTodo.terms, directDependencies, hashLen)
4855

49-
pped <- Cli.currentPrettyPrintEnvDecl
56+
ppe <- Cli.currentPrettyPrintEnvDecl
5057

51-
Cli.respondNumbered (TodoOutput hashLen pped todo)
58+
Cli.respondNumbered $
59+
Output'Todo
60+
TodoOutput
61+
{ hashLen,
62+
dependentsOfTodo,
63+
directDependenciesWithoutNames =
64+
Defns
65+
{ terms = Set.difference directDependencies.terms (Branch.deepTermReferences currentNamespace),
66+
types = Set.difference directDependencies.types (Branch.deepTypeReferences currentNamespace)
67+
},
68+
nameConflicts = Names.conflicts (Branch.toNames currentNamespaceWithoutLibdeps),
69+
ppe
70+
}

unison-cli/src/Unison/Codebase/Editor/HandleInput/Update2.hs

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -511,17 +511,8 @@ getNamespaceDependentsOf ::
511511
Set Reference ->
512512
Transaction (DefnsF (Relation Name) TermReferenceId TypeReferenceId)
513513
getNamespaceDependentsOf names dependencies = do
514-
dependents <- Ops.dependentsWithinScope (Names.referenceIds names) dependencies
515-
let dependents1 :: DefnsF Set TermReferenceId TypeReferenceId
516-
dependents1 =
517-
Map.foldlWithKey'
518-
( \defns refId -> \case
519-
Reference.RtTerm -> let !terms1 = Set.insert refId defns.terms in defns & #terms .~ terms1
520-
Reference.RtType -> let !types1 = Set.insert refId defns.types in defns & #types .~ types1
521-
)
522-
(Defns Set.empty Set.empty)
523-
dependents
524-
pure (bimap (foldMap nameTerm) (foldMap nameType) dependents1)
514+
dependents <- Ops.transitiveDependentsWithinScope (Names.referenceIds names) dependencies
515+
pure (bimap (foldMap nameTerm) (foldMap nameType) dependents)
525516
where
526517
nameTerm :: TermReferenceId -> Relation Name TermReferenceId
527518
nameTerm ref =
@@ -542,26 +533,21 @@ getNamespaceDependentsOf2 defns dependencies = do
542533
let scope = bifoldMap toTermScope toTypeScope defns
543534

544535
dependents <-
545-
Ops.dependentsWithinScope scope dependencies
546-
547-
let (termDependentRefs, typeDependentRefs) =
548-
dependents & Map.partition \case
549-
Reference.RtTerm -> True
550-
Reference.RtType -> False
536+
Ops.transitiveDependentsWithinScope scope dependencies
551537

552538
pure
553539
Defns
554-
{ terms = Map.foldlWithKey' addTerms Map.empty termDependentRefs,
555-
types = Map.foldlWithKey' addTypes Map.empty typeDependentRefs
540+
{ terms = Set.foldl' addTerms Map.empty dependents.terms,
541+
types = Set.foldl' addTypes Map.empty dependents.types
556542
}
557543
where
558-
addTerms :: Map Name TermReferenceId -> TermReferenceId -> ignored -> Map Name TermReferenceId
559-
addTerms acc0 ref _ =
544+
addTerms :: Map Name TermReferenceId -> TermReferenceId -> Map Name TermReferenceId
545+
addTerms acc0 ref =
560546
let names = BiMultimap.lookupDom (Referent.fromTermReferenceId ref) defns.terms
561547
in Set.foldl' (\acc name -> Map.insert name ref acc) acc0 names
562548

563-
addTypes :: Map Name TypeReferenceId -> TypeReferenceId -> ignored -> Map Name TypeReferenceId
564-
addTypes acc0 ref _ =
549+
addTypes :: Map Name TypeReferenceId -> TypeReferenceId -> Map Name TypeReferenceId
550+
addTypes acc0 ref =
565551
let names = BiMultimap.lookupDom (Reference.fromId ref) defns.types
566552
in Set.foldl' (\acc name -> Map.insert name ref acc) acc0 names
567553

0 commit comments

Comments
 (0)