From fe2f40a142ef8767ad379b11a86d3161a44b3887 Mon Sep 17 00:00:00 2001 From: ch-iv Date: Tue, 8 Nov 2022 09:27:32 -0500 Subject: [PATCH 01/20] Add an example for Pin::new() --- library/core/src/pin.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index ccef35b45325a..7751dfb4767d1 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -485,6 +485,13 @@ impl> Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. + /// + /// # Examples + /// + /// ``` + /// let val: u8 = 5; + /// let pinned: Pin<&u8> = Pin::new(&val); + /// ``` #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin", since = "1.33.0")] From 8b5379e4b5c032271fe0fb29972f15510e911066 Mon Sep 17 00:00:00 2001 From: ch-iv Date: Wed, 9 Nov 2022 09:02:28 -0500 Subject: [PATCH 02/20] Add example for the into_inner() method --- library/core/src/pin.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 7751dfb4767d1..1af638a6b8a63 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -489,7 +489,10 @@ impl> Pin

{ /// # Examples /// /// ``` + /// use std::pin::Pin; + /// /// let val: u8 = 5; + /// // Wrap the value in a pin to make sure it doesn't move /// let pinned: Pin<&u8> = Pin::new(&val); /// ``` #[inline(always)] @@ -505,6 +508,17 @@ impl> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. + /// + /// # Examples + /// + /// ``` + /// use std::pin::Pin; + /// + /// let pinned: Pin<&u8> = Pin::new(&5); + /// // Unwrap the pin to get a reference to the value + /// let r = Pin::into_inner(pinned); + /// assert_eq!(*r, 5); + /// ``` #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] #[stable(feature = "pin_into_inner", since = "1.39.0")] From dfa90e76b7d24f8b7f5b588df884b93807b64790 Mon Sep 17 00:00:00 2001 From: ch-iv Date: Wed, 9 Nov 2022 09:59:05 -0500 Subject: [PATCH 03/20] fix formatting --- library/core/src/pin.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 1af638a6b8a63..421efa7659a84 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -485,12 +485,12 @@ impl> Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. - /// + /// /// # Examples - /// + /// /// ``` /// use std::pin::Pin; - /// + /// /// let val: u8 = 5; /// // Wrap the value in a pin to make sure it doesn't move /// let pinned: Pin<&u8> = Pin::new(&val); @@ -508,9 +508,9 @@ impl> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. - /// + /// /// # Examples - /// + /// /// ``` /// use std::pin::Pin; /// From 6f48b60ace325b4b8f7260012df8a47ef04fdbbf Mon Sep 17 00:00:00 2001 From: ch-iv Date: Wed, 9 Nov 2022 17:02:30 -0500 Subject: [PATCH 04/20] Repace inaccruate comment --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 421efa7659a84..df65fcfe151cd 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -492,7 +492,7 @@ impl> Pin

{ /// use std::pin::Pin; /// /// let val: u8 = 5; - /// // Wrap the value in a pin to make sure it doesn't move + /// // We can pin the value, since it doesn't care about being moved /// let pinned: Pin<&u8> = Pin::new(&val); /// ``` #[inline(always)] From a4ee02b15ce1cf1518b0b2661a6f00d94847755b Mon Sep 17 00:00:00 2001 From: ch-iv Date: Wed, 9 Nov 2022 17:07:58 -0500 Subject: [PATCH 05/20] formatting --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index df65fcfe151cd..12cef04d1f9b7 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -492,7 +492,7 @@ impl> Pin

{ /// use std::pin::Pin; /// /// let val: u8 = 5; - /// // We can pin the value, since it doesn't care about being moved + /// // We can pin the value, since it doesn't care about being moved /// let pinned: Pin<&u8> = Pin::new(&val); /// ``` #[inline(always)] From 06c2ce05a4b0d05553858cf1951f75777a7e9406 Mon Sep 17 00:00:00 2001 From: ch-iv <108201575+ch-iv@users.noreply.github.com> Date: Thu, 10 Nov 2022 08:34:13 -0500 Subject: [PATCH 06/20] Update library/core/src/pin.rs Co-authored-by: Vincenzo Palazzo --- library/core/src/pin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 12cef04d1f9b7..eafbc2c781889 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -506,7 +506,7 @@ impl> Pin

{ /// Unwraps this `Pin

` returning the underlying pointer. /// - /// This requires that the data inside this `Pin` is [`Unpin`] so that we + /// This requires that the data inside this `Pin` implements [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. /// /// # Examples From 7a47e2c85314ec5c13c5d0bd2992997bb10033d6 Mon Sep 17 00:00:00 2001 From: ch-iv Date: Wed, 23 Nov 2022 16:55:25 -0500 Subject: [PATCH 07/20] Demonstrate with an &mut reference --- library/core/src/pin.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index f94969d7c1ac9..3f8acc8505ff1 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -491,9 +491,9 @@ impl> Pin

{ /// ``` /// use std::pin::Pin; /// - /// let val: u8 = 5; + /// let mut val: u8 = 5; /// // We can pin the value, since it doesn't care about being moved - /// let pinned: Pin<&u8> = Pin::new(&val); + /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val); /// ``` #[inline(always)] #[rustc_const_unstable(feature = "const_pin", issue = "76654")] @@ -514,7 +514,8 @@ impl> Pin

{ /// ``` /// use std::pin::Pin; /// - /// let pinned: Pin<&u8> = Pin::new(&5); + /// let mut val: u8 = 5; + /// let pinned: Pin<&mut u8> = Pin::new(&mut val); /// // Unwrap the pin to get a reference to the value /// let r = Pin::into_inner(pinned); /// assert_eq!(*r, 5); @@ -728,6 +729,18 @@ impl Pin

{ /// /// This overwrites pinned data, but that is okay: its destructor gets /// run before being overwritten, so no pinning guarantee is violated. + /// + /// # Example + /// + /// ``` + /// use std::pin::Pin; + /// + /// let mut val: u8 = 5; + /// let mut pinned: Pin<&mut u8> = Pin::new(&mut val); + /// println!("{}", pinned); // 5 + /// pinned.as_mut().set(10); + /// println!("{}", pinned); // 10 + /// ``` #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn set(&mut self, value: P::Target) From 0e19fb92e1eb7f91aa5570b2ac782c9a42a6e329 Mon Sep 17 00:00:00 2001 From: Yiming Lei Date: Wed, 30 Nov 2022 12:01:00 -0800 Subject: [PATCH 08/20] While parsing enum variant, the error message always disappear Because the error message that emit out is from main error of parser The information of enum variant disappears while parsing enum variant with error We only check the syntax of expecting token, i.e, in case #103869 It will error it without telling the message that this error is from pasring enum variant. Propagate the sub-error from parsing enum variant to the main error of parser by chaining it with map_err Check the sub-error before emitting the main error of parser and attach it. Fix #103869 --- compiler/rustc_parse/src/parser/item.rs | 5 ++++- compiler/rustc_parse/src/parser/mod.rs | 4 ++++ src/test/ui/macros/syntax-error-recovery.stderr | 1 + src/test/ui/parser/issue-101477-enum.stderr | 2 ++ src/test/ui/parser/issue-103869.rs | 9 +++++++++ src/test/ui/parser/issue-103869.stderr | 16 ++++++++++++++++ src/test/ui/parser/macro/issue-37113.stderr | 1 + src/test/ui/structs/struct-fn-in-definition.rs | 1 + .../ui/structs/struct-fn-in-definition.stderr | 1 + 9 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/issue-103869.rs create mode 100644 src/test/ui/parser/issue-103869.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 767fb9378bef1..7ce89b5c3597b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1414,7 +1414,10 @@ impl<'a> Parser<'a> { Ok((Some(vr), TrailingToken::MaybeComma)) }, - ) + ).map_err(|mut err|{ + err.help("enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`"); + err + }) } /// Parses `struct Foo { ... }`. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4d8bff28b05aa..bebb012660a16 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -943,6 +943,10 @@ impl<'a> Parser<'a> { Err(e) => { // Parsing failed, therefore it must be something more serious // than just a missing separator. + for xx in &e.children { + // propagate the help message from sub error 'e' to main error 'expect_err; + expect_err.children.push(xx.clone()); + } expect_err.emit(); e.cancel(); diff --git a/src/test/ui/macros/syntax-error-recovery.stderr b/src/test/ui/macros/syntax-error-recovery.stderr index c153b3b910bbe..c42ee9b295e1d 100644 --- a/src/test/ui/macros/syntax-error-recovery.stderr +++ b/src/test/ui/macros/syntax-error-recovery.stderr @@ -7,6 +7,7 @@ LL | $token $($inner)? = $value, LL | values!(STRING(1) as (String) => cfg(test),); | -------------------------------------------- in this macro invocation | + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info) error: macro expansion ignores token `(String)` and any following diff --git a/src/test/ui/parser/issue-101477-enum.stderr b/src/test/ui/parser/issue-101477-enum.stderr index bffc881bdc84b..1edca391e8fd0 100644 --- a/src/test/ui/parser/issue-101477-enum.stderr +++ b/src/test/ui/parser/issue-101477-enum.stderr @@ -3,6 +3,8 @@ error: unexpected `==` | LL | B == 2 | ^^ help: try using `=` instead + | + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` error: expected item, found `==` --> $DIR/issue-101477-enum.rs:6:7 diff --git a/src/test/ui/parser/issue-103869.rs b/src/test/ui/parser/issue-103869.rs new file mode 100644 index 0000000000000..28c442bdd632d --- /dev/null +++ b/src/test/ui/parser/issue-103869.rs @@ -0,0 +1,9 @@ +enum VecOrMap{ + vec: Vec, + //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `:` + //~| HELP: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + //~| ERROR expected item, found `:` + map: HashMap +} + +fn main() {} diff --git a/src/test/ui/parser/issue-103869.stderr b/src/test/ui/parser/issue-103869.stderr new file mode 100644 index 0000000000000..0b8cd919a9de2 --- /dev/null +++ b/src/test/ui/parser/issue-103869.stderr @@ -0,0 +1,16 @@ +error: expected one of `(`, `,`, `=`, `{`, or `}`, found `:` + --> $DIR/issue-103869.rs:2:8 + | +LL | vec: Vec, + | ^ expected one of `(`, `,`, `=`, `{`, or `}` + | + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` + +error: expected item, found `:` + --> $DIR/issue-103869.rs:2:8 + | +LL | vec: Vec, + | ^ expected item + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/macro/issue-37113.stderr b/src/test/ui/parser/macro/issue-37113.stderr index b1f8674fbdf38..da9e743a0b44f 100644 --- a/src/test/ui/parser/macro/issue-37113.stderr +++ b/src/test/ui/parser/macro/issue-37113.stderr @@ -9,6 +9,7 @@ LL | $( $t, )* LL | test_macro!(String,); | -------------------- in this macro invocation | + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` = note: this error originates in the macro `test_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/structs/struct-fn-in-definition.rs b/src/test/ui/structs/struct-fn-in-definition.rs index 5ae1b727dc772..7f48f55fec938 100644 --- a/src/test/ui/structs/struct-fn-in-definition.rs +++ b/src/test/ui/structs/struct-fn-in-definition.rs @@ -28,6 +28,7 @@ enum E { //~^ ERROR functions are not allowed in enum definitions //~| HELP unlike in C++, Java, and C#, functions are declared in `impl` blocks //~| HELP see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + //~| HELP enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` } fn main() {} diff --git a/src/test/ui/structs/struct-fn-in-definition.stderr b/src/test/ui/structs/struct-fn-in-definition.stderr index 472365c6ed739..439c86ec22b0e 100644 --- a/src/test/ui/structs/struct-fn-in-definition.stderr +++ b/src/test/ui/structs/struct-fn-in-definition.stderr @@ -33,6 +33,7 @@ LL | fn foo() {} | = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + = help: enum variants can be `Variant`, `Variant = `, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }` error: aborting due to 3 previous errors From c823dfa8b2f1b0cfb82d253e6d55efd6927bcb6d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Dec 2022 10:32:00 +0100 Subject: [PATCH 09/20] remove no-op 'let _ = ' --- library/std/src/sync/mpsc/mod.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 27fba761ada10..adb488d4378f0 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -629,9 +629,7 @@ impl Clone for Sender { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Sender { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] @@ -751,9 +749,7 @@ impl Clone for SyncSender { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for SyncSender { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] @@ -1094,9 +1090,7 @@ impl IntoIterator for Receiver { #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Receiver { - fn drop(&mut self) { - let _ = self.inner; - } + fn drop(&mut self) {} } #[stable(feature = "mpsc_debug", since = "1.8.0")] From 44948d1fdc97a4fd24594be77df673a2c3b40544 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 4 Dec 2022 13:54:41 +0000 Subject: [PATCH 10/20] Recurse into nested impl-trait when computing variance. --- .../rustc_hir_analysis/src/variance/mod.rs | 42 +++++++++++++++++-- src/test/ui/impl-trait/nested-return-type4.rs | 8 ++++ .../ui/impl-trait/nested-return-type4.stderr | 20 +++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/impl-trait/nested-return-type4.rs create mode 100644 src/test/ui/impl-trait/nested-return-type4.stderr diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 9db05eedbde79..8b2719c2f8aaa 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -7,7 +7,8 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, CrateVariancesMap, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable}; use std::ops::ControlFlow; /// Defines the `TermsContext` basically houses an arena where we can @@ -75,11 +76,30 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc // type Foo<'a, 'b, 'c> = impl Trait<'a> + 'b; // ``` // we may not use `'c` in the hidden type. - struct OpaqueTypeLifetimeCollector { + struct OpaqueTypeLifetimeCollector<'tcx> { + tcx: TyCtxt<'tcx>, + root_def_id: DefId, variances: Vec, } - impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector { + impl<'tcx> OpaqueTypeLifetimeCollector<'tcx> { + #[instrument(level = "trace", skip(self), ret)] + fn visit_opaque(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> ControlFlow { + if def_id != self.root_def_id && self.tcx.is_descendant_of(def_id, self.root_def_id) { + let child_variances = self.tcx.variances_of(def_id); + for (a, v) in substs.iter().zip(child_variances) { + if *v != ty::Bivariant { + a.visit_with(self)?; + } + } + ControlFlow::CONTINUE + } else { + substs.visit_with(self) + } + } + } + + impl<'tcx> ty::TypeVisitor<'tcx> for OpaqueTypeLifetimeCollector<'tcx> { #[instrument(level = "trace", skip(self), ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() { @@ -87,6 +107,19 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } r.super_visit_with(self) } + + #[instrument(level = "trace", skip(self), ret)] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + match t.kind() { + ty::Opaque(def_id, substs) => self.visit_opaque(*def_id, substs), + ty::Projection(proj) + if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder => + { + self.visit_opaque(proj.item_def_id, proj.substs) + } + _ => t.super_visit_with(self), + } + } } // By default, RPIT are invariant wrt type and const generics, but they are bivariant wrt @@ -111,7 +144,8 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc } } - let mut collector = OpaqueTypeLifetimeCollector { variances }; + let mut collector = + OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances }; let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id.to_def_id()); for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() { let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs); diff --git a/src/test/ui/impl-trait/nested-return-type4.rs b/src/test/ui/impl-trait/nested-return-type4.rs new file mode 100644 index 0000000000000..cec70bb1a0d9e --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type4.rs @@ -0,0 +1,8 @@ +// edition: 2021 + +fn test<'s: 's>(s: &'s str) -> impl std::future::Future { + async move { let _s = s; } + //~^ ERROR hidden type for `impl Future` captures lifetime that does not appear in bounds +} + +fn main() {} diff --git a/src/test/ui/impl-trait/nested-return-type4.stderr b/src/test/ui/impl-trait/nested-return-type4.stderr new file mode 100644 index 0000000000000..e761a60e79c27 --- /dev/null +++ b/src/test/ui/impl-trait/nested-return-type4.stderr @@ -0,0 +1,20 @@ +error[E0700]: hidden type for `impl Future` captures lifetime that does not appear in bounds + --> $DIR/nested-return-type4.rs:4:5 + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future { + | -- hidden type `[async block@$DIR/nested-return-type4.rs:4:5: 4:31]` captures the lifetime `'s` as defined here +LL | async move { let _s = s; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: to declare that `impl Future` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future + 's { + | ++++ +help: to declare that `impl Sized` captures `'s`, you can add an explicit `'s` lifetime bound + | +LL | fn test<'s: 's>(s: &'s str) -> impl std::future::Future { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0700`. From 19175e9b75234647963c84247db653f53c8c936a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Dec 2022 05:44:24 +0000 Subject: [PATCH 11/20] Synthesize generics for bad auto traits in dyn types --- compiler/rustc_middle/src/ty/sty.rs | 24 +++++++++++++++++-- .../ui/auto-traits/bad-generics-on-dyn.rs | 11 +++++++++ .../ui/auto-traits/bad-generics-on-dyn.stderr | 11 +++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/auto-traits/bad-generics-on-dyn.rs create mode 100644 src/test/ui/auto-traits/bad-generics-on-dyn.stderr diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 5984686044b73..8e69824e6c790 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -722,8 +722,28 @@ impl<'tcx> PolyExistentialPredicate<'tcx> { self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) } ExistentialPredicate::AutoTrait(did) => { - let trait_ref = self.rebind(tcx.mk_trait_ref(did, [self_ty])); - trait_ref.without_const().to_predicate(tcx) + let generics = tcx.generics_of(did); + let trait_ref = if generics.params.len() == 1 { + tcx.mk_trait_ref(did, [self_ty]) + } else { + // If this is an ill-formed auto trait, then synthesize + // new error substs for the missing generics. + let err_substs = ty::InternalSubsts::for_item(tcx, did, |def, substs| { + if def.index == 0 { + self_ty.into() + } else { + match &def.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(), + ty::GenericParamDefKind::Const { .. } => tcx + .const_error(tcx.bound_type_of(def.def_id).subst(tcx, substs)) + .into(), + } + } + }); + tcx.mk_trait_ref(did, err_substs) + }; + self.rebind(trait_ref).without_const().to_predicate(tcx) } } } diff --git a/src/test/ui/auto-traits/bad-generics-on-dyn.rs b/src/test/ui/auto-traits/bad-generics-on-dyn.rs new file mode 100644 index 0000000000000..3f8ac14c72d95 --- /dev/null +++ b/src/test/ui/auto-traits/bad-generics-on-dyn.rs @@ -0,0 +1,11 @@ +#![feature(auto_traits)] + +auto trait Trait1<'a> {} +//~^ ERROR auto traits cannot have generic parameters + +fn f<'a>(x: &dyn Trait1<'a>) +{} + +fn main() { + f(&1); +} diff --git a/src/test/ui/auto-traits/bad-generics-on-dyn.stderr b/src/test/ui/auto-traits/bad-generics-on-dyn.stderr new file mode 100644 index 0000000000000..ade69ced6060d --- /dev/null +++ b/src/test/ui/auto-traits/bad-generics-on-dyn.stderr @@ -0,0 +1,11 @@ +error[E0567]: auto traits cannot have generic parameters + --> $DIR/bad-generics-on-dyn.rs:3:18 + | +LL | auto trait Trait1<'a> {} + | ------^^^^ help: remove the parameters + | | + | auto trait cannot have generic parameters + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0567`. From f4c76b193d54eeb88b2c966612679d733536efaf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Dec 2022 08:15:30 -0800 Subject: [PATCH 12/20] Be more careful about unresolved exprs in suggestion --- .../rustc_hir_typeck/src/method/suggest.rs | 23 +++++++++++-------- .../path-to-method-sugg-unresolved-expr.rs | 4 ++++ ...path-to-method-sugg-unresolved-expr.stderr | 9 ++++++++ 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs create mode 100644 src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9ba4ddfd5cf7f..db93cfab2c0db 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1482,15 +1482,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident_name: Symbol, } + // FIXME: This really should be taking scoping, etc into account. impl<'v> Visitor<'v> for LetVisitor<'v> { fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { - if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind { - if let Binding(_, _, ident, ..) = pat.kind && - ident.name == self.ident_name { - self.result = *init; - } + if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind + && let Binding(_, _, ident, ..) = pat.kind + && ident.name == self.ident_name + { + self.result = *init; + } else { + hir::intravisit::walk_stmt(self, ex); } - hir::intravisit::walk_stmt(self, ex); } } @@ -1498,9 +1500,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { visitor.visit_body(&body); let parent = self.tcx.hir().get_parent_node(seg1.hir_id); - if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) && - let Some(expr) = visitor.result { - let self_ty = self.node_ty(expr.hir_id); + if let Some(Node::Expr(call_expr)) = self.tcx.hir().find(parent) + && let Some(expr) = visitor.result + && let Some(self_ty) = self.node_ty_opt(expr.hir_id) + { let probe = self.lookup_probe( seg2.ident, self_ty, @@ -1513,7 +1516,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(), "you may have meant to call an instance method", ".".to_string(), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } } diff --git a/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs new file mode 100644 index 0000000000000..fb56b394493dc --- /dev/null +++ b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.rs @@ -0,0 +1,4 @@ +fn main() { + let page_size = page_size::get(); + //~^ ERROR failed to resolve: use of undeclared crate or module `page_size` +} diff --git a/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr new file mode 100644 index 0000000000000..b01e30be54de0 --- /dev/null +++ b/src/test/ui/typeck/path-to-method-sugg-unresolved-expr.stderr @@ -0,0 +1,9 @@ +error[E0433]: failed to resolve: use of undeclared crate or module `page_size` + --> $DIR/path-to-method-sugg-unresolved-expr.rs:2:21 + | +LL | let page_size = page_size::get(); + | ^^^^^^^^^ use of undeclared crate or module `page_size` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. From da929fa63c7a9687de708587f170cbe7f874a495 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Dec 2022 17:34:17 +0000 Subject: [PATCH 13/20] Make get_impl_future_output_ty work with AFIT --- .../src/infer/error_reporting/mod.rs | 10 +++++++- .../in-trait/return-type-suggestion.rs | 14 +++++++++++ .../in-trait/return-type-suggestion.stderr | 23 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/async-await/in-trait/return-type-suggestion.rs create mode 100644 src/test/ui/async-await/in-trait/return-type-suggestion.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 662136ca18df6..3256ca1fb20fb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -341,7 +341,15 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>( impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option> { - let ty::Opaque(def_id, substs) = *ty.kind() else { return None; }; + let (def_id, substs) = match *ty.kind() { + ty::Opaque(def_id, substs) => (def_id, substs), + ty::Projection(data) + if self.tcx.def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder => + { + (data.item_def_id, data.substs) + } + _ => return None, + }; let future_trait = self.tcx.require_lang_item(LangItem::Future, None); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; diff --git a/src/test/ui/async-await/in-trait/return-type-suggestion.rs b/src/test/ui/async-await/in-trait/return-type-suggestion.rs new file mode 100644 index 0000000000000..3446761d119da --- /dev/null +++ b/src/test/ui/async-await/in-trait/return-type-suggestion.rs @@ -0,0 +1,14 @@ +// edition: 2021 + +#![feature(async_fn_in_trait)] +//~^ WARN the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + +trait A { + async fn e() { + Ok(()) + //~^ ERROR mismatched types + //~| HELP consider using a semicolon here + } +} + +fn main() {} diff --git a/src/test/ui/async-await/in-trait/return-type-suggestion.stderr b/src/test/ui/async-await/in-trait/return-type-suggestion.stderr new file mode 100644 index 0000000000000..5a9b15e54a008 --- /dev/null +++ b/src/test/ui/async-await/in-trait/return-type-suggestion.stderr @@ -0,0 +1,23 @@ +warning: the feature `async_fn_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/return-type-suggestion.rs:3:12 + | +LL | #![feature(async_fn_in_trait)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #91611 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0308]: mismatched types + --> $DIR/return-type-suggestion.rs:8:9 + | +LL | Ok(()) + | ^^^^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found enum `Result` + | + = note: expected unit type `()` + found enum `Result<(), _>` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0308`. From c9bab74fb2cb494b99edba2f8b999dfe9281c548 Mon Sep 17 00:00:00 2001 From: Boxy Date: Mon, 5 Dec 2022 23:17:55 +0000 Subject: [PATCH 14/20] support `Expr` in `is_const_evaluatable` and `compute` --- .../src/traits/const_evaluatable.rs | 58 +++++++++++++------ .../rustc_trait_selection/src/traits/wf.rs | 19 +++++- .../const_kind_expr/wf_obligation.rs | 22 +++++++ .../const_kind_expr/wf_obligation.stderr | 20 +++++++ 4 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs create mode 100644 src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index e9e65336299e4..d01c6bac2963b 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -25,15 +25,13 @@ use crate::traits::ObligationCtxt; #[instrument(skip(infcx), level = "debug")] pub fn is_const_evaluatable<'tcx>( infcx: &InferCtxt<'tcx>, - ct: ty::Const<'tcx>, + unexpanded_ct: ty::Const<'tcx>, param_env: ty::ParamEnv<'tcx>, span: Span, ) -> Result<(), NotConstEvaluatable> { let tcx = infcx.tcx; - let uv = match ct.kind() { - ty::ConstKind::Unevaluated(uv) => uv, - // FIXME(generic_const_exprs): this seems wrong but I couldn't find a way to get this to trigger - ty::ConstKind::Expr(_) => bug!("unexpected expr in `is_const_evaluatable: {ct:?}"), + match unexpanded_ct.kind() { + ty::ConstKind::Unevaluated(_) | ty::ConstKind::Expr(_) => (), ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) @@ -43,7 +41,7 @@ pub fn is_const_evaluatable<'tcx>( }; if tcx.features().generic_const_exprs { - let ct = tcx.expand_abstract_consts(ct); + let ct = tcx.expand_abstract_consts(unexpanded_ct); let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() { tcx.def_kind(uv.def.did) == DefKind::AnonConst @@ -62,18 +60,40 @@ pub fn is_const_evaluatable<'tcx>( } } - let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); - match concrete { - Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error( - infcx - .tcx - .sess - .delay_span_bug(span, "Missing value for constant, but no error reported?"), - )), - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), - Ok(_) => Ok(()), + match unexpanded_ct.kind() { + ty::ConstKind::Expr(_) => { + // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but + // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it + // is evaluatable or not. For now we just ICE until this is implemented this. + Err(NotConstEvaluatable::Error(tcx.sess.delay_span_bug( + span, + "evaluating `ConstKind::Expr` is not currently supported", + ))) + } + ty::ConstKind::Unevaluated(uv) => { + let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); + match concrete { + Err(ErrorHandled::TooGeneric) => { + Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( + span, + "Missing value for constant, but no error reported?", + ))) + } + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Ok(_) => Ok(()), + } + } + _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), } } else { + let uv = match unexpanded_ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + ty::ConstKind::Expr(_) => { + bug!("`ConstKind::Expr` without `feature(generic_const_exprs)` enabled") + } + _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), + }; + // FIXME: We should only try to evaluate a given constant here if it is fully concrete // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. // @@ -92,7 +112,7 @@ pub fn is_const_evaluatable<'tcx>( && satisfied_from_param_env( tcx, infcx, - tcx.expand_abstract_consts(ct), + tcx.expand_abstract_consts(unexpanded_ct), param_env, ) => { @@ -152,6 +172,7 @@ fn satisfied_from_param_env<'tcx>( impl<'a, 'tcx> TypeVisitor<'tcx> for Visitor<'a, 'tcx> { type BreakTy = (); fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { + debug!("is_const_evaluatable: candidate={:?}", c); if let Ok(()) = self.infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new_in_snapshot(self.infcx); if let Ok(()) = ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()) @@ -187,7 +208,7 @@ fn satisfied_from_param_env<'tcx>( let result = b_ct.visit_with(&mut v); if let ControlFlow::Break(()) = result { - debug!("is_const_evaluatable: abstract_const ~~> ok"); + debug!("is_const_evaluatable: yes"); return true; } } @@ -195,5 +216,6 @@ fn satisfied_from_param_env<'tcx>( } } + debug!("is_const_evaluatable: no"); false } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0855d6d19736f..e47ba64245f50 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -476,9 +476,24 @@ impl<'tcx> WfPredicates<'tcx> { ty::Binder::dummy(ty::PredicateKind::WellFormed(ct.into())), )); } - // FIXME(generic_const_exprs): This seems wrong but I could not find a way to get this to trigger ty::ConstKind::Expr(_) => { - bug!("checking wfness of `ConstKind::Expr` is unsupported") + // FIXME(generic_const_exprs): this doesnt verify that given `Expr(N + 1)` the + // trait bound `typeof(N): Add` holds. This is currently unnecessary + // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated` + // which means that the `DefId` would have been typeck'd elsewhere. However in + // the future we may allow directly lowering to `ConstKind::Expr` in which case + // we would not be proving bounds we should. + + let predicate = + ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ct)); + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + predicate, + )); } ty::ConstKind::Error(_) diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs new file mode 100644 index 0000000000000..6093fc70b1696 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.rs @@ -0,0 +1,22 @@ +#![feature(generic_const_exprs, generic_arg_infer)] +#![allow(incomplete_features)] + +// minimized repro for #105205 +// +// the `foo::<_, L>` call results in a `WellFormed(_)` obligation and a +// `ConstEvaluatable(Unevaluated(_ + 1 + L))` obligation. Attempting to fulfill the latter +// unifies the `_` with `Expr(L - 1)` from the paramenv which turns the `WellFormed` +// obligation into `WellFormed(Expr(L - 1))` + +fn foo(_: [(); N + 1 + M]) {} + +fn ice() +where + [(); (L - 1) + 1 + L]:, +{ + foo::<_, L>([(); L + 1 + L]); + //~^ ERROR: mismatched types + //~^^ ERROR: unconstrained generic constant +} + +fn main() {} diff --git a/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr new file mode 100644 index 0000000000000..da5194696e657 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/const_kind_expr/wf_obligation.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/wf_obligation.rs:17:17 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^^^^^^^ expected `N + 1 + M`, found `L + 1 + L` + | + = note: expected constant `N + 1 + M` + found constant `L + 1 + L` + +error: unconstrained generic constant + --> $DIR/wf_obligation.rs:17:22 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); L + 1 + L]:` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From e940f845be13ff37d4ba28df5f40d74e5b0895a0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Dec 2022 00:00:01 +0000 Subject: [PATCH 15/20] drive-by: Default param for ToPredicate --- .../rustc_borrowck/src/type_check/canonical.rs | 6 ++---- compiler/rustc_middle/src/ty/mod.rs | 18 +++++++++--------- .../rustc_trait_selection/src/traits/mod.rs | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 1aad6738bba7a..3617bf58be9dd 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -121,9 +121,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn prove_predicates( &mut self, - predicates: impl IntoIterator< - Item = impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug, - >, + predicates: impl IntoIterator + std::fmt::Debug>, locations: Locations, category: ConstraintCategory<'tcx>, ) { @@ -135,7 +133,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn prove_predicate( &mut self, - predicate: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + std::fmt::Debug, + predicate: impl ToPredicate<'tcx> + std::fmt::Debug, locations: Locations, category: ConstraintCategory<'tcx>, ) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index dd4ab3e8d30bf..81847e2e4cab6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1150,8 +1150,8 @@ impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { } } -pub trait ToPredicate<'tcx, Predicate> { - fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate; +pub trait ToPredicate<'tcx, P = Predicate<'tcx>> { + fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P; } impl<'tcx, T> ToPredicate<'tcx, T> for T { @@ -1160,21 +1160,21 @@ impl<'tcx, T> ToPredicate<'tcx, T> for T { } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, PredicateKind<'tcx>> { +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(self) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Clause<'tcx> { +impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self))) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> { +impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx); @@ -1193,25 +1193,25 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTraitPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyRegionOutlivesPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::RegionOutlives(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyTypeOutlivesPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::TypeOutlives(p))).to_predicate(tcx) } } -impl<'tcx> ToPredicate<'tcx, Predicate<'tcx>> for PolyProjectionPredicate<'tcx> { +impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { self.map_bound(|p| PredicateKind::Clause(Clause::Projection(p))).to_predicate(tcx) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index c6818a4e57d42..d3cfd61e1956d 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -150,7 +150,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx, ty::Predicate<'tcx>> + TypeVisitable<'tcx>, + pred: impl ToPredicate<'tcx> + TypeVisitable<'tcx>, span: Span, ) -> bool { let has_non_region_infer = pred.has_non_region_infer(); From d2a80c157145d0c1e6fd6669862358de6cd89185 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Dec 2022 00:19:42 +0000 Subject: [PATCH 16/20] Avoid noting cause code (which is usually misc, b/c codegen) for opaque type reveal overflow --- .../src/traits/codegen.rs | 2 +- .../src/traits/error_reporting/mod.rs | 84 ++++++++++++++----- .../src/traits/error_reporting/suggestions.rs | 4 +- .../src/traits/project.rs | 12 ++- .../src/traits/query/normalize.rs | 14 ++-- .../src/traits/select/mod.rs | 13 +-- 6 files changed, 80 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index 61743d78e9e80..0102d268b42e1 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -70,7 +70,7 @@ pub fn codegen_select_candidate<'tcx>( // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. for err in errors { if let FulfillmentErrorCode::CodeCycle(cycle) = err.code { - infcx.err_ctxt().report_overflow_error_cycle(&cycle); + infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); } } return Err(CodegenObligationError::FulfillmentError); 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 56dea916b305f..80870d871d163 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -99,26 +99,36 @@ pub trait InferCtxtExt<'tcx> { } pub trait TypeErrCtxtExt<'tcx> { + fn report_overflow_error( + &self, + predicate: &T, + span: Span, + suggest_increasing_limit: bool, + mutate: impl FnOnce(&mut Diagnostic), + ) -> ! + where + T: fmt::Display + + TypeFoldable<'tcx> + + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, + >>::Error: std::fmt::Debug; + fn report_fulfillment_errors( &self, errors: &[FulfillmentError<'tcx>], body_id: Option, ) -> ErrorGuaranteed; - fn report_overflow_error( + fn report_overflow_obligation( &self, obligation: &Obligation<'tcx, T>, suggest_increasing_limit: bool, ) -> ! where - T: fmt::Display - + TypeFoldable<'tcx> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - >>::Error: std::fmt::Debug; + T: ToPredicate<'tcx> + Clone; fn suggest_new_overflow_limit(&self, err: &mut Diagnostic); - fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; + fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> !; /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, @@ -458,8 +468,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// occurrences in any case. fn report_overflow_error( &self, - obligation: &Obligation<'tcx, T>, + predicate: &T, + span: Span, suggest_increasing_limit: bool, + mutate: impl FnOnce(&mut Diagnostic), ) -> ! where T: fmt::Display @@ -467,8 +479,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, >>::Error: std::fmt::Debug, { - let predicate = self.resolve_vars_if_possible(obligation.predicate.clone()); + let predicate = self.resolve_vars_if_possible(predicate.clone()); let mut pred_str = predicate.to_string(); + if pred_str.len() > 50 { // We don't need to save the type to a file, we will be talking about this type already // in a separate note when we explain the obligation, so it will be available that way. @@ -483,7 +496,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } let mut err = struct_span_err!( self.tcx.sess, - obligation.cause.span, + span, E0275, "overflow evaluating the requirement `{}`", pred_str, @@ -493,20 +506,46 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_new_overflow_limit(&mut err); } - self.note_obligation_cause_code( - &mut err, - &obligation.predicate, - obligation.param_env, - obligation.cause.code(), - &mut vec![], - &mut Default::default(), - ); + mutate(&mut err); err.emit(); self.tcx.sess.abort_if_errors(); bug!(); } + /// Reports that an overflow has occurred and halts compilation. We + /// halt compilation unconditionally because it is important that + /// overflows never be masked -- they basically represent computations + /// whose result could not be truly determined and thus we can't say + /// if the program type checks or not -- and they are unusual + /// occurrences in any case. + fn report_overflow_obligation( + &self, + obligation: &Obligation<'tcx, T>, + suggest_increasing_limit: bool, + ) -> ! + where + T: ToPredicate<'tcx> + Clone, + { + let predicate = obligation.predicate.clone().to_predicate(self.tcx); + let predicate = self.resolve_vars_if_possible(predicate); + self.report_overflow_error( + &predicate, + obligation.cause.span, + suggest_increasing_limit, + |err| { + self.note_obligation_cause_code( + err, + &predicate, + obligation.param_env, + obligation.cause.code(), + &mut vec![], + &mut Default::default(), + ); + }, + ); + } + fn suggest_new_overflow_limit(&self, err: &mut Diagnostic) { let suggested_limit = match self.tcx.recursion_limit() { Limit(0) => Limit(2), @@ -521,11 +560,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } /// Reports that a cycle was detected which led to overflow and halts - /// compilation. This is equivalent to `report_overflow_error` except + /// compilation. This is equivalent to `report_overflow_obligation` except /// that we can give a more helpful error message (and, in particular, /// we do not suggest increasing the overflow limit, which is not /// going to help). - fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { let cycle = self.resolve_vars_if_possible(cycle.to_owned()); assert!(!cycle.is_empty()); @@ -533,7 +572,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // The 'deepest' obligation is most likely to have a useful // cause 'backtrace' - self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false); + self.report_overflow_obligation( + cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), + false, + ); } fn report_selection_error( @@ -1554,7 +1596,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { diag.emit(); } FulfillmentErrorCode::CodeCycle(ref cycle) => { - self.report_overflow_error_cycle(cycle); + self.report_overflow_obligation_cycle(cycle); } } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 1740128727a5a..6ea54b625bbc0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -298,7 +298,7 @@ pub trait TypeErrCtxtExt<'tcx> { obligated_types: &mut Vec>, seen_requirements: &mut FxHashSet, ) where - T: fmt::Display + ToPredicate<'tcx, T>; + T: fmt::Display + ToPredicate<'tcx>; /// Suggest to await before try: future? => future.await? fn suggest_await_before_try( @@ -2353,7 +2353,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { obligated_types: &mut Vec>, seen_requirements: &mut FxHashSet, ) where - T: fmt::Display, + T: fmt::Display + ToPredicate<'tcx>, { let tcx = self.tcx; match *cause_code { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 051660be9c474..1790ef5b4814e 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -504,14 +504,12 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { Reveal::All => { let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.depth) { - let obligation = Obligation::with_depth( - self.tcx(), - self.cause.clone(), - recursion_limit.0, - self.param_env, - ty, + self.selcx.infcx.err_ctxt().report_overflow_error( + &ty, + self.cause.span, + true, + |_| {}, ); - self.selcx.infcx.err_ctxt().report_overflow_error(&obligation, true); } let substs = substs.fold_with(self); diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index f899321fc01e1..7ad532d8a3464 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,7 +7,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; -use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; @@ -214,14 +214,12 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let substs = substs.try_fold_with(self)?; let recursion_limit = self.tcx().recursion_limit(); if !recursion_limit.value_within_limit(self.anon_depth) { - let obligation = Obligation::with_depth( - self.tcx(), - self.cause.clone(), - recursion_limit.0, - self.param_env, - ty, + self.infcx.err_ctxt().report_overflow_error( + &ty, + self.cause.span, + true, + |_| {}, ); - self.infcx.err_ctxt().report_overflow_error(&obligation, true); } let generic_ty = self.tcx().bound_type_of(def_id); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 8835f2cc1b97a..035deb6163981 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -43,7 +43,6 @@ use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; @@ -1313,10 +1312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { error_obligation: &Obligation<'tcx, T>, ) -> Result<(), OverflowError> where - T: fmt::Display - + TypeFoldable<'tcx> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - >>::Error: std::fmt::Debug, + T: ToPredicate<'tcx> + Clone, { if !self.infcx.tcx.recursion_limit().value_within_limit(depth) { match self.query_mode { @@ -1324,7 +1320,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(e) = self.infcx.tainted_by_errors() { return Err(OverflowError::Error(e)); } - self.infcx.err_ctxt().report_overflow_error(error_obligation, true); + self.infcx.err_ctxt().report_overflow_obligation(error_obligation, true); } TraitQueryMode::Canonical => { return Err(OverflowError::Canonical); @@ -1345,10 +1341,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { error_obligation: &Obligation<'tcx, V>, ) -> Result<(), OverflowError> where - V: fmt::Display - + TypeFoldable<'tcx> - + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>, - >>::Error: std::fmt::Debug, + V: ToPredicate<'tcx> + Clone, { self.check_recursion_depth(obligation.recursion_depth, error_obligation) } From 6dc2aa26759578f09974041f19767a75b8c6320e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Dec 2022 01:52:02 +0000 Subject: [PATCH 17/20] Add GenericParamDef::to_error and InternalSubsts::extend_with_error --- compiler/rustc_middle/src/ty/generics.rs | 14 ++++++++++++++ compiler/rustc_middle/src/ty/sty.rs | 15 ++------------- compiler/rustc_middle/src/ty/subst.rs | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index a8da93e4c69b0..48329da3e6332 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -101,6 +101,20 @@ impl GenericParamDef { _ => None, } } + + pub fn to_error<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + preceding_substs: &[ty::GenericArg<'tcx>], + ) -> ty::GenericArg<'tcx> { + match &self.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), + ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(), + ty::GenericParamDefKind::Const { .. } => { + tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into() + } + } + } } #[derive(Default)] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8e69824e6c790..1eec119616ea7 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -728,19 +728,8 @@ impl<'tcx> PolyExistentialPredicate<'tcx> { } else { // If this is an ill-formed auto trait, then synthesize // new error substs for the missing generics. - let err_substs = ty::InternalSubsts::for_item(tcx, did, |def, substs| { - if def.index == 0 { - self_ty.into() - } else { - match &def.kind { - ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(), - ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(), - ty::GenericParamDefKind::Const { .. } => tcx - .const_error(tcx.bound_type_of(def.def_id).subst(tcx, substs)) - .into(), - } - } - }); + let err_substs = + ty::InternalSubsts::extend_with_error(tcx, did, &[self_ty.into()]); tcx.mk_trait_ref(did, err_substs) }; self.rebind(trait_ref).without_const().to_predicate(tcx) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 141c8354c183d..23507d2804592 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -352,6 +352,22 @@ impl<'tcx> InternalSubsts<'tcx> { } } + // Extend an `original_substs` list to the full number of substs expected by `def_id`, + // filling in the missing parameters with error ty/ct or 'static regions. + pub fn extend_with_error( + tcx: TyCtxt<'tcx>, + def_id: DefId, + original_substs: &[GenericArg<'tcx>], + ) -> SubstsRef<'tcx> { + ty::InternalSubsts::for_item(tcx, def_id, |def, substs| { + if let Some(subst) = original_substs.get(def.index as usize) { + *subst + } else { + def.to_error(tcx, substs) + } + }) + } + #[inline] pub fn types(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { self.iter() From eff76455fd4061f268546a706d3dfb1cc34ecb48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 5 Dec 2022 16:13:32 -0800 Subject: [PATCH 18/20] Avoid ICE by accounting for missing type Fix #105330 --- .../src/traits/error_reporting/mod.rs | 2 +- src/test/ui/issues/issue-105330.rs | 21 ++++ src/test/ui/issues/issue-105330.stderr | 109 ++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-105330.rs create mode 100644 src/test/ui/issues/issue-105330.stderr 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 3379279dd1544..fcf0a94462e10 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1607,7 +1607,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectCastObligation(..) | ObligationCauseCode::OpaqueType ); - let expected_ty = data.term.ty().unwrap(); + let expected_ty = data.term.ty().unwrap_or_else(|| self.tcx.ty_error()); // constrain inference variables a bit more to nested obligations from normalize so // we can have more helpful errors. diff --git a/src/test/ui/issues/issue-105330.rs b/src/test/ui/issues/issue-105330.rs new file mode 100644 index 0000000000000..86e45f10b0e16 --- /dev/null +++ b/src/test/ui/issues/issue-105330.rs @@ -0,0 +1,21 @@ +pub trait TraitWAssocConst { + const A: usize; +} +pub struct Demo {} + +impl TraitWAssocConst for impl Demo { //~ ERROR E0404 + //~^ ERROR E0562 + pubconst A: str = 32; //~ ERROR expected one of +} + +fn foo>() { //~ ERROR E0658 + foo::()(); //~ ERROR E0271 + //~^ ERROR E0618 + //~| ERROR E0277 +} + +fn main>() { //~ ERROR E0131 + //~^ ERROR E0658 + foo::(); //~ ERROR E0277 + //~^ ERROR E0271 +} diff --git a/src/test/ui/issues/issue-105330.stderr b/src/test/ui/issues/issue-105330.stderr new file mode 100644 index 0000000000000..92f2ccb6544b1 --- /dev/null +++ b/src/test/ui/issues/issue-105330.stderr @@ -0,0 +1,109 @@ +error: expected one of `!` or `::`, found `A` + --> $DIR/issue-105330.rs:8:14 + | +LL | impl TraitWAssocConst for impl Demo { + | - while parsing this item list starting here +LL | +LL | pubconst A: str = 32; + | ^ expected one of `!` or `::` +LL | } + | - the item list ends here + +error[E0404]: expected trait, found struct `Demo` + --> $DIR/issue-105330.rs:6:32 + | +LL | impl TraitWAssocConst for impl Demo { + | ^^^^ not a trait + +error[E0658]: associated const equality is incomplete + --> $DIR/issue-105330.rs:11:28 + | +LL | fn foo>() { + | ^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + +error[E0658]: associated const equality is incomplete + --> $DIR/issue-105330.rs:17:29 + | +LL | fn main>() { + | ^^^^ + | + = note: see issue #92827 for more information + = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable + +error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type + --> $DIR/issue-105330.rs:6:27 + | +LL | impl TraitWAssocConst for impl Demo { + | ^^^^^^^^^ + +error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied + --> $DIR/issue-105330.rs:12:11 + | +LL | foo::()(); + | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:11 + | +LL | fn foo>() { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error[E0271]: type mismatch resolving `::A == 32` + --> $DIR/issue-105330.rs:12:11 + | +LL | foo::()(); + | ^^^^ types differ + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:28 + | +LL | fn foo>() { + | ^^^^ required by this bound in `foo` + +error[E0618]: expected function, found `()` + --> $DIR/issue-105330.rs:12:5 + | +LL | fn foo>() { + | ----------------------------------- `foo::` defined here returns `()` +LL | foo::()(); + | ^^^^^^^^^^^^^-- + | | + | call expression requires function + +error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied + --> $DIR/issue-105330.rs:19:11 + | +LL | foo::(); + | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:11 + | +LL | fn foo>() { + | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error[E0271]: type mismatch resolving `::A == 32` + --> $DIR/issue-105330.rs:19:11 + | +LL | foo::(); + | ^^^^ types differ + | +note: required by a bound in `foo` + --> $DIR/issue-105330.rs:11:28 + | +LL | fn foo>() { + | ^^^^ required by this bound in `foo` + +error[E0131]: `main` function is not allowed to have generic parameters + --> $DIR/issue-105330.rs:17:8 + | +LL | fn main>() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658. +For more information about an error, try `rustc --explain E0131`. From e802165dfe346e92a3ef9b0e49634943df862a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 28 Nov 2022 00:03:57 -0800 Subject: [PATCH 19/20] On E0195 point at where clause lifetime bounds Fix #104733 --- .../locales/en-US/hir_analysis.ftl | 2 + .../src/check/compare_method.rs | 51 +++++++++++++++---- compiler/rustc_hir_analysis/src/errors.rs | 4 ++ ...ssing-where-clause-lifetimes-from-trait.rs | 30 +++++++++++ ...g-where-clause-lifetimes-from-trait.stderr | 27 ++++++++++ 5 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs create mode 100644 src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl index 0894bbcaad474..a5cb8a88819df 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -17,6 +17,8 @@ hir_analysis_lifetimes_or_bounds_mismatch_on_trait = lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration .label = lifetimes do not match {$item_kind} in trait .generics_label = lifetimes in impl do not match this {$item_kind} in trait + .where_label = this `where` clause might not match the one in the trait + .bounds_label = this bound might be missing in the impl hir_analysis_drop_impl_on_wrong_item = the `Drop` trait may only be implemented for local structs, enums, and unions diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 82a77416a190c..1d6f9b2917651 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -751,17 +751,45 @@ fn check_region_bounds_on_impl_item<'tcx>( .get_generics(impl_m.def_id.expect_local()) .expect("expected impl item to have generics or else we can't compare them") .span; - let generics_span = if let Some(local_def_id) = trait_m.def_id.as_local() { - Some( - tcx.hir() - .get_generics(local_def_id) - .expect("expected trait item to have generics or else we can't compare them") - .span, - ) - } else { - None - }; + let mut generics_span = None; + let mut bounds_span = vec![]; + let mut where_span = None; + if let Some(trait_node) = tcx.hir().get_if_local(trait_m.def_id) + && let Some(trait_generics) = trait_node.generics() + { + generics_span = Some(trait_generics.span); + // FIXME: we could potentially look at the impl's bounds to not point at bounds that + // *are* present in the impl. + for p in trait_generics.predicates { + if let hir::WherePredicate::BoundPredicate(pred) = p { + for b in pred.bounds { + if let hir::GenericBound::Outlives(lt) = b { + bounds_span.push(lt.ident.span); + } + } + } + } + if let Some(impl_node) = tcx.hir().get_if_local(impl_m.def_id) + && let Some(impl_generics) = impl_node.generics() + { + let mut impl_bounds = 0; + for p in impl_generics.predicates { + if let hir::WherePredicate::BoundPredicate(pred) = p { + for b in pred.bounds { + if let hir::GenericBound::Outlives(_) = b { + impl_bounds += 1; + } + } + } + } + if impl_bounds == bounds_span.len() { + bounds_span = vec![]; + } else if impl_generics.has_where_clause_predicates { + where_span = Some(impl_generics.where_clause_span); + } + } + } let reported = tcx .sess .create_err(LifetimesOrBoundsMismatchOnTrait { @@ -769,9 +797,10 @@ fn check_region_bounds_on_impl_item<'tcx>( item_kind: assoc_item_kind_str(impl_m), ident: impl_m.ident(tcx), generics_span, + bounds_span, + where_span, }) .emit_unless(delay); - return Err(reported); } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index afbb27155a2f5..5156d432b5b37 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -43,6 +43,10 @@ pub struct LifetimesOrBoundsMismatchOnTrait { pub span: Span, #[label(generics_label)] pub generics_span: Option, + #[label(where_label)] + pub where_span: Option, + #[label(bounds_label)] + pub bounds_span: Vec, pub item_kind: &'static str, pub ident: Ident, } diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs new file mode 100644 index 0000000000000..1994120ce1466 --- /dev/null +++ b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs @@ -0,0 +1,30 @@ +trait Trait { + fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a; +} + +impl Trait<()> for () { + fn foo<'a, K>(self, _: (), _: K) where { //~ ERROR E0195 + todo!(); + } +} + +struct State; + +trait Foo { + fn foo<'a>(&self, state: &'a State) -> &'a T + where + T: 'a; +} + +impl Foo for F +where + F: Fn(&State) -> &T, +{ + fn foo<'a>(&self, state: &'a State) -> &'a T { //~ ERROR E0195 + self(state) + } +} + +fn main() { + ().foo((), ()); +} diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr new file mode 100644 index 0000000000000..3a02369e2ee8a --- /dev/null +++ b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr @@ -0,0 +1,27 @@ +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:6:11 + | +LL | fn foo<'a, K>(self, _: T, _: K) where T: 'a, K: 'a; + | ------- -- -- this bound might be missing in the impl + | | | + | | this bound might be missing in the impl + | lifetimes in impl do not match this method in trait +... +LL | fn foo<'a, K>(self, _: (), _: K) where { + | ^^^^^^^ lifetimes do not match method in trait + +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:23:11 + | +LL | fn foo<'a>(&self, state: &'a State) -> &'a T + | ---- lifetimes in impl do not match this method in trait +LL | where +LL | T: 'a; + | -- this bound might be missing in the impl +... +LL | fn foo<'a>(&self, state: &'a State) -> &'a T { + | ^^^^ lifetimes do not match method in trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0195`. From 9ffd0868653ad5113962c6f2a42d5061afbcf493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 28 Nov 2022 14:04:46 -0800 Subject: [PATCH 20/20] review comment: add test case --- .../impl-missing-where-clause-lifetimes-from-trait.rs | 8 ++++++++ ...l-missing-where-clause-lifetimes-from-trait.stderr | 11 ++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs index 1994120ce1466..dcdbd02287371 100644 --- a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs +++ b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.rs @@ -25,6 +25,14 @@ where } } +trait Bar { + fn foo<'a>(&'a self) {} +} + +impl Bar for () { + fn foo<'a: 'a>(&'a self) {} //~ ERROR E0195 +} + fn main() { ().foo((), ()); } diff --git a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr index 3a02369e2ee8a..e26cb22163f1e 100644 --- a/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr +++ b/src/test/ui/trait-bounds/impl-missing-where-clause-lifetimes-from-trait.stderr @@ -22,6 +22,15 @@ LL | T: 'a; LL | fn foo<'a>(&self, state: &'a State) -> &'a T { | ^^^^ lifetimes do not match method in trait -error: aborting due to 2 previous errors +error[E0195]: lifetime parameters or bounds on method `foo` do not match the trait declaration + --> $DIR/impl-missing-where-clause-lifetimes-from-trait.rs:33:11 + | +LL | fn foo<'a>(&'a self) {} + | ---- lifetimes in impl do not match this method in trait +... +LL | fn foo<'a: 'a>(&'a self) {} + | ^^^^^^^^ lifetimes do not match method in trait + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0195`.