1use rustc_data_structures::fx::FxHashSet;
69use rustc_hir::def_id::{DefId, LocalDefId};
70use rustc_infer::infer::TyCtxtInferExt;
71use rustc_infer::traits::specialization_graph::Node;
72use rustc_infer::traits::{ObligationCause, TraitErrors};
73use rustc_middle::ty::trait_def::TraitSpecializationKind;
74use rustc_middle::ty::{self, GenericArg, GenericArgs, TyCtxt, TypeVisitableExt, TypingMode};
75use rustc_span::{ErrorGuaranteed, Span};
76use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
77use rustc_trait_selection::traits::{self, ObligationCtxt, translate_args_with_cause, wf};
78use tracing::{debug, instrument};
79
80use crate::diagnostics::GenericArgsOnOverriddenImpl;
81use crate::{constrained_generic_params as cgp, diagnostics};
82
83pub(super) fn check_min_specialization(
84 tcx: TyCtxt<'_>,
85 impl_def_id: LocalDefId,
86) -> Result<(), ErrorGuaranteed> {
87 if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
88 check_always_applicable(tcx, impl_def_id, node)?;
89 }
90 Ok(())
91}
92
93fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
94 let trait_ref = tcx.impl_trait_ref(impl1_def_id);
95 let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
96
97 let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
98
99 let always_applicable_trait =
100 #[allow(non_exhaustive_omitted_patterns)] match trait_def.specialization_kind
{
TraitSpecializationKind::AlwaysApplicable => true,
_ => false,
}matches!(trait_def.specialization_kind, TraitSpecializationKind::AlwaysApplicable);
101 if impl2_node.is_from_trait() && !always_applicable_trait {
102 return None;
104 }
105 if trait_def.is_marker {
106 return None;
108 }
109 Some(impl2_node)
110}
111
112{}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("check_always_applicable",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(113u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::impl_wf_check::min_specialization"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl1_def_id")
}> =
::tracing::__macro_support::FieldName::new("impl1_def_id");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl2_node")
}> =
::tracing::__macro_support::FieldName::new("impl2_node");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl1_def_id)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl2_node)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Result<(), ErrorGuaranteed> =
loop {};
return __tracing_attr_fake_return;
}
{
let span = tcx.def_span(impl1_def_id);
let (impl1_args, impl2_args) =
get_impl_args(tcx, impl1_def_id, impl2_node)?;
let impl2_def_id = impl2_node.def_id();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs:123",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(123u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::impl_wf_check::min_specialization"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl2_def_id")
}> =
::tracing::__macro_support::FieldName::new("impl2_def_id");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl2_args")
}> =
::tracing::__macro_support::FieldName::new("impl2_args");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl2_def_id)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl2_args)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
let parent_args =
if impl2_node.is_from_trait() {
impl2_args.as_slice().to_vec()
} else {
unconstrained_parent_impl_args(tcx, impl2_def_id,
impl2_args)
};
check_has_items(tcx, impl1_def_id, impl2_node,
span).and(check_static_lifetimes(tcx, &parent_args,
span)).and(check_duplicate_params(tcx, impl1_args,
parent_args,
span)).and(check_predicates(tcx, impl1_def_id, impl1_args,
impl2_node, impl2_args, span))
}
}
}#[instrument(level = "debug", skip(tcx))]
114fn check_always_applicable(
115 tcx: TyCtxt<'_>,
116 impl1_def_id: LocalDefId,
117 impl2_node: Node,
118) -> Result<(), ErrorGuaranteed> {
119 let span = tcx.def_span(impl1_def_id);
120
121 let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?;
122 let impl2_def_id = impl2_node.def_id();
123 debug!(?impl2_def_id, ?impl2_args);
124
125 let parent_args = if impl2_node.is_from_trait() {
126 impl2_args.as_slice().to_vec()
127 } else {
128 unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
129 };
130
131 check_has_items(tcx, impl1_def_id, impl2_node, span)
132 .and(check_static_lifetimes(tcx, &parent_args, span))
133 .and(check_duplicate_params(tcx, impl1_args, parent_args, span))
134 .and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span))
135}
136
137fn check_has_items(
138 tcx: TyCtxt<'_>,
139 impl1_def_id: LocalDefId,
140 impl2_node: Node,
141 span: Span,
142) -> Result<(), ErrorGuaranteed> {
143 if let Node::Impl(impl2_id) = impl2_node
144 && tcx.associated_item_def_ids(impl1_def_id).is_empty()
145 {
146 let base_impl_span = tcx.def_span(impl2_id);
147 return Err(tcx.dcx().emit_err(diagnostics::EmptySpecialization { span, base_impl_span }));
148 }
149 Ok(())
150}
151
152fn get_impl_args(
165 tcx: TyCtxt<'_>,
166 impl1_def_id: LocalDefId,
167 impl2_node: Node,
168) -> Result<(GenericArgs<'_>, GenericArgs<'_>), ErrorGuaranteed> {
169 let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
170 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
171 let param_env = tcx.param_env(impl1_def_id);
172 let impl1_span = tcx.def_span(impl1_def_id);
173
174 let impl1_args = GenericArgs::identity_for_item(tcx, impl1_def_id);
175 let impl2_args = translate_args_with_cause(
176 infcx,
177 param_env,
178 impl1_def_id.to_def_id(),
179 impl1_args,
180 impl2_node,
181 &ObligationCause::misc(impl1_span, impl1_def_id),
182 );
183
184 let errors = ocx.evaluate_obligations_error_on_ambiguity();
185 if let TraitErrors::HasErrors(errors) = errors {
186 let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(errors);
187 return Err(guar);
188 }
189
190 let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
191 ocx.resolve_regions_and_report_errors(impl1_def_id, param_env, assumed_wf_types)?;
192 let Ok(impl2_args) = infcx.deeply_resolve_via_region_graph(impl2_args) else {
193 let span = tcx.def_span(impl1_def_id);
194 let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
195 return Err(guar);
196 };
197 Ok((impl1_args, impl2_args))
198}
199
200fn unconstrained_parent_impl_args<'tcx>(
209 tcx: TyCtxt<'tcx>,
210 impl_def_id: DefId,
211 impl_args: GenericArgs<'tcx>,
212) -> Vec<GenericArg<'tcx>> {
213 let impl_generic_clauses = tcx.clauses_of(impl_def_id);
214 let mut unconstrained_parameters = FxHashSet::default();
215 let mut constrained_params = FxHashSet::default();
216 let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip();
217
218 for (clause, _) in impl_generic_clauses.clauses.iter() {
223 if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() {
224 let unbound_trait_ref = proj.projection_term.trait_ref(tcx);
225 if unbound_trait_ref == impl_trait_ref {
226 continue;
227 }
228
229 unconstrained_parameters.extend(cgp::parameters_for(tcx, proj.projection_term, true));
230
231 for param in cgp::parameters_for(tcx, proj.term, false) {
232 if !unconstrained_parameters.contains(¶m) {
233 constrained_params.insert(param.0);
234 }
235 }
236
237 unconstrained_parameters.extend(cgp::parameters_for(tcx, proj.term, true));
238 }
239 }
240
241 impl_args
242 .iter()
243 .enumerate()
244 .filter(|&(idx, _)| !constrained_params.contains(&(idx as u32)))
245 .map(|(_, arg)| arg)
246 .collect()
247}
248
249fn check_duplicate_params<'tcx>(
270 tcx: TyCtxt<'tcx>,
271 impl1_args: GenericArgs<'tcx>,
272 parent_args: Vec<GenericArg<'tcx>>,
273 span: Span,
274) -> Result<(), ErrorGuaranteed> {
275 let mut base_params = cgp::parameters_for(tcx, parent_args, true);
276 base_params.sort_unstable();
277 if let (_, [duplicate, ..]) = base_params.partition_dedup() {
278 let param = impl1_args[duplicate.0 as usize];
279 return Err(tcx
280 .dcx()
281 .struct_span_err(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("specializing impl repeats parameter `{0}`",
param))
})format!("specializing impl repeats parameter `{param}`"))
282 .emit_err());
283 }
284 Ok(())
285}
286
287fn check_static_lifetimes<'tcx>(
296 tcx: TyCtxt<'tcx>,
297 parent_args: &Vec<GenericArg<'tcx>>,
298 span: Span,
299) -> Result<(), ErrorGuaranteed> {
300 if tcx.any_free_region_meets(parent_args, |r| r.is_static()) {
301 return Err(tcx.dcx().emit_err(diagnostics::StaticSpecialize { span }));
302 }
303 Ok(())
304}
305
306{}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("check_predicates",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(316u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::impl_wf_check::min_specialization"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl1_def_id")
}> =
::tracing::__macro_support::FieldName::new("impl1_def_id");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl1_args")
}> =
::tracing::__macro_support::FieldName::new("impl1_args");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl2_node")
}> =
::tracing::__macro_support::FieldName::new("impl2_node");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl2_args")
}> =
::tracing::__macro_support::FieldName::new("impl2_args");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("span")
}> =
::tracing::__macro_support::FieldName::new("span");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl1_def_id)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl1_args)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl2_node)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl2_args)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&span)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Result<(), ErrorGuaranteed> =
loop {};
return __tracing_attr_fake_return;
}
{
let impl1_clauses: Vec<(ty::Clause<'_>, _)> =
traits::elaborate(tcx,
tcx.clauses_of(impl1_def_id).instantiate(tcx,
impl1_args).into_iter().map(|(c, s)|
(c.skip_norm_wip(), s))).collect();
let mut impl2_clauses: Vec<ty::Clause<'_>> =
if impl2_node.is_from_trait() {
Vec::new()
} else {
traits::elaborate(tcx,
tcx.clauses_of(impl2_node.def_id()).instantiate(tcx,
impl2_args).into_iter().map(|(c, _s)|
c.skip_norm_wip())).collect()
};
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs:348",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(348u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::impl_wf_check::min_specialization"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl1_clauses")
}> =
::tracing::__macro_support::FieldName::new("impl1_clauses");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("impl2_clauses")
}> =
::tracing::__macro_support::FieldName::new("impl2_clauses");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl1_clauses)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&impl2_clauses)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
let always_applicable_traits =
impl1_clauses.iter().copied().filter(|&(clause, _span)|
{
#[allow(non_exhaustive_omitted_patterns)]
match trait_specialization_kind(tcx, clause) {
Some(TraitSpecializationKind::AlwaysApplicable) => true,
_ => false,
}
}).map(|(c, _span)| c);
for arg in
tcx.impl_trait_ref(impl1_def_id).instantiate_identity().skip_norm_wip().args
{
let Some(term) = arg.as_term() else { continue; };
let infcx =
&tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let obligations =
wf::obligations(infcx, tcx.param_env(impl1_def_id),
impl1_def_id, 0, term, span).unwrap();
if !!obligations.has_infer() {
::core::panicking::panic("assertion failed: !obligations.has_infer()")
};
impl2_clauses.extend(traits::elaborate(tcx,
obligations).filter_map(|obligation|
obligation.predicate.as_clause()))
}
impl2_clauses.extend(traits::elaborate(tcx,
always_applicable_traits));
let mut res = Ok(());
for (clause1, span) in impl1_clauses {
if !impl2_clauses.iter().any(|&clause2| clause1 == clause2) {
res = res.and(check_specialization_on(tcx, clause1, span))
}
}
res
}
}
}#[instrument(level = "debug", skip(tcx))]
317fn check_predicates<'tcx>(
318 tcx: TyCtxt<'tcx>,
319 impl1_def_id: LocalDefId,
320 impl1_args: GenericArgs<'tcx>,
321 impl2_node: Node,
322 impl2_args: GenericArgs<'tcx>,
323 span: Span,
324) -> Result<(), ErrorGuaranteed> {
325 let impl1_clauses: Vec<(ty::Clause<'_>, _)> = traits::elaborate(
326 tcx,
327 tcx.clauses_of(impl1_def_id)
328 .instantiate(tcx, impl1_args)
329 .into_iter()
330 .map(|(c, s)| (c.skip_norm_wip(), s)),
331 )
332 .collect();
333
334 let mut impl2_clauses: Vec<ty::Clause<'_>> = if impl2_node.is_from_trait() {
335 Vec::new()
338 } else {
339 traits::elaborate(
340 tcx,
341 tcx.clauses_of(impl2_node.def_id())
342 .instantiate(tcx, impl2_args)
343 .into_iter()
344 .map(|(c, _s)| c.skip_norm_wip()),
345 )
346 .collect()
347 };
348 debug!(?impl1_clauses, ?impl2_clauses);
349
350 let always_applicable_traits = impl1_clauses
366 .iter()
367 .copied()
368 .filter(|&(clause, _span)| {
369 matches!(
370 trait_specialization_kind(tcx, clause),
371 Some(TraitSpecializationKind::AlwaysApplicable)
372 )
373 })
374 .map(|(c, _span)| c);
375
376 for arg in tcx.impl_trait_ref(impl1_def_id).instantiate_identity().skip_norm_wip().args {
378 let Some(term) = arg.as_term() else {
379 continue;
380 };
381 let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
382 let obligations =
383 wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, term, span)
384 .unwrap();
385
386 assert!(!obligations.has_infer());
387 impl2_clauses.extend(
388 traits::elaborate(tcx, obligations)
389 .filter_map(|obligation| obligation.predicate.as_clause()),
390 )
391 }
392 impl2_clauses.extend(traits::elaborate(tcx, always_applicable_traits));
393
394 let mut res = Ok(());
395 for (clause1, span) in impl1_clauses {
396 if !impl2_clauses.iter().any(|&clause2| clause1 == clause2) {
397 res = res.and(check_specialization_on(tcx, clause1, span))
398 }
399 }
400 res
401}
402
403{}
#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("check_specialization_on",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(403u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::impl_wf_check::min_specialization"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("clause")
}> =
::tracing::__macro_support::FieldName::new("clause");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("span")
}> =
::tracing::__macro_support::FieldName::new("span");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&clause)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&span)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Result<(), ErrorGuaranteed> =
loop {};
return __tracing_attr_fake_return;
}
{
match clause.kind().skip_binder() {
_ if clause.is_global() => Ok(()),
ty::ClauseKind::Trait(ty::TraitClause { trait_ref, polarity: _
}) => {
if #[allow(non_exhaustive_omitted_patterns)] match trait_specialization_kind(tcx,
clause) {
Some(TraitSpecializationKind::Marker) => true,
_ => false,
} {
Ok(())
} else {
Err(tcx.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot specialize on trait `{0}`",
tcx.def_path_str(trait_ref.def_id)))
})).emit_err())
}
}
ty::ClauseKind::Projection(ty::ProjectionClause {
projection_term, term }) =>
Err(tcx.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot specialize on associated type `{0} == {1}`",
projection_term, term))
})).emit_err()),
ty::ClauseKind::ConstArgHasType(..) => { Ok(()) }
_ =>
Err(tcx.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("cannot specialize on predicate `{0}`",
clause))
})).emit_err()),
}
}
}
}#[instrument(level = "debug", skip(tcx))]
404fn check_specialization_on<'tcx>(
405 tcx: TyCtxt<'tcx>,
406 clause: ty::Clause<'tcx>,
407 span: Span,
408) -> Result<(), ErrorGuaranteed> {
409 match clause.kind().skip_binder() {
410 _ if clause.is_global() => Ok(()),
413 ty::ClauseKind::Trait(ty::TraitClause { trait_ref, polarity: _ }) => {
416 if matches!(
417 trait_specialization_kind(tcx, clause),
418 Some(TraitSpecializationKind::Marker)
419 ) {
420 Ok(())
421 } else {
422 Err(tcx
423 .dcx()
424 .struct_span_err(
425 span,
426 format!(
427 "cannot specialize on trait `{}`",
428 tcx.def_path_str(trait_ref.def_id),
429 ),
430 )
431 .emit_err())
432 }
433 }
434 ty::ClauseKind::Projection(ty::ProjectionClause { projection_term, term }) => Err(tcx
435 .dcx()
436 .struct_span_err(
437 span,
438 format!("cannot specialize on associated type `{projection_term} == {term}`",),
439 )
440 .emit_err()),
441 ty::ClauseKind::ConstArgHasType(..) => {
442 Ok(())
451 }
452 _ => Err(tcx
453 .dcx()
454 .struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
455 .emit_err()),
456 }
457}
458
459fn trait_specialization_kind<'tcx>(
460 tcx: TyCtxt<'tcx>,
461 clause: ty::Clause<'tcx>,
462) -> Option<TraitSpecializationKind> {
463 match clause.kind().skip_binder() {
464 ty::ClauseKind::Trait(ty::TraitClause { trait_ref, polarity: _ }) => {
465 Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
466 }
467 ty::ClauseKind::RegionOutlives(_)
468 | ty::ClauseKind::TypeOutlives(_)
469 | ty::ClauseKind::Projection(_)
470 | ty::ClauseKind::ConstArgHasType(..)
471 | ty::ClauseKind::WellFormed(_)
472 | ty::ClauseKind::ConstEvaluatable(..)
473 | ty::ClauseKind::UnstableFeature(_)
474 | ty::ClauseKind::HostEffect(..) => None,
475 }
476}