From fe4aec1c4da0e92dbb727ebe5a2ee8951a6a45d9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 16 Jun 2023 13:45:03 +0000 Subject: [PATCH 01/14] Simplify `Span::source_callee` impl --- compiler/rustc_span/src/lib.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index eae3f0fa041dd..aed1fcd3d5760 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -65,11 +65,11 @@ use rustc_data_structures::sync::{Lock, Lrc}; use std::borrow::Cow; use std::cmp::{self, Ordering}; -use std::fmt; use std::hash::Hash; use std::ops::{Add, Range, Sub}; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::{fmt, iter}; use md5::Digest; use md5::Md5; @@ -733,12 +733,15 @@ impl Span { /// else returns the `ExpnData` for the macro definition /// corresponding to the source callsite. pub fn source_callee(self) -> Option { - fn source_callee(expn_data: ExpnData) -> ExpnData { - let next_expn_data = expn_data.call_site.ctxt().outer_expn_data(); - if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data } - } let expn_data = self.ctxt().outer_expn_data(); - if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None } + + // Create an iterator of call site expansions + iter::successors(Some(expn_data), |expn_data| { + Some(expn_data.call_site.ctxt().outer_expn_data()) + }) + // Find the last expansion which is not root + .take_while(|expn_data| !expn_data.is_root()) + .last() } /// Checks if a span is "internal" to a macro in which `#[unstable]` @@ -777,7 +780,7 @@ impl Span { pub fn macro_backtrace(mut self) -> impl Iterator { let mut prev_span = DUMMY_SP; - std::iter::from_fn(move || { + iter::from_fn(move || { loop { let expn_data = self.ctxt().outer_expn_data(); if expn_data.is_root() { From c4c428b6da234aea4aa639fac73828792d064a07 Mon Sep 17 00:00:00 2001 From: David Weikersdorfer <517608+Danvil@users.noreply.github.com> Date: Sun, 18 Jun 2023 00:46:51 -0700 Subject: [PATCH 02/14] Use BorrowFlag instead of explicit isize The integer type tracking borrow count has a typedef called `BorrowFlag`. This type should be used instead of explicit `isize`. --- library/core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c1cc892eb8607..b1b15e84dbf18 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1756,7 +1756,7 @@ impl<'b> BorrowRefMut<'b> { let borrow = self.borrow.get(); debug_assert!(is_writing(borrow)); // Prevent the borrow counter from underflowing. - assert!(borrow != isize::MIN); + assert!(borrow != BorrowFlag::MIN); self.borrow.set(borrow - 1); BorrowRefMut { borrow: self.borrow } } From 09707ee12a29856453782f7dc41cfef49749e9de Mon Sep 17 00:00:00 2001 From: David Weikersdorfer <517608+Danvil@users.noreply.github.com> Date: Sun, 18 Jun 2023 01:14:45 -0700 Subject: [PATCH 03/14] Same for BorrowRef --- library/core/src/cell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index b1b15e84dbf18..909b32547e74c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1374,7 +1374,7 @@ impl Clone for BorrowRef<'_> { debug_assert!(is_reading(borrow)); // Prevent the borrow counter from overflowing into // a writing borrow. - assert!(borrow != isize::MAX); + assert!(borrow != BorrowFlag::MAX); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } From 94f7a7931c035473565c1b2ec0a6c2ffaa3b4f79 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Wed, 5 Apr 2023 13:06:49 +0200 Subject: [PATCH 04/14] [doc] poll_fn: explain how to pin captured state safely MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Usage of `Pin::new_unchecked(&mut …)` is dangerous with `poll_fn`, even though the `!Unpin`-infectiousness has made things smoother. Nonetheless, there are easy ways to avoid the need for any `unsafe` altogether, be it through `Box::pin`ning, or the `pin!` macro. Since the latter only works within an `async` context, showing an example artifically introducing one ought to help people navigate this subtlety with safety and confidence. --- library/core/src/future/poll_fn.rs | 87 ++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 90cb797391a08..d27a9dfc176e3 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -24,6 +24,93 @@ use crate::task::{Context, Poll}; /// assert_eq!(read_future.await, "Hello, World!".to_owned()); /// # } /// ``` +/// +/// ## Capturing a pinned state +/// +/// Example of a closure wrapping inner futures: +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select( +/// a: impl Future, +/// b: impl Future, +/// ) -> impl Future +/// { +/// let (mut a, mut b) = (Box::pin(a), Box::pin(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }) +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// +/// let a = future::pending(); +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 27); +/// +/// let a = async { 42 }; +/// let b = async { 27 }; +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); // biased towards `a` in case of tie! +/// # } +/// ``` +/// +/// This time without [`Box::pin`]ning: +/// +/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin +/// +/// ``` +/// # async fn run() { +/// use core::future::{self, Future}; +/// use core::pin::pin; +/// use core::task::Poll; +/// +/// /// Resolves to the first future that completes. In the event of a tie, `a` wins. +/// fn naive_select( +/// a: impl Future, +/// b: impl Future, +/// ) -> impl Future +/// { +/// async { +/// let (mut a, mut b) = (pin!(a), pin!(b)); +/// future::poll_fn(move |cx| { +/// if let Poll::Ready(r) = a.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else if let Poll::Ready(r) = b.as_mut().poll(cx) { +/// Poll::Ready(r) +/// } else { +/// Poll::Pending +/// } +/// }).await +/// } +/// } +/// +/// let a = async { 42 }; +/// let b = future::pending(); +/// let v = naive_select(a, b).await; +/// assert_eq!(v, 42); +/// # } +/// ``` +/// +/// - Notice how, by virtue of being in an `async` context, we have been able to make the [`pin!`] +/// macro work, thereby avoiding any need for the `unsafe` +/// [Pin::new_unchecked](&mut fut) constructor. +/// +/// [`pin!`]: crate::pin::pin! #[stable(feature = "future_poll_fn", since = "1.64.0")] pub fn poll_fn(f: F) -> PollFn where From 8fa9003621d0031a76b208b277c7832a06e1570a Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 18 Jun 2023 07:19:19 +0100 Subject: [PATCH 05/14] Add translatable diagnostic for changing import binding --- compiler/rustc_resolve/messages.ftl | 3 +++ compiler/rustc_resolve/src/diagnostics.rs | 11 +++-------- compiler/rustc_resolve/src/errors.rs | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 539b88aa9d342..2952f82e2de30 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -262,3 +262,6 @@ resolve_variable_bound_with_different_mode = variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` .label = bound in different ways .first_binding_span = first binding + +resolve_change_import_binding = + you can use `as` to change the binding name of the import diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e42b2df1a5ab8..0c780672ea3ad 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -30,6 +30,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::ThinVec; +use crate::errors::{ChangeImportBinding, ChangeImportBindingSuggestion}; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; @@ -376,16 +377,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { _ => unreachable!(), } - let rename_msg = "you can use `as` to change the binding name of the import"; if let Some(suggestion) = suggestion { - err.span_suggestion( - binding_span, - rename_msg, - suggestion, - Applicability::MaybeIncorrect, - ); + err.subdiagnostic(ChangeImportBindingSuggestion { span: binding_span, suggestion }); } else { - err.span_label(binding_span, rename_msg); + err.subdiagnostic(ChangeImportBinding { span: binding_span }); } } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e88cbb955b556..b7b5e9d15bcaf 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -586,3 +586,22 @@ pub(crate) enum ParamKindInEnumDiscriminant { #[note(resolve_lifetime_param_in_enum_discriminant)] Lifetime, } + +#[derive(Subdiagnostic)] +#[label(resolve_change_import_binding)] +pub(crate) struct ChangeImportBinding { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_change_import_binding, + code = "{suggestion}", + applicability = "maybe-incorrect" +)] +pub(crate) struct ChangeImportBindingSuggestion { + #[primary_span] + pub(crate) span: Span, + pub(crate) suggestion: String, +} From 50c971a0b7e645754e758709b399c6da0205167a Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 18 Jun 2023 09:14:25 +0100 Subject: [PATCH 06/14] Add translatable diagnostic for invalid imports --- compiler/rustc_resolve/messages.ftl | 3 +++ compiler/rustc_resolve/src/errors.rs | 8 ++++++++ compiler/rustc_resolve/src/late.rs | 10 +++++----- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 2952f82e2de30..3702f03269e24 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -265,3 +265,6 @@ resolve_variable_bound_with_different_mode = resolve_change_import_binding = you can use `as` to change the binding name of the import + +resolve_imports_cannot_refer_to = + imports cannot refer to {$what} \ No newline at end of file diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index b7b5e9d15bcaf..a7a8aa8b9577b 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -605,3 +605,11 @@ pub(crate) struct ChangeImportBindingSuggestion { pub(crate) span: Span, pub(crate) suggestion: String, } + +#[derive(Diagnostic)] +#[diag(resolve_imports_cannot_refer_to)] +pub(crate) struct ImportsCannotReferTo<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) what: &'a str, +} diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ddd75ea3b33e0..e700e8c9ce086 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,6 +6,7 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. +use crate::errors::ImportsCannotReferTo; use crate::BindingKey; use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; @@ -2244,12 +2245,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { _ => &[TypeNS], }; let report_error = |this: &Self, ns| { - let what = if ns == TypeNS { "type parameters" } else { "local variables" }; if this.should_report_errs() { - this.r - .tcx - .sess - .span_err(ident.span, format!("imports cannot refer to {}", what)); + let what = if ns == TypeNS { "type parameters" } else { "local variables" }; + + let err = ImportsCannotReferTo { span: ident.span, what }; + this.r.tcx.sess.create_err(err).emit(); } }; From 355a6895425354ee2caf5df99fbe4ec9d136a460 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 18 Jun 2023 12:15:17 +0100 Subject: [PATCH 07/14] Add translatable diagnostic for cannot find in this scope --- compiler/rustc_resolve/messages.ftl | 5 ++++- compiler/rustc_resolve/src/errors.rs | 9 +++++++++ compiler/rustc_resolve/src/macros.rs | 13 ++++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 3702f03269e24..8c199ff0150b4 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -267,4 +267,7 @@ resolve_change_import_binding = you can use `as` to change the binding name of the import resolve_imports_cannot_refer_to = - imports cannot refer to {$what} \ No newline at end of file + imports cannot refer to {$what} + +resolve_cannot_find_ident_in_this_scope = + cannot find {$expected} `{$ident}` in this scope diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index a7a8aa8b9577b..0f9039912ed01 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -613,3 +613,12 @@ pub(crate) struct ImportsCannotReferTo<'a> { pub(crate) span: Span, pub(crate) what: &'a str, } + +#[derive(Diagnostic)] +#[diag(resolve_cannot_find_ident_in_this_scope)] +pub(crate) struct CannotFindIdentInThisScope<'a> { + #[primary_span] + pub(crate) span: Span, + pub(crate) expected: &'a str, + pub(crate) ident: Ident, +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ca4f3331b9a2d..4dcef8f6efd99 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1,7 +1,9 @@ //! A bunch of methods and structures more or less related to resolving macros and //! interface provided by `Resolver` to macro expander. -use crate::errors::{self, AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive}; +use crate::errors::{ + self, AddAsNonDerive, CannotFindIdentInThisScope, MacroExpectedFound, RemoveSurroundingDerive, +}; use crate::Namespace::*; use crate::{BuiltinMacroState, Determinacy}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; @@ -793,8 +795,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Err(..) => { let expected = kind.descr_expected(); - let msg = format!("cannot find {} `{}` in this scope", expected, ident); - let mut err = self.tcx.sess.struct_span_err(ident.span, msg); + + let mut err = self.tcx.sess.create_err(CannotFindIdentInThisScope { + span: ident.span, + expected, + ident, + }); + self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); err.emit(); } From 4b5a5a4529d86cb0ff6abd539cbddebe81e0c0d1 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 18 Jun 2023 12:26:31 +0100 Subject: [PATCH 08/14] Add translatable diagnostic for various strings in resolve::unresolved_macro_suggestions --- compiler/rustc_resolve/messages.ftl | 13 ++++++++++ compiler/rustc_resolve/src/diagnostics.rs | 20 ++++++++------- compiler/rustc_resolve/src/errors.rs | 31 +++++++++++++++++++++++ 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 8c199ff0150b4..75799aa8b70cd 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -271,3 +271,16 @@ resolve_imports_cannot_refer_to = resolve_cannot_find_ident_in_this_scope = cannot find {$expected} `{$ident}` in this scope + +resolve_explicit_unsafe_traits = + unsafe traits like `{$ident}` should be implemented explicitly + +resolve_added_macro_use = + have you added the `#[macro_use]` on the module/import? + +resolve_consider_adding_a_derive = + consider adding a derive + .suggestion = FIXME + +resolve_consider_adding_a_derive_enum = + consider adding `#[derive(Default)]` to this enum diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 0c780672ea3ad..2a22e1ba242c8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -30,7 +30,10 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::ThinVec; -use crate::errors::{ChangeImportBinding, ChangeImportBindingSuggestion}; +use crate::errors::{ + AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, + ConsiderAddingADeriveEnum, ExplicitUnsafeTraits, +}; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; @@ -1377,12 +1380,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ); if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { - let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); - err.span_note(ident.span, msg); + err.subdiagnostic(ExplicitUnsafeTraits { span: ident.span, ident }); return; } if self.macro_names.contains(&ident.normalize_to_macros_2_0()) { - err.help("have you added the `#[macro_use]` on the module/import?"); + err.subdiagnostic(AddedMacroUse); return; } if ident.name == kw::Default @@ -1392,12 +1394,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); if let Ok(head) = source_map.span_to_snippet(head_span) { - err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect); + err.subdiagnostic(ConsiderAddingADerive { + span: head_span, + suggestion: format!("#[derive(Default)]\n{head}") + }); } else { - err.span_help( - head_span, - "consider adding `#[derive(Default)]` to this enum", - ); + err.subdiagnostic(ConsiderAddingADeriveEnum { span: head_span }); } } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 0f9039912ed01..fb70fbe2c1faf 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -622,3 +622,34 @@ pub(crate) struct CannotFindIdentInThisScope<'a> { pub(crate) expected: &'a str, pub(crate) ident: Ident, } + +#[derive(Subdiagnostic)] +#[note(resolve_explicit_unsafe_traits)] +pub(crate) struct ExplicitUnsafeTraits { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + +#[derive(Subdiagnostic)] +#[help(resolve_added_macro_use)] +pub(crate) struct AddedMacroUse; + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_consider_adding_a_derive, + code = "{suggestion}", + applicability = "maybe-incorrect" +)] +pub(crate) struct ConsiderAddingADerive { + #[primary_span] + pub(crate) span: Span, + pub(crate) suggestion: String, +} + +#[derive(Subdiagnostic)] +#[help(resolve_consider_adding_a_derive_enum)] +pub(crate) struct ConsiderAddingADeriveEnum { + #[primary_span] + pub(crate) span: Span, +} From c07b50a2137277a518799de3e5755cd52b9ab959 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Sun, 18 Jun 2023 13:10:05 +0100 Subject: [PATCH 09/14] Fix tidy --- compiler/rustc_resolve/messages.ftl | 43 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 75799aa8b70cd..062f9e85a9c22 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -5,6 +5,9 @@ resolve_add_as_non_derive = add as non-Derive macro `#[{$macro_path}]` +resolve_added_macro_use = + have you added the `#[macro_use]` on the module/import? + resolve_ampersand_used_without_explicit_lifetime_name = `&` without an explicit lifetime name cannot be used here .note = explicit lifetime name needed here @@ -45,9 +48,21 @@ resolve_cannot_capture_dynamic_environment_in_fn_item = can't capture dynamic environment in a fn item .help = use the `|| {"{"} ... {"}"}` closure form instead +resolve_cannot_find_ident_in_this_scope = + cannot find {$expected} `{$ident}` in this scope + resolve_cannot_use_self_type_here = can't use `Self` here +resolve_change_import_binding = + you can use `as` to change the binding name of the import + +resolve_consider_adding_a_derive = + consider adding a derive + +resolve_consider_adding_a_derive_enum = + consider adding `#[derive(Default)]` to this enum + resolve_const_not_member_of_trait = const `{$const_}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` @@ -74,6 +89,9 @@ resolve_expected_found = expected module, found {$res} `{$path_str}` .label = not a module +resolve_explicit_unsafe_traits = + unsafe traits like `{$ident}` should be implemented explicitly + resolve_forward_declared_generic_param = generic parameters with a default cannot use forward declared identifiers .label = defaulted generic parameters cannot be forward declared @@ -96,6 +114,9 @@ resolve_ident_bound_more_than_once_in_same_pattern = resolve_imported_crate = `$crate` may not be imported +resolve_imports_cannot_refer_to = + imports cannot refer to {$what} + resolve_indeterminate = cannot determine resolution for the visibility @@ -262,25 +283,3 @@ resolve_variable_bound_with_different_mode = variable `{$variable_name}` is bound inconsistently across alternatives separated by `|` .label = bound in different ways .first_binding_span = first binding - -resolve_change_import_binding = - you can use `as` to change the binding name of the import - -resolve_imports_cannot_refer_to = - imports cannot refer to {$what} - -resolve_cannot_find_ident_in_this_scope = - cannot find {$expected} `{$ident}` in this scope - -resolve_explicit_unsafe_traits = - unsafe traits like `{$ident}` should be implemented explicitly - -resolve_added_macro_use = - have you added the `#[macro_use]` on the module/import? - -resolve_consider_adding_a_derive = - consider adding a derive - .suggestion = FIXME - -resolve_consider_adding_a_derive_enum = - consider adding `#[derive(Default)]` to this enum From 493b18b65380b36baa4b9997417e1c33cbc4fdb2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 18 Jun 2023 20:56:30 +0000 Subject: [PATCH 10/14] Continue folding in query normalizer on weak aliases --- .../src/traits/query/normalize.rs | 8 ++++++-- tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2d97a80822581..1b6e92946c4be 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -322,8 +322,12 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> }; // `tcx.normalize_projection_ty` may normalize to a type that still has // unevaluated consts, so keep normalizing here if that's the case. - if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { - res.try_super_fold_with(self)? + // Similarly, `tcx.normalize_weak_ty` will only unwrap one layer of type + // and we need to continue folding it to reveal the TAIT behind it. + if res != ty + && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak) + { + res.try_fold_with(self)? } else { res } diff --git a/tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs b/tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs new file mode 100644 index 0000000000000..44158349fdd64 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/debug-ty-with-weak.rs @@ -0,0 +1,12 @@ +// compile-flags: --crate-type=lib -Cdebuginfo=2 +// build-pass + +#![feature(type_alias_impl_trait)] + +type Debuggable = impl core::fmt::Debug; + +static mut TEST: Option = None; + +fn foo() -> Debuggable { + 0u32 +} From d43683f2e905d34ab289882c16124deb5ed09edd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 18 Jun 2023 22:10:07 +0000 Subject: [PATCH 11/14] Treat TAIT equation as always ambiguous in coherence --- compiler/rustc_infer/src/infer/combine.rs | 11 +++---- .../tests/ui/from_over_into_unfixable.rs | 6 ---- .../tests/ui/from_over_into_unfixable.stderr | 33 ++++++++++++++----- ...coherence-treats-tait-ambig.current.stderr | 13 ++++++++ .../coherence-treats-tait-ambig.next.stderr | 13 ++++++++ .../impl-trait/coherence-treats-tait-ambig.rs | 19 +++++++++++ 6 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr create mode 100644 tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr create mode 100644 tests/ui/impl-trait/coherence-treats-tait-ambig.rs diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 152c56572b691..12cb86d7d72bd 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -124,13 +124,10 @@ impl<'tcx> InferCtxt<'tcx> { } // During coherence, opaque types should be treated as *possibly* - // equal to each other, even if their generic params differ, as - // they could resolve to the same hidden type, even for different - // generic params. - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }), - ) if self.intercrate && a_def_id == b_def_id => { + // equal to any other type (except for possibly itself). This is an + // extremely heavy hammer, but can be relaxed in a fowards-compatible + // way later. + (&ty::Alias(ty::Opaque, _), _) | (_, &ty::Alias(ty::Opaque, _)) if self.intercrate => { relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]); Ok(a) } diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs index bd62c655216e8..3b280b7488ae7 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs @@ -32,10 +32,4 @@ impl Into for ContainsVal { } } -type Opaque = impl Sized; -struct IntoOpaque; -impl Into for IntoOpaque { - fn into(self) -> Opaque {} -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr index bb966af4b0ffd..251f1d84e74e3 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr @@ -1,12 +1,29 @@ -error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/from_over_into_unfixable.rs:35:15 +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:11:1 | -LL | type Opaque = impl Sized; - | ^^^^^^^^^^ +LL | impl Into for String { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #63063 for more information - = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable + = help: replace the `Into` implementation with `From` + = note: `-D clippy::from-over-into` implied by `-D warnings` -error: aborting due to previous error +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:19:1 + | +LL | impl Into for &'static [u8] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: replace the `Into` implementation with `From<&'static [u8]>` + +error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true + --> $DIR/from_over_into_unfixable.rs:28:1 + | +LL | impl Into for ContainsVal { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `impl From for Foreign` is allowed by the orphan rules, for more information see + https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence + = help: replace the `Into` implementation with `From` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr b/tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr new file mode 100644 index 0000000000000..61fed16294b4e --- /dev/null +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.current.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Into` for type `Foo` + --> $DIR/coherence-treats-tait-ambig.rs:10:1 + | +LL | impl Into for Foo { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl Into for T + where U: From; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr b/tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr new file mode 100644 index 0000000000000..61fed16294b4e --- /dev/null +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.next.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Into` for type `Foo` + --> $DIR/coherence-treats-tait-ambig.rs:10:1 + | +LL | impl Into for Foo { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `core`: + - impl Into for T + where U: From; + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/coherence-treats-tait-ambig.rs b/tests/ui/impl-trait/coherence-treats-tait-ambig.rs new file mode 100644 index 0000000000000..156a7eb0e23d7 --- /dev/null +++ b/tests/ui/impl-trait/coherence-treats-tait-ambig.rs @@ -0,0 +1,19 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next + +#![feature(type_alias_impl_trait)] + +type T = impl Sized; + +struct Foo; + +impl Into for Foo { +//~^ ERROR conflicting implementations of trait `Into` for type `Foo` + fn into(self) -> T { + Foo + } +} + +fn main() { + let _: T = Foo.into(); +} From 29c74d561992c156cec01119ef4e70766efa013c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 Jun 2023 02:46:10 +0000 Subject: [PATCH 12/14] Don't ICE on bound var in reject_fn_ptr_impls --- .../src/traits/select/candidate_assembly.rs | 8 ++---- .../foreach-partial-eq.rs | 12 ++++++++ .../foreach-partial-eq.stderr | 28 +++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs create mode 100644 tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f2dfa6921f41c..9f209b4b62326 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -417,17 +417,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Fast path to avoid evaluating an obligation that trivially holds. // There may be more bounds, but these are checked by the regular path. ty::FnPtr(..) => return false, + // These may potentially implement `FnPtr` ty::Placeholder(..) | ty::Dynamic(_, _, _) | ty::Alias(_, _) | ty::Infer(_) - | ty::Param(..) => {} + | ty::Param(..) + | ty::Bound(_, _) => {} - ty::Bound(_, _) => span_bug!( - obligation.cause.span(), - "cannot have escaping bound var in self type of {obligation:#?}" - ), // These can't possibly implement `FnPtr` as they are concrete types // and not `FnPtr` ty::Bool diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs new file mode 100644 index 0000000000000..96a7424f0dc9c --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.rs @@ -0,0 +1,12 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn auto_trait() +where + for T: PartialEq + PartialOrd, +{} + +fn main() { + auto_trait(); + //~^ ERROR can't compare `T` with `T` +} diff --git a/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr new file mode 100644 index 0000000000000..da09343fb276b --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/foreach-partial-eq.stderr @@ -0,0 +1,28 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/foreach-partial-eq.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: can't compare `T` with `T` + --> $DIR/foreach-partial-eq.rs:10:5 + | +LL | auto_trait(); + | ^^^^^^^^^^ no implementation for `T < T` and `T > T` + | + = help: the trait `PartialOrd` is not implemented for `T` +note: required by a bound in `auto_trait` + --> $DIR/foreach-partial-eq.rs:6:27 + | +LL | fn auto_trait() + | ---------- required by a bound in this function +LL | where +LL | for T: PartialEq + PartialOrd, + | ^^^^^^^^^^ required by this bound in `auto_trait` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. From db613750a91215a89ac25fd65cdaef02df2f73d5 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Mon, 19 Jun 2023 16:21:33 +0100 Subject: [PATCH 13/14] Reformatting --- compiler/rustc_resolve/src/late.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index e700e8c9ce086..9f4573ea02594 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2247,9 +2247,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let report_error = |this: &Self, ns| { if this.should_report_errs() { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - - let err = ImportsCannotReferTo { span: ident.span, what }; - this.r.tcx.sess.create_err(err).emit(); + this.r + .tcx + .sess + .create_err(ImportsCannotReferTo { span: ident.span, what }) + .emit(); } }; From 2027e989bce7d1c2f702d7aed383bf9cbdaf51d1 Mon Sep 17 00:00:00 2001 From: Tom Martin Date: Mon, 19 Jun 2023 16:22:21 +0100 Subject: [PATCH 14/14] Remove unreachable and untested suggestion for invalid span enum derive(Default) --- compiler/rustc_resolve/messages.ftl | 3 --- compiler/rustc_resolve/src/diagnostics.rs | 14 +++++--------- compiler/rustc_resolve/src/errors.rs | 7 ------- tests/ui/enum/suggest-default-attribute.stderr | 2 +- 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 062f9e85a9c22..60b6d74da7b9f 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -60,9 +60,6 @@ resolve_change_import_binding = resolve_consider_adding_a_derive = consider adding a derive -resolve_consider_adding_a_derive_enum = - consider adding `#[derive(Default)]` to this enum - resolve_const_not_member_of_trait = const `{$const_}` is not a member of trait `{$trait_}` .label = not a member of trait `{$trait_}` diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2a22e1ba242c8..539b4a1d5e714 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -32,7 +32,7 @@ use thin_vec::ThinVec; use crate::errors::{ AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, - ConsiderAddingADeriveEnum, ExplicitUnsafeTraits, + ExplicitUnsafeTraits, }; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; @@ -1393,14 +1393,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = self.def_span(def_id); let source_map = self.tcx.sess.source_map(); let head_span = source_map.guess_head_span(span); - if let Ok(head) = source_map.span_to_snippet(head_span) { - err.subdiagnostic(ConsiderAddingADerive { - span: head_span, - suggestion: format!("#[derive(Default)]\n{head}") - }); - } else { - err.subdiagnostic(ConsiderAddingADeriveEnum { span: head_span }); - } + err.subdiagnostic(ConsiderAddingADerive { + span: head_span.shrink_to_lo(), + suggestion: format!("#[derive(Default)]\n") + }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index fb70fbe2c1faf..93b626c779419 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -646,10 +646,3 @@ pub(crate) struct ConsiderAddingADerive { pub(crate) span: Span, pub(crate) suggestion: String, } - -#[derive(Subdiagnostic)] -#[help(resolve_consider_adding_a_derive_enum)] -pub(crate) struct ConsiderAddingADeriveEnum { - #[primary_span] - pub(crate) span: Span, -} diff --git a/tests/ui/enum/suggest-default-attribute.stderr b/tests/ui/enum/suggest-default-attribute.stderr index fb830d3f78b64..b56d599a78663 100644 --- a/tests/ui/enum/suggest-default-attribute.stderr +++ b/tests/ui/enum/suggest-default-attribute.stderr @@ -7,7 +7,7 @@ LL | #[default] help: consider adding a derive | LL + #[derive(Default)] -LL ~ pub enum Test { +LL | pub enum Test { | error: aborting due to previous error