}
match a.sty {
- ty::TyFnDef(.., a_f) => {
+ ty::TyFnDef(..) => {
// Function items are coercible to any closure
// type; function pointers are not (that would
// require double indirection).
// Additionally, we permit coercion of function
// items to drop the unsafe qualifier.
- self.coerce_from_fn_item(a, a_f, b)
+ self.coerce_from_fn_item(a, b)
}
ty::TyFnPtr(a_f) => {
// We permit coercion of fn pointers to drop the
fn coerce_from_fn_item(&self,
a: Ty<'tcx>,
- fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a Rust function item
match b.sty {
ty::TyFnPtr(_) => {
- let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
- self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b,
- simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))
+ let a_sig = a.fn_sig(self.tcx);
+ let InferOk { value: a_sig, mut obligations } =
+ self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);
+
+ let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
+ let InferOk { value, obligations: o2 } =
+ self.coerce_from_safe_fn(a_fn_pointer, a_sig, b,
+ simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))?;
+
+ obligations.extend(o2);
+ Ok(InferOk { value, obligations })
}
_ => self.unify_and(a, b, identity),
}
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
// to
// `fn(arg0,arg1,...) -> _`
- let sig = self.closure_type(def_id_a).subst(self.tcx, substs_a.substs);
+ let sig = self.fn_sig(def_id_a).subst(self.tcx, substs_a.substs);
let converted_sig = sig.map_bound(|s| {
let params_iter = match s.inputs()[0].sty {
ty::TyTuple(params, _) => {
// Special-case that coercion alone cannot handle:
// Two function item types of differing IDs or Substs.
- match (&prev_ty.sty, &new_ty.sty) {
- (&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
- // The signature must always match.
- let fty = self.at(cause, self.param_env)
- .trace(prev_ty, new_ty)
- .lub(&a_fty, &b_fty)
- .map(|ok| self.register_infer_ok_obligations(ok))?;
-
- if a_def_id == b_def_id {
- // Same function, maybe the parameters match.
- let substs = self.commit_if_ok(|_| {
- self.at(cause, self.param_env)
- .trace(prev_ty, new_ty)
- .lub(&a_substs, &b_substs)
- .map(|ok| self.register_infer_ok_obligations(ok))
- });
-
- if let Ok(substs) = substs {
- // We have a LUB of prev_ty and new_ty, just return it.
- return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty));
- }
- }
+ if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) {
+ // 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;
+ }
- // Reify both sides and return the reified fn pointer type.
- let fn_ptr = self.tcx.mk_fn_ptr(fty);
- 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.
- self.apply_adjustments(expr, vec![Adjustment {
- kind: Adjust::ReifyFnPointer,
- target: fn_ptr
- }]);
- }
- return Ok(fn_ptr);
+ // 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)
+ .trace(prev_ty, new_ty)
+ .lub(&a_sig, &b_sig)
+ .map(|ok| self.register_infer_ok_obligations(ok))?;
+
+ // 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.
+ self.apply_adjustments(expr, vec![Adjustment {
+ kind: Adjust::ReifyFnPointer,
+ target: fn_ptr
+ }]);
}
- _ => {}
+ return Ok(fn_ptr);
}
let mut coerce = Coerce::new(self, cause.clone());