- go decls fvs gates []
- = returnRn (decls, fvs, gates)
-
- go decls fvs gates (wanted_name:refs)
- | isWiredInName wanted_name
- = load_home wanted_name `thenRn_`
- go decls fvs (gates `plusFV` getWiredInGates wanted_name) refs
-
- | otherwise
- = importDecl wanted_name `thenRn` \ maybe_decl ->
- case maybe_decl of
- -- No declaration... (already slurped, or local)
- Nothing -> go decls fvs gates refs
- Just decl -> rnIfaceDecl decl `thenRn` \ (new_decl, fvs1) ->
- let
- new_gates = getGates source_fvs new_decl
- in
- go (new_decl : decls)
- (fvs1 `plusFV` fvs)
- (gates `plusFV` new_gates)
- (nameSetToList new_gates ++ refs)
-
- -- When we find a wired-in name we must load its
- -- home module so that we find any instance decls therein
- load_home name
- | name `elemNameSet` source_binders = returnRn ()
- -- When compiling the prelude, a wired-in thing may
- -- be defined in this module, in which case we don't
- -- want to load its home module!
- -- Using 'isLocallyDefined' doesn't work because some of
- -- the free variables returned are simply 'listTyCon_Name',
- -- with a system provenance. We could look them up every time
- -- but that seems a waste.
- | otherwise = loadHomeInterface doc name `thenRn_`
- returnRn ()
- where
- doc = ptext SLIT("need home module for wired in thing") <+> ppr name
+ -- The outer loop repeatedly slurps the decls for the current gates
+ -- and the instance decls
+
+ -- The outer loop is needed because consider
+ -- instance Foo a => Baz (Maybe a) where ...
+ -- It may be that @Baz@ and @Maybe@ are used in the source module,
+ -- but not @Foo@; so we need to chase @Foo@ too.
+ --
+ -- We also need to follow superclass refs. In particular, 'chasing @Foo@' must
+ -- include actually getting in Foo's class decl
+ -- class Wib a => Foo a where ..
+ -- so that its superclasses are discovered. The point is that Wib is a gate too.
+ -- We do this for tycons too, so that we look through type synonyms.
+
+ go_outer decls fvs all_gates []
+ = returnRn (decls, fvs)
+
+ go_outer decls fvs all_gates refs -- refs are not necessarily slurped yet
+ = traceRn (text "go_outer" <+> ppr refs) `thenRn_`
+ foldlRn go_inner (decls, fvs, emptyFVs) refs `thenRn` \ (decls1, fvs1, gates1) ->
+ getImportedInstDecls (all_gates `plusFV` gates1) `thenRn` \ inst_decls ->
+ rnInstDecls decls1 fvs1 gates1 inst_decls `thenRn` \ (decls2, fvs2, gates2) ->
+ go_outer decls2 fvs2 (all_gates `plusFV` gates2)
+ (nameSetToList (gates2 `minusNameSet` all_gates))
+ -- Knock out the all_gates because even if we don't slurp any new
+ -- decls we can get some apparently-new gates from wired-in names
+
+ go_inner (decls, fvs, gates) wanted_name
+ = importDecl wanted_name `thenRn` \ import_result ->
+ case import_result of
+ AlreadySlurped -> returnRn (decls, fvs, gates)
+ WiredIn -> returnRn (decls, fvs, gates `plusFV` getWiredInGates wanted_name)
+ Deferred -> returnRn (decls, fvs, gates `addOneFV` wanted_name) -- It's a type constructor
+
+ HereItIs decl -> rnIfaceDecl decl `thenRn` \ (new_decl, fvs1) ->
+ returnRn (new_decl : decls,
+ fvs1 `plusFV` fvs,
+ gates `plusFV` getGates source_fvs new_decl)
+
+rnInstDecls decls fvs gates []
+ = returnRn (decls, fvs, gates)
+rnInstDecls decls fvs gates (d:ds)
+ = rnIfaceDecl d `thenRn` \ (new_decl, fvs1) ->
+ rnInstDecls (new_decl:decls)
+ (fvs1 `plusFV` fvs)
+ (gates `plusFV` getInstDeclGates new_decl)
+ ds