Skip to content

Migrate rustc_hir_analysis to session diagnostic [Part 5] #115821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 29, 2023
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
25 changes: 25 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr
hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
.label = `for<...>` is here

hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures

hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
.note = `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
.coercions_note = currently, {$number} fields need coercions: {$coercions}
.label = requires multiple coercions

hir_analysis_coercion_between_struct_same_note = expected coercion between the same definition; expected `{$source_path}`, found `{$target_path}`

hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found

hir_analysis_const_bound_for_non_const_trait =
~const can only be applied to `#[const_trait]` traits

Expand All @@ -57,6 +68,15 @@ hir_analysis_copy_impl_on_type_with_dtor =
the trait `Copy` cannot be implemented for this type; the type has a destructor
.label = `Copy` not allowed on types with destructors

hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
.note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
.coercions_note = currently, {$number} fields need coercions: {$coercions}

hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`

hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment, and nothing else
.note = extra field `{$name}` of type `{$ty}` is not allowed

hir_analysis_drop_impl_negative = negative `Drop` impls are not supported

hir_analysis_drop_impl_on_wrong_item =
Expand Down Expand Up @@ -228,6 +248,8 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
.label = not allowed in type signatures

hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`

hir_analysis_return_type_notation_conflicting_bound =
ambiguous associated function `{$assoc_name}` for `{$ty_name}`
.note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
Expand Down Expand Up @@ -295,6 +317,9 @@ hir_analysis_too_large_static = extern static is too large for the current archi
hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
.suggestion = remove this annotation

hir_analysis_trait_cannot_impl_for_ty = the trait `{$trait_name}` cannot be implemented for this type
.label = this field does not implement `{$trait_name}`

hir_analysis_trait_object_declared_with_no_traits =
at least one trait is required for an object type
.alias_span = this alias does not contain a trait
Expand Down
200 changes: 78 additions & 122 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/codegen.

use crate::errors::{
ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
};
use crate::errors;

use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
Expand Down Expand Up @@ -65,7 +64,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {

let impl_ = tcx.hir().expect_item(impl_did).expect_impl();

tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span });
tcx.sess.emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span });
}

fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
Expand All @@ -91,10 +90,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
}
Err(CopyImplementationError::NotAnAdt) => {
tcx.sess.emit_err(CopyImplOnNonAdt { span });
tcx.sess.emit_err(errors::CopyImplOnNonAdt { span });
}
Err(CopyImplementationError::HasDestructor) => {
tcx.sess.emit_err(CopyImplOnTypeWithDtor { span });
tcx.sess.emit_err(errors::CopyImplOnTypeWithDtor { span });
}
}
}
Expand All @@ -117,7 +116,7 @@ fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId)
infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
}
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
tcx.sess.emit_err(errors::ConstParamTyImplOnNonAdt { span });
}
}
}
Expand Down Expand Up @@ -152,8 +151,6 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef

let param_env = tcx.param_env(impl_did);

let create_err = |msg: &str| struct_span_err!(tcx.sess, span, E0378, "{}", msg);

let infcx = tcx.infer_ctxt().build();
let cause = ObligationCause::misc(span, impl_did);

Expand All @@ -176,22 +173,19 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
let source_path = tcx.def_path_str(def_a.did());
let target_path = tcx.def_path_str(def_b.did());

create_err(&format!(
"the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures with the same \
definition; expected `{source_path}`, found `{target_path}`",
))
.emit();
tcx.sess.emit_err(errors::DispatchFromDynCoercion {
span,
trait_name: "DispatchFromDyn",
note: true,
source_path,
target_path,
});

return;
}

if def_a.repr().c() || def_a.repr().packed() {
create_err(
"structs implementing `DispatchFromDyn` may not have \
`#[repr(packed)]` or `#[repr(C)]`",
)
.emit();
tcx.sess.emit_err(errors::DispatchFromDynRepr { span });
}

