1use rustc_errors::ErrorGuaranteed;
2use rustc_hir as hir;
3use rustc_hir::ItemKind;
4use rustc_hir::attrs::lang_items::LangItem;
5use rustc_hir::def_id::{DefId, LocalDefId};
6use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
7use rustc_infer::traits::{Obligation, TraitErrors};
8use rustc_middle::ty::relate::solver_relating::RelateExt;
9use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized};
10use rustc_span::Span;
11use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
12use rustc_trait_selection::traits::{self, ObligationCtxt};
13use tracing::debug;
14
15use super::{
16 ReborrowDataField, assert_field_type_is_copy, collect_reborrow_data_fields, field_type_is_copy,
17 field_type_is_reborrow, trait_impl_lifetime_params_count,
18};
19use crate::diagnostics;
20
21#[derive(#[automatically_derived]
impl ::core::clone::Clone for CoerceSharedDiagnosticContext {
#[inline]
fn clone(&self) -> CoerceSharedDiagnosticContext {
let _: ::core::clone::AssertParamIsClone<Span>;
let _: ::core::clone::AssertParamIsClone<Option<Span>>;
let _: ::core::clone::AssertParamIsClone<Option<Span>>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CoerceSharedDiagnosticContext { }Copy)]
22struct CoerceSharedDiagnosticContext {
23 impl_span: Span,
24 trait_span: Span,
25 source_ty_span: Span,
26 target_ty_span: Span,
27 source_lifetime_span: Option<Span>,
28 target_lifetime_span: Option<Span>,
29}
30
31#[derive(#[automatically_derived]
impl ::core::clone::Clone for CoerceSharedTypeRole {
#[inline]
fn clone(&self) -> CoerceSharedTypeRole { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for CoerceSharedTypeRole { }Copy)]
32enum CoerceSharedTypeRole {
33 Source,
34 Target,
35}
36
37impl CoerceSharedTypeRole {
38 fn as_str(self) -> &'static str {
39 match self {
40 CoerceSharedTypeRole::Source => "source",
41 CoerceSharedTypeRole::Target => "target",
42 }
43 }
44
45 fn type_span(self, diagnostic_context: CoerceSharedDiagnosticContext) -> Span {
46 match self {
47 CoerceSharedTypeRole::Source => diagnostic_context.source_ty_span,
48 CoerceSharedTypeRole::Target => diagnostic_context.target_ty_span,
49 }
50 }
51}
52
53fn coerce_shared_diagnostic_context(
54 tcx: TyCtxt<'_>,
55 impl_did: LocalDefId,
56) -> CoerceSharedDiagnosticContext {
57 let item = tcx.hir_expect_item(impl_did);
58 let fallback_span = tcx.def_span(impl_did);
59 let mut diagnostic_context = CoerceSharedDiagnosticContext {
60 impl_span: item.span,
61 trait_span: fallback_span,
62 source_ty_span: fallback_span,
63 target_ty_span: fallback_span,
64 source_lifetime_span: None,
65 target_lifetime_span: None,
66 };
67
68 let ItemKind::Impl(impl_) = &item.kind else {
69 return diagnostic_context;
70 };
71 let Some(of_trait) = impl_.of_trait else {
72 return diagnostic_context;
73 };
74
75 diagnostic_context.trait_span = of_trait.trait_ref.path.span;
76 diagnostic_context.source_ty_span = impl_.self_ty.span;
77 diagnostic_context.source_lifetime_span = first_explicit_lifetime_span_in_ty(impl_.self_ty)
78 .or_else(|| first_explicit_impl_lifetime_param_span(impl_.generics));
79
80 if let Some(target_ty) = coerce_shared_target_ty_from_path(of_trait.trait_ref.path) {
81 diagnostic_context.target_ty_span = target_ty.span;
82 diagnostic_context.target_lifetime_span =
83 first_explicit_lifetime_span_in_ambig_ty(target_ty);
84 } else {
85 diagnostic_context.target_ty_span = diagnostic_context.trait_span;
86 }
87
88 diagnostic_context
89}
90
91fn coerce_shared_target_ty_from_path<'hir>(
92 path: &'hir hir::Path<'hir>,
93) -> Option<&'hir hir::Ty<'hir, hir::AmbigArg>> {
94 path.segments.last()?.args().args.iter().find_map(|arg| match arg {
95 hir::GenericArg::Type(ty) => Some(*ty),
96 hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) | hir::GenericArg::Infer(_) => {
97 None
98 }
99 })
100}
101
102fn first_explicit_impl_lifetime_param_span(generics: &hir::Generics<'_>) -> Option<Span> {
103 generics.params.iter().find_map(|param| match param.kind {
104 hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
105 Some(param.span)
106 }
107 hir::GenericParamKind::Lifetime { .. }
108 | hir::GenericParamKind::Type { .. }
109 | hir::GenericParamKind::Const { .. } => None,
110 })
111}
112
113fn first_explicit_lifetime_span(lifetime: &hir::Lifetime) -> Option<Span> {
114 match lifetime.kind {
115 hir::LifetimeKind::Param(_) | hir::LifetimeKind::Static
116 if !lifetime.ident.span.is_dummy() =>
117 {
118 Some(lifetime.ident.span)
119 }
120 hir::LifetimeKind::Param(_)
121 | hir::LifetimeKind::Static
122 | hir::LifetimeKind::ImplicitObjectLifetimeDefault
123 | hir::LifetimeKind::Error(_)
124 | hir::LifetimeKind::Infer => None,
125 }
126}
127
128fn first_explicit_lifetime_span_in_ambig_ty(ty: &hir::Ty<'_, hir::AmbigArg>) -> Option<Span> {
129 first_explicit_lifetime_span_in_ty(ty.as_unambig_ty())
130}
131
132fn first_explicit_lifetime_span_in_ty(ty: &hir::Ty<'_>) -> Option<Span> {
133 match ty.kind {
134 hir::TyKind::Ref(lifetime, mut_ty) => first_explicit_lifetime_span(lifetime)
135 .or_else(|| first_explicit_lifetime_span_in_ty(mut_ty.ty)),
136 hir::TyKind::Slice(ty)
137 | hir::TyKind::Array(ty, _)
138 | hir::TyKind::Pat(ty, _)
139 | hir::TyKind::FieldOf(ty, _)
140 | hir::TyKind::View(ty, _) => first_explicit_lifetime_span_in_ty(ty),
141 hir::TyKind::Ptr(mut_ty) => first_explicit_lifetime_span_in_ty(mut_ty.ty),
142 hir::TyKind::Tup(tys) => tys.iter().find_map(first_explicit_lifetime_span_in_ty),
143 hir::TyKind::Path(qpath) => first_explicit_lifetime_span_in_qpath(qpath),
144 hir::TyKind::TraitObject(bounds, lifetime) => bounds
145 .iter()
146 .find_map(|bound| first_explicit_lifetime_span_in_path(bound.trait_ref.path))
147 .or_else(|| first_explicit_lifetime_span(&lifetime)),
148 hir::TyKind::OpaqueDef(opaque) => first_explicit_lifetime_span_in_bounds(opaque.bounds),
149 hir::TyKind::TraitAscription(bounds) => first_explicit_lifetime_span_in_bounds(bounds),
150 hir::TyKind::FnPtr(fn_ptr) => {
151 fn_ptr.generic_params.iter().find_map(|param| match param.kind {
152 hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
153 Some(param.span)
154 }
155 hir::GenericParamKind::Lifetime { .. }
156 | hir::GenericParamKind::Type { .. }
157 | hir::GenericParamKind::Const { .. } => None,
158 })
159 }
160 hir::TyKind::UnsafeBinder(binder) => binder
161 .generic_params
162 .iter()
163 .find_map(|param| match param.kind {
164 hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } => {
165 Some(param.span)
166 }
167 hir::GenericParamKind::Lifetime { .. }
168 | hir::GenericParamKind::Type { .. }
169 | hir::GenericParamKind::Const { .. } => None,
170 })
171 .or_else(|| first_explicit_lifetime_span_in_ty(binder.inner_ty)),
172 hir::TyKind::InferDelegation(_)
173 | hir::TyKind::Never
174 | hir::TyKind::Infer(())
175 | hir::TyKind::Err(_) => None,
176 }
177}
178
179fn first_explicit_lifetime_span_in_bounds(bounds: hir::GenericBounds<'_>) -> Option<Span> {
180 bounds.iter().find_map(|bound| match bound {
181 hir::GenericBound::Trait(poly_trait_ref) => {
182 first_explicit_lifetime_span_in_path(poly_trait_ref.trait_ref.path)
183 }
184 hir::GenericBound::Outlives(lifetime) => first_explicit_lifetime_span(lifetime),
185 hir::GenericBound::Use(args, _) => args.iter().find_map(|arg| match arg {
186 hir::PreciseCapturingArgKind::Lifetime(lifetime) => {
187 first_explicit_lifetime_span(lifetime)
188 }
189 hir::PreciseCapturingArgKind::Param(_) => None,
190 }),
191 })
192}
193
194fn first_explicit_lifetime_span_in_qpath(qpath: hir::QPath<'_>) -> Option<Span> {
195 match qpath {
196 hir::QPath::Resolved(qself, path) => qself
197 .and_then(first_explicit_lifetime_span_in_ty)
198 .or_else(|| first_explicit_lifetime_span_in_path(path)),
199 hir::QPath::TypeRelative(qself, segment) => first_explicit_lifetime_span_in_ty(qself)
200 .or_else(|| first_explicit_lifetime_span_in_path_segment(segment)),
201 }
202}
203
204fn first_explicit_lifetime_span_in_path(path: &hir::Path<'_>) -> Option<Span> {
205 path.segments.iter().find_map(first_explicit_lifetime_span_in_path_segment)
206}
207
208fn first_explicit_lifetime_span_in_path_segment(segment: &hir::PathSegment<'_>) -> Option<Span> {
209 first_explicit_lifetime_span_in_generic_args(segment.args())
210}
211
212fn first_explicit_lifetime_span_in_generic_args(args: &hir::GenericArgs<'_>) -> Option<Span> {
213 args.args
214 .iter()
215 .find_map(|arg| match arg {
216 hir::GenericArg::Lifetime(lifetime) => first_explicit_lifetime_span(lifetime),
217 hir::GenericArg::Type(ty) => first_explicit_lifetime_span_in_ambig_ty(ty),
218 hir::GenericArg::Const(_) | hir::GenericArg::Infer(_) => None,
219 })
220 .or_else(|| {
221 args.constraints.iter().find_map(|constraint| {
222 first_explicit_lifetime_span_in_generic_args(constraint.gen_args)
223 .or_else(|| constraint.ty().and_then(first_explicit_lifetime_span_in_ty))
224 })
225 })
226}
227
228pub(super) fn coerce_shared_info<'tcx>(
229 tcx: TyCtxt<'tcx>,
230 impl_did: LocalDefId,
231) -> Result<(), ErrorGuaranteed> {
232 {
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/coherence/builtin/coerce_shared.rs:232",
"rustc_hir_analysis::coherence::builtin::coerce_shared",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_hir_analysis/src/coherence/builtin/coerce_shared.rs"),
::tracing_core::__macro_support::Option::Some(232u32),
::tracing_core::__macro_support::Option::Some("rustc_hir_analysis::coherence::builtin::coerce_shared"),
::tracing_core::field::FieldSet::new(&["message"],
::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(&format_args!("compute_coerce_shared_info(impl_did={0:?})",
impl_did) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!("compute_coerce_shared_info(impl_did={:?})", impl_did);
233 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
234 let span = tcx.def_span(impl_did);
235 let diagnostic_context = coerce_shared_diagnostic_context(tcx, impl_did);
236 let trait_name = "CoerceShared";
237
238 let coerce_shared_trait = tcx.require_lang_item(LangItem::CoerceShared, span);
239
240 let source = tcx.type_of(impl_did).instantiate_identity().skip_norm_wip();
241 let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity().skip_norm_wip();
242
243 if trait_impl_lifetime_params_count(tcx, impl_did) != 1 {
244 return Err(tcx
245 .dcx()
246 .emit_err(diagnostics::CoerceSharedNotSingleLifetimeParam { span, trait_name }));
247 }
248
249 {
match (&trait_ref.def_id, &coerce_shared_trait) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(trait_ref.def_id, coerce_shared_trait);
250 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
251 let param_env = tcx.param_env(impl_did);
252 let (source, target) = ocx
253 .deeply_normalize(
254 &traits::ObligationCause::misc(span, impl_did),
255 param_env,
256 Unnormalized::new_wip((source, trait_ref.args.type_at(1))),
257 )
258 .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
259 let errors = ocx.evaluate_obligations_error_on_ambiguity();
260 if let TraitErrors::HasErrors(errors) = errors {
261 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
262 }
263
264 if !!source.has_escaping_bound_vars() {
::core::panicking::panic("assertion failed: !source.has_escaping_bound_vars()")
};assert!(!source.has_escaping_bound_vars());
265
266 match (source.kind(), target.kind()) {
267 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
268 if def_a.is_struct() && def_b.is_struct() =>
269 {
270 let a_lifetime = single_region_arg(args_a);
271 let b_lifetime = single_region_arg(args_b);
272
273 if a_lifetime.is_none() || b_lifetime.is_none() {
274 return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedMulti {
275 span: diagnostic_context.trait_span,
276 trait_name,
277 }));
278 }
279
280 if a_lifetime != b_lifetime {
281 return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedLifetimeMismatch {
282 span: diagnostic_context.trait_span,
283 source_lifetime_span: diagnostic_context.source_lifetime_span,
284 target_lifetime_span: diagnostic_context.target_lifetime_span,
285 trait_name,
286 }));
287 }
288
289 validate_reborrow_field_access(
290 tcx,
291 impl_did,
292 def_a,
293 trait_name,
294 diagnostic_context,
295 CoerceSharedTypeRole::Source,
296 )?;
297 validate_reborrow_field_access(
298 tcx,
299 impl_did,
300 def_b,
301 trait_name,
302 diagnostic_context,
303 CoerceSharedTypeRole::Target,
304 )?;
305
306 validate_coerce_shared_fields(
307 &infcx,
308 impl_did,
309 param_env,
310 coerce_shared_trait,
311 trait_name,
312 span,
313 diagnostic_context,
314 def_a,
315 args_a,
316 def_b,
317 args_b,
318 )
319 }
320
321 _ => {
322 Err(tcx.dcx().emit_err(diagnostics::CoerceUnsizedNonStruct { span, trait_name }))
324 }
325 }
326}
327
328#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for CoerceSharedFieldPair<'tcx> {
#[inline]
fn clone(&self) -> CoerceSharedFieldPair<'tcx> {
let _: ::core::clone::AssertParamIsClone<ReborrowDataField<'tcx>>;
let _: ::core::clone::AssertParamIsClone<ReborrowDataField<'tcx>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for CoerceSharedFieldPair<'tcx> { }Copy)]
329struct CoerceSharedFieldPair<'tcx> {
330 source: ReborrowDataField<'tcx>,
331 target: ReborrowDataField<'tcx>,
332}
333
334struct CoerceSharedFields<'tcx> {
335 pairs: Vec<CoerceSharedFieldPair<'tcx>>,
336 unpaired_sources: Vec<ReborrowDataField<'tcx>>,
337}
338
339#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for CoerceSharedFieldPairError<'tcx> {
#[inline]
fn clone(&self) -> CoerceSharedFieldPairError<'tcx> {
let _: ::core::clone::AssertParamIsClone<ReborrowDataField<'tcx>>;
*self
}
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for CoerceSharedFieldPairError<'tcx> { }Copy)]
340enum CoerceSharedFieldPairError<'tcx> {
341 FieldStyleMismatch,
342 MissingSourceField { target: ReborrowDataField<'tcx> },
343}
344
345fn single_region_arg<'tcx>(args: ty::GenericArgsRef<'tcx>) -> Option<ty::Region<'tcx>> {
346 let mut lifetimes = args.iter().filter_map(|arg| arg.as_region());
347 let lifetime = lifetimes.next()?;
348 lifetimes.next().is_none().then_some(lifetime)
349}
350
351fn collect_coerce_shared_field_pairs<'tcx>(
355 tcx: TyCtxt<'tcx>,
356 source_def: ty::AdtDef<'tcx>,
357 source_args: ty::GenericArgsRef<'tcx>,
358 target_def: ty::AdtDef<'tcx>,
359 target_args: ty::GenericArgsRef<'tcx>,
360) -> Result<CoerceSharedFields<'tcx>, CoerceSharedFieldPairError<'tcx>> {
361 let source_variant = source_def.non_enum_variant();
362 let target_variant = target_def.non_enum_variant();
363 if source_variant.ctor_kind() != target_variant.ctor_kind() {
364 return Err(CoerceSharedFieldPairError::FieldStyleMismatch);
365 }
366
367 let source_fields = collect_reborrow_data_fields(tcx, source_def, source_args);
368 let target_fields = collect_reborrow_data_fields(tcx, target_def, target_args);
369
370 let mut pairs = Vec::with_capacity(target_fields.len());
371
372 for target in &target_fields {
373 let source = source_fields
374 .iter()
375 .find(|source| tcx.hygienic_eq(target.ident, source.ident, source_variant.def_id))
376 .ok_or(CoerceSharedFieldPairError::MissingSourceField { target: *target })?;
377
378 pairs.push(CoerceSharedFieldPair { source: *source, target: *target });
379 }
380
381 let unpaired_sources = source_fields
382 .into_iter()
383 .filter(|source| {
384 !target_fields
385 .iter()
386 .any(|target| tcx.hygienic_eq(target.ident, source.ident, source_variant.def_id))
387 })
388 .collect();
389
390 Ok(CoerceSharedFields { pairs, unpaired_sources })
391}
392
393fn validate_reborrow_field_access(
394 tcx: TyCtxt<'_>,
395 impl_did: LocalDefId,
396 def: ty::AdtDef<'_>,
397 trait_name: &'static str,
398 diagnostic_context: CoerceSharedDiagnosticContext,
399 role: CoerceSharedTypeRole,
400) -> Result<(), ErrorGuaranteed> {
401 let module = tcx.parent_module_from_def_id(impl_did);
402 let variant = def.non_enum_variant();
403 if variant.field_list_has_applicable_non_exhaustive() {
404 return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedInaccessibleField {
405 span: diagnostic_context.impl_span,
406 type_span: role.type_span(diagnostic_context),
407 trait_name,
408 role: role.as_str(),
409 type_name: tcx.item_name(def.did()),
410 }));
411 }
412
413 for field in &variant.fields {
414 if !field.vis.is_accessible_from(module, tcx) {
415 return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedInaccessibleField {
416 span: diagnostic_context.impl_span,
417 type_span: role.type_span(diagnostic_context),
418 trait_name,
419 role: role.as_str(),
420 type_name: tcx.item_name(def.did()),
421 }));
422 }
423 }
424
425 Ok(())
426}
427
428fn validate_coerce_shared_fields<'tcx>(
429 infcx: &InferCtxt<'tcx>,
430 impl_did: LocalDefId,
431 param_env: ty::ParamEnv<'tcx>,
432 coerce_shared_trait: DefId,
433 trait_name: &'static str,
434 span: Span,
435 diagnostic_context: CoerceSharedDiagnosticContext,
436 source_def: ty::AdtDef<'tcx>,
437 source_args: ty::GenericArgsRef<'tcx>,
438 target_def: ty::AdtDef<'tcx>,
439 target_args: ty::GenericArgsRef<'tcx>,
440) -> Result<(), ErrorGuaranteed> {
441 let tcx = infcx.tcx;
442 let fields = match collect_coerce_shared_field_pairs(
443 tcx,
444 source_def,
445 source_args,
446 target_def,
447 target_args,
448 ) {
449 Ok(fields) => fields,
450 Err(CoerceSharedFieldPairError::FieldStyleMismatch) => {
451 return Err(tcx
452 .dcx()
453 .emit_err(diagnostics::CoerceSharedFieldStyleMismatch { span, trait_name }));
454 }
455 Err(CoerceSharedFieldPairError::MissingSourceField { target }) => {
456 return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedMissingField {
457 span: target.span,
458 source_ty_span: diagnostic_context.source_ty_span,
459 trait_name,
460 source_ty_name: tcx.item_name(source_def.did()),
461 field_name: target.name,
462 }));
463 }
464 };
465
466 for field_pair in fields.pairs {
467 validate_coerce_shared_field(
468 infcx,
469 impl_did,
470 param_env,
471 coerce_shared_trait,
472 trait_name,
473 span,
474 diagnostic_context,
475 field_pair.source,
476 field_pair.target,
477 )?;
478 }
479
480 let reborrow_trait = tcx.require_lang_item(LangItem::Reborrow, span);
481 for source in fields.unpaired_sources {
482 validate_coerce_shared_unpaired_source_field(
483 infcx,
484 impl_did,
485 param_env,
486 reborrow_trait,
487 trait_name,
488 diagnostic_context,
489 source,
490 )?;
491 }
492
493 validate_coerce_shared_fields_are_memcpy_compatible(
497 infcx,
498 impl_did,
499 param_env,
500 coerce_shared_trait,
501 trait_name,
502 span,
503 diagnostic_context,
504 source_def,
505 source_args,
506 target_def,
507 target_args,
508 )?;
509
510 Ok(())
511}
512
513fn validate_coerce_shared_fields_are_memcpy_compatible<'tcx>(
514 infcx: &InferCtxt<'tcx>,
515 impl_did: LocalDefId,
516 param_env: ty::ParamEnv<'tcx>,
517 coerce_shared_trait: DefId,
518 trait_name: &'static str,
519 span: Span,
520 diagnostic_context: CoerceSharedDiagnosticContext,
521 source_def: ty::AdtDef<'tcx>,
522 source_args: ty::GenericArgsRef<'tcx>,
523 target_def: ty::AdtDef<'tcx>,
524 target_args: ty::GenericArgsRef<'tcx>,
525) -> Result<(), ErrorGuaranteed> {
526 let tcx = infcx.tcx;
527 let source_non_zst_fields =
528 non_zst_reborrow_data_fields(infcx, param_env, source_def, source_args);
529 let target_non_zst_fields =
530 non_zst_reborrow_data_fields(infcx, param_env, target_def, target_args);
531
532 match (&source_non_zst_fields[..], &target_non_zst_fields[..]) {
533 ([], []) => Ok(()),
534 ([source], [target]) => {
535 if field_tys_satisfy_relation_after_normalization_and_resolution(
536 tcx,
537 impl_did,
538 param_env,
539 source.ty,
540 target.ty,
541 source.span,
542 FieldRelation::Equal,
543 ) {
544 return Ok(());
545 }
546
547 if #[allow(non_exhaustive_omitted_patterns)] match (source.ty.kind(),
target.ty.kind()) {
(&ty::Ref(_, _, ty::Mutability::Mut), &ty::Ref(_, _, ty::Mutability::Not))
| (&ty::Alias(..), _) | (_, &ty::Alias(..)) => true,
_ => false,
}matches!(
548 (source.ty.kind(), target.ty.kind()),
549 (&ty::Ref(_, _, ty::Mutability::Mut), &ty::Ref(_, _, ty::Mutability::Not))
550 | (&ty::Alias(..), _)
551 | (_, &ty::Alias(..))
552 ) && field_tys_satisfy_relation_after_normalization_and_resolution(
553 tcx,
554 impl_did,
555 param_env,
556 source.ty,
557 target.ty,
558 source.span,
559 FieldRelation::MutRefToSharedRef,
560 ) {
561 return Ok(());
562 }
563
564 validate_field_tys_satisfy_coerce_shared_relation(
565 infcx,
566 impl_did,
567 param_env,
568 coerce_shared_trait,
569 trait_name,
570 span,
571 diagnostic_context,
572 *source,
573 *target,
574 )
575 }
576 _ => Err(tcx.dcx().emit_err(diagnostics::CoerceSharedMultipleNonZstFields {
577 span: diagnostic_context.impl_span,
578 source_ty_span: diagnostic_context.source_ty_span,
579 target_ty_span: diagnostic_context.target_ty_span,
580 trait_name,
581 source_count: source_non_zst_fields.len(),
582 target_count: target_non_zst_fields.len(),
583 })),
584 }
585}
586
587fn non_zst_reborrow_data_fields<'tcx>(
588 infcx: &InferCtxt<'tcx>,
589 param_env: ty::ParamEnv<'tcx>,
590 def: ty::AdtDef<'tcx>,
591 args: ty::GenericArgsRef<'tcx>,
592) -> Vec<ReborrowDataField<'tcx>> {
593 let tcx = infcx.tcx;
594 collect_reborrow_data_fields(tcx, def, args)
595 .into_iter()
596 .filter(|field| {
597 !#[allow(non_exhaustive_omitted_patterns)] match tcx.layout_of(infcx.typing_env(param_env).as_query_input(field.ty))
{
Ok(layout) if layout.is_zst() => true,
_ => false,
}matches!(
598 tcx.layout_of(infcx.typing_env(param_env).as_query_input(field.ty)),
599 Ok(layout) if layout.is_zst()
600 )
601 })
602 .collect()
603}
604
605fn validate_coerce_shared_field<'tcx>(
606 infcx: &InferCtxt<'tcx>,
607 impl_did: LocalDefId,
608 param_env: ty::ParamEnv<'tcx>,
609 coerce_shared_trait: DefId,
610 trait_name: &'static str,
611 span: Span,
612 diagnostic_context: CoerceSharedDiagnosticContext,
613 source: ReborrowDataField<'tcx>,
614 target: ReborrowDataField<'tcx>,
615) -> Result<(), ErrorGuaranteed> {
616 let tcx = infcx.tcx;
617 if #[allow(non_exhaustive_omitted_patterns)] match (source.ty.kind(),
target.ty.kind()) {
(&ty::Ref(_, _, ty::Mutability::Mut), &ty::Ref(_, _, ty::Mutability::Not))
| (&ty::Alias(..), _) | (_, &ty::Alias(..)) => true,
_ => false,
}matches!(
618 (source.ty.kind(), target.ty.kind()),
619 (&ty::Ref(_, _, ty::Mutability::Mut), &ty::Ref(_, _, ty::Mutability::Not))
620 | (&ty::Alias(..), _)
621 | (_, &ty::Alias(..))
622 ) && field_tys_satisfy_relation_after_normalization_and_resolution(
623 tcx,
624 impl_did,
625 param_env,
626 source.ty,
627 target.ty,
628 source.span,
629 FieldRelation::MutRefToSharedRef,
630 ) {
631 return Ok(());
632 }
633
634 if field_tys_satisfy_relation_after_normalization_and_resolution(
635 tcx,
636 impl_did,
637 param_env,
638 source.ty,
639 target.ty,
640 source.span,
641 FieldRelation::Equal,
642 ) {
643 return assert_field_type_is_copy(tcx, infcx, impl_did, param_env, source.ty, source.span);
644 }
645
646 validate_field_tys_satisfy_coerce_shared_relation(
647 infcx,
648 impl_did,
649 param_env,
650 coerce_shared_trait,
651 trait_name,
652 span,
653 diagnostic_context,
654 source,
655 target,
656 )
657}
658
659fn validate_coerce_shared_unpaired_source_field<'tcx>(
660 infcx: &InferCtxt<'tcx>,
661 impl_did: LocalDefId,
662 param_env: ty::ParamEnv<'tcx>,
663 reborrow_trait: DefId,
664 trait_name: &'static str,
665 diagnostic_context: CoerceSharedDiagnosticContext,
666 mut source: ReborrowDataField<'tcx>,
667) -> Result<(), ErrorGuaranteed> {
668 let tcx = infcx.tcx;
669 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
670 source.ty = ocx
671 .deeply_normalize(
672 &traits::ObligationCause::misc(source.span, impl_did),
673 param_env,
674 Unnormalized::new_wip(source.ty),
675 )
676 .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
677
678 if field_type_is_reborrow(
679 tcx,
680 infcx,
681 reborrow_trait,
682 impl_did,
683 param_env,
684 source.ty,
685 source.span,
686 ) || field_type_is_copy(tcx, infcx, impl_did, param_env, source.ty, source.span)
687 {
688 return Ok(());
689 }
690
691 Err(tcx.dcx().emit_err(diagnostics::CoerceSharedOmittedSourceFieldNotCopyOrReborrow {
692 span: source.span,
693 impl_span: diagnostic_context.impl_span,
694 trait_name,
695 field_name: source.name,
696 field_ty: source.ty,
697 }))
698}
699
700fn validate_field_tys_satisfy_coerce_shared_relation<'tcx>(
701 infcx: &InferCtxt<'tcx>,
702 impl_did: LocalDefId,
703 param_env: ty::ParamEnv<'tcx>,
704 coerce_shared_trait: DefId,
705 trait_name: &'static str,
706 span: Span,
707 diagnostic_context: CoerceSharedDiagnosticContext,
708 source: ReborrowDataField<'tcx>,
709 target: ReborrowDataField<'tcx>,
710) -> Result<(), ErrorGuaranteed> {
711 let tcx = infcx.tcx;
712 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
713 let cause = traits::ObligationCause::misc(span, impl_did);
714 ocx.register_obligation(Obligation::new(
715 tcx,
716 cause,
717 param_env,
718 ty::TraitRef::new(tcx, coerce_shared_trait, [source.ty, target.ty]),
719 ));
720 let errors = ocx.evaluate_obligations_error_on_ambiguity();
721
722 if errors.has_errors() {
723 return Err(emit_coerce_shared_field_mismatch(
724 tcx,
725 trait_name,
726 diagnostic_context,
727 source,
728 target,
729 ));
730 }
731
732 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])
733}
734
735fn emit_coerce_shared_field_mismatch<'tcx>(
736 tcx: TyCtxt<'tcx>,
737 trait_name: &'static str,
738 diagnostic_context: CoerceSharedDiagnosticContext,
739 source: ReborrowDataField<'tcx>,
740 target: ReborrowDataField<'tcx>,
741) -> ErrorGuaranteed {
742 tcx.dcx().emit_err(diagnostics::CoerceSharedFieldMismatch {
743 span: target.span,
744 source_span: source.span,
745 impl_span: diagnostic_context.impl_span,
746 source_name: source.name,
747 source_ty: source.ty,
748 target_name: target.name,
749 target_ty: target.ty,
750 trait_name,
751 })
752}
753
754enum FieldRelation {
755 Equal,
756 MutRefToSharedRef,
757}
758
759fn field_tys_satisfy_relation_after_normalization_and_resolution<'tcx>(
764 tcx: TyCtxt<'tcx>,
765 impl_did: LocalDefId,
766 param_env: ty::ParamEnv<'tcx>,
767 source_ty: Ty<'tcx>,
768 target_ty: Ty<'tcx>,
769 span: Span,
770 relation: FieldRelation,
771) -> bool {
772 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
773 let cause = traits::ObligationCause::misc(span, impl_did);
774 let ocx = ObligationCtxt::new(&infcx);
775
776 let Ok((source_ty, target_ty)) =
777 ocx.deeply_normalize(&cause, param_env, Unnormalized::new_wip((source_ty, target_ty)))
778 else {
779 return false;
780 };
781
782 if ocx.evaluate_obligations_error_on_ambiguity().has_errors() {
783 return false;
784 }
785
786 match relation {
787 FieldRelation::Equal => {
788 if infcx.relate(param_env, source_ty, ty::Variance::Invariant, target_ty, span).is_err()
789 {
790 return false;
791 }
792 }
793 FieldRelation::MutRefToSharedRef => {
794 let (
795 &ty::Ref(source_region, source_referent_ty, ty::Mutability::Mut),
796 &ty::Ref(target_region, target_referent_ty, ty::Mutability::Not),
797 ) = (source_ty.kind(), target_ty.kind())
798 else {
799 return false;
800 };
801 if source_region != target_region {
802 return false;
803 }
804 if ocx.sup(&cause, param_env, target_referent_ty, source_referent_ty).is_err() {
805 return false;
806 }
807 }
808 };
809
810 ocx.evaluate_obligations_error_on_ambiguity().no_errors()
811 && ocx.resolve_regions(impl_did, param_env, []).is_empty()
812}