Skip to content

Commit e0b91b2

Browse files
authored
Rollup merge of rust-lang#139582 - oli-obk:coercion-cleanups, r=compiler-errors
Various coercion cleanups I think the commit order is the most reasonable one, but there's probably more ways to get to the same goal. Essentially I got rid of the `simple` and `identity` helpers by adding a dedicated function for the common `identity` case and getting rid of the callbacks alltogether by realizing that all callbacks were of the pattern "use this fixed prefix list of adjustments, then add another adjustment with the unified type as the target type". No behavioral changes intended
2 parents 88e7f7d + f80b121 commit e0b91b2

File tree

1 file changed

+82
-94
lines changed

1 file changed

+82
-94
lines changed

Diff for: compiler/rustc_hir_typeck/src/coercion.rs

+82-94
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,6 @@ fn coerce_mutbls<'tcx>(
103103
if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
104104
}
105105

106-
/// Do not require any adjustments, i.e. coerce `x -> x`.
107-
fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
108-
vec![]
109-
}
110-
111-
fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
112-
move |target| vec![Adjustment { kind, target }]
113-
}
114-
115106
/// This always returns `Ok(...)`.
116107
fn success<'tcx>(
117108
adj: Vec<Adjustment<'tcx>>,
@@ -131,7 +122,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
131122
Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
132123
}
133124

134-
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
125+
fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
135126
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
136127
self.commit_if_ok(|_| {
137128
let at = self.at(&self.cause, self.fcx.param_env);
@@ -161,13 +152,30 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
161152
})
162153
}
163154

155+
/// Unify two types (using sub or lub).
156+
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
157+
self.unify_raw(a, b)
158+
.and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations))
159+
}
160+
164161
/// Unify two types (using sub or lub) and produce a specific coercion.
165-
fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
166-
where
167-
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
168-
{
169-
self.unify(a, b)
170-
.and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
162+
fn unify_and(
163+
&self,
164+
a: Ty<'tcx>,
165+
b: Ty<'tcx>,
166+
adjustments: impl IntoIterator<Item = Adjustment<'tcx>>,
167+
final_adjustment: Adjust,
168+
) -> CoerceResult<'tcx> {
169+
self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| {
170+
success(
171+
adjustments
172+
.into_iter()
173+
.chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment }))
174+
.collect(),
175+
ty,
176+
obligations,
177+
)
178+
})
171179
}
172180

173181
#[instrument(skip(self))]
@@ -180,18 +188,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
180188
// Coercing from `!` to any type is allowed:
181189
if a.is_never() {
182190
if self.coerce_never {
183-
return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
191+
return success(
192+
vec![Adjustment { kind: Adjust::NeverToAny, target: b }],
193+
b,
194+
PredicateObligations::new(),
195+
);
184196
} else {
185197
// Otherwise the only coercion we can do is unification.
186-
return self.unify_and(a, b, identity);
198+
return self.unify(a, b);
187199
}
188200
}
189201

190202
// Coercing *from* an unresolved inference variable means that
191203
// we have no information about the source type. This will always
192204
// ultimately fall back to some form of subtyping.
193205
if a.is_ty_var() {
194-
return self.coerce_from_inference_variable(a, b, identity);
206+
return self.coerce_from_inference_variable(a, b);
195207
}
196208

197209
// Consider coercing the subtype to a DST
@@ -247,7 +259,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
247259
ty::FnPtr(a_sig_tys, a_hdr) => {
248260
// We permit coercion of fn pointers to drop the
249261
// unsafe qualifier.
250-
self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b)
262+
self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b)
251263
}
252264
ty::Closure(closure_def_id_a, args_a) => {
253265
// Non-capturing closures are coercible to
@@ -257,20 +269,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
257269
}
258270
_ => {
259271
// Otherwise, just use unification rules.
260-
self.unify_and(a, b, identity)
272+
self.unify(a, b)
261273
}
262274
}
263275
}
264276

265277
/// Coercing *from* an inference variable. In this case, we have no information
266278
/// about the source type, so we can't really do a true coercion and we always
267279
/// fall back to subtyping (`unify_and`).
268-
fn coerce_from_inference_variable(
269-
&self,
270-
a: Ty<'tcx>,
271-
b: Ty<'tcx>,
272-
make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
273-
) -> CoerceResult<'tcx> {
280+
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
274281
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
275282
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
276283
assert!(self.shallow_resolve(b) == b);
@@ -298,12 +305,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
298305
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
299306
target_ty, obligations
300307
);
301-
let adjustments = make_adjustments(target_ty);
302-
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
308+
success(vec![], target_ty, obligations)
303309
} else {
304310
// One unresolved type variable: just apply subtyping, we may be able
305311
// to do something useful.
306-
self.unify_and(a, b, make_adjustments)
312+
self.unify(a, b)
307313
}
308314
}
309315

@@ -331,7 +337,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
331337
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
332338
(r_a, mt_a)
333339
}
334-
_ => return self.unify_and(a, b, identity),
340+
_ => return self.unify(a, b),
335341
};
336342

