From 853c92a0b7d2b17375134fe7b879acc59d89337c Mon Sep 17 00:00:00 2001
From: Magnus Hallin <mhallin@fastmail.com>
Date: Wed, 28 Dec 2016 18:54:09 +0100
Subject: [PATCH] Use borrowed string references in all AST nodes

---
 src/ast.rs                                    | 78 +++++++++----------
 src/executor.rs                               |  6 +-
 src/parser/document.rs                        | 44 +++++------
 src/parser/tests/document.rs                  |  8 +-
 src/types/base.rs                             | 18 ++---
 src/validation/context.rs                     |  6 +-
 src/validation/input_value.rs                 |  4 +-
 src/validation/multi_visitor.rs               |  8 +-
 .../rules/arguments_of_correct_type.rs        |  2 +-
 .../rules/default_values_of_correct_type.rs   |  2 +-
 src/validation/rules/known_argument_names.rs  |  2 +-
 src/validation/rules/known_type_names.rs      |  2 +-
 src/validation/rules/no_fragment_cycles.rs    |  2 +-
 .../rules/no_undefined_variables.rs           |  6 +-
 src/validation/rules/no_unused_fragments.rs   |  2 +-
 src/validation/rules/no_unused_variables.rs   | 12 +--
 .../rules/overlapping_fields_can_be_merged.rs |  8 +-
 .../rules/possible_fragment_spreads.rs        |  2 +-
 src/validation/rules/unique_argument_names.rs |  2 +-
 src/validation/rules/unique_variable_names.rs |  2 +-
 .../rules/variables_are_input_types.rs        |  2 +-
 .../rules/variables_in_allowed_position.rs    |  8 +-
 src/validation/test_harness.rs                | 10 +--
 src/validation/traits.rs                      |  8 +-
 src/validation/visitor.rs                     |  4 +-
 25 files changed, 121 insertions(+), 127 deletions(-)

diff --git a/src/ast.rs b/src/ast.rs
index 908e910b..8d96b9ba 100644
--- a/src/ast.rs
+++ b/src/ast.rs
@@ -55,35 +55,35 @@ pub struct VariableDefinition<'a> {
 }
 
 #[derive(Clone, PartialEq, Debug)]
