Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions compiler/rustc_hir_analysis/src/check/always_applicable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rustc_span::sym;
use rustc_trait_selection::regions::InferCtxtRegionExt;
use rustc_trait_selection::traits::{self, ObligationCtxt};

use crate::check::missing_items_must_implement_one_of_err;
use crate::diagnostics;
use crate::hir::def_id::{DefId, LocalDefId};

Expand Down Expand Up @@ -394,11 +395,12 @@ fn check_drop_xor_pin_drop<'tcx>(
match (drop_span, pin_drop_span) {
(None, None) => {
if tcx.features().pin_ergonomics() {
return Err(tcx.dcx().emit_err(crate::diagnostics::MissingOneOfTraitItem {
span: tcx.def_span(drop_impl_did),
note: None,
missing_items_msg: "drop`, `pin_drop".to_string(),
}));
return Err(missing_items_must_implement_one_of_err(
tcx,
drop_impl_did,
[sym::drop, sym::pin_drop].into_iter(),
None,
));
} else {
return Err(tcx
.dcx()
Expand Down
12 changes: 3 additions & 9 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1436,19 +1436,13 @@ fn check_impl_items_against_trait<'tcx>(
}

if !missing_items.is_empty() {
let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));
missing_items_err(tcx, impl_id, &missing_items, full_impl_span);
missing_items_err(tcx, impl_id, &missing_items);
}

if let Some(missing_items) = must_implement_one_of {
let attr_span = find_attr!(tcx, trait_ref.def_id, RustcMustImplementOneOf {attr_span, ..} => *attr_span);

missing_items_must_implement_one_of_err(
tcx,
tcx.def_span(impl_id),
missing_items,
attr_span,
);
let missing_items = missing_items.into_iter().map(|i| i.name);
missing_items_must_implement_one_of_err(tcx, impl_id, missing_items, attr_span);
}
}
}
Expand Down
70 changes: 50 additions & 20 deletions compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ use tracing::debug;

use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
use self::region::region_scope_tree;
use crate::diagnostics::{
MissingTraitItemLabel, MissingTraitItemSuggestion, MissingTraitItemSuggestionNone,
};
use crate::{check_c_variadic_abi, diagnostics};

/// Adds query implementations to the [Providers] vtable, see [`rustc_middle::query`]
Expand Down Expand Up @@ -203,11 +206,30 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
}
}

fn missing_items_err(
fn impl_suggestion_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span {
let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_def_id));
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
&& snippet.ends_with("}")
{
// `Span` before impl block closing brace.
let hi = full_impl_span.hi() - BytePos(1);
// Point at the place right before the closing brace of the relevant `impl` to suggest
// adding the associated item at the end of its body.
full_impl_span.with_lo(hi).with_hi(hi)
} else {
full_impl_span.shrink_to_hi()
}
}

fn missing_items_suggestions(
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
missing_items: &[ty::AssocItem],
full_impl_span: Span,
) -> (
String,
Vec<MissingTraitItemSuggestion>,
Vec<MissingTraitItemSuggestionNone>,
Vec<MissingTraitItemLabel>,
) {
let missing_items =
missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
Expand All @@ -218,17 +240,7 @@ fn missing_items_err(
.collect::<Vec<_>>()
.join("`, `");

let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
&& snippet.ends_with("}")
{
// `Span` before impl block closing brace.
let hi = full_impl_span.hi() - BytePos(1);
// Point at the place right before the closing brace of the relevant `impl` to suggest
// adding the associated item at the end of its body.
full_impl_span.with_lo(hi).with_hi(hi)
} else {
full_impl_span.shrink_to_hi()
};
let sugg_sp = impl_suggestion_span(tcx, impl_def_id);

// Obtain the level of indentation ending in `sugg_sp`.
let padding = tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(String::new);
Expand Down Expand Up @@ -259,6 +271,13 @@ fn missing_items_err(
}
}

(missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label)
}

fn missing_items_err(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, missing_items: &[ty::AssocItem]) {
let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) =
missing_items_suggestions(tcx, impl_def_id, missing_items);

tcx.dcx().emit_err(diagnostics::MissingTraitItem {
span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
missing_items_msg,
Expand All @@ -270,18 +289,29 @@ fn missing_items_err(

fn missing_items_must_implement_one_of_err(
tcx: TyCtxt<'_>,
impl_span: Span,
missing_items: &[Ident],
impl_def_id: LocalDefId,
missing_items: impl Iterator<Item = Symbol>,
Comment thread
joshtriplett marked this conversation as resolved.
annotation_span: Option<Span>,
) {
let missing_items_msg =
missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
) -> ErrorGuaranteed {
// Look up the associated items so we can use them to emit better errors.
let trait_def_id = tcx.impl_trait_id(impl_def_id);
let assoc_items = tcx.associated_items(trait_def_id);
let missing_items = missing_items
.flat_map(|s| assoc_items.filter_by_name_unhygienic_and_kind(s, ty::AssocTag::Fn))
.cloned()
.collect::<Vec<_>>();

let (missing_items_msg, missing_trait_item, missing_trait_item_none, missing_trait_item_label) =
missing_items_suggestions(tcx, impl_def_id, &missing_items);

tcx.dcx().emit_err(diagnostics::MissingOneOfTraitItem {
span: impl_span,
span: tcx.def_span(impl_def_id),
note: annotation_span,
missing_items_msg,
});
missing_trait_item_label,
missing_trait_item,
missing_trait_item_none,
})
}

fn default_body_is_unstable(
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir_analysis/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,12 @@ pub(crate) struct MissingOneOfTraitItem {
pub span: Span,
#[note("required because of this annotation")]
pub note: Option<Span>,
#[subdiagnostic]
pub missing_trait_item_label: Vec<MissingTraitItemLabel>,
#[subdiagnostic]
pub missing_trait_item: Vec<MissingTraitItemSuggestion>,
#[subdiagnostic]
pub missing_trait_item_none: Vec<MissingTraitItemSuggestionNone>,
pub missing_items_msg: String,
}

Expand Down
6 changes: 6 additions & 0 deletions tests/ui/pin-ergonomics/pinned-drop-check.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,18 @@ error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop
|
LL | impl Drop for Foo {}
| ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation
|
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
= help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }`

error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop`
--> $DIR/pinned-drop-check.rs:60:5
|
LL | impl Drop for Bar {}
| ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation
|
= help: implement the missing item: `fn drop(&mut self) { todo!() }`
= help: implement the missing item: `fn pin_drop(self: Pin<&mut Self>) { todo!() }`

error: `Bar` must implement `pin_drop`
--> $DIR/pinned-drop-check.rs:87:9
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
error[E0046]: not all trait items implemented, missing one of: `eq`, `neq`
--> $DIR/rustc_must_implement_one_of.rs:41:1
|
LL | fn eq(&self, other: &Self) -> bool {
| ---------------------------------- `eq` from trait
...
LL | fn neq(&self, other: &Self) -> bool {
| ----------------------------------- `neq` from trait
...
LL | impl Equal for T3 {}
| ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation
|
Expand Down
Loading