code: def get_field_def(
      schema,  # type: GraphQLSchema
      parent_type,  # type: Union[GraphQLInterfaceType, GraphQLObjectType]
      field_ast,  # type: Field
  ):
      # type: (...) -> Optional[GraphQLField]
      
      name = field_ast.name.value
      if name == "__schema" and schema.get_query_type() == parent_type:
          return SchemaMetaFieldDef
  
      elif name == "__type" and schema.get_query_type() == parent_type:
          return TypeMetaFieldDef
  
      elif name == "__typename" and isinstance(
          parent_type, (GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType)
      ):
          return TypeNameMetaFieldDef
  
      elif isinstance(parent_type, (GraphQLObjectType, GraphQLInterfaceType)):
          return parent_type.fields.get(name)
docs: Not exactly the same as the executor's definition of get_field_def, in this
      statically evaluated environment we do not always have an Object type,
      and need to handle Interface and Union types.