   #?(:cljs {:tag boolean})
   [env t]
   ;; don't use resolve-existing-var to avoid warnings
-  (when (and t (symbol? t))
-    (let [var (resolve-var env t)]
-      (or (:type var)
-          (-> var :info :type)
-          (:protocol-symbol var)
-          ;; need to hard code some cases because of
-          ;; forward declaration - David
-          ('#{cljs.core/PersistentHashMap
-              cljs.core/List} t)))))
+  (when (and (not (nil? t)) (symbol? t))
+    (let [var (resolve-var env t)
+          type (:type var)]
+      (if-not (nil? type)
+        type
+        (let [type (-> var :info :type)]
+          (if-not (nil? type)
+            type
+            (let [proto (:protocol-symbol var)]
+              (if-not (nil? proto)
+                proto
+                (get '#{cljs.core/PersistentHashMap cljs.core/List} t)))))))))
+
+(declare infer-tag)
+
+(def NOT_NATIVE '#{clj not-native})
+
+(def BOOLEAN_OR_SEQ '#{boolean seq})
+
+(defn infer-if [env e]
+  (let [{{:keys [op form]} :test} e
+        then-tag (infer-tag env (:then e))]
+    (if (and #?(:clj (= op :constant)
+                :cljs (keyword-identical? op :constant))
+             (not (nil? form))
+             (not (false? form)))
+      then-tag
+      (let [else-tag (infer-tag env (:else e))]
+        (cond
+          (or #?(:clj (= then-tag else-tag)
+                 :cljs (symbol-identical? then-tag else-tag))
+              #?(:clj (= else-tag IGNORE_SYM)
+                 :cljs (symbol-identical? else-tag IGNORE_SYM))) then-tag
+          #?(:clj (= then-tag IGNORE_SYM)
+             :cljs (symbol-identical? then-tag IGNORE_SYM)) else-tag
+          ;; TODO: temporary until we move not-native -> clj - David
+          (and (or (not (nil? (get NOT_NATIVE then-tag))) (type? env then-tag))
+               (or (not (nil? (get NOT_NATIVE else-tag))) (type? env else-tag)))
+          'clj
+          :else
+          (if (and (not (nil? (get BOOLEAN_OR_SEQ then-tag)))
+                   (not (nil? (get BOOLEAN_OR_SEQ else-tag))))
+            'seq
+            (let [then-tag (if #?(:clj (set? then-tag)
+                                  :cljs (cljs-set? then-tag))
+                             then-tag #{then-tag})
+                  else-tag (if #?(:clj (set? else-tag)
+                                  :cljs (cljs-set? else-tag))
+                             else-tag #{else-tag})]
+              (into then-tag else-tag))))))))
+
+(defn infer-invoke [env e]
+  (let [{info :info :as f} (:f e)
+        ret-tag (when-not (nil? (:fn-var info)) (:ret-tag info))]
+    (if-not (nil? ret-tag)
+      ret-tag
+      (let [ret-tag (infer-tag env (assoc (find-matching-method f (:args e)) :op :method))]
+        (if-not (nil? ret-tag)
+          ret-tag
+          ANY_SYM)))))
 
 (defn infer-tag
   "Given env, an analysis environment, and e, an AST node, return the inferred


#?(:cljs
   (def CLJS_CORE_SYM 'cljs.core))

#?(:cljs
   (defn ^boolean cljs-seq? [x]

#?(:cljs
   (def STRING_SYM 'string))

(def BOOLEAN_SYM 'boolean)

#?(:cljs
   (def JS_STAR_SYM 'js*))
