From 8b64988575d4b71616620bd78d9c2e9a4f526232 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Jul 2022 09:41:19 +0000 Subject: [PATCH 1/2] Fix error message with non-tupled bare fn trait --- .../src/infer/error_reporting/mod.rs | 1 + compiler/rustc_infer/src/infer/mod.rs | 12 ++++++++ compiler/rustc_middle/src/ty/error.rs | 12 ++++++++ .../src/traits/error_reporting/mod.rs | 30 +++++++++++++++++-- src/test/ui/mismatched_types/E0631.rs | 4 +-- src/test/ui/mismatched_types/E0631.stderr | 24 +++++++-------- .../ui/mismatched_types/closure-arg-count.rs | 4 +-- .../mismatched_types/closure-arg-count.stderr | 27 +++++++---------- .../non-tupled-arg-mismatch.rs | 8 +++++ .../non-tupled-arg-mismatch.stderr | 17 +++++++++++ 10 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs create mode 100644 src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fcb87a9f32f1e..3c7dac2bfd816 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1750,6 +1750,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() && let Some(def_id) = def_id.as_local() + && terr.involves_regions() { let span = self.tcx.def_span(def_id); diag.span_note(span, "this closure does not fulfill the lifetime requirements"); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 1e26e7bb86ef0..444817f396e56 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1935,6 +1935,18 @@ impl<'tcx> TypeTrace<'tcx> { } } + pub fn poly_trait_refs( + cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: ty::PolyTraitRef<'tcx>, + b: ty::PolyTraitRef<'tcx>, + ) -> TypeTrace<'tcx> { + TypeTrace { + cause: cause.clone(), + values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a.into(), b.into())), + } + } + pub fn consts( cause: &ObligationCause<'tcx>, a_is_expected: bool, diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 8e6af936ded18..ac89bec702efd 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -74,6 +74,18 @@ pub enum TypeError<'tcx> { TargetFeatureCast(DefId), } +impl TypeError<'_> { + pub fn involves_regions(self) -> bool { + match self { + TypeError::RegionsDoesNotOutlive(_, _) + | TypeError::RegionsInsufficientlyPolymorphic(_, _) + | TypeError::RegionsOverlyPolymorphic(_, _) + | TypeError::RegionsPlaceholderMismatch => true, + _ => false, + } + } +} + /// Explains the source of a type err in a short, human readable way. This is meant to be placed /// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` /// afterwards to present additional details, particularly when it comes to lifetime-related diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 4260cb53adc1c..1a39a1680384d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -22,6 +22,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::GenericParam; use rustc_hir::Item; use rustc_hir::Node; +use rustc_infer::infer::TypeTrace; use rustc_infer::traits::TraitEngine; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -941,9 +942,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); + let mut not_tupled = false; + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], - _ => vec![ArgKind::empty()], + _ => { + not_tupled = true; + vec![ArgKind::empty()] + } }; let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); @@ -951,10 +957,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty::Tuple(ref tys) => { tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect() } - _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], + _ => { + not_tupled = true; + vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())] + } }; - if found.len() == expected.len() { + // If this is a `Fn` family trait and either the expected or found + // is not tupled, then fall back to just a regular mismatch error. + // This shouldn't be common unless manually implementing one of the + // traits manually, but don't make it more confusing when it does + // happen. + if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled { + self.report_and_explain_type_error( + TypeTrace::poly_trait_refs( + &obligation.cause, + true, + expected_trait_ref, + found_trait_ref, + ), + ty::error::TypeError::Mismatch, + ) + } else if found.len() == expected.len() { self.report_closure_arg_mismatch( span, found_span, diff --git a/src/test/ui/mismatched_types/E0631.rs b/src/test/ui/mismatched_types/E0631.rs index a293946583069..e66ef6aaeda06 100644 --- a/src/test/ui/mismatched_types/E0631.rs +++ b/src/test/ui/mismatched_types/E0631.rs @@ -5,7 +5,7 @@ fn bar>(_: F) {} fn main() { fn f(_: u64) {} foo(|_: isize| {}); //~ ERROR type mismatch - bar(|_: isize| {}); //~ ERROR type mismatch + bar(|_: isize| {}); //~ ERROR mismatched types foo(f); //~ ERROR type mismatch - bar(f); //~ ERROR type mismatch + bar(f); //~ ERROR mismatched types } diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr index 4d673d45559a9..fefb6fea4eb9f 100644 --- a/src/test/ui/mismatched_types/E0631.stderr +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -14,16 +14,14 @@ note: required by a bound in `foo` LL | fn foo(_: F) {} | ^^^^^^^^^ required by this bound in `foo` -error[E0631]: type mismatch in closure arguments +error[E0308]: mismatched types --> $DIR/E0631.rs:8:5 | LL | bar(|_: isize| {}); - | ^^^ ---------- found signature defined here - | | - | expected due to this + | ^^^ types differ | - = note: expected closure signature `fn(usize) -> _` - found closure signature `fn(isize) -> _` + = note: expected trait `Fn` + found trait `Fn<(isize,)>` note: required by a bound in `bar` --> $DIR/E0631.rs:4:11 | @@ -49,19 +47,16 @@ note: required by a bound in `foo` LL | fn foo(_: F) {} | ^^^^^^^^^ required by this bound in `foo` -error[E0631]: type mismatch in function arguments +error[E0308]: mismatched types --> $DIR/E0631.rs:10:9 | -LL | fn f(_: u64) {} - | ------------ found signature defined here -... LL | bar(f); - | --- ^ expected due to this + | --- ^ types differ | | | required by a bound introduced by this call | - = note: expected function signature `fn(usize) -> _` - found function signature `fn(u64) -> _` + = note: expected trait `Fn` + found trait `Fn<(u64,)>` note: required by a bound in `bar` --> $DIR/E0631.rs:4:11 | @@ -70,4 +65,5 @@ LL | fn bar>(_: F) {} error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0631`. +Some errors have detailed explanations: E0308, E0631. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index e817631ad5d79..b6759d750c8c9 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -11,9 +11,9 @@ fn main() { [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!()); //~^ ERROR closure is expected to take f(|| panic!()); - //~^ ERROR closure is expected to take + //~^ ERROR mismatched types f( move || panic!()); - //~^ ERROR closure is expected to take + //~^ ERROR mismatched types let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); //~^ ERROR closure is expected to take diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 3968774e35793..d13e5d682da47 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -45,41 +45,33 @@ help: change the closure to take multiple arguments instead of a single tuple LL | [1, 2, 3].sort_by(|tuple, tuple2| panic!()); | ~~~~~~~~~~~~~~~ -error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments +error[E0308]: mismatched types --> $DIR/closure-arg-count.rs:13:5 | LL | f(|| panic!()); - | ^ -- takes 0 arguments - | | - | expected closure that takes 1 argument + | ^ types differ | + = note: expected trait `Fn` + found trait `Fn<()>` note: required by a bound in `f` --> $DIR/closure-arg-count.rs:3:9 | LL | fn f>(_: F) {} | ^^^^^^^^^ required by this bound in `f` -help: consider changing the closure to take and ignore the expected argument - | -LL | f(|_| panic!()); - | ~~~ -error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments +error[E0308]: mismatched types --> $DIR/closure-arg-count.rs:15:5 | LL | f( move || panic!()); - | ^ ---------- takes 0 arguments - | | - | expected closure that takes 1 argument + | ^ types differ | + = note: expected trait `Fn` + found trait `Fn<()>` note: required by a bound in `f` --> $DIR/closure-arg-count.rs:3:9 | LL | fn f>(_: F) {} | ^^^^^^^^^ required by this bound in `f` -help: consider changing the closure to take and ignore the expected argument - | -LL | f( move |_| panic!()); - | ~~~ error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments --> $DIR/closure-arg-count.rs:18:53 @@ -198,4 +190,5 @@ LL | fn call(_: F) where F: FnOnce() -> R {} error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0593`. +Some errors have detailed explanations: E0308, E0593. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs new file mode 100644 index 0000000000000..925463d6deedc --- /dev/null +++ b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.rs @@ -0,0 +1,8 @@ +#![feature(unboxed_closures)] + +fn a>(f: F) {} + +fn main() { + a(|_: usize| {}); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr new file mode 100644 index 0000000000000..9a24fb8c2beec --- /dev/null +++ b/src/test/ui/unboxed-closures/non-tupled-arg-mismatch.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/non-tupled-arg-mismatch.rs:6:5 + | +LL | a(|_: usize| {}); + | ^ types differ + | + = note: expected trait `Fn` + found trait `Fn<(usize,)>` +note: required by a bound in `a` + --> $DIR/non-tupled-arg-mismatch.rs:3:9 + | +LL | fn a>(f: F) {} + | ^^^^^^^^^ required by this bound in `a` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 1c084f15f308f1d977fd763c3d8bed831b44abf2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Jul 2022 09:44:22 +0000 Subject: [PATCH 2/2] Correct meaning of two UI tests --- src/test/ui/mismatched_types/E0631.rs | 6 ++-- src/test/ui/mismatched_types/E0631.stderr | 32 +++++++++-------- .../ui/mismatched_types/closure-arg-count.rs | 6 ++-- .../mismatched_types/closure-arg-count.stderr | 35 +++++++++++-------- 4 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/test/ui/mismatched_types/E0631.rs b/src/test/ui/mismatched_types/E0631.rs index e66ef6aaeda06..83dbdb77abeb5 100644 --- a/src/test/ui/mismatched_types/E0631.rs +++ b/src/test/ui/mismatched_types/E0631.rs @@ -1,11 +1,11 @@ #![feature(unboxed_closures)] fn foo(_: F) {} -fn bar>(_: F) {} +fn bar>(_: F) {} fn main() { fn f(_: u64) {} foo(|_: isize| {}); //~ ERROR type mismatch - bar(|_: isize| {}); //~ ERROR mismatched types + bar(|_: isize| {}); //~ ERROR type mismatch foo(f); //~ ERROR type mismatch - bar(f); //~ ERROR mismatched types + bar(f); //~ ERROR type mismatch } diff --git a/src/test/ui/mismatched_types/E0631.stderr b/src/test/ui/mismatched_types/E0631.stderr index fefb6fea4eb9f..410ea4b0b3439 100644 --- a/src/test/ui/mismatched_types/E0631.stderr +++ b/src/test/ui/mismatched_types/E0631.stderr @@ -14,19 +14,21 @@ note: required by a bound in `foo` LL | fn foo(_: F) {} | ^^^^^^^^^ required by this bound in `foo` -error[E0308]: mismatched types +error[E0631]: type mismatch in closure arguments --> $DIR/E0631.rs:8:5 | LL | bar(|_: isize| {}); - | ^^^ types differ + | ^^^ ---------- found signature defined here + | | + | expected due to this | - = note: expected trait `Fn` - found trait `Fn<(isize,)>` + = note: expected closure signature `fn(usize) -> _` + found closure signature `fn(isize) -> _` note: required by a bound in `bar` --> $DIR/E0631.rs:4:11 | -LL | fn bar>(_: F) {} - | ^^^^^^^^^ required by this bound in `bar` +LL | fn bar>(_: F) {} + | ^^^^^^^^^^^^ required by this bound in `bar` error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:9:9 @@ -47,23 +49,25 @@ note: required by a bound in `foo` LL | fn foo(_: F) {} | ^^^^^^^^^ required by this bound in `foo` -error[E0308]: mismatched types +error[E0631]: type mismatch in function arguments --> $DIR/E0631.rs:10:9 | +LL | fn f(_: u64) {} + | ------------ found signature defined here +... LL | bar(f); - | --- ^ types differ + | --- ^ expected due to this | | | required by a bound introduced by this call | - = note: expected trait `Fn` - found trait `Fn<(u64,)>` + = note: expected function signature `fn(usize) -> _` + found function signature `fn(u64) -> _` note: required by a bound in `bar` --> $DIR/E0631.rs:4:11 | -LL | fn bar>(_: F) {} - | ^^^^^^^^^ required by this bound in `bar` +LL | fn bar>(_: F) {} + | ^^^^^^^^^^^^ required by this bound in `bar` error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0631. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0631`. diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index b6759d750c8c9..65c8d6a7e936e 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -1,6 +1,6 @@ #![feature(unboxed_closures)] -fn f>(_: F) {} +fn f>(_: F) {} fn main() { [1, 2, 3].sort_by(|| panic!()); //~^ ERROR closure is expected to take @@ -11,9 +11,9 @@ fn main() { [1, 2, 3].sort_by(|(tuple, tuple2): (usize, _)| panic!()); //~^ ERROR closure is expected to take f(|| panic!()); - //~^ ERROR mismatched types + //~^ ERROR closure is expected to take f( move || panic!()); - //~^ ERROR mismatched types + //~^ ERROR closure is expected to take let _it = vec![1, 2, 3].into_iter().enumerate().map(|i, x| i); //~^ ERROR closure is expected to take diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index d13e5d682da47..a02ec81983883 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -45,33 +45,41 @@ help: change the closure to take multiple arguments instead of a single tuple LL | [1, 2, 3].sort_by(|tuple, tuple2| panic!()); | ~~~~~~~~~~~~~~~ -error[E0308]: mismatched types +error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:13:5 | LL | f(|| panic!()); - | ^ types differ + | ^ -- takes 0 arguments + | | + | expected closure that takes 1 argument | - = note: expected trait `Fn` - found trait `Fn<()>` note: required by a bound in `f` --> $DIR/closure-arg-count.rs:3:9 | -LL | fn f>(_: F) {} - | ^^^^^^^^^ required by this bound in `f` +LL | fn f>(_: F) {} + | ^^^^^^^^^^^^ required by this bound in `f` +help: consider changing the closure to take and ignore the expected argument + | +LL | f(|_| panic!()); + | ~~~ -error[E0308]: mismatched types +error[E0593]: closure is expected to take 1 argument, but it takes 0 arguments --> $DIR/closure-arg-count.rs:15:5 | LL | f( move || panic!()); - | ^ types differ + | ^ ---------- takes 0 arguments + | | + | expected closure that takes 1 argument | - = note: expected trait `Fn` - found trait `Fn<()>` note: required by a bound in `f` --> $DIR/closure-arg-count.rs:3:9 | -LL | fn f>(_: F) {} - | ^^^^^^^^^ required by this bound in `f` +LL | fn f>(_: F) {} + | ^^^^^^^^^^^^ required by this bound in `f` +help: consider changing the closure to take and ignore the expected argument + | +LL | f( move |_| panic!()); + | ~~~ error[E0593]: closure is expected to take a single 2-tuple as argument, but it takes 2 distinct arguments --> $DIR/closure-arg-count.rs:18:53 @@ -190,5 +198,4 @@ LL | fn call(_: F) where F: FnOnce() -> R {} error: aborting due to 14 previous errors -Some errors have detailed explanations: E0308, E0593. -For more information about an error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0593`.