Repository: apollographql/apollo-rs
Pull request #777 (2023-12-10 11:15:10)

fix(parser): emit syntax errors for variables in const values
https://github.com/apollographql/apollo-rs/issues/538 tracks making such invalid values impossible to represent in Rust data structures, so that users matching on the enum values don’t need to handle impossible cases. But that isn’t needed to make the parser emit syntax errors.


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index c10a54e..19b06c9 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -6,7 +6,7 @@ version: 2.1
 orbs:
   rust: circleci/rust@1.6.0
   gh: circleci/github-cli@2.2.0
-  secops: apollo/circleci-secops-orb@2.0.3
+  secops: apollo/circleci-secops-orb@2.0.4
 
 # We run jobs on the following platforms: linux, macos and windows.
 # These are their specifications:
diff --git a/crates/apollo-compiler/CHANGELOG.md b/crates/apollo-compiler/CHANGELOG.md
index 2af77a7..bb3909b 100644
--- a/crates/apollo-compiler/CHANGELOG.md
+++ b/crates/apollo-compiler/CHANGELOG.md
@@ -21,14 +21,18 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 
 ## Features
 - **Add `NodeStr::from(Name)` - [goto-bus-stop], [pull/773]**
+- **Convenience accessors for `ast::Selection` enum - [SimonSapin], [pull/777]**
+  `as_field`, `as_inline_fragment`, and `as_fragment_spread`; all returning `Option<&_>`.
 
 ## Fixes
 - **Fix serializing single-line strings with leading whitespace - [goto-bus-stop], [pull/774]**
   Previously, the leading whitespace would get lost.
 
 [goto-bus-stop]: https://github.com/goto-bus-stop]
+[SimonSapin]: https://github.com/SimonSapin
 [pull/773]: https://github.com/apollographql/apollo-rs/pull/773
 [pull/774]: https://github.com/apollographql/apollo-rs/pull/774
+[pull/777]: https://github.com/apollographql/apollo-rs/pull/777
 
 # [1.0.0-beta.10](https://crates.io/crates/apollo-compiler/1.0.0-beta.10) - 2023-12-04
 
diff --git a/crates/apollo-compiler/src/ast/impls.rs b/crates/apollo-compiler/src/ast/impls.rs
index f49e088..09efdf3 100644
--- a/crates/apollo-compiler/src/ast/impls.rs
+++ b/crates/apollo-compiler/src/ast/impls.rs
@@ -858,6 +858,30 @@ impl Selection {
         }
     }
 
+    pub fn as_field(&self) -> Option<&Node<Field>> {
+        if let Self::Field(x) = self {
+            Some(x)
+        } else {
+            None
+        }
+    }
+
+    pub fn as_fragment_spread(&self) -> Option<&Node<FragmentSpread>> {
+        if let Self::FragmentSpread(x) = self {
+            Some(x)
+        } else {
+            None
+        }
+    }
+
+    pub fn as_inline_fragment(&self) -> Option<&Node<InlineFragment>> {
+        if let Self::InlineFragment(x) = self {
+            Some(x)
+        } else {
+            None
+        }
+    }
+
     serialize_method!();
 }
 
diff --git a/crates/apollo-compiler/src/executable/mod.rs b/crates/apollo-compiler/src/executable/mod.rs
index 63097ab..0f9d13f 100644
--- a/crates/apollo-compiler/src/executable/mod.rs
+++ b/crates/apollo-compiler/src/executable/mod.rs
@@ -435,6 +435,30 @@ impl Selection {
         }
     }
 
+    pub fn as_field(&self) -> Option<&Node<Field>> {
+        if let Self::Field(field) = self {
+            Some(field)
+        } else {
+            None
+        }
+    }
+
+    pub fn as_inline_fragment(&self) -> Option<&Node<InlineFragment>> {
+        if let Self::InlineFragment(inline) = self {
+            Some(inline)
+        } else {
+            None
+        }
+    }
+
+    pub fn as_fragment_spread(&self) -> Option<&Node<FragmentSpread>> {
+        if let Self::FragmentSpread(spread) = self {
+            Some(spread)
+        } else {
+            None
+        }
+    }
+
     serialize_method!();
 }
 
@@ -474,32 +498,6 @@ impl From<FragmentSpread> for Selection {
     }
 }
 
