public static PredictionContext mergeRoot(SingletonPredictionContext a,
											  SingletonPredictionContext b,
											  boolean rootIsWildcard)
	{
		if ( rootIsWildcard ) {
			if ( a == EmptyPredictionContext.Instance) return EmptyPredictionContext.Instance;  // * + b = *
			if ( b == EmptyPredictionContext.Instance) return EmptyPredictionContext.Instance;  // a + * = *
		}
		else {
			if ( a == EmptyPredictionContext.Instance && b == EmptyPredictionContext.Instance) return EmptyPredictionContext.Instance; // $ + $ = $
			if ( a == EmptyPredictionContext.Instance) { // $ + x = [x,$]
				int[] payloads = {b.returnState, EMPTY_RETURN_STATE};
				PredictionContext[] parents = {b.parent, null};
				PredictionContext joined =
					new ArrayPredictionContext(parents, payloads);
				return joined;
			}
			if ( b == EmptyPredictionContext.Instance) { // x + $ = [x,$] ($ is always last if present)
				int[] payloads = {a.returnState, EMPTY_RETURN_STATE};
				PredictionContext[] parents = {a.parent, null};
				PredictionContext joined =
					new ArrayPredictionContext(parents, payloads);
				return joined;
			}
		}
		return null;
	}
Handle case where at least one of {@code a} or {@code b} is
{@link EmptyPredictionContext#Instance}. In the following diagrams, the symbol {@code $} is used
to represent {@link EmptyPredictionContext#Instance}.

<h2>Local-Context Merges</h2>

<p>These local-context merge operations are used when {@code rootIsWildcard}
is true.</p>

<p>{@link EmptyPredictionContext#Instance} is superset of any graph; return {@link EmptyPredictionContext#Instance}.<br>
<embed src="images/LocalMerge_EmptyRoot.svg" type="image/svg+xml"/></p>

<p>{@link EmptyPredictionContext#Instance} and anything is {@code #EMPTY}, so merged parent is
{@code #EMPTY}; return left graph.<br>
<embed src="images/LocalMerge_EmptyParent.svg" type="image/svg+xml"/></p>

<p>Special case of last merge if local context.<br>
<embed src="images/LocalMerge_DiffRoots.svg" type="image/svg+xml"/></p>

<h2>Full-Context Merges</h2>

<p>These full-context merge operations are used when {@code rootIsWildcard}
is false.</p>

<p><embed src="images/FullMerge_EmptyRoots.svg" type="image/svg+xml"/></p>

<p>Must keep all contexts; {@link EmptyPredictionContext#Instance} in array is a special value (and
null parent).<br>
<embed src="images/FullMerge_EmptyRoot.svg" type="image/svg+xml"/></p>

<p><embed src="images/FullMerge_SameRoot.svg" type="image/svg+xml"/></p>

@param a the first {@link SingletonPredictionContext}
@param b the second {@link SingletonPredictionContext}
@param rootIsWildcard {@code true} if this is a local-context merge,
otherwise false to indicate a full-context merge
runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java