use rustc_hir::def_id::DefId;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
+use rustc_infer::traits::Obligation;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{self, BytePos, Span};
}
fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
+ // First, remove any resolved type variables (at the top level, at least):
let a = self.shallow_resolve(a);
+ let b = self.shallow_resolve(b);
debug!("Coerce.tys({:?} => {:?})", a, b);
// Just ignore error types.
return success(vec![], self.fcx.tcx.ty_error(), vec![]);
}
+ // Coercing from `!` to any type is allowed:
if a.is_never() {
// Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
// type variable, we want `?T` to fallback to `!` if not
// let _: Option<?T> = Some({ return; });
//
// here, we would coerce from `!` to `?T`.
- let b = self.shallow_resolve(b);
- return if self.shallow_resolve(b).is_ty_var() {
+ return if b.is_ty_var() {
// Micro-optimization: no need for this if `b` is
// already resolved in some way.
let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::AdjustmentType,
span: self.cause.span,
});
- self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
+ self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
} else {
success(simple(Adjust::NeverToAny)(b), b, vec![])
};
}
+ // Coercing *from* an unresolved inference variable means that
+ // we have no information about the source type. This will always
+ // ultimately fall back to some form of subtyping.
+ if a.is_ty_var() {
+ return self.coerce_from_inference_variable(a, b, identity);
+ }
+
// Consider coercing the subtype to a DST
//
// NOTE: this is wrapped in a `commit_if_ok` because it creates
debug!("coerce: unsize failed");
// Examine the supertype and consider auto-borrowing.
- //
- // Note: does not attempt to resolve type variables we encounter.
- // See above for details.
match *b.kind() {
ty::RawPtr(mt_b) => {
return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
}
}
+ /// Coercing *from* an inference variable. In this case, we have no information
+ /// about the source type, so we can't really do a true coercion and we always
+ /// fall back to subtyping (`unify_and`).
+ fn coerce_from_inference_variable(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
+ ) -> CoerceResult<'tcx> {
+ debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
+ assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
+ assert!(self.infcx.shallow_resolve(b) == b);
+
+ if b.is_ty_var() {
+ // Two unresolved type variables: create a `Coerce` predicate.
+ let target_ty = if self.use_lub {
+ self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::LatticeVariable,
+ span: self.cause.span,
+ })
+ } else {
+ b
+ };
+
+ let mut obligations = Vec::with_capacity(2);
+ for &source_ty in &[a, b] {
+ if source_ty != target_ty {
+ obligations.push(Obligation::new(
+ self.cause.clone(),
+ self.param_env,
+ ty::PredicateKind::Coerce(ty::CoercePredicate {
+ a: source_ty,
+ b: target_ty,
+ })
+ .to_predicate(self.tcx()),
+ ));
+ }
+ }
+
+ debug!(
+ "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
+ target_ty, obligations
+ );
+ let adjustments = make_adjustments(target_ty);
+ InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
+ } else {
+ // One unresolved type variable: just apply subtyping, we may be able
+ // to do something useful.
+ self.unify_and(a, b, make_adjustments)
+ }
+ }
+
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
/// To match `A` with `B`, autoderef will be performed,
/// calling `deref`/`deref_mut` where necessary.
//! into a closure or a `proc`.
let b = self.shallow_resolve(b);
+ let InferOk { value: b, mut obligations } =
+ self.normalize_associated_types_in_as_infer_ok(self.cause.span, b);
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
match b.kind() {
}
}
- let InferOk { value: a_sig, mut obligations } =
+ let InferOk { value: a_sig, obligations: o1 } =
self.normalize_associated_types_in_as_infer_ok(self.cause.span, a_sig);
+ obligations.extend(o1);
let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
/// The inner coercion "engine". If `expression` is `None`, this
/// is a forced-unit case, and hence `expression_ty` must be
/// `Nil`.
+ #[instrument(skip(self, fcx, augment_error, label_expression_as_expected), level = "debug")]
crate fn coerce_inner<'a>(
&mut self,
fcx: &FnCtxt<'a, 'tcx>,