1use rustc_data_structures::fx::FxHashSet;
69use rustc_hir::def_id::{DefId, LocalDefId};
70use rustc_infer::infer::TyCtxtInferExt;
71use rustc_infer::traits::ObligationCause;
72use rustc_infer::traits::specialization_graph::Node;
73use rustc_middle::ty::trait_def::TraitSpecializationKind;
74use rustc_middle::ty::{
75 self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode,
76};
77use rustc_span::{ErrorGuaranteed, Span};
78use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
79use rustc_trait_selection::traits::{self, ObligationCtxt, translate_args_with_cause, wf};
80use tracing::{debug, instrument};
81
82use crate::diagnostics::GenericArgsOnOverriddenImpl;
83use crate::{constrained_generic_params as cgp, diagnostics};
84
85pub(super) fn check_min_specialization(
86 tcx: TyCtxt<'_>,
87 impl_def_id: LocalDefId,
88) -> Result<(), ErrorGuaranteed> {
89 if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
90 check_always_applicable(tcx, impl_def_id, node)?;
91 }
92 Ok(())
93}
94
95fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Option<Node> {
96 let trait_ref = tcx.impl_trait_ref(impl1_def_id);
97 let trait_def = tcx.trait_def(trait_ref.skip_binder().def_id);
98
99 let impl2_node = trait_def.ancestors(tcx, impl1_def_id.to_def_id()).ok()?.nth(1)?;
100
101 let always_applicable_trait =
102 #[allow(non_exhaustive_omitted_patterns)] match trait_def.specialization_kind
{
TraitSpecializationKind::AlwaysApplicable => true,
_ => false,
}matches!(trait_def.specialization_kind, TraitSpecializationKind::AlwaysApplicable);
103 if impl2_node.is_from_trait() && !always_applicable_trait {
104 return None;
106 }
107 if trait_def.is_marker {
108 return None;
110 }
111 Some(impl2_node)
112}
113
114#[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("compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(115u32),
::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 compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs:125",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(125u32),
::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.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))]
116fn check_always_applicable(
117 tcx: TyCtxt<'_>,
118 impl1_def_id: LocalDefId,
119 impl2_node: Node,
120) -> Result<(), ErrorGuaranteed> {
121 let span = tcx.def_span(impl1_def_id);
122
123 let (impl1_args, impl2_args) = get_impl_args(tcx, impl1_def_id, impl2_node)?;
124 let impl2_def_id = impl2_node.def_id();
125 debug!(?impl2_def_id, ?impl2_args);
126
127 let parent_args = if impl2_node.is_from_trait() {
128 impl2_args.to_vec()
129 } else {
130 unconstrained_parent_impl_args(tcx, impl2_def_id, impl2_args)
131 };
132
133 check_has_items(tcx, impl1_def_id, impl2_node, span)
134 .and(check_static_lifetimes(tcx, &parent_args, span))
135 .and(check_duplicate_params(tcx, impl1_args, parent_args, span))
136 .and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span))
137}
138
139fn check_has_items(
140 tcx: TyCtxt<'_>,
141 impl1_def_id: LocalDefId,
142 impl2_node: Node,
143 span: Span,
144) -> Result<(), ErrorGuaranteed> {
145 if let Node::Impl(impl2_id) = impl2_node
146 && tcx.associated_item_def_ids(impl1_def_id).is_empty()
147 {
148 let base_impl_span = tcx.def_span(impl2_id);
149 return Err(tcx.dcx().emit_err(diagnostics::EmptySpecialization { span, base_impl_span }));
150 }
151 Ok(())
152}
153
154fn get_impl_args(
167 tcx: TyCtxt<'_>,
168 impl1_def_id: LocalDefId,
169 impl2_node: Node,
170) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> {
171 let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
172 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
173 let param_env = tcx.param_env(impl1_def_id);
174 let impl1_span = tcx.def_span(impl1_def_id);
175
176 let impl1_args = GenericArgs::identity_for_item(tcx, impl1_def_id);
177 let impl2_args = translate_args_with_cause(
178 infcx,
179 param_env,
180 impl1_def_id.to_def_id(),
181 impl1_args,
182 impl2_node,
183 &ObligationCause::misc(impl1_span, impl1_def_id),
184 );
185
186 let errors = ocx.evaluate_obligations_error_on_ambiguity();
187 if !errors.is_empty() {
188 let guar = ocx.infcx.err_ctxt().report_fulfillment_errors(errors);
189 return Err(guar);
190 }
191
192 let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?;
193 ocx.resolve_regions_and_report_errors(impl1_def_id, param_env, assumed_wf_types)?;
194 let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
195 let span = tcx.def_span(impl1_def_id);
196 let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span });
197 return Err(guar);
198 };
199 Ok((impl1_args, impl2_args))
200}
201
202fn unconstrained_parent_impl_args<'tcx>(
211 tcx: TyCtxt<'tcx>,
212 impl_def_id: DefId,
213 impl_args: GenericArgsRef<'tcx>,
214) -> Vec<GenericArg<'tcx>> {
215 let impl_generic_clauses = tcx.clauses_of(impl_def_id);
216 let mut unconstrained_parameters = FxHashSet::default();
217 let mut constrained_params = FxHashSet::default();
218 let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity().skip_norm_wip();
219
220 for (clause, _) in impl_generic_clauses.clauses.iter() {
225 if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() {
226 let unbound_trait_ref = proj.projection_term.trait_ref(tcx);
227 if unbound_trait_ref == impl_trait_ref {
228 continue;
229 }
230
231 unconstrained_parameters.extend(cgp::parameters_for(tcx, proj.projection_term, true));
232
233 for param in cgp::parameters_for(tcx, proj.term, false) {
234 if !unconstrained_parameters.contains(¶m) {
235 constrained_params.insert(param.0);
236 }
237 }
238
239 unconstrained_parameters.extend(cgp::parameters_for(tcx, proj.term, true));
240 }
241 }
242
243 impl_args
244 .iter()
245 .enumerate()
246 .filter(|&(idx, _)| !constrained_params.contains(&(idx as u32)))
247 .map(|(_, arg)| arg)
248 .collect()
249}
250
251fn check_duplicate_params<'tcx>(
272 tcx: TyCtxt<'tcx>,
273 impl1_args: GenericArgsRef<'tcx>,
274 parent_args: Vec<GenericArg<'tcx>>,
275 span: Span,
276) -> Result<(), ErrorGuaranteed> {
277 let mut base_params = cgp::parameters_for(tcx, parent_args, true);
278 base_params.sort_unstable();
279 if let (_, [duplicate, ..]) = base_params.partition_dedup() {
280 let param = impl1_args[duplicate.0 as usize];
281 return Err(tcx
282 .dcx()
283 .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}`"))
284 .emit());
285 }
286 Ok(())
287}
288
289fn check_static_lifetimes<'tcx>(
298 tcx: TyCtxt<'tcx>,
299 parent_args: &Vec<GenericArg<'tcx>>,
300 span: Span,
301) -> Result<(), ErrorGuaranteed> {
302 if tcx.any_free_region_meets(parent_args, |r| r.is_static()) {
303 return Err(tcx.dcx().emit_err(diagnostics::StaticSpecialize { span }));
304 }
305 Ok(())
306}
307
308#[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("compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(318u32),
::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 compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs:350",
"rustc_hir_analysis::impl_wf_check::min_specialization",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(350u32),
::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))]
319fn check_predicates<'tcx>(
320 tcx: TyCtxt<'tcx>,
321 impl1_def_id: LocalDefId,
322 impl1_args: GenericArgsRef<'tcx>,
323 impl2_node: Node,
324 impl2_args: GenericArgsRef<'tcx>,
325 span: Span,
326) -> Result<(), ErrorGuaranteed> {
327 let impl1_clauses: Vec<(ty::Clause<'_>, _)> = traits::elaborate(
328 tcx,
329 tcx.clauses_of(impl1_def_id)
330 .instantiate(tcx, impl1_args)
331 .into_iter()
332 .map(|(c, s)| (c.skip_norm_wip(), s)),
333 )
334 .collect();
335
336 let mut impl2_clauses: Vec<ty::Clause<'_>> = if impl2_node.is_from_trait() {
337 Vec::new()
340 } else {
341 traits::elaborate(
342 tcx,
343 tcx.clauses_of(impl2_node.def_id())
344 .instantiate(tcx, impl2_args)
345 .into_iter()
346 .map(|(c, _s)| c.skip_norm_wip()),
347 )
348 .collect()
349 };
350 debug!(?impl1_clauses, ?impl2_clauses);
351
352 let always_applicable_traits = impl1_clauses
368 .iter()
369 .copied()
370 .filter(|&(clause, _span)| {
371 matches!(
372 trait_specialization_kind(tcx, clause),
373 Some(TraitSpecializationKind::AlwaysApplicable)
374 )
375 })
376 .map(|(c, _span)| c);
377
378 for arg in tcx.impl_trait_ref(impl1_def_id).instantiate_identity().skip_norm_wip().args {
380 let Some(term) = arg.as_term() else {
381 continue;
382 };
383 let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
384 let obligations =
385 wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, term, span)
386 .unwrap();
387
388 assert!(!obligations.has_infer());
389 impl2_clauses.extend(
390 traits::elaborate(tcx, obligations)
391 .filter_map(|obligation| obligation.predicate.as_clause()),
392 )
393 }
394 impl2_clauses.extend(traits::elaborate(tcx, always_applicable_traits));
395
396 let mut res = Ok(());
397 for (clause1, span) in impl1_clauses {
398 if !impl2_clauses.iter().any(|&clause2| clause1 == clause2) {
399 res = res.and(check_specialization_on(tcx, clause1, span))
400 }
401 }
402 res
403}
404
405#[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("compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs"),
::tracing_core::__macro_support::Option::Some(405u32),
::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::TraitPredicate {
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())
}
}
ty::ClauseKind::Projection(ty::ProjectionPredicate {
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()),
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()),
}
}
}
}#[instrument(level = "debug", skip(tcx))]
406fn check_specialization_on<'tcx>(
407 tcx: TyCtxt<'tcx>,
408 clause: ty::Clause<'tcx>,
409 span: Span,
410) -> Result<(), ErrorGuaranteed> {
411 match clause.kind().skip_binder() {
412 _ if clause.is_global() => Ok(()),
415 ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
418 if matches!(
419 trait_specialization_kind(tcx, clause),
420 Some(TraitSpecializationKind::Marker)
421 ) {
422 Ok(())
423 } else {
424 Err(tcx
425 .dcx()
426 .struct_span_err(
427 span,
428 format!(
429 "cannot specialize on trait `{}`",
430 tcx.def_path_str(trait_ref.def_id),
431 ),
432 )
433 .emit())
434 }
435 }
436 ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_term, term }) => Err(tcx
437 .dcx()
438 .struct_span_err(
439 span,
440 format!("cannot specialize on associated type `{projection_term} == {term}`",),
441 )
442 .emit()),
443 ty::ClauseKind::ConstArgHasType(..) => {
444 Ok(())
453 }
454 _ => Err(tcx
455 .dcx()
456 .struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
457 .emit()),
458 }
459}
460
461fn trait_specialization_kind<'tcx>(
462 tcx: TyCtxt<'tcx>,
463 clause: ty::Clause<'tcx>,
464) -> Option<TraitSpecializationKind> {
465 match clause.kind().skip_binder() {
466 ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
467 Some(tcx.trait_def(trait_ref.def_id).specialization_kind)
468 }
469 ty::ClauseKind::RegionOutlives(_)
470 | ty::ClauseKind::TypeOutlives(_)
471 | ty::ClauseKind::Projection(_)
472 | ty::ClauseKind::ConstArgHasType(..)
473 | ty::ClauseKind::WellFormed(_)
474 | ty::ClauseKind::ConstEvaluatable(..)
475 | ty::ClauseKind::UnstableFeature(_)
476 | ty::ClauseKind::HostEffect(..) => None,
477 }
478}