From 94c9d0c90f6bb6f7d8fdc6e326e148e7b5bb30cf Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 30 Jul 2023 12:12:26 +0000 Subject: [PATCH 01/13] Make non-zero check more obvious --- compiler/rustc_trait_selection/src/traits/object_safety.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 5823b4508d94e..1dbe3039107c5 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -464,7 +464,7 @@ fn virtual_call_violation_for_method<'tcx>( // We can't monomorphize things like `fn foo(...)`. let own_counts = tcx.generics_of(method.def_id).own_counts(); - if own_counts.types + own_counts.consts != 0 { + if own_counts.types > 0 || own_counts.consts > 0 { return Some(MethodViolationCode::Generic); } From 9017b974eef3b43cb4a0c781cc24404b896b0ce5 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Thu, 19 Oct 2023 08:44:15 +0200 Subject: [PATCH 02/13] Improve the warning messages for the `#[diagnostic::on_unimplemented]` This commit improves warnings emitted for malformed on unimplemented attributes by: * Improving the span of the warnings * Adding a label message to them * Separating the messages for missing and unexpected options * Adding a help message that says which options are supported --- compiler/rustc_trait_selection/messages.ftl | 5 ++ .../error_reporting/on_unimplemented.rs | 57 +++++++++++--- ...o_not_fail_parsing_on_invalid_options_1.rs | 8 ++ ...t_fail_parsing_on_invalid_options_1.stderr | 77 +++++++++++++++---- ...ptions_and_continue_to_use_fallback.stderr | 6 +- 5 files changed, 126 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 20253b32add8c..a9792ca2795c9 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -28,6 +28,11 @@ trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-claus .label = invalid on-clause here trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute + .help = only `message`, `note` and `label` are allowed as options + .label = invalid option found here + +trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute + .help = at least one of the `message`, `note` and `label` options are expected trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> [none] {""} diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 9c9b78f415238..6a17dea02b4f2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -1,5 +1,8 @@ use super::{ObligationCauseCode, PredicateObligation}; use crate::infer::error_reporting::TypeErrCtxt; +use rustc_ast::AttrArgs; +use rustc_ast::AttrArgsEq; +use rustc_ast::AttrKind; use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; @@ -342,7 +345,22 @@ pub enum AppendConstMessage { #[derive(LintDiagnostic)] #[diag(trait_selection_malformed_on_unimplemented_attr)] -pub struct NoValueInOnUnimplementedLint; +#[help] +pub struct MalformedOnUnimplementedAttrLint { + #[label] + pub span: Span, +} + +impl MalformedOnUnimplementedAttrLint { + fn new(span: Span) -> Self { + Self { span } + } +} + +#[derive(LintDiagnostic)] +#[diag(trait_selection_missing_options_for_on_unimplemented_attr)] +#[help] +pub struct MissingOptionsForOnUnimplementedAttr; impl<'tcx> OnUnimplementedDirective { fn parse( @@ -453,7 +471,7 @@ impl<'tcx> OnUnimplementedDirective { UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), vec![item.span()], - NoValueInOnUnimplementedLint, + MalformedOnUnimplementedAttrLint::new(item.span()), ); } else { // nothing found @@ -530,21 +548,40 @@ impl<'tcx> OnUnimplementedDirective { append_const_msg: None, })) } else { + let item = attr.get_normal_item(); + let report_span = match &item.args { + AttrArgs::Empty => item.path.span, + AttrArgs::Delimited(args) => args.dspan.entire(), + AttrArgs::Eq(eq_span, AttrArgsEq::Ast(expr)) => eq_span.to(expr.span), + AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span), + }; + tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), - attr.span, - NoValueInOnUnimplementedLint, + report_span, + MalformedOnUnimplementedAttrLint::new(report_span), ); Ok(None) } } else if is_diagnostic_namespace_variant { - tcx.emit_spanned_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), - attr.span, - NoValueInOnUnimplementedLint, - ); + match &attr.kind { + AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { + tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + attr.span, + MalformedOnUnimplementedAttrLint::new(attr.span), + ); + } + _ => tcx.emit_spanned_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + attr.span, + MissingOptionsForOnUnimplementedAttr, + ), + }; + Ok(None) } else { let reported = diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs index 00fb59d14d76a..346d8373f7398 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs @@ -23,9 +23,15 @@ trait Boom {} //~^WARN malformed `on_unimplemented` attribute trait Doom {} +#[diagnostic::on_unimplemented] +//~^WARN missing options for `on_unimplemented` attribute +//~|WARN missing options for `on_unimplemented` attribute +trait Whatever {} + fn take_foo(_: impl Foo) {} fn take_baz(_: impl Baz) {} fn take_boom(_: impl Boom) {} +fn take_whatever(_: impl Whatever) {} fn main() { take_foo(1_i32); @@ -34,4 +40,6 @@ fn main() { //~^ERROR Boom take_boom(1_i32); //~^ERROR Boom + take_whatever(1_i32); + //~^ERROR the trait bound `i32: Whatever` is not satisfied } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr index bd39c91ffe88f..162ddd79fbbd9 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr @@ -10,36 +10,53 @@ warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options warning: malformed `on_unimplemented` attribute - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:1 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:22:32 | LL | #[diagnostic::on_unimplemented = "boom"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ invalid option found here + | + = help: only `message`, `note` and `label` are allowed as options + +warning: missing options for `on_unimplemented` attribute + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + | +LL | #[diagnostic::on_unimplemented] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:3:32 | LL | #[diagnostic::on_unimplemented(unsupported = "foo")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `i32: Foo` is not satisfied - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:37:14 | LL | take_foo(1_i32); | -------- ^^^^^ the trait `Foo` is not implemented for `i32` @@ -52,7 +69,7 @@ help: this trait has no implementations, consider adding one LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `take_foo` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:21 | LL | fn take_foo(_: impl Foo) {} | ^^^ required by this bound in `take_foo` @@ -61,12 +78,13 @@ warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:12:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", unsupported = "Bar")] - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:14 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:39:14 | LL | take_baz(1_i32); | -------- ^^^^^ the trait `Baz` is not implemented for `i32` @@ -79,7 +97,7 @@ help: this trait has no implementations, consider adding one LL | trait Baz {} | ^^^^^^^^^ note: required by a bound in `take_baz` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:27:21 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:32:21 | LL | fn take_baz(_: impl Baz) {} | ^^^ required by this bound in `take_baz` @@ -88,12 +106,13 @@ warning: malformed `on_unimplemented` attribute --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:17:50 | LL | #[diagnostic::on_unimplemented(message = "Boom", on(_Self = "i32", message = "whatever"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Boom - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:35:15 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:41:15 | LL | take_boom(1_i32); | --------- ^^^^^ the trait `Boom` is not implemented for `i32` @@ -106,11 +125,39 @@ help: this trait has no implementations, consider adding one LL | trait Boom {} | ^^^^^^^^^^ note: required by a bound in `take_boom` - --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:28:22 + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:33:22 | LL | fn take_boom(_: impl Boom) {} | ^^^^ required by this bound in `take_boom` -error: aborting due to 3 previous errors; 8 warnings emitted +warning: missing options for `on_unimplemented` attribute + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:26:1 + | +LL | #[diagnostic::on_unimplemented] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: at least one of the `message`, `note` and `label` options are expected + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: the trait bound `i32: Whatever` is not satisfied + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:43:19 + | +LL | take_whatever(1_i32); + | ------------- ^^^^^ the trait `Whatever` is not implemented for `i32` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:29:1 + | +LL | trait Whatever {} + | ^^^^^^^^^^^^^^ +note: required by a bound in `take_whatever` + --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:34:26 + | +LL | fn take_whatever(_: impl Whatever) {} + | ^^^^^^^^ required by this bound in `take_whatever` + +error: aborting due to 4 previous errors; 10 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr index 6a83d8e39c656..ba14c9c84b809 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -8,8 +8,9 @@ LL | | if(Self = ()), ... | LL | | note = "not used yet" LL | | )] - | |__^ + | |__^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute @@ -22,8 +23,9 @@ LL | | if(Self = ()), ... | LL | | note = "not used yet" LL | | )] - | |__^ + | |__^ invalid option found here | + = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: fallback!! From 3d03a8a6537ae944d38fb22b2edd1df0dcbaeeb1 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Fri, 20 Oct 2023 13:24:58 +0200 Subject: [PATCH 03/13] Fix a span for one of the test cases --- ...ed_options_and_continue_to_use_fallback.rs | 10 +++--- ...ptions_and_continue_to_use_fallback.stderr | 34 ++++++------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs index 353075863918c..8410b3eb10513 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -1,22 +1,20 @@ #![feature(diagnostic_namespace)] #[diagnostic::on_unimplemented( + if(Self = "()"), //~^WARN malformed `on_unimplemented` attribute //~|WARN malformed `on_unimplemented` attribute - if(Self = ()), - message = "not used yet", - label = "not used yet", - note = "not used yet" + message = "custom message", + note = "custom note" )] #[diagnostic::on_unimplemented(message = "fallback!!")] #[diagnostic::on_unimplemented(label = "fallback label")] #[diagnostic::on_unimplemented(note = "fallback note")] -#[diagnostic::on_unimplemented(message = "fallback2!!")] trait Foo {} fn takes_foo(_: impl Foo) {} fn main() { takes_foo(()); - //~^ERROR fallback!! + //~^ERROR custom message } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr index ba14c9c84b809..7860e540589db 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -1,35 +1,23 @@ warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | -LL | / #[diagnostic::on_unimplemented( -LL | | -LL | | -LL | | if(Self = ()), -... | -LL | | note = "not used yet" -LL | | )] - | |__^ invalid option found here +LL | if(Self = "()"), + | ^^^^^^^^^^^^^^^ invalid option found here | = help: only `message`, `note` and `label` are allowed as options = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default warning: malformed `on_unimplemented` attribute - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:4:5 | -LL | / #[diagnostic::on_unimplemented( -LL | | -LL | | -LL | | if(Self = ()), -... | -LL | | note = "not used yet" -LL | | )] - | |__^ invalid option found here +LL | if(Self = "()"), + | ^^^^^^^^^^^^^^^ invalid option found here | = help: only `message`, `note` and `label` are allowed as options = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: fallback!! - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 +error[E0277]: custom message + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:18:15 | LL | takes_foo(()); | --------- ^^ fallback label @@ -37,14 +25,14 @@ LL | takes_foo(()); | required by a bound introduced by this call | = help: the trait `Foo` is not implemented for `()` - = note: fallback note + = note: custom note help: this trait has no implementations, consider adding one - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:13:1 | LL | trait Foo {} | ^^^^^^^^^ note: required by a bound in `takes_foo` - --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:22 | LL | fn takes_foo(_: impl Foo) {} | ^^^ required by this bound in `takes_foo` From 4aaf8e03e1a1e2a53e95196569213baafc421b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 21 Oct 2023 06:04:41 +0200 Subject: [PATCH 04/13] on unresolved import disambiguate suggested path if it would collide --- compiler/rustc_resolve/src/diagnostics.rs | 58 ++++++++++++++----- tests/ui/imports/issue-56125.stderr | 12 ++-- tests/ui/unresolved/auxiliary/library.rs | 1 + ...ved-import-avoid-suggesting-global-path.rs | 31 ++++++++++ ...import-avoid-suggesting-global-path.stderr | 25 ++++++++ ...ort-suggest-disambiguated-crate-name.fixed | 19 ++++++ ...import-suggest-disambiguated-crate-name.rs | 19 ++++++ ...rt-suggest-disambiguated-crate-name.stderr | 14 +++++ 8 files changed, 159 insertions(+), 20 deletions(-) create mode 100644 tests/ui/unresolved/auxiliary/library.rs create mode 100644 tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs create mode 100644 tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr create mode 100644 tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed create mode 100644 tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs create mode 100644 tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 925ee615b095b..3e43b6bfdaec8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -25,7 +25,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; -use thin_vec::ThinVec; +use thin_vec::{thin_vec, ThinVec}; use crate::errors::{ AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, @@ -1147,7 +1147,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace: Namespace, parent_scope: &ParentScope<'a>, start_module: Module<'a>, - crate_name: Ident, + crate_path: ThinVec, filter_fn: FilterFn, ) -> Vec where @@ -1163,8 +1163,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(x) => Some(x), } { let in_module_is_extern = !in_module.def_id().is_local(); - // We have to visit module children in deterministic order to avoid - // instabilities in reported imports (#43552). in_module.for_each_child(self, |this, ident, ns, name_binding| { // avoid non-importable candidates if !name_binding.is_importable() { @@ -1214,12 +1212,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let res = name_binding.res(); if filter_fn(res) { // create the path - let mut segms = path_segments.clone(); - if lookup_ident.span.at_least_rust_2018() { + let mut segms = if lookup_ident.span.at_least_rust_2018() { // crate-local absolute paths start with `crate::` in edition 2018 // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660) - segms.insert(0, ast::PathSegment::from_ident(crate_name)); - } + crate_path.clone() + } else { + ThinVec::new() + }; + segms.append(&mut path_segments.clone()); segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; @@ -1318,18 +1318,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { where FilterFn: Fn(Res) -> bool, { + let crate_path = thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(kw::Crate))]; let mut suggestions = self.lookup_import_candidates_from_module( lookup_ident, namespace, parent_scope, self.graph_root, - Ident::with_dummy_span(kw::Crate), + crate_path, &filter_fn, ); if lookup_ident.span.at_least_rust_2018() { - let extern_prelude_names = self.extern_prelude.clone(); - for (ident, _) in extern_prelude_names.into_iter() { + for ident in self.extern_prelude.clone().into_keys() { if ident.span.from_expansion() { // Idents are adjusted to the root context before being // resolved in the extern prelude, so reporting this to the @@ -1340,13 +1340,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)); if let Some(crate_id) = crate_id { - let crate_root = self.expect_module(crate_id.as_def_id()); + let crate_def_id = crate_id.as_def_id(); + let crate_root = self.expect_module(crate_def_id); + + // Check if there's already an item in scope with the same name as the crate. + // If so, we have to disambiguate the potential import suggestions by making + // the paths *global* (i.e., by prefixing them with `::`). + let needs_disambiguation = + self.resolutions(parent_scope.module).borrow().iter().any( + |(key, name_resolution)| { + if key.ns == TypeNS + && key.ident == ident + && let Some(binding) = name_resolution.borrow().binding + { + match binding.res() { + // No disambiguation needed if the identically named item we + // found in scope actually refers to the crate in question. + Res::Def(_, def_id) => def_id != crate_def_id, + Res::PrimTy(_) => true, + _ => false, + } + } else { + false + } + }, + ); + let mut crate_path = ThinVec::new(); + if needs_disambiguation { + crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); + } + crate_path.push(ast::PathSegment::from_ident(ident)); + suggestions.extend(self.lookup_import_candidates_from_module( lookup_ident, namespace, parent_scope, crate_root, - ident, + crate_path, &filter_fn, )); } @@ -2541,7 +2571,7 @@ fn show_candidates( candidates.iter().for_each(|c| { (if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings }) - .push((path_names_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) + .push((pprust::path_to_string(&c.path), c.descr, c.did, &c.note, c.via_import)) }); // we want consistent results across executions, but candidates are produced diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index 15477fb6f1015..d2a0f436c42d0 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -6,14 +6,14 @@ LL | use empty::issue_56125; | help: consider importing one of these items instead | +LL | use ::issue_56125::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use ::issue_56125::last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | use ::issue_56125::non_last_segment::non_last_segment::issue_56125; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | use crate::m3::last_segment::issue_56125; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use crate::m3::non_last_segment::non_last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use issue_56125::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~ -LL | use issue_56125::last_segment::issue_56125; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ and 1 other candidate error[E0659]: `issue_56125` is ambiguous diff --git a/tests/ui/unresolved/auxiliary/library.rs b/tests/ui/unresolved/auxiliary/library.rs new file mode 100644 index 0000000000000..1169ed9622523 --- /dev/null +++ b/tests/ui/unresolved/auxiliary/library.rs @@ -0,0 +1 @@ +pub struct SomeUsefulType; diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs new file mode 100644 index 0000000000000..af8207aaadded --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.rs @@ -0,0 +1,31 @@ +// Test that we don't prepend `::` to paths referencing crates from the extern prelude +// when it can be avoided[^1] since it's more idiomatic to do so. +// +// [^1]: Counterexample: `unresolved-import-suggest-disambiguated-crate-name.rs` +#![feature(decl_macro)] // allows us to create items with hygienic names + +// aux-crate:library=library.rs +// edition: 2021 + +mod hygiene { + make!(); + macro make() { + // This won't conflict with the suggested *non-global* path as the syntax context differs. + mod library {} + } + + mod module {} + use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` +} + +mod glob { + use inner::*; + mod inner { + mod library {} + } + + mod module {} + use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` +} + +fn main() {} diff --git a/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr new file mode 100644 index 0000000000000..b0352ab675435 --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-avoid-suggesting-global-path.stderr @@ -0,0 +1,25 @@ +error[E0432]: unresolved import `module::SomeUsefulType` + --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:18:9 + | +LL | use module::SomeUsefulType; + | ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `hygiene::module` + | +help: consider importing this struct instead + | +LL | use library::SomeUsefulType; + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0432]: unresolved import `module::SomeUsefulType` + --> $DIR/unresolved-import-avoid-suggesting-global-path.rs:28:9 + | +LL | use module::SomeUsefulType; + | ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `glob::module` + | +help: consider importing this struct instead + | +LL | use library::SomeUsefulType; + | ~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed new file mode 100644 index 0000000000000..2b20d3f106b9d --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.fixed @@ -0,0 +1,19 @@ +// Regression test for issue #116970. +// +// When we suggest importing an item from a crate found in the extern prelude and there +// happens to exist a module or type in the current scope with the same name as the crate, +// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`). +// +// For context, when it can be avoided we don't prepend `::` to paths referencing crates +// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`. + +// run-rustfix + +// compile-flags: --crate-type=lib +// aux-crate:library=library.rs +// edition: 2021 + +mod library {} // this module shares the same name as the external crate! + +mod module {} +pub use ::library::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs new file mode 100644 index 0000000000000..b810a7f52966a --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.rs @@ -0,0 +1,19 @@ +// Regression test for issue #116970. +// +// When we suggest importing an item from a crate found in the extern prelude and there +// happens to exist a module or type in the current scope with the same name as the crate, +// disambiguate the suggested path by making it global (i.e., by prefixing it with `::`). +// +// For context, when it can be avoided we don't prepend `::` to paths referencing crates +// from the extern prelude. See also `unresolved-import-avoid-suggesting-global-path.rs`. + +// run-rustfix + +// compile-flags: --crate-type=lib +// aux-crate:library=library.rs +// edition: 2021 + +mod library {} // this module shares the same name as the external crate! + +mod module {} +pub use module::SomeUsefulType; //~ ERROR unresolved import `module::SomeUsefulType` diff --git a/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr new file mode 100644 index 0000000000000..f139c0f3cf1e8 --- /dev/null +++ b/tests/ui/unresolved/unresolved-import-suggest-disambiguated-crate-name.stderr @@ -0,0 +1,14 @@ +error[E0432]: unresolved import `module::SomeUsefulType` + --> $DIR/unresolved-import-suggest-disambiguated-crate-name.rs:19:9 + | +LL | pub use module::SomeUsefulType; + | ^^^^^^^^^^^^^^^^^^^^^^ no `SomeUsefulType` in `module` + | +help: consider importing this struct instead + | +LL | pub use ::library::SomeUsefulType; + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. From 079b29043976afd44cf49eec74486bf2fc15973d Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Wed, 25 Oct 2023 09:11:16 +0530 Subject: [PATCH 05/13] Do not suggest 'Trait' when in trait impl because that would be illegal syntax --- .../wrong_number_of_generic_args.rs | 72 +++++++++--- ...lid-assoc-type-suggestion-in-trait-impl.rs | 43 +++++++ ...assoc-type-suggestion-in-trait-impl.stderr | 109 ++++++++++++++++++ 3 files changed, 210 insertions(+), 14 deletions(-) create mode 100644 tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs create mode 100644 tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 61b182b1be782..fe0576358dd8f 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -129,6 +129,44 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { if self.missing_lifetimes() { "lifetime" } else { "generic" } } + /// Returns true if the generic type is a trait + /// and is being referred to from one of its trait impls + fn is_in_trait_impl(&self) -> bool { + if self.tcx.is_trait(self.def_id) { + // Here we check if the reference to the generic type + // is from the 'of_trait' field of the enclosing impl + + let parent = self.tcx.hir().get_parent(self.path_segment.hir_id); + let parent_item = self + .tcx + .hir() + .get_by_def_id(self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id); + + // Get the HIR id of the trait ref + let hir::Node::TraitRef(hir::TraitRef { hir_ref_id: trait_ref_id, .. }) = parent else { + return false; + }; + + // Get the HIR id of the 'of_trait' field of the impl + let hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl(hir::Impl { + of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }), + .. + }), + .. + }) = parent_item + else { + return false; + }; + + // Check that trait is referred to from the of_trait field of impl + trait_ref_id == id_in_of_trait + } else { + false + } + } + fn num_provided_args(&self) -> usize { if self.missing_lifetimes() { self.num_provided_lifetime_args() @@ -948,20 +986,26 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // If there is a single unbound associated type and a single excess generic param // suggest replacing the generic param with the associated type bound if provided_args_matches_unbound_traits && !unbound_types.is_empty() { - let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; - let suggestions = iter::zip(unused_generics, &unbound_types) - .map(|(potential, name)| (potential.span().shrink_to_lo(), format!("{name} = "))) - .collect::>(); - - if !suggestions.is_empty() { - err.multipart_suggestion_verbose( - format!( - "replace the generic bound{s} with the associated type{s}", - s = pluralize!(unbound_types.len()) - ), - suggestions, - Applicability::MaybeIncorrect, - ); + // Don't suggest if we're in a trait impl as + // that would result in invalid syntax (fixes #116464) + if !self.is_in_trait_impl() { + let unused_generics = &self.gen_args.args[self.num_expected_type_or_const_args()..]; + let suggestions = iter::zip(unused_generics, &unbound_types) + .map(|(potential, name)| { + (potential.span().shrink_to_lo(), format!("{name} = ")) + }) + .collect::>(); + + if !suggestions.is_empty() { + err.multipart_suggestion_verbose( + format!( + "replace the generic bound{s} with the associated type{s}", + s = pluralize!(unbound_types.len()) + ), + suggestions, + Applicability::MaybeIncorrect, + ); + } } } else if remove_entire_generics { let span = self diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs new file mode 100644 index 0000000000000..e0edd522431a5 --- /dev/null +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs @@ -0,0 +1,43 @@ +// Regression test for #116464 +// Checks that we do not suggest Trait<..., Assoc=arg> when the trait +// is referred to from one of its impls but do so at all other places + +pub trait Trait { + type Assoc; +} + +impl Trait for i32 { + type Assoc = String; +} + +// Should not not trigger suggestion here... +impl Trait for () {} +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + +//... but should do so in all of the below cases except the last one +fn func>(t: T) -> impl Trait<(), i32> { +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied +//~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied + 3 +} + +struct Struct> { +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + a: T +} + +trait AnotherTrait> {} +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + +impl> Struct {} +//~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied + +// Test for self type. Should not trigger suggestion as it doesn't have an +// associated type +trait YetAnotherTrait {} +impl, U> YetAnotherTrait for Struct {} +//~^ ERROR struct takes 1 generic argument but 2 generic arguments were supplied + + +fn main() { +} diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr new file mode 100644 index 0000000000000..711ccf1b6682c --- /dev/null +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -0,0 +1,109 @@ +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:14:12 + | +LL | impl Trait for () {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:12 + | +LL | fn func>(t: T) -> impl Trait<(), i32> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | fn func>(t: T) -> impl Trait<(), i32> { + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:18:46 + | +LL | fn func>(t: T) -> impl Trait<(), i32> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | fn func>(t: T) -> impl Trait<(), Assoc = i32> { + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:18 + | +LL | struct Struct> { + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | struct Struct> { + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:29:23 + | +LL | trait AnotherTrait> {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | trait AnotherTrait> {} + | +++++++ + +error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:32:9 + | +LL | impl> Struct {} + | ^^^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:5:11 + | +LL | pub trait Trait { + | ^^^^^ - +help: replace the generic bound with the associated type + | +LL | impl> Struct {} + | +++++++ + +error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:38:58 + | +LL | impl, U> YetAnotherTrait for Struct {} + | ^^^^^^ - help: remove this generic argument + | | + | expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:24:8 + | +LL | struct Struct> { + | ^^^^^^ - + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0107`. From af8a998b1ed2ed39f9c5514131f364f3fc163990 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 23 Oct 2023 17:02:40 +0000 Subject: [PATCH 06/13] Rename `AsyncCoroutineKind` to `CoroutineSource` similar to how we have `MatchSource`, it explains where the desugaring came from. --- compiler/rustc_ast_lowering/src/expr.rs | 6 ++-- compiler/rustc_ast_lowering/src/item.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 6 ++-- .../src/diagnostics/region_name.rs | 6 ++-- .../src/debuginfo/type_names.rs | 8 ++--- .../src/transform/check_consts/ops.rs | 4 +-- compiler/rustc_hir/src/hir.rs | 30 +++++++++---------- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_hir_typeck/src/closure.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 6 ++-- compiler/rustc_smir/src/rustc_smir/mod.rs | 8 ++--- .../src/traits/error_reporting/suggestions.rs | 8 ++--- .../error_reporting/type_err_ctxt_ext.rs | 6 ++-- compiler/stable_mir/src/mir/body.rs | 4 +-- .../clippy_lints/src/async_yields_async.rs | 4 +-- .../clippy_lints/src/await_holding_invalid.rs | 4 +-- .../clippy_lints/src/manual_async_fn.rs | 4 +-- .../src/needless_question_mark.rs | 4 +-- .../clippy_lints/src/redundant_async_block.rs | 4 +-- 19 files changed, 59 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4f1b13870fd46..b82f878ea87e0 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -188,7 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.id, None, e.span, - hir::AsyncCoroutineKind::Block, + hir::CoroutineSource::Block, |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), @@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_node_id: NodeId, ret_ty: Option>, span: Span, - async_gen_kind: hir::AsyncCoroutineKind, + async_gen_kind: hir::CoroutineSource, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); @@ -1005,7 +1005,7 @@ impl<'hir> LoweringContext<'_, 'hir> { inner_closure_id, async_ret_ty, body.span, - hir::AsyncCoroutineKind::Closure, + hir::CoroutineSource::Closure, |this| this.with_new_scopes(|this| this.lower_expr_mut(body)), ); let hir_id = this.lower_node_id(inner_closure_id); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3c165f87dbf3d..ca851bd4d35f0 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1206,7 +1206,7 @@ impl<'hir> LoweringContext<'_, 'hir> { closure_id, None, body.span, - hir::AsyncCoroutineKind::Fn, + hir::CoroutineSource::Fn, |this| { // Create a block from the user's function body: let user_body = this.lower_block_expr(body); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b5ad02dc688ff..928c25d106179 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -8,7 +8,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; -use rustc_hir::{AsyncCoroutineKind, CoroutineKind, LangItem}; +use rustc_hir::{CoroutineKind, CoroutineSource, LangItem}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter::OnlyBodies; use rustc_middle::mir::tcx::PlaceTy; @@ -2506,8 +2506,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let kind = match use_span.coroutine_kind() { Some(coroutine_kind) => match coroutine_kind { CoroutineKind::Async(async_kind) => match async_kind { - AsyncCoroutineKind::Block => "async block", - AsyncCoroutineKind::Closure => "async closure", + CoroutineSource::Block => "async block", + CoroutineSource::Closure => "async closure", _ => bug!("async block/closure expected, but async function found."), }, CoroutineKind::Coroutine => "coroutine", diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index de9ece3faba4d..e630ac7c4faee 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -682,9 +682,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { }; let mir_description = match hir.body(body).coroutine_kind { Some(hir::CoroutineKind::Async(gen)) => match gen { - hir::AsyncCoroutineKind::Block => " of async block", - hir::AsyncCoroutineKind::Closure => " of async closure", - hir::AsyncCoroutineKind::Fn => { + hir::CoroutineSource::Block => " of async block", + hir::CoroutineSource::Closure => " of async closure", + hir::CoroutineSource::Fn => { let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id).def_id); let output = &parent_item diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index e401f6bbcbfb2..5900c764073df 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_hir::def_id::DefId; use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; -use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Mutability}; +use rustc_hir::{CoroutineKind, CoroutineSource, Mutability}; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, ExistentialProjection, ParamEnv, Ty, TyCtxt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; @@ -560,9 +560,9 @@ pub fn push_item_name(tcx: TyCtxt<'_>, def_id: DefId, qualified: bool, output: & fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { match coroutine_kind { - Some(CoroutineKind::Async(AsyncCoroutineKind::Block)) => "async_block", - Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) => "async_closure", - Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) => "async_fn", + Some(CoroutineKind::Async(CoroutineSource::Block)) => "async_block", + Some(CoroutineKind::Async(CoroutineSource::Closure)) => "async_closure", + Some(CoroutineKind::Async(CoroutineSource::Fn)) => "async_fn", Some(CoroutineKind::Coroutine) => "coroutine", None => "closure", } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 616fab8fe7d65..1258d71d52178 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -360,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { pub struct Coroutine(pub hir::CoroutineKind); impl<'tcx> NonConstOp<'tcx> for Coroutine { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { - if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 { + if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { Status::Unstable(sym::const_async_blocks) } else { Status::Forbidden @@ -373,7 +373,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind()); - if let hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) = self.0 { + if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { ccx.tcx.sess.create_feature_err( errors::UnallowedOpInConstContext { span, msg }, sym::const_async_blocks, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 63711f5804d68..0e14a0e43460b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1511,7 +1511,7 @@ impl<'hir> Body<'hir> { #[derive(HashStable_Generic, Encodable, Decodable)] pub enum CoroutineKind { /// An explicit `async` block or the body of an async function. - Async(AsyncCoroutineKind), + Async(CoroutineSource), /// A coroutine literal created via a `yield` inside a closure. Coroutine, @@ -1535,40 +1535,40 @@ impl CoroutineKind { } } -/// In the case of a coroutine created as part of an async construct, -/// which kind of async construct caused it to be created? +/// In the case of a coroutine created as part of an async/gen construct, +/// which kind of async/gen construct caused it to be created? /// /// This helps error messages but is also used to drive coercions in /// type-checking (see #60424). #[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)] #[derive(HashStable_Generic, Encodable, Decodable)] -pub enum AsyncCoroutineKind { - /// An explicit `async` block written by the user. +pub enum CoroutineSource { + /// An explicit `async`/`gen` block written by the user. Block, - /// An explicit `async` closure written by the user. + /// An explicit `async`/`gen` closure written by the user. Closure, - /// The `async` block generated as the body of an async function. + /// The `async`/`gen` block generated as the body of an async/gen function. Fn, } -impl fmt::Display for AsyncCoroutineKind { +impl fmt::Display for CoroutineSource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { - AsyncCoroutineKind::Block => "async block", - AsyncCoroutineKind::Closure => "async closure body", - AsyncCoroutineKind::Fn => "async fn body", + CoroutineSource::Block => "async block", + CoroutineSource::Closure => "async closure body", + CoroutineSource::Fn => "async fn body", }) } } -impl AsyncCoroutineKind { +impl CoroutineSource { pub fn descr(&self) -> &'static str { match self { - AsyncCoroutineKind::Block => "`async` block", - AsyncCoroutineKind::Closure => "`async` closure body", - AsyncCoroutineKind::Fn => "`async fn` body", + CoroutineSource::Block => "`async` block", + CoroutineSource::Closure => "`async` closure body", + CoroutineSource::Fn => "`async fn` body", } } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 5eb68cf6b28c3..6b6d1574b2bf6 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -305,7 +305,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) = (parent_node, callee_node) { let fn_decl_span = if hir.body(body).coroutine_kind - == Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure)) + == Some(hir::CoroutineKind::Async(hir::CoroutineSource::Closure)) { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cf8a4cafbb611..47bde21ceb2eb 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -636,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing // function. - Some(hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn)) => { + Some(hir::CoroutineKind::Async(hir::CoroutineSource::Fn)) => { debug!("closure is async fn body"); let def_id = self.tcx.hir().body_owner_def_id(body.id()); self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 13aa6454bc363..6d55abb646966 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -10,8 +10,8 @@ use rustc_hir::def::Res; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ - AsyncCoroutineKind, CoroutineKind, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, - Stmt, StmtKind, TyKind, WherePredicate, + CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, Path, QPath, Stmt, + StmtKind, TyKind, WherePredicate, }; use rustc_hir_analysis::astconv::AstConv; use rustc_infer::traits::{self, StatementAsExpression}; @@ -536,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Coroutine(def_id, ..) if matches!( self.tcx.coroutine_kind(def_id), - Some(CoroutineKind::Async(AsyncCoroutineKind::Closure)) + Some(CoroutineKind::Async(CoroutineSource::Closure)) ) => { errors::SuggestBoxing::AsyncBody diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 2253dc570103c..1127cbe7a182c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -917,13 +917,13 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> { impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { type T = stable_mir::mir::CoroutineKind; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - use rustc_hir::{AsyncCoroutineKind, CoroutineKind}; + use rustc_hir::{CoroutineKind, CoroutineSource}; match self { CoroutineKind::Async(async_gen) => { let async_gen = match async_gen { - AsyncCoroutineKind::Block => stable_mir::mir::AsyncCoroutineKind::Block, - AsyncCoroutineKind::Closure => stable_mir::mir::AsyncCoroutineKind::Closure, - AsyncCoroutineKind::Fn => stable_mir::mir::AsyncCoroutineKind::Fn, + CoroutineSource::Block => stable_mir::mir::CoroutineSource::Block, + CoroutineSource::Closure => stable_mir::mir::CoroutineSource::Closure, + CoroutineSource::Fn => stable_mir::mir::CoroutineSource::Fn, }; stable_mir::mir::CoroutineKind::Async(async_gen) } 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 78b466907b32b..77d167eadd8cd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -22,7 +22,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; -use rustc_hir::{AsyncCoroutineKind, CoroutineKind, Node}; +use rustc_hir::{CoroutineKind, CoroutineSource, Node}; use rustc_hir::{Expr, HirId}; use rustc_infer::infer::error_reporting::TypeErrCtxt; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -2410,7 +2410,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .and_then(|coroutine_did| { Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() { CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"), - CoroutineKind::Async(AsyncCoroutineKind::Fn) => self + CoroutineKind::Async(CoroutineSource::Fn) => self .tcx .parent(coroutine_did) .as_local() @@ -2419,10 +2419,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .map(|name| { format!("future returned by `{name}` is not {trait_name}") })?, - CoroutineKind::Async(AsyncCoroutineKind::Block) => { + CoroutineKind::Async(CoroutineSource::Block) => { format!("future created by async block is not {trait_name}") } - CoroutineKind::Async(AsyncCoroutineKind::Closure) => { + CoroutineKind::Async(CoroutineSource::Closure) => { format!("future created by async closure is not {trait_name}") } }) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 1245b4a7756e1..353a69ef6d324 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1611,9 +1611,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> { self.tcx.hir().body(body_id).coroutine_kind.map(|gen_kind| match gen_kind { hir::CoroutineKind::Coroutine => "a coroutine", - hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Block) => "an async block", - hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Fn) => "an async function", - hir::CoroutineKind::Async(hir::AsyncCoroutineKind::Closure) => "an async closure", + hir::CoroutineKind::Async(hir::CoroutineSource::Block) => "an async block", + hir::CoroutineKind::Async(hir::CoroutineSource::Fn) => "an async function", + hir::CoroutineKind::Async(hir::CoroutineSource::Closure) => "an async closure", }) } diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 5eee1ec00df50..7c6b454e18395 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -135,12 +135,12 @@ pub enum UnOp { #[derive(Clone, Debug)] pub enum CoroutineKind { - Async(AsyncCoroutineKind), + Async(CoroutineSource), Coroutine, } #[derive(Clone, Debug)] -pub enum AsyncCoroutineKind { +pub enum CoroutineSource { Block, Closure, Fn, diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 56f56fff1e78a..050df68a0fa14 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{AsyncCoroutineKind, Body, BodyId, CoroutineKind, ExprKind, QPath}; +use rustc_hir::{CoroutineSource, Body, BodyId, CoroutineKind, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -45,7 +45,7 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { - use AsyncCoroutineKind::{Block, Closure}; + use CoroutineSource::{Block, Closure}; // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind { diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index ae8618dcaa062..0c356934992f5 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; -use rustc_hir::{AsyncCoroutineKind, Body, CoroutineKind}; +use rustc_hir::{CoroutineSource, Body, CoroutineKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -195,7 +195,7 @@ impl LateLintPass<'_> for AwaitHolding { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - use AsyncCoroutineKind::{Block, Closure, Fn}; + use CoroutineSource::{Block, Closure, Fn}; if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind { let def_id = cx.tcx.hir().body_owner_def_id(body.id()); if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 5a87e75722d01..a75c76d6fe0d8 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -4,7 +4,7 @@ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - AsyncCoroutineKind, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, + CoroutineSource, Block, Body, Closure, CoroutineKind, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, }; use rustc_lint::{LateContext, LateLintPass}; @@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) .. } = block_expr; let closure_body = cx.tcx.hir().body(body); - if closure_body.coroutine_kind == Some(CoroutineKind::Async(AsyncCoroutineKind::Block)); + if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block)); then { return Some(closure_body); } diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index ed279a3813d70..b3a2060d6ac9d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{AsyncCoroutineKind, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{CoroutineSource, Block, Body, CoroutineKind, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Async(AsyncCoroutineKind::Fn)) = body.coroutine_kind { + if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind { if let ExprKind::Block( Block { expr: diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 2e895d5f23696..bf9bdacba5b90 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{AsyncCoroutineKind, Closure, CoroutineKind, Expr, ExprKind, MatchSource}; +use rustc_hir::{CoroutineSource, Closure, CoroutineKind, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -71,7 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) && - matches!(body.coroutine_kind, Some(CoroutineKind::Async(AsyncCoroutineKind::Block))) + matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block))) { cx .typeck_results() From 024ca99de5d39956a94815532db32bb241cef555 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 20 Oct 2023 21:07:30 -0700 Subject: [PATCH 07/13] Uplift Canonical to rustc_type_ir --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 3 +- compiler/rustc_middle/src/infer/canonical.rs | 80 +-------- compiler/rustc_middle/src/ty/context.rs | 3 +- .../rustc_middle/src/ty/structural_impls.rs | 1 - .../rustc_middle/src/ty/typeck_results.rs | 30 ++-- .../src/traits/query/normalize.rs | 2 +- compiler/rustc_type_ir/src/canonical.rs | 169 ++++++++++++++++++ compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/lib.rs | 2 + compiler/rustc_type_ir/src/macros.rs | 1 + compiler/rustc_type_ir/src/region_kind.rs | 2 +- compiler/rustc_type_ir/src/ty_kind.rs | 2 +- 12 files changed, 201 insertions(+), 95 deletions(-) create mode 100644 compiler/rustc_type_ir/src/canonical.rs diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index afa5a3b9379ea..82e9bd50cc8fa 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -207,7 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("fcx {}", self.tag()); - if !canonical_user_type_annotation.is_identity() { + // FIXME: is_identity being on `UserType` and not `Canonical` is awkward + if !canonical_user_type_annotation.value.is_identity() { self.typeck_results .borrow_mut() .user_provided_types_mut() diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index c8f3c2a20a694..0b5426c3bb1a1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -21,35 +21,17 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::infer::MemberConstraint; -use crate::mir::ConstraintCategory; -use crate::ty::GenericArg; -use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; use rustc_macros::HashStable; +use rustc_type_ir::Canonical as IrCanonical; use smallvec::SmallVec; -use std::fmt::Display; use std::ops::Index; -/// A "canonicalized" type `V` is one where all free inference -/// variables have been rewritten to "canonical vars". These are -/// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] -pub struct Canonical<'tcx, V> { - pub value: V, - pub max_universe: ty::UniverseIndex, - pub variables: CanonicalVarInfos<'tcx>, -} +use crate::infer::MemberConstraint; +use crate::mir::ConstraintCategory; +use crate::ty::GenericArg; +use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt}; -impl<'tcx, V: Display> std::fmt::Display for Canonical<'tcx, V> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", - self.value, self.max_universe, self.variables - ) - } -} +pub type Canonical<'tcx, V> = IrCanonical, V>; pub type CanonicalVarInfos<'tcx> = &'tcx List>; @@ -379,56 +361,6 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { - pub fn is_proven(&self) -> bool { - self.value.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, V> Canonical<'tcx, V> { - /// Allows you to map the `value` of a canonical while keeping the - /// same set of bound variables. - /// - /// **WARNING:** This function is very easy to mis-use, hence the - /// name! In particular, the new value `W` must use all **the - /// same type/region variables** in **precisely the same order** - /// as the original! (The ordering is defined by the - /// `TypeFoldable` implementation of the type in question.) - /// - /// An example of a **correct** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'_, T> = ...; - /// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, )); - /// ``` - /// - /// An example of an **incorrect** use of this: - /// - /// ```rust,ignore (not real code) - /// let a: Canonical<'tcx, T> = ...; - /// let ty: Ty<'tcx> = ...; - /// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty)); - /// ``` - pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } - } - - /// Allows you to map the `value` of a canonical while keeping the same set of - /// bound variables. - /// - /// **WARNING:** This function is very easy to mis-use, hence the name! See - /// the comment of [Canonical::unchecked_map] for more details. - pub fn unchecked_rebind(self, value: W) -> Canonical<'tcx, W> { - let Canonical { max_universe, variables, value: _ } = self; - Canonical { max_universe, variables, value } - } -} - pub type QueryOutlivesConstraint<'tcx> = (ty::OutlivesPredicate, Region<'tcx>>, ConstraintCategory<'tcx>); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index fe8caf30a1109..d965db892986e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -6,7 +6,7 @@ pub mod tls; use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; -use crate::infer::canonical::CanonicalVarInfo; +use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use crate::lint::struct_lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -88,6 +88,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Binder = Binder<'tcx, T>; type TypeAndMut = TypeAndMut<'tcx>; + type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; type Tys = &'tcx List>; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 7f86acd4bf5b1..6af68bc5dbabb 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -449,7 +449,6 @@ TrivialTypeTraversalImpls! { crate::ty::IntVarValue, crate::ty::adjustment::PointerCoercion, crate::ty::RegionVid, - crate::ty::UniverseIndex, crate::ty::Variance, ::rustc_span::Span, ::rustc_span::symbol::Ident, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 7d516410b201f..51f36e282e2ac 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -594,11 +594,24 @@ pub struct CanonicalUserTypeAnnotation<'tcx> { /// Canonical user type annotation. pub type CanonicalUserType<'tcx> = Canonical<'tcx, UserType<'tcx>>; -impl<'tcx> CanonicalUserType<'tcx> { +/// A user-given type annotation attached to a constant. These arise +/// from constants that are named via paths, like `Foo::::new` and +/// so forth. +#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] +#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)] +pub enum UserType<'tcx> { + Ty(Ty<'tcx>), + + /// The canonical type is the result of `type_of(def_id)` with the + /// given substitutions applied. + TypeOf(DefId, UserArgs<'tcx>), +} + +impl<'tcx> UserType<'tcx> { /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, /// i.e., each thing is mapped to a canonical variable with the same index. pub fn is_identity(&self) -> bool { - match self.value { + match self { UserType::Ty(_) => false, UserType::TypeOf(_, user_args) => { if user_args.user_self_ty.is_some() { @@ -640,19 +653,6 @@ impl<'tcx> CanonicalUserType<'tcx> { } } -/// A user-given type annotation attached to a constant. These arise -/// from constants that are named via paths, like `Foo::::new` and -/// so forth. -#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)] -#[derive(Eq, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum UserType<'tcx> { - Ty(Ty<'tcx>), - - /// The canonical type is the result of `type_of(def_id)` with the - /// given substitutions applied. - TypeOf(DefId, UserArgs<'tcx>), -} - impl<'tcx> std::fmt::Display for UserType<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 349741a698c9a..c761d0d103ea2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -293,7 +293,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> _ => unreachable!(), }?; // We don't expect ambiguity. - if result.is_ambiguous() { + if !result.value.is_proven() { // Rustdoc normalizes possibly not well-formed types, so only // treat this as a bug if we're not in rustdoc. if !tcx.sess.opts.actually_rustdoc { diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs new file mode 100644 index 0000000000000..c0b6aed98ef2e --- /dev/null +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -0,0 +1,169 @@ +use std::fmt; +use std::hash; +use std::ops::ControlFlow; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_serialize::{Decodable, Encodable}; + +use crate::fold::{FallibleTypeFolder, TypeFoldable}; +use crate::visit::{TypeVisitable, TypeVisitor}; +use crate::TyDecoder; +use crate::{HashStableContext, Interner, TyEncoder, UniverseIndex}; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewritten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +pub struct Canonical { + pub value: V, + pub max_universe: UniverseIndex, + pub variables: I::CanonicalVars, +} + +impl Canonical { + /// Allows you to map the `value` of a canonical while keeping the + /// same set of bound variables. + /// + /// **WARNING:** This function is very easy to mis-use, hence the + /// name! In particular, the new value `W` must use all **the + /// same type/region variables** in **precisely the same order** + /// as the original! (The ordering is defined by the + /// `TypeFoldable` implementation of the type in question.) + /// + /// An example of a **correct** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical = ...; + /// let b: Canonical = a.unchecked_map(|v| (v, )); + /// ``` + /// + /// An example of an **incorrect** use of this: + /// + /// ```rust,ignore (not real code) + /// let a: Canonical = ...; + /// let ty: Ty = ...; + /// let b: Canonical)> = a.unchecked_map(|v| (v, ty)); + /// ``` + pub fn unchecked_map(self, map_op: impl FnOnce(V) -> W) -> Canonical { + let Canonical { max_universe, variables, value } = self; + Canonical { max_universe, variables, value: map_op(value) } + } + + /// Allows you to map the `value` of a canonical while keeping the same set of + /// bound variables. + /// + /// **WARNING:** This function is very easy to mis-use, hence the name! See + /// the comment of [Canonical::unchecked_map] for more details. + pub fn unchecked_rebind(self, value: W) -> Canonical { + let Canonical { max_universe, variables, value: _ } = self; + Canonical { max_universe, variables, value } + } +} + +impl hash::Hash for Canonical { + fn hash(&self, state: &mut H) { + self.value.hash(state); + self.max_universe.hash(state); + self.variables.hash(state); + } +} + +impl> HashStable for Canonical +where + I::CanonicalVars: HashStable, +{ + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.value.hash_stable(hcx, hasher); + self.max_universe.hash_stable(hcx, hasher); + self.variables.hash_stable(hcx, hasher); + } +} + +impl Eq for Canonical {} + +impl PartialEq for Canonical { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + && self.max_universe == other.max_universe + && self.variables == other.variables + } +} + +impl fmt::Display for Canonical { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", + self.value, self.max_universe, self.variables + ) + } +} + +impl fmt::Debug for Canonical { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Canonical") + .field("value", &self.value) + .field("max_universe", &self.max_universe) + .field("variables", &self.variables) + .finish() + } +} + +impl Clone for Canonical { + fn clone(&self) -> Self { + Canonical { + value: self.value.clone(), + max_universe: self.max_universe.clone(), + variables: self.variables.clone(), + } + } +} + +impl Copy for Canonical where I::CanonicalVars: Copy {} + +impl> TypeFoldable for Canonical +where + I::CanonicalVars: TypeFoldable, +{ + fn try_fold_with>(self, folder: &mut F) -> Result { + Ok(Canonical { + value: self.value.try_fold_with(folder)?, + max_universe: self.max_universe.try_fold_with(folder)?, + variables: self.variables.try_fold_with(folder)?, + }) + } +} + +impl> TypeVisitable for Canonical +where + I::CanonicalVars: TypeVisitable, +{ + fn visit_with>(&self, folder: &mut F) -> ControlFlow { + self.value.visit_with(folder)?; + self.max_universe.visit_with(folder)?; + self.variables.visit_with(folder) + } +} + +impl, V: Encodable> Encodable for Canonical +where + I::CanonicalVars: Encodable, +{ + fn encode(&self, s: &mut E) { + self.value.encode(s); + self.max_universe.encode(s); + self.variables.encode(s); + } +} + +impl, V: Decodable> Decodable for Canonical +where + I::CanonicalVars: Decodable, +{ + fn decode(d: &mut D) -> Self { + Canonical { + value: Decodable::decode(d), + max_universe: Decodable::decode(d), + variables: Decodable::decode(d), + } + } +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6e5d3ee0b6de7..7f75e5b35a204 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -18,6 +18,7 @@ pub trait Interner: Sized { type Binder; type TypeAndMut: Clone + Debug + Hash + Ord; + type CanonicalVars: Clone + Debug + Hash + Eq; // Kinds of tys type Ty: Clone + DebugWithInfcx + Hash + Ord; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 3494b24f06038..a056fbeda9811 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -26,6 +26,7 @@ pub mod visit; #[macro_use] mod macros; +mod canonical; mod const_kind; mod debug; mod flags; @@ -33,6 +34,7 @@ mod interner; mod predicate_kind; mod region_kind; +pub use canonical::*; pub use codec::*; pub use const_kind::*; pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx}; diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 88314aca6f36c..cfed84a35c671 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -50,4 +50,5 @@ TrivialTypeTraversalImpls! { String, crate::DebruijnIndex, crate::AliasRelationDirection, + crate::UniverseIndex, } diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 60b90f4fae3b2..19576ea58f1f0 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -307,7 +307,7 @@ impl fmt::Debug for RegionKind { } // This is manually implemented because a derive would require `I: Encodable` -impl Encodable for RegionKind +impl> Encodable for RegionKind where I::EarlyBoundRegion: Encodable, I::BoundRegion: Encodable, diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 2128666c2a459..b542547589ac4 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -622,7 +622,7 @@ impl fmt::Debug for TyKind { } // This is manually implemented because a derive would require `I: Encodable` -impl Encodable for TyKind +impl> Encodable for TyKind where I::ErrorGuaranteed: Encodable, I::AdtDef: Encodable, From 8f3b4f94ef739b9ad7d4f3cdee6be91f6913938f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Oct 2023 16:11:48 -0400 Subject: [PATCH 08/13] Add a IsIdentity extension trait for CanonicalUserType --- compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 4 ++-- compiler/rustc_middle/src/ty/typeck_results.rs | 10 +++++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 82e9bd50cc8fa..b5a07f0d3e9ec 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType, + self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType, }; use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy}; use rustc_session::lint; @@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("fcx {}", self.tag()); // FIXME: is_identity being on `UserType` and not `Canonical` is awkward - if !canonical_user_type_annotation.value.is_identity() { + if !canonical_user_type_annotation.is_identity() { self.typeck_results .borrow_mut() .user_provided_types_mut() diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cc0db39ac5719..5d6d46e16b784 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -106,8 +106,8 @@ pub use self::sty::{ }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ - CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, TypeckResults, - UserType, UserTypeAnnotationIndex, + CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, + TypeckResults, UserType, UserTypeAnnotationIndex, }; pub mod _match; diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 51f36e282e2ac..58ad1eb900fd5 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -607,11 +607,15 @@ pub enum UserType<'tcx> { TypeOf(DefId, UserArgs<'tcx>), } -impl<'tcx> UserType<'tcx> { +pub trait IsIdentity { + fn is_identity(&self) -> bool; +} + +impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { - match self { + fn is_identity(&self) -> bool { + match self.value { UserType::Ty(_) => false, UserType::TypeOf(_, user_args) => { if user_args.user_self_ty.is_some() { From 92b41eeee6ffef609e2216dd145c88ba0fb14102 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Oct 2023 16:26:36 +0000 Subject: [PATCH 09/13] Rename in preparation for moving the `async` printing out of `CoroutineSource` --- compiler/rustc_hir/src/hir.rs | 2 +- tests/ui/async-await/async-await-let-else.stderr | 4 ++-- tests/ui/async-await/issue-68112.stderr | 2 +- tests/ui/async-await/issue-70935-complex-spans.stderr | 2 +- tests/ui/async-await/issues/issue-67893.stderr | 2 +- tests/ui/async-await/partial-drop-partial-reinit.rs | 2 +- tests/ui/async-await/partial-drop-partial-reinit.stderr | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 0e14a0e43460b..e39ddd8f28461 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1568,7 +1568,7 @@ impl CoroutineSource { match self { CoroutineSource::Block => "`async` block", CoroutineSource::Closure => "`async` closure body", - CoroutineSource::Fn => "`async fn` body", + CoroutineSource::Fn => "`async` fn body", } } } diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr index c3b4e761824f8..b360aab6b595f 100644 --- a/tests/ui/async-await/async-await-let-else.stderr +++ b/tests/ui/async-await/async-await-let-else.stderr @@ -30,7 +30,7 @@ LL | is_send(foo2(Some(true))); | required by a bound introduced by this call | = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/async-await-let-else.rs:24:29 | LL | async fn bar2(_: T) -> ! { @@ -39,7 +39,7 @@ LL | | panic!() LL | | } | |_^ = note: required because it captures the following types: `impl Future` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/async-await-let-else.rs:18:32 | LL | async fn foo2(x: Option) { diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr index 17b619ebee32a..1cd8beac26035 100644 --- a/tests/ui/async-await/issue-68112.stderr +++ b/tests/ui/async-await/issue-68112.stderr @@ -45,7 +45,7 @@ LL | require_send(send_fut); = help: the trait `Sync` is not implemented for `RefCell` = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead = note: required for `Arc>` to implement `Send` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/issue-68112.rs:47:31 | LL | async fn ready2(t: T) -> T { diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index ab834daa85dc2..d0605d7e1a6f2 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -18,7 +18,7 @@ note: required because it's used within this closure | LL | baz(|| async { | ^^ -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/issue-70935-complex-spans.rs:12:67 | LL | async fn baz(_c: impl FnMut() -> T) where T: Future { diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr index 3d6d1fb5c0919..2a712aee9c481 100644 --- a/tests/ui/async-await/issues/issue-67893.stderr +++ b/tests/ui/async-await/issues/issue-67893.stderr @@ -13,7 +13,7 @@ LL | pub async fn run() { | = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` = note: required because it captures the following types: `Arc>`, `MutexGuard<'_, ()>`, `impl Future` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/auxiliary/issue_67893.rs:9:20 | LL | pub async fn run() { diff --git a/tests/ui/async-await/partial-drop-partial-reinit.rs b/tests/ui/async-await/partial-drop-partial-reinit.rs index 75acb442e7a33..815cc916b41f6 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.rs +++ b/tests/ui/async-await/partial-drop-partial-reinit.rs @@ -26,7 +26,7 @@ impl Drop for NotSend { impl !Send for NotSend {} async fn foo() { - //~^ NOTE used within this `async fn` body + //~^ NOTE used within this `async` fn body //~| NOTE within this `impl Future let mut x = (NotSend {},); drop(x.0); diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr index d115c1b1cc4bd..310a292395571 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.stderr +++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr @@ -12,7 +12,7 @@ LL | async fn foo() { = help: within `impl Future`, the trait `Send` is not implemented for `NotSend` = note: required because it appears within the type `(NotSend,)` = note: required because it captures the following types: `(NotSend,)`, `impl Future` -note: required because it's used within this `async fn` body +note: required because it's used within this `async` fn body --> $DIR/partial-drop-partial-reinit.rs:28:16 | LL | async fn foo() { From c601ade3ad7e59a31d4b429078034074566fd715 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 Oct 2023 16:37:21 +0000 Subject: [PATCH 10/13] Refactor away the need for some `descr` methods. Instead we use `Display` impls and their `alternate` render scheme to decide whether we want backticks or not. --- .../src/transform/check_consts/ops.rs | 2 +- compiler/rustc_hir/src/hir.rs | 35 +++++++------------ .../src/infer/error_reporting/mod.rs | 21 +++++------ compiler/rustc_middle/src/ty/error.rs | 8 +++-- .../src/traits/error_reporting/suggestions.rs | 4 +-- 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index 1258d71d52178..40183baccf8fe 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -372,7 +372,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine { ccx: &ConstCx<'_, 'tcx>, span: Span, ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> { - let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind()); + let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind()); if let hir::CoroutineKind::Async(hir::CoroutineSource::Block) = self.0 { ccx.tcx.sess.create_feature_err( errors::UnallowedOpInConstContext { span, msg }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e39ddd8f28461..259af4f565bda 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1520,21 +1520,19 @@ pub enum CoroutineKind { impl fmt::Display for CoroutineKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - CoroutineKind::Async(k) => fmt::Display::fmt(k, f), + CoroutineKind::Async(k) => { + if f.alternate() { + f.write_str("`async` ")?; + } else { + f.write_str("async ")? + } + k.fmt(f) + } CoroutineKind::Coroutine => f.write_str("coroutine"), } } } -impl CoroutineKind { - pub fn descr(&self) -> &'static str { - match self { - CoroutineKind::Async(ask) => ask.descr(), - CoroutineKind::Coroutine => "coroutine", - } - } -} - /// In the case of a coroutine created as part of an async/gen construct, /// which kind of async/gen construct caused it to be created? /// @@ -1555,21 +1553,12 @@ pub enum CoroutineSource { impl fmt::Display for CoroutineSource { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(match self { - CoroutineSource::Block => "async block", - CoroutineSource::Closure => "async closure body", - CoroutineSource::Fn => "async fn body", - }) - } -} - -impl CoroutineSource { - pub fn descr(&self) -> &'static str { match self { - CoroutineSource::Block => "`async` block", - CoroutineSource::Closure => "`async` closure body", - CoroutineSource::Fn => "`async` fn body", + CoroutineSource::Block => "block", + CoroutineSource::Closure => "closure body", + CoroutineSource::Fn => "fn body", } + .fmt(f) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ba118f8110f31..e4be435fded30 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1584,14 +1584,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { target: &str, types: &FxIndexMap>, ) { - for (key, values) in types.iter() { + for (kind, values) in types.iter() { let count = values.len(); - let kind = key.descr(); for &sp in values { err.span_label( sp, format!( - "{}{} {}{}", + "{}{} {:#}{}", if count == 1 { "the " } else { "one of the " }, target, kind, @@ -2952,17 +2951,19 @@ pub enum TyCategory { Foreign, } -impl TyCategory { - fn descr(&self) -> &'static str { +impl fmt::Display for TyCategory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::Closure => "closure", - Self::Opaque => "opaque type", - Self::OpaqueFuture => "future", - Self::Coroutine(gk) => gk.descr(), - Self::Foreign => "foreign type", + Self::Closure => "closure".fmt(f), + Self::Opaque => "opaque type".fmt(f), + Self::OpaqueFuture => "future".fmt(f), + Self::Coroutine(gk) => gk.fmt(f), + Self::Foreign => "foreign type".fmt(f), } } +} +impl TyCategory { pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> { match *ty.kind() { ty::Closure(def_id, _) => Some((Self::Closure, def_id)), diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 184a70ed4cb8c..738bb5e8b1959 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -241,7 +241,9 @@ impl<'tcx> Ty<'tcx> { } ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), - ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(), + ty::Coroutine(def_id, ..) => { + format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into() + } ty::CoroutineWitness(..) => "coroutine witness".into(), ty::Infer(ty::TyVar(_)) => "inferred type".into(), ty::Infer(ty::IntVar(_)) => "integer".into(), @@ -299,7 +301,9 @@ impl<'tcx> Ty<'tcx> { ty::FnPtr(_) => "fn pointer".into(), ty::Dynamic(..) => "trait object".into(), ty::Closure(..) => "closure".into(), - ty::Coroutine(def_id, ..) => tcx.coroutine_kind(def_id).unwrap().descr().into(), + ty::Coroutine(def_id, ..) => { + format!("{:#}", tcx.coroutine_kind(def_id).unwrap()).into() + } ty::CoroutineWitness(..) => "coroutine witness".into(), ty::Tuple(..) => "tuple".into(), ty::Placeholder(..) => "higher-ranked type".into(), 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 77d167eadd8cd..b9a08056ad162 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2995,11 +2995,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let sp = self.tcx.def_span(def_id); // Special-case this to say "async block" instead of `[static coroutine]`. - let kind = tcx.coroutine_kind(def_id).unwrap().descr(); + let kind = tcx.coroutine_kind(def_id).unwrap(); err.span_note( sp, with_forced_trimmed_paths!(format!( - "required because it's used within this {kind}", + "required because it's used within this {kind:#}", )), ) } From 6cb33764341e6a2a9b2b2c2b881204b54e52858b Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 30 Jul 2023 12:14:08 +0000 Subject: [PATCH 11/13] Add a comment explaining some weird `is_vtable_safe_method` behavior --- compiler/rustc_trait_selection/src/traits/object_safety.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 1dbe3039107c5..9984a3cbb29dd 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -97,6 +97,10 @@ fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { /// object. Note that object-safe traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or /// otherwise ensure that they cannot be used when `Self = Trait`. +/// +/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards +/// compatibility, see and +/// [`WHERE_CLAUSES_OBJECT_SAFETY`]. pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); From 89582351cf6e5a64298af282975bfec38621ca6f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 30 Jul 2023 12:15:18 +0000 Subject: [PATCH 12/13] Don't allow dead code --- compiler/rustc_trait_selection/src/traits/object_safety.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 9984a3cbb29dd..a0d578d581a3c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -714,7 +714,6 @@ fn object_ty_for_trait<'tcx>( // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this // fallback query: `Receiver: Unsize U]>` to support receivers like // `self: Wrapper`. -#[allow(dead_code)] fn receiver_is_dispatchable<'tcx>( tcx: TyCtxt<'tcx>, method: ty::AssocItem, From ecdbefa487c597a29184ac494d9d0eae175b1529 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 30 Jul 2023 15:14:39 +0000 Subject: [PATCH 13/13] Return multiple object-safety violation errors --- .../src/traits/object_safety.rs | 77 ++++++++++--------- .../object-safety-err-ret.stderr | 7 +- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index a0d578d581a3c..9443703cd0f74 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -109,10 +109,9 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A return false; } - match virtual_call_violation_for_method(tcx, trait_def_id, method) { - None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, - Some(_) => false, - } + virtual_call_violations_for_method(tcx, trait_def_id, method) + .iter() + .all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf)) } fn object_safety_violations_for_trait( @@ -123,7 +122,7 @@ fn object_safety_violations_for_trait( let mut violations: Vec<_> = tcx .associated_items(trait_def_id) .in_definition_order() - .filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item)) + .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item)) .collect(); // Check the trait itself. @@ -361,49 +360,52 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { /// Returns `Some(_)` if this item makes the containing trait not object safe. #[instrument(level = "debug", skip(tcx), ret)] -fn object_safety_violation_for_assoc_item( +fn object_safety_violations_for_assoc_item( tcx: TyCtxt<'_>, trait_def_id: DefId, item: ty::AssocItem, -) -> Option { +) -> Vec { // Any item that has a `Self : Sized` requisite is otherwise // exempt from the regulations. if tcx.generics_require_sized_self(item.def_id) { - return None; + return Vec::new(); } match item.kind { // Associated consts are never object safe, as they can't have `where` bounds yet at all, // and associated const bounds in trait objects aren't a thing yet either. ty::AssocKind::Const => { - Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)) + vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)] } - ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| { - let node = tcx.hir().get_if_local(item.def_id); - // Get an accurate span depending on the violation. - let span = match (&v, node) { - (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, - (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, - (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) - } - _ => item.ident(tcx).span, - }; + ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) + .into_iter() + .map(|v| { + let node = tcx.hir().get_if_local(item.def_id); + // Get an accurate span depending on the violation. + let span = match (&v, node) { + (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, + (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span, + (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span, + (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { + node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span()) + } + _ => item.ident(tcx).span, + }; - ObjectSafetyViolation::Method(item.name, v, span) - }), + ObjectSafetyViolation::Method(item.name, v, span) + }) + .collect(), // Associated types can only be object safe if they have `Self: Sized` bounds. ty::AssocKind::Type => { if !tcx.features().generic_associated_types_extended && !tcx.generics_of(item.def_id).params.is_empty() && !item.is_impl_trait_in_trait() { - Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)) + vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)] } else { // We will permit associated types if they are explicitly mentioned in the trait object. // We can't check this here, as here we only check if it is guaranteed to not be possible. - None + Vec::new() } } } @@ -413,11 +415,11 @@ fn object_safety_violation_for_assoc_item( /// object; this does not necessarily imply that the enclosing trait /// is not object safe, because the method might have a where clause /// `Self:Sized`. -fn virtual_call_violation_for_method<'tcx>( +fn virtual_call_violations_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem, -) -> Option { +) -> Vec { let sig = tcx.fn_sig(method.def_id).instantiate_identity(); // The method's first parameter must be named `self` @@ -442,9 +444,14 @@ fn virtual_call_violation_for_method<'tcx>( } else { None }; - return Some(MethodViolationCode::StaticMethod(sugg)); + + // Not having `self` parameter messes up the later checks, + // so we need to return instead of pushing + return vec![MethodViolationCode::StaticMethod(sugg)]; } + let mut errors = Vec::new(); + for (i, &input_ty) in sig.skip_binder().inputs().iter().enumerate().skip(1) { if contains_illegal_self_type_reference(tcx, trait_def_id, sig.rebind(input_ty)) { let span = if let Some(hir::Node::TraitItem(hir::TraitItem { @@ -456,20 +463,20 @@ fn virtual_call_violation_for_method<'tcx>( } else { None }; - return Some(MethodViolationCode::ReferencesSelfInput(span)); + errors.push(MethodViolationCode::ReferencesSelfInput(span)); } } if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output()) { - return Some(MethodViolationCode::ReferencesSelfOutput); + errors.push(MethodViolationCode::ReferencesSelfOutput); } if let Some(code) = contains_illegal_impl_trait_in_trait(tcx, method.def_id, sig.output()) { - return Some(code); + errors.push(code); } // We can't monomorphize things like `fn foo(...)`. let own_counts = tcx.generics_of(method.def_id).own_counts(); if own_counts.types > 0 || own_counts.consts > 0 { - return Some(MethodViolationCode::Generic); + errors.push(MethodViolationCode::Generic); } let receiver_ty = tcx.liberate_late_bound_regions(method.def_id, sig.input(0)); @@ -489,7 +496,7 @@ fn virtual_call_violation_for_method<'tcx>( } else { None }; - return Some(MethodViolationCode::UndispatchableReceiver(span)); + errors.push(MethodViolationCode::UndispatchableReceiver(span)); } else { // Do sanity check to make sure the receiver actually has the layout of a pointer. @@ -598,10 +605,10 @@ fn virtual_call_violation_for_method<'tcx>( contains_illegal_self_type_reference(tcx, trait_def_id, pred) }) { - return Some(MethodViolationCode::WhereClauseReferencesSelf); + errors.push(MethodViolationCode::WhereClauseReferencesSelf); } - None + errors } /// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr index 4e1d71f154558..7ce2b9ac95a59 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-ret.stderr @@ -5,12 +5,15 @@ LL | fn use_dyn(v: &dyn Foo) { | ^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/object-safety-err-ret.rs:8:23 + --> $DIR/object-safety-err-ret.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... LL | fn test(&self) -> [u8; bar::()]; - | ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type + | ^^^^ ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type + | | + | ...because method `test` references the `Self` type in its `where` clause + = help: consider moving `test` to another trait = help: consider moving `test` to another trait error: aborting due to previous error