Skip to content

Commit

Permalink
Minimal repro of S488223
Browse files Browse the repository at this point in the history
Reviewed By: lynnshaoyu

Differential Revision: D69484406

fbshipit-source-id: 9bf41b6908ec80f8d6daf0c1bd12dc952ac56734
  • Loading branch information
captbaritone authored and facebook-github-bot committed Feb 12, 2025
1 parent 134aea4 commit aeaac5f
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
==================================== INPUT ====================================
# expected-to-throw

fragment FragmentC on User {
url(relative: true, site: $varX)
nearest_neighbor {
...FragmentD
}
}

fragment FragmentD on User {
url(relative: true, site: $varY)
...FragmentC
}

query QueryA($varX: String, $varY: String) {
me {
# By visiting FragmentC first, we incorrectly end up recording that
# FragmentD has only reads its own variable ($varY) and omit that it
# transitively reads $varX via its spread of FragmentC

# When we traverse into FragmentC we initialize the cache for FragmentC with
# an empty set of variables. We then traverse into FragmentD which
# initializes the cache with an empty set of variables for FragmentD.
#
# FragmentD then records its own read of $varY, and attempts to traverse
# into FragmentC. Here we hit the empty initialized cache for FragmentC. As
# a result we _incorrectly_ treat the used variables for FragmentD as just:
# $varY.
#
# We now pop back up to FragmentC which correctly records its read variables
# as $varX and $varY, and the dependencies for QueryA are correctly validated.
#
# BUT! We've left behind an invalid cache record for FragmentD.
...FragmentC
}
}

query QueryB($varX: String, $varY: String) {
me {
# Now as we traverse into FragmentD we get a cache hit (the invalid one left
# behind by our traversal of QueryA) and incorrectly conclude FragmentD only
# read $varY, and _incorrectly_ report $varX as unused by QueryB.
...FragmentD
}
}
==================================== ERROR ====================================
✖︎ Variable `$varX` is never used in operation `QueryB`

cycle-bug.graphql:38:14
37 │
38 │ query QueryB($varX: String, $varY: String) {
│ ^^^^^
39 │ me {
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# expected-to-throw

fragment FragmentC on User {
url(relative: true, site: $varX)
nearest_neighbor {
...FragmentD
}
}

fragment FragmentD on User {
url(relative: true, site: $varY)
...FragmentC
}

query QueryA($varX: String, $varY: String) {
me {
# By visiting FragmentC first, we incorrectly end up recording that
# FragmentD has only reads its own variable ($varY) and omit that it
# transitively reads $varX via its spread of FragmentC

# When we traverse into FragmentC we initialize the cache for FragmentC with
# an empty set of variables. We then traverse into FragmentD which
# initializes the cache with an empty set of variables for FragmentD.
#
# FragmentD then records its own read of $varY, and attempts to traverse
# into FragmentC. Here we hit the empty initialized cache for FragmentC. As
# a result we _incorrectly_ treat the used variables for FragmentD as just:
# $varY.
#
# We now pop back up to FragmentC which correctly records its read variables
# as $varX and $varY, and the dependencies for QueryA are correctly validated.
#
# BUT! We've left behind an invalid cache record for FragmentD.
...FragmentC
}
}

query QueryB($varX: String, $varY: String) {
me {
# Now as we traverse into FragmentD we get a cache hit (the invalid one left
# behind by our traversal of QueryA) and incorrectly conclude FragmentD only
# read $varY, and _incorrectly_ report $varX as unused by QueryB.
...FragmentD
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<2d9c78832993b2bbe4c580b22d0aeecf>>
* @generated SignedSource<<129140cf3a271d88276cfcac0046937b>>
*/

mod validate_unused_variables;

use validate_unused_variables::transform_fixture;
use fixture_tests::test_fixture;

#[tokio::test]
async fn cycle_bug() {
let input = include_str!("validate_unused_variables/fixtures/cycle-bug.graphql");
let expected = include_str!("validate_unused_variables/fixtures/cycle-bug.expected");
test_fixture(transform_fixture, file!(), "cycle-bug.graphql", "validate_unused_variables/fixtures/cycle-bug.expected", input, expected).await;
}

#[tokio::test]
async fn fragment_with_root_arguments() {
let input = include_str!("validate_unused_variables/fixtures/fragment-with-root-arguments.graphql");
Expand Down

0 comments on commit aeaac5f

Please sign in to comment.