@@ -24,6 +24,7 @@ use rustc_data_structures::fx::FxHashMap;
24
24
use rustc_data_structures:: sync;
25
25
use rustc_errors:: { struct_span_err, Applicability } ;
26
26
use rustc_hir as hir;
27
+ use rustc_hir:: def:: Res ;
27
28
use rustc_hir:: def_id:: { CrateNum , DefId } ;
28
29
use rustc_hir:: definitions:: { DefPathData , DisambiguatedDefPathData } ;
29
30
use rustc_middle:: lint:: LintDiagnosticBuilder ;
@@ -427,15 +428,12 @@ pub struct LateContext<'a, 'tcx> {
427
428
/// Current body, or `None` if outside a body.
428
429
pub enclosing_body : Option < hir:: BodyId > ,
429
430
430
- /// Type-checking side-tables for the current body. Access using the
431
- /// `tables` method , which handles querying the tables on demand.
431
+ /// Type-checking side-tables for the current body. Access using the `tables`
432
+ /// and `maybe_tables` methods , which handle querying the tables on demand.
432
433
// FIXME(eddyb) move all the code accessing internal fields like this,
433
434
// to this module, to avoid exposing it to lint logic.
434
435
pub ( super ) cached_typeck_tables : Cell < Option < & ' tcx ty:: TypeckTables < ' tcx > > > ,
435
436
436
- // HACK(eddyb) replace this with having `Option` around `&TypeckTables`.
437
- pub ( super ) empty_typeck_tables : & ' a ty:: TypeckTables < ' tcx > ,
438
-
439
437
/// Parameter environment for the item we are in.
440
438
pub param_env : ty:: ParamEnv < ' tcx > ,
441
439
@@ -677,18 +675,35 @@ impl LintContext for EarlyContext<'_> {
677
675
678
676
impl < ' a , ' tcx > LateContext < ' a , ' tcx > {
679
677
/// Gets the type-checking side-tables for the current body,
680
- /// or empty `TypeckTables` if outside a body.
681
- // FIXME(eddyb) return `Option<&'tcx ty::TypeckTables<'tcx>>`,
682
- // where `None` indicates we're outside a body.
683
- pub fn tables ( & self ) -> & ' a ty:: TypeckTables < ' tcx > {
684
- if let Some ( body) = self . enclosing_body {
685
- self . cached_typeck_tables . get ( ) . unwrap_or_else ( || {
678
+ /// or `None` if outside a body.
679
+ pub fn maybe_typeck_tables ( & self ) -> Option < & ' tcx ty:: TypeckTables < ' tcx > > {
680
+ self . cached_typeck_tables . get ( ) . or_else ( || {
681
+ self . enclosing_body . map ( |body| {
686
682
let tables = self . tcx . body_tables ( body) ;
687
683
self . cached_typeck_tables . set ( Some ( tables) ) ;
688
684
tables
689
685
} )
690
- } else {
691
- self . empty_typeck_tables
686
+ } )
687
+ }
688
+
689
+ /// Gets the type-checking side-tables for the current body.
690
+ /// As this will ICE if called outside bodies, only call when working with
691
+ /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
692
+ #[ track_caller]
693
+ pub fn tables ( & self ) -> & ' tcx ty:: TypeckTables < ' tcx > {
694
+ self . maybe_typeck_tables ( ) . expect ( "`LateContext::tables` called outside of body" )
695
+ }
696
+
697
+ /// Returns the final resolution of a `QPath`, or `Res::Err` if unavailable.
698
+ /// Unlike `.tables().qpath_res(qpath, id)`, this can be used even outside
699
+ /// bodies (e.g. for paths in `hir::Ty`), without any risk of ICE-ing.
700
+ pub fn qpath_res ( & self , qpath : & hir:: QPath < ' _ > , id : hir:: HirId ) -> Res {
701
+ match * qpath {
702
+ hir:: QPath :: Resolved ( _, ref path) => path. res ,
703
+ hir:: QPath :: TypeRelative ( ..) => self
704
+ . maybe_typeck_tables ( )
705
+ . and_then ( |tables| tables. type_dependent_def ( id) )
706
+ . map_or ( Res :: Err , |( kind, def_id) | Res :: Def ( kind, def_id) ) ,
692
707
}
693
708
}
694
709
0 commit comments