It is more that the modes (+,?) and (-,?) are not logically compatible. With a given predicate the system will search for the predicate that is going to do the job should you call it, i.e. called in user it will find that some predicate is not there, but it is in system and report the properties thereof as that is what will be called. In (-,?) mode it just enumerates what is actually imported into the current module and will not do any searching … well, except for predicate_property(P, visible) which mimics the entire search process, returning all predicates you may call that will not result in an (immediate) undefined predicate error.
The lazy properties of SWI-Prolog make a fully logical definition rather impractical as (-,?) mode calls would need to do all possible lazy operations.
?- current_module(M), predicate_property(M:X,static),
predicate_property(M:X,built_in).
M = system,
X = '$destroy_findall_bag' ;
M = system,
X = '$clause_from_source'(_, _, _, _) ;
M = system,
X = '$compilation_level'(_, _) ;
M = system,
X = '$set_autoload_level'(_) ;
M = system,
X = '$prolog_list_goal'(_) ;
M = system,
X = (_=\=_) ;
Etc...
It gives much more results. And predicate_property(_,_) is also among:
?- current_module(M), predicate_property(M:X,static),
predicate_property(M:X,built_in), X=predicate_property(_,_).
M = system,
X = predicate_property(_, _) ;
false.
At least it searches all modules. Given an instantiated predicate though, it will also invoke the autoloader if the predicate is not defined. With an unbound predicate we will not autoload everything that can be autoloaded.
Actually you do not need the current_module(M) as just passing M:X tells predicate property to look in all modules instead of in just the calling module.