git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
make `exportedDeclarations` filter everything

Fixes #747 In addition to its previous behaviour of filtering out declarations which are not exported, `exportedDeclarations` will now also: * Filter out instance declarations which refer to non-exported types, as these can be considered as unexported. * Descend into data declarations, and filter out unexported constructors The effect of this is that tooling like psci and psc-docs can now simply call `exportedDeclarations` and not have to worry about anything.

commit783061d5faac72d2dac1e8acdd95d2b8f33db566 authorHarry Garrood <harry@garrood.me> dateWed 15 Apr 2015, 03:03 (12 years ago) parentb7a4b32
7 files changed+194−76
examples/manual/passing/ExportedInstanceDeclarations.purs+41 psci/Completion.hs+5−14 purescript.cabal+1 src/Language/PureScript/AST.hs+1 src/Language/PureScript/AST/Declarations.hs−47 src/Language/PureScript/AST/Exported.hs+132 src/Language/PureScript/Docs/Render.hs+14−15
examples/manual/passing/ExportedInstanceDeclarations.pursnew file+41
@@ -0,0 +1,41 @@
1+
2+-- Tests that instances for non-exported classes / types do not appear in the
3+-- result of `exportedDeclarations`.
4+
5+module ExportedInstanceDeclarations
6+ ( Const(..)
7+ , Foo
8+ , foo
9+ ) where
10+
11+data Const a b = Const a
12+
13+class Foo a where
14+ foo :: a
15+
16+data NonexportedType = NonexportedType
17+
18+class NonexportedClass a where
19+ notExported :: a
20+
21+-- There are three places that a nonexported type or type class can occur,
22+-- leading an instance to count as non-exported:
23+-- * Constraints
24+-- * The type class itself
25+-- * The instance types
26+
27+-- Case 1: constraints
28+instance nonExportedFoo :: (NonexportedClass a) => Foo a where
29+ foo = notExported
30+
31+-- Another instance of case 1:
32+instance nonExportedFoo2 :: (Foo NonexportedType) => Foo (a -> a) where
33+ foo = id
34+
35+-- Case 2: type class
36+instance nonExportedNonexportedType :: NonexportedClass (Const Number a) where
37+ notExported = Const 0
38+
39+-- Case 3: instance types
40+instance constFoo :: Foo (Const NonexportedType b) where
41+ foo = Const NonexportedType
psci/Completion.hs+5−14
@@ -204,21 +204,12 @@ identNames = nubOnFst . mapMaybe getDeclName . P.exportedDeclarations
204204 getDeclName _ = Nothing
205205
206206dctorNames :: P.Module -> [(N.ProperName, P.Declaration)]
207−dctorNames m = nubOnFst $ concatMap dctors dnames
207+dctorNames = nubOnFst . concatMap go . P.exportedDeclarations
208208 where
209− getDataDeclName :: P.Declaration -> Maybe (N.ProperName, P.Declaration)
210− getDataDeclName d@(P.DataDeclaration _ name _ _) = Just (name, d)
211− getDataDeclName (P.PositionedDeclaration _ _ d) = getDataDeclName d
212− getDataDeclName _ = Nothing
213−
214− dnames :: [(N.ProperName, P.Declaration)]
215− dnames = (mapMaybe getDataDeclName onlyDataDecls)
216−
217− onlyDataDecls :: [P.Declaration]
218− onlyDataDecls = (filter P.isDataDecl (P.exportedDeclarations m))
219−
220− dctors :: (N.ProperName, P.Declaration) -> [(N.ProperName, P.Declaration)]
221− dctors (name, decl) = map (\n -> (n, decl)) (map fst (P.exportedDctors m name))
209+ go :: P.Declaration -> [(N.ProperName, P.Declaration)]
210+ go decl@(P.DataDeclaration _ _ _ ctors) = map (\n -> (n, decl)) (map fst ctors)
211+ go (P.PositionedDeclaration _ _ d) = go d
212+ go _ = []
222213
223214moduleNames :: [P.Module] -> [String]
224215moduleNames ms = nub [show moduleName | P.Module _ moduleName _ _ <- ms]
purescript.cabal+1
@@ -43,6 +43,7 @@ library
4343 Language.PureScript.AST.Operators
4444 Language.PureScript.AST.SourcePos
4545 Language.PureScript.AST.Traversals
46+ Language.PureScript.AST.Exported
4647 Language.PureScript.CodeGen
4748 Language.PureScript.CodeGen.Externs
4849 Language.PureScript.CodeGen.JS
src/Language/PureScript/AST.hs+1
@@ -21,3 +21,4 @@ import Language.PureScript.AST.Declarations as AST
2121import Language.PureScript.AST.Operators as AST
2222import Language.PureScript.AST.SourcePos as AST
2323import Language.PureScript.AST.Traversals as AST
24+import Language.PureScript.AST.Exported as AST
src/Language/PureScript/AST/Declarations.hs−47
@@ -40,53 +40,6 @@ data Module = Module [Comment] ModuleName [Declaration] (Maybe [DeclarationRef])
4040getModuleName :: Module -> ModuleName
4141getModuleName (Module _ name _ _) = name
4242
43−-- |
44−-- Test if a declaration is exported, given a module's export list.
45−--
46−isExported :: Maybe [DeclarationRef] -> Declaration -> Bool
47−isExported Nothing _ = True
48−isExported _ TypeInstanceDeclaration{} = True
49−isExported exps (PositionedDeclaration _ _ d) = isExported exps d
50−isExported (Just exps) decl = any (matches decl) exps
51− where
52− matches (TypeDeclaration ident _) (ValueRef ident') = ident == ident'
53− matches (ValueDeclaration ident _ _ _) (ValueRef ident') = ident == ident'
54− matches (ExternDeclaration _ ident _ _) (ValueRef ident') = ident == ident'
55− matches (DataDeclaration _ ident _ _) (TypeRef ident' _) = ident == ident'
56− matches (ExternDataDeclaration ident _) (TypeRef ident' _) = ident == ident'
57− matches (TypeSynonymDeclaration ident _ _) (TypeRef ident' _) = ident == ident'
58− matches (TypeClassDeclaration ident _ _ _) (TypeClassRef ident') = ident == ident'
59− matches (PositionedDeclaration _ _ d) r = d `matches` r
60− matches d (PositionedDeclarationRef _ _ r) = d `matches` r
61− matches _ _ = False
62−
63−exportedDeclarations :: Module -> [Declaration]
64−exportedDeclarations (Module _ _ decls exps) = filter (isExported exps) (flattenDecls decls)
65−
66−-- |
67−-- Test if a data constructor for a given type is exported, given a module's export list.
68−--
69−isDctorExported :: ProperName -> Maybe [DeclarationRef] -> ProperName -> Bool
70−isDctorExported _ Nothing _ = True
71−isDctorExported ident (Just exps) ctor = test `any` exps
72− where
73− test (PositionedDeclarationRef _ _ d) = test d
74− test (TypeRef ident' Nothing) = ident == ident'
75− test (TypeRef ident' (Just ctors)) = ident == ident' && ctor `elem` ctors
76− test _ = False
77−
78−-- |
79−-- Return the exported data constructors for a given type.
80−--
81−exportedDctors :: Module -> ProperName -> [(ProperName, [Type])]
82−exportedDctors (Module _ _ decls exps) ident =
83− filter (isDctorExported ident exps . fst) dctors
84− where
85− dctors = concatMap getDctors (flattenDecls decls)
86− getDctors (DataDeclaration _ _ _ ctors) = ctors
87− getDctors (PositionedDeclaration _ _ d) = getDctors d
88− getDctors _ = []
89−
9043-- |
9144-- An item in a list of explicit imports or exports
9245--
src/Language/PureScript/AST/Exported.hsnew file+132
@@ -0,0 +1,132 @@
1+
2+module Language.PureScript.AST.Exported (
3+ exportedDeclarations,
4+ isExported
5+) where
6+
7+import Control.Category ((>>>))
8+import Data.Maybe (mapMaybe)
9+
10+import Language.PureScript.AST.Declarations
11+import Language.PureScript.Types
12+import Language.PureScript.Names
13+
14+-- |
15+-- Return a list of all declarations which are exported from a module.
16+-- This function descends into data declarations to filter out unexported
17+-- data constructors, and also filters out type instance declarations if
18+-- they refer to classes or types which are not themselves exported.
19+--
20+-- Note that this function assumes that the module has already had its imports
21+-- desugared using 'Language.PureScript.Sugar.Names.desugarImports'. It will
22+-- produce incorrect results if this is not the case - for example, type class
23+-- instances will be incorrectly removed in some cases.
24+--
25+exportedDeclarations :: Module -> [Declaration]
26+exportedDeclarations (Module _ _ decls exps) = go decls
27+ where
28+ go = flattenDecls
29+ >>> filter (isExported exps)
30+ >>> map (filterDataConstructors exps)
31+ >>> filterInstances exps
32+
33+-- |
34+-- Filter out all data constructors from a declaration which are not exported.
35+-- If the supplied declaration is not a data declaration, this function returns
36+-- it unchanged.
37+--
38+filterDataConstructors :: Maybe [DeclarationRef] -> Declaration -> Declaration
39+filterDataConstructors exps (DataDeclaration dType tyName tyArgs dctors) =
40+ DataDeclaration dType tyName tyArgs $
41+ filter (isDctorExported tyName exps . fst) dctors
42+filterDataConstructors exps (PositionedDeclaration srcSpan coms d) =
43+ PositionedDeclaration srcSpan coms (filterDataConstructors exps d)
44+filterDataConstructors _ other = other
45+
46+-- |
47+-- Filter out all the type instances from a list of declarations which
48+-- reference a type or type class which is both local and not exported.
49+--
50+-- Note that this function assumes that the module has already had its imports
51+-- desugared using "Language.PureScript.Sugar.Names.desugarImports". It will
52+-- produce incorrect results if this is not the case - for example, type class
53+-- instances will be incorrectly removed in some cases.
54+--
55+filterInstances :: Maybe [DeclarationRef] -> [Declaration] -> [Declaration]
56+filterInstances Nothing = id
57+filterInstances (Just exps) =
58+ let refs = mapMaybe typeName exps ++ mapMaybe typeClassName exps
59+ in filter (all (visibleOutside refs) . typeInstanceConstituents)
60+ where
61+ -- Given a Qualified ProperName, and a list of all exported types and type
62+ -- classes, returns whether the supplied Qualified ProperName is visible
63+ -- outside this module. This is true if one of the following hold:
64+ --
65+ -- * the name is defined in the same module and is exported,
66+ -- * the name is defined in a different module (and must be exported from
67+ -- that module; the code would fail to compile otherwise).
68+ visibleOutside _ (Qualified (Just _) _) = True
69+ visibleOutside refs (Qualified Nothing n) = any (== n) refs
70+
71+ typeName (TypeRef n _) = Just n
72+ typeName (PositionedDeclarationRef _ _ r) = typeName r
73+ typeName _ = Nothing
74+
75+ typeClassName (TypeClassRef n) = Just n
76+ typeClassName (PositionedDeclarationRef _ _ r) = typeClassName r
77+ typeClassName _ = Nothing
78+
79+-- |
80+-- Get all type and type class names referenced by a type instance declaration.
81+--
82+typeInstanceConstituents :: Declaration -> [Qualified ProperName]
83+typeInstanceConstituents (TypeInstanceDeclaration _ constraints className tys _) =
84+ className : (concatMap fromConstraint constraints ++ concatMap fromType tys)
85+ where
86+
87+ fromConstraint (name, tys') = name : concatMap fromType tys'
88+ fromType = everythingOnTypes (++) go
89+
90+ -- Note that type synonyms are disallowed in instance declarations, so
91+ -- we don't need to handle them here.
92+ go (TypeConstructor n) = [n]
93+ go (ConstrainedType cs _) = concatMap fromConstraint cs
94+ go _ = []
95+
96+typeInstanceConstituents (PositionedDeclaration _ _ d) = typeInstanceConstituents d
97+typeInstanceConstituents _ = []
98+
99+
100+-- |
101+-- Test if a declaration is exported, given a module's export list. Prefer
102+-- 'exportedDeclarations' to this function, where possible.
103+--
104+isExported :: Maybe [DeclarationRef] -> Declaration -> Bool
105+isExported Nothing _ = True
106+isExported _ TypeInstanceDeclaration{} = True
107+isExported exps (PositionedDeclaration _ _ d) = isExported exps d
108+isExported (Just exps) decl = any (matches decl) exps
109+ where
110+ matches (TypeDeclaration ident _) (ValueRef ident') = ident == ident'
111+ matches (ValueDeclaration ident _ _ _) (ValueRef ident') = ident == ident'
112+ matches (ExternDeclaration _ ident _ _) (ValueRef ident') = ident == ident'
113+ matches (DataDeclaration _ ident _ _) (TypeRef ident' _) = ident == ident'
114+ matches (ExternDataDeclaration ident _) (TypeRef ident' _) = ident == ident'
115+ matches (TypeSynonymDeclaration ident _ _) (TypeRef ident' _) = ident == ident'
116+ matches (TypeClassDeclaration ident _ _ _) (TypeClassRef ident') = ident == ident'
117+ matches (PositionedDeclaration _ _ d) r = d `matches` r
118+ matches d (PositionedDeclarationRef _ _ r) = d `matches` r
119+ matches _ _ = False
120+
121+-- |
122+-- Test if a data constructor for a given type is exported, given a module's
123+-- export list. Prefer 'exportedDeclarations' to this function, where possible.
124+--
125+isDctorExported :: ProperName -> Maybe [DeclarationRef] -> ProperName -> Bool
126+isDctorExported _ Nothing _ = True
127+isDctorExported ident (Just exps) ctor = test `any` exps
128+ where
129+ test (PositionedDeclarationRef _ _ d) = test d
130+ test (TypeRef ident' Nothing) = ident == ident'
131+ test (TypeRef ident' (Just ctors)) = ident == ident' && ctor `elem` ctors
132+ test _ = False
src/Language/PureScript/Docs/Render.hs+14−15
@@ -35,14 +35,14 @@ renderPackage name vers mods =
3535-- Render a single Module.
3636--
3737renderModule :: P.Module -> RenderedModule
38−renderModule m@(P.Module coms moduleName _ exps) =
38+renderModule m@(P.Module coms moduleName _ _) =
3939 RenderedModule (show moduleName) comments declarations
4040 where
4141 comments = renderComments coms
4242 declarations = groupChildren declarationsWithChildren
4343 declarationsWithChildren = mapMaybe go (P.exportedDeclarations m)
4444 go decl = getDeclarationTitle decl
45− >>= renderDeclaration exps decl
45+ >>= renderDeclaration decl
4646
4747-- | An intermediate stage which we go through during rendering.
4848--
@@ -95,39 +95,38 @@ getDeclarationTitle _ = Nothing
9595basicDeclaration :: String -> RenderedCode -> Maybe IntermediateDeclaration
9696basicDeclaration title code = Just (Right (RenderedDeclaration title Nothing code Nothing []))
9797
98−renderDeclaration :: Maybe [P.DeclarationRef] -> P.Declaration -> String -> Maybe IntermediateDeclaration
99−renderDeclaration _ (P.TypeDeclaration ident' ty) title =
98+renderDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
99+renderDeclaration (P.TypeDeclaration ident' ty) title =
100100 basicDeclaration title code
101101 where
102102 code = ident (show ident')
103103 <> sp <> syntax "::" <> sp
104104 <> renderType ty
105−renderDeclaration _ (P.ExternDeclaration _ ident' _ ty) title =
105+renderDeclaration (P.ExternDeclaration _ ident' _ ty) title =
106106 basicDeclaration title code
107107 where
108108 code = ident (show ident')
109109 <> sp <> syntax "::" <> sp
110110 <> renderType ty
111−renderDeclaration exps (P.DataDeclaration dtype name args ctors) title =
111+renderDeclaration (P.DataDeclaration dtype name args ctors) title =
112112 Just (Right (RenderedDeclaration title Nothing code Nothing children))
113113 where
114114 typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
115− exported = filter (P.isDctorExported name exps . fst) ctors
116115 code = keyword (show dtype) <> sp <> renderType typeApp
117− children = map renderCtor exported
116+ children = map renderCtor ctors
118117 -- TODO: Comments for data constructors?
119118 renderCtor (ctor', tys) =
120119 let typeApp' = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing ctor')) tys
121120 childCode = renderType typeApp'
122121 in RenderedChildDeclaration (show ctor') Nothing childCode Nothing ChildDataConstructor
123−renderDeclaration _ (P.ExternDataDeclaration name kind') title =
122+renderDeclaration (P.ExternDataDeclaration name kind') title =
124123 basicDeclaration title code
125124 where
126125 code = keywordData <> sp
127126 <> renderType (P.TypeConstructor (P.Qualified Nothing name))
128127 <> sp <> syntax "::" <> sp
129128 <> renderKind kind'
130−renderDeclaration _ (P.TypeSynonymDeclaration name args ty) title =
129+renderDeclaration (P.TypeSynonymDeclaration name args ty) title =
131130 basicDeclaration title code
132131 where
133132 typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
@@ -137,7 +136,7 @@ renderDeclaration _ (P.TypeSynonymDeclaration name args ty) title =
137136 , syntax "="
138137 , renderType ty
139138 ]
140−renderDeclaration _ (P.TypeClassDeclaration name args implies ds) title = do
139+renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
141140 Just (Right (RenderedDeclaration title Nothing code Nothing children))
142141 where
143142 code = mintersperse sp $
@@ -172,7 +171,7 @@ renderDeclaration _ (P.TypeClassDeclaration name args implies ds) title = do
172171 ]
173172 in RenderedChildDeclaration (show ident') Nothing childCode Nothing ChildTypeClassMember
174173 renderClassMember _ = error "Invalid argument to renderClassMember."
175−renderDeclaration _ (P.TypeInstanceDeclaration name constraints className tys _) title = do
174+renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) title = do
176175 Just (Left (classNameString : typeNameStrings, childDecl))
177176 where
178177 classNameString = unQual className
@@ -204,15 +203,15 @@ renderDeclaration _ (P.TypeInstanceDeclaration name constraints className tys _)
204203 in renderType supApp
205204
206205 classApp = foldl P.TypeApp (P.TypeConstructor className) tys
207−renderDeclaration exps (P.PositionedDeclaration srcSpan com d') title =
208− fmap (addComments . addSourceSpan) (renderDeclaration exps d' title)
206+renderDeclaration (P.PositionedDeclaration srcSpan com d') title =
207+ fmap (addComments . addSourceSpan) (renderDeclaration d' title)
209208 where
210209 addComments (Left (t, d)) = Left (t, d { rcdComments = renderComments com })
211210 addComments (Right d) = Right (d { rdComments = renderComments com })
212211
213212 addSourceSpan (Left (t, d)) = Left (t, d { rcdSourceSpan = Just srcSpan })
214213 addSourceSpan (Right d) = Right (d { rdSourceSpan = Just srcSpan })
215−renderDeclaration _ _ _ = Nothing
214+renderDeclaration _ _ = Nothing
216215
217216renderComments :: [P.Comment] -> Maybe String
218217renderComments cs = do