summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_hir_analysis/src/coherence
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_hir_analysis/src/coherence
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_hir_analysis/src/coherence')
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs287
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs29
5 files changed, 192 insertions, 141 deletions
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 0f40cca94..a98d8e171 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -1,9 +1,11 @@
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/codegen.
-use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
+use crate::errors::{
+ ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
+};
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
@@ -14,9 +16,11 @@ use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::misc::{
- type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
+ type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
+ ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
};
use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
@@ -27,6 +31,7 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
Checker { tcx, trait_def_id }
.check(lang_items.drop_trait(), visit_implementation_of_drop)
.check(lang_items.copy_trait(), visit_implementation_of_copy)
+ .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
}
@@ -74,120 +79,16 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
- let span = match tcx.hir().expect_item(impl_did).kind {
- ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return,
- ItemKind::Impl(impl_) => impl_.self_ty.span,
- _ => bug!("expected Copy impl item"),
+ let span = match tcx.hir().expect_item(impl_did).expect_impl() {
+ hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+ hir::Impl { self_ty, .. } => self_ty.span,
};
let cause = traits::ObligationCause::misc(span, impl_did);
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
Ok(()) => {}
- Err(CopyImplementationError::InfrigingFields(fields)) => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0204,
- "the trait `Copy` 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();
-
- 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, "this field does not implement `Copy`");
-
- match reason {
- InfringingFieldsReason::Fulfill(fulfillment_errors) => {
- for error in fulfillment_errors {
- let error_predicate = error.obligation.predicate;
- // Only note if it's not the root obligation, otherwise it's trivial and
- // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
- // FIXME: This error could be more descriptive, especially if the error_predicate
- // contains a foreign type or if it's a deeply nested type...
- if error_predicate != error.root_obligation.predicate {
- errors
- .entry((ty.to_string(), error_predicate.to_string()))
- .or_default()
- .push(error.obligation.cause.span);
- }
- if let ty::PredicateKind::Clause(ty::Clause::Trait(
- ty::TraitPredicate {
- trait_ref,
- polarity: ty::ImplPolarity::Positive,
- ..
- },
- )) = error_predicate.kind().skip_binder()
- {
- let ty = trait_ref.self_ty();
- if let ty::Param(_) = ty.kind() {
- bounds.push((
- format!("{ty}"),
- trait_ref.print_only_trait_path().to_string(),
- Some(trait_ref.def_id),
- ));
- }
- }
- }
- }
- InfringingFieldsReason::Regions(region_errors) => {
- for error in region_errors {
- let ty = ty.to_string();
- match error {
- RegionResolutionError::ConcreteFailure(origin, a, b) => {
- let predicate = format!("{b}: {a}");
- errors
- .entry((ty.clone(), predicate.clone()))
- .or_default()
- .push(origin.span());
- if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
- bounds.push((b.to_string(), a.to_string(), None));
- }
- }
- RegionResolutionError::GenericBoundFailure(origin, a, b) => {
- let predicate = format!("{a}: {b}");
- errors
- .entry((ty.clone(), predicate.clone()))
- .or_default()
- .push(origin.span());
- if let infer::region_constraints::GenericKind::Param(_) = a {
- bounds.push((a.to_string(), b.to_string(), None));
- }
- }
- _ => continue,
- }
- }
- }
- }
- }
- for ((ty, error_predicate), spans) in errors {
- let span: MultiSpan = spans.into();
- err.span_note(
- span,
- &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
- );
- }
- suggest_constraining_type_params(
- tcx,
- tcx.hir().get_generics(impl_did).expect("impls always have generics"),
- &mut err,
- bounds.iter().map(|(param, constraint, def_id)| {
- (param.as_str(), constraint.as_str(), *def_id)
- }),
- None,
- );
- err.emit();
+ Err(CopyImplementationError::InfringingFields(fields)) => {
+ infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
}
Err(CopyImplementationError::NotAnAdt) => {
tcx.sess.emit_err(CopyImplOnNonAdt { span });
@@ -198,6 +99,29 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
}
}
+fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+ let self_type = tcx.type_of(impl_did).subst_identity();
+ assert!(!self_type.has_escaping_bound_vars());
+
+ let param_env = tcx.param_env(impl_did);
+
+ let span = match tcx.hir().expect_item(impl_did).expect_impl() {
+ hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+ impl_ => impl_.self_ty.span,
+ };
+
+ let cause = traits::ObligationCause::misc(span, impl_did);
+ match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
+ Ok(()) => {}
+ Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
+ infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
+ }
+ Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
+ tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
+ }
+ }
+}
+
fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
@@ -289,7 +213,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
for structs containing the field being coerced, \
ZST fields with 1 byte alignment, and nothing else",
)
- .note(&format!(
+ .note(format!(
"extra field `{}` of type `{}` is not allowed",
field.name, ty_a,
))
@@ -317,7 +241,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
for a coercion between structures with a single field \
being coerced",
)
- .note(&format!(
+ .note(format!(
"currently, {} fields need coercions: {}",
coerced_fields.len(),
coerced_fields
@@ -341,10 +265,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
tcx,
cause.clone(),
param_env,
- ty::Binder::dummy(tcx.mk_trait_ref(
+ ty::TraitRef::new(
+ tcx,
dispatch_from_dyn_trait,
[field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
- )),
+ ),
));
}
let errors = ocx.select_all_or_error();
@@ -373,9 +298,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
- let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
- tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string()));
- });
+ let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
let source = tcx.type_of(impl_did).subst_identity();
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
@@ -545,7 +468,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
"`CoerceUnsized` may only be implemented for \
a coercion between structures with one field being coerced",
)
- .note(&format!(
+ .note(format!(
"currently, {} fields need coercions: {}",
diff_fields.len(),
diff_fields
@@ -580,8 +503,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
// Register an obligation for `A: Trait<B>`.
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did);
- let obligation =
- Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target]));
+ let obligation = Obligation::new(
+ tcx,
+ cause,
+ param_env,
+ ty::TraitRef::new(tcx, trait_def_id, [source, target]),
+ );
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
@@ -594,3 +521,119 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
CoerceUnsizedInfo { custom_kind: kind }
}
+
+fn infringing_fields_error(
+ tcx: TyCtxt<'_>,
+ fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
+ lang_item: LangItem,
+ impl_did: LocalDefId,
+ impl_span: Span,
+) -> ErrorGuaranteed {
+ let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
+
+ 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();
+
+ 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}`"));
+
+ match reason {
+ InfringingFieldsReason::Fulfill(fulfillment_errors) => {
+ for error in fulfillment_errors {
+ let error_predicate = error.obligation.predicate;
+ // Only note if it's not the root obligation, otherwise it's trivial and
+ // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+ // FIXME: This error could be more descriptive, especially if the error_predicate
+ // contains a foreign type or if it's a deeply nested type...
+ if error_predicate != error.root_obligation.predicate {
+ errors
+ .entry((ty.to_string(), error_predicate.to_string()))
+ .or_default()
+ .push(error.obligation.cause.span);
+ }
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
+ trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ ..
+ })) = error_predicate.kind().skip_binder()
+ {
+ let ty = trait_ref.self_ty();
+ if let ty::Param(_) = ty.kind() {
+ bounds.push((
+ format!("{ty}"),
+ trait_ref.print_only_trait_path().to_string(),
+ Some(trait_ref.def_id),
+ ));
+ }
+ }
+ }
+ }
+ InfringingFieldsReason::Regions(region_errors) => {
+ for error in region_errors {
+ let ty = ty.to_string();
+ match error {
+ RegionResolutionError::ConcreteFailure(origin, a, b) => {
+ let predicate = format!("{b}: {a}");
+ errors
+ .entry((ty.clone(), predicate.clone()))
+ .or_default()
+ .push(origin.span());
+ if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
+ bounds.push((b.to_string(), a.to_string(), None));
+ }
+ }
+ RegionResolutionError::GenericBoundFailure(origin, a, b) => {
+ let predicate = format!("{a}: {b}");
+ errors
+ .entry((ty.clone(), predicate.clone()))
+ .or_default()
+ .push(origin.span());
+ if let infer::region_constraints::GenericKind::Param(_) = a {
+ bounds.push((a.to_string(), b.to_string(), None));
+ }
+ }
+ _ => continue,
+ }
+ }
+ }
+ }
+ }
+ for ((ty, error_predicate), spans) in errors {
+ let span: MultiSpan = spans.into();
+ err.span_note(
+ span,
+ format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
+ );
+ }
+ suggest_constraining_type_params(
+ tcx,
+ tcx.hir().get_generics(impl_did).expect("impls always have generics"),
+ &mut err,
+ bounds
+ .iter()
+ .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
+ None,
+ );
+
+ err.emit()
+}
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 3d37e0ce0..335590206 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -146,7 +146,7 @@ impl<'tcx> InherentCollect<'tcx> {
);
err.help("consider using an extension trait instead");
if let ty::Ref(_, subty, _) = ty.kind() {
- err.note(&format!(
+ err.note(format!(
"you could also try moving the reference to \
uses of `{}` (such as `self`) within the implementation",
subty
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index ad76e2bed..bd6252344 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -3,7 +3,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Symbol;
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 465e787c9..4524b87a4 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -5,9 +5,10 @@
// done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here.
+use crate::errors;
use rustc_errors::{error_code, struct_span_err};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::sym;
use rustc_trait_selection::traits;
@@ -22,7 +23,7 @@ fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<
debug!(
"(checking implementation) adding impl for trait '{:?}', item '{}'",
trait_ref,
- tcx.def_path_str(impl_def_id.to_def_id())
+ tcx.def_path_str(impl_def_id)
);
// Skip impls where one of the self type is an error type.
@@ -67,13 +68,7 @@ fn enforce_trait_manually_implementable(
tcx.trait_def(trait_def_id).specialization_kind
{
if !tcx.features().specialization && !tcx.features().min_specialization {
- tcx.sess
- .struct_span_err(
- impl_header_span,
- "implementing `rustc_specialization_trait` traits is unstable",
- )
- .help("add `#![feature(min_specialization)]` to the crate attributes to enable")
- .emit();
+ tcx.sess.emit_err(errors::SpecializationTrait { span: impl_header_span });
return;
}
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 47c47de8c..23beacd2a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::util::IgnoreRegions;
+use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::{
self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor,
@@ -210,6 +210,19 @@ fn do_orphan_check_impl<'tcx>(
NonlocalImpl::DisallowOther,
),
+ // ```
+ // struct S<T>(T);
+ // impl<T: ?Sized> S<T> {
+ // type This = T;
+ // }
+ // impl<T: ?Sized> AutoTrait for S<T>::This {}
+ // ```
+ // FIXME(inherent_associated_types): The example code above currently leads to a cycle
+ ty::Alias(AliasKind::Inherent, _) => (
+ LocalImpl::Disallow { problematic_kind: "associated type" },
+ NonlocalImpl::DisallowOther,
+ ),
+
// type Opaque = impl Trait;
// impl AutoTrait for Opaque {}
ty::Alias(AliasKind::Opaque, _) => (
@@ -372,10 +385,10 @@ fn emit_orphan_check_error<'tcx>(
if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(self_ty_span, &msg);
+ err.span_label(self_ty_span, msg);
} else {
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(trait_span, &msg);
+ err.span_label(trait_span, msg);
}
}
err.note("define and implement a trait or new type instead");
@@ -457,7 +470,7 @@ fn emit_newtype_suggestion_for_raw_ptr(
ptr_ty: &ty::TypeAndMut<'_>,
diag: &mut Diagnostic,
) {
- if !self_ty.needs_subst() {
+ if !self_ty.has_param() {
let mut_key = ptr_ty.mutbl.prefix_str();
let msg_sugg = "consider introducing a new wrapper type".to_owned();
let sugg = vec![
@@ -494,7 +507,7 @@ fn lint_auto_trait_impl<'tcx>(
// Impls which completely cover a given root type are fine as they
// disable auto impls entirely. So only lint if the substs
// are not a permutation of the identity substs.
- let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
+ let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else {
// ok
return;
};
@@ -531,15 +544,15 @@ fn lint_auto_trait_impl<'tcx>(
let self_descr = tcx.def_descr(self_type_did);
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
- lint.note(&format!("`{}` is mentioned multiple times", arg));
+ lint.note(format!("`{}` is mentioned multiple times", arg));
}
ty::util::NotUniqueParam::NotParam(arg) => {
- lint.note(&format!("`{}` is not a generic parameter", arg));
+ lint.note(format!("`{}` is not a generic parameter", arg));
}
}
lint.span_note(
item_span,
- &format!(
+ format!(
"try using the same sequence of generic parameters as the {} definition",
self_descr,
),