-pub struct Arguments {
-    pub items: Vec<(Spanning<String>, Spanning<InputValue>)>,
+pub struct Arguments<'a> {
+    pub items: Vec<(Spanning<&'a str>, Spanning<InputValue>)>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
 pub struct VariableDefinitions<'a> {
-    pub items: Vec<(Spanning<String>, VariableDefinition<'a>)>,
+    pub items: Vec<(Spanning<&'a str>, VariableDefinition<'a>)>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
-pub struct Field {
-    pub alias: Option<Spanning<String>>,
-    pub name: Spanning<String>,
-    pub arguments: Option<Spanning<Arguments>>,
-    pub directives: Option<Vec<Spanning<Directive>>>,
-    pub selection_set: Option<Vec<Selection>>,
+pub struct Field<'a> {
+    pub alias: Option<Spanning<&'a str>>,
+    pub name: Spanning<&'a str>,
+    pub arguments: Option<Spanning<Arguments<'a>>>,
+    pub directives: Option<Vec<Spanning<Directive<'a>>>>,
+    pub selection_set: Option<Vec<Selection<'a>>>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
-pub struct FragmentSpread {
-    pub name: Spanning<String>,
-    pub directives: Option<Vec<Spanning<Directive>>>,
+pub struct FragmentSpread<'a> {
+    pub name: Spanning<&'a str>,
+    pub directives: Option<Vec<Spanning<Directive<'a>>>>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
-pub struct InlineFragment {
-    pub type_condition: Option<Spanning<String>>,
-    pub directives: Option<Vec<Spanning<Directive>>>,
-    pub selection_set: Vec<Selection>,
+pub struct InlineFragment<'a> {
+    pub type_condition: Option<Spanning<&'a str>>,
+    pub directives: Option<Vec<Spanning<Directive<'a>>>>,
+    pub selection_set: Vec<Selection<'a>>,
 }
 
 /// Entry in a GraphQL selection set
@@ -103,16 +103,16 @@ pub struct InlineFragment {
 /// ```
 #[derive(Clone, PartialEq, Debug)]
 #[allow(missing_docs)]
-pub enum Selection {
-    Field(Spanning<Field>),
-    FragmentSpread(Spanning<FragmentSpread>),
-    InlineFragment(Spanning<InlineFragment>),
+pub enum Selection<'a> {
+    Field(Spanning<Field<'a>>),
+    FragmentSpread(Spanning<FragmentSpread<'a>>),
+    InlineFragment(Spanning<InlineFragment<'a>>),
 }
 
 #[derive(Clone, PartialEq, Debug)]
-pub struct Directive {
-    pub name: Spanning<String>,
-    pub arguments: Option<Spanning<Arguments>>,
+pub struct Directive<'a> {
+    pub name: Spanning<&'a str>,
+    pub arguments: Option<Spanning<Arguments<'a>>>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
@@ -124,24 +124,24 @@ pub enum OperationType {
 #[derive(Clone, PartialEq, Debug)]
 pub struct Operation<'a> {
     pub operation_type: OperationType,
-    pub name: Option<Spanning<String>>,
+    pub name: Option<Spanning<&'a str>>,
     pub variable_definitions: Option<Spanning<VariableDefinitions<'a>>>,
-    pub directives: Option<Vec<Spanning<Directive>>>,
-    pub selection_set: Vec<Selection>,
+    pub directives: Option<Vec<Spanning<Directive<'a>>>>,
+    pub selection_set: Vec<Selection<'a>>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
-pub struct Fragment {
-    pub name: Spanning<String>,
-    pub type_condition: Spanning<String>,
-    pub directives: Option<Vec<Spanning<Directive>>>,
-    pub selection_set: Vec<Selection>,
+pub struct Fragment<'a> {
+    pub name: Spanning<&'a str>,
+    pub type_condition: Spanning<&'a str>,
+    pub directives: Option<Vec<Spanning<Directive<'a>>>>,
+    pub selection_set: Vec<Selection<'a>>,
 }
 
 #[derive(Clone, PartialEq, Debug)]
 pub enum Definition<'a> {
     Operation(Spanning<Operation<'a>>),
-    Fragment(Spanning<Fragment>),
+    Fragment(Spanning<Fragment<'a>>),
 }
 
 pub type Document<'a> = Vec<Definition<'a>>;
@@ -417,23 +417,19 @@ impl ToJson for InputValue {
     }
 }
 
-impl Arguments {
-    pub fn into_iter(self) -> vec::IntoIter<(Spanning<String>, Spanning<InputValue>)> {
+impl<'a> Arguments<'a> {
+    pub fn into_iter(self) -> vec::IntoIter<(Spanning<&'a str>, Spanning<InputValue>)> {
         self.items.into_iter()
     }
 
-    pub fn iter(&self) -> slice::Iter<(Spanning<String>, Spanning<InputValue>)> {
+    pub fn iter(&self) -> slice::Iter<(Spanning<&'a str>, Spanning<InputValue>)> {
         self.items.iter()
     }
 
-    pub fn iter_mut(&mut self) -> slice::IterMut<(Spanning<String>, Spanning<InputValue>)> {
+    pub fn iter_mut(&mut self) -> slice::IterMut<(Spanning<&'a str>, Spanning<InputValue>)> {
         self.items.iter_mut()
     }
 
-    pub fn drain<'a>(&'a mut self) -> vec::Drain<'a, (Spanning<String>, Spanning<InputValue>)> {
-        self.items.drain(..)
-    }
-
     pub fn len(&self) -> usize {
         self.items.len()
     }
@@ -448,7 +444,7 @@ impl Arguments {
 }
 
 impl<'a> VariableDefinitions<'a> {
-    pub fn iter(&self) -> slice::Iter<(Spanning<String>, VariableDefinition)> {
+    pub fn iter(&self) -> slice::Iter<(Spanning<&'a str>, VariableDefinition)> {
         self.items.iter()
     }
 }
diff --git a/src/executor.rs b/src/executor.rs
index bb707378..6e4b2734 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -35,9 +35,9 @@ pub enum FieldPath<'a> {
 /// The executor helps drive the query execution in a schema. It keeps track
 /// of the current field stack, context, variables, and errors.
 pub struct Executor<'a, CtxT> where CtxT: 'a {
-    fragments: &'a HashMap<&'a str, &'a Fragment>,
+    fragments: &'a HashMap<&'a str, &'a Fragment<'a>>,
     variables: &'a HashMap<String, InputValue>,
-    current_selection_set: Option<&'a [Selection]>,
+    current_selection_set: Option<&'a [Selection<'a>]>,
     schema: &'a SchemaType<'a>,
     context: &'a CtxT,
     errors: &'a RwLock<Vec<ExecutionError>>,
@@ -332,7 +332,7 @@ pub fn execute_validated_query<'a, QueryT, MutationT, CtxT>(
 
     {
         let executor = Executor {
-            fragments: &fragments.iter().map(|f| (f.item.name.item.as_str(), &f.item)).collect(),
+            fragments: &fragments.iter().map(|f| (f.item.name.item, &f.item)).collect(),
             variables: variables,
             current_selection_set: Some(&op.item.selection_set[..]),
             schema: &root_node.schema,
diff --git a/src/parser/document.rs b/src/parser/document.rs
index 8d47c63d..a7f653d2 100644
--- a/src/parser/document.rs
+++ b/src/parser/document.rs
@@ -54,7 +54,7 @@ fn parse_operation_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Op
         let start_pos = parser.peek().start.clone();
         let operation_type = try!(parse_operation_type(parser));
         let name = match parser.peek().item {
-            Token::Name(_) => Some(try!(parser.expect_name()).map(|s| s.to_owned())),
+            Token::Name(_) => Some(try!(parser.expect_name())),
             _ => None
         };
         let variable_definitions = try!(parse_variable_definitions(parser));
@@ -74,7 +74,7 @@ fn parse_operation_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Op
     }
 }
 
-fn parse_fragment_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Fragment> {
+fn parse_fragment_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Fragment<'a>> {
     let Spanning { start: start_pos, .. } = try!(parser.expect(&Token::Name("fragment")));
     let name = match parser.expect_name() {
         Ok(n) => if n.item == "on" {
@@ -95,14 +95,14 @@ fn parse_fragment_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Fra
         &start_pos,
         &selection_set.end,
         Fragment {
-            name: name.map(|s| s.to_owned()),
-            type_condition: type_cond.map(|s| s.to_owned()),
+            name: name,
+            type_condition: type_cond,
             directives: directives.map(|s| s.item),
             selection_set: selection_set.item,
         }))
 }
 
-fn parse_optional_selection_set<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Vec<Selection>> {
+fn parse_optional_selection_set<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Vec<Selection<'a>>> {
     if parser.peek().item == Token::CurlyOpen {
         Ok(Some(try!(parse_selection_set(parser))))
     }
@@ -111,21 +111,21 @@ fn parse_optional_selection_set<'a>(parser: &mut Parser<'a>) -> OptionParseResul
     }
 }
 
-fn parse_selection_set<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Vec<Selection>> {
+fn parse_selection_set<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Vec<Selection<'a>>> {
     parser.unlocated_delimited_nonempty_list(
         &Token::CurlyOpen,
         parse_selection,
         &Token::CurlyClose)
 }
 
-fn parse_selection<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selection> {
+fn parse_selection<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selection<'a>> {
     match parser.peek().item {
         Token::Ellipsis => parse_fragment(parser),
         _ => parse_field(parser).map(Selection::Field),
     }
 }
 
-fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selection> {
+fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selection<'a>> {
     let Spanning { start: ref start_pos, .. } = try!(parser.expect(&Token::Ellipsis));
 
     match parser.peek().item {
@@ -140,7 +140,7 @@ fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selec
                     &start_pos.clone(),
                     &selection_set.end,
                     InlineFragment {
-                        type_condition: Some(name.map(|s| s.to_owned())),
+                        type_condition: Some(name),
                         directives: directives.map(|s| s.item),
                         selection_set: selection_set.item,
                     })))
@@ -167,7 +167,7 @@ fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selec
                     &start_pos.clone(),
                     &directives.as_ref().map_or(&frag_name.end, |s| &s.end).clone(),
                     FragmentSpread {
-                        name: frag_name.map(|s| s.to_owned()),
+                        name: frag_name,
                         directives: directives.map(|s| s.item),
                     })))
         },
@@ -189,11 +189,11 @@ fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selec
     }
 }
 
-fn parse_field<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Field> {
-    let mut alias = Some(try!(parser.expect_name()).map(|s| s.to_owned()));
+fn parse_field<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Field<'a>> {
+    let mut alias = Some(try!(parser.expect_name()));
 
     let name = if try!(parser.skip(&Token::Colon)).is_some() {
-        try!(parser.expect_name()).map(|s| s.to_owned())
+        try!(parser.expect_name())
     }
     else {
         alias.take().unwrap()
@@ -212,14 +212,14 @@ fn parse_field<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Field> {
             .clone(),
         Field {
             alias: alias,
-            name: name.map(|s| s.to_owned()),
+            name: name,
             arguments: arguments,
             directives: directives.map(|s| s.item),
             selection_set: selection_set.map(|s| s.item),
         }))
 }
 
-fn parse_arguments<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Arguments> {
+fn parse_arguments<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Arguments<'a>> {
     if parser.peek().item != Token::ParenOpen {
         Ok(None)
     } else {
@@ -231,7 +231,7 @@ fn parse_arguments<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Argumen
     }
 }
 
-fn parse_argument<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Spanning<String>, Spanning<InputValue>)> {
+fn parse_argument<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Spanning<&'a str>, Spanning<InputValue>)> {
     let name = try!(parser.expect_name());
     try!(parser.expect(&Token::Colon));
     let value = try!(parse_value_literal(parser, false));
@@ -239,7 +239,7 @@ fn parse_argument<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Spanning<Stri
     Ok(Spanning::start_end(
         &name.start.clone(),
         &value.end.clone(),
-        (name.map(|s| s.to_owned()), value)))
+        (name, value)))
 }
 
 fn parse_operation_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, OperationType> {
@@ -263,7 +263,7 @@ fn parse_variable_definitions<'a>(parser: &mut Parser<'a>) -> OptionParseResult<
     }
 }
 
-fn parse_variable_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Spanning<String>, VariableDefinition<'a>)> {
+fn parse_variable_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Spanning<&'a str>, VariableDefinition<'a>)> {
     let Spanning { start: start_pos, .. } = try!(parser.expect(&Token::Dollar));
     let var_name = try!(parser.expect_name());
     try!(parser.expect(&Token::Colon));
@@ -283,7 +283,7 @@ fn parse_variable_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Sp
             Spanning::start_end(
                 &start_pos,
                 &var_name.end,
-                var_name.item.to_owned(),
+                var_name.item,
             ),
             VariableDefinition {
                 var_type: var_type,
@@ -292,7 +292,7 @@ fn parse_variable_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, (Sp
         )))
 }
 
