Fix #2725 by calling load_context/1 in the unspecified branch of strip_module/3
This fixes #2725, by making it so that `strip_module(Pred, M, P), call(M:P)` doesn't throw an `instanciation_error` when `Pred` isn't in the form `module:predicate`. Now, `strip_module(hello, M, P)` will call `load_context(M)`, which unifies `M` with the topmost module (or `user`). Two new test cases are added: issue2725.pl, which tests the minimal case id(X) --> X. and the strip_module(P, M, _), call(M:P) scenario, and module_resolution, which tests the behavior of strip_module in a few scenarios.
This commit is contained in:
@@ -1175,7 +1175,7 @@ clause(H, B) :-
|
||||
% Asserts (inserts) a new clause (rule or fact) into the current module.
|
||||
% The clause will be inserted at the beginning of the module.
|
||||
asserta(Clause0) :-
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
asserta_(Module, Clause).
|
||||
|
||||
asserta_(Module, (Head :- Body)) :-
|
||||
@@ -1191,7 +1191,7 @@ asserta_(Module, Fact) :-
|
||||
% Asserts (inserts) a new clause (rule or fact) into the current module.
|
||||
% The clase will be inserted at the end of the module.
|
||||
assertz(Clause0) :-
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
assertz_(Module, Clause).
|
||||
|
||||
assertz_(Module, (Head :- Body)) :-
|
||||
@@ -1211,15 +1211,9 @@ retract(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
loader:strip_module(Clause, Module, Head),
|
||||
( var(Module) -> Module = user
|
||||
; true
|
||||
),
|
||||
Body = true,
|
||||
retract_module_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
( var(Module) -> Module = user
|
||||
; true
|
||||
),
|
||||
retract_module_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
@@ -1374,10 +1368,6 @@ current_predicate(Pred) :-
|
||||
'$get_db_refs'(_, _, _, PIs),
|
||||
lists:member(Pred, PIs)
|
||||
; loader:strip_module(Pred, Module, UnqualifiedPred),
|
||||
( var(Module),
|
||||
\+ functor(Pred, (:), 2)
|
||||
; atom(Module)
|
||||
),
|
||||
UnqualifiedPred = Name/Arity ->
|
||||
( ( nonvar(Name), \+ atom(Name)
|
||||
; nonvar(Arity), \+ integer(Arity)
|
||||
|
||||
@@ -695,10 +695,9 @@ strip_module(Goal, M, G) :-
|
||||
( MQ = specified(M) ->
|
||||
true
|
||||
; MQ = unspecified,
|
||||
true
|
||||
load_context(M)
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking strip_subst_module/4.
|
||||
|
||||
strip_subst_module(Goal, M1, M2, G) :-
|
||||
|
||||
@@ -104,6 +104,22 @@ use super::libraries;
|
||||
use super::preprocessor::to_op_decl;
|
||||
use super::preprocessor::to_op_decl_spec;
|
||||
|
||||
/// Represents the presence (or absence) of a `module:` prefix to predicates, used to
|
||||
/// refer to predicates defined in a given `module` that haven't been imported
|
||||
/// (through `use_module/1`) or exported.
|
||||
///
|
||||
/// On the Rust side, [`MachineState::strip_module`] splits a given [`HeapCellValue`] into
|
||||
/// a pair of [`ModuleQuantification`] and `HeapCellValue`.
|
||||
///
|
||||
/// On the Prolog side, `strip_module(X, Y, Z)` is a wrapper around [`MachineState::strip_module`],
|
||||
/// which takes care of splitting the `X = module:predicate` pair into `Y = module` and
|
||||
/// `Z = predicate`. If no module prefix is present (ie. [`MachineState::strip_module`] returned
|
||||
/// `Unspecified`), then `strip_module/3` calls `load_context(Y)`, unifying `Y` with the currently
|
||||
/// loaded module (or `user`).
|
||||
///
|
||||
/// [`Machine::quantification_to_module_name`] provides a similar mechanism on the Rust side to
|
||||
/// obtain the currently loaded module in the `Unspecified` case.
|
||||
/// It also defaults to `user`, for instance if we are in the REPL.
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ModuleQuantification {
|
||||
Specified(HeapCellValue),
|
||||
|
||||
8
src/tests/module_resolution.pl
Normal file
8
src/tests/module_resolution.pl
Normal file
@@ -0,0 +1,8 @@
|
||||
:- module(module_resolution, [get_module/2]).
|
||||
|
||||
get_module(P, M) :- strip_module(P, M, _).
|
||||
|
||||
:- initialization((strip_module(hello, M, _), write(M), write('\n'))).
|
||||
:- initialization((loader:strip_module(hello, M, _), write(M), write('\n'))).
|
||||
:- initialization((get_module(hello, M), write(M), write('\n'))).
|
||||
:- initialization((module_resolution:get_module(hello, M), write(M), write('\n'))).
|
||||
Reference in New Issue
Block a user