@@ -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