-fn parse_directives<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Vec<Spanning<Directive>>> {
+fn parse_directives<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Vec<Spanning<Directive<'a>>>> {
     if parser.peek().item != Token::At {
         Ok(None)
     }
@@ -306,7 +306,7 @@ fn parse_directives<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Vec<Sp
     }
 }
 
-fn parse_directive<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Directive> {
+fn parse_directive<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Directive<'a>> {
     let Spanning { start: start_pos, .. } = try!(parser.expect(&Token::At));
     let name = try!(parser.expect_name());
     let arguments = try!(parse_arguments(parser));
@@ -315,7 +315,7 @@ fn parse_directive<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Directive> {
         &start_pos,
         &arguments.as_ref().map_or(&name.end, |s| &s.end).clone(),
         Directive {
-            name: name.map(|s| s.to_owned()),
+            name: name,
             arguments: arguments,
         }))
 }
diff --git a/src/parser/tests/document.rs b/src/parser/tests/document.rs
index 3908a69d..566fa79f 100644
--- a/src/parser/tests/document.rs
+++ b/src/parser/tests/document.rs
@@ -44,7 +44,7 @@ fn simple_ast() {
                                     name: Spanning::start_end(
                                         &SourcePosition::new(31, 2, 16),
                                         &SourcePosition::new(35, 2, 20),
-                                        "node".to_owned()),
+                                        "node"),
                                     arguments: Some(Spanning::start_end(
                                         &SourcePosition::new(35, 2, 20),
                                         &SourcePosition::new(42, 2, 27),
@@ -54,7 +54,7 @@ fn simple_ast() {
                                                     Spanning::start_end(
                                                         &SourcePosition::new(36, 2, 21),
                                                         &SourcePosition::new(38, 2, 23),
-                                                        "id".to_owned()),
+                                                        "id"),
                                                     Spanning::start_end(
                                                         &SourcePosition::new(40, 2, 25),
                                                         &SourcePosition::new(41, 2, 26),
@@ -73,7 +73,7 @@ fn simple_ast() {
                                                     name: Spanning::start_end(
                                                         &SourcePosition::new(65, 3, 20),
                                                         &SourcePosition::new(67, 3, 22),
-                                                        "id".to_owned()),
+                                                        "id"),
                                                     arguments: None,
                                                     directives: None,
                                                     selection_set: None,
@@ -87,7 +87,7 @@ fn simple_ast() {
                                                     name: Spanning::start_end(
                                                         &SourcePosition::new(88, 4, 20),
                                                         &SourcePosition::new(92, 4, 24),
-                                                        "name".to_owned()),
+                                                        "name"),
                                                     arguments: None,
                                                     directives: None,
                                                     selection_set: None,
diff --git a/src/types/base.rs b/src/types/base.rs
index 149669ba..eadab4a3 100644
--- a/src/types/base.rs
+++ b/src/types/base.rs
@@ -307,16 +307,16 @@ fn resolve_selection_set_into<T, CtxT>(
 
                 let response_name = &f.alias.as_ref().unwrap_or(&f.name).item;
 
-                if &f.name.item == "__typename" {
+                if f.name.item == "__typename" {
                     result.insert(
-                        response_name.clone(),
+                        (*response_name).to_owned(),
                         Value::string(
                             instance.concrete_type_name(executor.context())));
                     continue;
                 }
 
                 let meta_field = meta_type.field_by_name(&f.name.item)
-                    .expect(&format!("Field {} not found on type {:?}", f.name.item, meta_type.name()));
+                    .unwrap_or_else(|| panic!(format!("Field {} not found on type {:?}", f.name.item, meta_type.name())));
 
                 let exec_vars = executor.variables();
 
@@ -330,15 +330,15 @@ fn resolve_selection_set_into<T, CtxT>(
                     &Arguments::new(
                         f.arguments.as_ref().map(|m|
                             m.item.iter().map(|&(ref k, ref v)|
-                                (k.item.as_str(), v.item.clone().into_const(exec_vars))).collect()),
+                                (k.item, v.item.clone().into_const(exec_vars))).collect()),
                         &meta_field.arguments),
                     &mut sub_exec);
 
                 match field_result {
-                    Ok(v) => merge_key_into(result, response_name.clone(), v),
+                    Ok(v) => merge_key_into(result, response_name, v),
                     Err(e) => {
                         sub_exec.push_error(e, start_pos.clone());
-                        result.insert(response_name.clone(), Value::null());
+                        result.insert((*response_name).to_owned(), Value::null());
                     }
                 }
             },
@@ -415,10 +415,10 @@ fn is_excluded(directives: &Option<Vec<Spanning<Directive>>>, vars: &HashMap<Str
 
 fn merge_key_into(
     result: &mut HashMap<String, Value>,
-    response_name: String,
+    response_name: &str,
     value: Value,
 ) {
-    match result.entry(response_name) {
+    match result.entry(response_name.to_owned()) {
         Entry::Occupied(mut e) => {
             println!("Merging object at '{}'", e.key());
             match (e.get_mut().as_mut_object_value(), value) {
@@ -442,7 +442,7 @@ fn merge_maps(
 ) {
     for (key, value) in src {
         if dest.contains_key(&key) {
-            merge_key_into(dest, key, value);
+            merge_key_into(dest, &key, value);
         }
         else {
             dest.insert(key, value);
diff --git a/src/validation/context.rs b/src/validation/context.rs
index 9073ac8a..736362d5 100644
--- a/src/validation/context.rs
+++ b/src/validation/context.rs
@@ -23,7 +23,7 @@ pub struct ValidatorContext<'a> {
     input_type_stack: Vec<Option<&'a MetaType<'a>>>,
     input_type_literal_stack: Vec<Option<Type<'a>>>,
     parent_type_stack: Vec<Option<&'a MetaType<'a>>>,
-    fragment_names: HashSet<String>,
+    fragment_names: HashSet<&'a str>,
 }
 
 impl RuleError {
@@ -51,7 +51,7 @@ impl RuleError {
 
 impl<'a> ValidatorContext<'a> {
     #[doc(hidden)]
-    pub fn new(schema: &'a SchemaType, document: &Document) -> ValidatorContext<'a> {
+    pub fn new(schema: &'a SchemaType, document: &Document<'a>) -> ValidatorContext<'a> {
         ValidatorContext {
             errors: Vec::new(),
             schema: schema,
@@ -62,7 +62,7 @@ impl<'a> ValidatorContext<'a> {
             input_type_literal_stack: Vec::new(),
             fragment_names: document.iter()
                 .filter_map(|def| match *def {
-                    Definition::Fragment(ref frag) => Some(frag.item.name.item.clone()),
+                    Definition::Fragment(ref frag) => Some(frag.item.name.item),
                     _ => None,
                 })
                 .collect()
diff --git a/src/validation/input_value.rs b/src/validation/input_value.rs
index 456523f2..97130620 100644
--- a/src/validation/input_value.rs
+++ b/src/validation/input_value.rs
@@ -47,7 +47,7 @@ fn validate_var_defs(
             Some(t) if t.is_input() => {
                 let ct = schema.make_type(&def.var_type.item);
 
-                if def.var_type.item.is_non_null() && is_absent_or_null(values.get(&name.item)) {
+                if def.var_type.item.is_non_null() && is_absent_or_null(values.get(name.item)) {
                     errors.push(RuleError::new(
                         &format!(
                             r#"Variable "${}" of required type "{}" was not provided."#,
@@ -55,7 +55,7 @@ fn validate_var_defs(
                         ),
                         &[ name.start.clone() ],
                     ));
-                } else if let Some(ref v) = values.get(&name.item) {
+                } else if let Some(ref v) = values.get(name.item) {
                     unify_value(&name.item, &name.start, v, &ct, schema, errors, Path::Root);
                 }
             },
diff --git a/src/validation/multi_visitor.rs b/src/validation/multi_visitor.rs
index 8fb7d3d8..bda0e43c 100644
--- a/src/validation/multi_visitor.rs
+++ b/src/validation/multi_visitor.rs
@@ -46,10 +46,10 @@ impl<'a> Visitor<'a> for MultiVisitor<'a> {
         self.visit_all(|v| v.exit_fragment_definition(ctx, f));
     }
 
-    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, def: &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, def: &'a (Spanning<&'a str>, VariableDefinition)) {
         self.visit_all(|v| v.enter_variable_definition(ctx, def));
     }
-    fn exit_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, def: &'a (Spanning<String>, VariableDefinition)) {
+    fn exit_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, def: &'a (Spanning<&'a str>, VariableDefinition)) {
         self.visit_all(|v| v.exit_variable_definition(ctx, def));
     }
 
@@ -60,10 +60,10 @@ impl<'a> Visitor<'a> for MultiVisitor<'a> {
         self.visit_all(|v| v.exit_directive(ctx, d));
     }
 
-    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, arg: &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, arg: &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         self.visit_all(|v| v.enter_argument(ctx, arg));
     }
-    fn exit_argument(&mut self, ctx: &mut ValidatorContext<'a>, arg: &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn exit_argument(&mut self, ctx: &mut ValidatorContext<'a>, arg: &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         self.visit_all(|v| v.exit_argument(ctx, arg));
     }
 
diff --git a/src/validation/rules/arguments_of_correct_type.rs b/src/validation/rules/arguments_of_correct_type.rs
index 8a972324..1cffe445 100644
--- a/src/validation/rules/arguments_of_correct_type.rs
+++ b/src/validation/rules/arguments_of_correct_type.rs
@@ -35,7 +35,7 @@ impl<'a> Visitor<'a> for ArgumentsOfCorrectType<'a> {
         self.current_args = None;
     }
 
-    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, &(ref arg_name, ref arg_value): &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, &(ref arg_name, ref arg_value): &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         if let Some(argument_meta) = self.current_args
             .and_then(|args| args.iter().filter(|a| a.name == arg_name.item).next())
         {
diff --git a/src/validation/rules/default_values_of_correct_type.rs b/src/validation/rules/default_values_of_correct_type.rs
index f2ecdce7..09f2096a 100644
--- a/src/validation/rules/default_values_of_correct_type.rs
+++ b/src/validation/rules/default_values_of_correct_type.rs
@@ -12,7 +12,7 @@ pub fn factory() -> DefaultValuesOfCorrectType {
 }
 
 impl<'a> Visitor<'a> for DefaultValuesOfCorrectType {
-    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(ref var_name, ref var_def): &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(ref var_name, ref var_def): &'a (Spanning<&'a str>, VariableDefinition)) {
         if let Some(Spanning { item: ref var_value, ref start, .. }) = var_def.default_value {
             if var_def.var_type.item.is_non_null() {
                 ctx.report_error(
diff --git a/src/validation/rules/known_argument_names.rs b/src/validation/rules/known_argument_names.rs
index 1de82cb5..2141e39b 100644
--- a/src/validation/rules/known_argument_names.rs
+++ b/src/validation/rules/known_argument_names.rs
@@ -46,7 +46,7 @@ impl<'a> Visitor<'a> for KnownArgumentNames<'a> {
         self.current_args = None;
     }
 
-    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, &(ref arg_name, _): &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, &(ref arg_name, _): &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         if let Some((ref pos, args)) = self.current_args {
             if args.iter().filter(|a| a.name == arg_name.item).next().is_none() {
                 let message = match *pos {
diff --git a/src/validation/rules/known_type_names.rs b/src/validation/rules/known_type_names.rs
index 835e63f8..4072798c 100644
--- a/src/validation/rules/known_type_names.rs
+++ b/src/validation/rules/known_type_names.rs
@@ -20,7 +20,7 @@ impl<'a> Visitor<'a> for KnownTypeNames {
         validate_type(ctx, &type_cond.item, &type_cond.start);
     }
 
-    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(_, ref var_def): &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(_, ref var_def): &'a (Spanning<&'a str>, VariableDefinition)) {
         let type_name = var_def.var_type.item.innermost_name();
         validate_type(ctx, &type_name, &var_def.var_type.start);
     }
diff --git a/src/validation/rules/no_fragment_cycles.rs b/src/validation/rules/no_fragment_cycles.rs
index ade106dc..a14d91be 100644
--- a/src/validation/rules/no_fragment_cycles.rs
+++ b/src/validation/rules/no_fragment_cycles.rs
@@ -55,7 +55,7 @@ impl<'a> Visitor<'a> for NoFragmentCycles<'a> {
     }
 
     fn exit_fragment_definition(&mut self, _: &mut ValidatorContext<'a>, fragment: &'a Spanning<Fragment>) {
-        assert_eq!(Some(fragment.item.name.item.as_str()), self.current_fragment);
+        assert_eq!(Some(fragment.item.name.item), self.current_fragment);
         self.current_fragment = None;
     }
 
diff --git a/src/validation/rules/no_undefined_variables.rs b/src/validation/rules/no_undefined_variables.rs
index 3441793a..89c9ca42 100644
--- a/src/validation/rules/no_undefined_variables.rs
+++ b/src/validation/rules/no_undefined_variables.rs
@@ -69,7 +69,7 @@ impl<'a> Visitor<'a> for NoUndefinedVariables<'a> {
     }
 
     fn enter_operation_definition(&mut self, _: &mut ValidatorContext<'a>, op: &'a Spanning<Operation>) {
-        let op_name = op.item.name.as_ref().map(|s| s.item.as_str());
+        let op_name = op.item.name.as_ref().map(|s| s.item);
         self.current_scope = Some(Scope::Operation(op_name));
         self.defined_variables.insert(op_name, (op.start.clone(), HashSet::new()));
     }
@@ -86,7 +86,7 @@ impl<'a> Visitor<'a> for NoUndefinedVariables<'a> {
         }
     }
 
-    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, &(ref var_name, _): &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, &(ref var_name, _): &'a (Spanning<&'a str>, VariableDefinition)) {
         if let Some(Scope::Operation(ref name)) = self.current_scope {
             if let Some(&mut (_, ref mut vars)) = self.defined_variables.get_mut(name) {
                 vars.insert(&var_name.item);
@@ -94,7 +94,7 @@ impl<'a> Visitor<'a> for NoUndefinedVariables<'a> {
         }
     }
 
-    fn enter_argument(&mut self, _: &mut ValidatorContext<'a>, &(_, ref value): &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn enter_argument(&mut self, _: &mut ValidatorContext<'a>, &(_, ref value): &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         if let Some(ref scope) = self.current_scope {
             self.used_variables
                 .entry(scope.clone())
diff --git a/src/validation/rules/no_unused_fragments.rs b/src/validation/rules/no_unused_fragments.rs
index abeff3af..f96a0e4d 100644
--- a/src/validation/rules/no_unused_fragments.rs
+++ b/src/validation/rules/no_unused_fragments.rs
@@ -49,7 +49,7 @@ impl<'a> Visitor<'a> for NoUnusedFragments<'a> {
 
         for def in defs {
             if let Definition::Operation(Spanning { item: Operation { ref name, .. }, ..}) = *def {
-                let op_name = name.as_ref().map(|s| s.item.as_str());
+                let op_name = name.as_ref().map(|s| s.item);
                 self.find_reachable_fragments(&Scope::Operation(op_name), &mut reachable);
             }
         }
diff --git a/src/validation/rules/no_unused_variables.rs b/src/validation/rules/no_unused_variables.rs
index a25e923e..953f43a5 100644
--- a/src/validation/rules/no_unused_variables.rs
+++ b/src/validation/rules/no_unused_variables.rs
@@ -10,7 +10,7 @@ pub enum Scope<'a> {
 }
 
 pub struct NoUnusedVariables<'a> {
-    defined_variables: HashMap<Option<&'a str>, HashSet<&'a Spanning<String>>>,
+    defined_variables: HashMap<Option<&'a str>, HashSet<&'a Spanning<&'a str>>>,
     used_variables: HashMap<Scope<'a>, Vec<&'a str>>,
     current_scope: Option<Scope<'a>>,
     spreads: HashMap<Scope<'a>, Vec<&'a str>>,
@@ -56,13 +56,13 @@ impl<'a> Visitor<'a> for NoUnusedVariables<'a> {
             let mut visited = HashSet::new();
             self.find_used_vars(
                 &Scope::Operation(op_name.clone()),
-                &def_vars.iter().map(|def| def.item.as_str()).collect(),
+                &def_vars.iter().map(|def| def.item).collect(),
                 &mut used,
                 &mut visited);
 
             ctx.append_errors(def_vars
                 .iter()
-                .filter(|var| !used.contains(var.item.as_str()))
+                .filter(|var| !used.contains(var.item))
                 .map(|var| RuleError::new(
                     &error_message(&var.item, op_name.clone()),
                     &[var.start.clone()]))
@@ -71,7 +71,7 @@ impl<'a> Visitor<'a> for NoUnusedVariables<'a> {
     }
 
     fn enter_operation_definition(&mut self, _: &mut ValidatorContext<'a>, op: &'a Spanning<Operation>) {
-        let op_name = op.item.name.as_ref().map(|s| s.item.as_str());
+        let op_name = op.item.name.as_ref().map(|s| s.item);
         self.current_scope = Some(Scope::Operation(op_name.clone()));
         self.defined_variables.insert(op_name, HashSet::new());
     }
@@ -88,7 +88,7 @@ impl<'a> Visitor<'a> for NoUnusedVariables<'a> {
         }
     }
 
-    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, &(ref var_name, _): &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, &(ref var_name, _): &'a (Spanning<&'a str>, VariableDefinition)) {
         if let Some(Scope::Operation(ref name)) = self.current_scope {
             if let Some(vars) = self.defined_variables.get_mut(name) {
                 vars.insert(var_name);
@@ -96,7 +96,7 @@ impl<'a> Visitor<'a> for NoUnusedVariables<'a> {
         }
     }
 
-    fn enter_argument(&mut self, _: &mut ValidatorContext<'a>, &(_, ref value): &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn enter_argument(&mut self, _: &mut ValidatorContext<'a>, &(_, ref value): &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         if let Some(ref scope) = self.current_scope {
             self.used_variables
                 .entry(scope.clone())
diff --git a/src/validation/rules/overlapping_fields_can_be_merged.rs b/src/validation/rules/overlapping_fields_can_be_merged.rs
index 361d13c3..2e0a956e 100644
--- a/src/validation/rules/overlapping_fields_can_be_merged.rs
+++ b/src/validation/rules/overlapping_fields_can_be_merged.rs
@@ -14,7 +14,7 @@ struct Conflict(ConflictReason, Vec<SourcePosition>, Vec<SourcePosition>);
 struct ConflictReason(String, ConflictReasonMessage);
 
 #[derive(Debug)]
-struct AstAndDef<'a>(Option<&'a str>, &'a Spanning<Field>, Option<&'a FieldType<'a>>);
+struct AstAndDef<'a>(Option<&'a str>, &'a Spanning<Field<'a>>, Option<&'a FieldType<'a>>);
 
 type AstAndDefCollection<'a> = OrderedMap<&'a str, Vec<AstAndDef<'a>>>;
 
@@ -116,7 +116,7 @@ impl<'a> PairSet<'a> {
 }
 
 pub struct OverlappingFieldsCanBeMerged<'a> {
-    named_fragments: HashMap<&'a str, &'a Fragment>,
+    named_fragments: HashMap<&'a str, &'a Fragment<'a>>,
     compared_fragments: RefCell<PairSet<'a>>,
 }
 
@@ -573,11 +573,11 @@ impl<'a> OverlappingFieldsCanBeMerged<'a> {
                     let field_def = parent_type.and_then(|t| t.field_by_name(field_name));
                     let response_name = f.item.alias.as_ref().map(|s| &s.item).unwrap_or_else(|| &field_name);
 
-                    if !ast_and_defs.contains_key(response_name.as_str()) {
+                    if !ast_and_defs.contains_key(response_name) {
                         ast_and_defs.insert(response_name, Vec::new());
                     }
 
-                    ast_and_defs.get_mut(response_name.as_str()).unwrap()
+                    ast_and_defs.get_mut(response_name).unwrap()
                         .push(AstAndDef(parent_type.and_then(MetaType::name), f, field_def));
                 },
                 Selection::FragmentSpread(Spanning { item: FragmentSpread { ref name, ..}, ..}) => {
diff --git a/src/validation/rules/possible_fragment_spreads.rs b/src/validation/rules/possible_fragment_spreads.rs
index aed2cb7f..1bc219e8 100644
--- a/src/validation/rules/possible_fragment_spreads.rs
+++ b/src/validation/rules/possible_fragment_spreads.rs
@@ -42,7 +42,7 @@ impl<'a> Visitor<'a> for PossibleFragmentSpreads<'a> {
 
     fn enter_fragment_spread(&mut self, ctx: &mut ValidatorContext<'a>, spread: &'a Spanning<FragmentSpread>) {
         if let (Some(ref parent_type), Some(ref frag_type))
-            = (ctx.parent_type(), self.fragment_types.get(spread.item.name.item.as_str()))
+            = (ctx.parent_type(), self.fragment_types.get(spread.item.name.item))
         {
             if !ctx.schema.type_overlap(parent_type, frag_type) {
                 ctx.report_error(
diff --git a/src/validation/rules/unique_argument_names.rs b/src/validation/rules/unique_argument_names.rs
index 99abb946..be84a884 100644
--- a/src/validation/rules/unique_argument_names.rs
+++ b/src/validation/rules/unique_argument_names.rs
@@ -23,7 +23,7 @@ impl<'a> Visitor<'a> for UniqueArgumentNames<'a> {
         self.known_names = HashMap::new();
     }
 
-    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, &(ref arg_name, _): &'a (Spanning<String>, Spanning<InputValue>)) {
+    fn enter_argument(&mut self, ctx: &mut ValidatorContext<'a>, &(ref arg_name, _): &'a (Spanning<&'a str>, Spanning<InputValue>)) {
         match self.known_names.entry(&arg_name.item) {
             Entry::Occupied(e) => {
                 ctx.report_error(
diff --git a/src/validation/rules/unique_variable_names.rs b/src/validation/rules/unique_variable_names.rs
index 25c48a48..c80cb14d 100644
--- a/src/validation/rules/unique_variable_names.rs
+++ b/src/validation/rules/unique_variable_names.rs
@@ -19,7 +19,7 @@ impl<'a> Visitor<'a> for UniqueVariableNames<'a> {
         self.names = HashMap::new();
     }
 
-    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(ref var_name, _): &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(ref var_name, _): &'a (Spanning<&'a str>, VariableDefinition)) {
         match self.names.entry(&var_name.item) {
             Entry::Occupied(e) => {
                 ctx.report_error(
diff --git a/src/validation/rules/variables_are_input_types.rs b/src/validation/rules/variables_are_input_types.rs
index 8b6b9eb9..65eec493 100644
--- a/src/validation/rules/variables_are_input_types.rs
+++ b/src/validation/rules/variables_are_input_types.rs
@@ -9,7 +9,7 @@ pub fn factory() -> UniqueVariableNames {
 }
 
 impl<'a> Visitor<'a> for UniqueVariableNames {
-    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(ref var_name, ref var_def): &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, ctx: &mut ValidatorContext<'a>, &(ref var_name, ref var_def): &'a (Spanning<&'a str>, VariableDefinition)) {
         if let Some(var_type) = ctx.schema.concrete_type_by_name(var_def.var_type.item.innermost_name()) {
             if !var_type.is_input() {
                 ctx.report_error(
diff --git a/src/validation/rules/variables_in_allowed_position.rs b/src/validation/rules/variables_in_allowed_position.rs
index d7f5131d..ceb30408 100644
--- a/src/validation/rules/variables_in_allowed_position.rs
+++ b/src/validation/rules/variables_in_allowed_position.rs
@@ -13,7 +13,7 @@ pub enum Scope<'a> {
 pub struct VariableInAllowedPosition<'a> {
     spreads: HashMap<Scope<'a>, HashSet<&'a str>>,
     variable_usages: HashMap<Scope<'a>, Vec<(Spanning<&'a String>, Type<'a>)>>,
-    variable_defs: HashMap<Scope<'a>, Vec<&'a (Spanning<String>, VariableDefinition<'a>)>>,
+    variable_defs: HashMap<Scope<'a>, Vec<&'a (Spanning<&'a str>, VariableDefinition<'a>)>>,
     current_scope: Option<Scope<'a>>,
 }
 
@@ -30,7 +30,7 @@ impl<'a> VariableInAllowedPosition<'a> {
     fn collect_incorrect_usages(
         &self,
         from: &Scope<'a>,
-        var_defs: &Vec<&'a (Spanning<String>, VariableDefinition)>,
+        var_defs: &Vec<&'a (Spanning<&'a str>, VariableDefinition)>,
         ctx: &mut ValidatorContext<'a>,
         visited: &mut HashSet<Scope<'a>>,
     )
@@ -83,7 +83,7 @@ impl<'a> Visitor<'a> for VariableInAllowedPosition<'a> {
     }
 
     fn enter_operation_definition(&mut self, _: &mut ValidatorContext<'a>, op: &'a Spanning<Operation>) {
-        self.current_scope = Some(Scope::Operation(op.item.name.as_ref().map(|s| s.item.as_str())));
+        self.current_scope = Some(Scope::Operation(op.item.name.as_ref().map(|s| s.item)));
     }
 
     fn enter_fragment_spread(&mut self, _: &mut ValidatorContext<'a>, spread: &'a Spanning<FragmentSpread>) {
@@ -95,7 +95,7 @@ impl<'a> Visitor<'a> for VariableInAllowedPosition<'a> {
         }
     }
 
-    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, def: &'a (Spanning<String>, VariableDefinition)) {
+    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, def: &'a (Spanning<&'a str>, VariableDefinition)) {
         if let Some(ref scope) = self.current_scope {
             self.variable_defs
                 .entry(scope.clone())
diff --git a/src/validation/test_harness.rs b/src/validation/test_harness.rs
index 3d0de147..e96a4bcb 100644
--- a/src/validation/test_harness.rs
+++ b/src/validation/test_harness.rs
@@ -452,7 +452,7 @@ impl GraphQLType for QueryRoot {
     }
 }
 
-pub fn validate<'a, R, V, F>(r: R, q: &str, factory: F)
+pub fn validate<'a, R, V, F>(r: R, q: &'a str, factory: F)
     -> Vec<RuleError>
     where R: GraphQLType,
           V: Visitor<'a> + 'a,
@@ -479,14 +479,14 @@ pub fn validate<'a, R, V, F>(r: R, q: &str, factory: F)
     ctx.into_errors()
 }
 
-pub fn expect_passes_rule<'a, V, F>(factory: F, q: &str)
+pub fn expect_passes_rule<'a, V, F>(factory: F, q: &'a str)
     where V: Visitor<'a> + 'a,
           F: Fn() -> V
 {
     expect_passes_rule_with_schema(QueryRoot, factory, q);
 }
 
-pub fn expect_passes_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &str)
+pub fn expect_passes_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &'a str)
     where R: GraphQLType,
           V: Visitor<'a> + 'a,
           F: Fn() -> V
@@ -499,14 +499,14 @@ pub fn expect_passes_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &str)
     }
 }
 
-pub fn expect_fails_rule<'a, V, F>(factory: F, q: &str, expected_errors: &[RuleError])
+pub fn expect_fails_rule<'a, V, F>(factory: F, q: &'a str, expected_errors: &[RuleError])
     where V: Visitor<'a> + 'a,
           F: Fn() -> V
 {
     expect_fails_rule_with_schema(QueryRoot, factory, q, expected_errors);
 }
 
-pub fn expect_fails_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &str, expected_errors: &[RuleError])
+pub fn expect_fails_rule_with_schema<'a, R, V, F>(r: R, factory: F, q: &'a str, expected_errors: &[RuleError])
     where R: GraphQLType,
           V: Visitor<'a> + 'a,
           F: Fn() -> V
diff --git a/src/validation/traits.rs b/src/validation/traits.rs
index c6913cdb..aaec53c4 100644
--- a/src/validation/traits.rs
+++ b/src/validation/traits.rs
@@ -15,14 +15,14 @@ pub trait Visitor<'a> {
     fn enter_fragment_definition(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<Fragment>) {}
     fn exit_fragment_definition(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<Fragment>) {}
 
-    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<String>, VariableDefinition)) {}
-    fn exit_variable_definition(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<String>, VariableDefinition)) {}
+    fn enter_variable_definition(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<&'a str>, VariableDefinition)) {}
+    fn exit_variable_definition(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<&'a str>, VariableDefinition)) {}
 
     fn enter_directive(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<Directive>) {}
     fn exit_directive(&mut self, _: &mut ValidatorContext<'a>, _: &'a Spanning<Directive>) {}
 
-    fn enter_argument(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<String>, Spanning<InputValue>)) {}
-    fn exit_argument(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<String>, Spanning<InputValue>)) {}
+    fn enter_argument(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<&'a str>, Spanning<InputValue>)) {}
+    fn exit_argument(&mut self, _: &mut ValidatorContext<'a>, _: &'a (Spanning<&'a str>, Spanning<InputValue>)) {}
 
     fn enter_selection_set(&mut self, _: &mut ValidatorContext<'a>, _: &'a Vec<Selection>) {}
     fn exit_selection_set(&mut self, _: &mut ValidatorContext<'a>, _: &'a Vec<Selection>) {}
diff --git a/src/validation/visitor.rs b/src/validation/visitor.rs
index 8c5cd255..7076a331 100644
--- a/src/validation/visitor.rs
+++ b/src/validation/visitor.rs
@@ -161,8 +161,6 @@ fn visit_fragment_spread<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut ValidatorConte
 }
 
 fn visit_inline_fragment<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut ValidatorContext<'a>, fragment: &'a Spanning<InlineFragment>) {
-    let type_name = fragment.item.type_condition.as_ref().map(|s| s.item.as_str());
-
     let mut visit_fn = move |ctx: &mut ValidatorContext<'a>| {
         v.enter_inline_fragment(ctx, fragment);
 
@@ -172,7 +170,7 @@ fn visit_inline_fragment<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut ValidatorConte
         v.exit_inline_fragment(ctx, fragment);
     };
 
-    if let Some(type_name) = type_name {
+    if let &Some(Spanning { item: ref type_name, .. }) = &fragment.item.type_condition {
         ctx.with_pushed_type(Some(&Type::NonNullNamed(type_name)), visit_fn);
     }
     else {