Maybe to give context to the other answers, try to avoid
UncheckAccount/AccountInfo where possible. However, there may be situations where this is unavoidable.
CPI's are a possible scenario where you may end up needing to use these two types.
Because of rust's package manager, cyclic imports are not allowed. What this means for smart contracts on solana is:
If one smart contract (A) wants to be able to make cpi calls to another program (B),
They likely take the other program in via a
Program<'info, ProgramB>
For this to be recognized, they also have to import the other program's crate/library.
If the other program (B) wants to further ensure that what calls it, is indeed program A - it can not import program A and verify via Program<'info, ProgramA>
because this would lead to a cyclic import cycle
The only way (at time of writing this)
would be via AccountInfo or UncheckedAccount and add the
#[account(executable)]
macro check on it in Program B
#[account(executable, address = Pubkey::new([program a's pubkey]))]
pub program_a: UncheckedAccount<'info>