   lookupInMap compiledModules, name
 
 
-compileTopLevel = (source, moduleName = '@unnamed') ->
-  required = newSetWith 'Prelude' # TODO: Hardcoded prelude dependency
-  if (not lookupCompiledModule 'Prelude') and moduleName isnt 'Prelude'
-    request: 'Prelude'
-  else
-    directRequires = subtractSets required, (newSetWith moduleName)
-    replaceOrAddToMap moduleGraph, moduleName, requires: directRequires
-    toInject = collectRequiresFor moduleName
-    ctx = injectedContext toInject
-    {js, ast} = compileCtxAstToJs topLevel, ctx, (astFromSource "(#{source})", -1, -1)
-    (finalizeTypes ctx, ast)
-    replaceOrAddToMap compiledModules, moduleName,
-      declared: (subtractContexts ctx, (injectedContext toInject)) # must recompute because ctx is mutated
-      js: js
+compileTopLevel = (source, moduleName = '@unnamed', requiredMap = newMap()) ->
+  addToMap requiredMap, 'Prelude', yes # TODO: Hardcoded prelude dependency
+  removeFromMap requiredMap, moduleName
+  for requiredModuleName of values requiredMap
+    if not lookupCompiledModule requiredModuleName
+      return request: requiredModuleName
+  replaceOrAddToMap moduleGraph, moduleName, requires: requiredMap
+  toInject = collectRequiresFor moduleName
+  ctx = injectedContext toInject
+  {request, ast, ir, js} = compileCtxAstToJs topLevel, ctx, (astFromSource "(#{source})", -1, -1)
+  if request
+    if not allInjected request, requiredMap
+      return compileTopLevel source, moduleName, request
+    else
+      {js} = compileCtxIrToJs ctx, ir
+  (finalizeTypes ctx, ast)
+  replaceOrAddToMap compiledModules, moduleName,
+    declared: (subtractContexts ctx, (injectedContext toInject)) # must recompute because ctx is mutated
     js: js
-    ast: ast
-    types: typeEnumaration ctx
-    errors: checkTypes ctx
+  js: js
+  ast: ast
+  types: typeEnumaration ctx
+  errors: checkTypes ctx
 
 compileExpression = (source, moduleName = '@unnamed') ->
   ast = (astFromSource "(#{source})", -1, -1)


finalizeTypes = (ctx, ast) ->
  visitExpressions ast, (expression) ->
    if expression?.label is 'name' and (type = ctx.finalType expression.symbol)
      expression.tea = type
    else if expression.tea
      expression.tea = substitute ctx.substitution, expression.tea

#     content = mainCache.concat(varDecls, compiledCases.join '').join '\n'
#     """(function(){
#       #{content} else {throw new Error('match failed to match');}}())"""
#   'list': (items...) ->
#     "$listize(#{compileList items})"

