Rollup merge of #71599 - ldm0:fnclo, r=nikomatsakis
Support coercion between (FnDef | Closure) and (FnDef | Closure) Fixes #46742, fixes #48109 Inject `Closure` into the `FnDef x FnDef` coercion special case, which makes coercion of `(FnDef | Closure) x (FnDef | Closure)` possible, where closures should be **non-capturing**.
This commit is contained in:
commit
58e6447365
@ -2069,24 +2069,25 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }))
|
||||
}
|
||||
|
||||
/// Given a closure signature `sig`, returns an equivalent `fn`
|
||||
/// type with the same signature. Detuples and so forth -- so
|
||||
/// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get
|
||||
/// a `fn(u32, i32)`.
|
||||
/// `unsafety` determines the unsafety of the `fn` type. If you pass
|
||||
/// Given a closure signature, returns an equivalent fn signature. Detuples
|
||||
/// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
|
||||
/// you would get a `fn(u32, i32)`.
|
||||
/// `unsafety` determines the unsafety of the fn signature. If you pass
|
||||
/// `hir::Unsafety::Unsafe` in the previous example, then you would get
|
||||
/// an `unsafe fn (u32, i32)`.
|
||||
/// It cannot convert a closure that requires unsafe.
|
||||
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> {
|
||||
let converted_sig = sig.map_bound(|s| {
|
||||
pub fn signature_unclosure(
|
||||
self,
|
||||
sig: PolyFnSig<'tcx>,
|
||||
unsafety: hir::Unsafety,
|
||||
) -> PolyFnSig<'tcx> {
|
||||
sig.map_bound(|s| {
|
||||
let params_iter = match s.inputs()[0].kind {
|
||||
ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()),
|
||||
_ => bug!(),
|
||||
};
|
||||
self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi::Abi::Rust)
|
||||
});
|
||||
|
||||
self.mk_fn_ptr(converted_sig)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
|
@ -2088,7 +2088,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
ty::Closure(_, substs) => substs.as_closure().sig(),
|
||||
_ => bug!(),
|
||||
};
|
||||
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety);
|
||||
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
|
||||
|
||||
if let Err(terr) = self.eq_types(
|
||||
ty_fn_ptr_from,
|
||||
|
@ -793,7 +793,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
// `unsafe fn(arg0,arg1,...) -> _`
|
||||
let closure_sig = substs_a.as_closure().sig();
|
||||
let unsafety = fn_ty.unsafety();
|
||||
let pointer_ty = self.tcx.coerce_closure_fn_ty(closure_sig, unsafety);
|
||||
let pointer_ty =
|
||||
self.tcx.mk_fn_ptr(self.tcx.signature_unclosure(closure_sig, unsafety));
|
||||
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
|
||||
self.unify_and(
|
||||
pointer_ty,
|
||||
@ -909,23 +910,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
|
||||
|
||||
// Special-case that coercion alone cannot handle:
|
||||
// Two function item types of differing IDs or InternalSubsts.
|
||||
if let (&ty::FnDef(..), &ty::FnDef(..)) = (&prev_ty.kind, &new_ty.kind) {
|
||||
// Don't reify if the function types have a LUB, i.e., they
|
||||
// are the same function and their parameters have a LUB.
|
||||
let lub_ty = self
|
||||
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
|
||||
.map(|ok| self.register_infer_ok_obligations(ok));
|
||||
|
||||
if lub_ty.is_ok() {
|
||||
// We have a LUB of prev_ty and new_ty, just return it.
|
||||
return lub_ty;
|
||||
// Function items or non-capturing closures of differing IDs or InternalSubsts.
|
||||
let (a_sig, b_sig) = {
|
||||
let is_capturing_closure = |ty| {
|
||||
if let &ty::Closure(_, substs) = ty {
|
||||
substs.as_closure().upvar_tys().next().is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
if is_capturing_closure(&prev_ty.kind) || is_capturing_closure(&new_ty.kind) {
|
||||
(None, None)
|
||||
} else {
|
||||
match (&prev_ty.kind, &new_ty.kind) {
|
||||
(&ty::FnDef(..), &ty::FnDef(..)) => {
|
||||
// Don't reify if the function types have a LUB, i.e., they
|
||||
// are the same function and their parameters have a LUB.
|
||||
match self
|
||||
.commit_if_ok(|_| self.at(cause, self.param_env).lub(prev_ty, new_ty))
|
||||
{
|
||||
// We have a LUB of prev_ty and new_ty, just return it.
|
||||
Ok(ok) => return Ok(self.register_infer_ok_obligations(ok)),
|
||||
Err(_) => {
|
||||
(Some(prev_ty.fn_sig(self.tcx)), Some(new_ty.fn_sig(self.tcx)))
|
||||
}
|
||||
}
|
||||
}
|
||||
(&ty::Closure(_, substs), &ty::FnDef(..)) => {
|
||||
let b_sig = new_ty.fn_sig(self.tcx);
|
||||
let a_sig = self
|
||||
.tcx
|
||||
.signature_unclosure(substs.as_closure().sig(), b_sig.unsafety());
|
||||
(Some(a_sig), Some(b_sig))
|
||||
}
|
||||
(&ty::FnDef(..), &ty::Closure(_, substs)) => {
|
||||
let a_sig = prev_ty.fn_sig(self.tcx);
|
||||
let b_sig = self
|
||||
.tcx
|
||||
.signature_unclosure(substs.as_closure().sig(), a_sig.unsafety());
|
||||
(Some(a_sig), Some(b_sig))
|
||||
}
|
||||
(&ty::Closure(_, substs_a), &ty::Closure(_, substs_b)) => (
|
||||
Some(self.tcx.signature_unclosure(
|
||||
substs_a.as_closure().sig(),
|
||||
hir::Unsafety::Normal,
|
||||
)),
|
||||
Some(self.tcx.signature_unclosure(
|
||||
substs_b.as_closure().sig(),
|
||||
hir::Unsafety::Normal,
|
||||
)),
|
||||
),
|
||||
_ => (None, None),
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
if let (Some(a_sig), Some(b_sig)) = (a_sig, b_sig) {
|
||||
// The signature must match.
|
||||
let a_sig = prev_ty.fn_sig(self.tcx);
|
||||
let a_sig = self.normalize_associated_types_in(new.span, &a_sig);
|
||||
let b_sig = new_ty.fn_sig(self.tcx);
|
||||
let b_sig = self.normalize_associated_types_in(new.span, &b_sig);
|
||||
let sig = self
|
||||
.at(cause, self.param_env)
|
||||
@ -935,17 +976,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
// Reify both sides and return the reified fn pointer type.
|
||||
let fn_ptr = self.tcx.mk_fn_ptr(sig);
|
||||
for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
|
||||
// The only adjustment that can produce an fn item is
|
||||
// `NeverToAny`, so this should always be valid.
|
||||
let prev_adjustment = match prev_ty.kind {
|
||||
ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())),
|
||||
ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let next_adjustment = match new_ty.kind {
|
||||
ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())),
|
||||
ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
for expr in exprs.iter().map(|e| e.as_coercion_site()) {
|
||||
self.apply_adjustments(
|
||||
expr,
|
||||
vec![Adjustment {
|
||||
kind: Adjust::Pointer(PointerCast::ReifyFnPointer),
|
||||
target: fn_ptr,
|
||||
}],
|
||||
vec![Adjustment { kind: prev_adjustment.clone(), target: fn_ptr }],
|
||||
);
|
||||
}
|
||||
self.apply_adjustments(new, vec![Adjustment { kind: next_adjustment, target: fn_ptr }]);
|
||||
return Ok(fn_ptr);
|
||||
}
|
||||
|
||||
|
39
src/test/ui/closures/closure_cap_coerce_many_fail.rs
Normal file
39
src/test/ui/closures/closure_cap_coerce_many_fail.rs
Normal file
@ -0,0 +1,39 @@
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
fn main() {
|
||||
// We shouldn't coerce capturing closure to a function
|
||||
let cap = 0;
|
||||
let _ = match "+" {
|
||||
"+" => add,
|
||||
"-" => |a, b| (a - b + cap) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
|
||||
|
||||
// We shouldn't coerce capturing closure to a non-capturing closure
|
||||
let _ = match "+" {
|
||||
"+" => |a, b| (a + b) as i32,
|
||||
"-" => |a, b| (a - b + cap) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
|
||||
|
||||
// We shouldn't coerce non-capturing closure to a capturing closure
|
||||
let _ = match "+" {
|
||||
"+" => |a, b| (a + b + cap) as i32,
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
|
||||
// We shouldn't coerce capturing closure to a capturing closure
|
||||
let _ = match "+" {
|
||||
"+" => |a, b| (a + b + cap) as i32,
|
||||
"-" => |a, b| (a - b + cap) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
}
|
73
src/test/ui/closures/closure_cap_coerce_many_fail.stderr
Normal file
73
src/test/ui/closures/closure_cap_coerce_many_fail.stderr
Normal file
@ -0,0 +1,73 @@
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:9:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => add,
|
||||
| | --- this is found to be of type `fn(i32, i32) -> i32 {add}`
|
||||
LL | | "-" => |a, b| (a - b + cap) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn item, found closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `fn(i32, i32) -> i32 {add}`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]`
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:18:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => |a, b| (a + b) as i32,
|
||||
| | --------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
|
||||
LL | | "-" => |a, b| (a - b + cap) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:27:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => |a, b| (a + b + cap) as i32,
|
||||
| | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
|
||||
LL | | "-" => |a, b| (a - b) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/closure_cap_coerce_many_fail.rs:35:16
|
||||
|
|
||||
LL | let _ = match "+" {
|
||||
| _____________-
|
||||
LL | | "+" => |a, b| (a + b + cap) as i32,
|
||||
| | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
|
||||
LL | | "-" => |a, b| (a - b + cap) as i32,
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => unimplemented!(),
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]`
|
||||
found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
166
src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs
Normal file
166
src/test/ui/closures/closure_no_cap_coerce_many_check_pass.rs
Normal file
@ -0,0 +1,166 @@
|
||||
// check-pass
|
||||
// Ensure non-capturing Closure passes CoerceMany.
|
||||
fn foo(x: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn bar(x: usize) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// One FnDef and one non-capturing Closure
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
2 => |a| 2,
|
||||
0 => foo,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [foo, |a| 2];
|
||||
let _ = [|a| 2, foo];
|
||||
|
||||
|
||||
|
||||
// Two FnDefs and one non-capturing Closure
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
1 => bar,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
2 => |a| 2,
|
||||
1 => bar,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
2 => |a| 2,
|
||||
0 => foo,
|
||||
1 => bar,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [foo, bar, |a| 2];
|
||||
let _ = [foo, |a| 2, bar];
|
||||
let _ = [|a| 2, foo, bar];
|
||||
|
||||
|
||||
|
||||
// One FnDef and two non-capturing Closures
|
||||
let _ = match 0 {
|
||||
0 => foo,
|
||||
1 => |a| 1,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
1 => |a| 1,
|
||||
0 => foo,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = match 0 {
|
||||
1 => |a| 1,
|
||||
2 => |a| 2,
|
||||
0 => foo,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [foo, |a| 1, |a| 2];
|
||||
let _ = [|a| 1, foo, |a| 2];
|
||||
let _ = [|a| 1, |a| 2, foo];
|
||||
|
||||
|
||||
|
||||
// Three non-capturing Closures
|
||||
let _ = match 0 {
|
||||
0 => |a: usize| 0,
|
||||
1 => |a| 1,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let _ = [|a: usize| 0, |a| 1, |a| 2];
|
||||
|
||||
|
||||
|
||||
// Three non-capturing Closures variable
|
||||
let clo0 = |a: usize| 0;
|
||||
let clo1 = |a| 1;
|
||||
let clo2 = |a| 2;
|
||||
let _ = match 0 {
|
||||
0 => clo0,
|
||||
1 => clo1,
|
||||
2 => clo2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
let clo0 = |a: usize| 0;
|
||||
let clo1 = |a| 1;
|
||||
let clo2 = |a| 2;
|
||||
let _ = [clo0, clo1, clo2];
|
||||
|
||||
|
||||
|
||||
// --- Function pointer related part
|
||||
|
||||
// Closure is not in a variable
|
||||
type FnPointer = fn(usize) -> usize;
|
||||
|
||||
let _ = match 0 {
|
||||
0 => foo as FnPointer,
|
||||
2 => |a| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let _ = match 0 {
|
||||
2 => |a| 2,
|
||||
0 => foo as FnPointer,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let _ = [foo as FnPointer, |a| 2];
|
||||
let _ = [|a| 2, foo as FnPointer];
|
||||
let _ = [foo, bar, |x| x];
|
||||
let _ = [foo as FnPointer, bar, |x| x];
|
||||
let _ = [foo, bar as FnPointer, |x| x];
|
||||
let _ = [foo, bar, (|x| x) as FnPointer];
|
||||
let _ = [foo as FnPointer, bar as FnPointer, |x| x];
|
||||
|
||||
// Closure is in a variable
|
||||
let x = |a| 2;
|
||||
let _ = match 0 {
|
||||
0 => foo as FnPointer,
|
||||
2 => x,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let x = |a| 2;
|
||||
let _ = match 0 {
|
||||
2 => x,
|
||||
0 => foo as FnPointer,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let x = |a| 2;
|
||||
let _ = [foo as FnPointer, x];
|
||||
let _ = [x, foo as FnPointer];
|
||||
|
||||
let x = |a| 2;
|
||||
let _ = [foo, bar, x];
|
||||
let x: FnPointer = |a| 2;
|
||||
let _ = [foo, bar, x];
|
||||
let x = |a| 2;
|
||||
let _ = [foo, bar as FnPointer, x];
|
||||
let x = |a| 2;
|
||||
let _ = [foo as FnPointer, bar, x];
|
||||
let x = |a| 2;
|
||||
let _ = [foo as FnPointer, bar as FnPointer, x];
|
||||
}
|
59
src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs
Normal file
59
src/test/ui/closures/closure_no_cap_coerce_many_run_pass.rs
Normal file
@ -0,0 +1,59 @@
|
||||
// run-pass
|
||||
// Ensure non-capturing Closure passing CoerceMany work correctly.
|
||||
fn foo(_: usize) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn bar(_: usize) -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Coerce result check
|
||||
|
||||
type FnPointer = fn(usize) -> usize;
|
||||
|
||||
let c = |x| x;
|
||||
let c_pointer: FnPointer = c;
|
||||
assert_eq!(c_pointer(42), 42);
|
||||
|
||||
let f = match 0 {
|
||||
0 => foo,
|
||||
1 => |_| 1,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 0);
|
||||
|
||||
let f = match 2 {
|
||||
2 => |_| 2,
|
||||
0 => foo,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 2);
|
||||
|
||||
let f = match 1 {
|
||||
0 => foo,
|
||||
1 => bar,
|
||||
2 => |_| 2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 1);
|
||||
|
||||
let clo0 = |_: usize| 0;
|
||||
let clo1 = |_| 1;
|
||||
let clo2 = |_| 2;
|
||||
let f = match 0 {
|
||||
0 => clo0,
|
||||
1 => clo1,
|
||||
2 => clo2,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(f(42), 0);
|
||||
|
||||
let funcs = [add, |a, b| (a - b) as i32];
|
||||
assert_eq!([funcs[0](5, 5), funcs[1](5, 5)], [10, 0]);
|
||||
}
|
22
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs
Normal file
22
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_0.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Ensure we get unsafe function after coercion
|
||||
unsafe fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
fn main() {
|
||||
// We can coerce non-capturing closure to unsafe function
|
||||
let foo = match "+" {
|
||||
"+" => add,
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
|
||||
|
||||
|
||||
// We can coerce unsafe function to non-capturing closure
|
||||
let foo = match "+" {
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
"+" => add,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let result: i32 = foo(5, 5); //~ ERROR call to unsafe function
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:12:23
|
||||
|
|
||||
LL | let result: i32 = foo(5, 5);
|
||||
| ^^^^^^^^^ call to unsafe function
|
||||
|
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
|
||||
--> $DIR/closure_no_cap_coerce_many_unsafe_0.rs:21:23
|
||||
|
|
||||
LL | let result: i32 = foo(5, 5);
|
||||
| ^^^^^^^^^ call to unsafe function
|
||||
|
|
||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0133`.
|
23
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs
Normal file
23
src/test/ui/closures/closure_no_cap_coerce_many_unsafe_1.rs
Normal file
@ -0,0 +1,23 @@
|
||||
// run-pass
|
||||
// Ensure we get correct unsafe function after coercion
|
||||
unsafe fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
fn main() {
|
||||
// We can coerce non-capturing closure to unsafe function
|
||||
let foo = match "+" {
|
||||
"+" => add,
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(unsafe { foo(5, 5) }, 10);
|
||||
|
||||
|
||||
// We can coerce unsafe function to non-capturing closure
|
||||
let foo = match "-" {
|
||||
"-" => |a, b| (a - b) as i32,
|
||||
"+" => add,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
assert_eq!(unsafe { foo(5, 5) }, 0);
|
||||
}
|
9
src/test/ui/closures/issue-46742.rs
Normal file
9
src/test/ui/closures/issue-46742.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// check-pass
|
||||
fn main() {
|
||||
let _: i32 = (match "" {
|
||||
"+" => ::std::ops::Add::add,
|
||||
"-" => ::std::ops::Sub::sub,
|
||||
"<" => |a,b| (a < b) as i32,
|
||||
_ => unimplemented!(),
|
||||
})(5, 5);
|
||||
}
|
14
src/test/ui/closures/issue-48109.rs
Normal file
14
src/test/ui/closures/issue-48109.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
fn useful(i: usize) -> usize {
|
||||
i
|
||||
}
|
||||
|
||||
fn useful2(i: usize) -> usize {
|
||||
i
|
||||
}
|
||||
|
||||
fn main() {
|
||||
for f in &[useful, useful2, |x| x] {
|
||||
println!("{}", f(6));
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ fn closure_from_match() {
|
||||
2 => |c| c - 1,
|
||||
_ => |c| c - 1
|
||||
};
|
||||
//~^^^ ERROR `match` arms have incompatible types
|
||||
//~^^^^ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
@ -11,24 +11,13 @@ LL | x = |c| c + 1;
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
|
||||
error[E0308]: `match` arms have incompatible types
|
||||
--> $DIR/issue-24036.rs:10:14
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/issue-24036.rs:9:15
|
||||
|
|
||||
LL | let x = match 1usize {
|
||||
| _____________-
|
||||
LL | | 1 => |c| c + 1,
|
||||
| | --------- this is found to be of type `[closure@$DIR/issue-24036.rs:9:14: 9:23]`
|
||||
LL | | 2 => |c| c - 1,
|
||||
| | ^^^^^^^^^ expected closure, found a different closure
|
||||
LL | | _ => |c| c - 1
|
||||
LL | | };
|
||||
| |_____- `match` arms have incompatible types
|
||||
|
|
||||
= note: expected type `[closure@$DIR/issue-24036.rs:9:14: 9:23]`
|
||||
found closure `[closure@$DIR/issue-24036.rs:10:14: 10:23]`
|
||||
= note: no two closures, even if identical, have the same type
|
||||
= help: consider boxing your closure and/or using it as a trait object
|
||||
LL | 1 => |c| c + 1,
|
||||
| ^ consider giving this closure parameter a type
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
Some errors have detailed explanations: E0282, E0308.
|
||||
For more information about an error, try `rustc --explain E0282`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user