# Buggy code
def match(self, segments, parse_context):
    """Match a specific sequence of elements."""
    if isinstance(segments, BaseSegment):
        segments = tuple(segments)

    matched_segments = MatchResult.from_empty()
    unmatched_segments = segments

    for idx, elem in enumerate(self._elements):
        while True:
            # Is it an indent or dedent?
            if elem.is_meta:
                matched_segments += elem()
                break

            if len(unmatched_segments) == 0:
                # We've run our of sequence without matching everyting.
                # Do only optional elements remain.
                if all(e.is_optional() for e in self._elements[idx:]):
                    # then it's ok, and we can return what we've got so far.
                    # No need to deal with anything left over because we're at the end.
                    return matched_segments
                else:
                    # we've got to the end of the sequence without matching all
                    # required elements.
                    return MatchResult.from_unmatched(segments)
            else:
                # We're not at the end, first detect whitespace and then try to match.
                if self.code_only and not unmatched_segments[0].is_code:
                    # We should add this one to the match and carry on
                    matched_segments += (unmatched_segments[0],)
                    unmatched_segments = unmatched_segments[1:]
                    check_still_complete(
                        segments, matched_segments.matched_segments, unmatched_segments
                    )
                    continue

                # It's not whitespace, so carry on to matching
                elem_match = elem._match(
                    unmatched_segments,
                    parse_context=parse_context.copy(incr="match_depth"),
                )

                if elem_match.has_match():
                    # We're expecting mostly partial matches here, but complete
                    # matches are possible.
                    matched_segments += elem_match.matched_segments
                    unmatched_segments = elem_match.unmatched_segments
                    # Each time we do this, we do a sense check to make sure we haven't
                    # dropped anything. (Because it's happened before!).
                    check_still_complete(
                        segments, matched_segments.matched_segments, unmatched_segments
                    )

                    # Break out of the while loop and move to the next element.
                    break
                else:
                    # If we can't match an element, we should ascertain whether it's
                    # required. If so then fine, move on, but otherwise we should crash
                    # out without a match. We have not matched the sequence.
                    if elem.is_optional():
                        # This will crash us out of the while loop and move us
                        # onto the next matching element
                        break
                    else:
                        return MatchResult.from_unmatched(segments)

    # If we get to here, we've matched all of the elements (or skipped them)
    # but still have some segments left (or perhaps have precisely zero left).
    # In either case, we're golden. Return successfully, with any leftovers as
    # the unmatched elements. UNLESS they're whitespace and we should be greedy.
    if self.code_only:
        while unmatched_segments and not unmatched_segments[0].is_code:
            # We should add this one to the match and carry on
            matched_segments += (unmatched_segments[0],)
            unmatched_segments = unmatched_segments[1:]
            check_still_complete(
                segments, matched_segments.matched_segments, unmatched_segments
            )

    return MatchResult(matched_segments.matched_segments, unmatched_segments)


