1use rustc_attr_ir::lang_items::LangItem;
2use rustc_errors::ErrorGuaranteed;
3use rustc_hir as hir;
4use rustc_hir::ItemKind;
5use rustc_hir::def_id::{DefId, LocalDefId};
6use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin, TyCtxtInferExt};
7use rustc_infer::traits::{Obligation, TraitErrors};
8use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized};
9use rustc_span::Span;
10use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
11use rustc_trait_selection::traits::{self, ObligationCtxt};
12use tracing::debug;
13
14use super::{
15 ReborrowDataField, assert_field_type_is_copy, collect_reborrow_data_fields, field_type_is_copy,
16 field_type_is_reborrow, trait_impl_lifetime_params_count,
17};
18use crate::coherence::builtin::generic_lifetime_params_count;
19use crate::diagnostics;
20
21#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for CoerceSharedDiagnosticContext {
}
#[automatically_derived]impl ::core::clone::Clone for
CoerceSharedDiagnosticContext {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
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]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
for CoerceSharedTypeRole {
}
#[automatically_derived]impl ::core::clone::Clone for CoerceSharedTypeRole {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self { *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, ty, _) => first_explicit_lifetime_span(lifetime)
135 .or_else(|| first_explicit_lifetime_span_in_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(ty, _) => first_explicit_lifetime_span_in_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 /rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/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("/rustc-dev/3ef0c22cdb86ac42dc6b8f0f1ec36857daa6f2a1/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) == 0 {
244 return Err(tcx.dcx().emit_err(diagnostics::ReborrowNoLifetimes { span, trait_name }));
245 }
246
247 {
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);
248 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
249 let param_env = tcx.param_env(impl_did);
250 let (source, target) = ocx
251 .deeply_normalize(
252 &traits::ObligationCause::misc(span, impl_did),
253 param_env,
254 Unnormalized::new_wip((source, trait_ref.args.type_at(1))),
255 )
256 .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
257 let errors = ocx.evaluate_obligations_error_on_ambiguity();
258 if let TraitErrors::HasErrors(errors) = errors {
259 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
260 }
261
262 if !!source.has_escaping_bound_vars() {
::core::panicking::panic("assertion failed: !source.has_escaping_bound_vars()")
};assert!(!source.has_escaping_bound_vars());
263
264 match (source.kind(), target.kind()) {
265 (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
266 if def_a.is_struct() && def_b.is_struct() =>
267 {
268 let lifetimes_count = generic_lifetime_params_count(args_a.as_slice());
269 if lifetimes_count == 0 {
270 return Err(tcx
271 .dcx()
272 .emit_err(diagnostics::ReborrowNoLifetimes { span, trait_name }));
273 }
274 validate_reborrow_field_access(
275 tcx,
276 impl_did,
277 def_a,
278 trait_name,
279 diagnostic_context,
280 CoerceSharedTypeRole::Source,
281 )?;
282 validate_reborrow_field_access(
283 tcx,
284 impl_did,
285 def_b,
286 trait_name,
287 diagnostic_context,
288 CoerceSharedTypeRole::Target,
289 )?;
290
291 validate_coerce_shared_fields(
292 &infcx,
293 impl_did,
294 param_env,
295 coerce_shared_trait,
296 trait_name,
297 span,
298 diagnostic_context,
299 def_a,
300 args_a,
301 def_b,
302 args_b,
303 )
304 }
305
306 _ => {
307 Err(tcx.dcx().emit_err(diagnostics::CoerceUnsizedNonStruct { span, trait_name }))
309 }
310 }
311}
312
313#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl<'tcx>
::core::clone::TrivialClone for CoerceSharedFieldPair<'tcx> {
}
#[automatically_derived]impl<'tcx> ::core::clone::Clone for
CoerceSharedFieldPair<'tcx> {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
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)]
314struct CoerceSharedFieldPair<'tcx> {
315 source: ReborrowDataField<'tcx>,
316 target: ReborrowDataField<'tcx>,
317}
318
319struct CoerceSharedFields<'tcx> {
320 pairs: Vec<CoerceSharedFieldPair<'tcx>>,
321 unpaired_sources: Vec<ReborrowDataField<'tcx>>,
322}
323
324#[derive(#[automatically_derived]#[doc(hidden)]unsafe impl<'tcx>
::core::clone::TrivialClone for CoerceSharedFieldPairError<'tcx> {
}
#[automatically_derived]impl<'tcx> ::core::clone::Clone for
CoerceSharedFieldPairError<'tcx> {
#[inline]
#[rustc_trivial_field_reads]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<ReborrowDataField<'tcx>>;
*self
}
}Clone, #[automatically_derived]impl<'tcx> ::core::marker::Copy for
CoerceSharedFieldPairError<'tcx> {
}Copy)]
325enum CoerceSharedFieldPairError<'tcx> {
326 FieldStyleMismatch,
327 MissingSourceField { target: ReborrowDataField<'tcx> },
328}
329
330fn collect_coerce_shared_field_pairs<'tcx>(
334 tcx: TyCtxt<'tcx>,
335 source_def: ty::AdtDef<'tcx>,
336 source_args: ty::GenericArgs<'tcx>,
337 target_def: ty::AdtDef<'tcx>,
338 target_args: ty::GenericArgs<'tcx>,
339) -> Result<CoerceSharedFields<'tcx>, CoerceSharedFieldPairError<'tcx>> {
340 let source_variant = source_def.non_enum_variant();
341 let target_variant = target_def.non_enum_variant();
342 if source_variant.ctor_kind() != target_variant.ctor_kind() {
343 return Err(CoerceSharedFieldPairError::FieldStyleMismatch);
344 }
345
346 let source_fields = collect_reborrow_data_fields(tcx, source_def, source_args);
347 let target_fields = collect_reborrow_data_fields(tcx, target_def, target_args);
348
349 let mut pairs = Vec::with_capacity(target_fields.len());
350
351 for target in &target_fields {
352 let source = source_fields
353 .iter()
354 .find(|source| tcx.hygienic_eq(target.ident, source.ident, source_variant.def_id))
355 .ok_or(CoerceSharedFieldPairError::MissingSourceField { target: *target })?;
356
357 pairs.push(CoerceSharedFieldPair { source: *source, target: *target });
358 }
359
360 let unpaired_sources = source_fields
361 .into_iter()
362 .filter(|source| {
363 !target_fields
364 .iter()
365 .any(|target| tcx.hygienic_eq(target.ident, source.ident, source_variant.def_id))
366 })
367 .collect();
368
369 Ok(CoerceSharedFields { pairs, unpaired_sources })
370}
371
372fn validate_reborrow_field_access(
373 tcx: TyCtxt<'_>,
374 impl_did: LocalDefId,
375 def: ty::AdtDef<'_>,
376 trait_name: &'static str,
377 diagnostic_context: CoerceSharedDiagnosticContext,
378 role: CoerceSharedTypeRole,
379) -> Result<(), ErrorGuaranteed> {
380 let module = tcx.parent_module_from_def_id(impl_did);
381 let variant = def.non_enum_variant();
382
383 if variant.field_list_has_applicable_non_exhaustive()
384 || variant.fields.iter().any(|f| !f.vis.is_accessible_from(module, tcx))
385 {
386 Err(tcx.dcx().emit_err(diagnostics::CoerceSharedInaccessibleField {
387 span: diagnostic_context.impl_span,
388 type_span: role.type_span(diagnostic_context),
389 trait_name,
390 role: role.as_str(),
391 type_name: tcx.item_name(def.did()),
392 }))
393 } else {
394 Ok(())
395 }
396}
397
398fn validate_coerce_shared_fields<'tcx>(
399 infcx: &InferCtxt<'tcx>,
400 impl_did: LocalDefId,
401 param_env: ty::ParamEnv<'tcx>,
402 coerce_shared_trait: DefId,
403 trait_name: &'static str,
404 span: Span,
405 diagnostic_context: CoerceSharedDiagnosticContext,
406 source_def: ty::AdtDef<'tcx>,
407 source_args: ty::GenericArgs<'tcx>,
408 target_def: ty::AdtDef<'tcx>,
409 target_args: ty::GenericArgs<'tcx>,
410) -> Result<(), ErrorGuaranteed> {
411 let tcx = infcx.tcx;
412 let fields = match collect_coerce_shared_field_pairs(
413 tcx,
414 source_def,
415 source_args,
416 target_def,
417 target_args,
418 ) {
419 Ok(fields) => fields,
420 Err(CoerceSharedFieldPairError::FieldStyleMismatch) => {
421 return Err(tcx
422 .dcx()
423 .emit_err(diagnostics::CoerceSharedFieldStyleMismatch { span, trait_name }));
424 }
425 Err(CoerceSharedFieldPairError::MissingSourceField { target }) => {
426 return Err(tcx.dcx().emit_err(diagnostics::CoerceSharedMissingField {
427 span: target.span,
428 source_ty_span: diagnostic_context.source_ty_span,
429 trait_name,
430 source_ty_name: tcx.item_name(source_def.did()),
431 field_name: target.name,
432 }));
433 }
434 };
435
436 for field_pair in fields.pairs {
437 validate_coerce_shared_field(
438 infcx,
439 impl_did,
440 param_env,
441 coerce_shared_trait,
442 trait_name,
443 span,
444 diagnostic_context,
445 field_pair.source,
446 field_pair.target,
447 )?;
448 }
449
450 let reborrow_trait = tcx.require_lang_item(LangItem::Reborrow, span);
451 for source in fields.unpaired_sources {
452 validate_coerce_shared_unpaired_source_field(
453 infcx,
454 impl_did,
455 param_env,
456 reborrow_trait,
457 trait_name,
458 diagnostic_context,
459 source,
460 )?;
461 }
462
463 validate_coerce_shared_fields_are_memcpy_compatible(
467 infcx,
468 impl_did,
469 param_env,
470 coerce_shared_trait,
471 trait_name,
472 span,
473 diagnostic_context,
474 source_def,
475 source_args,
476 target_def,
477 target_args,
478 )?;
479
480 Ok(())
481}
482
483fn validate_coerce_shared_fields_are_memcpy_compatible<'tcx>(
484 infcx: &InferCtxt<'tcx>,
485 impl_did: LocalDefId,
486 param_env: ty::ParamEnv<'tcx>,
487 coerce_shared_trait: DefId,
488 trait_name: &'static str,
489 span: Span,
490 diagnostic_context: CoerceSharedDiagnosticContext,
491 source_def: ty::AdtDef<'tcx>,
492 source_args: ty::GenericArgs<'tcx>,
493 target_def: ty::AdtDef<'tcx>,
494 target_args: ty::GenericArgs<'tcx>,
495) -> Result<(), ErrorGuaranteed> {
496 let tcx = infcx.tcx;
497 let source_non_zst_fields =
498 non_zst_reborrow_data_fields(infcx, param_env, source_def, source_args);
499 let target_non_zst_fields =
500 non_zst_reborrow_data_fields(infcx, param_env, target_def, target_args);
501
502 match (&source_non_zst_fields[..], &target_non_zst_fields[..]) {
503 ([], []) => Ok(()),
504 ([source], [target]) => {
505 if field_tys_satisfy_relation_after_normalization_and_resolution(
506 tcx,
507 impl_did,
508 param_env,
509 source.ty,
510 target.ty,
511 source.span,
512 FieldRelation::Equal,
513 ) {
514 return Ok(());
515 }
516
517 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!(
518 (source.ty.kind(), target.ty.kind()),
519 (&ty::Ref(_, _, ty::Mutability::Mut), &ty::Ref(_, _, ty::Mutability::Not))
520 | (&ty::Alias(..), _)
521 | (_, &ty::Alias(..))
522 ) && field_tys_satisfy_relation_after_normalization_and_resolution(
523 tcx,
524 impl_did,
525 param_env,
526 source.ty,
527 target.ty,
528 source.span,
529 FieldRelation::MutRefToSharedRef,
530 ) {
531 return Ok(());
532 }
533
534 validate_field_tys_satisfy_coerce_shared_relation(
535 infcx,
536 impl_did,
537 param_env,
538 coerce_shared_trait,
539 trait_name,
540 span,
541 diagnostic_context,
542 *source,
543 *target,
544 )
545 }
546 _ => Err(tcx.dcx().emit_err(diagnostics::CoerceSharedMultipleNonZstFields {
547 span: diagnostic_context.impl_span,
548 source_ty_span: diagnostic_context.source_ty_span,
549 target_ty_span: diagnostic_context.target_ty_span,
550 trait_name,
551 source_count: source_non_zst_fields.len(),
552 target_count: target_non_zst_fields.len(),
553 })),
554 }
555}
556
557fn non_zst_reborrow_data_fields<'tcx>(
558 infcx: &InferCtxt<'tcx>,
559 param_env: ty::ParamEnv<'tcx>,
560 def: ty::AdtDef<'tcx>,
561 args: ty::GenericArgs<'tcx>,
562) -> Vec<ReborrowDataField<'tcx>> {
563 let tcx = infcx.tcx;
564 collect_reborrow_data_fields(tcx, def, args)
565 .into_iter()
566 .filter(|field| {
567 !#[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!(
568 tcx.layout_of(infcx.typing_env(param_env).as_query_input(field.ty)),
569 Ok(layout) if layout.is_zst()
570 )
571 })
572 .collect()
573}
574
575fn validate_coerce_shared_field<'tcx>(
576 infcx: &InferCtxt<'tcx>,
577 impl_did: LocalDefId,
578 param_env: ty::ParamEnv<'tcx>,
579 coerce_shared_trait: DefId,
580 trait_name: &'static str,
581 span: Span,
582 diagnostic_context: CoerceSharedDiagnosticContext,
583 source: ReborrowDataField<'tcx>,
584 target: ReborrowDataField<'tcx>,
585) -> Result<(), ErrorGuaranteed> {
586 let tcx = infcx.tcx;
587 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!(
588 (source.ty.kind(), target.ty.kind()),
589 (&ty::Ref(_, _, ty::Mutability::Mut), &ty::Ref(_, _, ty::Mutability::Not))
590 | (&ty::Alias(..), _)
591 | (_, &ty::Alias(..))
592 ) && field_tys_satisfy_relation_after_normalization_and_resolution(
593 tcx,
594 impl_did,
595 param_env,
596 source.ty,
597 target.ty,
598 source.span,
599 FieldRelation::MutRefToSharedRef,
600 ) {
601 return Ok(());
602 }
603
604 if field_tys_satisfy_relation_after_normalization_and_resolution(
605 tcx,
606 impl_did,
607 param_env,
608 source.ty,
609 target.ty,
610 source.span,
611 FieldRelation::Equal,
612 ) {
613 return assert_field_type_is_copy(tcx, infcx, impl_did, param_env, source.ty, source.span);
614 }
615
616 validate_field_tys_satisfy_coerce_shared_relation(
617 infcx,
618 impl_did,
619 param_env,
620 coerce_shared_trait,
621 trait_name,
622 span,
623 diagnostic_context,
624 source,
625 target,
626 )
627}
628
629fn validate_coerce_shared_unpaired_source_field<'tcx>(
630 infcx: &InferCtxt<'tcx>,
631 impl_did: LocalDefId,
632 param_env: ty::ParamEnv<'tcx>,
633 reborrow_trait: DefId,
634 trait_name: &'static str,
635 diagnostic_context: CoerceSharedDiagnosticContext,
636 mut source: ReborrowDataField<'tcx>,
637) -> Result<(), ErrorGuaranteed> {
638 let tcx = infcx.tcx;
639 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
640 source.ty = ocx
641 .deeply_normalize(
642 &traits::ObligationCause::misc(source.span, impl_did),
643 param_env,
644 Unnormalized::new_wip(source.ty),
645 )
646 .map_err(|errors| infcx.err_ctxt().report_fulfillment_errors(errors))?;
647
648 if field_type_is_reborrow(
649 tcx,
650 infcx,
651 reborrow_trait,
652 impl_did,
653 param_env,
654 source.ty,
655 source.span,
656 ) || field_type_is_copy(tcx, infcx, impl_did, param_env, source.ty, source.span)
657 {
658 return Ok(());
659 }
660
661 Err(tcx.dcx().emit_err(diagnostics::CoerceSharedOmittedSourceFieldNotCopyOrReborrow {
662 span: source.span,
663 impl_span: diagnostic_context.impl_span,
664 trait_name,
665 field_name: source.name,
666 field_ty: source.ty,
667 }))
668}
669
670fn validate_field_tys_satisfy_coerce_shared_relation<'tcx>(
671 infcx: &InferCtxt<'tcx>,
672 impl_did: LocalDefId,
673 param_env: ty::ParamEnv<'tcx>,
674 coerce_shared_trait: DefId,
675 trait_name: &'static str,
676 span: Span,
677 diagnostic_context: CoerceSharedDiagnosticContext,
678 source: ReborrowDataField<'tcx>,
679 target: ReborrowDataField<'tcx>,
680) -> Result<(), ErrorGuaranteed> {
681 let tcx = infcx.tcx;
682 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
683 let cause = traits::ObligationCause::misc(span, impl_did);
684 ocx.register_obligation(Obligation::new(
685 tcx,
686 cause,
687 param_env,
688 ty::TraitRef::new(tcx, coerce_shared_trait, [source.ty, target.ty]),
689 ));
690 let errors = ocx.evaluate_obligations_error_on_ambiguity();
691
692 if errors.has_errors() {
693 return Err(emit_coerce_shared_field_mismatch(
694 tcx,
695 trait_name,
696 diagnostic_context,
697 source,
698 target,
699 ));
700 }
701
702 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])
703}
704
705fn emit_coerce_shared_field_mismatch<'tcx>(
706 tcx: TyCtxt<'tcx>,
707 trait_name: &'static str,
708 diagnostic_context: CoerceSharedDiagnosticContext,
709 source: ReborrowDataField<'tcx>,
710 target: ReborrowDataField<'tcx>,
711) -> ErrorGuaranteed {
712 tcx.dcx().emit_err(diagnostics::CoerceSharedFieldMismatch {
713 span: target.span,
714 source_span: source.span,
715 impl_span: diagnostic_context.impl_span,
716 source_name: source.name,
717 source_ty: source.ty,
718 target_name: target.name,
719 target_ty: target.ty,
720 trait_name,
721 })
722}
723
724enum FieldRelation {
725 Equal,
726 MutRefToSharedRef,
727}
728
729fn field_tys_satisfy_relation_after_normalization_and_resolution<'tcx>(
737 tcx: TyCtxt<'tcx>,
738 impl_did: LocalDefId,
739 param_env: ty::ParamEnv<'tcx>,
740 source_ty: Ty<'tcx>,
741 target_ty: Ty<'tcx>,
742 span: Span,
743 relation: FieldRelation,
744) -> bool {
745 let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
746 let cause = traits::ObligationCause::misc(span, impl_did);
747 let ocx = ObligationCtxt::new(&infcx);
748
749 let Ok((source_ty, target_ty)) =
750 ocx.deeply_normalize(&cause, param_env, Unnormalized::new_wip((source_ty, target_ty)))
751 else {
752 return false;
753 };
754
755 if ocx.evaluate_obligations_error_on_ambiguity().has_errors() {
756 return false;
757 }
758
759 match relation {
766 FieldRelation::Equal => {
767 if infcx
768 .at(&cause, param_env)
769 .relate(DefineOpaqueTypes::Yes, source_ty, ty::Variance::Covariant, target_ty)
770 .is_err()
771 {
772 return false;
773 }
774 }
775 FieldRelation::MutRefToSharedRef => {
776 let (
777 &ty::Ref(source_region, source_referent_ty, ty::Mutability::Mut),
778 &ty::Ref(target_region, target_referent_ty, ty::Mutability::Not),
779 ) = (source_ty.kind(), target_ty.kind())
780 else {
781 return false;
782 };
783 infcx.sub_regions(
787 SubregionOrigin::Reborrow(span),
788 target_region,
789 source_region,
790 ty::VisibleForLeakCheck::Yes,
791 );
792 if ocx.sup(&cause, param_env, target_referent_ty, source_referent_ty).is_err() {
793 return false;
794 }
795 }
796 };
797
798 ocx.evaluate_obligations_error_on_ambiguity().no_errors()
799 && ocx.resolve_regions(impl_did, param_env, []).is_empty()
800}