let fields = &def_a.non_enum_variant().fields;
Expand All @@ -213,16 +207,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
{
if ok.obligations.is_empty() {
create_err(
"the trait `DispatchFromDyn` may only be implemented \
for structs containing the field being coerced, \
ZST fields with 1 byte alignment, and nothing else",
)
.note(format!(
"extra field `{}` of type `{}` is not allowed",
field.name, ty_a,
))
.emit();
tcx.sess.emit_err(errors::DispatchFromDynZST {
span,
name: field.name,
ty: ty_a,
});

return false;
}
Expand All @@ -233,36 +222,29 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
.collect::<Vec<_>>();

if coerced_fields.is_empty() {
create_err(
"the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures with a single field \
being coerced, none found",
)
.emit();
tcx.sess.emit_err(errors::DispatchFromDynSingle {
span,
trait_name: "DispatchFromDyn",
note: true,
});
} else if coerced_fields.len() > 1 {
create_err("implementing the `DispatchFromDyn` trait requires multiple coercions")
.note(
"the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures with a single field \
being coerced",
)
.note(format!(
"currently, {} fields need coercions: {}",
coerced_fields.len(),
coerced_fields
.iter()
.map(|field| {
format!(
"`{}` (`{}` to `{}`)",
field.name,
field.ty(tcx, args_a),
field.ty(tcx, args_b),
)
})
.collect::<Vec<_>>()
.join(", ")
))
.emit();
tcx.sess.emit_err(errors::DispatchFromDynMulti {
span,
coercions_note: true,
number: coerced_fields.len(),
coercions: coerced_fields
.iter()
.map(|field| {
format!(
"`{}` (`{}` to `{}`)",
field.name,
field.ty(tcx, args_a),
field.ty(tcx, args_b),
)
})
.collect::<Vec<_>>()
.join(", "),
});
} else {
let ocx = ObligationCtxt::new(&infcx);
for field in coerced_fields {
Expand All @@ -288,11 +270,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
}
}
_ => {
create_err(
"the trait `DispatchFromDyn` may only be implemented \
for a coercion between structures",
)
.emit();
tcx.sess.emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" });
}
}
}
Expand Down Expand Up @@ -359,17 +337,13 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
if def_a != def_b {
let source_path = tcx.def_path_str(def_a.did());
let target_path = tcx.def_path_str(def_b.did());
struct_span_err!(
tcx.sess,
tcx.sess.emit_err(errors::DispatchFromDynSame {
span,
E0377,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with the same \
definition; expected `{}`, found `{}`",
trait_name: "CoerceUnsized",
note: true,
source_path,
target_path
)
.emit();
target_path,
});
return err_info;
}

Expand Down Expand Up @@ -445,15 +419,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
.collect::<Vec<_>>();

if diff_fields.is_empty() {
struct_span_err!(
tcx.sess,
tcx.sess.emit_err(errors::CoerceUnsizedOneField {
span,
E0374,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, none found"
)
.emit();
trait_name: "CoerceUnsized",
note: true,
});
return err_info;
} else if diff_fields.len() > 1 {
let item = tcx.hir().expect_item(impl_did);
Expand All @@ -463,29 +433,17 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
tcx.def_span(impl_did)
};

struct_span_err!(
tcx.sess,
tcx.sess.emit_err(errors::CoerceUnsizedMulti {
span,
E0375,
"implementing the trait \
`CoerceUnsized` requires multiple \
coercions"
)
.note(
"`CoerceUnsized` may only be implemented for \
a coercion between structures with one field being coerced",
)
.note(format!(
"currently, {} fields need coercions: {}",
diff_fields.len(),
diff_fields
coercions_note: true,
number: diff_fields.len(),
coercions: diff_fields
.iter()
.map(|&(i, a, b)| { format!("`{}` (`{}` to `{}`)", fields[i].name, a, b) })
.map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
.collect::<Vec<_>>()
.join(", ")
))
.span_label(span, "requires multiple coercions")
.emit();
.join(", "),
});

return err_info;
}

Expand All @@ -495,14 +453,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
}

_ => {
struct_span_err!(
tcx.sess,
span,
E0376,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures"
)
.emit();
tcx.sess.emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" });
return err_info;
}
};
Expand Down Expand Up @@ -540,28 +491,22 @@ fn infringing_fields_error(

let trait_name = tcx.def_path_str(trait_did);

let mut err = struct_span_err!(
tcx.sess,
impl_span,
E0204,
"the trait `{trait_name}` cannot be implemented for this type"
);

// We'll try to suggest constraining type parameters to fulfill the requirements of
// their `Copy` implementation.
let mut errors: BTreeMap<_, Vec<_>> = Default::default();
let mut bounds = vec![];

let mut seen_tys = FxHashSet::default();

let mut label_spans = Vec::new();

for (field, ty, reason) in fields {
// Only report an error once per type.
if !seen_tys.insert(ty) {
continue;
}

let field_span = tcx.def_span(field.did);
err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
label_spans.push(tcx.def_span(field.did));

match reason {
InfringingFieldsReason::Fulfill(fulfillment_errors) => {
Expand Down Expand Up @@ -625,13 +570,24 @@ fn infringing_fields_error(
}
}
}
let mut notes = Vec::new();
for ((ty, error_predicate), spans) in errors {
let span: MultiSpan = spans.into();
err.span_note(
notes.push(errors::ImplForTyRequires {
span,
format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
);
error_predicate,
trait_name: trait_name.clone(),
ty,
});
}

let mut err = tcx.sess.create_err(errors::TraitCannotImplForTy {
span: impl_span,
trait_name,
label_spans,
notes,
});

suggest_constraining_type_params(
tcx,
tcx.hir().get_generics(impl_did).expect("impls always have generics"),
Expand Down
Loading