void handleInSelfElemU(MIS& env) { if (!couldBeInSelf(env, env.base)) return; if (auto const name = env.base.locName) { auto const ty = selfPropAsCell(env, name); if (ty) mergeSelfProp(env, name, loosen_statics(*ty)); } else { mergeEachSelfPropRaw(env, loosen_statics); } }
Type typeIncDec(IncDecOp op, Type t) { auto const overflowToDbl = isIncDecO(op); auto const val = tv(t); if (!val) { // Doubles always stay doubles if (t.subtypeOf(TDbl)) return TDbl; // Ints stay ints unless they can overflow to doubles if (t.subtypeOf(TInt)) { return overflowToDbl ? TNum : TInt; } // Null goes to 1 on ++, stays null on --. Uninit is folded to init. if (t.subtypeOf(TNull)) { return isInc(op) ? ival(1) : TInitNull; } // No-op on bool, array, resource, object. if (t.subtypeOfAny(TBool, TArr, TRes, TObj)) return t; // Last unhandled case: strings. These result in Int|Str because of the // behavior on strictly-numeric strings, and we can't express that yet. return TInitCell; } auto const inc = isInc(op); // We can't constprop with this eval_cell, because of the effects // on locals. auto resultTy = eval_cell([inc,overflowToDbl,val] { auto c = *val; if (inc) { (overflowToDbl ? cellIncO : cellInc)(c); } else { (overflowToDbl ? cellDecO : cellDec)(c); } return c; }); if (!resultTy) resultTy = TInitCell; // We may have inferred a TSStr or TSArr with a value here, but at // runtime it will not be static. resultTy = loosen_statics(*resultTy); return *resultTy; }
Type typeSame(const Type& a, const Type& b) { auto const nsa = loosen_statics(a); auto const nsb = loosen_statics(b); if (!nsa.couldBe(nsb)) return TFalse; return TBool; }