# Traceback (TypeError)
$ sqlfluff fix --rules L001 forecastservice\sql\get_phasing_v2.sql
==== finding violations ====
== [forecastservice\sql\get_phasing_v2.sql] FAIL
L:   0 | P:   0 | ???? | Failure in Jinja templating: 'first_mon' is undefined. Have you configured your variables?
L:   7 | P:   1 | ???? | Unable to lex characters: ''{% if regi'...'
==== fixing violations ====
2 violations found
Are you sure you wish to attempt to fix these? [Y/n] ...
Attempting fixes...
Persisting Changes...
Traceback (most recent call last):
File "C:\Users\alan\dev\tails-analytics-forecastservice\env\Scripts\sqlfluff-script.py", line 11, in <module>
load_entry_point('sqlfluff==0.2.4', 'console_scripts', 'sqlfluff')()
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 764, in __call__
return self.main(*args, **kwargs)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 717, in main
rv = self.invoke(ctx)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 1137, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 956, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\click\core.py", line 555, in invoke
return callback(*args, **kwargs)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\cli\commands.py", line 197, in fix
result.persist_changes(verbosity=verbose)
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 327, in persist_changes
return self.combine_dicts(*[path.persist_changes(verbosity=verbosity) for path in self.paths])
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 327, in <listcomp>
return self.combine_dicts(*[path.persist_changes(verbosity=verbosity) for path in self.paths])
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 253, in persist_changes
return {file.path: file.persist_tree(verbosity=verbosity) for file in self.files}
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 253, in <dictcomp>
return {file.path: file.persist_tree(verbosity=verbosity) for file in self.files}
File "c:\users\alan\dev\tails-analytics-forecastservice\env\lib\site-packages\sqlfluff\linter.py", line 61, in persist_tree
diff_templ_codes = diff_templ.get_opcodes()
File "C:\Users\alan\AppData\Local\Programs\Python\Python36\lib\difflib.py", line 550, in get_opcodes
for ai, bj, size in self.get_matching_blocks():
File "C:\Users\alan\AppData\Local\Programs\Python\Python36\lib\difflib.py", line 467, in get_matching_blocks
la, lb = len(self.a), len(self.b)
TypeError: object of type 'NoneType' has no len()

# Fixed code
def match(self, segments, parse_context):
    """Match a specific sequence of elements."""
    if isinstance(segments, BaseSegment):
        segments = tuple(segments)

    matched_segments = MatchResult.from_empty()
    unmatched_segments = segments

    for idx, elem in enumerate(self._elements):
        while True:
            # Is it an indent or dedent?
            if elem.is_meta:
                # Work out how to find an appropriate pos_marker for
                # the meta segment.
                if matched_segments:
                    last_matched = matched_segments.matched_segments[-1]
                    meta_pos_marker = last_matched.get_end_pos_marker()
                else:
                    meta_pos_marker = unmatched_segments[0].pos_marker
                matched_segments += elem(pos_marker=meta_pos_marker)
                break

            if len(unmatched_segments) == 0:
                # We've run our of sequence without matching everyting.
                # Do only optional elements remain.
                if all(e.is_optional() for e in self._elements[idx:]):
                    # then it's ok, and we can return what we've got so far.
                    # No need to deal with anything left over because we're at the end.
                    return matched_segments
                else:
                    # we've got to the end of the sequence without matching all
                    # required elements.
                    return MatchResult.from_unmatched(segments)
            else:
                # We're not at the end, first detect whitespace and then try to match.
                if self.code_only and not unmatched_segments[0].is_code:
                    # We should add this one to the match and carry on
                    matched_segments += (unmatched_segments[0],)
                    unmatched_segments = unmatched_segments[1:]
                    check_still_complete(
                        segments, matched_segments.matched_segments, unmatched_segments
                    )
                    continue

                # It's not whitespace, so carry on to matching
                elem_match = elem._match(
                    unmatched_segments,
                    parse_context=parse_context.copy(incr="match_depth"),
                )

                if elem_match.has_match():
                    # We're expecting mostly partial matches here, but complete
                    # matches are possible.
                    matched_segments += elem_match.matched_segments
                    unmatched_segments = elem_match.unmatched_segments
                    # Each time we do this, we do a sense check to make sure we haven't
                    # dropped anything. (Because it's happened before!).
                    check_still_complete(
                        segments, matched_segments.matched_segments, unmatched_segments
                    )

                    # Break out of the while loop and move to the next element.
                    break
                else:
                    # If we can't match an element, we should ascertain whether it's
                    # required. If so then fine, move on, but otherwise we should crash
                    # out without a match. We have not matched the sequence.
                    if elem.is_optional():
                        # This will crash us out of the while loop and move us
                        # onto the next matching element
                        break
                    else:
                        return MatchResult.from_unmatched(segments)

    # If we get to here, we've matched all of the elements (or skipped them)
    # but still have some segments left (or perhaps have precisely zero left).
    # In either case, we're golden. Return successfully, with any leftovers as
    # the unmatched elements. UNLESS they're whitespace and we should be greedy.
    if self.code_only:
        while unmatched_segments and not unmatched_segments[0].is_code:
            # We should add this one to the match and carry on
            matched_segments += (unmatched_segments[0],)
            unmatched_segments = unmatched_segments[1:]
            check_still_complete(
                segments, matched_segments.matched_segments, unmatched_segments
            )

    return MatchResult(matched_segments.matched_segments, unmatched_segments)