@@ -33,7 +33,7 @@ use ty::VariantDef;
3333use super :: report_unexpected_variant_res;
3434use crate :: expectation:: Expectation ;
3535use crate :: gather_locals:: DeclOrigin ;
36- use crate :: { FnCtxt , LoweredTy , errors} ;
36+ use crate :: { FnCtxt , errors} ;
3737
3838const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ : & str = "\
3939 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 :: Overloaded }
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`?
@@ -336,13 +374,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336374 fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
337375 let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
338376
339- let path_res = match pat. kind {
377+ // For patterns containing paths, we need the path's resolution to determine whether to
378+ // implicitly dereference the scrutinee before matching.
379+ let opt_res_pat_or_err = match pat. kind {
340380 PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
341- Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath , * hir_id, * span) )
381+ Some ( self . resolve_pat_path ( * hir_id, * span, qpath ) )
342382 }
343383 _ => None ,
344384 } ;
345- let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
385+ let opt_res_pat = opt_res_pat_or_err. map ( Result :: ok) . flatten ( ) ;
386+
387+ let adjust_mode = self . calc_adjust_mode ( pat, opt_res_pat. as_ref ( ) ) ;
346388 let ( expected, binding_mode, max_ref_mutbl) =
347389 self . calc_default_binding_mode ( pat, expected, binding_mode, adjust_mode, max_ref_mutbl) ;
348390 let pat_info = PatInfo {
@@ -357,16 +399,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
357399 PatKind :: Wild | PatKind :: Err ( _) => expected,
358400 // We allow any type here; we ensure that the type is uninhabited during match checking.
359401 PatKind :: Never => expected,
360- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
361- let ty = self . check_pat_path (
362- * hir_id,
363- pat. hir_id ,
364- * span,
365- qpath,
366- path_res. unwrap ( ) ,
367- expected,
368- & pat_info. top_info ,
369- ) ;
402+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , hir_id, .. } ) => {
403+ let ty = match opt_res_pat_or_err. unwrap ( ) {
404+ Ok ( ref res_pat) => {
405+ self . check_pat_path ( pat. hir_id , pat. span , res_pat, expected, & ti)
406+ }
407+ Err ( guar) => Ty :: new_error ( self . tcx , guar) ,
408+ } ;
370409 self . write_ty ( * hir_id, ty) ;
371410 ty
372411 }
@@ -490,8 +529,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490529
491530 /// How should the binding mode and expected type be adjusted?
492531 ///
493- /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
494- fn calc_adjust_mode ( & self , pat : & ' tcx Pat < ' tcx > , opt_path_res : Option < Res > ) -> AdjustMode {
532+ /// When the pattern contains a path, `opt_resolved_pat` must be `Some(resolved_pat)`.
533+ fn calc_adjust_mode (
534+ & self ,
535+ pat : & ' tcx Pat < ' tcx > ,
536+ opt_resolved_pat : Option < & ResolvedPat < ' tcx > > ,
537+ ) -> AdjustMode {
495538 // When we perform destructuring assignment, we disable default match bindings, which are
496539 // unintuitive in this context.
497540 if !pat. default_binding_modes {
@@ -512,17 +555,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
512555 | PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: RefOnly } ,
513556 // A never pattern behaves somewhat like a literal or unit variant.
514557 PatKind :: Never => AdjustMode :: Peel { kind : PeelKind :: Overloaded } ,
515- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => match opt_path_res. unwrap ( ) {
516- // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
517- // Peeling the reference types too early will cause type checking failures.
518- // Although it would be possible to *also* peel the types of the constants too.
519- Res :: Def ( DefKind :: Const | DefKind :: AssocConst , _) => AdjustMode :: Pass ,
520- // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which
521- // could successfully compile. The former being `Self` requires a unit struct.
522- // In either case, and unlike constants, the pattern itself cannot be
523- // a reference type wherefore peeling doesn't give up any expressiveness.
524- _ => AdjustMode :: Peel { kind : PeelKind :: Overloaded } ,
525- } ,
558+ // For patterns with paths, how we peel the scrutinee depends on the path's resolution.
559+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , .. } ) => {
560+ opt_resolved_pat. map_or ( AdjustMode :: Peel { kind : PeelKind :: Overloaded } , ResolvedPat :: adjust_mode)
561+ }
526562
527563 // String and byte-string literals result in types `&str` and `&[u8]` respectively.
528564 // All other literals result in non-reference types.
@@ -1241,31 +1277,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12411277 }
12421278 }
12431279
1244- fn check_pat_path (
1280+ fn resolve_pat_path (
12451281 & self ,
12461282 path_id : HirId ,
1247- pat_id_for_diag : HirId ,
12481283 span : Span ,
1249- qpath : & hir:: QPath < ' _ > ,
1250- path_resolution : ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) ,
1251- expected : Ty < ' tcx > ,
1252- ti : & TopInfo < ' tcx > ,
1253- ) -> Ty < ' tcx > {
1284+ qpath : & ' tcx hir:: QPath < ' _ > ,
1285+ ) -> Result < ResolvedPat < ' tcx > , ErrorGuaranteed > {
12541286 let tcx = self . tcx ;
12551287
1256- // We have already resolved the path.
1257- let ( res , opt_ty , segments ) = path_resolution ;
1288+ let ( res , opt_ty , segments ) =
1289+ self . resolve_ty_and_res_fully_qualified_call ( qpath , path_id , span ) ;
12581290 match res {
12591291 Res :: Err => {
12601292 let e =
12611293 self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
12621294 self . set_tainted_by_errors ( e) ;
1263- return Ty :: new_error ( tcx , e) ;
1295+ return Err ( e) ;
12641296 }
12651297 Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
12661298 let expected = "unit struct, unit variant or constant" ;
12671299 let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1268- return Ty :: new_error ( tcx , e) ;
1300+ return Err ( e) ;
12691301 }
12701302 Res :: SelfCtor ( def_id) => {
12711303 if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
@@ -1283,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12831315 E0533 ,
12841316 "unit struct" ,
12851317 ) ;
1286- return Ty :: new_error ( tcx , e) ;
1318+ return Err ( e) ;
12871319 }
12881320 }
12891321 Res :: Def (
@@ -1296,15 +1328,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12961328 _ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
12971329 }
12981330
1299- // Type-check the path.
1331+ // Find the type of the path pattern, for later checking .
13001332 let ( pat_ty, pat_res) =
13011333 self . instantiate_value_path ( segments, opt_ty, res, span, span, path_id) ;
1334+ Ok ( ResolvedPat { ty : pat_ty, kind : ResolvedPatKind :: Path { res, pat_res, segments } } )
1335+ }
1336+
1337+ fn check_pat_path (
1338+ & self ,
1339+ pat_id_for_diag : HirId ,
1340+ span : Span ,
1341+ resolved : & ResolvedPat < ' tcx > ,
1342+ expected : Ty < ' tcx > ,
1343+ ti : & TopInfo < ' tcx > ,
1344+ ) -> Ty < ' tcx > {
13021345 if let Err ( err) =
1303- self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, pat_ty )
1346+ self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, resolved . ty )
13041347 {
1305- self . emit_bad_pat_path ( err, pat_id_for_diag, span, res , pat_res , pat_ty , segments ) ;
1348+ self . emit_bad_pat_path ( err, pat_id_for_diag, span, resolved ) ;
13061349 }
1307- pat_ty
1350+ resolved . ty
13081351 }
13091352
13101353 fn maybe_suggest_range_literal (
@@ -1347,11 +1390,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13471390 mut e : Diag < ' _ > ,
13481391 hir_id : HirId ,
13491392 pat_span : Span ,
1350- res : Res ,
1351- pat_res : Res ,
1352- pat_ty : Ty < ' tcx > ,
1353- segments : & ' tcx [ hir:: PathSegment < ' tcx > ] ,
1393+ resolved_pat : & ResolvedPat < ' tcx > ,
13541394 ) {
1395+ let ResolvedPatKind :: Path { res, pat_res, segments } = resolved_pat. kind ;
1396+
13551397 if let Some ( span) = self . tcx . hir_res_span ( pat_res) {
13561398 e. span_label ( span, format ! ( "{} defined here" , res. descr( ) ) ) ;
13571399 if let [ hir:: PathSegment { ident, .. } ] = & * segments {
@@ -1374,7 +1416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13741416 ) ;
13751417 }
13761418 _ => {
1377- let ( type_def_id, item_def_id) = match pat_ty . kind ( ) {
1419+ let ( type_def_id, item_def_id) = match resolved_pat . ty . kind ( ) {
13781420 ty:: Adt ( def, _) => match res {
13791421 Res :: Def ( DefKind :: Const , def_id) => ( Some ( def. did ( ) ) , Some ( def_id) ) ,
13801422 _ => ( None , None ) ,
0 commit comments