Move checks for closure bounds out of kind.rs
This commit is contained in:
parent
034f69ec4b
commit
2ec305d1bc
10 changed files with 74 additions and 171 deletions
|
@ -146,10 +146,7 @@ register_diagnostics!(
|
||||||
E0139,
|
E0139,
|
||||||
E0140,
|
E0140,
|
||||||
E0141,
|
E0141,
|
||||||
E0143,
|
|
||||||
E0144,
|
E0144,
|
||||||
E0145,
|
|
||||||
E0146,
|
|
||||||
E0152,
|
E0152,
|
||||||
E0153,
|
E0153,
|
||||||
E0154,
|
E0154,
|
||||||
|
|
|
@ -30,11 +30,6 @@ pub struct Context<'a,'tcx:'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
|
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
|
||||||
fn visit_fn(&mut self, fk: visit::FnKind, fd: &'v FnDecl,
|
|
||||||
b: &'v Block, s: Span, n: NodeId) {
|
|
||||||
check_fn(self, fk, fd, b, s, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: &Ty) {
|
fn visit_ty(&mut self, t: &Ty) {
|
||||||
check_ty(self, t);
|
check_ty(self, t);
|
||||||
}
|
}
|
||||||
|
@ -48,110 +43,6 @@ pub fn check_crate(tcx: &ty::ctxt) {
|
||||||
tcx.sess.abort_if_errors();
|
tcx.sess.abort_if_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yields the appropriate function to check the kind of closed over
|
|
||||||
// variables. `id` is the NodeId for some expression that creates the
|
|
||||||
// closure.
|
|
||||||
fn with_appropriate_checker(cx: &Context,
|
|
||||||
id: NodeId,
|
|
||||||
fn_span: Span,
|
|
||||||
b: |checker: |&Context, &ty::Freevar||) {
|
|
||||||
fn check_for_uniq(cx: &Context,
|
|
||||||
fn_span: Span,
|
|
||||||
fv: &ty::Freevar,
|
|
||||||
bounds: ty::BuiltinBounds) {
|
|
||||||
// all captured data must be owned, regardless of whether it is
|
|
||||||
// moved in or copied in.
|
|
||||||
let id = fv.def.def_id().node;
|
|
||||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
|
||||||
|
|
||||||
check_freevar_bounds(cx, fn_span, fv.span, var_t, bounds, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_for_block(cx: &Context,
|
|
||||||
fn_span: Span,
|
|
||||||
fn_id: NodeId,
|
|
||||||
fv: &ty::Freevar,
|
|
||||||
bounds: ty::BuiltinBounds) {
|
|
||||||
let id = fv.def.def_id().node;
|
|
||||||
let var_t = ty::node_id_to_type(cx.tcx, id);
|
|
||||||
let upvar_id = ty::UpvarId { var_id: id, closure_expr_id: fn_id };
|
|
||||||
let upvar_borrow = cx.tcx.upvar_borrow(upvar_id);
|
|
||||||
let implicit_borrowed_type =
|
|
||||||
ty::mk_rptr(cx.tcx,
|
|
||||||
upvar_borrow.region,
|
|
||||||
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
|
|
||||||
ty: var_t });
|
|
||||||
check_freevar_bounds(cx, fn_span, fv.span, implicit_borrowed_type,
|
|
||||||
bounds, Some(var_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_for_bare(cx: &Context, fv: &ty::Freevar) {
|
|
||||||
span_err!(cx.tcx.sess, fv.span, E0143,
|
|
||||||
"can't capture dynamic environment in a fn item; \
|
|
||||||
use the || {} closure form instead", "{ ... }");
|
|
||||||
} // same check is done in resolve.rs, but shouldn't be done
|
|
||||||
|
|
||||||
let fty = ty::node_id_to_type(cx.tcx, id);
|
|
||||||
match ty::get(fty).sty {
|
|
||||||
ty::ty_closure(box ty::ClosureTy {
|
|
||||||
store: ty::UniqTraitStore,
|
|
||||||
bounds: bounds,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
b(|cx, fv| check_for_uniq(cx, fn_span, fv,
|
|
||||||
bounds.builtin_bounds))
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::ty_closure(box ty::ClosureTy {
|
|
||||||
store: ty::RegionTraitStore(..), bounds, ..
|
|
||||||
}) => {
|
|
||||||
b(|cx, fv| check_for_block(cx, fn_span, id, fv,
|
|
||||||
bounds.builtin_bounds))
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::ty_bare_fn(_) => {
|
|
||||||
b(check_for_bare)
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::ty_unboxed_closure(..) => {}
|
|
||||||
|
|
||||||
ref s => {
|
|
||||||
cx.tcx.sess.bug(format!("expect fn type in kind checker, not \
|
|
||||||
{:?}",
|
|
||||||
s).as_slice());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the free variables used in a shared/sendable closure conform
|
|
||||||
// to the copy/move kind bounds. Then recursively check the function body.
|
|
||||||
fn check_fn(
|
|
||||||
cx: &mut Context,
|
|
||||||
fk: visit::FnKind,
|
|
||||||
decl: &FnDecl,
|
|
||||||
body: &Block,
|
|
||||||
sp: Span,
|
|
||||||
fn_id: NodeId) {
|
|
||||||
|
|
||||||
// <Check kinds on free variables:
|
|
||||||
with_appropriate_checker(cx, fn_id, sp, |chk| {
|
|
||||||
ty::with_freevars(cx.tcx, fn_id, |freevars| {
|
|
||||||
for fv in freevars.iter() {
|
|
||||||
chk(cx, fv);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
match fk {
|
|
||||||
visit::FkFnBlock(..) => {
|
|
||||||
visit::walk_fn(cx, fk, decl, body, sp)
|
|
||||||
}
|
|
||||||
visit::FkItemFn(..) | visit::FkMethod(..) => {
|
|
||||||
visit::walk_fn(cx, fk, decl, body, sp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_ty(cx: &mut Context, aty: &Ty) {
|
fn check_ty(cx: &mut Context, aty: &Ty) {
|
||||||
match aty.node {
|
match aty.node {
|
||||||
TyPath(_, _, id) => {
|
TyPath(_, _, id) => {
|
||||||
|
@ -208,29 +99,3 @@ pub fn check_typaram_bounds(cx: &Context,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_freevar_bounds(cx: &Context, fn_span: Span, sp: Span, ty: ty::t,
|
|
||||||
bounds: ty::BuiltinBounds, referenced_ty: Option<ty::t>)
|
|
||||||
{
|
|
||||||
check_builtin_bounds(cx, ty, bounds, |missing| {
|
|
||||||
// Will be Some if the freevar is implicitly borrowed (stack closure).
|
|
||||||
// Emit a less mysterious error message in this case.
|
|
||||||
match referenced_ty {
|
|
||||||
Some(rty) => {
|
|
||||||
span_err!(cx.tcx.sess, sp, E0145,
|
|
||||||
"cannot implicitly borrow variable of type `{}` in a \
|
|
||||||
bounded stack closure (implicit reference does not fulfill `{}`)",
|
|
||||||
ty_to_string(cx.tcx, rty), missing.user_string(cx.tcx));
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
span_err!(cx.tcx.sess, sp, E0146,
|
|
||||||
"cannot capture variable of type `{}`, which does \
|
|
||||||
not fulfill `{}`, in a bounded closure",
|
|
||||||
ty_to_string(cx.tcx, ty), missing.user_string(cx.tcx));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span_note!(cx.tcx.sess, fn_span,
|
|
||||||
"this closure's environment must satisfy `{}`",
|
|
||||||
bounds.user_string(cx.tcx));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
/*! See `doc.rs` for high-level documentation */
|
/*! See `doc.rs` for high-level documentation */
|
||||||
|
|
||||||
use super::DUMMY_CAUSE;
|
|
||||||
use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch};
|
use super::{EvaluatedToMatch, EvaluatedToAmbiguity, EvaluatedToUnmatch};
|
||||||
use super::{evaluate_impl};
|
use super::{evaluate_impl};
|
||||||
|
use super::ObligationCause;
|
||||||
use super::util;
|
use super::util;
|
||||||
|
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
|
@ -39,7 +39,7 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
|
||||||
// Determine whether `impl2` can provide an implementation for those
|
// Determine whether `impl2` can provide an implementation for those
|
||||||
// same types.
|
// same types.
|
||||||
let param_env = ty::empty_parameter_environment();
|
let param_env = ty::empty_parameter_environment();
|
||||||
match evaluate_impl(infcx, ¶m_env, infcx.tcx, DUMMY_CAUSE,
|
match evaluate_impl(infcx, ¶m_env, infcx.tcx, ObligationCause::dummy(),
|
||||||
impl2_def_id, impl1_self_ty) {
|
impl2_def_id, impl1_self_ty) {
|
||||||
EvaluatedToMatch | EvaluatedToAmbiguity => true,
|
EvaluatedToMatch | EvaluatedToAmbiguity => true,
|
||||||
EvaluatedToUnmatch => false,
|
EvaluatedToUnmatch => false,
|
||||||
|
|
|
@ -77,11 +77,11 @@ pub enum ObligationCauseCode {
|
||||||
StructInitializerSized, // S { ... } must be Sized
|
StructInitializerSized, // S { ... } must be Sized
|
||||||
VariableType(ast::NodeId), // Type of each variable must be Sized
|
VariableType(ast::NodeId), // Type of each variable must be Sized
|
||||||
RepeatVec, // [T,..n] --> T must be Copy
|
RepeatVec, // [T,..n] --> T must be Copy
|
||||||
}
|
|
||||||
|
|
||||||
pub static DUMMY_CAUSE: ObligationCause =
|
// Captures of variable the given id by a closure (span is the
|
||||||
ObligationCause { span: DUMMY_SP,
|
// span of the closure)
|
||||||
code: MiscObligation };
|
ClosureCapture(ast::NodeId, Span)
|
||||||
|
}
|
||||||
|
|
||||||
pub type Obligations = subst::VecPerParamSpace<Obligation>;
|
pub type Obligations = subst::VecPerParamSpace<Obligation>;
|
||||||
|
|
||||||
|
@ -358,6 +358,10 @@ impl ObligationCause {
|
||||||
pub fn misc(span: Span) -> ObligationCause {
|
pub fn misc(span: Span) -> ObligationCause {
|
||||||
ObligationCause { span: span, code: MiscObligation }
|
ObligationCause { span: span, code: MiscObligation }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dummy() -> ObligationCause {
|
||||||
|
ObligationCause { span: DUMMY_SP, code: MiscObligation }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N> Vtable<N> {
|
impl<N> Vtable<N> {
|
||||||
|
|
|
@ -120,11 +120,13 @@ and report an error, and it just seems like more mess in the end.)
|
||||||
|
|
||||||
use middle::def;
|
use middle::def;
|
||||||
use middle::mem_categorization as mc;
|
use middle::mem_categorization as mc;
|
||||||
|
use middle::traits;
|
||||||
use middle::ty::{ReScope};
|
use middle::ty::{ReScope};
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::typeck::astconv::AstConv;
|
use middle::typeck::astconv::AstConv;
|
||||||
use middle::typeck::check::FnCtxt;
|
use middle::typeck::check::FnCtxt;
|
||||||
use middle::typeck::check::regionmanip;
|
use middle::typeck::check::regionmanip;
|
||||||
|
use middle::typeck::check::vtable2;
|
||||||
use middle::typeck::infer::resolve_and_force_all_but_regions;
|
use middle::typeck::infer::resolve_and_force_all_but_regions;
|
||||||
use middle::typeck::infer::resolve_type;
|
use middle::typeck::infer::resolve_type;
|
||||||
use middle::typeck::infer;
|
use middle::typeck::infer;
|
||||||
|
@ -165,6 +167,11 @@ pub fn regionck_fn(fcx: &FnCtxt, id: ast::NodeId, blk: &ast::Block) {
|
||||||
// regionck assumes typeck succeeded
|
// regionck assumes typeck succeeded
|
||||||
rcx.visit_fn_body(id, blk);
|
rcx.visit_fn_body(id, blk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Region checking a fn can introduce new trait obligations,
|
||||||
|
// particularly around closure bounds.
|
||||||
|
vtable2::select_all_fcx_obligations_or_error(fcx);
|
||||||
|
|
||||||
fcx.infcx().resolve_regions_and_report_errors();
|
fcx.infcx().resolve_regions_and_report_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,16 +855,6 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ty::ty_closure(box ty::ClosureTy{store: ty::UniqTraitStore,
|
|
||||||
bounds: ref bounds,
|
|
||||||
..}) => {
|
|
||||||
// For proc, ensure that the *types* of the variables
|
|
||||||
// outlive region bound, since they are captured by value.
|
|
||||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
|
||||||
ensure_free_variable_types_outlive_closure_bound(
|
|
||||||
rcx, bounds.region_bound, expr, freevars);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ty::ty_unboxed_closure(_, region) => {
|
ty::ty_unboxed_closure(_, region) => {
|
||||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||||
// No free variables means that there is no environment and
|
// No free variables means that there is no environment and
|
||||||
|
@ -868,8 +865,9 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
// NDM -- this seems wrong, discuss with pcwalton, should
|
// NDM -- this seems wrong, discuss with pcwalton, should
|
||||||
// be straightforward enough.
|
// be straightforward enough.
|
||||||
if !freevars.is_empty() {
|
if !freevars.is_empty() {
|
||||||
|
let bounds = ty::region_existential_bound(region);
|
||||||
ensure_free_variable_types_outlive_closure_bound(
|
ensure_free_variable_types_outlive_closure_bound(
|
||||||
rcx, region, expr, freevars);
|
rcx, bounds, expr, freevars);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -881,20 +879,26 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
rcx.set_repeating_scope(repeating_scope);
|
rcx.set_repeating_scope(repeating_scope);
|
||||||
|
|
||||||
match ty::get(function_type).sty {
|
match ty::get(function_type).sty {
|
||||||
ty::ty_closure(box ty::ClosureTy {
|
ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. }) => {
|
||||||
store: ty::RegionTraitStore(..),
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||||
propagate_upupvar_borrow_kind(rcx, expr, freevars);
|
propagate_upupvar_borrow_kind(rcx, expr, freevars);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match ty::get(function_type).sty {
|
||||||
|
ty::ty_closure(box ty::ClosureTy {bounds, ..}) => {
|
||||||
|
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||||
|
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_free_variable_types_outlive_closure_bound(
|
fn ensure_free_variable_types_outlive_closure_bound(
|
||||||
rcx: &mut Rcx,
|
rcx: &mut Rcx,
|
||||||
region_bound: ty::Region,
|
bounds: ty::ExistentialBounds,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
freevars: &[ty::Freevar])
|
freevars: &[ty::Freevar])
|
||||||
{
|
{
|
||||||
|
@ -908,7 +912,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
let tcx = rcx.fcx.ccx.tcx;
|
let tcx = rcx.fcx.ccx.tcx;
|
||||||
|
|
||||||
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
|
debug!("ensure_free_variable_types_outlive_closure_bound({}, {})",
|
||||||
region_bound.repr(tcx), expr.repr(tcx));
|
bounds.region_bound.repr(tcx), expr.repr(tcx));
|
||||||
|
|
||||||
for freevar in freevars.iter() {
|
for freevar in freevars.iter() {
|
||||||
let var_node_id = {
|
let var_node_id = {
|
||||||
|
@ -917,11 +921,35 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||||
def_id.node
|
def_id.node
|
||||||
};
|
};
|
||||||
|
|
||||||
let var_ty = rcx.resolve_node_type(var_node_id);
|
// Compute the type of the field in the environment that
|
||||||
|
// represents `var_node_id`. For a by-value closure, this
|
||||||
|
// will be the same as the type of the variable. For a
|
||||||
|
// by-reference closure, this will be `&T` where `T` is
|
||||||
|
// the type of the variable.
|
||||||
|
let raw_var_ty = rcx.resolve_node_type(var_node_id);
|
||||||
|
let upvar_id = ty::UpvarId { var_id: var_node_id,
|
||||||
|
closure_expr_id: expr.id };
|
||||||
|
let var_ty = match rcx.fcx.inh.upvar_borrow_map.borrow().find(&upvar_id) {
|
||||||
|
Some(upvar_borrow) => {
|
||||||
|
ty::mk_rptr(rcx.tcx(),
|
||||||
|
upvar_borrow.region,
|
||||||
|
ty::mt { mutbl: upvar_borrow.kind.to_mutbl_lossy(),
|
||||||
|
ty: raw_var_ty })
|
||||||
|
}
|
||||||
|
None => raw_var_ty
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that the type meets the criteria of the existential bounds:
|
||||||
|
for builtin_bound in bounds.builtin_bounds.iter() {
|
||||||
|
let code = traits::ClosureCapture(var_node_id, expr.span);
|
||||||
|
let cause = traits::ObligationCause::new(freevar.span, code);
|
||||||
|
let obligation = traits::obligation_for_builtin_bound(rcx.tcx(), cause,
|
||||||
|
var_ty, builtin_bound);
|
||||||
|
rcx.fcx.inh.fulfillment_cx.borrow_mut().register_obligation(rcx.tcx(), obligation);
|
||||||
|
}
|
||||||
type_must_outlive(
|
type_must_outlive(
|
||||||
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
|
rcx, infer::RelateProcBound(expr.span, var_node_id, var_ty),
|
||||||
var_ty, region_bound);
|
var_ty, bounds.region_bound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -398,5 +398,13 @@ fn note_obligation_cause(fcx: &FnCtxt,
|
||||||
"use \"#[unsafe_destructor]\" on the implementation \
|
"use \"#[unsafe_destructor]\" on the implementation \
|
||||||
to force the compiler to allow this");
|
to force the compiler to allow this");
|
||||||
}
|
}
|
||||||
|
traits::ClosureCapture(var_id, closure_span) => {
|
||||||
|
let name = ty::local_var_name_str(tcx, var_id);
|
||||||
|
span_note!(tcx.sess, closure_span,
|
||||||
|
"the closure that captures `{}` requires that all captured variables \"
|
||||||
|
implement the trait `{}`",
|
||||||
|
name,
|
||||||
|
trait_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1560,7 +1560,7 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> {
|
||||||
"...so that it can be closed over into an object");
|
"...so that it can be closed over into an object");
|
||||||
}
|
}
|
||||||
infer::RelateProcBound(span, var_node_id, _ty) => {
|
infer::RelateProcBound(span, var_node_id, _ty) => {
|
||||||
self.tcx.sess.span_err(
|
self.tcx.sess.span_note(
|
||||||
span,
|
span,
|
||||||
format!(
|
format!(
|
||||||
"...so that the variable `{}` can be captured \
|
"...so that the variable `{}` can be captured \
|
||||||
|
|
|
@ -12,8 +12,9 @@ fn bar(blk: ||:'static) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn foo(x: &()) {
|
fn foo(x: &()) {
|
||||||
bar(|| {
|
bar(|| { //~ ERROR cannot infer an appropriate lifetime
|
||||||
let _ = x; //~ ERROR captured variable `x` does not outlive
|
let _ = x;
|
||||||
|
//~^ ERROR captured variable `x` does not outlive
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ fn foo(_x: Gc<uint>) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = box(GC) 3u;
|
let x = box(GC) 3u;
|
||||||
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
|
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
|
||||||
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
|
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
|
||||||
let _: proc():Send = proc() foo(x); //~ ERROR does not fulfill `Send`
|
let _: proc():Send = proc() foo(x); //~ ERROR `core::kinds::Send` is not implemented
|
||||||
let _: proc() = proc() foo(x);
|
let _: proc() = proc() foo(x);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ fn main() {
|
||||||
|
|
||||||
task::spawn(proc() {
|
task::spawn(proc() {
|
||||||
let y = x;
|
let y = x;
|
||||||
//~^ ERROR does not fulfill `Send`
|
//~^ ERROR `core::kinds::Send` is not implemented
|
||||||
println!("{:?}", y);
|
println!("{:?}", y);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue