@@ -34,7 +34,7 @@ use ty::adjustment::{PatAdjust, PatAdjustment};
34
34
use super :: report_unexpected_variant_res;
35
35
use crate :: expectation:: Expectation ;
36
36
use crate :: gather_locals:: DeclOrigin ;
37
- use crate :: { FnCtxt , LoweredTy , errors} ;
37
+ use crate :: { FnCtxt , errors} ;
38
38
39
39
const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ : & str = "\
40
40
This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
@@ -258,6 +258,44 @@ enum InheritedRefMatchRule {
258
258
} ,
259
259
}
260
260
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
+
261
299
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
262
300
/// Experimental pattern feature: after matching against a shared reference, do we limit the
263
301
/// 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> {
334
372
/// Conversely, inside this module, `check_pat_top` should never be used.
335
373
#[ instrument( level = "debug" , skip( self , pat_info) ) ]
336
374
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.
337
377
let opt_path_res = match pat. kind {
338
378
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 ) )
340
380
}
341
381
_ => None ,
342
382
} ;
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) ;
344
384
let ty = self . check_pat_inner ( pat, opt_path_res, adjust_mode, expected, pat_info) ;
345
385
self . write_ty ( pat. hir_id , ty) ;
346
386
@@ -406,7 +446,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
406
446
fn check_pat_inner (
407
447
& self ,
408
448
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 > > ,
410
450
adjust_mode : AdjustMode ,
411
451
expected : Ty < ' tcx > ,
412
452
pat_info : PatInfo < ' tcx > ,
@@ -515,16 +555,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
515
555
PatKind :: Missing | PatKind :: Wild | PatKind :: Err ( _) => expected,
516
556
// We allow any type here; we ensure that the type is uninhabited during match checking.
517
557
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
+ } ;
528
565
self . write_ty ( * hir_id, ty) ;
529
566
ty
530
567
}
@@ -566,8 +603,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
566
603
567
604
/// How should the binding mode and expected type be adjusted?
568
605
///
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 {
571
612
match & pat. kind {
572
613
// Type checking these product-like types successfully always require
573
614
// that the expected type be of those types and not reference types.
@@ -583,17 +624,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
583
624
| PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: ExplicitDerefPat } ,
584
625
// A never pattern behaves somewhat like a literal or unit variant.
585
626
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
+ }
597
632
598
633
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
599
634
// All other literals result in non-reference types.
@@ -1216,31 +1251,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1216
1251
}
1217
1252
}
1218
1253
1219
- fn check_pat_path (
1254
+ fn resolve_pat_path (
1220
1255
& self ,
1221
1256
path_id : HirId ,
1222
- pat_id_for_diag : HirId ,
1223
1257
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 > {
1229
1260
let tcx = self . tcx ;
1230
1261
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 ) ;
1233
1264
match res {
1234
1265
Res :: Err => {
1235
1266
let e =
1236
1267
self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
1237
1268
self . set_tainted_by_errors ( e) ;
1238
- return Ty :: new_error ( tcx , e) ;
1269
+ return Err ( e) ;
1239
1270
}
1240
1271
Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
1241
1272
let expected = "unit struct, unit variant or constant" ;
1242
1273
let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1243
- return Ty :: new_error ( tcx , e) ;
1274
+ return Err ( e) ;
1244
1275
}
1245
1276
Res :: SelfCtor ( def_id) => {
1246
1277
if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
@@ -1258,7 +1289,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1258
1289
E0533 ,
1259
1290
"unit struct" ,
1260
1291
) ;
1261
- return Ty :: new_error ( tcx , e) ;
1292
+ return Err ( e) ;
1262
1293
}
1263
1294
}
1264
1295
Res :: Def (
@@ -1271,15 +1302,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1271
1302
_ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
1272
1303
}
1273
1304
1274
- // Type-check the path.
1305
+ // Find the type of the path pattern, for later checking .
1275
1306
let ( pat_ty, pat_res) =
1276
1307
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 > {
1277
1319
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 )
1279
1321
{
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 ) ;
1281
1323
}
1282
- pat_ty
1324
+ resolved . ty
1283
1325
}
1284
1326
1285
1327
fn maybe_suggest_range_literal (
@@ -1322,11 +1364,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1322
1364
mut e : Diag < ' _ > ,
1323
1365
hir_id : HirId ,
1324
1366
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 > ,
1329
1368
) {
1369
+ let ResolvedPatKind :: Path { res, pat_res, segments } = resolved_pat. kind ;
1370
+
1330
1371
if let Some ( span) = self . tcx . hir_res_span ( pat_res) {
1331
1372
e. span_label ( span, format ! ( "{} defined here" , res. descr( ) ) ) ;
1332
1373
if let [ hir:: PathSegment { ident, .. } ] = & * segments {
@@ -1349,7 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1349
1390
) ;
1350
1391
}
1351
1392
_ => {
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 ( ) {
1353
1394
ty:: Adt ( def, _) => match res {
1354
1395
Res :: Def ( DefKind :: Const , def_id) => ( Some ( def. did ( ) ) , Some ( def_id) ) ,
1355
1396
_ => ( None , None ) ,
0 commit comments