-impl Selection {
-    pub fn as_field(&self) -> Option<&Node<Field>> {
-        if let Self::Field(field) = self {
-            Some(field)
-        } else {
-            None
-        }
-    }
-
-    pub fn as_inline_fragment(&self) -> Option<&Node<InlineFragment>> {
-        if let Self::InlineFragment(inline) = self {
-            Some(inline)
-        } else {
-            None
-        }
-    }
-
-    pub fn as_fragment_spread(&self) -> Option<&Node<FragmentSpread>> {
-        if let Self::FragmentSpread(spread) = self {
-            Some(spread)
-        } else {
-            None
-        }
-    }
-}
-
 impl Field {
     /// Create a new field with the given name and type.
     ///
diff --git a/crates/apollo-parser/CHANGELOG.md b/crates/apollo-parser/CHANGELOG.md
index 5c62d72..65015d0 100644
--- a/crates/apollo-parser/CHANGELOG.md
+++ b/crates/apollo-parser/CHANGELOG.md
@@ -23,9 +23,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 - **fix parsing `\\"""` in block string - [goto-bus-stop], [pull/774]**
   Previously this was parsed as `\` followed by the end of the string,
   now it's correctly parsed as `\` followed by an escaped `"""`.
+- **emit syntax errors for variables in constant values - [SimonSapin], [pull/777]**
+  default values and type system directive arguments are considered constants
+  and may not use `$foo` variable values.
 
 [goto-bus-stop]: https://github.com/goto-bus-stop
+[SimonSapin]: https://github.com/SimonSapin
 [pull/774]: https://github.com/apollographql/apollo-rs/pull/774
+[pull/777]: https://github.com/apollographql/apollo-rs/pull/777
 
 # [0.7.4](https://crates.io/crates/apollo-parser/0.7.4) - 2023-11-17
 
diff --git a/crates/apollo-parser/src/parser/grammar/argument.rs b/crates/apollo-parser/src/parser/grammar/argument.rs
index aa36c1e..a241b75 100644
--- a/crates/apollo-parser/src/parser/grammar/argument.rs
+++ b/crates/apollo-parser/src/parser/grammar/argument.rs
@@ -1,35 +1,34 @@
-use crate::{
-    parser::grammar::{input, name, value},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{input, name, value};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#Argument
 ///
-/// *Argument*:
-///    Name **:** Value
-pub(crate) fn argument(p: &mut Parser) {
+/// *Argument[Const]*:
+///    Name **:** Value[?Const]
+pub(crate) fn argument(p: &mut Parser, constness: Constness) {
     let _guard = p.start_node(SyntaxKind::ARGUMENT);
     name::name(p);
     if let Some(T![:]) = p.peek() {
         p.bump(S![:]);
-        value::value(p, false);
+        value::value(p, constness, false);
     }
 }
 
 /// See: https://spec.graphql.org/October2021/#Arguments
 ///
-/// *Arguments*:
-///    **(** Argument* **)**
-pub(crate) fn arguments(p: &mut Parser) {
+/// *Arguments[Const]*:
+///    **(** Argument[?Const]* **)**
+pub(crate) fn arguments(p: &mut Parser, constness: Constness) {
     let _g = p.start_node(SyntaxKind::ARGUMENTS);
     p.bump(S!['(']);
     if let Some(TokenKind::Name) = p.peek() {
-        argument(p);
+        argument(p, constness);
     } else {
         p.err("expected an Argument");
     }
     while let Some(TokenKind::Name) = p.peek() {
-        argument(p);
+        argument(p, constness);
     }
     p.expect(T![')'], S![')']);
 }
diff --git a/crates/apollo-parser/src/parser/grammar/directive.rs b/crates/apollo-parser/src/parser/grammar/directive.rs
index 4e477b3..c2b212e 100644
--- a/crates/apollo-parser/src/parser/grammar/directive.rs
+++ b/crates/apollo-parser/src/parser/grammar/directive.rs
@@ -1,7 +1,6 @@
-use crate::{
-    parser::grammar::{argument, description, input, name},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{argument, description, input, name};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#DirectiveDefinition
 ///
@@ -170,27 +169,27 @@ pub(crate) fn directive_locations(p: &mut Parser, is_location: bool) {
 
 /// See: https://spec.graphql.org/October2021/#Directive
 ///
-/// *Directive*:
-///     **@** Name Arguments?
-pub(crate) fn directive(p: &mut Parser) {
+/// *Directive[Const]*:
+///     **@** Name Arguments[?Const]?
+pub(crate) fn directive(p: &mut Parser, constness: Constness) {
     let _g = p.start_node(SyntaxKind::DIRECTIVE);
 
     p.expect(T![@], S![@]);
     name::name(p);
 
     if let Some(T!['(']) = p.peek() {
-        argument::arguments(p);
+        argument::arguments(p, constness);
     }
 }
 
 /// See: https://spec.graphql.org/October2021/#Directives
 ///
-/// *Directives*:
-///     Directive*
-pub(crate) fn directives(p: &mut Parser) {
+/// *Directives[Const]*:
+///     Directive[?Const]*
+pub(crate) fn directives(p: &mut Parser, constness: Constness) {
     let _g = p.start_node(SyntaxKind::DIRECTIVES);
     while let Some(T![@]) = p.peek() {
-        directive(p);
+        directive(p, constness);
     }
 }
 
diff --git a/crates/apollo-parser/src/parser/grammar/enum_.rs b/crates/apollo-parser/src/parser/grammar/enum_.rs
index 7b5bd58..b340edf 100644
--- a/crates/apollo-parser/src/parser/grammar/enum_.rs
+++ b/crates/apollo-parser/src/parser/grammar/enum_.rs
@@ -1,9 +1,8 @@
 #![allow(clippy::needless_return)]
 
-use crate::{
-    parser::grammar::{description, directive, name, value},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, name, value};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#EnumTypeDefinition
 ///
@@ -26,7 +25,7 @@ pub(crate) fn enum_type_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -37,8 +36,8 @@ pub(crate) fn enum_type_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#EnumTypeExtension
 ///
 // *EnumTypeExtension*:
-///    **extend** **enum** Name Directives? EnumValuesDefinition
-///    **extend** **enum** Name Directives?
+///    **extend** **enum** Name Directives[Const]? EnumValuesDefinition
+///    **extend** **enum** Name Directives[Const]?
 pub(crate) fn enum_type_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::ENUM_TYPE_EXTENSION);
     p.bump(SyntaxKind::extend_KW);
@@ -53,7 +52,7 @@ pub(crate) fn enum_type_extension(p: &mut Parser) {
 
     if let Some(T![@]) = p.peek() {
         meets_requirements = true;
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -89,7 +88,7 @@ pub(crate) fn enum_values_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#EnumValueDefinition
 ///
 /// *EnumValueDefinition*:
-///     Description? EnumValue Directives?
+///     Description? EnumValue Directives[Const]?
 pub(crate) fn enum_value_definition(p: &mut Parser) {
     if let Some(TokenKind::Name | TokenKind::StringValue) = p.peek() {
         let _guard = p.start_node(SyntaxKind::ENUM_VALUE_DEFINITION);
@@ -101,7 +100,7 @@ pub(crate) fn enum_value_definition(p: &mut Parser) {
         value::enum_value(p);
 
         if let Some(T![@]) = p.peek() {
-            directive::directives(p);
+            directive::directives(p, Constness::Const);
         }
     }
 }
diff --git a/crates/apollo-parser/src/parser/grammar/field.rs b/crates/apollo-parser/src/parser/grammar/field.rs
index f9a9903..54ce026 100644
--- a/crates/apollo-parser/src/parser/grammar/field.rs
+++ b/crates/apollo-parser/src/parser/grammar/field.rs
@@ -1,9 +1,8 @@
 #![allow(clippy::needless_return)]
 
-use crate::{
-    parser::grammar::{argument, description, directive, name, selection, ty},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{argument, description, directive, name, selection, ty};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#Field
 ///
@@ -22,11 +21,11 @@ pub(crate) fn field(p: &mut Parser) {
     }
 
     if let Some(T!['(']) = p.peek() {
-        argument::arguments(p);
+        argument::arguments(p, Constness::NotConst);
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::NotConst);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -51,7 +50,7 @@ pub(crate) fn fields_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#FieldDefinition
 ///
 /// *FieldDefinition*:
-///     Description? Name ArgumentsDefinition? **:** Type Directives?
+///     Description? Name ArgumentsDefinition? **:** Type Directives[Const]?
 pub(crate) fn field_definition(p: &mut Parser) {
     let _guard = p.start_node(SyntaxKind::FIELD_DEFINITION);
 
@@ -71,7 +70,7 @@ pub(crate) fn field_definition(p: &mut Parser) {
             Some(TokenKind::Name) | Some(T!['[']) => {
                 ty::ty(p);
                 if let Some(T![@]) = p.peek() {
-                    directive::directives(p);
+                    directive::directives(p, Constness::Const);
                 }
                 if p.peek().is_some() {
                     return;
diff --git a/crates/apollo-parser/src/parser/grammar/fragment.rs b/crates/apollo-parser/src/parser/grammar/fragment.rs
index f4e5844..ee65bc7 100644
--- a/crates/apollo-parser/src/parser/grammar/fragment.rs
+++ b/crates/apollo-parser/src/parser/grammar/fragment.rs
@@ -1,7 +1,6 @@
-use crate::{
-    parser::grammar::{directive, name, selection, ty},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{directive, name, selection, ty};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#FragmentDefinition
 ///
@@ -15,7 +14,7 @@ pub(crate) fn fragment_definition(p: &mut Parser) {
     type_condition(p);
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::NotConst);
     }
 
     match p.peek() {
@@ -73,7 +72,7 @@ pub(crate) fn inline_fragment(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::NotConst);
     }
 
     match p.peek() {
@@ -98,6 +97,6 @@ pub(crate) fn fragment_spread(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::NotConst);
     }
 }
diff --git a/crates/apollo-parser/src/parser/grammar/input.rs b/crates/apollo-parser/src/parser/grammar/input.rs
index 5d21002..0e7e95a 100644
--- a/crates/apollo-parser/src/parser/grammar/input.rs
+++ b/crates/apollo-parser/src/parser/grammar/input.rs
@@ -1,12 +1,11 @@
-use crate::{
-    parser::grammar::{description, directive, name, ty, value},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, name, ty, value};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#InputObjectTypeDefinition
 ///
 /// *InputObjectTypeDefinition*:
-///     Description? **input** Name Directives? InputFieldsDefinition?
+///     Description? **input** Name Directives[Const]? InputFieldsDefinition?
 /// ```
 pub(crate) fn input_object_type_definition(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::INPUT_OBJECT_TYPE_DEFINITION);
@@ -25,7 +24,7 @@ pub(crate) fn input_object_type_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -36,8 +35,8 @@ pub(crate) fn input_object_type_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#InputObjectTypeExtension
 ///
 /// *InputObjectTypeExtension*:
-///     **extend** **input** Name Directives? InputFieldsDefinition
-///     **extend** **input** Name Directives
+///     **extend** **input** Name Directives[Const]? InputFieldsDefinition
+///     **extend** **input** Name Directives[Const]
 pub(crate) fn input_object_type_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::INPUT_OBJECT_TYPE_EXTENSION);
     p.bump(SyntaxKind::extend_KW);
@@ -52,7 +51,7 @@ pub(crate) fn input_object_type_extension(p: &mut Parser) {
 
     if let Some(T![@]) = p.peek() {
         meets_requirements = true;
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -87,7 +86,7 @@ pub(crate) fn input_fields_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#InputValueDefinition
 ///
 /// *InputValueDefinition*:
-///     Description? Name **:** Type DefaultValue? Directives?
+///     Description? Name **:** Type DefaultValue? Directives[Const]?
 pub(crate) fn input_value_definition(p: &mut Parser) {
     let _guard = p.start_node(SyntaxKind::INPUT_VALUE_DEFINITION);
 
@@ -107,7 +106,7 @@ pub(crate) fn input_value_definition(p: &mut Parser) {
                 }
 
                 if let Some(T![@]) = p.peek() {
-                    directive::directives(p);
+                    directive::directives(p, Constness::Const);
                 }
             }
             _ => p.err("expected a Type"),
diff --git a/crates/apollo-parser/src/parser/grammar/interface.rs b/crates/apollo-parser/src/parser/grammar/interface.rs
index 90064bc..bcd9d5e 100644
--- a/crates/apollo-parser/src/parser/grammar/interface.rs
+++ b/crates/apollo-parser/src/parser/grammar/interface.rs
@@ -1,12 +1,11 @@
-use crate::{
-    parser::grammar::{description, directive, field, name, object},
-    Parser, SyntaxKind, TokenKind, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, field, name, object};
+use crate::{Parser, SyntaxKind, TokenKind, T};
 
 /// See: https://spec.graphql.org/October2021/#InterfaceTypeDefinition
 ///
 /// *InterfaceTypeDefinition*:
-///     Description? **interface** Name ImplementsInterface? Directives? FieldsDefinition?
+///     Description? **interface** Name ImplementsInterface? Directives[Const]? FieldsDefinition?
 pub(crate) fn interface_type_definition(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::INTERFACE_TYPE_DEFINITION);
 
@@ -28,7 +27,7 @@ pub(crate) fn interface_type_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -39,8 +38,8 @@ pub(crate) fn interface_type_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#InterfaceTypeExtension
 ///
 /// *InterfaceTypeExtension*:
-///     **extend** **interface** Name ImplementsInterface? Directives? FieldsDefinition
-///     **extend** **interface** Name ImplementsInterface? Directives
+///     **extend** **interface** Name ImplementsInterface? Directives[Const]? FieldsDefinition
+///     **extend** **interface** Name ImplementsInterface? Directives[Const]
 ///     **extend** **interface** Name ImplementsInterface
 pub(crate) fn interface_type_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::INTERFACE_TYPE_EXTENSION);
@@ -61,7 +60,7 @@ pub(crate) fn interface_type_extension(p: &mut Parser) {
 
     if let Some(T![@]) = p.peek() {
         meets_requirements = true;
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
diff --git a/crates/apollo-parser/src/parser/grammar/object.rs b/crates/apollo-parser/src/parser/grammar/object.rs
index 36a43ec..4d330b2 100644
--- a/crates/apollo-parser/src/parser/grammar/object.rs
+++ b/crates/apollo-parser/src/parser/grammar/object.rs
@@ -1,14 +1,13 @@
 #![allow(clippy::needless_return)]
 
-use crate::{
-    parser::grammar::{description, directive, field, name, ty},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, field, name, ty};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#ObjectTypeDefinition
 ///
 /// *ObjectTypeDefinition*:
-///     Description? **type** Name ImplementsInterfaces? Directives? FieldsDefinition?
+///     Description? **type** Name ImplementsInterfaces? Directives[Const]? FieldsDefinition?
 pub(crate) fn object_type_definition(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::OBJECT_TYPE_DEFINITION);
 
@@ -34,7 +33,7 @@ pub(crate) fn object_type_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -45,8 +44,8 @@ pub(crate) fn object_type_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#ObjectTypeExtension
 ///
 /// *ObjectTypeExtension*:
-///     **extend** **type** Name ImplementsInterfaces? Directives? FieldsDefinition
-///     **extend** **type** Name ImplementsInterfaces? Directives?
+///     **extend** **type** Name ImplementsInterfaces? Directives[Const]? FieldsDefinition
+///     **extend** **type** Name ImplementsInterfaces? Directives[Const]?
 ///     **extend** **type** Name ImplementsInterfaces
 pub(crate) fn object_type_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::OBJECT_TYPE_EXTENSION);
@@ -69,7 +68,7 @@ pub(crate) fn object_type_extension(p: &mut Parser) {
 
     if let Some(T![@]) = p.peek() {
         meets_requirements = true;
-        directive::directives(p)
+        directive::directives(p, Constness::Const)
     }
 
     if let Some(T!['{']) = p.peek() {
diff --git a/crates/apollo-parser/src/parser/grammar/operation.rs b/crates/apollo-parser/src/parser/grammar/operation.rs
index 4dd872b..afe0d66 100644
--- a/crates/apollo-parser/src/parser/grammar/operation.rs
+++ b/crates/apollo-parser/src/parser/grammar/operation.rs
@@ -1,7 +1,6 @@
-use crate::{
-    parser::grammar::{directive, name, selection, ty, variable},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{directive, name, selection, ty, variable};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// RootOperationTypeDefinition is used in a SchemaDefinition. Not to be confused
 /// with OperationDefinition.
@@ -65,7 +64,7 @@ pub(crate) fn operation_definition(p: &mut Parser) {
             }
 
             if let Some(T![@]) = p.peek() {
-                directive::directives(p);
+                directive::directives(p, Constness::NotConst);
             }
 
             match p.peek() {
diff --git a/crates/apollo-parser/src/parser/grammar/scalar.rs b/crates/apollo-parser/src/parser/grammar/scalar.rs
index 49502f9..808e0e6 100644
--- a/crates/apollo-parser/src/parser/grammar/scalar.rs
+++ b/crates/apollo-parser/src/parser/grammar/scalar.rs
@@ -1,12 +1,11 @@
-use crate::{
-    parser::grammar::{description, directive, name},
-    Parser, SyntaxKind, TokenKind, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, name};
+use crate::{Parser, SyntaxKind, TokenKind, T};
 
 /// See: https://spec.graphql.org/October2021/#ScalarTypeDefinition
 ///
 /// *ScalarTypeDefinition*:
-///     Description? **scalar** Name Directives?
+///     Description? **scalar** Name Directives[Const]?
 pub(crate) fn scalar_type_definition(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::SCALAR_TYPE_DEFINITION);
 
@@ -24,14 +23,14 @@ pub(crate) fn scalar_type_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 }
 
 /// See: https://spec.graphql.org/October2021/#ScalarTypeExtension
 ///
 /// *ScalarTypeExtension*:
-///     **extend** **scalar** Name Directives
+///     **extend** **scalar** Name Directives[Const]
 pub(crate) fn scalar_type_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::SCALAR_TYPE_EXTENSION);
     p.bump(SyntaxKind::extend_KW);
@@ -43,7 +42,7 @@ pub(crate) fn scalar_type_extension(p: &mut Parser) {
     }
 
     match p.peek() {
-        Some(T![@]) => directive::directives(p),
+        Some(T![@]) => directive::directives(p, Constness::Const),
         _ => p.err("expected Directives"),
     }
 }
diff --git a/crates/apollo-parser/src/parser/grammar/schema.rs b/crates/apollo-parser/src/parser/grammar/schema.rs
index 4b4203d..eed2eec 100644
--- a/crates/apollo-parser/src/parser/grammar/schema.rs
+++ b/crates/apollo-parser/src/parser/grammar/schema.rs
@@ -1,12 +1,11 @@
-use crate::{
-    parser::grammar::{description, directive, operation},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, operation};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#SchemaDefinition
 ///
 /// *SchemaDefinition*:
-///     Description? **schema** Directives? **{** RootOperationTypeDefinition* **}**
+///     Description? **schema** Directives[Const]? **{** RootOperationTypeDefinition* **}**
 pub(crate) fn schema_definition(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::SCHEMA_DEFINITION);
 
@@ -19,7 +18,7 @@ pub(crate) fn schema_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
@@ -33,8 +32,8 @@ pub(crate) fn schema_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#SchemaExtension
 ///
 /// *SchemaExtension*:
-///     **extend** **schema** Directives? **{** RootOperationTypeDefinition* **}**
-///     **extend** **schema** Directives
+///     **extend** **schema** Directives[Const]? **{** RootOperationTypeDefinition* **}**
+///     **extend** **schema** Directives[Const]
 pub(crate) fn schema_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::SCHEMA_EXTENSION);
     p.bump(SyntaxKind::extend_KW);
@@ -44,7 +43,7 @@ pub(crate) fn schema_extension(p: &mut Parser) {
 
     if let Some(T![@]) = p.peek() {
         meets_requirements = true;
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T!['{']) = p.peek() {
diff --git a/crates/apollo-parser/src/parser/grammar/union_.rs b/crates/apollo-parser/src/parser/grammar/union_.rs
index 7ff52ac..1a09614 100644
--- a/crates/apollo-parser/src/parser/grammar/union_.rs
+++ b/crates/apollo-parser/src/parser/grammar/union_.rs
@@ -1,14 +1,13 @@
 #![allow(clippy::needless_return)]
 
-use crate::{
-    parser::grammar::{description, directive, name, ty},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{description, directive, name, ty};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#UnionTypeDefinition
 ///
 /// *UnionTypeDefinition*:
-///     Description? **union** Name Directives? UnionDefMemberTypes?
+///     Description? **union** Name Directives[Const]? UnionDefMemberTypes?
 pub(crate) fn union_type_definition(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::UNION_TYPE_DEFINITION);
 
@@ -26,7 +25,7 @@ pub(crate) fn union_type_definition(p: &mut Parser) {
     }
 
     if let Some(T![@]) = p.peek() {
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T![=]) = p.peek() {
@@ -37,8 +36,8 @@ pub(crate) fn union_type_definition(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#UnionTypeExtension
 ///
 /// *UnionTypeExtension*:
-///     **extend** **union** Name Directives? UnionDefMemberTypes
-///     **extend** **union** Name Directives
+///     **extend** **union** Name Directives[Const]? UnionDefMemberTypes
+///     **extend** **union** Name Directives[Const]
 pub(crate) fn union_type_extension(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::UNION_TYPE_EXTENSION);
     p.bump(SyntaxKind::extend_KW);
@@ -53,7 +52,7 @@ pub(crate) fn union_type_extension(p: &mut Parser) {
 
     if let Some(T![@]) = p.peek() {
         meets_requirements = true;
-        directive::directives(p);
+        directive::directives(p, Constness::Const);
     }
 
     if let Some(T![=]) = p.peek() {
diff --git a/crates/apollo-parser/src/parser/grammar/value.rs b/crates/apollo-parser/src/parser/grammar/value.rs
index 96f84a3..498fa01 100644
--- a/crates/apollo-parser/src/parser/grammar/value.rs
+++ b/crates/apollo-parser/src/parser/grammar/value.rs
@@ -3,21 +3,38 @@ use crate::{
     Parser, SyntaxKind, TokenKind, S, T,
 };
 
+#[derive(Clone, Copy)]
+pub(crate) enum Constness {
+    Const,
+    NotConst,
+}
+
 /// See: https://spec.graphql.org/October2021/#Value
 ///
-/// *Value*
-///     Variable
+/// *Value[Const]*
+///     [if not Const] Variable
 ///     IntValue
 ///     FloatValue
 ///     StringValue
 ///     BooleanValue
 ///     NullValue
 ///     EnumValue
-///     ListValue
-///     ObjectValue
-pub(crate) fn value(p: &mut Parser, pop_on_error: bool) {
+///     ListValue[?Const]
+///     ObjectValue[?Const]
+pub(crate) fn value(p: &mut Parser, constness: Constness, pop_on_error: bool) {
     match p.peek() {
-        Some(T![$]) => variable::variable(p),
+        Some(T![$]) => {
+            if let Constness::Const = constness {
+                let error_message = "unexpected variable value in a Const context";
+                if pop_on_error {
+                    p.err_and_pop(error_message);
+                } else {
+                    p.err(error_message);
+                }
+            }
+            // Consume the variable name even if const, for better error recovery
+            variable::variable(p);
+        }
         Some(TokenKind::Int) => {
             let _g = p.start_node(SyntaxKind::INT_VALUE);
             p.bump(SyntaxKind::INT);
@@ -48,8 +65,8 @@ pub(crate) fn value(p: &mut Parser, pop_on_error: bool) {
                 _ => enum_value(p),
             }
         }
-        Some(T!['[']) => list_value(p),
-        Some(T!['{']) => object_value(p),
+        Some(T!['[']) => list_value(p, constness),
+        Some(T!['{']) => object_value(p, constness),
         _ => {
             let error_message = "expected a valid Value";
             if pop_on_error {
@@ -77,10 +94,10 @@ pub(crate) fn enum_value(p: &mut Parser) {
 
 /// See: https://spec.graphql.org/October2021/#ListValue
 ///
-/// *ListValue*:
+/// *ListValue[Const]*:
 ///     **[** **]**
-///     **[** Value* **]**
-pub(crate) fn list_value(p: &mut Parser) {
+///     **[** Value[?Const]* **]**
+pub(crate) fn list_value(p: &mut Parser, constness: Constness) {
     let _g = p.start_node(SyntaxKind::LIST_VALUE);
     p.bump(S!['[']);
 
@@ -95,7 +112,7 @@ pub(crate) fn list_value(p: &mut Parser) {
                 p.limit_err("parser recursion limit reached");
                 return;
             }
-            value(p, true);
+            value(p, constness, true);
             p.recursion_limit.decrement()
         }
     }
@@ -103,15 +120,15 @@ pub(crate) fn list_value(p: &mut Parser) {
 
 /// See: https://spec.graphql.org/October2021/#ObjectValue
 ///
-/// *ObjectValue*:
+/// *ObjectValue[Const]*:
 ///     **{** **}**
-///     **{** ObjectField* **}**
-pub(crate) fn object_value(p: &mut Parser) {
+///     **{** ObjectField[?Const]* **}**
+pub(crate) fn object_value(p: &mut Parser, constness: Constness) {
     let _g = p.start_node(SyntaxKind::OBJECT_VALUE);
     p.bump(S!['{']);
 
     while let Some(TokenKind::Name) = p.peek() {
-        object_field(p);
+        object_field(p, constness);
     }
 
     p.expect(T!['}'], S!['}']);
@@ -119,9 +136,9 @@ pub(crate) fn object_value(p: &mut Parser) {
 
 /// See: https://spec.graphql.org/October2021/#ObjectField
 ///
-/// *ObjectField*:
-///     Name **:** Value
-pub(crate) fn object_field(p: &mut Parser) {
+/// *ObjectField[Const]*:
+///     Name **:** Value[?Const]
+pub(crate) fn object_field(p: &mut Parser, constness: Constness) {
     let _guard = p.start_node(SyntaxKind::OBJECT_FIELD);
     name::name(p);
 
@@ -131,7 +148,7 @@ pub(crate) fn object_field(p: &mut Parser) {
             p.limit_err("parser recursion limit reached");
             return;
         }
-        value(p, true);
+        value(p, constness, true);
         p.recursion_limit.decrement()
     }
 }
@@ -139,11 +156,11 @@ pub(crate) fn object_field(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#DefaultValue
 ///
 /// *DefaultValue*:
-///     **=** Value
+///     **=** Value[Const]
 pub(crate) fn default_value(p: &mut Parser) {
     let _g = p.start_node(SyntaxKind::DEFAULT_VALUE);
     p.bump(S![=]);
-    value(p, false);
+    value(p, Constness::Const, false);
 }
 
 #[cfg(test)]
diff --git a/crates/apollo-parser/src/parser/grammar/variable.rs b/crates/apollo-parser/src/parser/grammar/variable.rs
index baeec86..7218ed1 100644
--- a/crates/apollo-parser/src/parser/grammar/variable.rs
+++ b/crates/apollo-parser/src/parser/grammar/variable.rs
@@ -1,7 +1,6 @@
-use crate::{
-    parser::grammar::{directive, name, ty, value},
-    Parser, SyntaxKind, TokenKind, S, T,
-};
+use crate::parser::grammar::value::Constness;
+use crate::parser::grammar::{directive, name, ty, value};
+use crate::{Parser, SyntaxKind, TokenKind, S, T};
 
 /// See: https://spec.graphql.org/October2021/#VariableDefinitions
 ///
@@ -26,7 +25,7 @@ pub(crate) fn variable_definitions(p: &mut Parser) {
 /// See: https://spec.graphql.org/October2021/#VariableDefinition
 ///
 /// *VariableDefinition*:
-///     Variable **:** Type DefaultValue? Directives?
+///     Variable **:** Type DefaultValue? Directives[Const]?
 pub(crate) fn variable_definition(p: &mut Parser) {
     let _guard = p.start_node(SyntaxKind::VARIABLE_DEFINITION);
     variable(p);
@@ -39,7 +38,7 @@ pub(crate) fn variable_definition(p: &mut Parser) {
                 value::default_value(p);
             }
             if let Some(T![@]) = p.peek() {
-                directive::directives(p)
+                directive::directives(p, Constness::Const)
             }
         } else {
             p.err("expected a Type");


Test patch:
diff --git a/crates/apollo-compiler/test_data/diagnostics/0111_const_value.graphql b/crates/apollo-compiler/test_data/diagnostics/0111_const_value.graphql
new file mode 100644
index 0000000..aa7c3e8
--- /dev/null
+++ b/crates/apollo-compiler/test_data/diagnostics/0111_const_value.graphql
@@ -0,0 +1,14 @@
+query(
+    $var1: Boolean!
+    $var2: Boolean! = $var
+) {
+    f1 @include(if: $var1)
+    f2 @include(if: $var2)
+}
+
+directive @someDir(arg: Boolean) on OBJECT
+
+type Query @someDir(arg: $var1) {
+    f1: Int
+    f2: Int
+}
diff --git a/crates/apollo-compiler/test_data/diagnostics/0111_const_value.txt b/crates/apollo-compiler/test_data/diagnostics/0111_const_value.txt
new file mode 100644
index 0000000..4ced292
--- /dev/null
+++ b/crates/apollo-compiler/test_data/diagnostics/0111_const_value.txt
@@ -0,0 +1,22 @@
+Error: syntax error: unexpected variable value in a Const context
+   ╭─[0111_const_value.graphql:3:23]
+   │
+ 3 │     $var2: Boolean! = $var
+   │                       ┬  
+   │                       ╰── unexpected variable value in a Const context
+───╯
+Error: variable `var1` is not defined
+    ╭─[0111_const_value.graphql:11:21]
+    │
+ 11 │ type Query @someDir(arg: $var1) {
+    │                          ──┬──  
+    │                            ╰──── not found in this scope
+────╯
+Error: syntax error: unexpected variable value in a Const context
+    ╭─[0111_const_value.graphql:11:26]
+    │
+ 11 │ type Query @someDir(arg: $var1) {
+    │                          ┬  
+    │                          ╰── unexpected variable value in a Const context
+────╯
+
diff --git a/crates/apollo-compiler/test_data/serializer/diagnostics/0111_const_value.graphql b/crates/apollo-compiler/test_data/serializer/diagnostics/0111_const_value.graphql
new file mode 100644
index 0000000..dd1e72c
--- /dev/null
+++ b/crates/apollo-compiler/test_data/serializer/diagnostics/0111_const_value.graphql
@@ -0,0 +1,11 @@
+query($var1: Boolean!, $var2: Boolean! = $var) {
+  f1 @include(if: $var1)
+  f2 @include(if: $var2)
+}
+
+directive @someDir(arg: Boolean) on OBJECT
+
+type Query @someDir(arg: $var1) {
+  f1: Int
+  f2: Int
+}
diff --git a/crates/apollo-compiler/tests/serde.rs b/crates/apollo-compiler/tests/serde.rs
index be89a9e..a7e61f5 100644
--- a/crates/apollo-compiler/tests/serde.rs
+++ b/crates/apollo-compiler/tests/serde.rs
@@ -5,16 +5,16 @@ use expect_test::expect;
 #[test]
 fn test_serde_value() {
     let input = r#"
-        query($var: I = {
-            null_field: null,
-            enum_field: EXAMPLE,
-            var_field: $var,
-            string_field: "example"
-            float_field: 1.5
-            int_field: 47
-            list_field: [1, 2, 3]
-        }) {
-            selection
+        query {
+            field(arg: {
+                null_field: null,
+                enum_field: EXAMPLE,
+                var_field: $var,
+                string_field: "example"
+                float_field: 1.5
+                int_field: 47
+                list_field: [1, 2, 3]
+            })
         }
     "#;
     let value = ast::Document::parse(input, "input.graphql")
@@ -22,10 +22,12 @@ fn test_serde_value() {
         .definitions[0]
         .as_operation_definition()
         .unwrap()
-        .variables[0]
-        .default_value
-        .clone()
-        .unwrap();
+        .selection_set[0]
+        .as_field()
+        .unwrap()
+        .arguments[0]
+        .value
+        .clone();
     let graphql = value.to_string();
     let expected_graphql = expect![[r#"
         {
diff --git a/crates/apollo-parser/test_data/parser/err/0052_const_value.graphql b/crates/apollo-parser/test_data/parser/err/0052_const_value.graphql
new file mode 100644
index 0000000..aa7c3e8
--- /dev/null
+++ b/crates/apollo-parser/test_data/parser/err/0052_const_value.graphql
@@ -0,0 +1,14 @@
+query(
+    $var1: Boolean!
+    $var2: Boolean! = $var
+) {
+    f1 @include(if: $var1)
+    f2 @include(if: $var2)
+}
+
+directive @someDir(arg: Boolean) on OBJECT
+
+type Query @someDir(arg: $var1) {
+    f1: Int
+    f2: Int
+}
diff --git a/crates/apollo-parser/test_data/parser/err/0052_const_value.txt b/crates/apollo-parser/test_data/parser/err/0052_const_value.txt
new file mode 100644
index 0000000..c27f2d8
--- /dev/null
+++ b/crates/apollo-parser/test_data/parser/err/0052_const_value.txt
@@ -0,0 +1,166 @@
+- DOCUMENT@0..219
+    - OPERATION_DEFINITION@0..113
+        - OPERATION_TYPE@0..5
+            - query_KW@0..5 "query"
+        - VARIABLE_DEFINITIONS@5..55
+            - L_PAREN@5..6 "("
+            - WHITESPACE@6..11 "\n    "
+            - VARIABLE_DEFINITION@11..26
+                - VARIABLE@11..16
+                    - DOLLAR@11..12 "$"
+                    - NAME@12..16
+                        - IDENT@12..16 "var1"
+                - COLON@16..17 ":"
+                - WHITESPACE@17..18 " "
+                - NON_NULL_TYPE@18..26
+                    - NAMED_TYPE@18..25
+                        - NAME@18..25
+                            - IDENT@18..25 "Boolean"
+                    - BANG@25..26 "!"
+            - WHITESPACE@26..31 "\n    "
+            - VARIABLE_DEFINITION@31..53
+                - VARIABLE@31..36
+                    - DOLLAR@31..32 "$"
+                    - NAME@32..36
+                        - IDENT@32..36 "var2"
+                - COLON@36..37 ":"
+                - WHITESPACE@37..38 " "
+                - NON_NULL_TYPE@38..46
+                    - NAMED_TYPE@38..45
+                        - NAME@38..45
+                            - IDENT@38..45 "Boolean"
+                    - BANG@45..46 "!"
+                - WHITESPACE@46..47 " "
+                - DEFAULT_VALUE@47..53
+                    - EQ@47..48 "="
+                    - WHITESPACE@48..49 " "
+                    - VARIABLE@49..53
+                        - DOLLAR@49..50 "$"
+                        - NAME@50..53
+                            - IDENT@50..53 "var"
+            - WHITESPACE@53..54 "\n"
+            - R_PAREN@54..55 ")"
+        - WHITESPACE@55..56 " "
+        - SELECTION_SET@56..113
+            - L_CURLY@56..57 "{"
+            - WHITESPACE@57..62 "\n    "
+            - FIELD@62..84
+                - NAME@62..64
+                    - IDENT@62..64 "f1"
+                - WHITESPACE@64..65 " "
+                - DIRECTIVES@65..84
+                    - DIRECTIVE@65..84
+                        - AT@65..66 "@"
+                        - NAME@66..73
+                            - IDENT@66..73 "include"
+                        - ARGUMENTS@73..84
+                            - L_PAREN@73..74 "("
+                            - ARGUMENT@74..83
+                                - NAME@74..76
+                                    - IDENT@74..76 "if"
+                                - COLON@76..77 ":"
+                                - WHITESPACE@77..78 " "
+                                - VARIABLE@78..83
+                                    - DOLLAR@78..79 "$"
+                                    - NAME@79..83
+                                        - IDENT@79..83 "var1"
+                            - R_PAREN@83..84 ")"
+            - WHITESPACE@84..89 "\n    "
+            - FIELD@89..111
+                - NAME@89..91
+                    - IDENT@89..91 "f2"
+                - WHITESPACE@91..92 " "
+                - DIRECTIVES@92..111
+                    - DIRECTIVE@92..111
+                        - AT@92..93 "@"
+                        - NAME@93..100
+                            - IDENT@93..100 "include"
+                        - ARGUMENTS@100..111
+                            - L_PAREN@100..101 "("
+                            - ARGUMENT@101..110
+                                - NAME@101..103
+                                    - IDENT@101..103 "if"
+                                - COLON@103..104 ":"
+                                - WHITESPACE@104..105 " "
+                                - VARIABLE@105..110
+                                    - DOLLAR@105..106 "$"
+                                    - NAME@106..110
+                                        - IDENT@106..110 "var2"
+                            - R_PAREN@110..111 ")"
+            - WHITESPACE@111..112 "\n"
+            - R_CURLY@112..113 "}"
+    - WHITESPACE@113..115 "\n\n"
+    - DIRECTIVE_DEFINITION@115..157
+        - directive_KW@115..124 "directive"
+        - WHITESPACE@124..125 " "
+        - AT@125..126 "@"
+        - NAME@126..133
+            - IDENT@126..133 "someDir"
+        - ARGUMENTS_DEFINITION@133..147
+            - L_PAREN@133..134 "("
+            - INPUT_VALUE_DEFINITION@134..146
+                - NAME@134..137
+                    - IDENT@134..137 "arg"
+                - COLON@137..138 ":"
+                - WHITESPACE@138..139 " "
+                - NAMED_TYPE@139..146
+                    - NAME@139..146
+                        - IDENT@139..146 "Boolean"
+            - R_PAREN@146..147 ")"
+        - WHITESPACE@147..148 " "
+        - on_KW@148..150 "on"
+        - WHITESPACE@150..151 " "
+        - DIRECTIVE_LOCATIONS@151..157
+            - DIRECTIVE_LOCATION@151..157
+                - OBJECT_KW@151..157 "OBJECT"
+    - WHITESPACE@157..159 "\n\n"
+    - OBJECT_TYPE_DEFINITION@159..218
+        - type_KW@159..163 "type"
+        - WHITESPACE@163..164 " "
+        - NAME@164..169
+            - IDENT@164..169 "Query"
+        - WHITESPACE@169..170 " "
+        - DIRECTIVES@170..190
+            - DIRECTIVE@170..190
+                - AT@170..171 "@"
+                - NAME@171..178
+                    - IDENT@171..178 "someDir"
+                - ARGUMENTS@178..190
+                    - L_PAREN@178..179 "("
+                    - ARGUMENT@179..189
+                        - NAME@179..182
+                            - IDENT@179..182 "arg"
+                        - COLON@182..183 ":"
+                        - WHITESPACE@183..184 " "
+                        - VARIABLE@184..189
+                            - DOLLAR@184..185 "$"
+                            - NAME@185..189
+                                - IDENT@185..189 "var1"
+                    - R_PAREN@189..190 ")"
+        - WHITESPACE@190..191 " "
+        - FIELDS_DEFINITION@191..218
+            - L_CURLY@191..192 "{"
+            - WHITESPACE@192..197 "\n    "
+            - FIELD_DEFINITION@197..204
+                - NAME@197..199
+                    - IDENT@197..199 "f1"
+                - COLON@199..200 ":"
+                - WHITESPACE@200..201 " "
+                - NAMED_TYPE@201..204
+                    - NAME@201..204
+                        - IDENT@201..204 "Int"
+            - WHITESPACE@204..209 "\n    "
+            - FIELD_DEFINITION@209..216
+                - NAME@209..211
+                    - IDENT@209..211 "f2"
+                - COLON@211..212 ":"
+                - WHITESPACE@212..213 " "
+                - NAMED_TYPE@213..216
+                    - NAME@213..216
+                        - IDENT@213..216 "Int"
+            - WHITESPACE@216..217 "\n"
+            - R_CURLY@217..218 "}"
+    - WHITESPACE@218..219 "\n"
+- ERROR@49:50 "unexpected variable value in a Const context" $
+- ERROR@184:185 "unexpected variable value in a Const context" $
+recursion limit: 500, high: 1
\ No newline at end of file