Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit dc442c5

Browse files
Make fast-path for implied wf lint better
1 parent 70d081e commit dc442c5

File tree

1 file changed

+92
-71
lines changed

1 file changed

+92
-71
lines changed

‎compiler/rustc_hir_analysis/src/check/compare_method.rs‎

Lines changed: 92 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,14 @@ pub(crate) fn compare_impl_method<'tcx>(
6767
return;
6868
}
6969

70-
if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
71-
{
70+
if let Err(_) = compare_predicate_entailment(
71+
tcx,
72+
impl_m,
73+
impl_m_span,
74+
trait_m,
75+
impl_trait_ref,
76+
CheckImpliedWfMode::Check,
77+
) {
7278
return;
7379
}
7480
}
@@ -146,6 +152,7 @@ fn compare_predicate_entailment<'tcx>(
146152
impl_m_span: Span,
147153
trait_m: &ty::AssocItem,
148154
impl_trait_ref: ty::TraitRef<'tcx>,
155+
check_implied_wf: CheckImpliedWfMode,
149156
) -> Result<(), ErrorGuaranteed> {
150157
let trait_to_impl_substs = impl_trait_ref.substs;
151158

@@ -300,92 +307,106 @@ fn compare_predicate_entailment<'tcx>(
300307
return Err(emitted);
301308
}
302309

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

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

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

391412
#[instrument(skip(tcx), level = "debug", ret)]

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /