-
Notifications
You must be signed in to change notification settings - Fork 24
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 for nested expressions - 1st stage #177
Conversation
e9cbc88
to
f8da050
Compare
This includes all existing constraints except for LiteralValue & the top level meta-constraint ExprConstraints which will be handled in separate commits.
Due to interface incompatibility in case of Copy() return value and the same type name, this is a necessary middle step towards phasing out the "old" constraint representation in favour of the new one.
f8da050
to
d58d9dc
Compare
d58d9dc
to
c219ee4
Compare
Previously the tests were testing internal API, this change makes the tests less brittle and easier to reuse when implementation changes.
3eec29c
to
812d0f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! I believe the changes will lead to a much more readable and easier extendable codebase. I've just found two minor things.
Regarding your questions:
Should decoder.Expression.ReferenceOrigins() accept context as the first argument, like the other methods?
I'm in favor as it will unify the interface, and we might need it anyway.
Should we also use that context to pass through "allowSelfRefs" somehow?
Maybe. But I would leave this open until we get to the implementation.
Should decoder.PathDecoder.CollectReferenceOrigins() also accept context, like other similar methods?
I'm against it for now as I couldn't find a good use-case yet.
Should decoder.Expression.ReferenceTargets() accept context as the first argument, like the other methods?
I'm in favor as it will unify the interface, and we might need it anyway.
Should decoder.PathDecoder.CollectReferenceTargets() also accept context, like other similar methods?
I'm against it for now as I couldn't find a good use-case yet.
Should we be updating tests, or copying them - i.e. should the old logic remain covered by tests in the meantime?
I'm in favor of copying tests and removing the old tests together with the old implementation. That should ensure we keep everything unbroken.
This is to make it easier for introducing new tests later, which are expected to be mostly copies of the existing tests, with Expr -> Constraint appropriate changes.
I believe I have addressed all concerns + I also decided to change the PTAL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! LGTM 👍
Motivations
One of the common constraints in use is the following:
which expresses either a reference of string type (
attr = var.mystring
), or literal string (attr = "foo"
). This has a few challenges:To address the mentioned challenges, it is proposed to refactor expression constraints to eventually enable the same constraint to be expressed this way:
Name Change: Expr -> Constraint
The new name reflects that constraints in HCL will generally always apply to expressions (certainly in the context of an attribute), and should better convey the purpose of the field and make it easier to "say out loud" while typing.
Singular Constraint
It is proposed to optimize for singular constraints as that is the common case, and allow multiple constraints via a special constraint type. Hence the top level type (
Expr / Constraint
) will no longer be a slice, butConstraint
interface.New Constraints
Two new constraints are proposed for addition, of which only the first one is part of this PR:
OneOf
- equivalent to the existing defaultExprConstraints
, to be also used as a temporary replacement untilAnyExpression
is implementedAnyExpression{OfType: cty.Type}
- to represent any expression which is expected to evaluate to a given typeConvenience Arguments
By using different name, we also gain the benefit of being able to work on this piece by piece, and not having to implement all expressions at the same time and face compilation errors. Adding
Constraint
is effectively a feature toggle.Implementation Notes
This is the first step towards implementing hashicorp/terraform-ls#496
The main aim here is to agree on two [new] interfaces,
schema.Constraint
anddecoder.Expression
:The PR intentionally leaves out most of the implementation of both interfaces for all expression/constraint types, as the diff is already quite large. It does however implement the simple methods like
Copy()
andFriendlyName()
forschema.Constraint
s as these were mostly copy-pasted from the existing implementations.There is a WIP staging ground for some implementations in https://github.com/hashicorp/hcl-lang/compare/f-expressions-staging-ground
The idea is that we can then raise separate PRs, where each focuses on each individual constraint/expression, or even different aspect of it (completion / hover / semantic tokens / reference origins / reference targets).
This PR is also leaving out addition of the planned new constraint,
schema.AnyExpressionOfType
or similar, which would effectively enable support for nested expressions. It should make adding such a constraint much easier/cleaner however.Open Questions
Shoulddecoder.Expression.ReferenceOrigins()
accept context as the first argument, like the other methods?decoder.PathDecoder.CollectReferenceOrigins()
also accept context, like other similar methods?Shoulddecoder.Expression.ReferenceTargets()
accept context as the first argument, like the other methods?decoder.PathDecoder.CollectReferenceTargets()
also accept context, like other similar methods?Conform()
be implemented for constraints other thanLiteralType
andOneOf
?Object
? How should optional attributes be treated?Should we be updating tests, or copying them - i.e. should the old logic remain covered by tests in the meantime?