docs: def reltags(self, src, cache=None):
      '''
      returns all the tags that are relevant at this state
      cache should be a dictionary and it is updated
      by the function
      '''
      if not self._tag_assocs:
        return set()
  
      # fucking python and it's terrible support for recursion makes this
      # far more complicated than it needs to be
      if cache == None:
        cache = {}
  
      q = _otq()
      q.append(src)
      updateq = _otq()
  
  
      while q:
        i = q.popleft()
        if i in cache:
          continue
  
        cache[i] = set()
        for (s,t) in self.transitions_to(i):
          q.append(s)
          if self.is_tagged(t,s,i):
            cache[i].add((self.tag(t,s,i),s, i))
          updateq.appendleft((i, s))
  
      while updateq:
        i = updateq.popleft()
        cache[i[0]].update(cache[i[1]])
  
      return cache[src]