 
 ;; TODO: x must be a symbol, not an arbitrary expression
 (defmacro exists? [x]
-  (assert (core/symbol? x) "x is substituted twice")
   (bool-expr
-   (core/list 'js* "typeof ~{} !== 'undefined'"
-              (vary-meta x assoc :analyzer/allow-undefined true))))
+    (core/list 'js* "typeof ~{} !== 'undefined'"
+      (vary-meta x assoc :cljs.analyzer/no-resolve true))))
 
 (defmacro undefined? [x]
   (bool-expr (core/list 'js* "(void 0 === ~{})" x)))


(defn simple-test-expr? [env ast]
  (core/and
   (#{:var :invoke :const :host-field :host-call :js} (:op ast))
   ('#{boolean seq} (:tag ast))))

;; TODO: suppress warnings
(defmacro and
  "Evaluates exprs one at a time, from left to right. If a form
  returns logical false (nil or false), and returns that value and

        fields (vec (map #(with-meta % nil) fields))
        base-fields fields
        pr-open (core/str "#" (.getNamespace rname) "." (.getName rname) "{")
        fields (conj fields '__meta '__extmap (with-meta '__hash {:mutable true}))]
    (let [gs (gensym)
          ksym (gensym "k")
          impls (concat
                 impls
                 ['IRecord
                  'ICloneable
                  `(~'-clone [this#] (new ~tagname ~@fields))
                  'IHash
                  `(~'-hash [this#] (caching-hash this# ~'hash-imap ~'__hash))
                  'IEquiv
                  `(~'-equiv [this# other#]
                             (if (and other#
                                      (identical? (.-constructor this#)
                                                  (.-constructor other#))
                                      (equiv-map this# other#))
                               true
                               false))
                  'IMeta
                  `(~'-meta [this#] ~'__meta)
                  'IWithMeta
                  `(~'-with-meta [this# ~gs] (new ~tagname ~@(replace {'__meta gs} fields)))
                  'ILookup
                  `(~'-lookup [this# k#] (-lookup this# k# nil))
                  `(~'-lookup [this# ~ksym else#]
                              (case ~ksym
                                ~@(mapcat (fn [f] [(keyword f) f]) base-fields)
                                (get ~'__extmap ~ksym else#)))
                  'ICounted
                  `(~'-count [this#] (+ ~(count base-fields) (count ~'__extmap)))
                  'ICollection
                  `(~'-conj [this# entry#]
                            (if (vector? entry#)
                              (-assoc this# (-nth entry# 0) (-nth entry# 1))
                              (reduce -conj
                                      this#
                                      entry#)))
                  'IAssociative
                  `(~'-assoc [this# k# ~gs]
                             (condp keyword-identical? k#
                               ~@(mapcat (fn [fld]
                                           [(keyword fld) (list* `new tagname (replace {fld gs '__hash nil} fields))])
                                         base-fields)
                               (new ~tagname ~@(remove #{'__extmap '__hash} fields) (assoc ~'__extmap k# ~gs) nil)))
                  'IMap
                  `(~'-dissoc [this# k#] (if (contains? #{~@(map keyword base-fields)} k#)
                                           (dissoc (with-meta (into {} this#) ~'__meta) k#)
                                           (new ~tagname ~@(remove #{'__extmap '__hash} fields)
                                                (not-empty (dissoc ~'__extmap k#))
                                                nil)))
                  'ISeqable
                  `(~'-seq [this#] (seq (concat [~@(map #(core/list `vector (keyword %) %) base-fields)]
                                                ~'__extmap)))

                  'IPrintWithWriter
                  `(~'-pr-writer [this# writer# opts#]
                                 (let [pr-pair# (fn [keyval#] (pr-sequential-writer writer# pr-writer "" " " "" opts# keyval#))]
                                   (pr-sequential-writer
                                    writer# pr-pair# ~pr-open ", " "}" opts#
                                    (concat [~@(map #(core/list `vector (keyword %) %) base-fields)]
                                            ~'__extmap))))
                  ])
          [fpps pmasks] (prepare-protocol-masks env impls)
          protocols (collect-protocols impls env)
          tagname (vary-meta tagname assoc
                    :protocols protocols
                    :skip-protocol-flag fpps)]
      `(do
         (~'defrecord* ~tagname ~hinted-fields ~pmasks
           (extend-type ~tagname ~@(dt->et tagname impls fields true)))))))

(defn- build-map-factory [rsym rname fields]
  (let [fn-name (with-meta (symbol (core/str 'map-> rsym))
                  (assoc (meta rsym) :factory :map))
        ms (gensym)
        ks (map keyword fields)
        getters (map (fn [k] `(~k ~ms)) ks)]
