Repository: rust-lang/rust
File: compiler/rustc_hir_typeck/src/coercion.rs (Rust)

Code before:
                // FIXME: structurally normalize?
                if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize)
                    && let ty::Dynamic(..) = pred.skip_binder().trait_ref.args.type_at(1).kind()
                    && let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind()
                    && self.fcx.type_var_is_sized(vid)
                {
                    // We get here when trying to unsize a type variable to a `dyn Trait`,
                    // knowing that that variable is sized. Unsizing definitely has to happen in that case.
                    // If the variable weren't sized, we may not need an unsizing coercion.
                    // In general, we don't want to add coercions too eagerly since it makes error messages much worse.
                    ControlFlow::Continue(())
                } else if let Some(cand) = goal.unique_applicable_candidate()
                    && cand.shallow_certainty() == Certainty::Yes
                {
                    cand.visit_nested_no_probe(self)
                } else {
                    ControlFlow::Break(())
                }
            }
        }
    }

    fn on_recursion_limit(&mut self) -> Self::Result {
        // This prevents accidentally committing unfulfilled unsized coercions while trying to find
        // the error source for diagnostics.
        // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/266.
        ControlFlow::Break(())
    }
}


Review comment (suggestion):
i think this breaks the following snippet if we encounter it in the `Certainty::Maybe` recursion

```rust
struct W<T: ?Sized>(T);
type Four<T: ?Sized> = W<W<W<W<T>>>>;
type Sixteen<T: ?Sized> = Four<Four<Four<Four<T>>>>;
fn ret<T>(x: T) -> Sixteen<T> {
    todo!();
}
fn please_coerce() {
    let mut y = Default::default();
    let x = ret(y);
    let _: &Sixteen<dyn Send> = &x;
    y = 1u32;
}
``` 

Code after:
                } else {
                    ControlFlow::Break(())
                }
            }
            Ok(Certainty::Maybe { .. }) => {
                // FIXME: structurally normalize?
                if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize)
                    && let ty::Dynamic(..) = pred.skip_binder().trait_ref.args.type_at(1).kind()
                    && let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind()
                    && self.fcx.type_var_is_sized(vid)
                {
                    // We get here when trying to unsize a type variable to a `dyn Trait`,
                    // knowing that that variable is sized. Unsizing definitely has to happen in that case.
                    // If the variable weren't sized, we may not need an unsizing coercion.
                    // In general, we don't want to add coercions too eagerly since it makes error messages much worse.
                    ControlFlow::Continue(())
                } else if let Some(cand) = goal.unique_applicable_candidate()
                    && cand.shallow_certainty() == Certainty::Yes
                {
                    cand.visit_nested_no_probe(self)
                } else {
                    ControlFlow::Break(())
                }
            }
        }
    }

    fn on_recursion_limit(&mut self) -> Self::Result {
        if self.errored {
            // This prevents accidentally committing unfulfilled unsized coercions while trying to
            // find the error source for diagnostics.
            // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/266.
            ControlFlow::Break(())
        } else {
            ControlFlow::Continue(())
        }
    }
}