Repository: rust-lang/rust
File: compiler/rustc_hir_analysis/src/collect.rs (Rust)

Code before:
                    rustc_errors::pluralize!(infer_replacements.len()),
                ),
                infer_replacements,
                Applicability::MachineApplicable,
            );
        }

        diag.emit()
    }
}

impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn dcx(&self) -> DiagCtxtHandle<'_> {
        self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
    }

    fn item_def_id(&self) -> LocalDefId {
        self.item_def_id
    }

    fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
        if let RegionInferReason::ObjectLifetimeDefault = reason {
            let e = struct_span_code_err!(
                self.dcx(),
                span,
                E0228,
                "the lifetime bound for this object type cannot be deduced \
                from context; please supply an explicit bound"
            )
            .emit();
            ty::Region::new_error(self.tcx(), e)
        } else {
            // This indicates an illegal lifetime in a non-assoc-trait position
            ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
        }
    }

    fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
        if !self.tcx.dcx().has_stashed_diagnostic(span, StashKey::ItemNoType) {
            self.report_placeholder_type_error(vec![span], vec![]);
        }
        Ty::new_error_with_message(self.tcx(), span, "bad placeholder type")
    }

    fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
        self.report_placeholder_type_error(vec![span], vec![]);
        ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant")

Review comment (refactor):
I've decided against fixing these ~minor issues in this PR because it's a rabbit hole I didn't want to pursue at the moment:

Most diagnostics in the compiler that suggest adding `+ /* bound */` to a type don't consider both last cases mentioned in the FIXME above (and I bet *none* properly account for trailing pluses[^1]). E.g., `suggest_new_region_bound` ([see FIXME](https://github.com/rust-lang/rust/blob/035b01b794602d5861daa43ac792f372f8981ed7/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs#L147)).

We do have some helpers in place for cases like this like [`hir::Generics::bounds_span_for_suggestions`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Generics.html#method.bounds_span_for_suggestions) but it's not general enough (e.g., I can't use it here) & it doesn't account for everything (like raw pointers).

I hope this paints a clear enough picture. I'd rather fix a bunch of these diagnostic suggestions *at once* in a separate future PR by providing better HIR helpers for these cases. I'm already tracking this in my internal issue tracker (and I might upstream this issue to r-l/r if I won't get to write a PR soon-ish). From a technical standpoint, it shouldn't be hard at all, you just need to check the parent & the child of the HIR type. I just really want to avoid duplicating code for this.

[^1]: Since trailing pluses aren't represented in the AST, HIR etc. and you can't just trim & `contains('+')`-check the relevant part of the source text as obtained via `source_map()` since it wouldn't account for source code comments; you'd actually need to re-lex the snippet (which is overkill for such a niche issue)

Code after:
                infer_replacements,
                Applicability::MachineApplicable,
            );
        }

        diag.emit()
    }
}

impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.tcx
    }

    fn dcx(&self) -> DiagCtxtHandle<'_> {
        self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
    }

    fn item_def_id(&self) -> LocalDefId {
        self.item_def_id
    }

    fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> {
        if let RegionInferReason::ObjectLifetimeDefault(sugg_sp) = reason {
            // FIXME: Account for trailing plus `dyn Trait+`, the need of parens in
            //        `*const dyn Trait` and `Fn() -> *const dyn Trait`.
            let guar = self
                .dcx()
                .struct_span_err(
                    span,
                    "cannot deduce the lifetime bound for this trait object type from context",
                )
                .with_code(E0228)
                .with_span_suggestion_verbose(
                    sugg_sp,
                    "please supply an explicit bound",
                    " + /* 'a */",
                    Applicability::HasPlaceholders,
                )
                .emit();
            ty::Region::new_error(self.tcx(), guar)
        } else {
            // This indicates an illegal lifetime in a non-assoc-trait position
            ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature")
        }
    }

    fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
        if !self.tcx.dcx().has_stashed_diagnostic(span, StashKey::ItemNoType) {
            self.report_placeholder_type_error(vec![span], vec![]);
        }