@@ -203,17 +203,15 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
203203 let tcx = checker.tcx;
204204 let impl_did = checker.impl_def_id;
205205 let trait_ref = checker.impl_header.trait_ref.instantiate_identity();
206+ assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
207+ let dispatch_from_dyn_trait_did = trait_ref.def_id;
206208 debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
207209
208210 let span = tcx.def_span(impl_did);
209211 let trait_name = "DispatchFromDyn";
210212
211- let source = trait_ref.self_ty();
212- let target = {
213- assert!(tcx.is_lang_item(trait_ref.def_id, LangItem::DispatchFromDyn));
214-
215- trait_ref.args.type_at(1)
216- };
213+ let mut source = trait_ref.self_ty();
214+ let mut target = trait_ref.args.type_at(1);
217215
218216 // Check `CoercePointee` impl is WF -- if not, then there's no reason to report
219217 // redundant errors for `DispatchFromDyn`. This is best effort, though.
@@ -242,138 +240,173 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
242240 // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else
243241 // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent)
244242 // even if they do not carry that attribute.
245- match (source.kind(), target.kind()) {
246- (&ty::Pat(_, pat_a), &ty::Pat(_, pat_b)) => {
247- if pat_a != pat_b {
248- return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
249- span,
250- trait_name,
251- pat_a: pat_a.to_string(),
252- pat_b: pat_b.to_string(),
253- }));
243+ let mut behind_ref = false;
244+ loop {
245+ match (source.kind(), target.kind()) {
246+ (&ty::Pat(ty_a, pat_a), &ty::Pat(ty_b, pat_b)) => {
247+ if pat_a != pat_b {
248+ return Err(tcx.dcx().emit_err(errors::CoerceSamePatKind {
249+ span,
250+ trait_name,
251+ pat_a: pat_a.to_string(),
252+ pat_b: pat_b.to_string(),
253+ }));
254+ }
255+ source = ty_a;
256+ target = ty_b;
254257 }
255- Ok(())
256- }
257258
258- (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b))
259- if r_a == *r_b && mutbl_a == *mutbl_b =>
260- {
261- Ok(())
262- }
263- (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()),
264- (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
265- if def_a.is_struct() && def_b.is_struct() =>
266- {
267- if def_a != def_b {
268- let source_path = tcx.def_path_str(def_a.did());
269- let target_path = tcx.def_path_str(def_b.did());
270- return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
271- span,
272- trait_name,
273- note: true,
274- source_path,
275- target_path,
276- }));
259+ (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b))
260+ if !behind_ref && r_a == r_b && mutbl_a == mutbl_b =>
261+ {
262+ source = ty_a;
263+ target = ty_b;
264+ behind_ref = true;
277265 }
278-
279- if def_a.repr().c() || def_a.repr().packed() {
280- return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
266+ (&ty::RawPtr(ty_a, a_mutbl), &ty::RawPtr(ty_b, b_mutbl))
267+ if !behind_ref && a_mutbl == b_mutbl =>
268+ {
269+ source = ty_a;
270+ target = ty_b;
271+ behind_ref = true;
281272 }
273+ (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b))
274+ if !behind_ref && def_a.is_struct() && def_b.is_struct() =>
275+ {
276+ if def_a != def_b {
277+ let source_path = tcx.def_path_str(def_a.did());
278+ let target_path = tcx.def_path_str(def_b.did());
279+ return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
280+ span,
281+ trait_name,
282+ note: true,
283+ source_path,
284+ target_path,
285+ }));
286+ }
282287
283- let fields = &def_a.non_enum_variant().fields;
284-
285- let mut res = Ok(());
286- let coerced_fields = fields
287- .iter_enumerated()
288- .filter_map(|(i, field)| {
289- // Ignore PhantomData fields
290- let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
291- if tcx
292- .try_normalize_erasing_regions(
293- ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
294- unnormalized_ty,
295- )
296- .unwrap_or(unnormalized_ty)
297- .is_phantom_data()
298- {
299- return None;
300- }
288+ if def_a.repr().c() || def_a.repr().packed() {
289+ return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
290+ }
301291
302- let ty_a = field.ty(tcx, args_a);
303- let ty_b = field.ty(tcx, args_b);
304-
305- // FIXME: We could do normalization here, but is it really worth it?
306- if ty_a == ty_b {
307- // Allow 1-ZSTs that don't mention type params.
308- //
309- // Allowing type params here would allow us to possibly transmute
310- // between ZSTs, which may be used to create library unsoundness.
311- if let Ok(layout) =
312- tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
313- && layout.is_1zst()
314- && !ty_a.has_non_region_param()
292+ let fields = &def_a.non_enum_variant().fields;
293+
294+ let coerced_fields: Vec<_> = fields
295+ .iter_enumerated()
296+ .filter_map(|(i, field)| {
297+ // Ignore PhantomData fields
298+ let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
299+ if tcx
300+ .try_normalize_erasing_regions(
301+ ty::TypingEnv::non_body_analysis(tcx, def_a.did()),
302+ unnormalized_ty,
303+ )
304+ .unwrap_or(unnormalized_ty)
305+ .is_phantom_data()
315306 {
316- // ignore 1-ZST fields
317307 return None;
318308 }
319309
320- res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
321- span,
322- name: field.ident(tcx),
323- ty: ty_a,
324- }));
310+ let ty_a = field.ty(tcx, args_a);
311+ let ty_b = field.ty(tcx, args_b);
312+
313+ // FIXME: We could do normalization here, but is it really worth it?
314+ if ty_a == ty_b {
315+ // Allow 1-ZSTs that don't mention type params.
316+ //
317+ // Allowing type params here would allow us to possibly transmute
318+ // between ZSTs, which may be used to create library unsoundness.
319+ if let Ok(layout) =
320+ tcx.layout_of(infcx.typing_env(param_env).as_query_input(ty_a))
321+ && layout.is_1zst()
322+ && !ty_a.has_non_region_param()
323+ {
324+ // ignore 1-ZST fields
325+ return None;
326+ }
325327
326- None
327- } else {
328- Some((i, ty_a, ty_b, tcx.def_span(field.did)))
328+ Some(Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
329+ span,
330+ name: field.ident(tcx),
331+ ty: ty_a,
332+ })))
333+ } else {
334+ Some(Ok((i, ty_a, ty_b, tcx.def_span(field.did))))
335+ }
336+ })
337+ .collect::<Result<_, _>>()?;
338+
339+ if coerced_fields.is_empty() {
340+ return Err(tcx.dcx().emit_err(errors::CoerceNoField {
341+ span,
342+ trait_name,
343+ note: true,
344+ }));
345+ }
346+ if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
347+ let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
348+ ocx.register_obligation(Obligation::new(
349+ tcx,
350+ cause.clone(),
351+ param_env,
352+ ty::TraitRef::new(tcx, dispatch_from_dyn_trait_did, [ty_a, ty_b]),
353+ ));
354+ let errors = ocx.evaluate_obligations_error_on_ambiguity();
355+ if !errors.is_empty() {
356+ if is_from_coerce_pointee_derive(tcx, span) {
357+ return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
358+ span,
359+ trait_name,
360+ ty: trait_ref.self_ty(),
361+ field_span,
362+ field_ty: ty_a,
363+ }));
364+ } else {
365+ return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
366+ }
329367 }
330- })
331- .collect::<Vec<_>>();
332- res?;
333368
334- if coerced_fields.is_empty() {
335- return Err(tcx.dcx().emit_err(errors::CoerceNoField {
369+ // Finally, resolve all regions.
370+ ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
371+
372+ return Ok(());
373+ }
374+ return Err(tcx.dcx().emit_err(errors::CoerceMulti {
336375 span,
337376 trait_name,
338- note: true,
377+ number: coerced_fields.len(),
378+ fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
339379 }));
340- } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
380+ }
381+ (ty::Param(_), ty::Param(_)) => {
341382 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
342383 ocx.register_obligation(Obligation::new(
343384 tcx,
344385 cause.clone(),
345386 param_env,
346- ty::TraitRef::new(tcx, trait_ref.def_id, [ty_a, ty_b]),
387+ ty::TraitRef::new(
388+ tcx,
389+ tcx.require_lang_item(LangItem::Unsize, span),
390+ [source, target],
391+ ),
347392 ));
348393 let errors = ocx.evaluate_obligations_error_on_ambiguity();
349394 if !errors.is_empty() {
350- if is_from_coerce_pointee_derive(tcx, span) {
351- return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
352- span,
353- trait_name,
354- ty: trait_ref.self_ty(),
355- field_span,
356- field_ty: ty_a,
357- }));
358- } else {
359- return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
360- }
395+ return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
361396 }
362-
363- // Finally, resolve all regions.
364397 ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
365-
366- Ok(())
367- } else {
368- return Err(tcx.dcx().emit_err(errors::CoerceMulti {
369- span,
370- trait_name,
371- number: coerced_fields.len(),
372- fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
373- }));
398+ return Ok(());
399+ }
400+ _ => {
401+ if behind_ref {
402+ return Err(tcx.dcx().emit_err(errors::DispatchFromDynMultiRefs { span }));
403+ } else {
404+ return Err(tcx
405+ .dcx()
406+ .emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
407+ }
374408 }
375409 }
376- _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
377410 }
378411}
379412
0 commit comments