create Coercion obligations given 2 unbound type variables

Motivation: in upcoming commits, we are going to create a graph of the
coercion relationships between variables. We want to
distinguish *coercion* specifically from other sorts of subtyping, as
it indicates values flowing from one place to another via assignment.
This commit is contained in:
Niko Matsakis 2020-11-21 15:47:14 -05:00 committed by Mark Rousskov
parent 020655b90d
commit faf84263f2

View File

@ -42,6 +42,7 @@ use rustc_hir as hir;
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,
@ -50,7 +51,7 @@ use rustc_middle::ty::error::TypeError;
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};
@ -172,7 +173,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
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![])
};
@ -182,7 +183,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
// 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);
return self.coerce_from_inference_variable(a, b, identity);
}
// Consider coercing the subtype to a DST
@ -245,11 +246,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
/// 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>) -> CoerceResult<'tcx> {
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);
self.unify_and(a, b, identity)
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`.