expand_call_goals/3 should expand meta-predicate subgoals (#2361)
This commit is contained in:
@@ -887,7 +887,12 @@ expand_call_goal_(UnexpandedGoals, Module, ExpandedGoals) :-
|
|||||||
UnexpandedGoals = ExpandedGoals
|
UnexpandedGoals = ExpandedGoals
|
||||||
; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
|
; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
|
||||||
( Module \== user ->
|
( Module \== user ->
|
||||||
goal_expansion(UnexpandedGoals1, user, ExpandedGoals)
|
goal_expansion(UnexpandedGoals1, user, Goals),
|
||||||
|
( predicate_property(Module:Goals, meta_predicate(MetaSpecs0)),
|
||||||
|
MetaSpecs0 =.. [_ | MetaSpecs] ->
|
||||||
|
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars, TGs)
|
||||||
|
; ExpandedGoals = Goals
|
||||||
|
)
|
||||||
; ExpandedGoals = UnexpandedGoals1
|
; ExpandedGoals = UnexpandedGoals1
|
||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -287,8 +287,25 @@ impl IndexStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn goal_expansion_defined(&self, key: PredicateKey) -> bool {
|
pub(crate) fn goal_expansion_defined(&self, key: PredicateKey, module_name: Atom) -> bool {
|
||||||
self.goal_expansion_indices.contains(&key)
|
let compilation_target = match module_name {
|
||||||
|
atom!("user") => CompilationTarget::User,
|
||||||
|
_ => CompilationTarget::Module(module_name),
|
||||||
|
};
|
||||||
|
|
||||||
|
match key {
|
||||||
|
_ if self.goal_expansion_indices.contains(&key) => true,
|
||||||
|
_ => self
|
||||||
|
.get_meta_predicate_spec(key.0, key.1, &compilation_target)
|
||||||
|
.map(|meta_specs| {
|
||||||
|
meta_specs.iter().find(|meta_spec| match meta_spec {
|
||||||
|
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|meta_spec_opt| meta_spec_opt.is_some())
|
||||||
|
.unwrap_or(false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_predicate_skeleton_mut(
|
pub(crate) fn get_predicate_skeleton_mut(
|
||||||
|
|||||||
@@ -1339,38 +1339,49 @@ impl Machine {
|
|||||||
let index_cell = index_cell_opt.or_else(|| {
|
let index_cell = index_cell_opt.or_else(|| {
|
||||||
let is_internal_call = name == atom!("$call") && goal_arity > 0;
|
let is_internal_call = name == atom!("$call") && goal_arity > 0;
|
||||||
|
|
||||||
if !is_internal_call && self.indices.goal_expansion_defined((name, arity)) {
|
if !is_internal_call {
|
||||||
None
|
let module_name = if module_name.get_tag() == HeapCellValueTag::Atom {
|
||||||
} else {
|
|
||||||
if is_internal_call {
|
|
||||||
debug_assert_eq!(goal.get_tag(), HeapCellValueTag::Str);
|
|
||||||
goal = self.machine_st.heap[goal.get_value() as usize + 1];
|
|
||||||
(module_name, goal) = self.machine_st.strip_module(goal, module_name);
|
|
||||||
|
|
||||||
if let Some((inner_name, inner_arity)) =
|
|
||||||
self.machine_st.name_and_arity_from_heap(goal)
|
|
||||||
{
|
|
||||||
arity -= goal_arity;
|
|
||||||
(name, goal_arity) = (inner_name, inner_arity);
|
|
||||||
arity += goal_arity;
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let module_name = if module_name.get_tag() != HeapCellValueTag::Atom {
|
|
||||||
if let Some(load_context) = self.load_contexts.last() {
|
|
||||||
load_context.module
|
|
||||||
} else {
|
|
||||||
atom!("user")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cell_as_atom!(module_name)
|
cell_as_atom!(module_name)
|
||||||
|
} else {
|
||||||
|
atom!("user")
|
||||||
};
|
};
|
||||||
|
|
||||||
self.indices
|
if self
|
||||||
.get_predicate_code_index(name, arity, module_name)
|
.indices
|
||||||
|
.goal_expansion_defined((name, arity), module_name)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_internal_call {
|
||||||
|
debug_assert_eq!(goal.get_tag(), HeapCellValueTag::Str);
|
||||||
|
goal = self.machine_st.heap[goal.get_value() as usize + 1];
|
||||||
|
(module_name, goal) = self.machine_st.strip_module(goal, module_name);
|
||||||
|
|
||||||
|
if let Some((inner_name, inner_arity)) =
|
||||||
|
self.machine_st.name_and_arity_from_heap(goal)
|
||||||
|
{
|
||||||
|
arity -= goal_arity;
|
||||||
|
(name, goal_arity) = (inner_name, inner_arity);
|
||||||
|
arity += goal_arity;
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let module_name = if module_name.get_tag() != HeapCellValueTag::Atom {
|
||||||
|
if let Some(load_context) = self.load_contexts.last() {
|
||||||
|
load_context.module
|
||||||
|
} else {
|
||||||
|
atom!("user")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cell_as_atom!(module_name)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.indices
|
||||||
|
.get_predicate_code_index(name, arity, module_name)
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(code_index) = index_cell {
|
if let Some(code_index) = index_cell {
|
||||||
|
|||||||
3
tests-pl/issue2361-call-qualified.pl
Normal file
3
tests-pl/issue2361-call-qualified.pl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
:- use_module(issue2361_m).
|
||||||
|
|
||||||
|
:- initialization(gs([(length("a",_),length("ab",_))])).
|
||||||
8
tests-pl/issue2361_m.pl
Normal file
8
tests-pl/issue2361_m.pl
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
:- module(m, [gs/1]).
|
||||||
|
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
|
gs([]).
|
||||||
|
gs([G|Gs]) :-
|
||||||
|
G,
|
||||||
|
gs(Gs).
|
||||||
@@ -11,3 +11,10 @@ fn call_0() {
|
|||||||
" error(existence_error(procedure,call/0),call/0).\n",
|
" error(existence_error(procedure,call/0),call/0).\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// issue #2361
|
||||||
|
#[serial]
|
||||||
|
#[test]
|
||||||
|
fn call_qualification() {
|
||||||
|
load_module_test("tests-pl/issue2361-call-qualified.pl", "");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user