Skip to content

Commit

Permalink
create Coercion obligations given 2 unbound type variables
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikomatsakis authored and Mark-Simulacrum committed Aug 20, 2021
1 parent 020655b commit faf8426
Showing 1 changed file with 48 additions and 5 deletions.
53 changes: 48 additions & 5 deletions compiler/rustc_typeck/src/check/coercion.rs
Expand Up @@ -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,
Expand All @@ -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};
Expand Down Expand Up @@ -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![])
};
Expand All @@ -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
Expand Down Expand Up @@ -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`.
Expand Down

0 comments on commit faf8426

Please sign in to comment.