Skip to content

Commit 35816ff

Browse files
authoredNov 12, 2022
Rollup merge of #104214 - Nilstrieb:returns_impl_Ice, r=compiler-errors
Emit error in `collecting_trait_impl_trait_tys` on mismatched signatures Previously, a `delay_span_bug` was isssued, failing normalization. This create a `TyKind::Error` in the signature, which caused `compare_predicate_entailment` to swallow its signature mismatch error, causing ICEs because no error was emitted. fixes #104183 r? ``@compiler-errors``
2 parents 662df1e + 07a47e0 commit 35816ff

File tree

3 files changed

+277
-105
lines changed

3 files changed

+277
-105
lines changed
 

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

+142-105
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ use rustc_hir::intravisit;
99
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
1010
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1111
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
12-
use rustc_infer::infer::{self, TyCtxtInferExt};
12+
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
1313
use rustc_infer::traits::util;
1414
use rustc_middle::ty::error::{ExpectedFound, TypeError};
1515
use rustc_middle::ty::util::ExplicitSelf;
16-
use rustc_middle::ty::InternalSubsts;
1716
use rustc_middle::ty::{
18-
self, AssocItem, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
17+
self, AssocItem, DefIdTree, TraitRef, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable,
18+
TypeVisitable,
1919
};
20+
use rustc_middle::ty::{FnSig, InternalSubsts};
2021
use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
2122
use rustc_span::Span;
2223
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@@ -303,102 +304,19 @@ fn compare_predicate_entailment<'tcx>(
303304
}
304305

305306
if let Err(terr) = result {
306-
debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
307+
debug!(?terr, "sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
307308

308-
let (impl_err_span, trait_err_span) =
309-
extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
310-
311-
cause.span = impl_err_span;
312-
313-
let mut diag = struct_span_err!(
314-
tcx.sess,
315-
cause.span(),
316-
E0053,
317-
"method `{}` has an incompatible type for trait",
318-
trait_m.name
319-
);
320-
match &terr {
321-
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
322-
if trait_m.fn_has_self_parameter =>
323-
{
324-
let ty = trait_sig.inputs()[0];
325-
let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
326-
ExplicitSelf::ByValue => "self".to_owned(),
327-
ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
328-
ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
329-
_ => format!("self: {ty}"),
330-
};
331-
332-
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
333-
// span points only at the type `Box<Self`>, but we want to cover the whole
334-
// argument pattern and type.
335-
let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
336-
ImplItemKind::Fn(ref sig, body) => tcx
337-
.hir()
338-
.body_param_names(body)
339-
.zip(sig.decl.inputs.iter())
340-
.map(|(param, ty)| param.span.to(ty.span))
341-
.next()
342-
.unwrap_or(impl_err_span),
343-
_ => bug!("{:?} is not a method", impl_m),
344-
};
345-
346-
diag.span_suggestion(
347-
span,
348-
"change the self-receiver type to match the trait",
349-
sugg,
350-
Applicability::MachineApplicable,
351-
);
352-
}
353-
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
354-
if trait_sig.inputs().len() == *i {
355-
// Suggestion to change output type. We do not suggest in `async` functions
356-
// to avoid complex logic or incorrect output.
357-
match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
358-
ImplItemKind::Fn(ref sig, _)
359-
if sig.header.asyncness == hir::IsAsync::NotAsync =>
360-
{
361-
let msg = "change the output type to match the trait";
362-
let ap = Applicability::MachineApplicable;
363-
match sig.decl.output {
364-
hir::FnRetTy::DefaultReturn(sp) => {
365-
let sugg = format!("-> {} ", trait_sig.output());
366-
diag.span_suggestion_verbose(sp, msg, sugg, ap);
367-
}
368-
hir::FnRetTy::Return(hir_ty) => {
369-
let sugg = trait_sig.output();
370-
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
371-
}
372-
};
373-
}
374-
_ => {}
375-
};
376-
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
377-
diag.span_suggestion(
378-
impl_err_span,
379-
"change the parameter type to match the trait",
380-
trait_ty,
381-
Applicability::MachineApplicable,
382-
);
383-
}
384-
}
385-
_ => {}
386-
}
387-
388-
infcx.err_ctxt().note_type_err(
389-
&mut diag,
390-
&cause,
391-
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
392-
Some(infer::ValuePairs::Terms(ExpectedFound {
393-
expected: trait_fty.into(),
394-
found: impl_fty.into(),
395-
})),
309+
let emitted = report_trait_method_mismatch(
310+
tcx,
311+
&mut cause,
312+
&infcx,
396313
terr,
397-
false,
398-
false,
314+
(trait_m, trait_fty),
315+
(impl_m, impl_fty),
316+
&trait_sig,
317+
&impl_trait_ref,
399318
);
400-
401-
return Err(diag.emit());
319+
return Err(emitted);
402320
}
403321