337343
let span = self.cause.span;
@@ -437,7 +443,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
437443
referent_ty,
438444
mutbl_b, // [1] above
439445
);
440-
match self.unify(derefd_ty_a, b) {
446+
match self.unify_raw(derefd_ty_a, b) {
441447
Ok(ok) => {
442448
found = Some(ok);
443449
break;
@@ -579,13 +585,13 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
579585
// We only have the latter, so we use an inference variable
580586
// for the former and let type inference do the rest.
581587
let coerce_target = self.next_ty_var(self.cause.span);
582-
let mut coercion = self.unify_and(coerce_target, target, |target| {
583-
let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
584-
match reborrow {
585-
None => vec![unsize],
586-
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
587-
}
588-
})?;
588+
589+
let mut coercion = self.unify_and(
590+
coerce_target,
591+
target,
592+
reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]),
593+
Adjust::Pointer(PointerCoercion::Unsize),
594+
)?;
589595

590596
let mut selcx = traits::SelectionContext::new(self);
591597

@@ -708,7 +714,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
708714
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
709715
&& a_data.principal_def_id() == b_data.principal_def_id()
710716
{
711-
return self.unify_and(a, b, |_| vec![]);
717+
return self.unify(a, b);
712718
}
713719

714720
// Check the obligations of the cast -- for example, when casting
@@ -808,23 +814,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
808814

809815
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
810816
// add the adjustments.
811-
self.unify_and(a, b, |_inner_ty| {
812-
vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }]
813-
})
817+
self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
814818
}
815819

816-
fn coerce_from_safe_fn<F, G>(
820+
fn coerce_from_safe_fn(
817821
&self,
818-
a: Ty<'tcx>,
819822
fn_ty_a: ty::PolyFnSig<'tcx>,
820823
b: Ty<'tcx>,
821-
to_unsafe: F,
822-
normal: G,
823-
) -> CoerceResult<'tcx>
824-
where
825-
F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
826-
G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
827-
{
824+
adjustment: Option<Adjust>,
825+
) -> CoerceResult<'tcx> {
828826
self.commit_if_ok(|snapshot| {
829827
let outer_universe = self.infcx.universe();
830828

@@ -833,9 +831,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
833831
&& hdr_b.safety.is_unsafe()
834832
{
835833
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
836-
self.unify_and(unsafe_a, b, to_unsafe)
834+
self.unify_and(
835+
unsafe_a,
836+
b,
837+
adjustment
838+
.map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }),
839+
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
840+
)
837841
} else {
838-
self.unify_and(a, b, normal)
842+
let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
843+
match adjustment {
844+
Some(adjust) => self.unify_and(a, b, [], adjust),
845+
None => self.unify(a, b),
846+
}
839847
};
840848

841849
// FIXME(#73154): This is a hack. Currently LUB can generate
@@ -852,7 +860,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
852860

853861
fn coerce_from_fn_pointer(
854862
&self,
855-
a: Ty<'tcx>,
856863
fn_ty_a: ty::PolyFnSig<'tcx>,
857864
b: Ty<'tcx>,
858865
) -> CoerceResult<'tcx> {
@@ -861,15 +868,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
861868
//!
862869
863870
let b = self.shallow_resolve(b);
864-
debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
865-
866-
self.coerce_from_safe_fn(
867-
a,
868-
fn_ty_a,
869-
b,
870-
simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
871-
identity,
872-
)
871+
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
872+
873+
self.coerce_from_safe_fn(fn_ty_a, b, None)
873874
}
874875

875876
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
@@ -916,30 +917,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
916917
self.at(&self.cause, self.param_env).normalize(a_sig);
917918
obligations.extend(o1);
918919

919-
let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
920920
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
921-
a_fn_pointer,
922921
a_sig,
923922
b,
924-
|unsafe_ty| {
925-
vec![
926-
Adjustment {
927-
kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer),
928-
target: a_fn_pointer,
929-
},
930-
Adjustment {
931-
kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
932-
target: unsafe_ty,
933-
},
934-
]
935-
},
936-
simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
923+
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
937924
)?;
938925

939926
obligations.extend(o2);
940927
Ok(InferOk { value, obligations })
941928
}
942-
_ => self.unify_and(a, b, identity),
929+
_ => self.unify(a, b),
943930
}
944931
}
945932

@@ -983,10 +970,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
983970
self.unify_and(
984971
pointer_ty,
985972
b,
986-
simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
973+
[],
974+
Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
987975
)
988976
}
989-
_ => self.unify_and(a, b, identity),
977+
_ => self.unify(a, b),
990978
}
991979
}
992980

@@ -1001,7 +989,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1001989
let (is_ref, mt_a) = match *a.kind() {
1002990
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
1003991
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
1004-
_ => return self.unify_and(a, b, identity),
992+
_ => return self.unify(a, b),
1005993
};
1006994
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
1007995

@@ -1011,16 +999,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1011999
// representation, we still register an Adjust::DerefRef so that
10121000
// regionck knows that the region for `a` must be valid here.
10131001
if is_ref {
1014-
self.unify_and(a_raw, b, |target| {
1015-
vec![
1016-
Adjustment { kind: Adjust::Deref(None), target: mt_a.ty },
1017-
Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target },
1018-
]
1019-
})
1002+
self.unify_and(
1003+
a_raw,
1004+
b,
1005+
[Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
1006+
Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
1007+
)
10201008
} else if mt_a.mutbl != mutbl_b {
1021-
self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
1009+
self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer))
10221010
} else {
1023-
self.unify_and(a_raw, b, identity)
1011+
self.unify(a_raw, b)
10241012
}
10251013
}
10261014
}
@@ -1118,9 +1106,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11181106
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
11191107
// We don't ever need two-phase here since we throw out the result of the coercion.
11201108
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
1121-
coerce
1122-
.autoderef(DUMMY_SP, expr_ty)
1123-
.find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
1109+
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
1110+
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
1111+
})
11241112
}
11251113

11261114
/// Given a type, this function will calculate and return the type given

0 commit comments

Comments
 (0)