Repository: apollographql/apollo-rs
Pull request #674 (2023-10-06 14:14:30)

feat(compiler): improve validation error summary
New error validation error messages for the 0.11.x branch, for use in JSON responses in the router.

The new messages are written so they briefly state what the problem is, not how to solve it, which we mostly already do using `.note()`s. For some messages, it would require work on the validation side to track the information required to improve them. It's intentionally a bit low effort, we can do a more thorough review on the 1.0 branch.

It would in particular be nice to have operation paths for the rule that composite types must have a subselection. Now it only uses the field name which can be ambiguous.

I use strings containing schema coordinates in some places to identify eg. which directive argument or which field is being used, just because they're nicely concise and they give a lot of information.


Patch:
diff --git a/crates/apollo-compiler/CHANGELOG.md b/crates/apollo-compiler/CHANGELOG.md
index 8752efc..03c5d97 100644
--- a/crates/apollo-compiler/CHANGELOG.md
+++ b/crates/apollo-compiler/CHANGELOG.md
@@ -42,7 +42,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 
 # [0.11.3] (unreleased) - 2023-mm-dd
 
-## Fixes
+## Features
 - expose line/column location and JSON format from diagnostics, by [goto-bus-stop] in [pull/668]
 
   You can now use `diagnostic.get_line_column()` to access the line/column number where a validation error occurred.
@@ -62,6 +62,21 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 [pull/668]: https://github.com/apollographql/apollo-rs/pull/668
 [JSON error format]: https://spec.graphql.org/draft/#sec-Errors.Error-Result-Format
 
+- improve validation error summaries, by [goto-bus-stop] in [pull/674]
+
+  Adds more context and a more consistent voice to the "main" message for validation errors. They are now concise,
+  matter-of-fact descriptions of the problem. Information about how to solve the problem is usually already provided
+  by labels and notes on the diagnostic.
+
+  > - operation `getName` is defined multiple times
+  > - interface `NamedEntity` implements itself
+
+  The primary use case for this is to make `diagnostic.data.to_string()` return a useful message for text-only error
+  reports, like in JSON responses. The JSON format for diagnostics uses these new messages.
+
+[goto-bus-stop]: https://github.com/goto-bus-stop
+[pull/674]: https://github.com/apollographql/apollo-rs/pull/674
+
 # [0.11.2](https://crates.io/crates/apollo-compiler/0.11.2) - 2023-09-11
 
 ## Fixes
diff --git a/crates/apollo-compiler/src/diagnostics.rs b/crates/apollo-compiler/src/diagnostics.rs
index f5e360b..25a99ff 100644
--- a/crates/apollo-compiler/src/diagnostics.rs
+++ b/crates/apollo-compiler/src/diagnostics.rs
@@ -164,35 +164,49 @@ pub enum DiagnosticData {
     LimitExceeded { message: String },
     #[error("expected identifier")]
     MissingIdent,
-    #[error("executable documents must not contain {kind}")]
-    ExecutableDefinition { kind: &'static str },
-    #[error("the {ty} `{name}` is defined multiple times in the document")]
+    #[error(
+        "executable documents can only contain executable definitions, {}",
+        name.as_ref().map(|name| format!("but `{name}` is a(n) {kind}"))
+            .unwrap_or_else(|| format!("got {kind}"))
+    )]
+    ExecutableDefinition {
+        name: Option<String>,
+        kind: &'static str,
+    },
+    #[error("{ty} `{name}` is defined multiple times")]
     UniqueDefinition {
         ty: &'static str,
         name: String,
         original_definition: DiagnosticLocation,
         redefined_definition: DiagnosticLocation,
     },
-    #[error("the argument `{name}` is defined multiple times")]
+    #[error("argument `{name}` is defined multiple times")]
     UniqueArgument {
         name: String,
         original_definition: DiagnosticLocation,
         redefined_definition: DiagnosticLocation,
     },
-    #[error("the value `{name}` is defined multiple times")]
+    #[error("value `{name}` is defined multiple times")]
     UniqueInputValue {
         name: String,
         original_value: DiagnosticLocation,
         redefined_value: DiagnosticLocation,
     },
-    #[error("subscription operations can only have one root field")]
+    #[error("enum member `{name}` is defined multiple times in `{coordinate}`")]
+    UniqueEnumValue {
+        name: String,
+        coordinate: String,
+        original_definition: DiagnosticLocation,
+        redefined_definition: DiagnosticLocation,
+    },
+    #[error("subscription operation has multiple root fields")]
     SingleRootField {
         // TODO(goto-bus-stop) if we keep this it should be a vec of the field names or nodes i think.
         // Else just remove as the labeling is done separately.
         fields: usize,
         subscription: DiagnosticLocation,
     },
