You may need to study skolems / rank-N types. The exact scope of the "IO" is inside the Wrapper, and nowhere else; so using it in let at all allows it to be visible outside its scope. With the case expression, it can be visible anywhere in the case alternative that pattern matches the Wrapper without it necessarily escaping the scope (you could explicitly leak it, but it will raise the same error about it escaping in that case).
GADTs are a way to get this same case matchung behavior, but it still doesn't help you with this; you are asking that the compiler ignore the rank of the type variable and make it visible outside its scope so that you can use let instead of case, and ghc will not let you do this.