Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support operator expressions (+, -, !=, !...) and parentheses #529

Closed
radeksimko opened this issue May 20, 2021 · 6 comments · Fixed by hashicorp/hcl-lang#366
Closed

Support operator expressions (+, -, !=, !...) and parentheses #529

radeksimko opened this issue May 20, 2021 · 6 comments · Fixed by hashicorp/hcl-lang#366
Assignees

Comments

@radeksimko
Copy link
Member

radeksimko commented May 20, 2021

Background

Terraform supports a number of operators, which can be combined with other expressions, for example:

  • -42
  • !var.bool
  • 1 + 2 * 3
  • (1 + 2) * 3
  • var.number * 2

Language server currently doesn't support any of these operators, which in practice means that e.g.

  • no completion is provided on either side of binary operator (e.g. before or after +), nor near unary operator (e.g. after !)
  • no data is provided on hover over any expression on any side of an operator
  • no expressions are highlighted as tokens when part of operator expression - e.g. var.bool is not reported as traversal if there is ! in the front

Proposal

Completion

TODO

  • completion for number references and functions is provided on the RHS from -
  • completion for bool references and functions is provided on the RHS from !

Hover

TODO

  • hovering over negative number is equivalent to hover over a number
  • hovering over negated bool is equivalent to hover over a bool

Semantic Tokens

TODO

  • negative number is highlighted as number
  • negated bool is highlighted as bool
@radeksimko radeksimko changed the title Support binary (+, -, !=...) and unary (e.g. !) operator expressions Support operator expressions (+, -, !=, !...) and parentheses May 20, 2021
@xiehan xiehan added this to the v0.31.0 milestone Oct 27, 2022
@xiehan
Copy link
Member

xiehan commented Jan 5, 2023

Need to research what happens if you e.g. try to + a string, and where that logic lives

@radeksimko
Copy link
Member Author

radeksimko commented Jan 5, 2023

@apparentlymart
Copy link

I think the discussion above is asking how the Terraform language treats addition of non-numeric types, which I can answer!

The direct answer to that question is: Terraform tries to convert both operands to numbers in the same way that the tonumber function would, and then if successful adds the results together. If unsuccessful, Terraform returns an error.

> "1" + "3"
4
> "1" + "elephant"
╷
│ Error: Invalid operand
│ 
│   on <console-input> line 1:
│   (source code not available)
│ 
│ Unsuitable value for right operand: a number is required.
╵

A more general answer:

In HCL, most of the operators are specified to take operands of a particular type only. (== and != are the only exceptions; they apply to all types.)

As a general rule, the operators will try to convert their operands to the prescribed type and then act on the result, just as we saw for numbers above.

For example, && expects boolean operands, and so it implicitly converts to boolean, like tobool, and returns an error only if the conversion fails.

> "true" && "true"
true
> "true" && "elephant"
╷
│ Error: Invalid operand
│ 
│   on <console-input> line 1:
│   (source code not available)
│ 
│ Unsuitable value for right operand: a bool is required.
╵

The operators are actually implemented as just function calls with a special syntax, so the automatic type conversion behavior is the same as for function calls where the underlying function has parameters with type constraints.

Those functions are not exposed as normal named functions so the built-in operators are the only way to access them, but their implementations are written using the same approach as for the more conventional functions accessible using the function call syntax. Because of that, it might be possible to reuse some existing logic for providing completion for function arguments, although of course only for semantics and not for syntax since the syntax is different.

The functions themselves actually belong to my underlying cty library rather than to HCL itself. The Impl field on each of the Operation objects in the code Radek linked to refers to the function underlying each of the supported operators. The mapping from the syntax to the Operation objects is not exported in the HCL API, but the objects themselves are exported so terraform-ls could in principle refer to them to avoid hard-coding anything except the syntax-level handling.

@radeksimko radeksimko self-assigned this Sep 21, 2023
@radeksimko
Copy link
Member Author

@apparentlymart Thanks, that is helpful, although in the context of LS we more often deal with situations where we either lack values or we just cannot or do not evaluate it (since we'd effectively have to re-implement pretty much the whole DAG inside LS, which is a problem of its own), so we are more often left with just types.

With that in mind, while we could be "smarter" and could avoid e.g. completing var.foo below, we may have to apply a more cautious approach and complete it.

variable "foo" {
  default = "not-a-number"
}
locals {
  baz = 42 + var. # HERE
}

This will be fine for smaller configurations but it will get less helpful with larger ones where the user will have to spend more time either typing or scrolling.

I am hopeful that we can at least start filtering the simplest of cases, e.g. variable defaults, which are resolvable without further context (i.e. without DAG) but I am not too optimistic about the other ones.

Either way I admit this (convertibility based on values) is not a new problem - we face it when filtering references and functions, whether or not operators are involved.

@radeksimko
Copy link
Member Author

Support for unary and binary operators was added in hashicorp/hcl-lang#320 but parentheses (i.e. ParenthesesExpr) are yet to be implemented.

Copy link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 22, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants