The BIP says:
For backward compatibility, for any version byte from 0 to 16, the script must fail if the witness program has a CastToBool value of zero. However, having a hash like this is a successful preimage attack against the hash function, and the risk is negligible.
(emphasis mine)
So the CastToBool is actually part of old script interpreter code, not the new segwit stuff. Otherwise it would not say "For backward compatibility".
The CastToBools are
https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1588 (native segwit) and
https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1634 (p2sh wrapped).
The reason this requirement is in here is because the interpreter evaluates the scriptSig and scriptPubKey before doing witness program validation. The segwit script (version byte + program) is always the last bit of script executed before witness program validation. So the script interpreter will CastToBool the top stack element, which will always be the witness program. In order for validation to continue to the witness program evaluation, the witness program itself must CastToBool true to get past the script interpreter's check.