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