@@ -24,6 +24,7 @@ use rustc_data_structures::fx::FxHashMap;
2424use rustc_data_structures:: sync;
2525use rustc_errors:: { struct_span_err, Applicability } ;
2626use rustc_hir as hir;
27+ use rustc_hir:: def:: Res ;
2728use rustc_hir:: def_id:: { CrateNum , DefId } ;
2829use rustc_hir:: definitions:: { DefPathData , DisambiguatedDefPathData } ;
2930use rustc_middle:: lint:: LintDiagnosticBuilder ;
@@ -427,15 +428,12 @@ pub struct LateContext<'a, 'tcx> {
427428 /// Current body, or `None` if outside a body.
428429 pub enclosing_body : Option < hir:: BodyId > ,
429430
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.
432433 // FIXME(eddyb) move all the code accessing internal fields like this,
433434 // to this module, to avoid exposing it to lint logic.
434435 pub ( super ) cached_typeck_tables : Cell < Option < & ' tcx ty:: TypeckTables < ' tcx > > > ,
435436
436- // HACK(eddyb) replace this with having `Option` around `&TypeckTables`.
437- pub ( super ) empty_typeck_tables : & ' a ty:: TypeckTables < ' tcx > ,
438-
439437 /// Parameter environment for the item we are in.
440438 pub param_env : ty:: ParamEnv < ' tcx > ,
441439
@@ -677,18 +675,35 @@ impl LintContext for EarlyContext<'_> {
677675
678676impl < ' a , ' tcx > LateContext < ' a , ' tcx > {
679677 /// 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| {
686682 let tables = self . tcx . body_tables ( body) ;
687683 self . cached_typeck_tables . set ( Some ( tables) ) ;
688684 tables
689685 } )
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) ) ,
692707 }
693708 }
694709
0 commit comments