Skip to content

Commit 0de2f2a

Browse files
committed
Improve construction of declaration index and select pass
Paired session with Edsko
1 parent 9356854 commit 0de2f2a

File tree

9 files changed

+215
-234
lines changed

9 files changed

+215
-234
lines changed

dev/select-pass.excalidraw

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,13 +457,13 @@
457457
"updated": 1763179304934,
458458
"link": null,
459459
"locked": false,
460-
"text": "getTransitiveAvailability",
460+
"text": "getTransitiveSelectability",
461461
"fontSize": 20,
462462
"fontFamily": 5,
463463
"textAlign": "center",
464464
"verticalAlign": "middle",
465465
"containerId": "2X3A6sCqYbvEBrGYPPdcT",
466-
"originalText": "getTransitiveAvailability",
466+
"originalText": "getTransitiveSelectability",
467467
"autoResize": true,
468468
"lineHeight": 1.25
469469
},
@@ -1748,4 +1748,4 @@
17481748
"lockedMultiSelections": {}
17491749
},
17501750
"files": {}
1751-
}
1751+
}

hs-bindgen/src-internal/HsBindgen/Frontend/Analysis/DeclIndex.hs

Lines changed: 66 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module HsBindgen.Frontend.Analysis.DeclIndex (
1010
Usable(..)
1111
, Unusable(..)
1212
, Entry(..)
13-
, DeclIndex
13+
, DeclIndex -- opaque
1414
-- * Construction
1515
, fromParseResults
1616
-- * Query parse successes
@@ -40,8 +40,9 @@ import Prelude hiding (lookup)
4040
import Control.Monad.State
4141
import Data.Foldable qualified as Foldable
4242
import Data.Function
43+
import Data.List.NonEmpty ((<|))
44+
import Data.List.NonEmpty qualified as NonEmpty
4345
import Data.Map.Strict qualified as Map
44-
import Optics.Core (over)
4546

4647
import Clang.HighLevel.Types
4748
import Clang.Paths
@@ -82,13 +83,14 @@ data Usable =
8283
-- (We avoid the term available, because it is overloaded with Clang's
8384
-- CXAvailabilityKind).
8485
data Unusable =
85-
UnusableParseNotAttempted ParseNotAttempted
86+
UnusableParseNotAttempted (NonEmpty ParseNotAttempted)
8687
| UnusableParseFailure ParseFailure
8788
| UnusableConflict ConflictingDeclarations
8889
| UnusableFailedMacro FailedMacro
8990
-- TODO https://github.com/well-typed/hs-bindgen/issues/1273: Attach
9091
-- information required to match the select predicate also to omitted
9192
-- declarations.
93+
-- | Omitted by prescriptive binding specifications
9294
| UnusableOmitted (C.QualName, SourcePath)
9395
deriving stock (Show, Generic)
9496

@@ -164,15 +166,15 @@ fromParseResults results = flip execState emptyIndex $ mapM_ aux results
164166
where
165167
aux :: ParseResult -> State DeclIndex ()
166168
aux new = modify' $
167-
DeclIndex . Map.alter (handleDeclaration declId new) declId . unDeclIndex
169+
DeclIndex . Map.alter (Just . handleParseResult declId new) declId . unDeclIndex
168170
where
169171
declId :: C.QualPrelimDeclId
170-
declId = getQualPrelimDeclId new
172+
declId = getParseResultDeclId new
171173

172-
handleDeclaration ::
173-
C.QualPrelimDeclId -> ParseResult -> Maybe Entry -> Maybe Entry
174-
handleDeclaration declId new = \case
175-
Nothing -> Just $ parseResultToEntry new
174+
handleParseResult ::
175+
C.QualPrelimDeclId -> ParseResult -> Maybe Entry -> Entry
176+
handleParseResult declId new = \case
177+
Nothing -> parseResultToEntry new
176178
-- We remove duplicates with /different/ values and store them as
177179
-- 'ConflictingDeclarations'. We could detect and handle some but not all
178180
-- of these duplicates; for now, we remove them all.
@@ -195,49 +197,36 @@ fromParseResults results = flip execState emptyIndex $ mapM_ aux results
195197
-- the @DeclIndex@ has been built (at this point the macro is merely a
196198
-- list of tokens). So whether the macro is something we can handle or not
197199
-- is irrelevant at this point.
198-
Just oldDuplicate -> Just $ case oldDuplicate of
200+
Just old -> case old of
199201
UsableE oldUsable -> case oldUsable of
200202
UsableSuccess oldParseSuccess
201203
-- Redeclaration but with the same definition. This can happen, for
202-
-- example for opaque structs. We stick with the first but add the
203-
-- parse messages of the second.
204+
-- example for opaque structs. We stick with the first declaration.
204205
| ParseResultSuccess newParseSuccess <- new
205-
, sameParseResult (ParseResultSuccess oldParseSuccess) new ->
206-
UsableE $ UsableSuccess $ over #psAttachedMsgs
207-
(++ newParseSuccess.psAttachedMsgs)
208-
oldParseSuccess
206+
, sameDefinition oldParseSuccess.psDecl.declKind newParseSuccess.psDecl.declKind ->
207+
old
209208
| otherwise ->
210209
newConflict oldParseSuccess.psDecl.declInfo.declLoc
211-
-- TODO_PR: Should not happen because we have no external entries yet.
212-
-- Panic?
213-
UsableExternal -> UsableE UsableExternal
210+
UsableExternal ->
211+
panicPure "handleParseResult: usable external"
214212
UnusableE oldUnusable -> case oldUnusable of
215-
(UnusableParseNotAttempted r)
216-
| sameParseResult (ParseResultNotAttempted r) new ->
217-
oldDuplicate
213+
(UnusableParseNotAttempted nasOld)
214+
| ParseResultNotAttempted naNew <- new ->
215+
UnusableE $ UnusableParseNotAttempted $ naNew <| nasOld
218216
| otherwise ->
219-
newConflict (unParseNotAttempted r).loc
220-
UnusableParseFailure r
221-
| sameParseResult (ParseResultFailure r) new ->
222-
oldDuplicate
223-
| otherwise ->
224-
newConflict (unParseFailure r).loc
225-
UnusableConflict c -> addConflict c
226-
-- TODO_PR: Should not happen because we have no failed macros yet.
227-
-- Panic?
228-
UnusableFailedMacro r -> UnusableE $ UnusableFailedMacro r
229-
-- TODO_PR: Should not happen because we have no omitted entries yet.
230-
-- Panic?
231-
UnusableOmitted o -> UnusableE $ UnusableOmitted o
217+
parseResultToEntry new
218+
UnusableParseFailure _ -> old
219+
UnusableConflict c -> addConflicts c
220+
UnusableFailedMacro x ->
221+
panicPure $ "handleParseResult: unusable failed macro" <> show x
222+
UnusableOmitted x ->
223+
panicPure $ "handelParseResult: unusable omitted" <> show x
232224
where
233225
newLoc :: SingleLoc
234-
newLoc = case new of
235-
ParseResultSuccess ParseSuccess{psDecl} -> psDecl.declInfo.declLoc
236-
ParseResultNotAttempted (ParseNotAttempted m) -> m.loc
237-
ParseResultFailure (ParseFailure m) -> m.loc
226+
newLoc = getParseResultLoc new
238227

239-
addConflict :: ConflictingDeclarations -> Entry
240-
addConflict c =
228+
addConflicts :: ConflictingDeclarations -> Entry
229+
addConflicts c =
241230
UnusableE $ UnusableConflict $
242231
addConflictingLoc c newLoc
243232

@@ -248,28 +237,20 @@ fromParseResults results = flip execState emptyIndex $ mapM_ aux results
248237

249238
parseResultToEntry :: ParseResult -> Entry
250239
parseResultToEntry = \case
251-
ParseResultSuccess r -> UsableE $ UsableSuccess r
252-
ParseResultNotAttempted r -> UnusableE $ UnusableParseNotAttempted r
253-
ParseResultFailure r -> UnusableE $ UnusableParseFailure r
254-
255-
sameParseResult :: ParseResult -> ParseResult -> Bool
256-
sameParseResult a b = case (a, b) of
257-
(ParseResultSuccess x1 , ParseResultSuccess x2) ->
258-
sameDefinition x1.psDecl.declKind x2.psDecl.declKind
259-
(ParseResultNotAttempted x1 , ParseResultNotAttempted x2) -> x1 == x2
260-
(ParseResultFailure x1 , ParseResultFailure x2) -> x1 == x2
261-
(_ , _) -> False
262-
263-
sameDefinition :: C.DeclKind Parse -> C.DeclKind Parse -> Bool
264-
sameDefinition a b =
265-
case (a, b) of
266-
(C.DeclMacro macroA, C.DeclMacro macroB) ->
267-
sameMacro macroA macroB
268-
_otherwise ->
269-
a == b
270-
271-
sameMacro :: UnparsedMacro -> UnparsedMacro -> Bool
272-
sameMacro = (==) `on` (map tokenSpelling . unparsedTokens)
240+
ParseResultSuccess r -> UsableE $ UsableSuccess r
241+
ParseResultNotAttempted r -> UnusableE $ UnusableParseNotAttempted $ r :| []
242+
ParseResultFailure r -> UnusableE $ UnusableParseFailure r
243+
244+
sameDefinition :: C.DeclKind Parse -> C.DeclKind Parse -> Bool
245+
sameDefinition a b =
246+
case (a, b) of
247+
(C.DeclMacro macroA, C.DeclMacro macroB) ->
248+
sameMacro macroA macroB
249+
_otherwise ->
250+
a == b
251+
252+
sameMacro :: UnparsedMacro -> UnparsedMacro -> Bool
253+
sameMacro = (==) `on` (map tokenSpelling . unparsedTokens)
273254

274255
{-------------------------------------------------------------------------------
275256
Query parse successes
@@ -308,36 +289,30 @@ lookupEntry x = Map.lookup x . unDeclIndex
308289
toList :: DeclIndex -> [(C.QualPrelimDeclId, Entry)]
309290
toList = Map.toList . unDeclIndex
310291

311-
-- | Get the source location of a declaration.
312-
lookupLoc :: C.QualPrelimDeclId -> DeclIndex -> Maybe SingleLoc
292+
-- | Get the source locations of a declaration.
293+
lookupLoc :: C.QualPrelimDeclId -> DeclIndex -> [SingleLoc]
313294
lookupLoc d (DeclIndex i) = case Map.lookup d i of
314-
Nothing -> Nothing
295+
Nothing -> []
315296
Just (UsableE e) -> case e of
316-
UsableSuccess x -> Just $ x.psDecl.declInfo.declLoc
317-
UsableExternal -> Nothing
318-
Just (UnusableE e) -> case e of
319-
UnusableParseNotAttempted (ParseNotAttempted x) -> Just $ x.loc
320-
UnusableParseFailure (ParseFailure x) -> Just $ x.loc
321-
-- TODO_PR: What should we do for conflicting declarations? Return the
322-
-- minimum location (relevant for sorting select messages), return all
323-
-- locations, or return none? See also 'lookupUnusableLoc' below.
324-
UnusableConflict x -> Just $ getMinimumLoc x
325-
UnusableFailedMacro (FailedMacro x) -> Just $ x.loc
326-
UnusableOmitted{} -> Nothing
327-
328-
-- TODO_PR: We use this function when looking for missing declarations during
329-
-- resolution of external binding specifications. Do we want to get all
330-
-- locations for conflicting declarations here?
297+
UsableSuccess x -> [x.psDecl.declInfo.declLoc]
298+
UsableExternal -> []
299+
Just (UnusableE e) -> unusableToLoc e
300+
301+
-- | Get the source locations of an unusable declaration.
331302
lookupUnusableLoc :: C.QualPrelimDeclId -> DeclIndex -> [SingleLoc]
332303
lookupUnusableLoc d (DeclIndex i) = case Map.lookup d i of
333304
Nothing -> []
334305
Just (UsableE _) -> []
335-
Just (UnusableE e) -> case e of
336-
UnusableParseNotAttempted (ParseNotAttempted x) -> [x.loc]
337-
UnusableParseFailure (ParseFailure x) -> [x.loc]
338-
UnusableConflict x -> getLocs x
339-
UnusableFailedMacro (FailedMacro x) -> [x.loc]
340-
UnusableOmitted{} -> []
306+
Just (UnusableE e) -> unusableToLoc e
307+
308+
unusableToLoc :: Unusable -> [SingleLoc]
309+
unusableToLoc = \case
310+
UnusableParseNotAttempted xs ->
311+
[x.loc | (ParseNotAttempted x) <- NonEmpty.toList xs]
312+
UnusableParseFailure (ParseFailure x) -> [x.loc]
313+
UnusableConflict x -> getLocs x
314+
UnusableFailedMacro (FailedMacro x) -> [x.loc]
315+
UnusableOmitted{} -> []
341316

342317
-- | Get the identifiers of all declarations in the index.
343318
keysSet :: DeclIndex -> Set C.QualPrelimDeclId
@@ -372,6 +347,8 @@ registerMacroFailures xs index = Foldable.foldl' insert index xs
372347
-- Match function to find selection roots.
373348
type Match = C.QualPrelimDeclId -> SingleLoc -> C.Availability -> Bool
374349

350+
-- | Limit the declaration index to those entries that match the select
351+
-- predicate. Do not include anything external nor omitted.
375352
selectDeclIndex :: Match -> DeclIndex -> DeclIndex
376353
selectDeclIndex p = DeclIndex . Map.filter matchEntry . unDeclIndex
377354
where
@@ -380,19 +357,17 @@ selectDeclIndex p = DeclIndex . Map.filter matchEntry . unDeclIndex
380357
UsableE e -> case e of
381358
UsableSuccess (ParseSuccess i d _) ->
382359
p i d.declInfo.declLoc d.declInfo.declAvailability
383-
-- TODO_PR: We should match external declarations.
384360
UsableExternal ->
385361
False
386362
UnusableE e -> case e of
387-
UnusableParseNotAttempted (ParseNotAttempted m) ->
388-
matchMsg m
363+
UnusableParseNotAttempted xs ->
364+
any (matchMsg . unParseNotAttempted) xs
389365
UnusableParseFailure (ParseFailure m) ->
390366
matchMsg m
391367
UnusableConflict x ->
392368
or [p (getDeclId x) l C.Available | l <- getLocs x ]
393369
UnusableFailedMacro (FailedMacro m) ->
394370
matchMsg m
395-
-- TODO_PR: We should match omitted declarations.
396371
UnusableOmitted{} ->
397372
False
398373

hs-bindgen/src-internal/HsBindgen/Frontend/Analysis/UseDeclGraph.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module HsBindgen.Frontend.Analysis.UseDeclGraph (
1616
-- * Query
1717
, toDecls
1818
, getTransitiveDeps
19+
, getStrictTransitiveDeps
1920
-- * Deletion
2021
, deleteDeps
2122
-- * Debugging
@@ -26,6 +27,7 @@ import Data.DynGraph.Labelled (DynGraph)
2627
import Data.DynGraph.Labelled qualified as DynGraph
2728
import Data.List qualified as List
2829
import Data.Map qualified as Map
30+
import Data.Set qualified as Set
2931

3032
import Clang.HighLevel.Types
3133
import Clang.Paths
@@ -118,6 +120,9 @@ toDecls index (Wrap graph) =
118120
getTransitiveDeps :: UseDeclGraph -> [C.QualPrelimDeclId] -> Set C.QualPrelimDeclId
119121
getTransitiveDeps = DynGraph.reaches . unwrap
120122

123+
getStrictTransitiveDeps :: UseDeclGraph -> [C.QualPrelimDeclId] -> Set C.QualPrelimDeclId
124+
getStrictTransitiveDeps graph xs = getTransitiveDeps graph xs Set.\\ (Set.fromList xs)
125+
121126
{-------------------------------------------------------------------------------
122127
Deletion
123128
-------------------------------------------------------------------------------}

hs-bindgen/src-internal/HsBindgen/Frontend/Pass/ConstructTranslationUnit/Conflict.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module HsBindgen.Frontend.Pass.ConstructTranslationUnit.Conflict (
2-
ConflictingDeclarations
2+
ConflictingDeclarations -- opaque
33
, conflictingDeclarations
44
, addConflictingLoc
55
, getDeclId
@@ -16,7 +16,7 @@ import HsBindgen.Frontend.Naming qualified as C
1616
import HsBindgen.Imports
1717
import HsBindgen.Util.Tracer
1818

19-
-- | Abstract data type describing conflicting declarations
19+
-- | Multiple declarations for the same identifier
2020
data ConflictingDeclarations = ConflictingDeclarations {
2121
conflictId :: C.QualPrelimDeclId
2222
, conflictLocs :: Set SingleLoc
@@ -48,7 +48,7 @@ conflictingDeclarations :: C.QualPrelimDeclId -> SingleLoc -> SingleLoc -> Confl
4848
conflictingDeclarations d l1 l2 = ConflictingDeclarations d $ Set.fromList [l1, l2]
4949

5050
addConflictingLoc :: ConflictingDeclarations -> SingleLoc -> ConflictingDeclarations
51-
addConflictingLoc (ConflictingDeclarations d ls) l = ConflictingDeclarations d $ Set.insert l ls
51+
addConflictingLoc (ConflictingDeclarations d xs) x = ConflictingDeclarations d $ Set.insert x xs
5252

5353
getDeclId :: ConflictingDeclarations -> C.QualPrelimDeclId
5454
getDeclId = conflictId

hs-bindgen/src-internal/HsBindgen/Frontend/Pass/Parse/Decl.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ structDecl info = \curr -> do
257257

258258
foldRecurseWith (declOrFieldDecl $ structFieldDecl info) $ \xs -> do
259259
let (otherRs, fields) = first concat $ partitionEithers xs
260-
(fails, otherDecls) = partitionEithers $ map getDecl otherRs
260+
(fails, otherDecls) = partitionEithers $ map getParseResultDecl otherRs
261261
mPartitioned <- partitionChildren otherDecls fields
262262
pure $ (fails ++) $ case mPartitioned of
263263
Just decls ->
@@ -318,7 +318,7 @@ unionDecl info = \curr -> do
318318

319319
foldRecurseWith (declOrFieldDecl $ unionFieldDecl info) $ \xs -> do
320320
let (otherRs, fields) = first concat $ partitionEithers xs
321-
(fails, otherDecls) = partitionEithers $ map getDecl otherRs
321+
(fails, otherDecls) = partitionEithers $ map getParseResultDecl otherRs
322322
mPartitioned <- partitionChildren otherDecls fields
323323
pure $ (fails ++) $ case mPartitioned of
324324
Just decls ->
@@ -517,7 +517,7 @@ functionDecl info = \curr -> do
517517
_ -> foldRecurseWith nestedDecl $ \nestedDecls -> do
518518
let declsAndAttrs = concat nestedDecls
519519
(parseRs, attrs) = partitionEithers declsAndAttrs
520-
(fails, decls) = partitionEithers $ map getDecl parseRs
520+
(fails, decls) = partitionEithers $ map getParseResultDecl parseRs
521521
purity = C.decideFunctionPurity attrs
522522
(anonDecls, otherDecls) = partitionAnonDecls decls
523523

@@ -638,7 +638,7 @@ varDecl info = \curr -> do
638638
foldContinue
639639
_ -> foldRecurseWith nestedDecl $ \nestedRs -> do
640640
let
641-
(fails, nestedDecls) = partitionEithers $ map getDecl $ concat nestedRs
641+
(fails, nestedDecls) = partitionEithers $ map getParseResultDecl $ concat nestedRs
642642
(anonDecls, otherDecls) = partitionAnonDecls nestedDecls
643643

644644
-- This declaration may act as a definition even if it has no

0 commit comments

Comments
 (0)