Skip to content

Commit 40110c0

Browse files
committed
Auto merge of #139582 - oli-obk:coercion-cleanups, r=<try>
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 f06e5c1 + 3528a65 commit 40110c0

File tree

1 file changed

+82
-93
lines changed

1 file changed

+82
-93
lines changed

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

+82-93
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,24 @@ 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+
mut adjustments: Vec<Adjustment<'tcx>>,
167+
final_adjustment: Adjust,
168+
) -> CoerceResult<'tcx> {
169+
self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| {
170+
adjustments.push(Adjustment { target: ty, kind: final_adjustment });
171+
success(adjustments, ty, obligations)
172+
})
171173
}
172174

173175
#[instrument(skip(self))]
@@ -180,18 +182,22 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
180182
// Coercing from `!` to any type is allowed:
181183
if a.is_never() {
182184
if self.coerce_never {
183-
return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
185+
return success(
186+
vec![Adjustment { kind: Adjust::NeverToAny, target: b }],
187+
b,
188+
PredicateObligations::new(),
189+
);
184190
} else {
185191
// Otherwise the only coercion we can do is unification.
186-
return self.unify_and(a, b, identity);
192+
return self.unify(a, b);
187193
}
188194
}
189195

190196
// Coercing *from* an unresolved inference variable means that
191197
// we have no information about the source type. This will always
192198
// ultimately fall back to some form of subtyping.
193199
if a.is_ty_var() {
194-
return self.coerce_from_inference_variable(a, b, identity);
200+
return self.coerce_from_inference_variable(a, b);
195201
}
196202

197203
// Consider coercing the subtype to a DST
@@ -247,7 +253,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
247253
ty::FnPtr(a_sig_tys, a_hdr) => {
248254
// We permit coercion of fn pointers to drop the
249255
// unsafe qualifier.
250-
self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b)
256+
self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b)
251257
}
252258
ty::Closure(closure_def_id_a, args_a) => {
253259
// Non-capturing closures are coercible to
@@ -257,20 +263,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
257263
}
258264
_ => {
259265
// Otherwise, just use unification rules.
260-
self.unify_and(a, b, identity)
266+
self.unify(a, b)
261267
}
262268
}
263269
}
264270

265271
/// Coercing *from* an inference variable. In this case, we have no information
266272
/// about the source type, so we can't really do a true coercion and we always
267273
/// 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> {
274+
fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
274275
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
275276
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
276277
assert!(self.shallow_resolve(b) == b);
@@ -298,12 +299,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
298299
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
299300
target_ty, obligations
300301
);
301-
let adjustments = make_adjustments(target_ty);
302-
InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
302+
success(vec![], target_ty, obligations)
303303
} else {
304304
// One unresolved type variable: just apply subtyping, we may be able
305305
// to do something useful.
306-
self.unify_and(a, b, make_adjustments)
306+
self.unify(a, b)
307307
}
308308
}
309309

@@ -331,7 +331,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
331331
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
332332
(r_a, mt_a)
333333
}
334-
_ => return self.unify_and(a, b, identity),
334+
_ => return self.unify(a, b),
335335
};
336336

337337
let span = self.cause.span;
@@ -437,7 +437,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
437437
referent_ty,
438438
mutbl_b, // [1] above
439439
);
440-
match self.unify(derefd_ty_a, b) {
440+
match self.unify_raw(derefd_ty_a, b) {
441441
Ok(ok) => {
442442
found = Some(ok);
443443
break;
@@ -579,13 +579,15 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
579579
// We only have the latter, so we use an inference variable
580580
// for the former and let type inference do the rest.
581581
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 };
582+
let mut coercion = self.unify_and(
583+
coerce_target,
584+
target,
584585
match reborrow {
585-
None => vec![unsize],
586-
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
587-
}
588-
})?;
586+
None => vec![],
587+
Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone()],
588+
},
589+
Adjust::Pointer(PointerCoercion::Unsize),
590+
)?;
589591

