| 115 | | I think that all lookups go through a single function, |
| 116 | | `RnEnv.lookupGreRn_maybe` |
| 117 | | So in `RnEnv.lookupGreRn_maybe`, if `(gre_prov gre)` is `(Imported _)` |
| 118 | | hen put `rdr_name` in a new |
| 119 | | {{{ |
| 120 | | tcg_used_imports :: TcRef (Set RdrName) |
| 121 | | }}} |
| 122 | | in `TcGblEnv`. All the `tcg_used_imports` are in scope; if not, |
| 123 | | we report an error and do not add it to `tct_used_imports`. |
| | 115 | I think that all lookups go through either, `RnEnv.lookupGreRn_maybe` or `RnEnv.lookup_sub_bndr`. |
| | 116 | So in `RnEnv.lookupGreRn_maybe`, if `(gre_prov gre)` is `(Imported _)`, |
| | 117 | and in `RnEnv.lookup_sub_bndr`, |
| | 118 | put `rdr_name` in a new |
| | 119 | {{{ |
| | 120 | tcg_used_rdrnames :: TcRef (Set RdrName) |
| | 121 | }}} |
| | 122 | in `TcGblEnv`. All the `tcg_used_rdrnames` are in scope; if not, |
| | 123 | we report an error and do not add it to `tcg_used_rdrnames`. |
| 146 | | * In `RnNames.reportUnusedNames`, call a function that actually does the |
| 147 | | hard work. The ugly part is when we have an import of Foo(..). Then we |
| 148 | | need to dig through the environments, similar to what |
| 149 | | `RnNames.exports_from_avail` does, so that we can expand the (..). |
| 150 | | |
| 151 | | |
| | 143 | ---- |
| | 144 | |
| | 145 | The algorithm for deciding which imports have been used is based around this datatype: |
| | 146 | {{{ |
| | 147 | data ImportInfo = ImportInfo SrcSpan |
| | 148 | SDoc |
| | 149 | [RdrName] -- The names the import provides |
| | 150 | Bool -- Has it been used yet? |
| | 151 | [ImportInfo] -- Child import infos |
| | 152 | }}} |
| | 153 | Here are how some example imports map to trees of `ImportInfo`, assuming `Foo` exports `a`, `b`, `D(c1, c2)`: |
| | 154 | {{{ |
| | 155 | import Foo |
| | 156 | -> |
| | 157 | ImportInfo "Foo" ["a", "b", "D", "c1", "c2", "Foo.a", "Foo.b", "Foo.D", "Foo.c1", "Foo.c2"] |
| | 158 | |
| | 159 | import qualified Foo as Bar |
| | 160 | -> |
| | 161 | ImportInfo "Foo" ["Bar.a", "Bar.b", "Bar.D", "Bar.c1", "Bar.c2"] |
| | 162 | |
| | 163 | import qualified Foo (a, D) |
| | 164 | -> |
| | 165 | ImportInfo "Foo" [] |
| | 166 | ImportInfo "Foo" ["Foo.a"] |
| | 167 | ImportInfo "Foo" ["Foo.D"] |
| | 168 | |
| | 169 | import qualified Foo hiding (a, D(..)) |
| | 170 | -> |
| | 171 | ImportInfo "Foo" ["Foo.b"] |
| | 172 | |
| | 173 | import Foo (D(c1, c2)) |
| | 174 | -> |
| | 175 | ImportInfo "Foo" [] |
| | 176 | ImportInfo "Foo" ["D", "Foo.D"] |
| | 177 | ImportInfo "Foo" ["c1", "Foo.c1"] |
| | 178 | ImportInfo "Foo" ["c2", "Foo.c2"] |
| | 179 | |
| | 180 | import qualified Foo (D(..)) |
| | 181 | -> |
| | 182 | ImportInfo "Foo" [] |
| | 183 | ImportInfo "Foo" ["Foo.D", "Foo.c1", "Foo.c2"] |
| | 184 | }}} |
| | 185 | |
| | 186 | If a node in the tree is marked as used, then so are all nodes above it. For example, given the tree |
| | 187 | {{{ |
| | 188 | ImportInfo "Foo" [] |
| | 189 | ImportInfo "Foo" ["D", "Foo.D"] |
| | 190 | ImportInfo "Foo" ["c1", "Foo.c1"] |
| | 191 | ImportInfo "Foo" ["c2", "Foo.c2"] |
| | 192 | }}} |
| | 193 | a use of `"D"` marks both the first and second lines as used. |
| | 194 | |
| | 195 | When we come to giving warnings, if a node is unused then we warn about it, and do not descend into the rest of that subtree, as the node we warn about subsumes its children. If the node is marked as used then we descend, looking to see if any of its children are unused. |
| | 196 | |
| | 197 | These trees are built by `RnNames.mkImportInfo`. In `RnNames.warnUnusedImportDecls` we make two lists of `ImportInfo`s; one list contains all the explicit imports, e.g. |
| | 198 | {{{ |
| | 199 | import Foo (a, b) |
| | 200 | }}} |
| | 201 | and the other contains the implicit imports, e.g. |
| | 202 | {{{ |
| | 203 | import Foo |
| | 204 | import Foo hiding (a, b) |
| | 205 | }}} |
| | 206 | |
| | 207 | Then `RnNames.markUsages` is called for each `RdrName` that was used in the program. The current implementation marks all explicit import as used unless there are no such imports, in which case it marks all implicit imports as used. A small tweak to `markUsages` would allow it to mark only the first import it finds as used. |
| | 208 | |
| | 209 | As well as the `RdrName`s used in the source, we also need to mark as used the names that are exported. We first call `RnNames.expandExports` to expand `D(..)` into `D(c1, c2)`, and then call `RnNames.markExportUsages`. Normally this just marks the `RdrName`s as used in the same way that uses in the module body are handled, but it is also possible for an entire module to be "used", if `module Foo` is in the export list. In this case `RnNames.markModuleUsed` does the hard work, marking every module imported with that name as used. |