-    #[error("{ty} root operation type is not defined")]
+    #[error("operation type {ty} is not defined")]
     UnsupportedOperation {
         // current operation type: subscription, mutation, query
         ty: &'static str,
@@ -204,14 +218,14 @@ pub enum DiagnosticData {
         /// Type name being queried
         ty: String,
     },
-    #[error("the argument `{name}` is not supported")]
-    UndefinedArgument { name: String },
-    #[error("cannot find type `{name}` in this document")]
+    #[error("the argument `{name}` is not supported by {coordinate}")]
+    UndefinedArgument { name: String, coordinate: String },
+    #[error("type `{name}` is not defined")]
     UndefinedDefinition {
         /// Name of the type not in scope
         name: String,
     },
-    #[error("cannot find directive `{name}` in this document")]
+    #[error("directive `@{name}` is not defined")]
     UndefinedDirective {
         /// Name of the missing directive
         name: String,
@@ -221,7 +235,7 @@ pub enum DiagnosticData {
         /// Name of the variable not in scope
         name: String,
     },
-    #[error("cannot find fragment `{name}` in this document")]
+    #[error("fragment `{name}` is not defined")]
     UndefinedFragment {
         /// Name of the fragment not in scope
         name: String,
@@ -242,87 +256,93 @@ pub enum DiagnosticData {
         /// Location of the extension
         extension: DiagnosticLocation,
     },
-    #[error("`{name}` directive definition cannot reference itself")]
+    #[error("directive definition `{name}` references itself")]
     RecursiveDirectiveDefinition { name: String },
-    #[error("interface {name} cannot implement itself")]
+    #[error("interface `{name}` implements itself")]
     RecursiveInterfaceDefinition { name: String },
-    #[error("`{name}` input object cannot reference itself")]
+    #[error("input object `{name}` references itself")]
     RecursiveInputObjectDefinition { name: String },
-    #[error("`{name}` fragment cannot reference itself")]
+    #[error("fragment `{name}` references itself")]
     RecursiveFragmentDefinition { name: String },
-    #[error("values in an Enum Definition should be capitalized")]
+    #[error("enum value `{value}` does not have a conventional all-caps name")]
     CapitalizedValue { value: String },
-    #[error("fields must be unique in a definition")]
+    #[error("field `{field}` is declared multiple times")]
     UniqueField {
         /// Name of the non-unique field.
         field: String,
         original_definition: DiagnosticLocation,
         redefined_definition: DiagnosticLocation,
     },
-    #[error("missing `{field}` field")]
+    #[error("type `{name}` does not satisfy interface `{interface}` because it is missing field `{field}`")]
     MissingField {
+        name: String,
+        interface: String,
         // current field that should be defined
         field: String,
     },
-    #[error("the required argument `{name}` is not provided")]
-    RequiredArgument { name: String },
-    #[error("type `{ty}` can only implement interface `{interface}` once")]
+    #[error("required argument `{coordinate}` is not provided")]
+    RequiredArgument { coordinate: String },
+    #[error("type `{ty}` implements interface `{interface}` multiple times")]
     DuplicateImplementsInterface { ty: String, interface: String },
-    #[error(
-        "Transitively implemented interfaces must also be defined on an implementing interface or object"
-    )]
+    // XXX(@goto-bus-stop): This error message would be better if it listed which other interface
+    // is responsible for `missing_interface` being required. It would require code changes in
+    // validation to pass that information on, so not doing it in 0.11.x--we should do it in 1.0 :)
+    #[error("type `{ty}` must implement `{missing_interface}`")]
     TransitiveImplementedInterfaces {
+        /// Name of the affected type
+        ty: String,
         // interface that should be defined
         missing_interface: String,
     },
-    #[error("`{name}` field must return an output type")]
+    #[error("`{name}` field does not return an output type")]
     OutputType {
         // field name
         name: String,
         // field type
         ty: &'static str,
     },
-    #[error("`{name}` field must be of an input type")]
+    #[error("type `{ty}` for input field or argument `{name}` is not an input type")]
     InputType {
         /// Field name.
         name: String,
-        /// The kind of type that the field is declared with.
-        ty: &'static str,
+        /// Declared type.
+        ty: String,
+    },
+    #[error("custom scalar `{ty}` does not have an @specifiedBy directive")]
+    ScalarSpecificationURL {
+        /// Name of the scalar.
+        ty: String,
     },
-    #[error(
-        "custom scalars should provide a scalar specification URL via the @specifiedBy directive"
-    )]
-    ScalarSpecificationURL,
     #[error("missing query root operation type in schema definition")]
     QueryRootOperationType,
     #[error("built-in scalars must be omitted for brevity")]
     BuiltInScalarDefinition,
-    #[error("`${name}` variable must be of an input type")]
+    #[error("type `{ty}` for variable `${name}` is not an input type")]
     VariableInputType {
-        /// Varialbe name.
+        /// Variable name.
         name: String,
-        /// The kind of type that the variable is declared with.
-        ty: &'static str,
+        /// Declared type.
+        ty: String,
     },
-    #[error("unused variable: `{name}`")]
+    #[error("variable `{name}` is unused")]
     UnusedVariable { name: String },
-    #[error("`{name}` field must return an object type")]
+    #[error("field `{name}` does not return an object type")]
     ObjectType {
         // union member
         name: String,
         // actual type
         ty: &'static str,
     },
