Fix monomorphization of unboxed closures
This adds a `Substs` field to `ty_unboxed_closure` and plumbs basic handling of it throughout the compiler. trans now correctly monomorphizes captured free variables and llvm function defs. This fixes uses of unboxed closures which reference a free type or region parameter from their environment in either their signature or free variables. Closes #16791
This commit is contained in:
parent
bd7138dd69
commit
f0cc3a9365
@ -465,9 +465,12 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||
return ty::mk_struct(st.tcx, did, substs);
|
||||
}
|
||||
'k' => {
|
||||
assert_eq!(next(st), '[');
|
||||
let did = parse_def(st, NominalType, |x,y| conv(x,y));
|
||||
let region = parse_region(st, conv);
|
||||
return ty::mk_unboxed_closure(st.tcx, did, region);
|
||||
let region = parse_region(st, |x,y| conv(x,y));
|
||||
let substs = parse_substs(st, |x,y| conv(x,y));
|
||||
assert_eq!(next(st), ']');
|
||||
return ty::mk_unboxed_closure(st.tcx, did, region, substs);
|
||||
}
|
||||
'e' => {
|
||||
return ty::mk_err();
|
||||
|
@ -285,9 +285,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
|
||||
enc_substs(w, cx, substs);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::ty_unboxed_closure(def, region) => {
|
||||
mywrite!(w, "k{}", (cx.ds)(def));
|
||||
ty::ty_unboxed_closure(def, region, ref substs) => {
|
||||
mywrite!(w, "k[{}|", (cx.ds)(def));
|
||||
enc_region(w, cx, region);
|
||||
enc_substs(w, cx, substs);
|
||||
mywrite!(w, "]");
|
||||
}
|
||||
ty::ty_err => {
|
||||
mywrite!(w, "e");
|
||||
|
@ -594,7 +594,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
};
|
||||
self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false)
|
||||
}
|
||||
ty::ty_unboxed_closure(closure_id, _) => {
|
||||
ty::ty_unboxed_closure(closure_id, _, _) => {
|
||||
let unboxed_closures = self.typer.unboxed_closures().borrow();
|
||||
let kind = (*unboxed_closures)[closure_id].kind;
|
||||
let mode = self.typer.capture_mode(fn_node_id);
|
||||
|
@ -110,7 +110,7 @@ enum Candidate {
|
||||
BuiltinCandidate(ty::BuiltinBound),
|
||||
ParamCandidate(VtableParamData),
|
||||
ImplCandidate(ast::DefId),
|
||||
UnboxedClosureCandidate(/* closure */ ast::DefId),
|
||||
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs),
|
||||
ErrorCandidate,
|
||||
}
|
||||
|
||||
@ -995,8 +995,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
};
|
||||
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
|
||||
let closure_def_id = match ty::get(self_ty).sty {
|
||||
ty::ty_unboxed_closure(id, _) => id,
|
||||
let (closure_def_id, substs) = match ty::get(self_ty).sty {
|
||||
ty::ty_unboxed_closure(id, _, ref substs) => (id, substs.clone()),
|
||||
ty::ty_infer(ty::TyVar(_)) => {
|
||||
candidates.ambiguous = true;
|
||||
return Ok(());
|
||||
@ -1019,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
};
|
||||
|
||||
if closure_kind == kind {
|
||||
candidates.vec.push(UnboxedClosureCandidate(closure_def_id));
|
||||
candidates.vec.push(UnboxedClosureCandidate(closure_def_id, substs.clone()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1383,7 +1383,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(If(tys.clone()))
|
||||
}
|
||||
|
||||
ty::ty_unboxed_closure(def_id, _) => {
|
||||
ty::ty_unboxed_closure(def_id, _, ref substs) => {
|
||||
// FIXME -- This case is tricky. In the case of by-ref
|
||||
// closures particularly, we need the results of
|
||||
// inference to decide how to reflect the type of each
|
||||
@ -1407,7 +1407,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
.map(|freevar| {
|
||||
let freevar_def_id = freevar.def.def_id();
|
||||
self.typer.node_ty(freevar_def_id.node)
|
||||
.unwrap_or(ty::mk_err())
|
||||
.unwrap_or(ty::mk_err()).subst(self.tcx(), substs)
|
||||
})
|
||||
.collect();
|
||||
Ok(If(tys))
|
||||
@ -1548,8 +1548,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(VtableImpl(vtable_impl))
|
||||
}
|
||||
|
||||
UnboxedClosureCandidate(closure_def_id) => {
|
||||
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id));
|
||||
UnboxedClosureCandidate(closure_def_id, ref substs) => {
|
||||
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, substs));
|
||||
Ok(VtableUnboxedClosure(closure_def_id))
|
||||
}
|
||||
}
|
||||
@ -1646,12 +1646,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
|
||||
fn confirm_unboxed_closure_candidate(&mut self,
|
||||
obligation: &Obligation,
|
||||
closure_def_id: ast::DefId)
|
||||
closure_def_id: ast::DefId,
|
||||
substs: &Substs)
|
||||
-> Result<(),SelectionError>
|
||||
{
|
||||
debug!("confirm_unboxed_closure_candidate({},{})",
|
||||
debug!("confirm_unboxed_closure_candidate({},{},{})",
|
||||
obligation.repr(self.tcx()),
|
||||
closure_def_id.repr(self.tcx()));
|
||||
closure_def_id.repr(self.tcx()),
|
||||
substs.repr(self.tcx()));
|
||||
|
||||
let closure_type = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
|
||||
Some(closure) => closure.closure_type.clone(),
|
||||
@ -1678,7 +1680,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let trait_ref = Rc::new(ty::TraitRef {
|
||||
def_id: obligation.trait_ref.def_id,
|
||||
substs: Substs::new_trait(
|
||||
vec![arguments_tuple, new_signature.output],
|
||||
vec![arguments_tuple.subst(self.tcx(), substs),
|
||||
new_signature.output.subst(self.tcx(), substs)],
|
||||
vec![],
|
||||
obligation.self_ty())
|
||||
});
|
||||
@ -1959,7 +1962,9 @@ impl Repr for Candidate {
|
||||
match *self {
|
||||
ErrorCandidate => format!("ErrorCandidate"),
|
||||
BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
|
||||
UnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c),
|
||||
UnboxedClosureCandidate(c, ref s) => {
|
||||
format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx))
|
||||
}
|
||||
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
|
||||
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
|
||||
}
|
||||
|
@ -176,8 +176,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
|
||||
|
||||
return Univariant(mk_struct(cx, ftys.as_slice(), packed, t), dtor)
|
||||
}
|
||||
ty::ty_unboxed_closure(def_id, _) => {
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
|
||||
ty::ty_unboxed_closure(def_id, _, ref substs) => {
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
|
||||
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
|
||||
return Univariant(mk_struct(cx, upvar_types.as_slice(), false, t),
|
||||
false)
|
||||
|
@ -253,21 +253,19 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
|
||||
}
|
||||
|
||||
pub fn self_type_for_unboxed_closure(ccx: &CrateContext,
|
||||
closure_id: ast::DefId)
|
||||
closure_id: ast::DefId,
|
||||
fn_ty: ty::t)
|
||||
-> ty::t {
|
||||
let unboxed_closure_type = ty::mk_unboxed_closure(ccx.tcx(),
|
||||
closure_id,
|
||||
ty::ReStatic);
|
||||
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
|
||||
let unboxed_closure = &(*unboxed_closures)[closure_id];
|
||||
match unboxed_closure.kind {
|
||||
ty::FnUnboxedClosureKind => {
|
||||
ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type)
|
||||
ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, fn_ty)
|
||||
}
|
||||
ty::FnMutUnboxedClosureKind => {
|
||||
ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type)
|
||||
ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, fn_ty)
|
||||
}
|
||||
ty::FnOnceUnboxedClosureKind => unboxed_closure_type,
|
||||
ty::FnOnceUnboxedClosureKind => fn_ty
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,14 +283,14 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
|
||||
ty::ty_closure(ref f) => {
|
||||
(f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx)))
|
||||
}
|
||||
ty::ty_unboxed_closure(closure_did, _) => {
|
||||
ty::ty_unboxed_closure(closure_did, _, ref substs) => {
|
||||
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
|
||||
let unboxed_closure = &(*unboxed_closures)[closure_did];
|
||||
let function_type = unboxed_closure.closure_type.clone();
|
||||
let self_type = self_type_for_unboxed_closure(ccx, closure_did);
|
||||
let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty);
|
||||
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
|
||||
(function_type.sig.inputs.clone(),
|
||||
function_type.sig.output,
|
||||
(function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(),
|
||||
function_type.sig.output.subst(ccx.tcx(), substs),
|
||||
RustCall,
|
||||
Some(llenvironment_type))
|
||||
}
|
||||
@ -738,9 +736,9 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::ty_unboxed_closure(def_id, _) => {
|
||||
ty::ty_unboxed_closure(def_id, _, ref substs) => {
|
||||
let repr = adt::represent_type(cx.ccx(), t);
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
|
||||
for (i, upvar) in upvars.iter().enumerate() {
|
||||
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
|
||||
cx = f(cx, llupvar, upvar.ty);
|
||||
@ -2351,12 +2349,12 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
|
||||
let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
|
||||
ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
|
||||
ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
|
||||
ty::ty_unboxed_closure(closure_did, _) => {
|
||||
ty::ty_unboxed_closure(closure_did, _, ref substs) => {
|
||||
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
|
||||
let ref function_type = (*unboxed_closures)[closure_did]
|
||||
.closure_type;
|
||||
|
||||
(function_type.sig.clone(), RustCall, true)
|
||||
(function_type.sig.subst(ccx.tcx(), substs), RustCall, true)
|
||||
}
|
||||
_ => ccx.sess().bug("expected closure or function.")
|
||||
};
|
||||
@ -2371,7 +2369,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
|
||||
// These have an odd calling convention, so we need to manually
|
||||
// unpack the input ty's
|
||||
let input_tys = match ty::get(fn_ty).sty {
|
||||
ty::ty_unboxed_closure(_, _) => {
|
||||
ty::ty_unboxed_closure(_, _, _) => {
|
||||
assert!(abi == RustCall);
|
||||
|
||||
match ty::get(fn_sig.inputs[0]).sty {
|
||||
|
@ -491,7 +491,7 @@ pub fn trans_fn_ref_with_substs(
|
||||
};
|
||||
|
||||
// If this is an unboxed closure, redirect to it.
|
||||
match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) {
|
||||
match closure::get_or_create_declaration_if_unboxed_closure(bcx, def_id) {
|
||||
None => {}
|
||||
Some(llfn) => return llfn,
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ use middle::trans::common::*;
|
||||
use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
|
||||
use middle::trans::debuginfo;
|
||||
use middle::trans::expr;
|
||||
use middle::trans::monomorphize::MonoId;
|
||||
use middle::trans::type_of::*;
|
||||
use middle::trans::type_::Type;
|
||||
use middle::ty;
|
||||
@ -312,7 +313,8 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
|
||||
}
|
||||
|
||||
// Special case for small by-value selfs.
|
||||
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id);
|
||||
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id,
|
||||
node_id_type(bcx, closure_id.node));
|
||||
let kind = kind_for_unboxed_closure(bcx.ccx(), closure_id);
|
||||
let llenv = if kind == ty::FnOnceUnboxedClosureKind &&
|
||||
!arg_is_indirect(bcx.ccx(), self_type) {
|
||||
@ -418,15 +420,26 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
|
||||
/// Returns the LLVM function declaration for an unboxed closure, creating it
|
||||
/// if necessary. If the ID does not correspond to a closure ID, returns None.
|
||||
pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
|
||||
closure_id: ast::DefId)
|
||||
-> Option<ValueRef> {
|
||||
pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
closure_id: ast::DefId)
|
||||
-> Option<ValueRef> {
|
||||
let ccx = bcx.ccx();
|
||||
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
|
||||
// Not an unboxed closure.
|
||||
return None
|
||||
}
|
||||
|
||||
match ccx.unboxed_closure_vals().borrow().find(&closure_id) {
|
||||
let function_type = node_id_type(bcx, closure_id.node);
|
||||
let params = match ty::get(function_type).sty {
|
||||
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
|
||||
_ => unreachable!()
|
||||
};
|
||||
let mono_id = MonoId {
|
||||
def: closure_id,
|
||||
params: params
|
||||
};
|
||||
|
||||
match ccx.unboxed_closure_vals().borrow().find(&mono_id) {
|
||||
Some(llfn) => {
|
||||
debug!("get_or_create_declaration_if_unboxed_closure(): found \
|
||||
closure");
|
||||
@ -435,9 +448,7 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
|
||||
None => {}
|
||||
}
|
||||
|
||||
let function_type = ty::mk_unboxed_closure(ccx.tcx(),
|
||||
closure_id,
|
||||
ty::ReStatic);
|
||||
let function_type = node_id_type(bcx, closure_id.node);
|
||||
let symbol = ccx.tcx().map.with_path(closure_id.node, |path| {
|
||||
mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
|
||||
});
|
||||
@ -449,9 +460,9 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
|
||||
|
||||
debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \
|
||||
closure {} (type {})",
|
||||
closure_id,
|
||||
mono_id,
|
||||
ccx.tn().type_to_string(val_ty(llfn)));
|
||||
ccx.unboxed_closure_vals().borrow_mut().insert(closure_id, llfn);
|
||||
ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn);
|
||||
|
||||
Some(llfn)
|
||||
}
|
||||
@ -469,7 +480,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
|
||||
|
||||
let closure_id = ast_util::local_def(id);
|
||||
let llfn = get_or_create_declaration_if_unboxed_closure(
|
||||
bcx.ccx(),
|
||||
bcx,
|
||||
closure_id).unwrap();
|
||||
|
||||
let unboxed_closures = bcx.tcx().unboxed_closures.borrow();
|
||||
|
@ -138,7 +138,7 @@ pub struct LocalCrateContext {
|
||||
builder: BuilderRef_res,
|
||||
|
||||
/// Holds the LLVM values for closure IDs.
|
||||
unboxed_closure_vals: RefCell<DefIdMap<ValueRef>>,
|
||||
unboxed_closure_vals: RefCell<HashMap<MonoId, ValueRef>>,
|
||||
|
||||
dbg_cx: Option<debuginfo::CrateDebugContext>,
|
||||
|
||||
@ -419,7 +419,7 @@ impl LocalCrateContext {
|
||||
int_type: Type::from_ref(ptr::null_mut()),
|
||||
opaque_vec_type: Type::from_ref(ptr::null_mut()),
|
||||
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
|
||||
unboxed_closure_vals: RefCell::new(DefIdMap::new()),
|
||||
unboxed_closure_vals: RefCell::new(HashMap::new()),
|
||||
dbg_cx: dbg_cx,
|
||||
eh_personality: RefCell::new(None),
|
||||
intrinsics: RefCell::new(HashMap::new()),
|
||||
@ -689,7 +689,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
self.local.opaque_vec_type
|
||||
}
|
||||
|
||||
pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<DefIdMap<ValueRef>> {
|
||||
pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<HashMap<MonoId,ValueRef>> {
|
||||
&self.local.unboxed_closure_vals
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ use llvm;
|
||||
use llvm::{ModuleRef, ContextRef, ValueRef};
|
||||
use llvm::debuginfo::*;
|
||||
use metadata::csearch;
|
||||
use middle::subst;
|
||||
use middle::subst::{mod, Subst};
|
||||
use middle::trans::adt;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::machine;
|
||||
@ -460,9 +460,9 @@ impl TypeMap {
|
||||
closure_ty.clone(),
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_unboxed_closure(ref def_id, _) => {
|
||||
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
|
||||
let closure_ty = cx.tcx().unboxed_closures.borrow()
|
||||
.find(def_id).unwrap().closure_type.clone();
|
||||
.find(def_id).unwrap().closure_type.subst(cx.tcx(), substs);
|
||||
self.get_unique_type_id_of_closure_type(cx,
|
||||
closure_ty,
|
||||
&mut unique_type_id);
|
||||
@ -2911,9 +2911,9 @@ fn type_metadata(cx: &CrateContext,
|
||||
ty::ty_closure(ref closurety) => {
|
||||
subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span)
|
||||
}
|
||||
ty::ty_unboxed_closure(ref def_id, _) => {
|
||||
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
|
||||
let sig = cx.tcx().unboxed_closures.borrow()
|
||||
.find(def_id).unwrap().closure_type.sig.clone();
|
||||
.find(def_id).unwrap().closure_type.sig.subst(cx.tcx(), substs);
|
||||
subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span)
|
||||
}
|
||||
ty::ty_struct(def_id, ref substs) => {
|
||||
|
@ -344,13 +344,10 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
}
|
||||
traits::VtableUnboxedClosure(closure_def_id) => {
|
||||
// The static region and type parameters are lies, but we're in
|
||||
// trans so it doesn't matter.
|
||||
//
|
||||
// FIXME(pcwalton): Is this true in the case of type parameters?
|
||||
let callee_substs = get_callee_substitutions_for_unboxed_closure(
|
||||
let self_ty = node_id_type(bcx, closure_def_id.node);
|
||||
let callee_substs = get_callee_substitutions_for_unboxed_closure(
|
||||
bcx,
|
||||
closure_def_id);
|
||||
self_ty);
|
||||
|
||||
let llfn = trans_fn_ref_with_substs(bcx,
|
||||
closure_def_id,
|
||||
@ -504,24 +501,22 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates the self type and (fake) callee substitutions for an unboxed
|
||||
/// closure with the given def ID. The static region and type parameters are
|
||||
/// lies, but we're in trans so it doesn't matter.
|
||||
/// Looks up the substitutions for an unboxed closure and adds the
|
||||
/// self type
|
||||
fn get_callee_substitutions_for_unboxed_closure(bcx: Block,
|
||||
def_id: ast::DefId)
|
||||
self_ty: ty::t)
|
||||
-> subst::Substs {
|
||||
let self_ty = ty::mk_unboxed_closure(bcx.tcx(), def_id, ty::ReStatic);
|
||||
subst::Substs::erased(
|
||||
VecPerParamSpace::new(Vec::new(),
|
||||
vec![
|
||||
ty::mk_rptr(bcx.tcx(),
|
||||
ty::ReStatic,
|
||||
ty::mt {
|
||||
match ty::get(self_ty).sty {
|
||||
ty::ty_unboxed_closure(_, _, ref substs) => {
|
||||
substs.with_self_ty(ty::mk_rptr(bcx.tcx(),
|
||||
ty::ReStatic,
|
||||
ty::mt {
|
||||
ty: self_ty,
|
||||
mutbl: ast::MutMutable,
|
||||
})
|
||||
],
|
||||
Vec::new()))
|
||||
}))
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a returns a dynamic vtable for the given type and vtable origin.
|
||||
@ -569,10 +564,12 @@ pub fn get_vtable(bcx: Block,
|
||||
emit_vtable_methods(bcx, id, substs).into_iter()
|
||||
}
|
||||
traits::VtableUnboxedClosure(closure_def_id) => {
|
||||
let self_ty = node_id_type(bcx, closure_def_id.node);
|
||||
|
||||
let callee_substs =
|
||||
get_callee_substitutions_for_unboxed_closure(
|
||||
bcx,
|
||||
closure_def_id);
|
||||
self_ty.clone());
|
||||
|
||||
let mut llfn = trans_fn_ref_with_substs(
|
||||
bcx,
|
||||
@ -590,25 +587,28 @@ pub fn get_vtable(bcx: Block,
|
||||
unboxed closure");
|
||||
if closure_info.kind == ty::FnOnceUnboxedClosureKind {
|
||||
// Untuple the arguments and create an unboxing shim.
|
||||
let mut new_inputs = vec![
|
||||
ty::mk_unboxed_closure(bcx.tcx(),
|
||||
closure_def_id,
|
||||
ty::ReStatic)
|
||||
];
|
||||
match ty::get(closure_info.closure_type
|
||||
.sig
|
||||
.inputs[0]).sty {
|
||||
ty::ty_tup(ref elements) => {
|
||||
for element in elements.iter() {
|
||||
new_inputs.push(*element)
|
||||
let (new_inputs, new_output) = match ty::get(self_ty).sty {
|
||||
ty::ty_unboxed_closure(_, _, ref substs) => {
|
||||
let mut new_inputs = vec![self_ty.clone()];
|
||||
match ty::get(closure_info.closure_type
|
||||
.sig
|
||||
.inputs[0]).sty {
|
||||
ty::ty_tup(ref elements) => {
|
||||
for element in elements.iter() {
|
||||
new_inputs.push(element.subst(bcx.tcx(), substs));
|
||||
}
|
||||
}
|
||||
ty::ty_nil => {}
|
||||
_ => {
|
||||
bcx.tcx().sess.bug("get_vtable(): closure \
|
||||
type wasn't a tuple")
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_nil => {}
|
||||
_ => {
|
||||
bcx.tcx().sess.bug("get_vtable(): closure \
|
||||
type wasn't a tuple")
|
||||
}
|
||||
}
|
||||
(new_inputs,
|
||||
closure_info.closure_type.sig.output.subst(bcx.tcx(), substs))
|
||||
},
|
||||
_ => bcx.tcx().sess.bug("get_vtable(): def wasn't an unboxed closure")
|
||||
};
|
||||
|
||||
let closure_type = ty::BareFnTy {
|
||||
fn_style: closure_info.closure_type.fn_style,
|
||||
@ -618,7 +618,7 @@ pub fn get_vtable(bcx: Block,
|
||||
.sig
|
||||
.binder_id,
|
||||
inputs: new_inputs,
|
||||
output: closure_info.closure_type.sig.output,
|
||||
output: new_output,
|
||||
variadic: false,
|
||||
},
|
||||
};
|
||||
|
@ -309,11 +309,15 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
let name = llvm_type_name(cx, an_enum, did, tps);
|
||||
adt::incomplete_type_of(cx, &*repr, name.as_slice())
|
||||
}
|
||||
ty::ty_unboxed_closure(did, _) => {
|
||||
ty::ty_unboxed_closure(did, _, ref substs) => {
|
||||
// Only create the named struct, but don't fill it in. We
|
||||
// fill it in *after* placing it into the type cache.
|
||||
let repr = adt::represent_type(cx, t);
|
||||
let name = llvm_type_name(cx, an_unboxed_closure, did, []);
|
||||
// Unboxed closures can have substitutions in all spaces
|
||||
// inherited from their environment, so we use entire
|
||||
// contents of the VecPerParamSpace to to construct the llvm
|
||||
// name
|
||||
let name = llvm_type_name(cx, an_unboxed_closure, did, substs.types.as_slice());
|
||||
adt::incomplete_type_of(cx, &*repr, name.as_slice())
|
||||
}
|
||||
|
||||
|
@ -962,7 +962,7 @@ pub enum sty {
|
||||
ty_closure(Box<ClosureTy>),
|
||||
ty_trait(Box<TyTrait>),
|
||||
ty_struct(DefId, Substs),
|
||||
ty_unboxed_closure(DefId, Region),
|
||||
ty_unboxed_closure(DefId, Region, Substs),
|
||||
ty_tup(Vec<t>),
|
||||
|
||||
ty_param(ParamTy), // type parameter
|
||||
@ -1636,7 +1636,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||
flags = flags | HAS_PARAMS;
|
||||
}
|
||||
}
|
||||
&ty_unboxed_closure(_, ref region) => flags = flags | rflags(*region),
|
||||
&ty_unboxed_closure(_, ref region, ref substs) => {
|
||||
flags = flags | rflags(*region);
|
||||
flags = flags | sflags(substs);
|
||||
}
|
||||
&ty_infer(_) => flags = flags | HAS_TY_INFER,
|
||||
&ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
|
||||
flags = flags | sflags(substs);
|
||||
@ -1885,9 +1888,9 @@ pub fn mk_struct(cx: &ctxt, struct_id: ast::DefId, substs: Substs) -> t {
|
||||
mk_t(cx, ty_struct(struct_id, substs))
|
||||
}
|
||||
|
||||
pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId, region: Region)
|
||||
pub fn mk_unboxed_closure(cx: &ctxt, closure_id: ast::DefId, region: Region, substs: Substs)
|
||||
-> t {
|
||||
mk_t(cx, ty_unboxed_closure(closure_id, region))
|
||||
mk_t(cx, ty_unboxed_closure(closure_id, region, substs))
|
||||
}
|
||||
|
||||
pub fn mk_var(cx: &ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) }
|
||||
@ -1922,12 +1925,12 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
|
||||
}
|
||||
match get(ty).sty {
|
||||
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||
ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_, _) | ty_err => {}
|
||||
ty_str | ty_infer(_) | ty_param(_) | ty_err => {}
|
||||
ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f),
|
||||
ty_ptr(ref tm) | ty_rptr(_, ref tm) => {
|
||||
maybe_walk_ty(tm.ty, f);
|
||||
}
|
||||
ty_enum(_, ref substs) | ty_struct(_, ref substs) |
|
||||
ty_enum(_, ref substs) | ty_struct(_, ref substs) | ty_unboxed_closure(_, _, ref substs) |
|
||||
ty_trait(box TyTrait { ref substs, .. }) => {
|
||||
for subty in (*substs).types.iter() {
|
||||
maybe_walk_ty(*subty, |x| f(x));
|
||||
@ -2484,10 +2487,10 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
apply_lang_items(cx, did, res)
|
||||
}
|
||||
|
||||
ty_unboxed_closure(did, r) => {
|
||||
ty_unboxed_closure(did, r, ref substs) => {
|
||||
// FIXME(#14449): `borrowed_contents` below assumes `&mut`
|
||||
// unboxed closure.
|
||||
let upvars = unboxed_closure_upvars(cx, did);
|
||||
let upvars = unboxed_closure_upvars(cx, did, substs);
|
||||
TypeContents::union(upvars.as_slice(),
|
||||
|f| tc_ty(cx, f.ty, cache)) |
|
||||
borrowed_contents(r, MutMutable)
|
||||
@ -2781,8 +2784,8 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
|
||||
r
|
||||
}
|
||||
|
||||
ty_unboxed_closure(did, _) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did);
|
||||
ty_unboxed_closure(did, _, ref substs) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did, substs);
|
||||
upvars.iter().any(|f| type_requires(cx, seen, r_ty, f.ty))
|
||||
}
|
||||
|
||||
@ -2869,8 +2872,8 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
|
||||
|
||||
find_nonrepresentable(cx, sp, seen, iter)
|
||||
}
|
||||
ty_unboxed_closure(did, _) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did);
|
||||
ty_unboxed_closure(did, _, ref substs) => {
|
||||
let upvars = unboxed_closure_upvars(cx, did, substs);
|
||||
find_nonrepresentable(cx, sp, seen, upvars.iter().map(|f| f.ty))
|
||||
}
|
||||
_ => Representable,
|
||||
@ -4225,7 +4228,7 @@ pub fn ty_to_def_id(ty: t) -> Option<ast::DefId> {
|
||||
ty_trait(box TyTrait { def_id: id, .. }) |
|
||||
ty_struct(id, _) |
|
||||
ty_enum(id, _) |
|
||||
ty_unboxed_closure(id, _) => Some(id),
|
||||
ty_unboxed_closure(id, _, _) => Some(id),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -4623,7 +4626,7 @@ pub struct UnboxedClosureUpvar {
|
||||
}
|
||||
|
||||
// Returns a list of `UnboxedClosureUpvar`s for each upvar.
|
||||
pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId)
|
||||
pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId, substs: &Substs)
|
||||
-> Vec<UnboxedClosureUpvar> {
|
||||
if closure_id.krate == ast::LOCAL_CRATE {
|
||||
let capture_mode = tcx.capture_modes.borrow().get_copy(&closure_id.node);
|
||||
@ -4632,7 +4635,8 @@ pub fn unboxed_closure_upvars(tcx: &ctxt, closure_id: ast::DefId)
|
||||
Some(ref freevars) => {
|
||||
freevars.iter().map(|freevar| {
|
||||
let freevar_def_id = freevar.def.def_id();
|
||||
let mut freevar_ty = node_id_to_type(tcx, freevar_def_id.node);
|
||||
let freevar_ty = node_id_to_type(tcx, freevar_def_id.node);
|
||||
let mut freevar_ty = freevar_ty.subst(tcx, substs);
|
||||
if capture_mode == ast::CaptureByRef {
|
||||
let borrow = tcx.upvar_borrow_map.borrow().get_copy(&ty::UpvarId {
|
||||
var_id: freevar_def_id.node,
|
||||
@ -5226,7 +5230,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
|
||||
ty_open(_) => byte!(22),
|
||||
ty_infer(_) => unreachable!(),
|
||||
ty_err => byte!(23),
|
||||
ty_unboxed_closure(d, r) => {
|
||||
ty_unboxed_closure(d, r, _) => {
|
||||
byte!(24);
|
||||
did(&mut state, d);
|
||||
region(&mut state, r);
|
||||
@ -5503,14 +5507,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
..
|
||||
}) |
|
||||
ty_struct(_, ref substs) => {
|
||||
match substs.regions {
|
||||
subst::ErasedRegions => {}
|
||||
subst::NonerasedRegions(ref regions) => {
|
||||
for region in regions.iter() {
|
||||
accumulator.push(*region)
|
||||
}
|
||||
}
|
||||
}
|
||||
accum_substs(accumulator, substs);
|
||||
}
|
||||
ty_closure(ref closure_ty) => {
|
||||
match closure_ty.store {
|
||||
@ -5518,7 +5515,10 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
UniqTraitStore => {}
|
||||
}
|
||||
}
|
||||
ty_unboxed_closure(_, ref region) => accumulator.push(*region),
|
||||
ty_unboxed_closure(_, ref region, ref substs) => {
|
||||
accumulator.push(*region);
|
||||
accum_substs(accumulator, substs);
|
||||
}
|
||||
ty_nil |
|
||||
ty_bot |
|
||||
ty_bool |
|
||||
@ -5537,7 +5537,18 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
ty_open(_) |
|
||||
ty_err => {}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
fn accum_substs(accumulator: &mut Vec<Region>, substs: &Substs) {
|
||||
match substs.regions {
|
||||
subst::ErasedRegions => {}
|
||||
subst::NonerasedRegions(ref regions) => {
|
||||
for region in regions.iter() {
|
||||
accumulator.push(*region)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A free variable referred to in a function.
|
||||
|
@ -534,8 +534,8 @@ pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
|
||||
ty::ty_struct(did, ref substs) => {
|
||||
ty::ty_struct(did, substs.fold_with(this))
|
||||
}
|
||||
ty::ty_unboxed_closure(did, ref region) => {
|
||||
ty::ty_unboxed_closure(did, region.fold_with(this))
|
||||
ty::ty_unboxed_closure(did, ref region, ref substs) => {
|
||||
ty::ty_unboxed_closure(did, region.fold_with(this), substs.fold_with(this))
|
||||
}
|
||||
ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_char | ty::ty_str |
|
||||
ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
|
||||
|
@ -505,7 +505,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
|
||||
}
|
||||
ty_enum(did, _) |
|
||||
ty_struct(did, _) |
|
||||
ty_unboxed_closure(did, _) => {
|
||||
ty_unboxed_closure(did, _, _) => {
|
||||
if self.check_traits == CheckTraitsAndInherentMethods {
|
||||
self.push_inherent_impl_candidates_for_type(did);
|
||||
}
|
||||
|
@ -3270,7 +3270,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
};
|
||||
let closure_type = ty::mk_unboxed_closure(fcx.ccx.tcx,
|
||||
local_def(expr.id),
|
||||
region);
|
||||
region,
|
||||
fcx.inh.param_env.free_substs.clone());
|
||||
fcx.write_ty(expr.id, closure_type);
|
||||
|
||||
check_fn(fcx.ccx,
|
||||
|
@ -867,7 +867,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||
}
|
||||
});
|
||||
}
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
ty::ty_unboxed_closure(_, region, _) => {
|
||||
if tcx.capture_modes.borrow().get_copy(&expr.id) == ast::CaptureByRef {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
if !freevars.is_empty() {
|
||||
@ -908,7 +908,7 @@ fn check_expr_fn_block(rcx: &mut Rcx,
|
||||
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
|
||||
})
|
||||
}
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
ty::ty_unboxed_closure(_, region, _) => {
|
||||
ty::with_freevars(tcx, expr.id, |freevars| {
|
||||
let bounds = ty::region_existential_bound(region);
|
||||
ensure_free_variable_types_outlive_closure_bound(rcx, bounds, expr, freevars);
|
||||
|
@ -108,7 +108,7 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
||||
self.accumulate_from_closure_ty(ty, c);
|
||||
}
|
||||
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
ty::ty_unboxed_closure(_, region, _) => {
|
||||
// An "unboxed closure type" is basically
|
||||
// modeled here as equivalent to a struct like
|
||||
//
|
||||
@ -118,6 +118,18 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
||||
//
|
||||
// where the `'b` is the lifetime bound of the
|
||||
// contents (i.e., all contents must outlive 'b).
|
||||
//
|
||||
// Even though unboxed closures are glorified structs
|
||||
// of upvars, we do not need to consider them as they
|
||||
// can't generate any new constraints. The
|
||||
// substitutions on the closure are equal to the free
|
||||
// substitutions of the enclosing parameter
|
||||
// environment. An upvar captured by value has the
|
||||
// same type as the original local variable which is
|
||||
// already checked for consistency. If the upvar is
|
||||
// captured by reference it must also outlive the
|
||||
// region bound on the closure, but this is explicitly
|
||||
// handled by logic in regionck.
|
||||
self.push_region_constraint_from_top(region);
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
|
||||
match get(base_type).sty {
|
||||
ty_enum(def_id, _) |
|
||||
ty_struct(def_id, _) |
|
||||
ty_unboxed_closure(def_id, _) => {
|
||||
ty_unboxed_closure(def_id, _, _) => {
|
||||
Some(def_id)
|
||||
}
|
||||
ty_ptr(ty::mt {ty, ..}) |
|
||||
@ -445,7 +445,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
||||
match ty::get(self_type.ty).sty {
|
||||
ty::ty_enum(type_def_id, _) |
|
||||
ty::ty_struct(type_def_id, _) |
|
||||
ty::ty_unboxed_closure(type_def_id, _) => {
|
||||
ty::ty_unboxed_closure(type_def_id, _, _) => {
|
||||
tcx.destructor_for_type
|
||||
.borrow_mut()
|
||||
.insert(type_def_id, method_def_id.def_id());
|
||||
|
@ -105,6 +105,15 @@ pub trait Combine<'tcx> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst)
|
||||
}
|
||||
|
||||
fn substs_variances(&self,
|
||||
variances: Option<&ty::ItemVariances>,
|
||||
a_subst: &subst::Substs,
|
||||
b_subst: &subst::Substs)
|
||||
-> cres<subst::Substs>
|
||||
{
|
||||
let mut substs = subst::Substs::empty();
|
||||
|
||||
for &space in subst::ParamSpace::all().iter() {
|
||||
@ -126,7 +135,7 @@ pub trait Combine<'tcx> {
|
||||
|
||||
let mut invariance = Vec::new();
|
||||
let r_variances = match variances {
|
||||
Some(ref variances) => {
|
||||
Some(variances) => {
|
||||
variances.regions.get_slice(space)
|
||||
}
|
||||
None => {
|
||||
@ -138,7 +147,6 @@ pub trait Combine<'tcx> {
|
||||
};
|
||||
|
||||
let regions = try!(relate_region_params(self,
|
||||
item_def_id,
|
||||
r_variances,
|
||||
a_regions,
|
||||
b_regions));
|
||||
@ -150,7 +158,6 @@ pub trait Combine<'tcx> {
|
||||
return Ok(substs);
|
||||
|
||||
fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C,
|
||||
item_def_id: ast::DefId,
|
||||
variances: &[ty::Variance],
|
||||
a_rs: &[ty::Region],
|
||||
b_rs: &[ty::Region])
|
||||
@ -159,11 +166,9 @@ pub trait Combine<'tcx> {
|
||||
let num_region_params = variances.len();
|
||||
|
||||
debug!("relate_region_params(\
|
||||
item_def_id={}, \
|
||||
a_rs={}, \
|
||||
b_rs={},
|
||||
variances={})",
|
||||
item_def_id.repr(tcx),
|
||||
a_rs.repr(tcx),
|
||||
b_rs.repr(tcx),
|
||||
variances.repr(tcx));
|
||||
@ -464,14 +469,15 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
|
||||
Ok(ty::mk_struct(tcx, a_id, substs))
|
||||
}
|
||||
|
||||
(&ty::ty_unboxed_closure(a_id, a_region),
|
||||
&ty::ty_unboxed_closure(b_id, b_region))
|
||||
(&ty::ty_unboxed_closure(a_id, a_region, ref a_substs),
|
||||
&ty::ty_unboxed_closure(b_id, b_region, ref b_substs))
|
||||
if a_id == b_id => {
|
||||
// All ty_unboxed_closure types with the same id represent
|
||||
// the (anonymous) type of the same closure expression. So
|
||||
// all of their regions should be equated.
|
||||
let region = try!(this.equate().regions(a_region, b_region));
|
||||
Ok(ty::mk_unboxed_closure(tcx, a_id, region))
|
||||
let substs = try!(this.substs_variances(None, a_substs, b_substs));
|
||||
Ok(ty::mk_unboxed_closure(tcx, a_id, region, substs))
|
||||
}
|
||||
|
||||
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
|
||||
|
@ -734,9 +734,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
/* leaf type -- noop */
|
||||
}
|
||||
|
||||
ty::ty_unboxed_closure(_, region) => {
|
||||
let contra = self.contravariant(variance);
|
||||
self.add_constraints_from_region(region, contra);
|
||||
ty::ty_unboxed_closure(..) => {
|
||||
self.tcx().sess.bug("Unexpected unboxed closure type in variance computation");
|
||||
}
|
||||
|
||||
ty::ty_rptr(region, ref mt) => {
|
||||
|
@ -425,7 +425,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
bound_str)
|
||||
}
|
||||
ty_str => "str".to_string(),
|
||||
ty_unboxed_closure(..) => "closure".to_string(),
|
||||
ty_unboxed_closure(ref did, _, ref substs) => {
|
||||
let unboxed_closures = cx.unboxed_closures.borrow();
|
||||
unboxed_closures.find(did).map(|cl| {
|
||||
closure_to_string(cx, &cl.closure_type.subst(cx, substs))
|
||||
}).unwrap_or_else(|| "closure".to_string())
|
||||
}
|
||||
ty_vec(t, sz) => {
|
||||
match sz {
|
||||
Some(n) => {
|
||||
|
Loading…
Reference in New Issue
Block a user