|
63 | 63 | use check::FnCtxt;
|
64 | 64 |
|
65 | 65 | use rustc::hir;
|
| 66 | +use rustc::hir::def_id::DefId; |
66 | 67 | use rustc::infer::{Coercion, InferOk, TypeTrace};
|
67 | 68 | use rustc::traits::{self, ObligationCause, ObligationCauseCode};
|
68 | 69 | use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
|
69 |
| -use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty}; |
| 70 | +use rustc::ty::{self, LvaluePreference, TypeAndMut, |
| 71 | + Ty, ClosureSubsts}; |
70 | 72 | use rustc::ty::fold::TypeFoldable;
|
71 | 73 | use rustc::ty::error::TypeError;
|
72 | 74 | use rustc::ty::relate::RelateResult;
|
| 75 | +use syntax::abi; |
| 76 | +use syntax::feature_gate; |
73 | 77 | use util::common::indent;
|
74 | 78 |
|
75 | 79 | use std::cell::RefCell;
|
@@ -196,6 +200,11 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
196 | 200 | // unsafe qualifier.
|
197 | 201 | self.coerce_from_fn_pointer(a, a_f, b)
|
198 | 202 | }
|
| 203 | + ty::TyClosure(def_id_a, substs_a) => { |
| 204 | + // Non-capturing closures are coercible to |
| 205 | + // function pointers |
| 206 | + self.coerce_closure_to_fn(a, def_id_a, substs_a, b) |
| 207 | + } |
199 | 208 | _ => {
|
200 | 209 | // Otherwise, just use unification rules.
|
201 | 210 | self.unify_and_identity(a, b)
|
@@ -551,6 +560,60 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
551 | 560 | }
|
552 | 561 | }
|
553 | 562 |
|
| 563 | + fn coerce_closure_to_fn(&self, |
| 564 | + a: Ty<'tcx>, |
| 565 | + def_id_a: DefId, |
| 566 | + substs_a: ClosureSubsts<'tcx>, |
| 567 | + b: Ty<'tcx>) |
| 568 | + -> CoerceResult<'tcx> { |
| 569 | + //! Attempts to coerce from the type of a non-capturing closure |
| 570 | + //! into a function pointer. |
| 571 | + //! |
| 572 | +
|
| 573 | + let b = self.shallow_resolve(b); |
| 574 | + |
| 575 | + let node_id_a = self.tcx.hir.as_local_node_id(def_id_a).unwrap(); |
| 576 | + match b.sty { |
| 577 | + ty::TyFnPtr(_) if self.tcx.with_freevars(node_id_a, |v| v.is_empty()) => { |
| 578 | + if !self.tcx.sess.features.borrow().closure_to_fn_coercion { |
| 579 | + feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, |
| 580 | + "closure_to_fn_coercion", |
| 581 | + self.cause.span, |
| 582 | + feature_gate::GateIssue::Language, |
| 583 | + feature_gate::CLOSURE_TO_FN_COERCION); |
| 584 | + return self.unify_and_identity(a, b); |
| 585 | + } |
| 586 | + // We coerce the closure, which has fn type |
| 587 | + // `extern "rust-call" fn((arg0,arg1,...)) -> _` |
| 588 | + // to |
| 589 | + // `fn(arg0,arg1,...) -> _` |
| 590 | + let sig = self.closure_type(def_id_a, substs_a).sig; |
| 591 | + let converted_sig = sig.map_bound(|s| { |
| 592 | + let params_iter = match s.inputs()[0].sty { |
| 593 | + ty::TyTuple(params, _) => { |
| 594 | + params.into_iter().cloned() |
| 595 | + } |
| 596 | + _ => bug!(), |
| 597 | + }; |
| 598 | + self.tcx.mk_fn_sig(params_iter, |
| 599 | + s.output(), |
| 600 | + s.variadic) |
| 601 | + }); |
| 602 | + let fn_ty = self.tcx.mk_bare_fn(ty::BareFnTy { |
| 603 | + unsafety: hir::Unsafety::Normal, |
| 604 | + abi: abi::Abi::Rust, |
| 605 | + sig: converted_sig, |
| 606 | + }); |
| 607 | + let pointer_ty = self.tcx.mk_fn_ptr(&fn_ty); |
| 608 | + debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", |
| 609 | + a, b, pointer_ty); |
| 610 | + self.unify_and_identity(pointer_ty, b) |
| 611 | + .map(|(ty, _)| (ty, Adjust::ClosureFnPointer)) |
| 612 | + } |
| 613 | + _ => self.unify_and_identity(a, b), |
| 614 | + } |
| 615 | + } |
| 616 | + |
554 | 617 | fn coerce_unsafe_ptr(&self,
|
555 | 618 | a: Ty<'tcx>,
|
556 | 619 | b: Ty<'tcx>,
|
|
0 commit comments