Skip to content

Commit 7d23487

Browse files
committed
move old solver coercion code to separate function
1 parent 2b0b99c commit 7d23487

File tree

1 file changed

+125
-107
lines changed

1 file changed

+125
-107
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 125 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -660,125 +660,143 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
660660
return Err(TypeError::Mismatch);
661661
}
662662
} else {
663-
let mut selcx = traits::SelectionContext::new(self);
664-
// Use a FIFO queue for this custom fulfillment procedure.
665-
//
666-
// A Vec (or SmallVec) is not a natural choice for a queue. However,
667-
// this code path is hot, and this queue usually has a max length of 1
668-
// and almost never more than 3. By using a SmallVec we avoid an
669-
// allocation, at the (very small) cost of (occasionally) having to
670-
// shift subsequent elements down when removing the front element.
671-
let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation];
672-
673-
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
674-
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
675-
// inference might unify those two inner type variables later.
676-
let traits = [coerce_unsized_did, unsize_did];
677-
while !queue.is_empty() {
678-
let obligation = queue.remove(0);
679-
let trait_pred = match obligation.predicate.kind().no_bound_vars() {
680-
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)))
681-
if traits.contains(&trait_pred.def_id()) =>
682-
{
683-
self.resolve_vars_if_possible(trait_pred)
684-
}
685-
// Eagerly process alias-relate obligations in new trait solver,
686-
// since these can be emitted in the process of solving trait goals,
687-
// but we need to constrain vars before processing goals mentioning
688-
// them.
689-
Some(ty::PredicateKind::AliasRelate(..)) => {
690-
let ocx = ObligationCtxt::new(self);
691-
ocx.register_obligation(obligation);
692-
if !ocx.try_evaluate_obligations().is_empty() {
693-
return Err(TypeError::Mismatch);
694-
}
695-
coercion.obligations.extend(ocx.into_pending_obligations());
696-
continue;
697-
}
698-
_ => {
699-
coercion.obligations.push(obligation);
700-
continue;
663+
self.coerece_unsized_old_solver(
664+
obligation,
665+
&mut coercion,
666+
coerce_unsized_did,
667+
unsize_did,
668+
)?;
669+
}
670+
671+
Ok(coercion)
672+
}
673+
674+
fn coerece_unsized_old_solver(
675+
&self,
676+
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
677+
coercion: &mut InferOk<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>,
678+
coerce_unsized_did: DefId,
679+
unsize_did: DefId,
680+
) -> Result<(), TypeError<'tcx>> {
681+
let mut selcx = traits::SelectionContext::new(self);
682+
// Use a FIFO queue for this custom fulfillment procedure.
683+
//
684+
// A Vec (or SmallVec) is not a natural choice for a queue. However,
685+
// this code path is hot, and this queue usually has a max length of 1
686+
// and almost never more than 3. By using a SmallVec we avoid an
687+
// allocation, at the (very small) cost of (occasionally) having to
688+
// shift subsequent elements down when removing the front element.
689+
let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation];
690+
691+
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
692+
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
693+
// inference might unify those two inner type variables later.
694+
let traits = [coerce_unsized_did, unsize_did];
695+
while !queue.is_empty() {
696+
let obligation = queue.remove(0);
697+
let trait_pred = match obligation.predicate.kind().no_bound_vars() {
698+
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)))
699+
if traits.contains(&trait_pred.def_id()) =>
700+
{
701+
self.resolve_vars_if_possible(trait_pred)
702+
}
703+
// Eagerly process alias-relate obligations in new trait solver,
704+
// since these can be emitted in the process of solving trait goals,
705+
// but we need to constrain vars before processing goals mentioning
706+
// them.
707+
Some(ty::PredicateKind::AliasRelate(..)) => {
708+
let ocx = ObligationCtxt::new(self);
709+
ocx.register_obligation(obligation);
710+
if !ocx.try_evaluate_obligations().is_empty() {
711+
return Err(TypeError::Mismatch);
701712
}
702-
};
703-
debug!("coerce_unsized resolve step: {:?}", trait_pred);
704-
match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) {
705-
// Uncertain or unimplemented.
706-
Ok(None) => {
707-
if trait_pred.def_id() == unsize_did {
708-
let self_ty = trait_pred.self_ty();
709-
let unsize_ty = trait_pred.trait_ref.args[1].expect_ty();
710-
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
711-
match (self_ty.kind(), unsize_ty.kind()) {
712-
(&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
713-
if self.type_var_is_sized(v) =>
714-
{
715-
debug!("coerce_unsized: have sized infer {:?}", v);
716-
coercion.obligations.push(obligation);
717-
// `$0: Unsize<dyn Trait>` where we know that `$0: Sized`, try going
718-
// for unsizing.
719-
}
720-
_ => {
721-
// Some other case for `$0: Unsize<Something>`. Note that we
722-
// hit this case even if `Something` is a sized type, so just
723-
// don't do the coercion.
724-
debug!("coerce_unsized: ambiguous unsize");
725-
return Err(TypeError::Mismatch);
726-
}
713+
coercion.obligations.extend(ocx.into_pending_obligations());
714+
continue;
715+
}
716+
_ => {
717+
coercion.obligations.push(obligation);
718+
continue;
719+
}
720+
};
721+
debug!("coerce_unsized resolve step: {:?}", trait_pred);
722+
match selcx.select(&obligation.with(selcx.tcx(), trait_pred)) {
723+
// Uncertain or unimplemented.
724+
Ok(None) => {
725+
if trait_pred.def_id() == unsize_did {
726+
let self_ty = trait_pred.self_ty();
727+
let unsize_ty = trait_pred.trait_ref.args[1].expect_ty();
728+
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);
729+
match (self_ty.kind(), unsize_ty.kind()) {
730+
(&ty::Infer(ty::TyVar(v)), ty::Dynamic(..))
731+
if self.type_var_is_sized(v) =>
732+
{
733+
debug!("coerce_unsized: have sized infer {:?}", v);
734+
coercion.obligations.push(obligation);
735+
// `$0: Unsize<dyn Trait>` where we know that `$0: Sized`, try going
736+
// for unsizing.
737+
}
738+
_ => {
739+
// Some other case for `$0: Unsize<Something>`. Note that we
740+
// hit this case even if `Something` is a sized type, so just
741+
// don't do the coercion.
742+
debug!("coerce_unsized: ambiguous unsize");
743+
return Err(TypeError::Mismatch);
727744
}
728-
} else {
729-
debug!("coerce_unsized: early return - ambiguous");
730-
return Err(TypeError::Mismatch);
731745
}
732-
}
733-
Err(SelectionError::Unimplemented) => {
734-
debug!("coerce_unsized: early return - can't prove obligation");
746+
} else {
747+
debug!("coerce_unsized: early return - ambiguous");
735748
return Err(TypeError::Mismatch);
736749
}
750+
}
751+
Err(SelectionError::Unimplemented) => {
752+
debug!("coerce_unsized: early return - can't prove obligation");
753+
return Err(TypeError::Mismatch);
754+
}
737755

738-
Err(SelectionError::TraitDynIncompatible(_)) => {
739-
// Dyn compatibility errors in coercion will *always* be due to the
740-
// fact that the RHS of the coercion is a non-dyn compatible `dyn Trait`
741-
// writen in source somewhere (otherwise we will never have lowered
742-
// the dyn trait from HIR to middle).
743-
//
744-
// There's no reason to emit yet another dyn compatibility error,
745-
// especially since the span will differ slightly and thus not be
746-
// deduplicated at all!
747-
self.fcx.set_tainted_by_errors(self.fcx.dcx().span_delayed_bug(
748-
self.cause.span,
749-
"dyn compatibility during coercion",
750-
));
751-
}
752-
Err(err) => {
753-
let guar = self.err_ctxt().report_selection_error(
754-
obligation.clone(),
755-
&obligation,
756-
&err,
757-
);
756+
Err(SelectionError::TraitDynIncompatible(_)) => {
757+
// Dyn compatibility errors in coercion will *always* be due to the
758+
// fact that the RHS of the coercion is a non-dyn compatible `dyn Trait`
759+
// written in source somewhere (otherwise we will never have lowered
760+
// the dyn trait from HIR to middle).
761+
//
762+
// There's no reason to emit yet another dyn compatibility error,
763+
// especially since the span will differ slightly and thus not be
764+
// deduplicated at all!
765+
self.fcx.set_tainted_by_errors(
766+
self.fcx
767+
.dcx()
768+
.span_delayed_bug(self.cause.span, "dyn compatibility during coercion"),
769+
);
770+
}
771+
Err(err) => {
772+
let guar = self.err_ctxt().report_selection_error(
773+
obligation.clone(),
774+
&obligation,
775+
&err,
776+
);
777+
self.fcx.set_tainted_by_errors(guar);
778+
// Treat this like an obligation and follow through
779+
// with the unsizing - the lack of a coercion should
780+
// be silent, as it causes a type mismatch later.
781+
}
782+
Ok(Some(ImplSource::UserDefined(impl_source))) => {
783+
queue.extend(impl_source.nested);
784+
// Certain incoherent `CoerceUnsized` implementations may cause ICEs,
785+
// so check the impl's validity. Taint the body so that we don't try
786+
// to evaluate these invalid coercions in CTFE. We only need to do this
787+
// for local impls, since upstream impls should be valid.
788+
if impl_source.impl_def_id.is_local()
789+
&& let Err(guar) =
790+
self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id)
791+
{
758792
self.fcx.set_tainted_by_errors(guar);
759-
// Treat this like an obligation and follow through
760-
// with the unsizing - the lack of a coercion should
761-
// be silent, as it causes a type mismatch later.
762793
}
763-
Ok(Some(ImplSource::UserDefined(impl_source))) => {
764-
queue.extend(impl_source.nested);
765-
// Certain incoherent `CoerceUnsized` implementations may cause ICEs,
766-
// so check the impl's validity. Taint the body so that we don't try
767-
// to evaluate these invalid coercions in CTFE. We only need to do this
768-
// for local impls, since upstream impls should be valid.
769-
if impl_source.impl_def_id.is_local()
770-
&& let Err(guar) =
771-
self.tcx.ensure_ok().coerce_unsized_info(impl_source.impl_def_id)
772-
{
773-
self.fcx.set_tainted_by_errors(guar);
774-
}
775-
}
776-
Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
777794
}
795+
Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()),
778796
}
779797
}
780798

781-
Ok(coercion)
799+
Ok(())
782800
}
783801

784802
/// Applies reborrowing for `Pin`

0 commit comments

Comments
 (0)