Skip to content

Commit 8c86773

Browse files
Make fast-path for implied wf lint better
1 parent c40eded commit 8c86773

File tree

1 file changed

+92
-71
lines changed

1 file changed

+92
-71
lines changed

Diff for: compiler/rustc_hir_analysis/src/check/compare_method.rs

+92-71
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,14 @@ pub(crate) fn compare_impl_method<'tcx>(
7171
return;
7272
}
7373

74-
if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
75-
{
74+
if let Err(_) = compare_predicate_entailment(
75+
tcx,
76+
impl_m,
77+
impl_m_span,
78+
trait_m,
79+
impl_trait_ref,
80+
CheckImpliedWfMode::Check,
81+
) {
7682
return;
7783
}
7884
}
@@ -150,6 +156,7 @@ fn compare_predicate_entailment<'tcx>(
150156
impl_m_span: Span,
151157
trait_m: &ty::AssocItem,
152158
impl_trait_ref: ty::TraitRef<'tcx>,
159+
check_implied_wf: CheckImpliedWfMode,
153160
) -> Result<(), ErrorGuaranteed> {
154161
let trait_to_impl_substs = impl_trait_ref.substs;
155162

@@ -304,92 +311,106 @@ fn compare_predicate_entailment<'tcx>(
304311
return Err(emitted);
305312
}
306313

307-
// Check that all obligations are satisfied by the implementation's
308-
// version.
309-
let errors = ocx.select_all_or_error();
310-
if !errors.is_empty() {
311-
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
312-
return Err(reported);
314+
if check_implied_wf == CheckImpliedWfMode::Check {
315+
// We need to check that the impl's args are well-formed given
316+
// the hybrid param-env (impl + trait method where-clauses).
317+
ocx.register_obligation(traits::Obligation::new(
318+
infcx.tcx,
319+
ObligationCause::dummy(),
320+
param_env,
321+
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
322+
));
313323
}
314-
315-
// FIXME(compiler-errors): This can be removed when IMPLIED_BOUNDS_ENTAILMENT
316-
// becomes a hard error.
317-
let lint_infcx = infcx.fork();
318-
319-
// Finally, resolve all regions. This catches wily misuses of
320-
// lifetime parameters.
321-
let outlives_environment = OutlivesEnvironment::with_bounds(
322-
param_env,
323-
Some(infcx),
324-
infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
325-
);
326-
if let Some(guar) = infcx.check_region_obligations_and_report_errors(
327-
impl_m.def_id.expect_local(),
328-
&outlives_environment,
329-
) {
330-
return Err(guar);
331-
}
332-
333-
// FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
334-
// becomes a hard error (i.e. ideally we'd just register a WF obligation above...)
335-
lint_implied_wf_entailment(
336-
impl_m.def_id.expect_local(),
337-
lint_infcx,
338-
param_env,
339-
unnormalized_impl_fty,
340-
wf_tys,
341-
);
342-
343-
Ok(())
344-
}
345-
346-
fn lint_implied_wf_entailment<'tcx>(
347-
impl_m_def_id: LocalDefId,
348-
infcx: InferCtxt<'tcx>,
349-
param_env: ty::ParamEnv<'tcx>,
350-
unnormalized_impl_fty: Ty<'tcx>,
351-
wf_tys: FxIndexSet<Ty<'tcx>>,
352-
) {
353-
let ocx = ObligationCtxt::new(&infcx);
354-
355-
// We need to check that the impl's args are well-formed given
356-
// the hybrid param-env (impl + trait method where-clauses).
357-
ocx.register_obligation(traits::Obligation::new(
358-
infcx.tcx,
359-
ObligationCause::dummy(),
360-
param_env,
361-
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
362-
));
363-
364-
let hir_id = infcx.tcx.hir().local_def_id_to_hir_id(impl_m_def_id);
365-
let lint = || {
324+
let emit_implied_wf_lint = || {
366325
infcx.tcx.struct_span_lint_hir(
367326
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
368-
hir_id,
369-
infcx.tcx.def_span(impl_m_def_id),
327+
impl_m_hir_id,
328+
infcx.tcx.def_span(impl_m.def_id),
370329
"impl method assumes more implied bounds than the corresponding trait method",
371330
|lint| lint,
372331
);
373332
};
374333

334+
// Check that all obligations are satisfied by the implementation's
335+
// version.
375336
let errors = ocx.select_all_or_error();
376337
if !errors.is_empty() {
377-
lint();
338+
match check_implied_wf {
339+
CheckImpliedWfMode::Check => {
340+
return compare_predicate_entailment(
341+
tcx,
342+
impl_m,
343+
impl_m_span,
344+
trait_m,
345+
impl_trait_ref,
346+
CheckImpliedWfMode::Skip,
347+
)
348+
.map(|()| {
349+
// If the skip-mode was successful, emit a lint.
350+
emit_implied_wf_lint();
351+
});
352+
}
353+
CheckImpliedWfMode::Skip => {
354+
let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
355+
return Err(reported);
356+
}
357+
}
378358
}
379359

380-
let outlives_environment = OutlivesEnvironment::with_bounds(
360+
// Finally, resolve all regions. This catches wily misuses of
361+
// lifetime parameters.
362+
let outlives_env = OutlivesEnvironment::with_bounds(
381363
param_env,
382-
Some(&infcx),
383-
infcx.implied_bounds_tys(param_env, hir_id, wf_tys.clone()),
364+
Some(infcx),
365+
infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys.clone()),
384366
);
385367
infcx.process_registered_region_obligations(
386-
outlives_environment.region_bound_pairs(),
387-
param_env,
368+
outlives_env.region_bound_pairs(),
369+
outlives_env.param_env,
388370
);
389-
390-
if !infcx.resolve_regions(&outlives_environment).is_empty() {
391-
lint();
371+
let errors = infcx.resolve_regions(&outlives_env);
372+
if !errors.is_empty() {
373+
// FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT
374+
// becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors`
375+
match check_implied_wf {
376+
CheckImpliedWfMode::Check => {
377+
return compare_predicate_entailment(
378+
tcx,
379+
impl_m,
380+
impl_m_span,
381+
trait_m,
382+
impl_trait_ref,
383+
CheckImpliedWfMode::Skip,
384+
)
385+
.map(|()| {
386+
// If the skip-mode was successful, emit a lint.
387+
emit_implied_wf_lint();
388+
});
389+
}
390+
CheckImpliedWfMode::Skip => {
391+
if infcx.tainted_by_errors().is_none() {
392+
infcx.err_ctxt().report_region_errors(impl_m.def_id.expect_local(), &errors);
393+
}
394+
return Err(tcx
395+
.sess
396+
.delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"));
397+
}
398+
}
392399
}
400+
401+
Ok(())
402+
}
403+
404+
#[derive(Debug, PartialEq, Eq)]
405+
enum CheckImpliedWfMode {
406+
/// Checks implied well-formedness of the impl method. If it fails, we will
407+
/// re-check with `Skip`, and emit a lint if it succeeds.
408+
Check,
409+
/// Skips checking implied well-formedness of the impl method, but will emit
410+
/// a lint if the `compare_predicate_entailment` succeeded. This means that
411+
/// the reason that we had failed earlier during `Check` was due to the impl
412+
/// having stronger requirements than the trait.
413+
Skip,
393414
}
394415

395416
fn compare_asyncness<'tcx>(

0 commit comments

Comments
 (0)