IIRC this was an intentional decision, made on the grounds that we can't tell whether the function/operator actually cares about having a determinate collation or not, so we have to leave it to execution of that function/operator to complain or not.
In this case, why treat implicit and explicit collation conflicts differently? A conflicting explicit collation will produce an error during planning, whereas a conflicting implicit collation will not produce an error until execution.
create table foo(a text COLLATE "es_ES"); create table bar(b text COLLATE "de_DE"); insert into foo values('a'), ('b'), ('c'), ('d'); insert into bar values('b'), ('c'), ('g'), ('h');
SELECT * FROM foo WHERE a > (SELECT b FROM bar LIMIT 1); -- error during execution
EXPLAIN SELECT * FROM foo WHERE a > (SELECT b FROM bar LIMIT 1); -- but no error during planning
It seems like this would not allow the function/operator to decide if it cares about a determinate collation during execution, since it would already have errored out during planning.