@@ -58,6 +58,9 @@ struct ConstToPat<'a, 'tcx> {
5858 include_lint_checks : bool ,
5959}
6060
61+ #[ derive( Debug ) ]
62+ struct FallbackToConstRef ;
63+
6164impl < ' a , ' tcx > ConstToPat < ' a , ' tcx > {
6265 fn new (
6366 pat_ctxt : & PatCtxt < ' _ , ' tcx > ,
@@ -103,7 +106,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
103106 // once indirect_structural_match is a full fledged error, this
104107 // level of indirection can be eliminated
105108
106- let inlined_const_as_pat = self . recur ( cv, mir_structural_match_violation) ;
109+ let inlined_const_as_pat = self . recur ( cv, mir_structural_match_violation) . unwrap ( ) ;
107110
108111 if self . include_lint_checks && !self . saw_const_match_error . get ( ) {
109112 // If we were able to successfully convert the const to some pat,
@@ -216,18 +219,22 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
216219 }
217220
218221 // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
219- fn recur ( & self , cv : & ' tcx ty:: Const < ' tcx > , mir_structural_match_violation : bool ) -> Pat < ' tcx > {
222+ fn recur (
223+ & self ,
224+ cv : & ' tcx ty:: Const < ' tcx > ,
225+ mir_structural_match_violation : bool ,
226+ ) -> Result < Pat < ' tcx > , FallbackToConstRef > {
220227 let id = self . id ;
221228 let span = self . span ;
222229 let tcx = self . tcx ( ) ;
223230 let param_env = self . param_env ;
224231
225- let field_pats = |vals : & [ & ' tcx ty:: Const < ' tcx > ] | {
232+ let field_pats = |vals : & [ & ' tcx ty:: Const < ' tcx > ] | -> Result < _ , _ > {
226233 vals. iter ( )
227234 . enumerate ( )
228235 . map ( |( idx, val) | {
229236 let field = Field :: new ( idx) ;
230- FieldPat { field, pattern : self . recur ( val, false ) }
237+ Ok ( FieldPat { field, pattern : self . recur ( val, false ) ? } )
231238 } )
232239 . collect ( )
233240 } ;
@@ -287,7 +294,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
287294 |lint| lint. build ( & msg) . emit ( ) ,
288295 ) ;
289296 }
290- PatKind :: Constant { value : cv }
297+ // Since we are behind a reference, we can just bubble the error up so we get a
298+ // constant at reference type, making it easy to let the fallback call
299+ // `PartialEq::eq` on it.
300+ return Err ( FallbackToConstRef ) ;
291301 }
292302 ty:: Adt ( adt_def, _) if !self . type_marked_structural ( cv. ty ) => {
293303 debug ! ( "adt_def {:?} has !type_marked_structural for cv.ty: {:?}" , adt_def, cv. ty) ;
@@ -309,20 +319,20 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
309319 variant_index : destructured
310320 . variant
311321 . expect ( "destructed const of adt without variant id" ) ,
312- subpatterns : field_pats ( destructured. fields ) ,
322+ subpatterns : field_pats ( destructured. fields ) ? ,
313323 }
314324 }
315325 ty:: Tuple ( _) | ty:: Adt ( _, _) => {
316326 let destructured = tcx. destructure_const ( param_env. and ( cv) ) ;
317- PatKind :: Leaf { subpatterns : field_pats ( destructured. fields ) }
327+ PatKind :: Leaf { subpatterns : field_pats ( destructured. fields ) ? }
318328 }
319329 ty:: Array ( ..) => PatKind :: Array {
320330 prefix : tcx
321331 . destructure_const ( param_env. and ( cv) )
322332 . fields
323333 . iter ( )
324334 . map ( |val| self . recur ( val, false ) )
325- . collect ( ) ,
335+ . collect :: < Result < _ , _ > > ( ) ? ,
326336 slice : None ,
327337 suffix : Vec :: new ( ) ,
328338 } ,
@@ -355,7 +365,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
355365 . fields
356366 . iter ( )
357367 . map ( |val| self . recur ( val, false ) )
358- . collect ( ) ,
368+ . collect :: < Result < _ , _ > > ( ) ? ,
359369 slice : None ,
360370 suffix : vec ! [ ] ,
361371 } ) ,
@@ -379,8 +389,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
379389 // deref pattern.
380390 _ => {
381391 let old = self . behind_reference . replace ( true ) ;
382- let val = PatKind :: Deref {
383- subpattern : self . recur ( tcx. deref_const ( self . param_env . and ( cv) ) , false ) ,
392+ // In case there are structural-match violations somewhere in this subpattern,
393+ // we fall back to a const pattern. If we do not do this, we may end up with
394+ // a !structural-match constant that is not of reference type, which makes it
395+ // very hard to invoke `PartialEq::eq` on it as a fallback.
396+ let val = match self . recur ( tcx. deref_const ( self . param_env . and ( cv) ) , false ) {
397+ Ok ( subpattern) => PatKind :: Deref { subpattern } ,
398+ Err ( FallbackToConstRef ) => PatKind :: Constant { value : cv } ,
384399 } ;
385400 self . behind_reference . set ( old) ;
386401 val
@@ -439,6 +454,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
439454 ) ;
440455 }
441456
442- Pat { span, ty : cv. ty , kind : Box :: new ( kind) }
457+ Ok ( Pat { span, ty : cv. ty , kind : Box :: new ( kind) } )
443458 }
444459}
0 commit comments