@@ -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,24 @@ 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, 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+
261279impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
262280 /// Experimental pattern feature: after matching against a shared reference, do we limit the
263281 /// 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> {
336354 fn check_pat ( & self , pat : & ' tcx Pat < ' tcx > , expected : Ty < ' tcx > , pat_info : PatInfo < ' tcx > ) {
337355 let PatInfo { binding_mode, max_ref_mutbl, top_info : ti, current_depth, .. } = pat_info;
338356
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 ) ) ;
346367 let ( expected, binding_mode, max_ref_mutbl) =
347368 self . calc_default_binding_mode ( pat, expected, binding_mode, adjust_mode, max_ref_mutbl) ;
348369 let pat_info = PatInfo {
@@ -357,16 +378,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
357378 PatKind :: Wild | PatKind :: Err ( _) => expected,
358379 // We allow any type here; we ensure that the type is uninhabited during match checking.
359380 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) ;
370383 self . write_ty ( * hir_id, ty) ;
371384 ty
372385 }
@@ -1251,33 +1264,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12511264 path_id : HirId ,
12521265 pat_id_for_diag : HirId ,
12531266 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 > ,
12571268 ti : & TopInfo < ' tcx > ,
1258- ) -> Ty < ' tcx > {
1269+ ) -> ResolvedPat < impl Fn ( Ty < ' tcx > , PatInfo < ' tcx > ) -> Ty < ' tcx > > {
12591270 let tcx = self . tcx ;
12601271
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 {
12641275 Res :: Err => {
12651276 let e =
12661277 self . dcx ( ) . span_delayed_bug ( qpath. span ( ) , "`Res::Err` but no error emitted" ) ;
12671278 self . set_tainted_by_errors ( e) ;
1268- return Ty :: new_error ( tcx , e ) ;
1279+ Err ( e )
12691280 }
12701281 Res :: Def ( DefKind :: AssocFn | DefKind :: Ctor ( _, CtorKind :: Fn ) | DefKind :: Variant , _) => {
12711282 let expected = "unit struct, unit variant or constant" ;
12721283 let e = report_unexpected_variant_res ( tcx, res, None , qpath, span, E0533 , expected) ;
1273- return Ty :: new_error ( tcx , e ) ;
1284+ Err ( e )
12741285 }
12751286 Res :: SelfCtor ( def_id) => {
12761287 if let ty:: Adt ( adt_def, _) = * tcx. type_of ( def_id) . skip_binder ( ) . kind ( )
12771288 && adt_def. is_struct ( )
12781289 && let Some ( ( CtorKind :: Const , _) ) = adt_def. non_enum_variant ( ) . ctor
12791290 {
1280- // Ok, we allow unit struct ctors in patterns only.
1291+ Ok ( ( ) ) // Ok, we allow unit struct ctors in patterns only.
12811292 } else {
12821293 let e = report_unexpected_variant_res (
12831294 tcx,
@@ -1288,7 +1299,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12881299 E0533 ,
12891300 "unit struct" ,
12901301 ) ;
1291- return Ty :: new_error ( tcx , e ) ;
1302+ Err ( e )
12921303 }
12931304 }
12941305 Res :: Def (
@@ -1297,19 +1308,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12971308 | DefKind :: AssocConst
12981309 | DefKind :: ConstParam ,
12991310 _,
1300- ) => { } // OK
1311+ ) => Ok ( ( ) ) , // OK
13011312 _ => bug ! ( "unexpected pattern resolution: {:?}" , res) ,
1302- }
1313+ } ;
13031314
13041315 // 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 }
13131333 }
13141334
13151335 fn maybe_suggest_range_literal (
0 commit comments