diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index fe83e45311..a9accbed53 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1087,38 +1087,12 @@ arrayexpr_cleanup_fn(PredIterInfo info)
 }
 
 
-/*----------
+/*
  * predicate_implied_by_simple_clause
  *	  Does the predicate implication test for a "simple clause" predicate
  *	  and a "simple clause" restriction.
  *
  * We return true if able to prove the implication, false if not.
- *
- * We have several strategies for determining whether one simple clause
- * implies another:
- *
- * A simple and general way is to see if they are equal(); this works for any
- * kind of expression, and for either implication definition.  (Actually,
- * there is an implied assumption that the functions in the expression are
- * immutable --- but this was checked for the predicate by the caller.)
- *
- * Another way that always works is that for boolean x, "x = TRUE" is
- * equivalent to "x", likewise "x = FALSE" is equivalent to "NOT x".
- * These can be worth checking because, while we preferentially simplify
- * boolean comparisons down to "x" and "NOT x", the other form has to be
- * dealt with anyway in the context of index conditions.
- *
- * If the predicate is of the form "foo IS NOT NULL", and we are considering
- * strong implication, we can conclude that the predicate is implied if the
- * clause is strict for "foo", i.e., it must yield false or NULL when "foo"
- * is NULL.  In that case truth of the clause ensures that "foo" isn't NULL.
- * (Again, this is a safe conclusion because "foo" must be immutable.)
- * This doesn't work for weak implication, though.
- *
- * Finally, if both clauses are binary operator expressions, we may be able
- * to prove something using the system's knowledge about operators; those
- * proof rules are encapsulated in operator_predicate_proof().
- *----------
  */
 static bool
 predicate_implied_by_simple_clause(Expr *predicate, Node *clause,
@@ -1127,65 +1101,115 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause,
 	/* Allow interrupting long proof attempts */
 	CHECK_FOR_INTERRUPTS();
 
-	/* First try the equal() test */
+	/*
+	 * A simple and general rule is that a clause implies itself, hence we
+	 * check if they are equal(); this works for any kind of expression, and
+	 * for either implication definition.  (Actually, there is an implied
+	 * assumption that the functions in the expression are immutable --- but
+	 * this was checked for the predicate by the caller.)
+	 */
 	if (equal((Node *) predicate, clause))
 		return true;
 
-	/* Next see if clause is boolean equality to a constant */
-	if (is_opclause(clause) &&
-		((OpExpr *) clause)->opno == BooleanEqualOperator)
+	/* Our remaining strategies are all clause-type-specific */
+	switch (nodeTag(clause))
 	{
-		OpExpr	   *op = (OpExpr *) clause;
-		Node	   *rightop;
-
-		Assert(list_length(op->args) == 2);
-		rightop = lsecond(op->args);
-		/* We might never see a null Const here, but better check anyway */
-		if (rightop && IsA(rightop, Const) &&
-			!((Const *) rightop)->constisnull)
-		{
-			Node	   *leftop = linitial(op->args);
-
-			if (DatumGetBool(((Const *) rightop)->constvalue))
+		case T_OpExpr:
 			{
-				/* X = true implies X */
-				if (equal(predicate, leftop))
-					return true;
+				OpExpr	   *op = (OpExpr *) clause;
+
+				/*----------
+				 * For boolean x, "x = TRUE" is equivalent to "x", likewise
+				 * "x = FALSE" is equivalent to "NOT x".  These can be worth
+				 * checking because, while we preferentially simplify boolean
+				 * comparisons down to "x" and "NOT x", the other form has to
+				 * be dealt with anyway in the context of index conditions.
+				 *
+				 * We could likewise check whether the predicate is boolean
+				 * equality to a constant; but there are no known use-cases
+				 * for that at the moment, assuming that the predicate has
+				 * been through constant-folding.
+				 *----------
+				 */
+				if (op->opno == BooleanEqualOperator)
+				{
+					Node	   *rightop;
+
+					Assert(list_length(op->args) == 2);
+					rightop = lsecond(op->args);
+
+					/*
+					 * We might never see a null Const here, but better check
+					 * anyway
+					 */
+					if (rightop && IsA(rightop, Const) &&
+						!((Const *) rightop)->constisnull)
+					{
+						Node	   *leftop = linitial(op->args);
+
+						if (DatumGetBool(((Const *) rightop)->constvalue))
+						{
+							/* X = true implies X */
+							if (equal(predicate, leftop))
+								return true;
+						}
+						else
+						{
+							/* X = false implies NOT X */
+							if (is_notclause(predicate) &&
+								equal(get_notclausearg(predicate), leftop))
+								return true;
+						}
+					}
+				}
 			}
-			else
+			break;
+		default:
+			break;
+	}
+
+	/* ... or predicate-type-specific */
+	switch (nodeTag(predicate))
+	{
+		case T_NullTest:
 			{
-				/* X = false implies NOT X */
-				if (is_notclause(predicate) &&
-					equal(get_notclausearg(predicate), leftop))
-					return true;
+				NullTest   *ntest = (NullTest *) predicate;
+
+				switch (ntest->nulltesttype)
+				{
+					case IS_NOT_NULL:
+
+						/*
+						 * If the predicate is of the form "foo IS NOT NULL",
+						 * and we are considering strong implication, we can
+						 * conclude that the predicate is implied if the
+						 * clause is strict for "foo", i.e., it must yield
+						 * false or NULL when "foo" is NULL.  In that case
+						 * truth of the clause ensures that "foo" isn't NULL.
+						 * (Again, this is a safe conclusion because "foo"
+						 * must be immutable.)  This doesn't work for weak
+						 * implication, though.  Also, "row IS NOT NULL" does
+						 * not act in the simple way we have in mind.
+						 */
+						if (!weak &&
+							!ntest->argisrow &&
+							clause_is_strict_for(clause, (Node *) ntest->arg, true))
+							return true;
+						break;
+					default:
+						break;
+				}
 			}
-		}
+			break;
+		default:
+			break;
 	}
 
 	/*
-	 * We could likewise check whether the predicate is boolean equality to a
-	 * constant; but there are no known use-cases for that at the moment,
-	 * assuming that the predicate has been through constant-folding.
+	 * If both clauses are binary operator expressions, we may be able to
+	 * prove something using the system's knowledge about operators; those
+	 * proof rules are encapsulated in operator_predicate_proof().
 	 */
-
-	/* Next try the IS NOT NULL case */
-	if (!weak &&
-		predicate && IsA(predicate, NullTest))
-	{
-		NullTest   *ntest = (NullTest *) predicate;
-
-		/* row IS NOT NULL does not act in the simple way we have in mind */
-		if (ntest->nulltesttype == IS_NOT_NULL &&
-			!ntest->argisrow)
-		{
-			/* strictness of clause for foo implies foo IS NOT NULL */
-			if (clause_is_strict_for(clause, (Node *) ntest->arg, true))
-				return true;
-		}
-		return false;			/* we can't succeed below... */
-	}
-
-	/* Else try operator-related knowledge */
 	return operator_predicate_proof(predicate, clause, false, weak);
 }
 