404322
// Check that all obligations are satisfied by the implementation's
@@ -424,6 +342,7 @@ fn compare_predicate_entailment<'tcx>(
424342
Ok(())
425343
}
426344

345+
#[instrument(skip(tcx), level = "debug", ret)]
427346
pub fn collect_trait_impl_trait_tys<'tcx>(
428347
tcx: TyCtxt<'tcx>,
429348
def_id: DefId,
@@ -437,7 +356,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
437356

438357
let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
439358
let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
440-
let cause = ObligationCause::new(
359+
let mut cause = ObligationCause::new(
441360
return_span,
442361
impl_m_hir_id,
443362
ObligationCauseCode::CompareImplItemObligation {
@@ -514,23 +433,35 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
514433
}
515434
}
516435

436+
debug!(?trait_sig, ?impl_sig, "equating function signatures");
437+
438+
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
439+
let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
440+
517441
// Unify the whole function signature. We need to do this to fully infer
518442
// the lifetimes of the return type, but do this after unifying just the
519443
// return types, since we want to avoid duplicating errors from
520444
// `compare_predicate_entailment`.
521-
match infcx
522-
.at(&cause, param_env)
523-
.eq(tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)), tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig)))
524-
{
445+
match infcx.at(&cause, param_env).eq(trait_fty, impl_fty) {
525446
Ok(infer::InferOk { value: (), obligations }) => {
526447
ocx.register_obligations(obligations);
527448
}
528449
Err(terr) => {
529-
let guar = tcx.sess.delay_span_bug(
530-
return_span,
531-
format!("could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}"),
450+
// This function gets called during `compare_predicate_entailment` when normalizing a
451+
// signature that contains RPITIT. When the method signatures don't match, we have to
452+
// emit an error now because `compare_predicate_entailment` will not report the error
453+
// when normalization fails.
454+
let emitted = report_trait_method_mismatch(
455+
tcx,
456+
&mut cause,
457+
infcx,
458+
terr,
459+
(trait_m, trait_fty),
460+
(impl_m, impl_fty),
461+
&trait_sig,
462+
&impl_trait_ref,
532463
);
533-
return Err(guar);
464+
return Err(emitted);
534465
}
535466
}
536467

@@ -690,6 +621,112 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
690621
}
691622
}
692623

