@@ -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,24 @@ 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, plus a callback to finish checking the pattern once we know its adjusted type.
269
+ // TODO: add an `adt_def: Option<DefId>` field to handle the `Cow` case above.
270
+ struct ResolvedPat < F : ?Sized > {
271
+ /// For path patterns, this must be `Some(res)`, where `res` is the resolution of the pattern's
272
+ /// `QPath`. Otherwise, this is `None`.
273
+ path_res : Option < Res > ,
274
+ /// Given the expected type of the scrutinee and the [`PatInfo`] after applying match ergonomics
275
+ /// adjustments, finish checking the pattern.
276
+ check : F ,
277
+ }
278
+
261
279
impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
262
280
/// Experimental pattern feature: after matching against a shared reference, do we limit the
263
281
/// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`?
@@ -336,13 +354,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336
354
fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
337
355
let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
338
356
339
- let path_res = match pat. kind {
340
- PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
341
- Some ( self . resolve_ty_and_res_fully_qualified_call ( qpath, * hir_id, * span) )
342
- }
343
- _ => None ,
344
- } ;
345
- let adjust_mode = self . calc_adjust_mode ( pat, path_res. map ( |( res, ..) | res) ) ;
357
+ // For patterns containing paths, we need the path's resolution to determine whether to
358
+ // implicitly dereference the scrutinee before matching.
359
+ let resolved_pat: Option < & ResolvedPat < dyn Fn ( Ty < ' tcx > , PatInfo < ' tcx > ) -> Ty < ' tcx > > > =
360
+ match pat. kind {
361
+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( qpath) , hir_id, span } ) => {
362
+ Some { 0 : & self . check_pat_path ( * hir_id, pat. hir_id , * span, qpath, & ti) }
363
+ }
364
+ _ => None ,
365
+ } ;
366
+ let adjust_mode = self . calc_adjust_mode ( pat, resolved_pat. and_then ( |r| r. path_res ) ) ;
346
367
let ( expected, binding_mode, max_ref_mutbl) =
347
368
self . calc_default_binding_mode ( pat, expected, binding_mode, adjust_mode, max_ref_mutbl) ;
348
369
let pat_info = PatInfo {
@@ -357,16 +378,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
357
378
PatKind :: Wild | PatKind :: Err ( _) => expected,
358
379
// We allow any type here; we ensure that the type is uninhabited during match checking.
359
380
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
- ) ;
381
+ PatKind :: Expr ( PatExpr { kind : PatExprKind :: Path ( _) , hir_id, .. } ) => {
382
+ let ty = ( resolved_pat. unwrap ( ) . check ) ( expected, pat_info) ;
370
383
self . write_ty ( * hir_id, ty) ;
371
384
ty
372
385
}
@@ -1251,33 +1264,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1251
1264
path_id : HirId ,
1252
1265
pat_id_for_diag : HirId ,
1253
1266
span : Span ,
1254
- qpath : & hir:: QPath < ' _ > ,
1255
- path_resolution : ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) ,
1256
- expected : Ty < ' tcx > ,
1267
+ qpath : & ' tcx hir:: QPath < ' tcx > ,
1257
1268
ti : & TopInfo < ' tcx > ,
1258
- ) -> Ty < ' tcx > {
1269
+ ) -> ResolvedPat < impl Fn ( Ty < ' tcx > , PatInfo < ' tcx > ) -> Ty < ' tcx > > {
1259
1270
let tcx = self . tcx ;
1260
1271
1261
- // We have already resolved the path.
1262
- let ( res , opt_ty , segments ) = path_resolution ;
1263
- match res {
1272
+ let ( res , opt_ty , segments ) =
1273
+ self . resolve_ty_and_res_fully_qualified_call ( qpath , path_id , span ) ;
1274
+ let res_ok = match res {
1264
1275
Res :: Err => {
1265
1276
let e =
1266
1277
self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
1267
1278
self . set_tainted_by_errors ( e) ;
1268
- return Ty :: new_error ( tcx , e ) ;
1279
+ Err ( e )
1269
1280
}
1270
1281
Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
1271
1282
let expected = "unit struct, unit variant or constant" ;
1272
1283
let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1273
- return Ty :: new_error ( tcx , e ) ;
1284
+ Err ( e )
1274
1285
}
1275
1286
Res :: SelfCtor ( def_id) => {
1276
1287
if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
1277
1288
&& adt_def. is_struct ( )
1278
1289
&& let Some ( ( CtorKind :: Const , _) ) = adt_def. non_enum_variant ( ) . ctor
1279
1290
{
1280
- // Ok, we allow unit struct ctors in patterns only.
1291
+ Ok ( ( ) ) // Ok, we allow unit struct ctors in patterns only.
1281
1292
} else {
1282
1293
let e = report_unexpected_variant_res (
1283
1294
tcx,
@@ -1288,7 +1299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1288
1299
E0533 ,
1289
1300
"unit struct" ,
1290
1301
) ;
1291
- return Ty :: new_error ( tcx , e ) ;
1302
+ Err ( e )
1292
1303
}
1293
1304
}
1294
1305
Res :: Def (
@@ -1297,19 +1308,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1297
1308
| DefKind :: AssocConst
1298
1309
| DefKind :: ConstParam ,
1299
1310
_,
1300
- ) => { } // OK
1311
+ ) => Ok ( ( ) ) , // OK
1301
1312
_ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
1302
- }
1313
+ } ;
1303
1314
1304
1315
// Type-check the path.
1305
- let ( pat_ty, pat_res) =
1306
- self . instantiate_value_path ( segments, opt_ty, res, span, span, path_id) ;
1307
- if let Err ( err) =
1308
- self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, pat_ty)
1309
- {
1310
- self . emit_bad_pat_path ( err, pat_id_for_diag, span, res, pat_res, pat_ty, segments) ;
1311
- }
1312
- pat_ty
1316
+ let pat_ty_and_res =
1317
+ res_ok. map ( |_| self . instantiate_value_path ( segments, opt_ty, res, span, span, path_id) ) ;
1318
+
1319
+ let check = move |expected, _pat_info| -> Ty < ' tcx > {
1320
+ let ( pat_ty, pat_res) = match pat_ty_and_res {
1321
+ Ok ( pat_ty_and_res) => pat_ty_and_res,
1322
+ Err ( guar) => return Ty :: new_error ( tcx, guar) ,
1323
+ } ;
1324
+
1325
+ if let Err ( err) =
1326
+ self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, pat_ty)
1327
+ {
1328
+ self . emit_bad_pat_path ( err, pat_id_for_diag, span, res, pat_res, pat_ty, segments) ;
1329
+ }
1330
+ pat_ty
1331
+ } ;
1332
+ ResolvedPat { path_res : Some ( res) , check }
1313
1333
}
1314
1334
1315
1335
fn maybe_suggest_range_literal (
0 commit comments