Skip to content

Conversation

tninesling
Copy link
Contributor

@tninesling tninesling commented Sep 19, 2025

Making mismatch reports more permissive

The TS implementation of reportMismatch and its related variants assumed that we were always working on AST nodes. So, it used the same generic type T for both sources and the destination. In Rust, we often work with position representations which are used to get the AST nodes later on. This means we may have a destination position paired with a list of AST node sources, or we may have an in-memory destination AST node and a set of source positions. This change aims to make it easier to generate mismatch reports from those situations where the types don't exactly match.

Splitting source and destination types

The main change here is the update to the report_mismatch type signature, which now has separate type parameters for source types and destination types.

- fn report_mismatch<T: Display, U>(...)
+ fn report_mismatch<D: Display, S, L>(...)

Instead of the T for type and U for node location, the signature now uses D for destination, S for source, and L for location. This necessitates different functions for the mismatch_accessor, which was previously defined as mismatch_accessor: impl Fn(&T, bool) -> Option<String> where the boolean parameter indicated whether this instance of T was the supergraph element or not. Now, we have two different accessor functions to account for the type difference:

- mismatch_accessor: impl Fn(&T, bool) -> Option<String>
+ supergraph_mismatch_accessor: impl Fn(&D) -> Option<String>,
+ subgraph_mismatch_accessor: impl Fn(&S, usize) -> Option<String>,

Supplying subgraph index to source accessor

The subgraph_mismatch_accessor now receives the subgraph index corresponding to the instance of S you're operating on. This is important when your Sources<&S> contains positions, and you want to access the actual AST nodes from the schema when generating your message.

Removal of ignore predicate

The ignore_predicate for mismatch accessors was almost never used. In the TS source, it was always undefined, except for when our mismatch accessor returned undefined descriptions. This meant we were almost always passing None for this value when using the mismatch reporter, but Rust made us define ugly types for the function we weren't passing (like None::<fn(Option<&DirectiveDefinitionPosition>) -> bool>).

Instead, we skip None outputs from the accessor, since they were being coalesced to empty strings in the messages anyway. This means we avoid the possibility of getting messages like A mismatch was found in , , and while removing the need to write these annoying signatures for the None case.


Checklist

Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.

  • PR description explains the motivation for the change and relevant context for reviewing
  • PR description links appropriate GitHub/Jira tickets (creating when necessary)
  • Changeset is included for user-facing changes
  • Changes are compatible1
  • Documentation2 completed
  • Performance impact assessed and acceptable
  • Metrics and logs are added3 and documented
  • Tests added and passing4
    • Unit tests
    • Integration tests
    • Manual tests, as necessary

Exceptions

Note any exceptions here

Notes

Footnotes

  1. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.

  2. Configuration is an important part of many changes. Where applicable please try to document configuration examples.

  3. A lot of (if not most) features benefit from built-in observability and debug-level logs. Please read this guidance on metrics best-practices.

  4. Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions.

@tninesling tninesling requested review from a team as code owners September 19, 2025 18:11
Copy link
Contributor

@tninesling, please consider creating a changeset entry in /.changesets/. These instructions describe the process and tooling.

@apollo-librarian
Copy link

apollo-librarian bot commented Sep 19, 2025

✅ Docs preview has no changes

The preview was not built because there were no changes.

Build ID: 0e3ae2d0f5dc84897a9aa7de
Build Logs: View logs

@briannafugate408 briannafugate408 self-assigned this Sep 19, 2025
Copy link
Contributor

@briannafugate408 briannafugate408 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had two questions, but overall I appreciate the description. It helped with understanding what was refactored and how we can make mismatch reports more permissive using these new different source and destination types.

},
&directive,
&definition_sources,
|def| Some(format!("\"@{}\"", def.name)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe we can make this into a function to remove redundancy between two lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the idea, but I think it's largely up to stylistic preference. Personally, I'd rather save the couple lines and keep these inlined since they're relatively short.

// determine which one we selected when it's looking through the sources.
pos.insert_directive(&mut self.merged, most_used_directive.clone())?;
self.error_reporter.report_mismatch_hint::<Directive, ()>(
fn print_arguments(elt: &Directive) -> Option<String> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a function that we might be able to expose for additional usages?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, this formatting is fairly specific to this error message. Most other places would use the coordinate format, so I don't think this generalizes

@tninesling tninesling merged commit b5b0927 into dev Sep 24, 2025
15 checks passed
@tninesling tninesling deleted the tninesling/mismatch-reports branch September 24, 2025 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants