@@ -23,7 +23,8 @@ import Development.IDE.Types.Location
23
23
-- standard imports
24
24
import Control.Monad.Extra
25
25
import Control.Monad.IO.Class
26
- import Data.List (isSuffixOf )
26
+ import Data.List (isSuffixOf , find )
27
+ import qualified Data.Set as S
27
28
import Data.Maybe
28
29
import System.FilePath
29
30
@@ -70,19 +71,30 @@ modSummaryToArtifactsLocation nfp ms = ArtifactsLocation nfp (ms_location <$> ms
70
71
Just modSum -> isSource (ms_hsc_src modSum)
71
72
mbMod = ms_mod <$> ms
72
73
74
+ data LocateResult
75
+ = LocateNotFound
76
+ | LocateFoundReexport UnitId
77
+ | LocateFoundFile UnitId NormalizedFilePath
78
+
73
79
-- | locate a module in the file system. Where we go from *daml to Haskell
74
80
locateModuleFile :: MonadIO m
75
- => [(UnitId , [FilePath ])]
81
+ => [(UnitId , [FilePath ], S. Set ModuleName )]
76
82
-> [String ]
77
83
-> (ModuleName -> NormalizedFilePath -> m (Maybe NormalizedFilePath ))
78
84
-> Bool
79
85
-> ModuleName
80
- -> m ( Maybe ( UnitId , NormalizedFilePath ))
86
+ -> m LocateResult
81
87
locateModuleFile import_dirss exts targetFor isSource modName = do
82
88
let candidates import_dirs =
83
89
[ toNormalizedFilePath' (prefix </> moduleNameSlashes modName <.> maybeBoot ext)
84
90
| prefix <- import_dirs , ext <- exts]
85
- firstJustM go (concat [map (uid,) (candidates dirs) | (uid, dirs) <- import_dirss])
91
+ mf <- firstJustM go (concat [map (uid,) (candidates dirs) | (uid, dirs, _) <- import_dirss])
92
+ case mf of
93
+ Nothing ->
94
+ case find (\ (_ , _, reexports) -> S. member modName reexports) import_dirss of
95
+ Just (uid,_,_) -> pure $ LocateFoundReexport uid
96
+ Nothing -> pure $ LocateNotFound
97
+ Just (uid,file) -> pure $ LocateFoundFile uid file
86
98
where
87
99
go (uid, candidate) = fmap ((uid,) <$> ) $ targetFor modName candidate
88
100
maybeBoot ext
@@ -94,11 +106,11 @@ locateModuleFile import_dirss exts targetFor isSource modName = do
94
106
-- current module. In particular, it will return Nothing for 'main' components
95
107
-- as they can never be imported into another package.
96
108
#if MIN_VERSION_ghc(9,3,0)
97
- mkImportDirs :: HscEnv -> (UnitId , DynFlags ) -> Maybe (UnitId , [FilePath ])
98
- mkImportDirs _env (i, flags) = Just (i, importPaths flags)
109
+ mkImportDirs :: HscEnv -> (UnitId , DynFlags ) -> Maybe (UnitId , ( [FilePath ], S. Set ModuleName ) )
110
+ mkImportDirs _env (i, flags) = Just (i, ( importPaths flags, reexportedModules flags) )
99
111
#else
100
- mkImportDirs :: HscEnv -> (UnitId , DynFlags ) -> Maybe (PackageName , (UnitId , [FilePath ]))
101
- mkImportDirs env (i, flags) = (, (i, importPaths flags)) <$> getUnitName env i
112
+ mkImportDirs :: HscEnv -> (UnitId , DynFlags ) -> Maybe (PackageName , (UnitId , [FilePath ], S. Set ModuleName ))
113
+ mkImportDirs env (i, flags) = (, (i, importPaths flags, S. empty )) <$> getUnitName env i
102
114
#endif
103
115
104
116
-- | locate a module in either the file system or the package database. Where we go from *daml to
@@ -125,16 +137,16 @@ locateModule env comp_info exts targetFor modName mbPkgName isSource = do
125
137
#else
126
138
Just " this" -> do
127
139
#endif
128
- lookupLocal (homeUnitId_ dflags) (importPaths dflags)
140
+ lookupLocal (homeUnitId_ dflags) (importPaths dflags) S. empty
129
141
-- if a package name is given we only go look for a package
130
142
#if MIN_VERSION_ghc(9,3,0)
131
143
OtherPkg uid
132
- | Just dirs <- lookup uid import_paths
133
- -> lookupLocal uid dirs
144
+ | Just ( dirs, reexports) <- lookup uid import_paths
145
+ -> lookupLocal uid dirs reexports
134
146
#else
135
147
Just pkgName
136
- | Just (uid, dirs) <- lookup (PackageName pkgName) import_paths
137
- -> lookupLocal uid dirs
148
+ | Just (uid, dirs, reexports ) <- lookup (PackageName pkgName) import_paths
149
+ -> lookupLocal uid dirs reexports
138
150
#endif
139
151
| otherwise -> lookupInPackageDB
140
152
#if MIN_VERSION_ghc(9,3,0)
@@ -143,10 +155,15 @@ locateModule env comp_info exts targetFor modName mbPkgName isSource = do
143
155
Nothing -> do
144
156
#endif
145
157
146
- mbFile <- locateModuleFile ((homeUnitId_ dflags, importPaths dflags) : other_imports) exts targetFor isSource $ unLoc modName
158
+ -- Reexports for current unit have to be empty because they only apply to other units depending on the
159
+ -- current unit. If we set the reexports to be the actual reexports then we risk looping forever trying
160
+ -- to find the module from the perspective of the current unit.
161
+ mbFile <- locateModuleFile ((homeUnitId_ dflags, importPaths dflags, S. empty) : other_imports) exts targetFor isSource $ unLoc modName
147
162
case mbFile of
148
- Nothing -> lookupInPackageDB
149
- Just (uid, file) -> toModLocation uid file
163
+ LocateNotFound -> lookupInPackageDB
164
+ -- Lookup again with the perspective of the unit reexporting the file
165
+ LocateFoundReexport uid -> locateModule (hscSetActiveUnitId uid env) comp_info exts targetFor modName noPkgQual isSource
166
+ LocateFoundFile uid file -> toModLocation uid file
150
167
where
151
168
dflags = hsc_dflags env
152
169
import_paths = mapMaybe (mkImportDirs env) comp_info
@@ -160,7 +177,7 @@ locateModule env comp_info exts targetFor modName mbPkgName isSource = do
160
177
-- about which module unit a imports.
161
178
-- Without multi-component support it is hard to recontruct the dependency environment so
162
179
-- unit a will have both unit b and unit c in scope.
163
- map (\ uid -> (uid, importPaths ( homeUnitEnv_dflags (ue_findHomeUnitEnv uid ue)) )) hpt_deps
180
+ map (\ uid -> let this_df = homeUnitEnv_dflags (ue_findHomeUnitEnv uid ue) in (uid, importPaths this_df, reexportedModules this_df )) hpt_deps
164
181
ue = hsc_unit_env env
165
182
units = homeUnitEnv_units $ ue_findHomeUnitEnv (homeUnitId_ dflags) ue
166
183
hpt_deps :: [UnitId ]
@@ -186,11 +203,13 @@ locateModule env comp_info exts targetFor modName mbPkgName isSource = do
186
203
let genMod = mkModule (RealUnit $ Definite uid) (unLoc modName) -- TODO support backpack holes
187
204
return $ Right $ FileImport $ ArtifactsLocation file (Just loc) (not isSource) (Just genMod)
188
205
189
- lookupLocal uid dirs = do
190
- mbFile <- locateModuleFile [(uid, dirs)] exts targetFor isSource $ unLoc modName
206
+ lookupLocal uid dirs reexports = do
207
+ mbFile <- locateModuleFile [(uid, dirs, reexports )] exts targetFor isSource $ unLoc modName
191
208
case mbFile of
192
- Nothing -> return $ Left $ notFoundErr env modName $ LookupNotFound []
193
- Just (uid', file) -> toModLocation uid' file
209
+ LocateNotFound -> return $ Left $ notFoundErr env modName $ LookupNotFound []
210
+ -- Lookup again with the perspective of the unit reexporting the file
211
+ LocateFoundReexport uid' -> locateModule (hscSetActiveUnitId uid' env) comp_info exts targetFor modName noPkgQual isSource
212
+ LocateFoundFile uid' file -> toModLocation uid' file
194
213
195
214
lookupInPackageDB = do
196
215
case Compat. lookupModuleWithSuggestions env (unLoc modName) mbPkgName of
@@ -239,3 +258,11 @@ notFound = NotFound
239
258
, fr_unusables = []
240
259
, fr_suggestions = []
241
260
}
261
+
262
+ #if MIN_VERSION_ghc(9,3,0)
263
+ noPkgQual :: PkgQual
264
+ noPkgQual = NoPkgQual
265
+ #else
266
+ noPkgQual :: Maybe a
267
+ noPkgQual = Nothing
268
+ #endif
0 commit comments