Skip to content

Commit f279482

Browse files
committed
refactor path pattern checking to get more info for peeling
See the doc comment on `ResolvedPat` for more information. This is to get the pattern's type's ADT def for (tuple) struct patterns, in order to know when to stop adding implicit deref patterns. Since we don't know the type we're matching against until we've peeled the scrutinee, `ResolvedPat` provides a way to finish checking the pattern once that type is known. The refactor's unfortunate, but this was the least disruptive way I could think of doing it. All the state that needs to be kept between resolution and type-checking is captured in a closure so it doesn't need to be manually passed around in `check_pat`. This first part only handles path patterns. Their resolutions were already needed early for adjust mode calculation, so I think it makes sense to handle that with `ResolvedPat` too.
1 parent 4c3e8fd commit f279482

File tree

1 file changed

+59
-39
lines changed
  • compiler/rustc_hir_typeck/src

1 file changed

+59
-39
lines changed

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use ty::VariantDef;
3333
use super::report_unexpected_variant_res;
3434
use crate::expectation::Expectation;
3535
use crate::gather_locals::DeclOrigin;
36-
use crate::{FnCtxt, LoweredTy, errors};
36+
use crate::{FnCtxt, errors};
3737

3838
const 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+
261279
impl<'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

Comments
 (0)