Skip to content

Commit a4f357d

Browse files
committed
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.
1 parent b37daab commit a4f357d

File tree

1 file changed

+55
-7
lines changed

1 file changed

+55
-7
lines changed

compiler/rustc_typeck/src/check/coercion.rs

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,22 @@ use crate::check::FnCtxt;
4040
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
4141
use rustc_hir as hir;
4242
use rustc_hir::def_id::DefId;
43-
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
4443
use rustc_infer::infer::{Coercion, InferOk, InferResult};
45-
use rustc_middle::ty::adjustment::{
46-
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
44+
use rustc_infer::{
45+
infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind},
46+
traits::Obligation,
4747
};
4848
use rustc_middle::ty::error::TypeError;
4949
use rustc_middle::ty::fold::TypeFoldable;
5050
use rustc_middle::ty::relate::RelateResult;
5151
use rustc_middle::ty::subst::SubstsRef;
5252
use rustc_middle::ty::{self, Ty, TypeAndMut};
53+
use rustc_middle::ty::{
54+
adjustment::{
55+
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
56+
},
57+
ToPredicate,
58+
};
5359
use rustc_session::parse::feature_err;
5460
use rustc_span::symbol::sym;
5561
use rustc_span::{self, BytePos, Span};
@@ -171,7 +177,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
171177
kind: TypeVariableOriginKind::AdjustmentType,
172178
span: self.cause.span,
173179
});
174-
self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
180+
self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
175181
} else {
176182
success(simple(Adjust::NeverToAny)(b), b, vec![])
177183
};
@@ -181,7 +187,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
181187
// we have no information about the source type. This will always
182188
// ultimately fall back to some form of subtyping.
183189
if a.is_ty_var() {
184-
return self.coerce_from_inference_variable(a, b);
190+
return self.coerce_from_inference_variable(a, b, identity);
185191
}
186192

187193
// Consider coercing the subtype to a DST
@@ -244,11 +250,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
244250
/// Coercing *from* an inference variable. In this case, we have no information
245251
/// about the source type, so we can't really do a true coercion and we always
246252
/// fall back to subtyping (`unify_and`).
247-
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
253+
fn coerce_from_inference_variable(
254+
&self,
255+
a: Ty<'tcx>,
256+
b: Ty<'tcx>,
257+
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
258+
) -> CoerceResult<'tcx> {
259+
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
248260
assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
249261
assert!(self.infcx.shallow_resolve(b) == b);
250262

251-
self.unify_and(a, b, identity)
263+
if b.is_ty_var() {
264+
// Two unresolved type variables: create a `Coerce` predicate.
265+
let target_ty = if self.use_lub {
266+
self.infcx.next_ty_var(TypeVariableOrigin {
267+
kind: TypeVariableOriginKind::LatticeVariable,
268+
span: self.cause.span,
269+
})
270+
} else {
271+
b
272+
};
273+
274+
let mut obligations = Vec::with_capacity(2);
275+
for &source_ty in &[a, b] {
276+
if source_ty != target_ty {
277+
obligations.push(Obligation::new(
278+
self.cause.clone(),
279+
self.param_env,
280+
ty::PredicateAtom::Coerce(ty::CoercePredicate {
281+
a: source_ty,
282+
b: target_ty,
283+
})
284+
.to_predicate(self.tcx()),
285+
));
286+
}
287+
}
288+
289+
debug!(
290+
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
291+
target_ty, obligations
292+
);
293+
let adjustments = make_adjustments(target_ty);
294+
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
295+
} else {
296+
// One unresolved type variable: just apply subtyping, we may be able
297+
// to do something useful.
298+
self.unify_and(a, b, make_adjustments)
299+
}
252300
}
253301

254302
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.

0 commit comments

Comments
 (0)