+
+ // FIXME: This code should really use AbstractValue::isType() and
+ // AbstractValue::couldBeType().
+ // https://bugs.webkit.org/show_bug.cgi?id=146870
+
+ bool constantWasSet = false;
+ switch (node->op()) {
+ case IsUndefined:
+ // FIXME: Use the masquerades-as-undefined watchpoint thingy.
+ // https://bugs.webkit.org/show_bug.cgi?id=144456
+
+ if (!(child.m_type & (SpecOther | SpecObjectOther))) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+ case IsBoolean:
+ if (!(child.m_type & ~SpecBoolean)) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ if (!(child.m_type & SpecBoolean)) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+ case IsNumber:
+ if (!(child.m_type & ~SpecFullNumber)) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ if (!(child.m_type & SpecFullNumber)) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+ case IsString:
+ if (!(child.m_type & ~SpecString)) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ if (!(child.m_type & SpecString)) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+ case IsObject:
+ if (!(child.m_type & ~SpecObject)) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ if (!(child.m_type & SpecObject)) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+ case IsObjectOrNull:
+ // FIXME: Use the masquerades-as-undefined watchpoint thingy.
+ // https://bugs.webkit.org/show_bug.cgi?id=144456
+
+ // These expressions are complicated to parse. A helpful way to parse this is that
+ // "!(T & ~S)" means "T is a subset of S". Conversely, "!(T & S)" means "T is a
+ // disjoint set from S". Things like "T - S" means that, provided that S is a
+ // subset of T, it's the "set of all things in T but not in S". Things like "T | S"
+ // mean the "union of T and S".
+
+ // Is the child's type an object that isn't an other-object (i.e. object that could
+ // have masquaredes-as-undefined traps) and isn't a function? Then: we should fold
+ // this to true.
+ if (!(child.m_type & ~(SpecObject - SpecObjectOther - SpecFunction))) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ // Is the child's type definitely not either of: an object that isn't a function,
+ // or either undefined or null? Then: we should fold this to false. This means
+ // for example that if it's any non-function object, including those that have
+ // masquerades-as-undefined traps, then we don't fold. It also means we won't fold
+ // if it's undefined-or-null, since the type bits don't distinguish between
+ // undefined (which should fold to false) and null (which should fold to true).
+ if (!(child.m_type & ((SpecObject - SpecFunction) | SpecOther))) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+
+ break;
+ case IsFunction:
+ if (!(child.m_type & ~SpecFunction)) {
+ setConstant(node, jsBoolean(true));
+ constantWasSet = true;
+ break;
+ }
+
+ if (!(child.m_type & (SpecFunction | SpecObjectOther))) {
+ setConstant(node, jsBoolean(false));
+ constantWasSet = true;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if (constantWasSet)
+ break;
+