E3056
E3056 —spawn { .. }outside atasks { .. }block. The end of thetasksblock waits for each task, so a task cannot outlive the variables it uses. Aspawnin a closure, or directly in another task, is outside the block too. Put thespawnin atasksblock of its own.
What the compiler reports
Error[E3056] at [[@LINE+2]]:11: `spawn { .. }` must be in a `tasks { .. }` block
Error[E3056] at [[@LINE+3]]:23: a `spawn` in a closure is not in a `tasks` block
Error[E3056] at [[@LINE+4]]:7: a `spawn` directly in a task is not in a `tasks` block
Error[E3057] at [[@LINE+6]]:5: 'h' is a task handle
Error[E3057] at [[@LINE+6]]:13: 'h' is a task handle
Error[E3057] at [[@LINE+3]]:11: a task must not leave its `tasks` block, so a `spawn` must be the value of a `let` or a statement of its own
Error[E3001] at [[@LINE+3]]:5: 'h' is a task handle of type 'Task<i32>', not 'i32'
Error[E3058] at [[@LINE+4]]:7: a `return` cannot leave a task
Error[E3058] at [[@LINE+5]]:9: a `break` cannot leave a task
Error[E3058] at [[@LINE+7]]:9: a task cannot join another task yet
Error[E4001] at [[@LINE+7]]:5: Use of moved or consumed linear variable: h
{{^}}Semantic check failed on {{.*}}: 11 error(s) emitted
The fragments the test suite holds the compiler to. An ellipsis marks text the test does not constrain; the emitted message also carries a source location.
A program that triggers it
//
// Part of the Vx Project, under the Apache License v2.0 with LLVM Exceptions.
// See LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
// The end of a `tasks` block waits for each task that it started. So a `spawn` must be in a
// `tasks` block, and a task handle must not leave it: its only use is `h.join()`. A task body
// ends with its result, so a `return` or `break` must not leave it.
fn no_tasks_block() -> i32 {
let h = spawn {
1
};
return h.join();
}
fn spawn_in_a_closure() -> void {
tasks {
let f = |x : i32| spawn {
x
};
}
}
fn spawn_directly_in_a_task() -> void {
tasks {
spawn {
spawn {
1
};
};
}
}
fn handle_is_the_value_of_the_block() -> i32 {
return tasks {
let h = spawn {
1
};
h
};
}
fn handle_given_to_a_variable() -> void {
tasks {
let h = spawn {
1
};
let g = h;
}
}
fn spawn_as_an_argument() -> void {
tasks {
print(spawn {
1
});
}
}
fn handle_with_a_wrong_type() -> void {
tasks {
let h : i32 = spawn {
1
};
h.join();
}
}
fn return_from_a_task() -> i32 {
tasks {
spawn {
return 1;
};
}
return 0;
}
fn break_out_of_a_task() -> void {
tasks {
for i in 0..3 {
spawn {
break;
};
}
}
}
fn task_joins_a_task() -> void {
tasks {
let a = spawn {
1
};
let b = spawn {
a.join() + 1
};
b.join();
}
}
fn joined_twice() -> void {
tasks {
let h = spawn {
1
};
h.join();
h.join();
}
}
fn main() -> i32 {
return 0;
}
// The errors above are all the errors.
From tests/frontend/fail/spawn_outside_a_tasks_block_and_handles_that_leave_it.vx, which asserts this diagnostic on every commit.
Related
A tour of VxThe chapter covering the rule this code enforces.
All diagnosticsEvery code the compiler can emit, grouped by stage.
E3055A task takes a value that is not
Send, or reads a variable whose type is not Sync. A task that moves a value, copies it or writes it needs Send. A task that reads a variable in place shares it with the code around the task, so it needs Sync. The error names the field that makes the type fail.
E3057A task handle used in a way other than h.join(), or a spawn that is not the value of a let or a statement of its own. A task must not leave its tasks block, so the program cannot return a handle, store it, or pass it to a function. Write let h = spawn { .. }; and later h.join().