summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/coherence
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/coherence')
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs212
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs94
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs1
3 files changed, 104 insertions, 203 deletions
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index c930537d4..be70acfc3 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -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;
@@ -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) {
@@ -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 });
}
}
}
@@ -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 });
}
}
}
@@ -152,11 +151,17 @@ 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);
+ // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
+ // pointers. This is enforced here: we only allow impls for references, raw pointers, and things
+ // that are effectively repr(transparent) newtypes around types that already hav a
+ // DispatchedFromDyn impl. We cannot literally use repr(transparent) on those tpyes since some
+ // of them support an allocator, but we ensure that for the cases where the type implements this
+ // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
+ // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
+ // even if they do not carry that attribute.
use rustc_type_ir::sty::TyKind::*;
match (source.kind(), target.kind()) {
(&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
@@ -168,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;
@@ -195,8 +197,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
let ty_b = field.ty(tcx, args_b);
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
- if layout.is_zst() && layout.align.abi.bytes() == 1 {
- // ignore ZST fields with alignment of 1 byte
+ if layout.is_1zst() {
+ // ignore 1-ZST fields
return false;
}
}
@@ -205,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;
}
@@ -225,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 {
@@ -280,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" });
}
}
}
@@ -351,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;
}
@@ -437,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);
@@ -455,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;
}
@@ -487,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;
}
};
@@ -532,13 +491,6 @@ 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();
@@ -546,14 +498,15 @@ fn infringing_fields_error(
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) => {
@@ -617,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"),
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index a94c75f91..0042d683b 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -7,7 +7,6 @@
//! `tcx.inherent_impls(def_id)`). That value, however,
//! is computed by selecting an idea from this table.
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -15,6 +14,8 @@ use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
use rustc_span::symbol::sym;
+use crate::errors;
+
/// On-demand query: yields a map containing all types mapped to their inherent impls.
pub fn crate_inherent_impls(tcx: TyCtxt<'_>, (): ()) -> CrateInherentImpls {
let mut collect = InherentCollect { tcx, impls_map: Default::default() };
@@ -45,14 +46,6 @@ struct InherentCollect<'tcx> {
impls_map: CrateInherentImpls,
}
-const INTO_CORE: &str = "consider moving this inherent impl into `core` if possible";
-const INTO_DEFINING_CRATE: &str =
- "consider moving this inherent impl into the crate defining the type if possible";
-const ADD_ATTR_TO_TY: &str = "alternatively add `#[rustc_has_incoherent_inherent_impls]` to the type \
- and `#[rustc_allow_incoherent_impl]` to the relevant impl items";
-const ADD_ATTR: &str =
- "alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items";
-
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, impl_def_id: LocalDefId, self_ty: Ty<'tcx>, ty_def_id: DefId) {
if let Some(ty_def_id) = ty_def_id.as_local() {
@@ -69,30 +62,17 @@ impl<'tcx> InherentCollect<'tcx> {
if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
let impl_span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
- impl_span,
- E0390,
- "cannot define inherent `impl` for a type outside of the crate where the type is defined",
- )
- .help(INTO_DEFINING_CRATE)
- .span_help(impl_span, ADD_ATTR_TO_TY)
- .emit();
+ self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
return;
}
for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let impl_span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
- impl_span,
- E0390,
- "cannot define inherent `impl` for a type outside of the crate where the type is defined",
- )
- .help(INTO_DEFINING_CRATE)
- .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
- .emit();
+ self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
+ span: impl_span,
+ help_span: self.tcx.def_span(impl_item),
+ });
return;
}
}
@@ -104,16 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
}
} else {
let impl_span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
- impl_span,
- E0116,
- "cannot define inherent `impl` for a type outside of the crate \
- where the type is defined"
- )
- .span_label(impl_span, "impl for type defined outside of crate.")
- .note("define and implement a trait or new type instead")
- .emit();
+ self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
}
}
@@ -124,34 +95,20 @@ impl<'tcx> InherentCollect<'tcx> {
for &impl_item in items {
if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
let span = self.tcx.def_span(impl_def_id);
- struct_span_err!(
- self.tcx.sess,
+ self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
span,
- E0390,
- "cannot define inherent `impl` for primitive types outside of `core`",
- )
- .help(INTO_CORE)
- .span_help(self.tcx.def_span(impl_item), ADD_ATTR)
- .emit();
+ help_span: self.tcx.def_span(impl_item),
+ });
return;
}
}
} else {
let span = self.tcx.def_span(impl_def_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0390,
- "cannot define inherent `impl` for primitive types",
- );
- err.help("consider using an extension trait instead");
+ let mut note = None;
if let ty::Ref(_, subty, _) = ty.kind() {
- err.note(format!(
- "you could also try moving the reference to \
- uses of `{subty}` (such as `self`) within the implementation"
- ));
+ note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
}
- err.emit();
+ self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
return;
}
}
@@ -178,15 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
}
ty::Dynamic(..) => {
- struct_span_err!(
- self.tcx.sess,
- item_span,
- E0785,
- "cannot define inherent `impl` for a dyn auto trait"
- )
- .span_label(item_span, "impl requires at least one non-auto trait")
- .note("define and implement a new trait or type instead")
- .emit();
+ self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
}
ty::Bool
| ty::Char
@@ -202,23 +151,12 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::FnPtr(_)
| ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
ty::Alias(..) | ty::Param(_) => {
- let mut err = struct_span_err!(
- self.tcx.sess,
- item_span,
- E0118,
- "no nominal type found for inherent implementation"
- );
-
- err.span_label(item_span, "impl requires a nominal type")
- .note("either implement a trait on it or create a newtype to wrap it instead");
-
- err.emit();
+ self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
}
ty::FnDef(..)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index bbdb108c5..69020b1f1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -245,7 +245,6 @@ fn do_orphan_check_impl<'tcx>(
ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Infer(..) => {