Skip to content

Commit

Permalink
Fix sleeping code under spawn() triggering SpacemanDMM_should_not_sle…
Browse files Browse the repository at this point in the history
…ep (#177)

Fixes #175.
  • Loading branch information
Cyberboss authored Jul 3, 2020
1 parent 430dff1 commit 36e69a3
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 19 deletions.
41 changes: 22 additions & 19 deletions src/dreamchecker/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,15 +468,15 @@ pub fn directive_value_to_truthy(expr: &Expression, location: Location) -> Resul
}
}

/// An ordered chain of ProcRef calls with their location
/// An ordered chain of ProcRef calls with their location and whether or not they are in a new context
#[derive(Default, Clone)]
pub struct CallStack<'o> {
call_stack: VecDeque<(ProcRef<'o>, Location)>,
call_stack: VecDeque<(ProcRef<'o>, Location, bool)>,
}

impl<'o> CallStack<'o> {
pub fn add_step(&mut self, proc: ProcRef<'o>, location: Location) {
self.call_stack.push_back((proc, location));
pub fn add_step(&mut self, proc: ProcRef<'o>, location: Location, new_context: bool) {
self.call_stack.push_back((proc, location, new_context));
}
}

Expand All @@ -488,7 +488,7 @@ trait DMErrorExt {

impl DMErrorExt for DMError {
fn with_callstack(mut self, stack: CallStack) -> DMError {
for (procref, location) in stack.call_stack.iter() {
for (procref, location, new_context) in stack.call_stack.iter() {
self.add_note(*location, format!("{}() called here", procref));
}
self
Expand Down Expand Up @@ -541,7 +541,7 @@ pub struct AnalyzeObjectTree<'o> {
// Debug(ProcRef) -> KwargInfo
used_kwargs: BTreeMap<String, KwargInfo>,

call_tree: HashMap<ProcRef<'o>, Vec<(ProcRef<'o>, Location)>>,
call_tree: HashMap<ProcRef<'o>, Vec<(ProcRef<'o>, Location, bool)>>,

sleeping_procs: ViolatingProcs<'o>,
impure_procs: ViolatingProcs<'o>,
Expand Down Expand Up @@ -639,15 +639,15 @@ impl<'o> AnalyzeObjectTree<'o> {
.register(self.context)
}
let mut visited = HashSet::<ProcRef<'o>>::new();
let mut to_visit = VecDeque::<(ProcRef<'o>, CallStack)>::new();
let mut to_visit = VecDeque::<(ProcRef<'o>, CallStack, bool)>::new();
if let Some(procscalled) = self.call_tree.get(procref) {
for (proccalled, location) in procscalled {
for (proccalled, location, new_context) in procscalled {
let mut callstack = CallStack::default();
callstack.add_step(*proccalled, *location);
to_visit.push_back((*proccalled, callstack));
callstack.add_step(*proccalled, *location, *new_context);
to_visit.push_back((*proccalled, callstack, *new_context));
}
}
while let Some((nextproc, callstack)) = to_visit.pop_front() {
while let Some((nextproc, callstack, new_context)) = to_visit.pop_front() {
if !visited.insert(nextproc) {
continue
}
Expand All @@ -657,6 +657,9 @@ impl<'o> AnalyzeObjectTree<'o> {
if let Some(_) = self.sleep_exempt.get(nextproc) {
continue
}
if new_context {
continue
}
if let Some(sleepvec) = self.sleeping_procs.get_violators(nextproc) {
error(procref.get().location, format!("{} sets SpacemanDMM_should_not_sleep but calls blocking proc {}", procref, nextproc))
.with_note(location, "SpacemanDMM_should_not_sleep set here")
Expand All @@ -665,10 +668,10 @@ impl<'o> AnalyzeObjectTree<'o> {
.with_blocking_builtins(sleepvec)
.register(self.context)
} else if let Some(calledvec) = self.call_tree.get(&nextproc) {
for (proccalled, location) in calledvec.iter() {
for (proccalled, location, new_context) in calledvec.iter() {
let mut newstack = callstack.clone();
newstack.add_step(*proccalled, *location);
to_visit.push_back((*proccalled, newstack));
newstack.add_step(*proccalled, *location, *new_context);
to_visit.push_back((*proccalled, newstack, *new_context));
}
}
}
Expand All @@ -685,9 +688,9 @@ impl<'o> AnalyzeObjectTree<'o> {
let mut visited = HashSet::<ProcRef<'o>>::new();
let mut to_visit = VecDeque::<(ProcRef<'o>, CallStack)>::new();
if let Some(procscalled) = self.call_tree.get(procref) {
for (proccalled, location) in procscalled {
for (proccalled, location, new_context) in procscalled {
let mut callstack = CallStack::default();
callstack.add_step(*proccalled, *location);
callstack.add_step(*proccalled, *location, *new_context);
to_visit.push_back((*proccalled, callstack));
}
}
Expand All @@ -703,9 +706,9 @@ impl<'o> AnalyzeObjectTree<'o> {
.with_impure_operations(impurevec)
.register(self.context)
} else if let Some(calledvec) = self.call_tree.get(&nextproc) {
for (proccalled, location) in calledvec.iter() {
for (proccalled, location, new_context) in calledvec.iter() {
let mut newstack = callstack.clone();
newstack.add_step(*proccalled, *location);
newstack.add_step(*proccalled, *location, *new_context);
to_visit.push_back((*proccalled, newstack));
}
}
Expand Down Expand Up @@ -1958,7 +1961,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
}

fn visit_call(&mut self, location: Location, src: TypeRef<'o>, proc: ProcRef<'o>, args: &'o [Expression], is_exact: bool, local_vars: &mut HashMap<String, LocalVar<'o>>) -> Analysis<'o> {
self.env.call_tree.entry(self.proc_ref).or_default().push((proc, location));
self.env.call_tree.entry(self.proc_ref).or_default().push((proc, location, self.inside_newcontext != 0));
if let Some((privateproc, true, decllocation)) = self.env.private.get_self_or_parent(proc) {
if self.ty != privateproc.ty() {
error(location, format!("{} attempting to call private proc {}, types do not match", self.proc_ref, privateproc))
Expand Down
10 changes: 10 additions & 0 deletions src/dreamchecker/tests/sleep_pure_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ fn sleep() {
/mob/proc/test4()
set SpacemanDMM_should_not_sleep = TRUE
bar()
/proc/spawnthensleepproc()
spawn(1)
sleep(1)
/mob/proc/test5()
set SpacemanDMM_should_not_sleep = TRUE
spawn(1)
sleepingproc()
/mob/proc/test6()
set SpacemanDMM_should_not_sleep = TRUE
spawnthensleepproc()
"##.trim();
check_errors_match(code, SLEEP_ERRORS);
}
Expand Down

0 comments on commit 36e69a3

Please sign in to comment.