@@ -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
}
@@ -1246,33 +1259,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1246
1259
path_id : HirId ,
1247
1260
pat_id_for_diag : HirId ,
1248
1261
span : Span ,
1249
- qpath : & hir:: QPath < ' _ > ,
1250
- path_resolution : ( Res , Option < LoweredTy < ' tcx > > , & ' tcx [ hir:: PathSegment < ' tcx > ] ) ,
1251
- expected : Ty < ' tcx > ,
1262
+ qpath : & ' tcx hir:: QPath < ' tcx > ,
1252
1263
ti : & TopInfo < ' tcx > ,
1253
- ) -> Ty < ' tcx > {
1264
+ ) -> ResolvedPat < impl Fn ( Ty < ' tcx > , PatInfo < ' tcx > ) -> Ty < ' tcx > > {
1254
1265
let tcx = self . tcx ;
1255
1266
1256
- // We have already resolved the path.
1257
- let ( res , opt_ty , segments ) = path_resolution ;
1258
- match res {
1267
+ let ( res , opt_ty , segments ) =
1268
+ self . resolve_ty_and_res_fully_qualified_call ( qpath , path_id , span ) ;
1269
+ let res_ok = match res {
1259
1270
Res :: Err => {
1260
1271
let e =
1261
1272
self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
1262
1273
self . set_tainted_by_errors ( e) ;
1263
- return Ty :: new_error ( tcx , e ) ;
1274
+ Err ( e )
1264
1275
}
1265
1276
Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
1266
1277
let expected = "unit struct, unit variant or constant" ;
1267
1278
let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1268
- return Ty :: new_error ( tcx , e ) ;
1279
+ Err ( e )
1269
1280
}
1270
1281
Res :: SelfCtor ( def_id) => {
1271
1282
if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
1272
1283
&& adt_def. is_struct ( )
1273
1284
&& let Some ( ( CtorKind :: Const , _) ) = adt_def. non_enum_variant ( ) . ctor
1274
1285
{
1275
- // Ok, we allow unit struct ctors in patterns only.
1286
+ Ok ( ( ) ) // Ok, we allow unit struct ctors in patterns only.
1276
1287
} else {
1277
1288
let e = report_unexpected_variant_res (
1278
1289
tcx,
@@ -1283,7 +1294,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1283
1294
E0533 ,
1284
1295
"unit struct" ,
1285
1296
) ;
1286
- return Ty :: new_error ( tcx , e ) ;
1297
+ Err ( e )
1287
1298
}
1288
1299
}
1289
1300
Res :: Def (
@@ -1292,19 +1303,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
1292
1303
| DefKind :: AssocConst
1293
1304
| DefKind :: ConstParam ,
1294
1305
_,
1295
- ) => { } // OK
1306
+ ) => Ok ( ( ) ) , // OK
1296
1307
_ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
1297
- }
1308
+ } ;
1298
1309
1299
1310
// Type-check the path.
1300
- let ( pat_ty, pat_res) =
1301
- self . instantiate_value_path ( segments, opt_ty, res, span, span, path_id) ;
1302
- if let Err ( err) =
1303
- self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, pat_ty)
1304
- {
1305
- self . emit_bad_pat_path ( err, pat_id_for_diag, span, res, pat_res, pat_ty, segments) ;
1306
- }
1307
- pat_ty
1311
+ let pat_ty_and_res =
1312
+ res_ok. map ( |_| self . instantiate_value_path ( segments, opt_ty, res, span, span, path_id) ) ;
1313
+
1314
+ let check = move |expected, _pat_info| -> Ty < ' tcx > {
1315
+ let ( pat_ty, pat_res) = match pat_ty_and_res {
1316
+ Ok ( pat_ty_and_res) => pat_ty_and_res,
1317
+ Err ( guar) => return Ty :: new_error ( tcx, guar) ,
1318
+ } ;
1319
+
1320
+ if let Err ( err) =
1321
+ self . demand_suptype_with_origin ( & self . pattern_cause ( ti, span) , expected, pat_ty)
1322
+ {
1323
+ self . emit_bad_pat_path ( err, pat_id_for_diag, span, res, pat_res, pat_ty, segments) ;
1324
+ }
1325
+ pat_ty
1326
+ } ;
1327
+ ResolvedPat { path_res : Some ( res) , check }
1308
1328
}
1309
1329
1310
1330
fn maybe_suggest_range_literal (
0 commit comments