A Type Checking Algorithm for Higher-Rank, Impredicative and Second-Order Types