Skip to content

Commit 947c0de

Browse files
nikomatsakisMark-Simulacrum
authored andcommitted
introduce a Coerce predicate
1 parent 5a8edc0 commit 947c0de

File tree

24 files changed

+153
-2
lines changed

24 files changed

+153
-2
lines changed

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,35 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
969969
);
970970
}
971971

972+
/// Processes a `Coerce` predicate from the fulfillment context.
973+
/// This is NOT the preferred way to handle coercion, which is to
974+
/// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`).
975+
///
976+
/// This method here is actually a fallback that winds up being
977+
/// invoked when `FnCtxt::coerce` encounters unresolved type variables
978+
/// and records a coercion predicate. Presently, this method is equivalent
979+
/// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up
980+
/// actually requiring `a <: b`. This is of course a valid coercion,
981+
/// but it's not as flexible as `FnCtxt::coerce` would be.
982+
///
983+
/// (We may refactor this in the future, but there are a number of
984+
/// practical obstacles. Among other things, `FnCtxt::coerce` presently
985+
/// records adjustments that are required on the HIR in order to perform
986+
/// the coercion, and we don't currently have a way to manage that.)
987+
pub fn coerce_predicate(
988+
&self,
989+
cause: &ObligationCause<'tcx>,
990+
param_env: ty::ParamEnv<'tcx>,
991+
predicate: ty::PolyCoercePredicate<'tcx>,
992+
) -> Option<InferResult<'tcx, ()>> {
993+
let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
994+
a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
995+
a: p.a,
996+
b: p.b,
997+
});
998+
self.subtype_predicate(cause, param_env, subtype_predicate)
999+
}
1000+
9721001
pub fn subtype_predicate(
9731002
&self,
9741003
cause: &ObligationCause<'tcx>,

compiler/rustc_infer/src/infer/outlives/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn explicit_outlives_bounds<'tcx>(
1919
.filter_map(move |kind| match kind {
2020
ty::PredicateKind::Projection(..)
2121
| ty::PredicateKind::Trait(..)
22+
| ty::PredicateKind::Coerce(..)
2223
| ty::PredicateKind::Subtype(..)
2324
| ty::PredicateKind::WellFormed(..)
2425
| ty::PredicateKind::ObjectSafe(..)

compiler/rustc_infer/src/traits/util.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ impl Elaborator<'tcx> {
158158
// Currently, we do not "elaborate" predicates like `X <: Y`,
159159
// though conceivably we might.
160160
}
161+
ty::PredicateKind::Coerce(..) => {
162+
// Currently, we do not "elaborate" predicates like `X -> Y`,
163+
// though conceivably we might.
164+
}
161165
ty::PredicateKind::Projection(..) => {
162166
// Nothing to elaborate in a projection predicate.
163167
}

compiler/rustc_lint/src/builtin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
16521652
ObjectSafe(..) |
16531653
ClosureKind(..) |
16541654
Subtype(..) |
1655+
Coerce(..) |
16551656
ConstEvaluatable(..) |
16561657
ConstEquate(..) |
16571658
TypeWellFormedFromEnv(..) => continue,

compiler/rustc_middle/src/ty/flags.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ impl FlagComputation {
231231
self.add_ty(a);
232232
self.add_ty(b);
233233
}
234+
ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
235+
self.add_ty(a);
236+
self.add_ty(b);
237+
}
234238
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
235239
self.add_projection_ty(projection_ty);
236240
self.add_ty(ty);

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,22 @@ pub enum PredicateKind<'tcx> {
485485
ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind),
486486