624+
fn report_trait_method_mismatch<'tcx>(
625+
tcx: TyCtxt<'tcx>,
626+
cause: &mut ObligationCause<'tcx>,
627+
infcx: &InferCtxt<'tcx>,
628+
terr: TypeError<'tcx>,
629+
(trait_m, trait_fty): (&AssocItem, Ty<'tcx>),
630+
(impl_m, impl_fty): (&AssocItem, Ty<'tcx>),
631+
trait_sig: &FnSig<'tcx>,
632+
impl_trait_ref: &TraitRef<'tcx>,
633+
) -> ErrorGuaranteed {
634+
let (impl_err_span, trait_err_span) =
635+
extract_spans_for_error_reporting(&infcx, terr, &cause, impl_m, trait_m);
636+
637+
cause.span = impl_err_span;
638+
639+
let mut diag = struct_span_err!(
640+
tcx.sess,
641+
cause.span(),
642+
E0053,
643+
"method `{}` has an incompatible type for trait",
644+
trait_m.name
645+
);
646+
match &terr {
647+
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
648+
if trait_m.fn_has_self_parameter =>
649+
{
650+
let ty = trait_sig.inputs()[0];
651+
let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty()) {
652+
ExplicitSelf::ByValue => "self".to_owned(),
653+
ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
654+
ExplicitSelf::ByReference(_, hir::Mutability::Mut) => "&mut self".to_owned(),
655+
_ => format!("self: {ty}"),
656+
};
657+
658+
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
659+
// span points only at the type `Box<Self`>, but we want to cover the whole
660+
// argument pattern and type.
661+
let span = match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
662+
ImplItemKind::Fn(ref sig, body) => tcx
663+
.hir()
664+
.body_param_names(body)
665+
.zip(sig.decl.inputs.iter())
666+
.map(|(param, ty)| param.span.to(ty.span))
667+
.next()
668+
.unwrap_or(impl_err_span),
669+
_ => bug!("{:?} is not a method", impl_m),
670+
};
671+
672+
diag.span_suggestion(
673+
span,
674+
"change the self-receiver type to match the trait",
675+
sugg,
676+
Applicability::MachineApplicable,
677+
);
678+
}
679+
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
680+
if trait_sig.inputs().len() == *i {
681+
// Suggestion to change output type. We do not suggest in `async` functions
682+
// to avoid complex logic or incorrect output.
683+
match tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind {
684+
ImplItemKind::Fn(ref sig, _)
685+
if sig.header.asyncness == hir::IsAsync::NotAsync =>
686+
{
687+
let msg = "change the output type to match the trait";
688+
let ap = Applicability::MachineApplicable;
689+
match sig.decl.output {
690+
hir::FnRetTy::DefaultReturn(sp) => {
691+
let sugg = format!("-> {} ", trait_sig.output());
692+
diag.span_suggestion_verbose(sp, msg, sugg, ap);
693+
}
694+
hir::FnRetTy::Return(hir_ty) => {
695+
let sugg = trait_sig.output();
696+
diag.span_suggestion(hir_ty.span, msg, sugg, ap);
697+
}
698+
};
699+
}
700+
_ => {}
701+
};
702+
} else if let Some(trait_ty) = trait_sig.inputs().get(*i) {
703+
diag.span_suggestion(
704+
impl_err_span,
705+
"change the parameter type to match the trait",
706+
trait_ty,
707+
Applicability::MachineApplicable,
708+
);
709+
}
710+
}
711+
_ => {}
712+
}
713+
714+
infcx.err_ctxt().note_type_err(
715+
&mut diag,
716+
&cause,
717+
trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
718+
Some(infer::ValuePairs::Terms(ExpectedFound {
719+
expected: trait_fty.into(),
720+
found: impl_fty.into(),
721+
})),
722+
terr,
723+
false,
724+
false,
725+
);
726+
727+
return diag.emit();
728+
}
729+
693730
fn check_region_bounds_on_impl_item<'tcx>(
694731
tcx: TyCtxt<'tcx>,
695732
impl_m: &ty::AssocItem,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// edition: 2021
2+
3+
#![feature(return_position_impl_trait_in_trait, async_fn_in_trait)]
4+
#![allow(incomplete_features)]
5+
6+
trait Uwu {
7+
fn owo(x: ()) -> impl Sized;
8+
}
9+
10+
impl Uwu for () {
11+
fn owo(_: u8) {}
12+
//~^ ERROR method `owo` has an incompatible type for trait
13+
}
14+
15+
trait AsyncUwu {
16+
async fn owo(x: ()) {}
17+
}
18+
19+
impl AsyncUwu for () {
20+
async fn owo(_: u8) {}
21+
//~^ ERROR method `owo` has an incompatible type for trait
22+
}
23+
24+
trait TooMuch {
25+
fn calm_down_please() -> impl Sized;
26+
}
27+
28+
impl TooMuch for () {
29+
fn calm_down_please(_: (), _: (), _: ()) {}
30+
//~^ ERROR method `calm_down_please` has 3 parameters but the declaration in trait `TooMuch::calm_down_please` has 0
31+
}
32+
33+
trait TooLittle {
34+
fn come_on_a_little_more_effort(_: (), _: (), _: ()) -> impl Sized;
35+
}
36+
37+
impl TooLittle for () {
38+
fn come_on_a_little_more_effort() {}
39+
//~^ ERROR method `come_on_a_little_more_effort` has 0 parameters but the declaration in trait `TooLittle::come_on_a_little_more_effort` has 3
40+
}
41+
42+
trait Lifetimes {
43+
fn early<'early, T>(x: &'early T) -> impl Sized;
44+
}
45+
46+
impl Lifetimes for () {
47+
fn early<'late, T>(_: &'late ()) {}
48+
//~^ ERROR method `early` has an incompatible type for trait
49+
}
50+
51+
fn main() {}

0 commit comments

Comments
 (0)