summaryrefslogtreecommitdiff
path: root/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs42
1 files changed, 34 insertions, 8 deletions
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index c09457e1d65..e84da2519ae 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -80,7 +80,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
-use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
+use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt};
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
@@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
// Implementing a normal trait isn't a specialization.
return None;
}
+ if trait_def.is_marker {
+ // Overlapping marker implementations are not really specializations.
+ return None;
+ }
Some(impl2_node)
}
/// Check that `impl1` is a sound specialization
#[instrument(level = "debug", skip(tcx))]
fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) {
+ let span = tcx.def_span(impl1_def_id);
+ check_has_items(tcx, impl1_def_id, impl2_node, span);
+
if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) {
let impl2_def_id = impl2_node.def_id();
debug!(?impl2_def_id, ?impl2_substs);
@@ -116,7 +123,6 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs)
};
- let span = tcx.def_span(impl1_def_id);
check_constness(tcx, impl1_def_id, impl2_node, span);
check_static_lifetimes(tcx, &parent_substs, span);
check_duplicate_params(tcx, impl1_substs, &parent_substs, span);
@@ -124,6 +130,13 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
}
}
+fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
+ if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() {
+ let base_impl_span = tcx.def_span(impl2_id);
+ tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
+ }
+}
+
/// Check that the specializing impl `impl1` is at least as const as the base
/// impl `impl2`
fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
@@ -167,8 +180,21 @@ fn get_impl_substs(
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
- let impl2_substs =
- translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
+ let impl1_span = tcx.def_span(impl1_def_id);
+ let impl2_substs = translate_substs_with_cause(
+ infcx,
+ param_env,
+ impl1_def_id.to_def_id(),
+ impl1_substs,
+ impl2_node,
+ |_, span| {
+ traits::ObligationCause::new(
+ impl1_span,
+ impl1_def_id,
+ traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span),
+ )
+ },
+ );
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
@@ -272,7 +298,7 @@ fn check_duplicate_params<'tcx>(
if let (_, [duplicate, ..]) = base_params.partition_dedup() {
let param = impl1_substs[duplicate.0 as usize];
tcx.sess
- .struct_span_err(span, &format!("specializing impl repeats parameter `{}`", param))
+ .struct_span_err(span, format!("specializing impl repeats parameter `{}`", param))
.emit();
}
}
@@ -464,7 +490,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
tcx.sess
.struct_span_err(
span,
- &format!(
+ format!(
"cannot specialize on trait `{}`",
tcx.def_path_str(trait_ref.def_id),
),
@@ -479,7 +505,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
tcx.sess
.struct_span_err(
span,
- &format!("cannot specialize on associated type `{projection_ty} == {term}`",),
+ format!("cannot specialize on associated type `{projection_ty} == {term}`",),
)
.emit();
}
@@ -495,7 +521,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
}
_ => {
tcx.sess
- .struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate))
+ .struct_span_err(span, format!("cannot specialize on predicate `{}`", predicate))
.emit();
}
}