[506806] Resolve isCondition/isRequired interactions
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractMappingRegion.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractMappingRegion.java
index cbe286d..8438bb6 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractMappingRegion.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/AbstractMappingRegion.java
@@ -169,6 +169,32 @@
 		super.addNode(node);
 	}
 
+	private boolean canBeStronglyMatched(@NonNull Node node) {
+		if (node.isExplicitNull()) {
+			return true;
+		}
+		if (node.isPattern()) {
+			return true;
+		}
+		return false;
+	}
+
+	private boolean canBeUnconditional(@NonNull Node node) {
+		if (node.isExplicitNull()) {
+			return true;
+		}
+		if (node.isIterator()) {
+			return false;
+		}
+		if (node.isOperation()) {
+			return true;
+		}
+		if (node.isPattern()) {
+			return true;
+		}
+		return false;
+	}
+
 	/**
 	 * Any node with an edge to an unconditional node that is not itself unconditional must be conditional.
 	 */
@@ -357,25 +383,33 @@
 		return headNodes;
 	}
 
-	private void computeStronglyMatchedNodes(@NonNull Node sourceNode, @NonNull Set<@NonNull Node> stronglyMatchedNodes) {
-		for (@NonNull NavigableEdge edge : sourceNode.getNavigationEdges()) {
-			Node targetNode = edge.getTarget();
-			if (isMatchable(targetNode)) {
-				boolean targetIsStronglyMatched = edge.isRequired();
-				if (targetIsStronglyMatched && stronglyMatchedNodes.add(targetNode)) {
-					computeStronglyMatchedNodes(targetNode, stronglyMatchedNodes);
-				}
-			}
-		}
-	}
-
 	private @NonNull Set<@NonNull Node> computeStronglyMatchedNodes(@NonNull Iterable<@NonNull Node> headNodes) {
 		Set<@NonNull Node> stronglyMatchedNodes = new HashSet<>();
 		for (@NonNull Node headNode : headNodes) {
-			if (!headNode.isDependency() && !headNode.isTrue() && stronglyMatchedNodes.add(headNode)) {
-				computeStronglyMatchedNodes(headNode, stronglyMatchedNodes);
+			if (!headNode.isDependency() && !headNode.isTrue()) {
+				stronglyMatchedNodes.add(headNode);
 			}
 		}
+		Set<@NonNull Node> moreStronglyMatchedNodes = new HashSet<>(stronglyMatchedNodes);
+		while (moreStronglyMatchedNodes.size() > 0) {
+			Set<@NonNull Node> moreMoreNodes = new HashSet<>();
+			for (@NonNull Node sourceNode : moreStronglyMatchedNodes) {
+				for (@NonNull NavigableEdge edge : sourceNode.getNavigationEdges()) {
+					Node targetNode = edge.getTarget();
+					if (canBeStronglyMatched(targetNode)) {
+						if (targetNode.isExplicitNull() || edge.getProperty().isIsRequired()) {
+							if (stronglyMatchedNodes.add(targetNode)) {
+								moreMoreNodes.add(targetNode);
+							}
+						}
+					}
+				}
+			}
+			if (moreMoreNodes.size() <= 0) {
+				break;
+			}
+			moreStronglyMatchedNodes = moreMoreNodes;
+		}
 		this.stronglyMatchedNodes = new ArrayList<>(stronglyMatchedNodes);
 		Collections.sort(this.stronglyMatchedNodes, NameUtil.NAMEABLE_COMPARATOR);
 		return stronglyMatchedNodes;
@@ -384,13 +418,15 @@
 	private @NonNull Set<@NonNull Node> computeUnconditionalNodes(@NonNull Iterable<@NonNull Node> headNodes) {
 		@NonNull Set<@NonNull Node> unconditionalNodes = Sets.newHashSet(headNodes);
 		Iterables.addAll(unconditionalNodes, getNewNodes());
-		for (@NonNull Edge edge : getRealizedEdges()) {
-			Node sourceNode = edge.getSource();
-			assert isUnconditionable(sourceNode);
-			unconditionalNodes.add(sourceNode);
-			Node targetNode = edge.getTarget();
-			assert isUnconditionable(targetNode);
-			unconditionalNodes.add(targetNode);
+		for (@NonNull NavigableEdge edge : getRealizedNavigationEdges()) {
+			if (!edge.isSecondary()) {
+				Node sourceNode = edge.getSource();
+				assert canBeUnconditional(sourceNode);
+				unconditionalNodes.add(sourceNode);
+				Node targetNode = edge.getTarget();
+				assert canBeUnconditional(targetNode);
+				unconditionalNodes.add(targetNode);
+			}
 		}
 		Set<@NonNull Node> moreUnconditionalNodes = new HashSet<>(unconditionalNodes);
 		while (moreUnconditionalNodes.size() > 0) {
@@ -398,14 +434,20 @@
 			for (@NonNull Node node : moreUnconditionalNodes) {
 				for (@NonNull Edge incomingEdge : node.getIncomingEdges()) {
 					Node sourceNode = incomingEdge.getSource();
-					if (!isUnconditionable(sourceNode)) {}
-					else if (incomingEdge.isNavigation()) {
-						if (unconditionalNodes.add(sourceNode)) {
-							moreMoreNodes.add(sourceNode);
-						}
-					}
+					if (!canBeUnconditional(sourceNode)) {}
 					else if (incomingEdge.isComputation()) {
-						if (!isConditionalEdge(incomingEdge) && unconditionalNodes.add(sourceNode)) {
+						if (!isConditionalEdge(incomingEdge)) {
+							if (unconditionalNodes.add(sourceNode)) {
+								moreMoreNodes.add(sourceNode);
+							}
+						}
+						// if is <<then>>
+						// gather <<then>> visibilities
+						// gather <<else>> visibilities
+						// intersection <<then>>/<<else>> is unconditional
+					}
+					else if (incomingEdge.isNavigation()) {		// Unconditional target has unconditional source
+						if (unconditionalNodes.add(sourceNode)) {
 							moreMoreNodes.add(sourceNode);
 						}
 					}
@@ -415,13 +457,20 @@
 				}
 				for (@NonNull Edge outgoingEdge : node.getOutgoingEdges()) {
 					Node targetNode = outgoingEdge.getTarget();
-					if (!isUnconditionable(targetNode)) {}
+					if (!canBeUnconditional(targetNode)) {}
+					else if (outgoingEdge.isComputation()) {}
 					else if (outgoingEdge.isNavigation()) {
-						if (((NavigableEdge)outgoingEdge).isRequired() && unconditionalNodes.add(targetNode)) {
-							moreMoreNodes.add(targetNode);
+						if (targetNode.isExplicitNull()) {
+							if (unconditionalNodes.add(targetNode)) {
+								moreMoreNodes.add(targetNode);
+							}
+						}
+						else if (node.isRequired() && ((NavigableEdge)outgoingEdge).getProperty().isIsRequired()) {
+							if (unconditionalNodes.add(targetNode)) {
+								moreMoreNodes.add(targetNode);
+							}
 						}
 					}
-					else if (outgoingEdge.isComputation()) {}
 					else {
 						System.out.println("Unsupported outgoing edge in " + this + " : " + outgoingEdge);
 					}
@@ -507,14 +556,6 @@
 				|| ExpressionAnalyzer.LOOP_BODY_NAME.equals(edgeName);
 	}
 
-	private boolean isMatchable(@NonNull Node node) {
-		return node.isExplicitNull() || node.isPattern();
-	}
-
-	private boolean isUnconditionable(@NonNull Node node) {
-		return !node.isIterator();
-	}
-
 	@Override
 	public void resetHead(@NonNull Node headNode) {
 		boolean wasRemoved = getHeadNodes().remove(headNode);
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/NavigableEdge.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/NavigableEdge.java
index ba969ed..de9aac7 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/NavigableEdge.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/NavigableEdge.java
@@ -44,11 +44,6 @@
 	 */
 	@NonNull Property getProperty();
 
-	/**
-	 * Return true if this edge has a non-zero target lower bound or if the target node isRequired.
-	 */
-	boolean isRequired();
-
 	void removeIncomingConnection(@NonNull EdgeConnection edgeConnection);
 	void removeOutgoingConnection(@NonNull EdgeConnection edgeConnection);
 }
\ No newline at end of file
diff --git a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/impl/NavigableEdgeImpl.java b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/impl/NavigableEdgeImpl.java
index 93c8c4a..49e2488 100644
--- a/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/impl/NavigableEdgeImpl.java
+++ b/plugins/org.eclipse.qvtd.compiler/src/org/eclipse/qvtd/compiler/internal/qvtp2qvts/impl/NavigableEdgeImpl.java
@@ -195,24 +195,6 @@
 	}
 
 	@Override
-	public boolean isRequired() {
-		Node targetNode = getTarget();
-		Property property = getProperty();
-		if (targetNode.isExplicitNull()) {
-			return true;			// ?? a degenerate typedElement.isIsRequired()
-		}
-		else if (property.isIsRequired()) {
-			return true;
-		}
-		else if (targetNode.isRequired()) {
-			return true;
-		}
-		else {
-			return false;
-		}
-	}
-
-	@Override
 	public boolean isSecondary() {
 		return isSecondary;
 	}