Skip to content

Commit 269623e

Browse files
committed
Auto merge of rust-lang#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 6813f95 + 673012f commit 269623e

File tree

1 file changed

+93
-93
lines changed

1 file changed

+93
-93
lines changed

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

+93-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,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,18 @@ 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],
588+
589+
let mut coercion = match reborrow {
590+
None => {
591+
self.unify_and(coerce_target, target, [], Adjust::Pointer(PointerCoercion::Unsize))?
587592
}
588-
})?;
593+
Some((ref deref, ref autoref)) => self.unify_and(
594+
coerce_target,
595+
target,
596+
[deref.clone(), autoref.clone()],
597+
Adjust::Pointer(PointerCoercion::Unsize),
598+
)?,
599+
};
589600

590601
let mut selcx = traits::SelectionContext::new(self);
591602

@@ -708,7 +719,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
708719
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
709720
&& a_data.principal_def_id() == b_data.principal_def_id()
710721
{
711-
return self.unify_and(a, b, |_| vec![]);
722+
return self.unify(a, b);
712723
}
713724

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

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

816-
fn coerce_from_safe_fn<F, G>(
825+
fn coerce_from_safe_fn(
817826
&self,
818-
a: Ty<'tcx>,
819827
fn_ty_a: ty::PolyFnSig<'tcx>,
820828
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-
{
829+
adjustment: Option<Adjust>,
830+
) -> CoerceResult<'tcx> {
828831
self.commit_if_ok(|snapshot| {
829832
let outer_universe = self.infcx.universe();
830833

@@ -833,9 +836,26 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
833836
&& hdr_b.safety.is_unsafe()
834837
{
835838
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
836-
self.unify_and(unsafe_a, b, to_unsafe)
839+
match adjustment {
840+
Some(kind) => self.unify_and(
841+
unsafe_a,
842+
b,
843+
[Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }],
844+
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
845+
),
846+
None => self.unify_and(
847+
unsafe_a,
848+
b,
849+
[],
850+
Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
851+
),
852+
}
837853
} else {
838-
self.unify_and(a, b, normal)
854+
let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
855+
match adjustment {
856+
Some(adjust) => self.unify_and(a, b, [], adjust),
857+
None => self.unify(a, b),
858+
}
839859
};
840860

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

853873
fn coerce_from_fn_pointer(
854874
&self,
855-
a: Ty<'tcx>,
856875
fn_ty_a: ty::PolyFnSig<'tcx>,
857876
b: Ty<'tcx>,
858877
) -> CoerceResult<'tcx> {
@@ -861,15 +880,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
861880
//!
862881
863882
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-
)
883+
debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
884+
885+
self.coerce_from_safe_fn(fn_ty_a, b, None)
873886
}
874887

875888
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
@@ -916,30 +929,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
916929
self.at(&self.cause, self.param_env).normalize(a_sig);
917930
obligations.extend(o1);
918931

919-
let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
920932
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
921-
a_fn_pointer,
922933
a_sig,
923934
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)),
935+
Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
937936
)?;
938937

939938
obligations.extend(o2);
940939
Ok(InferOk { value, obligations })
941940
}
942-
_ => self.unify_and(a, b, identity),
941+
_ => self.unify(a, b),
943942
}
944943
}
945944

@@ -983,10 +982,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
983982
self.unify_and(
984983
pointer_ty,
985984
b,
986-
simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
985+
[],
986+
Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
987987
)
988988
}
989-
_ => self.unify_and(a, b, identity),
989+
_ => self.unify(a, b),
990990
}
991991
}
992992

@@ -1001,7 +1001,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
10011001
let (is_ref, mt_a) = match *a.kind() {
10021002
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
10031003
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
1004-
_ => return self.unify_and(a, b, identity),
1004+
_ => return self.unify(a, b),
10051005
};
10061006
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
10071007

@@ -1011,16 +1011,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
10111011
// representation, we still register an Adjust::DerefRef so that
10121012
// regionck knows that the region for `a` must be valid here.
10131013
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-
})
1014+
self.unify_and(
1015+
a_raw,
1016+
b,
1017+
[Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
1018+
Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
1019+
)
10201020
} else if mt_a.mutbl != mutbl_b {
1021-
self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
1021+
self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer))
10221022
} else {
1023-
self.unify_and(a_raw, b, identity)
1023+
self.unify(a_raw, b)
10241024
}
10251025
}
10261026
}
@@ -1118,9 +1118,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11181118
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
11191119
// We don't ever need two-phase here since we throw out the result of the coercion.
11201120
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))
1121+
coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
1122+
self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
1123+
})
11241124
}
11251125

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

0 commit comments

Comments
 (0)