   isComplex: ->
     @name.isComplex()
 
-  # Finds the name or names of a `Param`; useful for detecting duplicates.
-  # In a sense, a destructured parameter represents multiple JS parameters,
-  # thus this method returns an `Array` of names.
-  # Reserved words used as param names, as well as the Object and Array
-  # literals used for destructured params, get a compiler generated name
-  # during the `Code` compilation step, so this is necessarily an incomplete
-  # list of a parameter's names.
-  names: (name = @name)->
+  # Iterates the name or names of a `Param`.
+  # In a sense, a destructured parameter represents multiple JS parameters. This
+  # method allows to iterate them all.
+  # The `iterator` function will be called as `iterator(name, node)` where
+  # `name` is the name of the parameter and `node` is the AST node corresponding
+  # to that name.
+  eachName: (iterator, name = @name)->
     atParam = (obj) ->
-      {value} = obj.properties[0].name
-      return if value.reserved then [] else [value]
+      node = obj.properties[0].name
+      iterator node.value, node unless node.value.reserved
     # * simple literals `foo`
-    return [name.value] if name instanceof Literal
+    return iterator name.value, name if name instanceof Literal
     # * at-params `@foo`
-    return atParam(name) if name instanceof Value
-    names = []
+    return atParam name if name instanceof Value
     for obj in name.objects
       # * assignments within destructured parameters `{foo:bar}`
       if obj instanceof Assign
-        names.push @names(obj.value.unwrap())...
+        @eachName iterator, obj.value.unwrap()
       # * splats within destructured parameters `[xs...]`
       else if obj instanceof Splat
-        names.push obj.name.unwrap().value
+        node = obj.name.unwrap()
+        iterator node.value, node
       else if obj instanceof Value
         # * destructured parameters within destructured parameters `[{a}]`
         if obj.isArray() or obj.isObject()
-          names.push @names(obj.base)...
+          @eachName iterator, obj.base
         # * at-params within destructured parameters `{@foo}`
         else if obj.this
-          names.push atParam(obj)...
+          atParam obj
         # * simple destructured parameters {foo}
-        else names.push obj.base.value
+        else iterator obj.base.value, obj.base
       else
         obj.error "illegal parameter #{obj.compile()}"
-    names
+    return
 
 #### Splat
 

    @body.expressions.unshift exprs... if exprs.length
    o.scope.parameter params[i] = p.compile o for p, i in params
    uniqs = []
    for name in @paramNames()
      # TODO Neither @paramNames nor `name` are proper AST nodes from which to
      # throw the error. Using `@` as the context for this error is too broad.
      # We should use the Param corresponding to `name` instead.
      @error "multiple parameters named '#{name}'" if name in uniqs
      uniqs.push name
    @body.makeReturn() unless wasEmpty or @noReturn
    if @bound

    delete o.isExistentialEquals
    params = []
    exprs  = []
    @eachParamName (name) -> # this step must be performed before the others
      unless o.scope.check name then o.scope.parameter name
    for param in @params when param.splat
      for {name: p} in @params
