     (while (>= (go-paren-level) orig-level)
       (skip-chars-forward "^}")
       (forward-char))))
+
+(defun go--find-enclosing-parentheses (position)
+  "Return points of outermost '(' and ')' surrounding POSITION if
+such parentheses exist.
+
+If outermost '(' exists but ')' does not, it returns the next blank
+line or end-of-buffer position instead of the position of the closing
+parenthesis.
+
+If the starting parenthesis is not found, it returns (POSITION
+POSITION).
+"
+  (save-excursion
+    (let (beg end)
+      (goto-char position)
+      (while (> (go-paren-level) 0)
+        (re-search-backward "[(\\[{]" nil t)
+        (when (looking-at "(")
+          (setq beg (point))))
+      (if (null beg)
+          (list position position)
+        (goto-char position)
+        (while (and (> (go-paren-level) 0)
+                    (search-forward ")" nil t)))
+        (when (> (go-paren-level) 0)
+          (unless (re-search-forward "^[[:space:]]*$" nil t)
+            (goto-char (point-max))))
+        (list beg (point))))))
+
+(defun go--search-next-comma (end)
+  "Search forward from point for a comma whose nesting level is
+the same as point. If it reaches the end of line or a closing
+parenthesis before a comma, it stops at it."
+  (let ((orig-level (go-paren-level)))
+    (while (and (< (point) end)
+                (or (looking-at "[^,)\n]")
+                    (> (go-paren-level) orig-level)))
+      (forward-char))
+    (when (and (looking-at ",")
+               (< (point) (1- end)))
+      (forward-char))))
+
+(defun go--looking-at-keyword ()
+  (and (looking-at (concat "\\(" go-identifier-regexp "\\)"))
+       (member (match-string 1) go-mode-keywords)))
+
+(defun go--match-func (end)
+  "Search for identifiers used as type names from a function
+parameter list, and set the identifier positions as the results
+of last search. Return t if search succeeded."
+  (when (re-search-forward (go--regexp-enclose-in-symbol "func") end t)
+    (let ((regions (go--match-func-type-names end)))
+      (if (null regions)
+          ;; Nothing to highlight. This can happen if the current func
+          ;; is "func()". Try next one.
+          (go--match-func end)
+        ;; There are something to highlight. Set those positions as
+        ;; last search results.
+        (setq regions (go--filter-match-data regions end))
+        (when regions
+          (set-match-data (go--make-match-data regions))
+          t)))))
+
+(defun go--match-func-type-names (end)
+  (cond
+   ;; Function declaration (e.g. "func foo(")
+   ((looking-at (concat "[[:space:]\n]*" go-identifier-regexp "[[:space:]\n]*("))
+    (goto-char (match-end 0))
+    (nconc (go--match-parameter-list end)
+           (go--match-function-result end)))
+   ;; Method declaration, function literal, or function type
+   ((looking-at "[[:space:]]*(")
+    (goto-char (match-end 0))
+    (let ((regions (go--match-parameter-list end)))
+      ;; Method declaration (e.g. "func (x y) foo(")
+      (when (looking-at (concat "[[:space:]]*" go-identifier-regexp "[[:space:]\n]*("))
+        (goto-char (match-end 0))
+        (setq regions (nconc regions (go--match-parameter-list end))))
+      (nconc regions (go--match-function-result end))))))
+
+(defun go--parameter-list-type (end)
+  "Return 'present if the parameter list has names, or 'absent if
+not, assuming point is at the beginning of a parameter list, just
+after '('."
+  (save-excursion
+    (skip-chars-forward "[:space:]\n" end)
+    (cond ((> (point) end)
+           nil)
+          ((looking-at (concat go-identifier-regexp "[[:space:]\n]*,"))
+           (goto-char (match-end 0))
+           (go--parameter-list-type end))
+          ((or (looking-at go-qualified-identifier-regexp)
+               (looking-at (concat go-type-name-no-prefix-regexp "[[:space:]\n]*\\(?:)\\|\\'\\)"))
+               (go--looking-at-keyword)
+               (looking-at "[*\\[]\\|\\.\\.\\.\\|\\'"))
+           'absent)
+          (t 'present))))
+
+(defconst go--opt-dotdotdot-regexp "\\(?:\\.\\.\\.\\)?")
+(defconst go--parameter-type-regexp
+  (concat go--opt-dotdotdot-regexp "[[:space:]*\n]*\\(" go-type-name-no-prefix-regexp "\\)[[:space:]\n]*\\([,)]\\|\\'\\)"))
+(defconst go--func-type-in-parameter-list-regexp
+  (concat go--opt-dotdotdot-regexp "[[:space:]*\n]*\\(" (go--regexp-enclose-in-symbol "func") "\\)"))
+
+(defun go--match-parameters-common (identifier-regexp end)
+  (let ((acc ())
+        (start -1))
+    (while (progn (skip-chars-forward "[:space:]\n" end)
+                  (and (not (looking-at "\\(?:)\\|\\'\\)"))
+                       (< start (point))
+                       (<= (point) end)))
+      (setq start (point))
+      (cond
+       ((looking-at (concat identifier-regexp go--parameter-type-regexp))
+        (setq acc (nconc acc (list (match-beginning 1) (match-end 1))))
+        (goto-char (match-beginning 2)))
+       ((looking-at (concat identifier-regexp go--func-type-in-parameter-list-regexp))
+        (goto-char (match-beginning 1))
+        (setq acc (nconc acc (go--match-func-type-names end)))
+        (go--search-next-comma end))
+       (t
+        (go--search-next-comma end))))
+    (when (and (looking-at ")")
+               (< (point) end))
+      (forward-char))
+    acc))
+
+(defun go--match-parameters-with-identifier-list (end)
+  (go--match-parameters-common
+   (concat go-identifier-regexp "[[:space:]\n]+")
+   end))
+
+(defun go--match-parameters-without-identifier-list (end)
+  (go--match-parameters-common "" end))
+
+(defun go--filter-match-data (regions end)
+  "Remove points from regions if they are beyond end. Regions are
+a list whose size is multiple of 2. Element 2n is beginning of a
+region and 2n+1 is end of it.
+
+This function is used to make sure we don't override end point
+that font-lock-mode gave to us."
+  (when regions
+    (let* ((vec (vconcat regions))
+           (i 0)
+           (len (length vec)))
+      (while (and (< i len)
+                  (<= (nth i regions) end)
+                  (<= (nth (1+ i) regions) end))
+        (setq i (+ i 2)))
+      (cond ((= i len)
+             regions)
+            ((zerop i)
+             nil)
+            (t
+             (setcdr (nth i regions) nil)
+             regions)))))
+
+(defun go--make-match-data (regions)
+  (let ((deficit (- (* 2 go--font-lock-func-param-num-groups)
+                    (length regions))))
+    (when (> deficit 0)
+      (let ((last (car (last regions))))
+        (setq regions (nconc regions (make-list deficit last))))))
+  `(,(car regions) ,@(last regions) ,@regions))
+
+(defun go--match-parameter-list (end)
+  "Returns a list of identifier positions that are used as type
+names in a function parameter list, assuming point is at the
+beginning of a parameter list. Returns nil if the text after
+point does not look like a parameter list.
+
+Set point to end of closing parenthesis on success.
+
+In Go, the names must either all be present or all be absent
+within a list of parameters.
+
+Parsing a parameter list is a little bit complicated because we
+have to scan through the parameter list to determine whether or
+not the list has names. Until a type name is found or reaching
+end of a parameter list, we are not sure which form the parameter
+list is.
+
+For example, X and Y are type names in a parameter list \"(X,
+Y)\" but are parameter names in \"(X, Y int)\". We cannot say if
+X is a type name until we see int after Y.
+
+Note that even \"(int, float T)\" is a valid parameter
+list. Builtin type names are not reserved words. In this example,
+int and float are parameter names and only T is a type name.
+
+In this function, we first scan the parameter list to see if the
+list has names, and then handle it accordingly."
+  (let ((name (go--parameter-list-type end)))
+    (cond ((eq name 'present)
+           (go--match-parameters-with-identifier-list end))
+          ((eq name 'absent)
+           (go--match-parameters-without-identifier-list end))
+          (t nil))))
+
+(defun go--match-function-result (end)
+  "Returns a list of identifier positions that are used as type
+names in a function result, assuming point is at the beginning of
+a result.
+
+Function result is a unparenthesized type or a parameter list."
+  (cond ((and (looking-at (concat "[[:space:]*]*\\(" go-type-name-no-prefix-regexp "\\)"))
+              (not (member (match-string 1) go-mode-keywords)))
+         (list (match-beginning 1) (match-end 1)))
+        ((looking-at "[[:space:]]*(")
+         (goto-char (match-end 0))
+         (go--match-parameter-list end))
+        (t nil)))
 
 ;;;###autoload
 (define-derived-mode go-mode prog-mode "Go"

     (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+\\([^[:space:]]+\\)") 1 font-lock-type-face) ;; types
     (,(concat (go--regexp-enclose-in-symbol "type") "[[:space:]]+" go-identifier-regexp "[[:space:]]*" go-type-name-regexp) 1 font-lock-type-face) ;; types
     (,(concat "[^[:word:][:multibyte:]]\\[\\([[:digit:]]+\\|\\.\\.\\.\\)?\\]" go-type-name-regexp) 2 font-lock-type-face) ;; Arrays/slices
     (,(concat "\\(" go-identifier-regexp "\\)" "{") 1 font-lock-type-face)
     (,(concat (go--regexp-enclose-in-symbol "map") "\\[[^]]+\\]" go-type-name-regexp) 1 font-lock-type-face) ;; map value type
     (,(concat (go--regexp-enclose-in-symbol "map") "\\[" go-type-name-regexp) 1 font-lock-type-face) ;; map key type
     (,(concat (go--regexp-enclose-in-symbol "chan") "[[:space:]]*\\(?:<-[[:space:]]*\\)?" go-type-name-regexp) 1 font-lock-type-face) ;; channel type
     (,(concat (go--regexp-enclose-in-symbol "\\(?:new\\|make\\)") "\\(?:[[:space:]]\\|)\\)*(" go-type-name-regexp) 1 font-lock-type-face) ;; new/make type
     ;; TODO do we actually need this one or isn't it just a function call?
     (,(concat "\\.\\s *(" go-type-name-regexp) 1 font-lock-type-face) ;; Type conversion
     (,(concat (go--regexp-enclose-in-symbol "func") "[[:space:]]+(" go-identifier-regexp "[[:space:]]+" go-type-name-regexp ")") 1 font-lock-type-face) ;; Method receiver
     (,(concat (go--regexp-enclose-in-symbol "func") "[[:space:]]+(" go-type-name-regexp ")") 1 font-lock-type-face) ;; Method receiver without variable name
     ;; Like the original go-mode this also marks compound literal
     ;; fields. There, it was marked as to fix, but I grew quite
     ;; accustomed to it, so it'll stay for now.

  "All keywords in the Go language.  Used for font locking.")

(defconst go-constants '("nil" "true" "false" "iota"))
(defconst go-type-name-regexp (concat "\\(?:[*(]\\)*\\(\\(?:" go-identifier-regexp "\\.\\)?" go-identifier-regexp "\\)"))

;; Maximum number of identifiers that can be highlighted as type names
;; in one function type/declaration.
(defconst go--font-lock-func-param-num-groups 16)

(defvar go-dangling-cache)
(defvar go-godoc-history nil)