590592
let mut selcx = traits::SelectionContext::new(self);
591593

@@ -708,7 +710,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
708710
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
709711
&& a_data.principal_def_id() == b_data.principal_def_id()
710712
{
711-
return self.unify_and(a, b, |_| vec![]);
713+
return self.unify(a, b);
712714
}
713715

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

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

816-
fn coerce_from_safe_fn<F, G>(
816+
fn coerce_from_safe_fn(
817817
&self,
818-
a: Ty<'tcx>,
819818
fn_ty_a: ty::PolyFnSig<'tcx>,
820819
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-
{
820+
adjustment: Option<Adjust>,
821+
) -> CoerceResult<'tcx> {
828822
self.commit_if_ok(|snapshot| {
829823
let outer_universe = self.infcx.universe();
830824

@@ -833,9 +827,24 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
833827
&& hdr_b.safety.is_unsafe()
834828
{
835829
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
836-
self.unify_and(unsafe_a, b, to_unsafe)
830+
let adjustments = match adjustment {
831+
Some(kind) => {
832+
vec![Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }]
833+
}
834+
None => vec![],
835+
};
836+
self.unify_and(
837+
unsafe_a,
838+
b,
839+
adjustments,
840+
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
841+
)
837842
} else {
838-
self.unify_and(a, b, normal)
843+
let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
844+
match adjustment {
845+
Some(adjust) => self.unify_and(a, b, vec![], adjust),
846+
None => self.unify(a, b),
847+
}
839848
};
840849

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

853862
fn coerce_from_fn_pointer(
854863
&self,
855-
a: Ty<'tcx>,
856864
fn_ty_a: ty::PolyFnSig<'tcx>,
857865
b: Ty<'tcx>,
858866
) -> CoerceResult<'tcx> {
@@ -861,15 +869,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
861869
//!
862870
863871
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-
)
872+
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
873+
874+
self.coerce_from_safe_fn(fn_ty_a, b, None)
873875
}
874876

875877
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
@@ -916,30 +918,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
916918
self.at(&self.cause, self.param_env).normalize(a_sig);
917919
obligations.extend(o1);
918920

919-
let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
920921
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
921-
a_fn_pointer,
922922
a_sig,
923923
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)),
924+
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
937925
)?;
938926

939927
obligations.extend(o2);
940928
Ok(InferOk { value, obligations })
941929
}
942-
_ => self.unify_and(a, b, identity),
930+
_ => self.unify(a, b),
943931
}
944932
}
945933

@@ -983,10 +971,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
983971
self.unify_and(
984972
pointer_ty,
985973
b,
986-
simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
974+
vec![],
975+
Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
987976
)
988977
}
989-
_ => self.unify_and(a, b, identity),
978+
_ => self.unify(a, b),
990979
}
991980
}
992981

@@ -1001,7 +990,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
1001990
let (is_ref, mt_a) = match *a.kind() {
1002991
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
1003992
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
1004-
_ => return self.unify_and(a, b, identity),
993+
_ => return self.unify(a, b),
1005994
};
1006995
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
1007996

@@ -1011,16 +1000,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
10111000
// representation, we still register an Adjust::DerefRef so that
10121001
// regionck knows that the region for `a` must be valid here.
10131002
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-
})
1003+
self.unify_and(
1004+
a_raw,
1005+
b,
1006+
vec![Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
1007+
Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
1008+
)
10201009
} else if mt_a.mutbl != mutbl_b {
1021-
self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
1010+
self.unify_and(a_raw, b, vec![], Adjust::Pointer(PointerCoercion::MutToConstPointer))
10221011
} else {
1023-
self.unify_and(a_raw, b, identity)
1012+
self.unify(a_raw, b)
10241013
}
10251014
}
10261015
}
@@ -1118,9 +1107,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11181107
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
11191108
// We don't ever need two-phase here since we throw out the result of the coercion.
11201109
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))
1110+
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
1111+
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
1112+
})
11241113
}
11251114

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

0 commit comments

Comments
 (0)