hphp/runtime/vm/jit/ir-instruction.cpp
// A pointer iterator type has three components:
//   - The pointer type: it's always PtrToElem, for now
//   - The target type: the union of the possible values of the base array
//   - The constant value: e.g. a specific pointer to the end of a static array
//
// The target type is the key aspect of this type. Because it's the union of
// the possible values of the base array, the type of the pointer iterator
// doesn't change when we advance it. This definition also allows us to type
// the pointer to the end of an array (even though its target is invalid).
//
// This definition makes sense by analogy to regular int* types in C: the type
// of the end of the array is an int* even though its target is invalid.
A pointer iterator type has three components:
The pointer type: it's always PtrToElem, for now
The target type: the union of the possible values of the base array
The constant value: e.g. a specific pointer to the end of a static array

The target type is the key aspect of this type. Because it's the union of
the possible values of the base array, the type of the pointer iterator
doesn't change when we advance it. This definition also allows us to type
the pointer to the end of an array (even though its target is invalid).

This definition makes sense by analogy to regular int* types in C: the type
of the end of the array is an int* even though its target is invalid.
A pointer iterator type has three components : The pointer type : it ' s always PtrToElem for now The target type : the union of the possible values of the base array The constant value : e . g . a specific pointer to the end of a static array The target type is the key aspect of this type . Because it ' s the union of the possible values of the base array the type of the pointer iterator doesn ' t change when we advance it . This definition also allows us to type the pointer to the end of an array ( even though its target is invalid ) . This definition makes sense by analogy to regular int * types in C : the type of the end of the array is an int * even though its target is invalid .
Type ptrIterReturn(const IRInstruction* inst) {
  if (inst->is(AdvanceDictPtrIter, AdvanceVecPtrIter)) {
    auto const ptr = inst->src(0)->type();
    assertx(ptr <= TPtrToElemCell);
    return ptr;
  }
  assertx(inst->is(GetDictPtrIter, GetVecPtrIter));
  auto const arr = inst->src(0)->type();
  assertx(arr <= TArrLike);
  auto const value = [&]{
    if (arr <= TArr)  return arrElemType(arr, TInt | TStr, inst->ctx()).first;
    if (arr <= TVec)  return vecElemType(arr, TInt, inst->ctx()).first;
    if (arr <= TDict) return dictElemType(arr, TInt | TStr).first;
    return TCell;
  }();
  return value.ptr(Ptr::Elem);
}
Type ptrIterReturn ( const IRInstruction * inst ) { if ( inst -> is ( AdvanceDictPtrIter , AdvanceVecPtrIter ) ) { auto const ptr = inst -> src ( 0 ) -> type ( ) ; assertx ( ptr <= TPtrToElemCell ) ; return ptr ; } assertx ( inst -> is ( GetDictPtrIter , GetVecPtrIter ) ) ; auto const arr = inst -> src ( 0 ) -> type ( ) ; assertx ( arr <= TArrLike ) ; auto const value = [ & ] { if ( arr <= TArr ) return arrElemType ( arr , TInt | TStr , inst -> ctx ( ) ) . first ; if ( arr <= TVec ) return vecElemType ( arr , TInt , inst -> ctx ( ) ) . first ; if ( arr <= TDict ) return dictElemType ( arr , TInt | TStr ) . first ; return TCell ; } ( ) ; return value . ptr ( Ptr :: Elem ) ; }
A pointer iterator type has three components:
 The pointer type: it's always PtrToElem, for now
 The target type: the union of the possible values of the base array
 The constant value: e.g.
A pointer iterator type has three components : The pointer type : it ' s always PtrToElem for now The target type : the union of the possible values of the base array The constant value : e . g .