-    #[error("{name} directive is not supported for {dir_loc} location")]
-    UnsupportedLocation {
-        /// current directive definition
+    #[error("directive `@{name}` can not be used on {dir_loc}")]
+    UnsupportedDirectiveLocation {
+        /// name of the directive
         name: String,
         /// current location where the directive is used
         dir_loc: DirectiveLocation,
         /// The source location where the directive that's being used was defined.
         directive_def: DiagnosticLocation,
     },
-    #[error("{ty} cannot be represented by a {value} value")]
+    #[error("`{value}` cannot be assigned to type `{ty}`")]
     UnsupportedValueType {
         // input value
         value: String,
@@ -341,16 +361,26 @@ pub enum DiagnosticData {
         original_call: DiagnosticLocation,
         conflicting_call: DiagnosticLocation,
     },
-    #[error("subscription operations can not have an introspection field as a root field")]
+    #[error("subscription operation uses introspection field `{field}` as a root field")]
     IntrospectionField {
         /// Name of the field
         field: String,
     },
-    #[error("subselection set for scalar and enum types must be empty")]
-    DisallowedSubselection,
-    #[error("interface, union and object types must have a subselection set")]
-    MissingSubselection,
-    #[error("operation must not select different types using the same field name `{field}`")]
+    #[error("field `{field}` has a subselection but its type `{ty}` is not a composite type")]
+    DisallowedSubselection {
+        /// Name of the field
+        field: String,
+        /// Name of the type
+        ty: String,
+    },
+    #[error("field `{field}` selects a composite type `{ty}` but does not have a subselection")]
+    MissingSubselection {
+        /// Name of the field
+        field: String,
+        /// Name of the type
+        ty: String,
+    },
+    #[error("operation selects different types into the same field name `{field}`")]
     ConflictingField {
         /// Name of the non-unique field.
         field: String,
@@ -362,19 +392,23 @@ pub enum DiagnosticData {
         /// Name of the type on which the fragment is declared
         ty: Option<String>,
     },
-    #[error("fragments can not be declared on primitive types")]
+    #[error("type condition `{ty}` is not a composite type")]
     InvalidFragmentTarget {
         /// Name of the type on which the fragment is declared
         ty: String,
     },
-    #[error("fragment cannot be applied to this type")]
+    #[error(
+        "{} cannot be applied to type `{type_name}`",
+        name.as_ref().map(|name| format!("fragment `{name}`"))
+            .unwrap_or_else(|| "anonymous fragment".to_string()),
+    )]
     InvalidFragmentSpread {
         /// Fragment name or None if it's an inline fragment
         name: Option<String>,
         /// Type name the fragment is being applied to
         type_name: String,
     },
-    #[error("fragment `{name}` must be used in an operation")]
+    #[error("fragment `{name}` is unused")]
     UnusedFragment {
         /// Name of the fragment
         name: String,
@@ -398,7 +432,7 @@ impl DiagnosticData {
         matches!(self, Self::CapitalizedValue { .. })
     }
     pub fn is_advice(&self) -> bool {
-        matches!(self, Self::ScalarSpecificationURL)
+        matches!(self, Self::ScalarSpecificationURL { .. })
     }
 }
 
diff --git a/crates/apollo-compiler/src/validation/directive.rs b/crates/apollo-compiler/src/validation/directive.rs
index fd023e7..113a3ce 100644
--- a/crates/apollo-compiler/src/validation/directive.rs
+++ b/crates/apollo-compiler/src/validation/directive.rs
@@ -204,7 +204,7 @@ pub fn validate_directives(
                 let mut diag = ApolloDiagnostic::new(
                         db,
                         loc.into(),
-                        DiagnosticData::UnsupportedLocation {
+                        DiagnosticData::UnsupportedDirectiveLocation {
                             name: name.into(),
                             dir_loc,
                             directive_def: directive_definition.loc.into(),
@@ -251,6 +251,7 @@ pub fn validate_directives(
                             arg.loc.into(),
                             DiagnosticData::UndefinedArgument {
                                 name: arg.name().into(),
+                                coordinate: format!("@{}", dir.name.src()),
                             },
                         )
                         .label(Label::new(arg.loc, "argument by this name not found"))
@@ -276,7 +277,11 @@ pub fn validate_directives(
                         db,
                         dir.loc.into(),
                         DiagnosticData::RequiredArgument {
-                            name: arg_def.name().into(),
+                            coordinate: format!(
+                                "@{}({}:)",
+                                directive_definition.name(),
+                                arg_def.name()
+                            ),
                         },
                     );
                     diagnostic = diagnostic.label(Label::new(
diff --git a/crates/apollo-compiler/src/validation/enum_.rs b/crates/apollo-compiler/src/validation/enum_.rs
index 57d55e7..e6c7aca 100644
--- a/crates/apollo-compiler/src/validation/enum_.rs
+++ b/crates/apollo-compiler/src/validation/enum_.rs
@@ -58,9 +58,9 @@ pub fn validate_enum_definition(
                 ApolloDiagnostic::new(
                     db,
                     redefined_definition.into(),
-                    DiagnosticData::UniqueDefinition {
-                        ty: "enum value",
+                    DiagnosticData::UniqueEnumValue {
                         name: value.into(),
+                        coordinate: enum_def.name().to_string(),
                         original_definition: original_definition.into(),
                         redefined_definition: redefined_definition.into(),
                     },
diff --git a/crates/apollo-compiler/src/validation/field.rs b/crates/apollo-compiler/src/validation/field.rs
index 97d4923..f7d728f 100644
--- a/crates/apollo-compiler/src/validation/field.rs
+++ b/crates/apollo-compiler/src/validation/field.rs
@@ -58,6 +58,13 @@ pub fn validate_field(
                             arg.loc.into(),
                             DiagnosticData::UndefinedArgument {
                                 name: arg.name().into(),
+                                coordinate: format!(
+                                    "{}.{}",
+                                    // Guaranteed to exist because `field.field_definition()`
+                                    // worked.
+                                    field.parent_obj.as_ref().unwrap(),
+                                    field.name.src(),
+                                ),
                             },
                         )
                         .labels(labels),
@@ -84,7 +91,14 @@ pub fn validate_field(
                     db,
                     field.loc.into(),
                     DiagnosticData::RequiredArgument {
-                        name: arg_def.name().into(),
+                        coordinate: format!(
+                            "{}.{}({}:)",
+                            // Guaranteed to exist as we wouldn't know about the expected arguments
+                            // for this field otherwise.
+                            field.parent_obj.as_ref().unwrap(),
+                            field.name(),
+                            arg_def.name()
+                        ),
                     },
                 );
                 diagnostic = diagnostic.label(Label::new(
@@ -274,11 +288,17 @@ pub fn validate_leaf_field_selection(
                 format!("field `{fname}` type `{tname}` is an interface and must select fields")
             }
             hir::TypeDefinition::UnionTypeDefinition(_) => {
-                format!("field `{fname}` type `{tname}` is an union and must select fields")
+                format!("field `{fname}` type `{tname}` is a union and must select fields")
             }
             _ => return Ok(()),
         };
-        (label, DiagnosticData::MissingSubselection)
+        (
+            label,
+            DiagnosticData::MissingSubselection {
+                field: fname,
+                ty: tname.clone(),
+            },
+        )
     } else {
         let label = match type_def {
             hir::TypeDefinition::EnumTypeDefinition(_) => {
@@ -289,7 +309,13 @@ pub fn validate_leaf_field_selection(
             ),
             _ => return Ok(()),
         };
-        (label, DiagnosticData::DisallowedSubselection)
+        (
+            label,
+            DiagnosticData::DisallowedSubselection {
+                field: fname,
+                ty: tname.clone(),
+            },
+        )
     };
 
     Err(ApolloDiagnostic::new(db, field.loc.into(), diagnostic_data)
diff --git a/crates/apollo-compiler/src/validation/input_object.rs b/crates/apollo-compiler/src/validation/input_object.rs
index d440dc5..20324ef 100644
--- a/crates/apollo-compiler/src/validation/input_object.rs
+++ b/crates/apollo-compiler/src/validation/input_object.rs
@@ -193,7 +193,7 @@ pub fn validate_input_values(
                 diagnostics.push(
                     ApolloDiagnostic::new(db, loc.into(), DiagnosticData::InputType {
                         name: input_value.name().into(),
-                        ty: field_ty.kind(),
+                        ty: input_value.ty().name(),
                     })
                         .label(Label::new(loc, format!("this is of `{}` type", field_ty.kind())))
                         .help(format!("Scalars, Enums, and Input Objects are input types. Change `{}` field to take one of these input types.", input_value.name())),
diff --git a/crates/apollo-compiler/src/validation/interface.rs b/crates/apollo-compiler/src/validation/interface.rs
index 8feb445..cf52dde 100644
--- a/crates/apollo-compiler/src/validation/interface.rs
+++ b/crates/apollo-compiler/src/validation/interface.rs
@@ -132,6 +132,8 @@ pub fn validate_interface_definition(
                         db,
                         interface_def.loc().into(),
                         DiagnosticData::MissingField {
+                            name: interface_def.name().to_string(),
+                            interface: super_interface.name().to_string(),
                             field: name.clone(),
                         },
                     )
@@ -232,6 +234,7 @@ pub fn validate_implements_interfaces(
                 db,
                 loc.into(),
                 DiagnosticData::TransitiveImplementedInterfaces {
+                    ty: implementor_name.clone(),
                     missing_interface: undefined.name.clone(),
                 },
             )
diff --git a/crates/apollo-compiler/src/validation/object.rs b/crates/apollo-compiler/src/validation/object.rs
index e173afc..4390902 100644
--- a/crates/apollo-compiler/src/validation/object.rs
+++ b/crates/apollo-compiler/src/validation/object.rs
@@ -103,6 +103,8 @@ pub fn validate_object_type_definition(
                     db,
                     object.loc().into(),
                     DiagnosticData::MissingField {
+                        name: object.name().to_string(),
+                        interface: interface.name().to_string(),
                         field: name.to_string(),
                     },
                 )
diff --git a/crates/apollo-compiler/src/validation/scalar.rs b/crates/apollo-compiler/src/validation/scalar.rs
index f6ba895..8ad581b 100644
--- a/crates/apollo-compiler/src/validation/scalar.rs
+++ b/crates/apollo-compiler/src/validation/scalar.rs
@@ -35,7 +35,9 @@ pub fn validate_scalar_definition(
                 ApolloDiagnostic::new(
                     db,
                     scalar_def.loc.into(),
-                    DiagnosticData::ScalarSpecificationURL,
+                    DiagnosticData::ScalarSpecificationURL {
+                        ty: scalar_def.name().into(),
+                    },
                 )
                 .label(Label::new(
                     scalar_def.loc,
diff --git a/crates/apollo-compiler/src/validation/validation_db.rs b/crates/apollo-compiler/src/validation/validation_db.rs
index 72c04b3..7f7b95a 100644
--- a/crates/apollo-compiler/src/validation/validation_db.rs
+++ b/crates/apollo-compiler/src/validation/validation_db.rs
@@ -547,7 +547,10 @@ fn validate_executable_inner(
                     ApolloDiagnostic::new(
                         db,
                         (file_id, def.syntax().text_range()).into(),
-                        DiagnosticData::ExecutableDefinition { kind: def.kind() },
+                        DiagnosticData::ExecutableDefinition {
+                            name: def.name().map(|node| node.text().to_string()),
+                            kind: def.kind(),
+                        },
                     )
                     .label(Label::new(
                         (file_id, def.syntax().text_range()),
@@ -636,7 +639,7 @@ query {
         assert_eq!(diagnostics.len(), 1);
         assert_eq!(
             diagnostics[0].data.to_string(),
-            "executable documents must not contain ObjectTypeDefinition"
+            "executable documents can only contain executable definitions, but `Object` is a(n) ObjectTypeDefinition"
         );
         assert_eq!(
             diagnostics[0].get_line_column(),
@@ -670,7 +673,7 @@ fragment q on Query {
         assert_eq!(diagnostics.len(), 1);
         assert_eq!(
             diagnostics[0].data.to_string(),
-            "`q` fragment cannot reference itself"
+            "fragment `q` references itself"
         );
     }
 
@@ -707,7 +710,7 @@ fragment q on TestObject {
         assert_eq!(diagnostics.len(), 1);
         assert_eq!(
             diagnostics[0].data.to_string(),
-            "`q` fragment cannot reference itself"
+            "fragment `q` references itself"
         );
     }
 
@@ -781,10 +784,7 @@ type TestObject {
         );
         let diagnostics = compiler.db.validate_standalone_executable(unused_frag_id);
         assert_eq!(diagnostics.len(), 1);
-        assert_eq!(
-            diagnostics[0].data.to_string(),
-            "fragment `A` must be used in an operation"
-        );
+        assert_eq!(diagnostics[0].data.to_string(), "fragment `A` is unused");
 
         let dupe_frag_id = compiler.add_executable(
             r#"
@@ -798,7 +798,7 @@ type TestObject {
         assert_eq!(diagnostics.len(), 1);
         assert_eq!(
             diagnostics[0].data.to_string(),
-            "the fragment `A` is defined multiple times in the document"
+            "fragment `A` is defined multiple times"
         );
 
         let unknown_frag_id = compiler.add_executable(r#"{ ...A }"#, "unknown_frag.graphql");
@@ -806,7 +806,7 @@ type TestObject {
         assert_eq!(diagnostics.len(), 1);
         assert_eq!(
             diagnostics[0].data.to_string(),
-            "cannot find fragment `A` in this document"
+            "fragment `A` is not defined"
         );
     }
 
diff --git a/crates/apollo-compiler/src/validation/value.rs b/crates/apollo-compiler/src/validation/value.rs
index bd65d59..58be27c 100644
--- a/crates/apollo-compiler/src/validation/value.rs
+++ b/crates/apollo-compiler/src/validation/value.rs
@@ -243,7 +243,7 @@ pub fn value_of_correct_type(
                                 db,
                                 val.loc().into(),
                                 DiagnosticData::RequiredArgument {
-                                    name: f.name().into(),
+                                    coordinate: format!("{}.{}", input_obj.name(), f.name()),
                                 },
                             );
                             diagnostic = diagnostic.label(Label::new(
diff --git a/crates/apollo-compiler/src/validation/variable.rs b/crates/apollo-compiler/src/validation/variable.rs
index 0138296..9c73af8 100644
--- a/crates/apollo-compiler/src/validation/variable.rs
+++ b/crates/apollo-compiler/src/validation/variable.rs
@@ -35,8 +35,8 @@ pub fn validate_variable_definitions(
                     let ty_name = type_def.kind();
                     diagnostics.push(
                     ApolloDiagnostic::new(db, variable.loc().into(), DiagnosticData::VariableInputType {
-                        name: variable.name().into(),
-                        ty: ty_name,
+                        name: variable.name().to_string(),
+                        ty: type_def.name().to_string(),
                     })
                     .label(Label::new(ty.loc().unwrap(), format!("this is of `{ty_name}` type")))
                     .help("objects, unions, and interfaces cannot be used because variables can only be of input type"),


Test patch:
diff --git a/crates/apollo-compiler/test_data/diagnostics/0003_anonymous_and_named_operation.txt b/crates/apollo-compiler/test_data/diagnostics/0003_anonymous_and_named_operation.txt
index b43a432..f9f28e0 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0003_anonymous_and_named_operation.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0003_anonymous_and_named_operation.txt
@@ -93,7 +93,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "name",
+            coordinate: "Mutation.addPet(name:)",
         },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0017_schema_with_unspecified_scalar.txt b/crates/apollo-compiler/test_data/diagnostics/0017_schema_with_unspecified_scalar.txt
index e9c68a6..6ad01a9 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0017_schema_with_unspecified_scalar.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0017_schema_with_unspecified_scalar.txt
@@ -24,6 +24,8 @@
             },
         ],
         help: None,
-        data: ScalarSpecificationURL,
+        data: ScalarSpecificationURL {
+            ty: "URL",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0018_schema_with_specified_scalar_missing_values.txt b/crates/apollo-compiler/test_data/diagnostics/0018_schema_with_specified_scalar_missing_values.txt
index f868b50..e96fc93 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0018_schema_with_specified_scalar_missing_values.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0018_schema_with_specified_scalar_missing_values.txt
@@ -24,6 +24,8 @@
             },
         ],
         help: None,
-        data: ScalarSpecificationURL,
+        data: ScalarSpecificationURL {
+            ty: "URL",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0019_enum_definition_with_duplicate_values.txt b/crates/apollo-compiler/test_data/diagnostics/0019_enum_definition_with_duplicate_values.txt
index cca3c5c..48d1459 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0019_enum_definition_with_duplicate_values.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0019_enum_definition_with_duplicate_values.txt
@@ -36,9 +36,9 @@
         help: Some(
             "CAT must only be defined once in this enum.",
         ),
-        data: UniqueDefinition {
-            ty: "enum value",
+        data: UniqueEnumValue {
             name: "CAT",
+            coordinate: "Pet",
             original_definition: DiagnosticLocation {
                 file_id: FileId {
                     id: 19,
@@ -92,9 +92,9 @@
         help: Some(
             "THRIVE_PET_FOODS must only be defined once in this enum.",
         ),
-        data: UniqueDefinition {
-            ty: "enum value",
+        data: UniqueEnumValue {
             name: "THRIVE_PET_FOODS",
+            coordinate: "Snack",
             original_definition: DiagnosticLocation {
                 file_id: FileId {
                     id: 19,
diff --git a/crates/apollo-compiler/test_data/diagnostics/0025_interface_definition_with_missing_transitive_fields.txt b/crates/apollo-compiler/test_data/diagnostics/0025_interface_definition_with_missing_transitive_fields.txt
index 40cac53..b6be07b 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0025_interface_definition_with_missing_transitive_fields.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0025_interface_definition_with_missing_transitive_fields.txt
@@ -37,6 +37,8 @@
             "An interface must be a super-set of all interfaces it implements",
         ),
         data: MissingField {
+            name: "Image",
+            interface: "Resource",
             field: "width",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0026_interface_definition_with_missing_implemetns_interface.txt b/crates/apollo-compiler/test_data/diagnostics/0026_interface_definition_with_missing_implemetns_interface.txt
index a95923e..242d757 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0026_interface_definition_with_missing_implemetns_interface.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0026_interface_definition_with_missing_implemetns_interface.txt
@@ -25,6 +25,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "Image",
             missing_interface: "Node",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0028_interface_definition_with_missing_fields_implements_intrefaces_undefined_interfaces.txt b/crates/apollo-compiler/test_data/diagnostics/0028_interface_definition_with_missing_fields_implements_intrefaces_undefined_interfaces.txt
index d7b65f9..56a3ad4 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0028_interface_definition_with_missing_fields_implements_intrefaces_undefined_interfaces.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0028_interface_definition_with_missing_fields_implements_intrefaces_undefined_interfaces.txt
@@ -37,6 +37,8 @@
             "An interface must be a super-set of all interfaces it implements",
         ),
         data: MissingField {
+            name: "Image",
+            interface: "Resource",
             field: "width",
         },
     },
@@ -66,6 +68,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "Image",
             missing_interface: "Node",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0034_object_type_definition_with_missing_transitive_fields.txt b/crates/apollo-compiler/test_data/diagnostics/0034_object_type_definition_with_missing_transitive_fields.txt
index 6251382..8b20714 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0034_object_type_definition_with_missing_transitive_fields.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0034_object_type_definition_with_missing_transitive_fields.txt
@@ -37,6 +37,8 @@
             "An object must provide all fields required by the interfaces it implements",
         ),
         data: MissingField {
+            name: "Query",
+            interface: "Node",
             field: "id",
         },
     },
@@ -78,6 +80,8 @@
             "An object must provide all fields required by the interfaces it implements",
         ),
         data: MissingField {
+            name: "Query",
+            interface: "Resource",
             field: "width",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0035_object_type_definition_with_missing_implements_interfaces_definition.txt b/crates/apollo-compiler/test_data/diagnostics/0035_object_type_definition_with_missing_implements_interfaces_definition.txt
index a21b35f..5219dcf 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0035_object_type_definition_with_missing_implements_interfaces_definition.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0035_object_type_definition_with_missing_implements_interfaces_definition.txt
@@ -25,6 +25,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "Query",
             missing_interface: "Resource",
         },
     },
@@ -54,6 +55,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "Image",
             missing_interface: "Node",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0042_mutation_operation_with_undefined_fields.txt b/crates/apollo-compiler/test_data/diagnostics/0042_mutation_operation_with_undefined_fields.txt
index 266e05b..bed7e94 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0042_mutation_operation_with_undefined_fields.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0042_mutation_operation_with_undefined_fields.txt
@@ -28,7 +28,7 @@
         ),
         data: InputType {
             name: "petType",
-            ty: "UnionTypeDefinition",
+            ty: "PetType",
         },
     },
     ApolloDiagnostic {
diff --git a/crates/apollo-compiler/test_data/diagnostics/0050_directives_in_invalid_locations.txt b/crates/apollo-compiler/test_data/diagnostics/0050_directives_in_invalid_locations.txt
index 31d1eaf..fa0f3d8 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0050_directives_in_invalid_locations.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0050_directives_in_invalid_locations.txt
@@ -26,7 +26,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "skip",
             dir_loc: Interface,
             directive_def: DiagnosticLocation {
@@ -75,7 +75,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveB",
             dir_loc: FieldDefinition,
             directive_def: DiagnosticLocation {
@@ -114,7 +114,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "include",
             dir_loc: InputObject,
             directive_def: DiagnosticLocation {
@@ -153,7 +153,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "include",
             dir_loc: InputFieldDefinition,
             directive_def: DiagnosticLocation {
@@ -202,7 +202,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveB",
             dir_loc: Union,
             directive_def: DiagnosticLocation {
@@ -251,7 +251,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveA",
             dir_loc: Enum,
             directive_def: DiagnosticLocation {
@@ -300,7 +300,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveA",
             dir_loc: EnumValue,
             directive_def: DiagnosticLocation {
@@ -339,7 +339,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "deprecated",
             dir_loc: Object,
             directive_def: DiagnosticLocation {
@@ -378,7 +378,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "specifiedBy",
             dir_loc: ArgumentDefinition,
             directive_def: DiagnosticLocation {
@@ -417,7 +417,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "include",
             dir_loc: Schema,
             directive_def: DiagnosticLocation {
@@ -466,7 +466,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveB",
             dir_loc: Scalar,
             directive_def: DiagnosticLocation {
@@ -505,7 +505,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "skip",
             dir_loc: VariableDefinition,
             directive_def: DiagnosticLocation {
@@ -544,7 +544,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "skip",
             dir_loc: Query,
             directive_def: DiagnosticLocation {
@@ -583,7 +583,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "deprecated",
             dir_loc: Field,
             directive_def: DiagnosticLocation {
@@ -632,7 +632,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveB",
             dir_loc: FragmentSpread,
             directive_def: DiagnosticLocation {
@@ -681,7 +681,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveB",
             dir_loc: FragmentDefinition,
             directive_def: DiagnosticLocation {
@@ -730,7 +730,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveA",
             dir_loc: InlineFragment,
             directive_def: DiagnosticLocation {
@@ -779,7 +779,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "directiveA",
             dir_loc: Subscription,
             directive_def: DiagnosticLocation {
@@ -818,7 +818,7 @@
         help: Some(
             "the directive must be used in a location that the service has declared support for",
         ),
-        data: UnsupportedLocation {
+        data: UnsupportedDirectiveLocation {
             name: "skip",
             dir_loc: Mutation,
             directive_def: DiagnosticLocation {
diff --git a/crates/apollo-compiler/test_data/diagnostics/0053_argument_name_is_not_defined.txt b/crates/apollo-compiler/test_data/diagnostics/0053_argument_name_is_not_defined.txt
index 3563d13..bb168a7 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0053_argument_name_is_not_defined.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0053_argument_name_is_not_defined.txt
@@ -36,6 +36,7 @@
         help: None,
         data: UndefinedArgument {
             name: "arg2",
+            coordinate: "Field.field",
         },
     },
     ApolloDiagnostic {
@@ -75,6 +76,7 @@
         help: None,
         data: UndefinedArgument {
             name: "arg3",
+            coordinate: "Field.field",
         },
     },
     ApolloDiagnostic {
@@ -114,6 +116,7 @@
         help: None,
         data: UndefinedArgument {
             name: "arg2",
+            coordinate: "Query.field",
         },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0054_argument_not_provided.txt b/crates/apollo-compiler/test_data/diagnostics/0054_argument_not_provided.txt
index a65afa6..effa133 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0054_argument_not_provided.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0054_argument_not_provided.txt
@@ -35,7 +35,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req1",
+            coordinate: "ComplicatedArgs.multipleReqs(req1:)",
         },
     },
     ApolloDiagnostic {
@@ -74,7 +74,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req2",
+            coordinate: "ComplicatedArgs.multipleReqs(req2:)",
         },
     },
     ApolloDiagnostic {
@@ -168,7 +168,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req1",
+            coordinate: "ComplicatedArgs.multipleReqs(req1:)",
         },
     },
     ApolloDiagnostic {
@@ -207,7 +207,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "if",
+            coordinate: "@skip(if:)",
         },
     },
     ApolloDiagnostic {
@@ -246,7 +246,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "if",
+            coordinate: "@include(if:)",
         },
     },
     ApolloDiagnostic {
@@ -286,6 +286,7 @@
         help: None,
         data: UndefinedArgument {
             name: "wrong",
+            coordinate: "@include",
         },
     },
     ApolloDiagnostic {
@@ -324,7 +325,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req1",
+            coordinate: "ComplicatedArgs.multipleReqs(req1:)",
         },
     },
     ApolloDiagnostic {
@@ -363,7 +364,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req2",
+            coordinate: "ComplicatedArgs.multipleOptAndReq(req2:)",
         },
     },
     ApolloDiagnostic {
@@ -402,7 +403,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req2",
+            coordinate: "ComplicatedArgs.multipleOptAndReq(req2:)",
         },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0056_variables_are_input_types.txt b/crates/apollo-compiler/test_data/diagnostics/0056_variables_are_input_types.txt
index dc6b362..c50d8fc 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0056_variables_are_input_types.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0056_variables_are_input_types.txt
@@ -28,7 +28,7 @@
         ),
         data: VariableInputType {
             name: "cat",
-            ty: "ObjectTypeDefinition",
+            ty: "Cat",
         },
     },
     ApolloDiagnostic {
@@ -100,7 +100,7 @@
         ),
         data: VariableInputType {
             name: "dog",
-            ty: "ObjectTypeDefinition",
+            ty: "Dog",
         },
     },
     ApolloDiagnostic {
@@ -172,7 +172,7 @@
         ),
         data: VariableInputType {
             name: "pets",
-            ty: "InterfaceTypeDefinition",
+            ty: "Pet",
         },
     },
     ApolloDiagnostic {
@@ -244,7 +244,7 @@
         ),
         data: VariableInputType {
             name: "catOrDog",
-            ty: "UnionTypeDefinition",
+            ty: "CatOrDog",
         },
     },
     ApolloDiagnostic {
diff --git a/crates/apollo-compiler/test_data/diagnostics/0065_subselection_of_enum.txt b/crates/apollo-compiler/test_data/diagnostics/0065_subselection_of_enum.txt
index cdb1927..07326f8 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0065_subselection_of_enum.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0065_subselection_of_enum.txt
@@ -34,7 +34,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "pet1",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -71,7 +74,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "pet2",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -108,7 +114,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "pet3",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -145,7 +154,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "pet4",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -182,7 +194,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "pet5",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -219,6 +234,9 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "pet6",
+            ty: "Pet",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0066_subselection_of_scalar.txt b/crates/apollo-compiler/test_data/diagnostics/0066_subselection_of_scalar.txt
index 3b6bae9..bf5f621 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0066_subselection_of_scalar.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0066_subselection_of_scalar.txt
@@ -34,7 +34,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "url1",
+            ty: "URL",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -71,7 +74,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "url2",
+            ty: "URL",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -108,7 +114,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "url3",
+            ty: "URL",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -145,7 +154,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "url4",
+            ty: "URL",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -182,7 +194,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "url5",
+            ty: "URL",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -219,6 +234,9 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "url6",
+            ty: "URL",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0067_subselection_of_interface.txt b/crates/apollo-compiler/test_data/diagnostics/0067_subselection_of_interface.txt
index 16a4815..4bb7dda 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0067_subselection_of_interface.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0067_subselection_of_interface.txt
@@ -34,7 +34,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet1",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -71,7 +74,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet2",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -108,7 +114,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet3",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -145,7 +154,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet4",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -182,7 +194,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet5",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -219,6 +234,9 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet6",
+            ty: "Pet",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0068_subselection_of_union.txt b/crates/apollo-compiler/test_data/diagnostics/0068_subselection_of_union.txt
index 8956015..153efc7 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0068_subselection_of_union.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0068_subselection_of_union.txt
@@ -20,7 +20,7 @@
                     offset: 27,
                     length: 4,
                 },
-                text: "field `pet1` type `CatOrDog` is an union and must select fields",
+                text: "field `pet1` type `CatOrDog` is a union and must select fields",
             },
             Label {
                 location: DiagnosticLocation {
@@ -34,7 +34,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet1",
+            ty: "CatOrDog",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -57,7 +60,7 @@
                     offset: 34,
                     length: 4,
                 },
-                text: "field `pet2` type `CatOrDog` is an union and must select fields",
+                text: "field `pet2` type `CatOrDog` is a union and must select fields",
             },
             Label {
                 location: DiagnosticLocation {
@@ -71,7 +74,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet2",
+            ty: "CatOrDog",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -94,7 +100,7 @@
                     offset: 41,
                     length: 4,
                 },
-                text: "field `pet3` type `CatOrDog` is an union and must select fields",
+                text: "field `pet3` type `CatOrDog` is a union and must select fields",
             },
             Label {
                 location: DiagnosticLocation {
@@ -108,7 +114,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet3",
+            ty: "CatOrDog",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -131,7 +140,7 @@
                     offset: 48,
                     length: 4,
                 },
-                text: "field `pet4` type `CatOrDog` is an union and must select fields",
+                text: "field `pet4` type `CatOrDog` is a union and must select fields",
             },
             Label {
                 location: DiagnosticLocation {
@@ -145,7 +154,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet4",
+            ty: "CatOrDog",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -168,7 +180,7 @@
                     offset: 55,
                     length: 4,
                 },
-                text: "field `pet5` type `CatOrDog` is an union and must select fields",
+                text: "field `pet5` type `CatOrDog` is a union and must select fields",
             },
             Label {
                 location: DiagnosticLocation {
@@ -182,7 +194,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet5",
+            ty: "CatOrDog",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -205,7 +220,7 @@
                     offset: 62,
                     length: 4,
                 },
-                text: "field `pet6` type `CatOrDog` is an union and must select fields",
+                text: "field `pet6` type `CatOrDog` is a union and must select fields",
             },
             Label {
                 location: DiagnosticLocation {
@@ -219,6 +234,9 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet6",
+            ty: "CatOrDog",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0069_subselection_of_object.txt b/crates/apollo-compiler/test_data/diagnostics/0069_subselection_of_object.txt
index 87c0f5b..a53ea46 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0069_subselection_of_object.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0069_subselection_of_object.txt
@@ -34,7 +34,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet1",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -71,7 +74,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet2",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -108,7 +114,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet3",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -145,7 +154,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet4",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -182,7 +194,10 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet5",
+            ty: "Pet",
+        },
     },
     ApolloDiagnostic {
         cache: {
@@ -219,6 +234,9 @@
             },
         ],
         help: None,
-        data: MissingSubselection,
+        data: MissingSubselection {
+            field: "pet6",
+            ty: "Pet",
+        },
     },
 ]
diff --git a/crates/apollo-compiler/test_data/diagnostics/0087_fragment_type_condition_on_composite_types.txt b/crates/apollo-compiler/test_data/diagnostics/0087_fragment_type_condition_on_composite_types.txt
index 23bea64..5bf1b21 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0087_fragment_type_condition_on_composite_types.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0087_fragment_type_condition_on_composite_types.txt
@@ -34,7 +34,10 @@
             },
         ],
         help: None,
-        data: DisallowedSubselection,
+        data: DisallowedSubselection {
+            field: "price",
+            ty: "Int",
+        },
     },
     ApolloDiagnostic {
         cache: {
diff --git a/crates/apollo-compiler/test_data/diagnostics/0091_recursive_interface_definition.txt b/crates/apollo-compiler/test_data/diagnostics/0091_recursive_interface_definition.txt
index 8ea6d3e..a0b54fe 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0091_recursive_interface_definition.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0091_recursive_interface_definition.txt
@@ -25,6 +25,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "A",
             missing_interface: "A",
         },
     },
@@ -54,6 +55,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "B",
             missing_interface: "B",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0093_fragment_validation_with_recursive_type_system.txt b/crates/apollo-compiler/test_data/diagnostics/0093_fragment_validation_with_recursive_type_system.txt
index 6b831d2..4369f2e 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0093_fragment_validation_with_recursive_type_system.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0093_fragment_validation_with_recursive_type_system.txt
@@ -25,6 +25,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "A",
             missing_interface: "A",
         },
     },
@@ -54,6 +55,7 @@
         ],
         help: None,
         data: TransitiveImplementedInterfaces {
+            ty: "B",
             missing_interface: "B",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0094_object_type_extensions.txt b/crates/apollo-compiler/test_data/diagnostics/0094_object_type_extensions.txt
index dbf33db..c1e64ce 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0094_object_type_extensions.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0094_object_type_extensions.txt
@@ -240,6 +240,8 @@
             "An object must provide all fields required by the interfaces it implements",
         ),
         data: MissingField {
+            name: "ImplementsBaseButNotExtension",
+            interface: "ExtendedInterface",
             field: "fail",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0097_enum_extensions.txt b/crates/apollo-compiler/test_data/diagnostics/0097_enum_extensions.txt
index 4dc229b..e5f52a9 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0097_enum_extensions.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0097_enum_extensions.txt
@@ -89,9 +89,9 @@
         help: Some(
             "MEMBER_2 must only be defined once in this enum.",
         ),
-        data: UniqueDefinition {
-            ty: "enum value",
+        data: UniqueEnumValue {
             name: "MEMBER_2",
+            coordinate: "E",
             original_definition: DiagnosticLocation {
                 file_id: FileId {
                     id: 94,
@@ -145,9 +145,9 @@
         help: Some(
             "MEMBER_4 must only be defined once in this enum.",
         ),
-        data: UniqueDefinition {
-            ty: "enum value",
+        data: UniqueEnumValue {
             name: "MEMBER_4",
+            coordinate: "E",
             original_definition: DiagnosticLocation {
                 file_id: FileId {
                     id: 94,
diff --git a/crates/apollo-compiler/test_data/diagnostics/0098_interface_extensions.txt b/crates/apollo-compiler/test_data/diagnostics/0098_interface_extensions.txt
index 05f8e0b..09e7c84 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0098_interface_extensions.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0098_interface_extensions.txt
@@ -145,6 +145,8 @@
             "An interface must be a super-set of all interfaces it implements",
         ),
         data: MissingField {
+            name: "Derived",
+            interface: "Base",
             field: "b",
         },
     },
diff --git a/crates/apollo-compiler/test_data/diagnostics/0102_invalid_string_values.txt b/crates/apollo-compiler/test_data/diagnostics/0102_invalid_string_values.txt
index 26dbc4d..74cb26d 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0102_invalid_string_values.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0102_invalid_string_values.txt
@@ -1164,7 +1164,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req2",
+            coordinate: "ComplicatedArgs.multipleReqs(req2:)",
         },
     },
     ApolloDiagnostic {
@@ -1243,7 +1243,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req1",
+            coordinate: "ComplicatedArgs.multipleReqs(req1:)",
         },
     },
     ApolloDiagnostic {
@@ -1282,7 +1282,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "req2",
+            coordinate: "ComplicatedArgs.multipleReqs(req2:)",
         },
     },
     ApolloDiagnostic {
@@ -1321,7 +1321,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "requiredField",
+            coordinate: "ComplexInput.requiredField",
         },
     },
     ApolloDiagnostic {
@@ -1590,7 +1590,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "requiredField",
+            coordinate: "ComplexInput.requiredField",
         },
     },
     ApolloDiagnostic {
@@ -1829,7 +1829,7 @@
         ],
         help: None,
         data: RequiredArgument {
-            name: "requiredField",
+            coordinate: "ComplexInput.requiredField",
         },
     },
     ApolloDiagnostic {
diff --git a/crates/apollo-compiler/test_data/diagnostics/0103_invalid_type_in_arg.txt b/crates/apollo-compiler/test_data/diagnostics/0103_invalid_type_in_arg.txt
index 8560f4b..7b49cdf 100644
--- a/crates/apollo-compiler/test_data/diagnostics/0103_invalid_type_in_arg.txt
+++ b/crates/apollo-compiler/test_data/diagnostics/0103_invalid_type_in_arg.txt
@@ -28,7 +28,7 @@
         ),
         data: InputType {
             name: "thisIsWrong",
-            ty: "ObjectTypeDefinition",
+            ty: "OutputType",
         },
     },
     ApolloDiagnostic {
@@ -118,7 +118,7 @@
         ),
         data: InputType {
             name: "a",
-            ty: "ObjectTypeDefinition",
+            ty: "OutputType",
         },
     },
     ApolloDiagnostic {
@@ -150,7 +150,7 @@
         ),
         data: InputType {
             name: "b",
-            ty: "UnionTypeDefinition",
+            ty: "OperationResult",
         },
     },
 ]