From b21bb996796b487d7f369f7e162a0d3096ffaae4 Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 9 Nov 2023 14:19:05 +0000
Subject: [PATCH 1/8] Add note about nullable variables with default values

---
 spec/Section 6 -- Execution.md | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md
index 8efd401a4..9d3fcaee5 100644
--- a/spec/Section 6 -- Execution.md	
+++ b/spec/Section 6 -- Execution.md	
@@ -645,6 +645,13 @@ Note: Variable values are not coerced because they are expected to be coerced
 before executing the operation in {CoerceVariableValues()}, and valid operations
 must only allow usage of variables of appropriate types.
 
+Note: When a default value exists for a variable definition, the type of the
+variable is allowed to be nullable even if it is used in a non-nullable
+position, see
+[Allowing Optional Variables When Default Values Exist](#sec-All-Variable-Usages-Are-Allowed.Allowing-Optional-Variables-When-Default-Values-Exist)
+in Validation. If the value for a variable is explicitly {null} and is used in a
+non-nullable position, a _field error_ will be raised.
+
 ### Value Resolution
 
 While nearly all of GraphQL execution can be described generically, ultimately

From a91cdba0dfedd0c13655f03cc3ac3910da388686 Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 9 Nov 2023 15:07:33 +0000
Subject: [PATCH 2/8] Add variables to table

---
 spec/Section 3 -- Type System.md | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index e52519fb7..74f598399 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1773,18 +1773,18 @@ constructing the list.
 
 Following are examples of input coercion with various list types and values:
 
-| Expected Type | Provided Value   | Coerced Value               |
-| ------------- | ---------------- | --------------------------- |
-| `[Int]`       | `[1, 2, 3]`      | `[1, 2, 3]`                 |
-| `[Int]`       | `[1, "b", true]` | Error: Incorrect item value |
-| `[Int]`       | `1`              | `[1]`                       |
-| `[Int]`       | `null`           | `null`                      |
-| `[[Int]]`     | `[[1], [2, 3]]`  | `[[1], [2, 3]]`             |
-| `[[Int]]`     | `[1, 2, 3]`      | `[[1], [2], [3]]`           |
-| `[[Int]]`     | `[1, null, 3]`   | `[[1], null, [3]]`          |
-| `[[Int]]`     | `[[1], ["b"]]`   | Error: Incorrect item value |
-| `[[Int]]`     | `1`              | `[[1]]`                     |
-| `[[Int]]`     | `null`           | `null`                      |
+| Expected Type | Literal Value    | Variable Values | Coerced Value               |
+| ------------- | ---------------- | --------------- | --------------------------- |
+| `[Int]`       | `[1, 2, 3]`      | `{}`            | `[1, 2, 3]`                 |
+| `[Int]`       | `[1, "b", true]` | `{}`            | Error: Incorrect item value |
+| `[Int]`       | `1`              | `{}`            | `[1]`                       |
+| `[Int]`       | `null`           | `{}`            | `null`                      |
+| `[[Int]]`     | `[[1], [2, 3]]`  | `{}`            | `[[1], [2, 3]]`             |
+| `[[Int]]`     | `[1, 2, 3]`      | `{}`            | `[[1], [2], [3]]`           |
+| `[[Int]]`     | `[1, null, 3]`   | `{}`            | `[[1], null, [3]]`          |
+| `[[Int]]`     | `[[1], ["b"]]`   | `{}`            | Error: Incorrect item value |
+| `[[Int]]`     | `1`              | `{}`            | `[[1]]`                     |
+| `[[Int]]`     | `null`           | `{}`            | `null`                      |
 
 ## Non-Null
 

From 4ca2023992ed5bb2aef2c58d4f532859fb580acd Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 9 Nov 2023 16:59:23 +0000
Subject: [PATCH 3/8] Algorithm for coercing list values

---
 spec/Section 3 -- Type System.md | 73 ++++++++++++++++++++++++++------
 1 file changed, 61 insertions(+), 12 deletions(-)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index 74f598399..c147257e2 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1771,20 +1771,69 @@ This allows inputs which accept one or many arguments (sometimes referred to as
 single value, a client can just pass that value directly rather than
 constructing the list.
 
+The result of coercion of a value {value} to a list type {listType} is
+{CoerceListValue(value, listType)}.
+
+CoerceListValue(value, listType):
+
+- If {value} is {null}, return {null}.
+- Let {itemType} be the inner type of {listType}.
+- Let {coercedList} be an empty list.
+- If {value} is a list:
+  - For each {itemValue} in {value}:
+    - Let {coercedItemValue} be {CoerceListItemValue(itemValue, itemType)}.
+    - Append {coercedItemValue} to {coercedList}.
+- Otherwise:
+  - Let {coercedItemValue} be {CoerceListItemValue(value, itemType)}.
+  - Append {coercedItemValue} to {coercedList}.
+- Return {coercedList}.
+
+CoerceListItemValue(itemValue, itemType):
+
+- If {itemValue} is {null}, return {null}.
+- Otherwise, if {itemValue} is a Variable:
+  - Let {runtimeValue} be the runtime value of that variable, or {null} if no
+    runtime value is provided.
+  - If {runtimeValue} is {null} and {itemType} is a non-null type, a _field
+    error_ must be raised.
+  - Return {runtimeValue}.
+- Otherwise, return the result of coercing {itemValue} according to the input
+  coercion rules for {itemType}.
+
 Following are examples of input coercion with various list types and values:
 
-| Expected Type | Literal Value    | Variable Values | Coerced Value               |
-| ------------- | ---------------- | --------------- | --------------------------- |
-| `[Int]`       | `[1, 2, 3]`      | `{}`            | `[1, 2, 3]`                 |
-| `[Int]`       | `[1, "b", true]` | `{}`            | Error: Incorrect item value |
-| `[Int]`       | `1`              | `{}`            | `[1]`                       |
-| `[Int]`       | `null`           | `{}`            | `null`                      |
-| `[[Int]]`     | `[[1], [2, 3]]`  | `{}`            | `[[1], [2, 3]]`             |
-| `[[Int]]`     | `[1, 2, 3]`      | `{}`            | `[[1], [2], [3]]`           |
-| `[[Int]]`     | `[1, null, 3]`   | `{}`            | `[[1], null, [3]]`          |
-| `[[Int]]`     | `[[1], ["b"]]`   | `{}`            | Error: Incorrect item value |
-| `[[Int]]`     | `1`              | `{}`            | `[[1]]`                     |
-| `[[Int]]`     | `null`           | `{}`            | `null`                      |
+| Expected Type | Literal Value    | Variable Values | Coerced Value                |
+| ------------- | ---------------- | --------------- | ---------------------------- |
+| `[Int]`       | `[1, 2, 3]`      | `{}`            | `[1, 2, 3]`                  |
+| `[Int]`       | `[1, null]`      | `{}`            | `[1, null]`                  |
+| `[Int]`       | `[1, "b", true]` | `{}`            | Error: Incorrect item value  |
+| `[Int]`       | `1`              | `{}`            | `[1]`                        |
+| `[Int]`       | `null`           | `{}`            | `null`                       |
+| `[Int]`       | `[1, $b]`        | `{}`            | `[1, null]`                  |
+| `[Int]`       | `[1, $b]`        | `{"b": 2}`      | `[1, 2]`                     |
+| `[Int]`       | `[1, $b]`        | `{"b": null}`   | `[1, null]`                  |
+| `[Int]!`      | `[null]`         | `{}`            | `[null]`                     |
+| `[Int]!`      | `null`           | `{}`            | Error: Must be non-null      |
+| `[Int!]`      | `[1, 2, 3]`      | `{}`            | `[1, 2, 3]`                  |
+| `[Int!]`      | `[1, null]`      | `{}`            | Error: Item must be non-null |
+| `[Int!]`      | `[1, "b", true]` | `{}`            | Error: Incorrect item value  |
+| `[Int!]`      | `1`              | `{}`            | `[1]`                        |
+| `[Int!]`      | `null`           | `{}`            | `null`                       |
+| `[Int!]`      | `[1, $b]`        | `{}`            | Error: Item must be non-null |
+| `[Int!]`      | `[1, $b]`        | `{"b": 2}`      | `[1, 2]`                     |
+| `[Int!]`      | `[1, $b]`        | `{"b": null}`   | Error: Item must be non-null |
+| `[[Int]]`     | `[[1], [2, 3]]`  | `{}`            | `[[1], [2, 3]]`              |
+| `[[Int]]`     | `[1, 2, 3]`      | `{}`            | `[[1], [2], [3]]`            |
+| `[[Int]]`     | `[1, null, 3]`   | `{}`            | `[[1], null, [3]]`           |
+| `[[Int]]`     | `[[1], ["b"]]`   | `{}`            | Error: Incorrect item value  |
+| `[[Int]]`     | `1`              | `{}`            | `[[1]]`                      |
+| `[[Int]]`     | `null`           | `{}`            | `null`                       |
+| `[[Int]]`     | `[1, [$b]]`      | `{}`            | `[[1],[null]]`               |
+| `[[Int]]`     | `[1, [$b]]`      | `{"b": null}`   | `[[1],[null]]`               |
+| `[[Int]]`     | `[1, [$b]]`      | `{"b": 2}`      | `[[1],[2]]`                  |
+| `[[Int]]`     | `[1, $b]`        | `{"b": [2]}`    | `[[1],[2]]`                  |
+| `[[Int]]`     | `[1, $b]`        | `{"b": 2}`      | `[[1],[2]]`                  |
+| `[[Int]]`     | `[1, $b]`        | `{"b": null}`   | `[[1],null]`                 |
 
 ## Non-Null
 

From ec3d50a664f02a3218c81bb8c3202c91765fa952 Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 9 Nov 2023 17:14:38 +0000
Subject: [PATCH 4/8] Move note and clarify algorithm

---
 spec/Section 3 -- Type System.md | 20 ++++++++++++++++----
 spec/Section 6 -- Execution.md   |  7 -------
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index c147257e2..2a1f783fd 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1792,14 +1792,26 @@ CoerceListItemValue(itemValue, itemType):
 
 - If {itemValue} is {null}, return {null}.
 - Otherwise, if {itemValue} is a Variable:
-  - Let {runtimeValue} be the runtime value of that variable, or {null} if no
-    runtime value is provided.
-  - If {runtimeValue} is {null} and {itemType} is a non-null type, a _field
+  - If the variable provides a runtime value:
+    - Let {coercedItemValue} be the runtime value of the variable.
+  - Otherwise, if the variable definition provides a default value:
+    - Let {coercedItemValue} be this default value.
+  - Otherwise:
+    - Let {coercedItemValue} be {null}.
+  - If {coercedItemValue} is {null} and {itemType} is a non-null type, a _field
     error_ must be raised.
-  - Return {runtimeValue}.
+  - Return {coercedItemValue}.
 - Otherwise, return the result of coercing {itemValue} according to the input
   coercion rules for {itemType}.
 
+Note: When a default value exists for a variable definition, the type of the
+variable is allowed to be nullable even if it is used in a non-nullable
+position, see
+[Allowing Optional Variables When Default Values Exist](#sec-All-Variable-Usages-Are-Allowed.Allowing-Optional-Variables-When-Default-Values-Exist)
+in Validation. If the value for such a variable is explicitly {null} and is used
+as the value for a list item of non-nullable type then a _field error_ will be
+raised.
+
 Following are examples of input coercion with various list types and values:
 
 | Expected Type | Literal Value    | Variable Values | Coerced Value                |
diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md
index 9d3fcaee5..8efd401a4 100644
--- a/spec/Section 6 -- Execution.md	
+++ b/spec/Section 6 -- Execution.md	
@@ -645,13 +645,6 @@ Note: Variable values are not coerced because they are expected to be coerced
 before executing the operation in {CoerceVariableValues()}, and valid operations
 must only allow usage of variables of appropriate types.
 
-Note: When a default value exists for a variable definition, the type of the
-variable is allowed to be nullable even if it is used in a non-nullable
-position, see
-[Allowing Optional Variables When Default Values Exist](#sec-All-Variable-Usages-Are-Allowed.Allowing-Optional-Variables-When-Default-Values-Exist)
-in Validation. If the value for a variable is explicitly {null} and is used in a
-non-nullable position, a _field error_ will be raised.
-
 ### Value Resolution
 
 While nearly all of GraphQL execution can be described generically, ultimately

From 6aed5a9653a92ada8849fdf6e289623997977436 Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Mon, 13 Nov 2023 09:26:27 +0000
Subject: [PATCH 5/8] Add another example

---
 spec/Section 3 -- Type System.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index 2a1f783fd..7e9663946 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1836,6 +1836,7 @@ Following are examples of input coercion with various list types and values:
 | `[Int!]`      | `[1, $b]`        | `{"b": null}`   | Error: Item must be non-null |
 | `[[Int]]`     | `[[1], [2, 3]]`  | `{}`            | `[[1], [2, 3]]`              |
 | `[[Int]]`     | `[1, 2, 3]`      | `{}`            | `[[1], [2], [3]]`            |
+| `[[Int]]`     | `[1, [2], 3]`    | `{}`            | `[[1], [2], [3]]`            |
 | `[[Int]]`     | `[1, null, 3]`   | `{}`            | `[[1], null, [3]]`           |
 | `[[Int]]`     | `[[1], ["b"]]`   | `{}`            | Error: Incorrect item value  |
 | `[[Int]]`     | `1`              | `{}`            | `[[1]]`                      |

From fba35d54523692c5b112c8fc3c773f50ef402b43 Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 28 Nov 2024 18:14:59 +0000
Subject: [PATCH 6/8] Fix bug in null handling

---
 spec/Section 3 -- Type System.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index 7e9663946..7c07ae64d 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1790,8 +1790,7 @@ CoerceListValue(value, listType):
 
 CoerceListItemValue(itemValue, itemType):
 
-- If {itemValue} is {null}, return {null}.
-- Otherwise, if {itemValue} is a Variable:
+- If {itemValue} is a Variable:
   - If the variable provides a runtime value:
     - Let {coercedItemValue} be the runtime value of the variable.
   - Otherwise, if the variable definition provides a default value:

From 8eaa45ba7bff01359afc2e3b038a1842a0c110e7 Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 23 Jan 2025 17:40:44 +0000
Subject: [PATCH 7/8] Reflect that variable values should already be coerced,
 and thus applying their defaults is redundant.

---
 spec/Section 3 -- Type System.md | 29 +++++++++++++++--------------
 spec/Section 6 -- Execution.md   |  3 +++
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index 7c07ae64d..b9f3f74a6 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1638,9 +1638,9 @@ defined by the input object type and for which a value exists. The resulting map
 is constructed with the following rules:
 
 - If no value is provided for a defined input object field and that field
-  definition provides a default value, the default value should be used. If no
+  definition provides a default value, the default value must be used. If no
   default value is provided and the input object field's type is non-null, an
-  error should be raised. Otherwise, if the field is not required, then no entry
+  error must be raised. Otherwise, if the field is not required, then no entry
   is added to the coerced unordered map.
 
 - If the value {null} was provided for an input object field, and the field's
@@ -1652,12 +1652,17 @@ is constructed with the following rules:
   coerced unordered map is given the result of coercing that value according to
   the input coercion rules for the type of that field.
 
-- If a variable is provided for an input object field, the runtime value of that
-  variable must be used. If the runtime value is {null} and the field type is
-  non-null, a _field error_ must be raised. If no runtime value is provided, the
-  variable definition's default value should be used. If the variable definition
-  does not provide a default value, the input object field definition's default
-  value should be used.
+- If a variable is provided for an input object field:
+
+  - If the _coerced runtime value_ of that variable exists then it must be used.
+    If the coerced runtime value is {null} and the field type is non-null, a
+    _field error_ must be raised.
+
+  - If the _coerced runtime value_ of that variable does not exist then the
+    input object field definition's default value must be used. If no default
+    value is provided and the input object field's type is non-null, an error
+    must be raised. Otherwise, if the field is not required, then no entry is
+    added to the coerced unordered map.
 
 Following are examples of input coercion for an input object type with a
 `String` field `a` and a required (non-null) `Int!` field `b`:
@@ -1791,12 +1796,8 @@ CoerceListValue(value, listType):
 CoerceListItemValue(itemValue, itemType):
 
 - If {itemValue} is a Variable:
-  - If the variable provides a runtime value:
-    - Let {coercedItemValue} be the runtime value of the variable.
-  - Otherwise, if the variable definition provides a default value:
-    - Let {coercedItemValue} be this default value.
-  - Otherwise:
-    - Let {coercedItemValue} be {null}.
+  - Let {coercedItemValue} be the _coerced runtime value_ of that variable, or
+    {null} if no such value exists.
   - If {coercedItemValue} is {null} and {itemType} is a non-null type, a _field
     error_ must be raised.
   - Return {coercedItemValue}.
diff --git a/spec/Section 6 -- Execution.md b/spec/Section 6 -- Execution.md
index 8efd401a4..a51939a41 100644
--- a/spec/Section 6 -- Execution.md	
+++ b/spec/Section 6 -- Execution.md	
@@ -81,6 +81,9 @@ need to be coerced using the input coercion rules of variable's declared type.
 If a _request error_ is encountered during input coercion of variable values,
 then the operation fails without execution.
 
+:: The _coerced runtime value_ of a variable is the entry matching the
+variable's name in the result of {CoerceVariableValues()}, if any.
+
 CoerceVariableValues(schema, operation, variableValues):
 
 - Let {coercedValues} be an empty unordered Map.

From a045f1493352f05570d39b8aa372ef0c5723961d Mon Sep 17 00:00:00 2001
From: Benjie Gillam <benjie@jemjie.com>
Date: Thu, 23 Jan 2025 17:46:39 +0000
Subject: [PATCH 8/8] 'Including null' (copied from section 6)

---
 spec/Section 3 -- Type System.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/spec/Section 3 -- Type System.md b/spec/Section 3 -- Type System.md
index b9f3f74a6..4be232544 100644
--- a/spec/Section 3 -- Type System.md	
+++ b/spec/Section 3 -- Type System.md	
@@ -1654,9 +1654,9 @@ is constructed with the following rules:
 
 - If a variable is provided for an input object field:
 
-  - If the _coerced runtime value_ of that variable exists then it must be used.
-    If the coerced runtime value is {null} and the field type is non-null, a
-    _field error_ must be raised.
+  - If the _coerced runtime value_ of that variable exists (including {null})
+    then it must be used. If the coerced runtime value is {null} and the field
+    type is non-null, a _field error_ must be raised.
 
   - If the _coerced runtime value_ of that variable does not exist then the
     input object field definition's default value must be used. If no default