487487
/// `T1 <: T2`
488+
///
489+
/// This obligation is created most often when we have two
490+
/// unresolved type variables and hence don't have enough
491+
/// information to process the subtyping obligation yet.
488492
Subtype(SubtypePredicate<'tcx>),
489493

494+
/// `T1` coerced to `T2`
495+
///
496+
/// Like a subtyping obligation, this is created most often
497+
/// when we have two unresolved type variables and hence
498+
/// don't have enough information to process the coercion
499+
/// obligation yet. At the moment, we actually process coercions
500+
/// very much like subtyping and don't handle the full coercion
501+
/// logic.
502+
Coerce(CoercePredicate<'tcx>),
503+
490504
/// Constant initializer must evaluate successfully.
491505
ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
492506

@@ -655,6 +669,9 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'t
655669
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
656670
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
657671

672+
/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
673+
/// whether the `a` type is the type that we should label as "expected" when
674+
/// presenting user diagnostics.
658675
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
659676
#[derive(HashStable, TypeFoldable)]
660677
pub struct SubtypePredicate<'tcx> {
@@ -664,6 +681,15 @@ pub struct SubtypePredicate<'tcx> {
664681
}
665682
pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
666683

684+
/// Encodes that we have to coerce *from* the `a` type to the `b` type.
685+
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
686+
#[derive(HashStable, TypeFoldable)]
687+
pub struct CoercePredicate<'tcx> {
688+
pub a: Ty<'tcx>,
689+
pub b: Ty<'tcx>,
690+
}
691+
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
692+
667693
/// This kind of predicate has no *direct* correspondent in the
668694
/// syntax, but it roughly corresponds to the syntactic forms:
669695
///
@@ -806,6 +832,7 @@ impl<'tcx> Predicate<'tcx> {
806832
}
807833
PredicateKind::Projection(..)
808834
| PredicateKind::Subtype(..)
835+
| PredicateKind::Coerce(..)
809836
| PredicateKind::RegionOutlives(..)
810837
| PredicateKind::WellFormed(..)
811838
| PredicateKind::ObjectSafe(..)
@@ -824,6 +851,7 @@ impl<'tcx> Predicate<'tcx> {
824851
PredicateKind::Trait(..)
825852
| PredicateKind::Projection(..)
826853
| PredicateKind::Subtype(..)
854+
| PredicateKind::Coerce(..)
827855
| PredicateKind::RegionOutlives(..)
828856
| PredicateKind::WellFormed(..)
829857
| PredicateKind::ObjectSafe(..)

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,6 +2236,10 @@ define_print_and_forward_display! {
22362236
p!(print(self.a), " <: ", print(self.b))
22372237
}
22382238

2239+
ty::CoercePredicate<'tcx> {
2240+
p!(print(self.a), " -> ", print(self.b))
2241+
}
2242+
22392243
ty::TraitPredicate<'tcx> {
22402244
p!(print(self.trait_ref.self_ty()), ": ",
22412245
print(self.trait_ref.print_only_trait_path()))
@@ -2268,6 +2272,7 @@ define_print_and_forward_display! {
22682272
p!(print(data))
22692273
}
22702274
ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
2275+
ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
22712276
ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
22722277
ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
22732278
ty::PredicateKind::Projection(predicate) => p!(print(predicate)),

compiler/rustc_middle/src/ty/structural_impls.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
179179
match *self {
180180
ty::PredicateKind::Trait(ref a) => a.fmt(f),
181181
ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
182+
ty::PredicateKind::Coerce(ref pair) => pair.fmt(f),
182183
ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
183184
ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
184185
ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
@@ -380,6 +381,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> {
380381
}
381382
}
382383

384+
impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> {
385+
type Lifted = ty::CoercePredicate<'tcx>;
386+
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> {
387+
tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b })
388+
}
389+
}
390+
383391
impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
384392
type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
385393
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -420,6 +428,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
420428
match self {
421429
ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait),
422430
ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
431+
ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce),
423432
ty::PredicateKind::RegionOutlives(data) => {
424433
tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
425434
}

compiler/rustc_mir/src/transform/check_consts/check.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,8 +420,8 @@ impl Checker<'mir, 'tcx> {
420420
ty::PredicateKind::ClosureKind(..) => {
421421
bug!("closure kind predicate on function: {:#?}", predicate)
422422
}
423-
ty::PredicateKind::Subtype(_) => {
424-
bug!("subtype predicate on function: {:#?}", predicate)
423+
ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
424+
bug!("subtype/coerce predicate on function: {:#?}", predicate)
425425
}
426426
ty::PredicateKind::Trait(pred) => {
427427
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {

compiler/rustc_trait_selection/src/opaque_types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,7 @@ crate fn required_region_bounds(
11191119
ty::PredicateKind::Projection(..)
11201120
| ty::PredicateKind::Trait(..)
11211121
| ty::PredicateKind::Subtype(..)
1122+
| ty::PredicateKind::Coerce(..)
11221123
| ty::PredicateKind::WellFormed(..)
11231124
| ty::PredicateKind::ObjectSafe(..)
11241125
| ty::PredicateKind::ClosureKind(..)

0 commit comments

Comments
 (0)