 
         visitCallExpression: (exp) ->
                 super
-                # unify the callee type with argtypes
-                # this is the complicated bit, since information can travel in both directions:
-                #   1. if the function body (and therefore the function type) has an undefined/any type
+                # If we have a type for the callee in our environment,
+                # try to look up a matching signature for
+                # parameters/arguments.
+                # 
+                # If we find one, then use the return type of that
+                # signature as exp's inferred type.
+                #
+                # If we don't find one, we need to re-traverse the
+                # function using the inferred argument types to see
+                # what the return type could be.
+                exp
+
+        visitFunctionBody: (exp) ->
+                @function_stack.push exp
+                exp.body = @visit exp.body
+                @function_stack.pop()
                 exp
 
         visitFunctionExpression: (exp) ->
-                exp
-
-        visitReturn: (n) ->
+                @visitFunctionBody exp
+
+        visitFunctionDeclaration: (exp) ->
+                @visitFunctionBody exp
+
+        visitReturn: (exp) ->
+                super
                 debug.log "visitReturn"
-                #if @iifeStack.top.iife_rv?
+                @assignType @function_stack.top, new FunctionType (@getType exp.argument), []
+                exp
 
         visitBinaryExpression: (exp) ->
                 super
                 switch exp.operator
                         when "+"
-                                if StringType.is(@getType exp.left) or StringType.is(@getType exp.right)
+                                if StringType.is @getType exp.left
                                         @assignType exp, new StringType
+                                        @setDesiredType exp.right, new StringType
+                                else if StringType.is @getType exp.right
+                                        @assignType exp, new StringType
+                                        @setDesiredType exp.left, new StringType
                                 else
                                         @assignType exp, new NumberType
+                                        @setDesiredType exp.left, new NumberType
+                                        @setDesiredType exp.right, new NumberType
                         when "-"
-                                # FIXME we need a way to push a the
-                                # NumberType down to left/right so
-                                # the compiler can possibly optimize
-                                # them.
                                 @assignType exp, new NumberType
+                                @setDesiredType exp.left, new NumberType
+                                @setDesiredType exp.right, new NumberType
                         when "*"
-                                # FIXME we need a way to push a the
-                                # NumberType down to left/right so
-                                # the compiler can possibly optimize
-                                # them.
                                 @assignType exp, new NumberType
+                                @setDesiredType exp.left, new NumberType
+                                @setDesiredType exp.right, new NumberType
                         when "/"
-                                # FIXME we need a way to push a the
-                                # NumberType down to left/right so
-                                # the compiler can possibly optimize
-                                # them.
                                 @assignType exp, new NumberType
+                                @setDesiredType exp.left, new NumberType
+                                @setDesiredType exp.right, new NumberType
                 exp
         visitVariableDeclarator: (exp) ->
                 super

                                enumerable: true
                                configurable: true
                                writable: true
                        console.warn "assigned type #{ast._ejs_inferredtype}"
                else if ast._ejs_inferredtype instanceof MultiType
                        # The ast node is already polymorphic, add the new type to the bunch
                        ast._ejs_inferredtype.addType ty


{ Stack } = require 'stack'
{ Set } = require 'set'
{ TreeVisitor } = require 'nodevisitor'

echo_util = require 'echo-util'

