tree-sitter / tree-sitter-typescript

TypeScript grammar for tree-sitter
MIT License
341 stars 104 forks source link

Wrong Highlight When a Union Type Inside a Generic Starts With null #164

Closed EduardoAraujoB closed 2 years ago

EduardoAraujoB commented 3 years ago

Problem

so I've found this bug in the highlighting image as you can see, if I start the generic with a null then this error happens, a good question also is if null should be highlighted as a reserved keyword, as a type, or as a value (in my color scheme types are blue , values are purple and reserved keywords are pink)

mjambon commented 3 years ago

Fascinating! Thanks for reporting this.

Case 1 (wrong):

$ tree-sitter parse <(echo 'const [a, b] = c<null|string>(null);')
(program [0, 0] - [1, 0]
  (lexical_declaration [0, 0] - [0, 36]
    (variable_declarator [0, 6] - [0, 35]
      name: (array_pattern [0, 6] - [0, 12]
        (identifier [0, 7] - [0, 8])
        (identifier [0, 10] - [0, 11]))
      value: (binary_expression [0, 15] - [0, 35]
        left: (binary_expression [0, 15] - [0, 21]
          left: (identifier [0, 15] - [0, 16])
          right: (null [0, 17] - [0, 21]))
        right: (binary_expression [0, 22] - [0, 35]
          left: (identifier [0, 22] - [0, 28])
          right: (parenthesized_expression [0, 29] - [0, 35]
            (null [0, 30] - [0, 34])))))))

Case 2 (correct):

$ tree-sitter parse <(echo 'const [a, b] = c<string|null>(null);')
(program [0, 0] - [1, 0]
  (lexical_declaration [0, 0] - [0, 36]
    (variable_declarator [0, 6] - [0, 35]
      name: (array_pattern [0, 6] - [0, 12]
        (identifier [0, 7] - [0, 8])
        (identifier [0, 10] - [0, 11]))
      value: (call_expression [0, 15] - [0, 35]
        function: (identifier [0, 15] - [0, 16])
        type_arguments: (type_arguments [0, 16] - [0, 29]
          (union_type [0, 17] - [0, 28]
            (predefined_type [0, 17] - [0, 23])
            (type_identifier [0, 24] - [0, 28])))
        arguments: (arguments [0, 29] - [0, 35]
          (null [0, 30] - [0, 34]))))))

Case 1b - With further simplication, we get a parsing error (null | d):

$ tree-sitter parse <(echo 'const [a, b] = c<null | d>()')
(program [0, 0] - [1, 0]
  (ERROR [0, 0] - [0, 28]
    (array_pattern [0, 6] - [0, 12]
      (identifier [0, 7] - [0, 8])
      (identifier [0, 10] - [0, 11]))
    (binary_expression [0, 15] - [0, 21]
      left: (identifier [0, 15] - [0, 16])
      right: (null [0, 17] - [0, 21]))
    (identifier [0, 24] - [0, 25])
    (formal_parameters [0, 26] - [0, 28])))
/dev/fd/63  0 ms    (ERROR [0, 0] - [0, 28])

Case 2b - With d | null instead of null | d, the result is still correct (like in Case 2):

$ tree-sitter parse <(echo 'const [a, b] = c<d | null>()')
(program [0, 0] - [1, 0]
  (lexical_declaration [0, 0] - [0, 28]
    (variable_declarator [0, 6] - [0, 28]
      name: (array_pattern [0, 6] - [0, 12]
        (identifier [0, 7] - [0, 8])
        (identifier [0, 10] - [0, 11]))
      value: (call_expression [0, 15] - [0, 28]
        function: (identifier [0, 15] - [0, 16])
        type_arguments: (type_arguments [0, 16] - [0, 26]
          (union_type [0, 17] - [0, 25]
            (type_identifier [0, 17] - [0, 18])
            (type_identifier [0, 21] - [0, 25])))
        arguments: (arguments [0, 26] - [0, 28])))))
mjambon commented 3 years ago

Even simpler repro:

$ tree-sitter parse <(echo 'a<null|b>()')
(program [0, 0] - [1, 0]
  (ERROR [0, 0] - [0, 11]
    (binary_expression [0, 0] - [0, 6]
      left: (identifier [0, 0] - [0, 1])
      right: (null [0, 2] - [0, 6]))
    (identifier [0, 7] - [0, 8])
    (formal_parameters [0, 9] - [0, 11])))
/dev/fd/63  0 ms    (ERROR [0, 0] - [0, 11])
$ tree-sitter parse <(echo 'a<b|null>()')
(program [0, 0] - [1, 0]
  (expression_statement [0, 0] - [0, 11]
    (call_expression [0, 0] - [0, 11]
      function: (identifier [0, 0] - [0, 1])
      type_arguments: (type_arguments [0, 1] - [0, 9]
        (union_type [0, 2] - [0, 8]
          (type_identifier [0, 2] - [0, 3])
          (type_identifier [0, 4] - [0, 8])))
      arguments: (arguments [0, 9] - [0, 11]))))
mjambon commented 3 years ago

I'm not going to work on this right now. If someone wants to give a shot, go for it.

EduardoAraujoB commented 3 years ago

thanks for reproducing the problem, I'm still a newbie on vim/nvim so I have no idea about how treesitter works and how to write a solution for that

resolritter commented 2 years ago

This seems to happen because predefined_type or literal_type are missing null (and undefined as well)

https://github.com/tree-sitter/tree-sitter-typescript/blob/74a2748896434c13cac7697c4d182b43ec170d30/common/define-grammar.js#L682-L688

https://github.com/tree-sitter/tree-sitter-typescript/blob/74a2748896434c13cac7697c4d182b43ec170d30/common/define-grammar.js#L703-L710

https://github.com/tree-sitter/tree-sitter-typescript/pull/184