@@ -33,7 +33,7 @@ use ty::VariantDef;
33
33
use super :: report_unexpected_variant_res;
34
34
use crate :: expectation:: Expectation ;
35
35
use crate :: gather_locals:: DeclOrigin ;
36
- use crate :: { FnCtxt , LoweredTy , errors} ;
36
+ use crate :: { FnCtxt , errors} ;
37
37
38
38
const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ : & str = "\
39
39
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 :: Overloaded }
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`?
@@ -336,13 +374,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336
374
fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
337
375
let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
338
376
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 {
340
380
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 ) )
342
382
}
343
383
_ => None ,
344
384
} ;
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 ( ) ) ;
346
388
let ( expected, binding_mode, max_ref_mutbl) =
347
389
self . calc_default_binding_mode ( pat, expected, binding_mode, adjust_mode, max_ref_mutbl) ;
348
390
let pat_info = PatInfo {
@@ -357,16 +399,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
357
399
PatKind :: Wild | PatKind :: Err ( _) => expected,
358
400
// We allow any type here; we ensure that the type is uninhabited during match checking.
359
401
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
+ } ;
370
409
self . write_ty ( * hir_id, ty) ;
371
410
ty
372
411
}
@@ -490,8 +529,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
490
529
491
530
/// How should the binding mode and expected type be adjusted?
492
531
///
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 {
495
538
// When we perform destructuring assignment, we disable default match bindings, which are
496
539
// unintuitive in this context.
497
540
if !pat. default_binding_modes {
@@ -512,17 +555,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
512
555
| PatKind :: Deref ( _) => AdjustMode :: Peel { kind : PeelKind :: RefOnly } ,
513
556
// A never pattern behaves somewhat like a literal or unit variant.
514
557
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
+ }
526
562
527
563
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
528
564
// All other literals result in non-reference types.
@@ -1241,31 +1277,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1241
1277
}
1242
1278
}
1243
1279
1244
- fn check_pat_path (
1280
+ fn resolve_pat_path (
1245
1281
& self ,
1246
1282
path_id : HirId ,
1247
- pat_id_for_diag : HirId ,
1248
1283
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 > {
1254
1286
let tcx = self . tcx ;
1255
1287
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 ) ;
1258
1290
match res {
1259
1291
Res :: Err => {
1260
1292
let e =
1261
1293
self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
1262
1294
self . set_tainted_by_errors ( e) ;
1263
- return Ty :: new_error ( tcx , e) ;
1295
+ return Err ( e) ;
1264
1296
}
1265
1297
Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
1266
1298
let expected = "unit struct, unit variant or constant" ;
1267
1299
let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1268
- return Ty :: new_error ( tcx , e) ;
1300
+ return Err ( e) ;
1269
1301
}
1270
1302
Res :: SelfCtor ( def_id) => {
1271
1303
if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
@@ -1283,7 +1315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1283
1315
E0533 ,
1284
1316
"unit struct" ,
1285
1317
) ;
1286
- return Ty :: new_error ( tcx , e) ;
1318
+ return Err ( e) ;
1287
1319
}
1288
1320
}
1289
1321
Res :: Def (
@@ -1296,15 +1328,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1296
1328
_ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
1297
1329
}
1298
1330
1299
- // Type-check the path.
1331
+ // Find the type of the path pattern, for later checking .
1300
1332
let ( pat_ty, pat_res) =
1301
1333
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 > {
1302
1345
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 )
1304
1347
{
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 ) ;
1306
1349
}
1307
- pat_ty
1350
+ resolved . ty
1308
1351
}
1309
1352
1310
1353
fn maybe_suggest_range_literal (
@@ -1347,11 +1390,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1347
1390
mut e : Diag < ' _ > ,
1348
1391
hir_id : HirId ,
1349
1392
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 > ,
1354
1394
) {
1395
+ let ResolvedPatKind :: Path { res, pat_res, segments } = resolved_pat. kind ;
1396
+
1355
1397
if let Some ( span) = self . tcx . hir_res_span ( pat_res) {
1356
1398
e. span_label ( span, format ! ( "{} defined here" , res. descr( ) ) ) ;
1357
1399
if let [ hir:: PathSegment { ident, .. } ] = & * segments {
@@ -1374,7 +1416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1374
1416
) ;
1375
1417
}
1376
1418
_ => {
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 ( ) {
1378
1420
ty:: Adt ( def, _) => match res {
1379
1421
Res :: Def ( DefKind :: Const , def_id) => ( Some ( def. did ( ) ) , Some ( def_id) ) ,
1380
1422
_ => ( None , None ) ,
0 commit comments