@@ -34,7 +34,7 @@ use ty::adjustment::{PatAdjust, PatAdjustment};
3434use super :: report_unexpected_variant_res;
3535use crate :: expectation:: Expectation ;
3636use crate :: gather_locals:: DeclOrigin ;
37- use crate :: { FnCtxt , LoweredTy , errors} ;
37+ use crate :: { FnCtxt , errors} ;
3838
3939const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ : & str = "\
4040 This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
@@ -258,6 +258,44 @@ enum InheritedRefMatchRule {
258258 } ,
259259}
260260
261+ /// When checking patterns containing paths, we need to know the path's resolution to determine
262+ /// whether to apply match ergonomics and implicitly dereference the scrutinee. For instance, when
263+ /// the `deref_patterns` feature is enabled and we're matching against a scrutinee of type
264+ /// `Cow<'a, Option<u8>>`, we insert an implicit dereference to allow the pattern `Some(_)` to type,
265+ /// but we must not dereference it when checking the pattern `Cow::Borrowed(_)`.
266+ ///
267+ /// `ResolvedPat` contains the information from resolution needed to determine match ergonomics
268+ /// adjustments, and to finish checking the pattern once we know its adjusted type.
269+ #[ derive( Clone , Copy , Debug ) ]
270+ struct ResolvedPat < ' tcx > {
271+ /// The type of the pattern, to be checked against the type of the scrutinee after peeling. This
272+ /// is also used to avoid peeling the scrutinee's constructors (see the `Cow` example above).
273+ ty : Ty < ' tcx > ,
274+ kind : ResolvedPatKind < ' tcx > ,
275+ }
276+
277+ #[ derive( Clone , Copy , Debug ) ]
278+ enum ResolvedPatKind < ' tcx > {
279+ Path { res : Res , pat_res : Res , segments : & ' tcx [ hir:: PathSegment < ' tcx > ] } ,
280+ }
281+
282+ impl < ' tcx > ResolvedPat < ' tcx > {
283+ fn adjust_mode ( & self ) -> AdjustMode {
284+ let ResolvedPatKind :: Path { res, .. } = self . kind ;
285+ if matches ! ( res, Res :: Def ( DefKind :: Const | DefKind :: AssocConst , _) ) {
286+ // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
287+ // Peeling the reference types too early will cause type checking failures.
288+ // Although it would be possible to *also* peel the types of the constants too.
289+ AdjustMode :: Pass
290+ } else {
291+ // The remaining possible resolutions for path, struct, and tuple struct patterns are
292+ // ADT constructors. As such, we may peel references freely, but we must not peel the
293+ // ADT itself from the scrutinee if it's a smart pointer.
294+ AdjustMode :: Peel { kind : PeelKind :: Implicit }
295+ }
296+ }
297+ }
298+
261299impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
262300 /// Experimental pattern feature: after matching against a shared reference, do we limit the
263301 /// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`?
@@ -334,13 +372,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
334372 /// Conversely, inside this module, `check_pat_top` should never be used.
335373 #[ instrument( level = "debug" , skip( self , pat_info) ) ]
336374 fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
375+ // For patterns containing paths, we need the path's resolution to determine whether to
376+ // implicitly dereference the scrutinee before matching.
337377 let opt_path_res = match pat. kind {
338378 PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
339- Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath , * hir_id, * span) )
379+ Some ( self . resolve_pat_path ( * hir_id, * span, qpath ) )
340380 }
341381 _ => None ,
342382 } ;
343- let adjust_mode = self . calc_adjust_mode ( pat, opt_path_res. map ( | ( res , .. ) | res ) ) ;
383+ let adjust_mode = self . calc_adjust_mode ( pat, opt_path_res) ;
344384 let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
345385 self . write_ty ( pat. hir_id , ty) ;
346386
@@ -406,7 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
406446 fn check_pat_inner (
407447 & self ,
408448 pat : & ' tcx Pat < ' tcx > ,
409- opt_path_res : Option < ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir :: PathSegment < ' tcx > ] ) > ,
449+ opt_path_res : Option < Result < ResolvedPat < ' tcx > , ErrorGuaranteed > > ,
410450 adjust_mode : AdjustMode ,
411451 expected : Ty < ' tcx > ,
412452 pat_info : PatInfo < ' tcx > ,
@@ -515,16 +555,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
515555 PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
516556 // We allow any type here; we ensure that the type is uninhabited during match checking.
517557 PatKind :: Never => expected,
518- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
519- let ty = self . check_pat_path (
520- * hir_id,
521- pat. hir_id ,
522- * span,
523- qpath,
524- opt_path_res. unwrap ( ) ,
525- expected,
526- & pat_info. top_info ,
527- ) ;
558+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , hir_id, .. } ) => {
559+ let ty = match opt_path_res. unwrap ( ) {
560+ Ok ( ref pr) => {
561+ self . check_pat_path ( pat. hir_id , pat. span , pr, expected, & pat_info. top_info )
562+ }
563+ Err ( guar) => Ty :: new_error ( self . tcx , guar) ,
564+ } ;
528565 self . write_ty ( * hir_id, ty) ;
529566 ty
530567 }
@@ -566,8 +603,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
566603
567604 /// How should the binding mode and expected type be adjusted?
568605 ///
569- /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
570- fn calc_adjust_mode ( & self , pat : & ' tcx Pat < ' tcx > , opt_path_res : Option < Res > ) -> AdjustMode {
606+ /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`.
607+ fn calc_adjust_mode (
608+ & self ,
609+ pat : & ' tcx Pat < ' tcx > ,
610+ opt_path_res : Option < Result < ResolvedPat < ' tcx > , ErrorGuaranteed > > ,
611+ ) -> AdjustMode {
571612 match & pat. kind {
572613 // Type checking these product-like types successfully always require
573614 // that the expected type be of those types and not reference types.
@@ -583,17 +624,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
583624 | PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: ExplicitDerefPat } ,
584625 // A never pattern behaves somewhat like a literal or unit variant.
585626 PatKind :: Never => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
586- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => match opt_path_res. unwrap ( ) {
587- // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
588- // Peeling the reference types too early will cause type checking failures.
589- // Although it would be possible to *also* peel the types of the constants too.
590- Res :: Def ( DefKind :: Const | DefKind :: AssocConst , _) => AdjustMode :: Pass ,
591- // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which
592- // could successfully compile. The former being `Self` requires a unit struct.
593- // In either case, and unlike constants, the pattern itself cannot be
594- // a reference type wherefore peeling doesn't give up any expressiveness.
595- _ => AdjustMode :: Peel { kind : PeelKind :: Implicit } ,
596- } ,
627+ // For patterns with paths, how we peel the scrutinee depends on the path's resolution.
628+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
629+ // If there was an error resolving the path, default to peeling everything.
630+ opt_path_res. unwrap ( ) . map_or ( AdjustMode :: Peel { kind : PeelKind :: Implicit } , |pr| pr. adjust_mode ( ) )
631+ }
597632
598633 // String and byte-string literals result in types `&str` and `&[u8]` respectively.
599634 // All other literals result in non-reference types.
@@ -1216,31 +1251,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12161251 }
12171252 }
12181253
1219- fn check_pat_path (
1254+ fn resolve_pat_path (
12201255 & self ,
12211256 path_id : HirId ,
1222- pat_id_for_diag : HirId ,
12231257 span : Span ,
1224- qpath : & hir:: QPath < ' _ > ,
1225- path_resolution : ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) ,
1226- expected : Ty < ' tcx > ,
1227- ti : & TopInfo < ' tcx > ,
1228- ) -> Ty < ' tcx > {
1258+ qpath : & ' tcx hir:: QPath < ' _ > ,
1259+ ) -> Result < ResolvedPat < ' tcx > , ErrorGuaranteed > {
12291260 let tcx = self . tcx ;
12301261
1231- // We have already resolved the path.
1232- let ( res , opt_ty , segments ) = path_resolution ;
1262+ let ( res , opt_ty , segments ) =
1263+ self . resolve_ty_and_res_fully_qualified_call ( qpath , path_id , span ) ;
12331264 match res {
12341265 Res :: Err => {
12351266 let e =
12361267 self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
12371268 self . set_tainted_by_errors ( e) ;
1238- return Ty :: new_error ( tcx , e) ;
1269+ return Err ( e) ;
12391270 }
12401271 Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
12411272 let expected = "unit struct, unit variant or constant" ;
12421273 let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1243- return Ty :: new_error ( tcx , e) ;
1274+ return Err ( e) ;
12441275 }
12451276 Res :: SelfCtor ( def_id) => {
12461277 if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
@@ -1258,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12581289 E0533 ,
12591290 "unit struct" ,
12601291 ) ;
1261- return Ty :: new_error ( tcx , e) ;
1292+ return Err ( e) ;
12621293 }
12631294 }
12641295 Res :: Def (
@@ -1271,15 +1302,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12711302 _ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
12721303 }
12731304
1274- // Type-check the path.
1305+ // Find the type of the path pattern, for later checking .
12751306 let ( pat_ty, pat_res) =
12761307 self . instantiate_value_path ( segments, opt_ty, res, span, span, path_id) ;
1308+ Ok ( ResolvedPat { ty : pat_ty, kind : ResolvedPatKind :: Path { res, pat_res, segments } } )
1309+ }
1310+
1311+ fn check_pat_path (
1312+ & self ,
1313+ pat_id_for_diag : HirId ,
1314+ span : Span ,
1315+ resolved : & ResolvedPat < ' tcx > ,
1316+ expected : Ty < ' tcx > ,
1317+ ti : & TopInfo < ' tcx > ,
1318+ ) -> Ty < ' tcx > {
12771319 if let Err ( err) =
1278- self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, pat_ty )
1320+ self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, resolved . ty )
12791321 {
1280- self . emit_bad_pat_path ( err, pat_id_for_diag, span, res , pat_res , pat_ty , segments ) ;
1322+ self . emit_bad_pat_path ( err, pat_id_for_diag, span, resolved ) ;
12811323 }
1282- pat_ty
1324+ resolved . ty
12831325 }
12841326
12851327 fn maybe_suggest_range_literal (
@@ -1322,11 +1364,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13221364 mut e : Diag < ' _ > ,
13231365 hir_id : HirId ,
13241366 pat_span : Span ,
1325- res : Res ,
1326- pat_res : Res ,
1327- pat_ty : Ty < ' tcx > ,
1328- segments : & ' tcx [ hir:: PathSegment < ' tcx > ] ,
1367+ resolved_pat : & ResolvedPat < ' tcx > ,
13291368 ) {
1369+ let ResolvedPatKind :: Path { res, pat_res, segments } = resolved_pat. kind ;
1370+
13301371 if let Some ( span) = self . tcx . hir_res_span ( pat_res) {
13311372 e. span_label ( span, format ! ( "{} defined here" , res. descr( ) ) ) ;
13321373 if let [ hir:: PathSegment { ident, .. } ] = & * segments {
@@ -1349,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13491390 ) ;
13501391 }
13511392 _ => {
1352- let ( type_def_id, item_def_id) = match pat_ty . kind ( ) {
1393+ let ( type_def_id, item_def_id) = match resolved_pat . ty . kind ( ) {
13531394 ty:: Adt ( def, _) => match res {
13541395 Res :: Def ( DefKind :: Const , def_id) => ( Some ( def. did ( ) ) , Some ( def_id) ) ,
13551396 _ => ( None , None ) ,
0 commit comments