@@ -1309,11 +1309,6 @@ impl<'tcx> Constructor<'tcx> {
13091309
13101310 Pat { ty, span : DUMMY_SP , kind : Box :: new ( pat) }
13111311 }
1312-
1313- /// Like `apply`, but where all the subpatterns are wildcards `_`.
1314- fn apply_wildcards < ' a > ( & self , cx : & MatchCheckCtxt < ' a , ' tcx > , ty : Ty < ' tcx > ) -> Pat < ' tcx > {
1315- self . apply ( cx, ty, Fields :: wildcards ( cx, self , ty) )
1316- }
13171312}
13181313
13191314/// Some fields need to be explicitly hidden away in certain cases; see the comment above the
@@ -1649,35 +1644,15 @@ impl<'tcx> Usefulness<'tcx> {
16491644 }
16501645 }
16511646
1652- fn apply_wildcard ( self , ty : Ty < ' tcx > ) -> Self {
1653- match self {
1654- UsefulWithWitness ( witnesses) => {
1655- let wild = Pat :: wildcard_from_ty ( ty) ;
1656- UsefulWithWitness (
1657- witnesses
1658- . into_iter ( )
1659- . map ( |mut witness| {
1660- witness. 0 . push ( wild. clone ( ) ) ;
1661- witness
1662- } )
1663- . collect ( ) ,
1664- )
1665- }
1666- x => x,
1667- }
1668- }
1669-
1670- fn apply_missing_ctors (
1647+ fn apply_wildcard < ' p > (
16711648 self ,
1672- cx : & MatchCheckCtxt < ' _ , ' tcx > ,
1673- ty : Ty < ' tcx > ,
1674- missing_ctors : & MissingConstructors < ' tcx > ,
1649+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
1650+ pcx : PatCtxt < ' tcx > ,
1651+ missing_ctors : MissingConstructors < ' tcx > ,
16751652 ) -> Self {
16761653 match self {
16771654 UsefulWithWitness ( witnesses) => {
1678- let new_patterns: Vec < _ > =
1679- missing_ctors. iter ( ) . map ( |ctor| ctor. apply_wildcards ( cx, ty) ) . collect ( ) ;
1680- // Add the new patterns to each witness
1655+ let new_patterns = missing_ctors. report_patterns ( cx, pcx) ;
16811656 UsefulWithWitness (
16821657 witnesses
16831658 . into_iter ( )
@@ -2270,11 +2245,21 @@ impl<'tcx> std::cmp::PartialEq for IntRange<'tcx> {
22702245struct MissingConstructors < ' tcx > {
22712246 all_ctors : Vec < Constructor < ' tcx > > ,
22722247 used_ctors : Vec < Constructor < ' tcx > > ,
2248+ is_top_level : bool ,
22732249}
22742250
22752251impl < ' tcx > MissingConstructors < ' tcx > {
2276- fn new ( all_ctors : Vec < Constructor < ' tcx > > , used_ctors : Vec < Constructor < ' tcx > > ) -> Self {
2277- MissingConstructors { all_ctors, used_ctors }
2252+ fn new < ' p > (
2253+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
2254+ pcx : PatCtxt < ' tcx > ,
2255+ matrix : & Matrix < ' p , ' tcx > ,
2256+ is_top_level : bool ,
2257+ ) -> Self {
2258+ let used_ctors: Vec < Constructor < ' _ > > =
2259+ matrix. head_ctors ( cx) . cloned ( ) . filter ( |c| !c. is_wildcard ( ) ) . collect ( ) ;
2260+ let all_ctors = all_constructors ( cx, pcx) ;
2261+
2262+ MissingConstructors { all_ctors, used_ctors, is_top_level }
22782263 }
22792264
22802265 fn into_inner ( self ) -> ( Vec < Constructor < ' tcx > > , Vec < Constructor < ' tcx > > ) {
@@ -2284,16 +2269,64 @@ impl<'tcx> MissingConstructors<'tcx> {
22842269 fn is_empty ( & self ) -> bool {
22852270 self . iter ( ) . next ( ) . is_none ( )
22862271 }
2287- /// Whether this contains all the constructors for the given type or only a
2288- /// subset.
2289- fn all_ctors_are_missing ( & self ) -> bool {
2290- self . used_ctors . is_empty ( )
2291- }
22922272
22932273 /// Iterate over all_ctors \ used_ctors
22942274 fn iter < ' a > ( & ' a self ) -> impl Iterator < Item = Constructor < ' tcx > > + Captures < ' a > {
22952275 self . all_ctors . iter ( ) . flat_map ( move |req_ctor| req_ctor. subtract_ctors ( & self . used_ctors ) )
22962276 }
2277+
2278+ /// List the patterns corresponding to the missing constructors. In some cases, instead of
2279+ /// listing all constructors of a given type, we prefer to simply report a wildcard.
2280+ fn report_patterns < ' p > (
2281+ & self ,
2282+ cx : & MatchCheckCtxt < ' p , ' tcx > ,
2283+ pcx : PatCtxt < ' tcx > ,
2284+ ) -> SmallVec < [ Pat < ' tcx > ; 1 ] > {
2285+ // There are 2 ways we can report a witness here.
2286+ // Commonly, we can report all the "free"
2287+ // constructors as witnesses, e.g., if we have:
2288+ //
2289+ // ```
2290+ // enum Direction { N, S, E, W }
2291+ // let Direction::N = ...;
2292+ // ```
2293+ //
2294+ // we can report 3 witnesses: `S`, `E`, and `W`.
2295+ //
2296+ // However, there is a case where we don't want
2297+ // to do this and instead report a single `_` witness:
2298+ // if the user didn't actually specify a constructor
2299+ // in this arm, e.g., in
2300+ //
2301+ // ```
2302+ // let x: (Direction, Direction, bool) = ...;
2303+ // let (_, _, false) = x;
2304+ // ```
2305+ //
2306+ // we don't want to show all 16 possible witnesses
2307+ // `(<direction-1>, <direction-2>, true)` - we are
2308+ // satisfied with `(_, _, true)`. In this case,
2309+ // `used_ctors` is empty.
2310+ // The exception is: if we are at the top-level, for example in an empty match, we
2311+ // sometimes prefer reporting the list of constructors instead of just `_`.
2312+ let report_when_all_missing = self . is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
2313+ if self . used_ctors . is_empty ( ) && !report_when_all_missing {
2314+ // All constructors are unused. Report only a wildcard
2315+ // rather than each individual constructor.
2316+ smallvec ! [ Pat :: wildcard_from_ty( pcx. ty) ]
2317+ } else {
2318+ // Construct for each missing constructor a "wild" version of this
2319+ // constructor, that matches everything that can be built with
2320+ // it. For example, if `ctor` is a `Constructor::Variant` for
2321+ // `Option::Some`, we get the pattern `Some(_)`.
2322+ self . iter ( )
2323+ . map ( |missing_ctor| {
2324+ let fields = Fields :: wildcards ( cx, & missing_ctor, pcx. ty ) ;
2325+ missing_ctor. apply ( cx, pcx. ty , fields)
2326+ } )
2327+ . collect ( )
2328+ }
2329+ }
22972330}
22982331
22992332impl < ' tcx > fmt:: Debug for MissingConstructors < ' tcx > {
@@ -2434,14 +2467,6 @@ crate fn is_useful<'p, 'tcx>(
24342467 } else {
24352468 debug ! ( "is_useful - expanding wildcard" ) ;
24362469
2437- let used_ctors: Vec < Constructor < ' _ > > =
2438- matrix. head_ctors ( cx) . cloned ( ) . filter ( |c| !c. is_wildcard ( ) ) . collect ( ) ;
2439- debug ! ( "is_useful_used_ctors = {:#?}" , used_ctors) ;
2440- // `all_ctors` are all the constructors for the given type, which
2441- // should all be represented (or caught with the wild pattern `_`).
2442- let all_ctors = all_constructors ( cx, pcx) ;
2443- debug ! ( "is_useful_all_ctors = {:#?}" , all_ctors) ;
2444-
24452470 // `missing_ctors` is the set of constructors from the same type as the
24462471 // first column of `matrix` that are matched only by wildcard patterns
24472472 // from the first column.
@@ -2453,7 +2478,7 @@ crate fn is_useful<'p, 'tcx>(
24532478 // Missing constructors are those that are not matched by any non-wildcard patterns in the
24542479 // current column. We only fully construct them on-demand, because they're rarely used and
24552480 // can be big.
2456- let missing_ctors = MissingConstructors :: new ( all_ctors , used_ctors ) ;
2481+ let missing_ctors = MissingConstructors :: new ( cx , pcx , matrix , is_top_level ) ;
24572482
24582483 debug ! ( "is_useful_missing_ctors.empty()={:#?}" , missing_ctors. is_empty( ) , ) ;
24592484
@@ -2485,49 +2510,7 @@ crate fn is_useful<'p, 'tcx>(
24852510 let usefulness =
24862511 is_useful ( cx, & matrix, & v, witness_preference, hir_id, is_under_guard, false ) ;
24872512
2488- // In this case, there's at least one "free"
2489- // constructor that is only matched against by
2490- // wildcard patterns.
2491- //
2492- // There are 2 ways we can report a witness here.
2493- // Commonly, we can report all the "free"
2494- // constructors as witnesses, e.g., if we have:
2495- //
2496- // ```
2497- // enum Direction { N, S, E, W }
2498- // let Direction::N = ...;
2499- // ```
2500- //
2501- // we can report 3 witnesses: `S`, `E`, and `W`.
2502- //
2503- // However, there is a case where we don't want
2504- // to do this and instead report a single `_` witness:
2505- // if the user didn't actually specify a constructor
2506- // in this arm, e.g., in
2507- //
2508- // ```
2509- // let x: (Direction, Direction, bool) = ...;
2510- // let (_, _, false) = x;
2511- // ```
2512- //
2513- // we don't want to show all 16 possible witnesses
2514- // `(<direction-1>, <direction-2>, true)` - we are
2515- // satisfied with `(_, _, true)`. In this case,
2516- // `used_ctors` is empty.
2517- // The exception is: if we are at the top-level, for example in an empty match, we
2518- // sometimes prefer reporting the list of constructors instead of just `_`.
2519- let report_ctors_rather_than_wildcard = is_top_level && !IntRange :: is_integral ( pcx. ty ) ;
2520- if missing_ctors. all_ctors_are_missing ( ) && !report_ctors_rather_than_wildcard {
2521- // All constructors are unused. Add a wild pattern
2522- // rather than each individual constructor.
2523- usefulness. apply_wildcard ( pcx. ty )
2524- } else {
2525- // Construct for each missing constructor a "wild" version of this
2526- // constructor, that matches everything that can be built with
2527- // it. For example, if `ctor` is a `Constructor::Variant` for
2528- // `Option::Some`, we get the pattern `Some(_)`.
2529- usefulness. apply_missing_ctors ( cx, pcx. ty , & missing_ctors)
2530- }
2513+ usefulness. apply_wildcard ( cx, pcx, missing_ctors)
25312514 }
25322515 } ;
25332516 debug ! ( "is_useful::returns({:#?}, {:#?}) = {:?}" , matrix, v, ret) ;
0 commit comments