Skip to content

Commit 762137e

Browse files
hir: introduce QPath::LangItem
This commit introduces `QPath::LangItem` to the HIR and uses it in AST lowering instead of constructing a `hir::Path` from a slice of symbols. This might be better for performance, but is also much cleaner as the previous approach is fragile. In addition, it resolves a bug (#61019) where an extern crate imported as "std" would result in the paths created during AST lowering being resolved incorrectly (or not at all). Co-authored-by: Matthew Jasper <[email protected]> Signed-off-by: David Wood <[email protected]>
1 parent 7dee5f8 commit 762137e

File tree

21 files changed

+289
-314
lines changed

21 files changed

+289
-314
lines changed

src/librustc_ast_lowering/expr.rs

+60-101
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
449449

450450
// `::std::ops::Try::from_ok($tail_expr)`
451451
block.expr = Some(this.wrap_in_try_constructor(
452-
sym::from_ok,
452+
hir::LangItem::TryFromOk,
453453
try_span,
454454
tail_expr,
455455
ok_wrapped_span,
@@ -461,14 +461,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
461461

462462
fn wrap_in_try_constructor(
463463
&mut self,
464-
method: Symbol,
464+
lang_item: hir::LangItem,
465465
method_span: Span,
466466
expr: &'hir hir::Expr<'hir>,
467467
overall_span: Span,
468468
) -> &'hir hir::Expr<'hir> {
469-
let path = &[sym::ops, sym::Try, method];
470469
let constructor =
471-
self.arena.alloc(self.expr_std_path(method_span, path, None, ThinVec::new()));
470+
self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new()));
472471
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
473472
}
474473

@@ -558,12 +557,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
558557
// `future::from_generator`:
559558
let unstable_span =
560559
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
561-
let gen_future = self.expr_std_path(
562-
unstable_span,
563-
&[sym::future, sym::from_generator],
564-
None,
565-
ThinVec::new(),
566-
);
560+
let gen_future =
561+
self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new());
567562

568563
// `future::from_generator(generator)`:
569564
hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
@@ -630,23 +625,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
630625
// Use of `await` outside of an async context, we cannot use `task_context` here.
631626
self.expr_err(span)
632627
};
633-
let pin_ty_id = self.next_id();
634-
let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
635-
pin_ty_id,
628+
let new_unchecked = self.expr_call_lang_item_fn_mut(
636629
span,
637-
&[sym::pin, sym::Pin],
638-
"new_unchecked",
630+
hir::LangItem::PinNewUnchecked,
639631
arena_vec![self; ref_mut_pinned],
640632
);
641-
let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new());
642-
let get_context = self.expr_call_std_path_mut(
633+
let get_context = self.expr_call_lang_item_fn_mut(
643634
gen_future_span,
644-
&[sym::future, sym::get_context],
635+
hir::LangItem::GetContext,
645636
arena_vec![self; task_context],
646637
);
647-
let call = self.expr_call_std_path(
638+
let call = self.expr_call_lang_item_fn(
648639
span,
649-
&[sym::future, sym::Future, sym::poll],
640+
hir::LangItem::FuturePoll,
650641
arena_vec![self; new_unchecked, get_context],
651642
);
652643
self.arena.alloc(self.expr_unsafe(call))
@@ -659,11 +650,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
659650
let x_ident = Ident::with_dummy_span(sym::result);
660651
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
661652
let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
662-
let ready_pat = self.pat_std_enum(
663-
span,
664-
&[sym::task, sym::Poll, sym::Ready],
665-
arena_vec![self; x_pat],
666-
);
653+
let ready_field = self.single_pat_field(span, x_pat);
654+
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
667655
let break_x = self.with_loop_scope(loop_node_id, move |this| {
668656
let expr_break =
669657
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
@@ -674,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
674662

675663
// `::std::task::Poll::Pending => {}`
676664
let pending_arm = {
677-
let pending_pat = self.pat_std_enum(span, &[sym::task, sym::Poll, sym::Pending], &[]);
665+
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
678666
let empty_block = self.expr_block_empty(span);
679667
self.arm(pending_pat, empty_block)
680668
};
@@ -842,16 +830,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
842830

843831
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
844832
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
845-
let id = self.next_id();
846833
let e1 = self.lower_expr_mut(e1);
847834
let e2 = self.lower_expr_mut(e2);
848-
self.expr_call_std_assoc_fn(
849-
id,
850-
span,
851-
&[sym::ops, sym::RangeInclusive],
852-
"new",
853-
arena_vec![self; e1, e2],
854-
)
835+
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
836+
let fn_expr =
837+
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
838+
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
855839
}
856840

857841
fn lower_expr_range(
@@ -863,12 +847,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
863847
) -> hir::ExprKind<'hir> {
864848
use rustc_ast::ast::RangeLimits::*;
865849

866-
let path = match (e1, e2, lims) {
867-
(None, None, HalfOpen) => sym::RangeFull,
868-
(Some(..), None, HalfOpen) => sym::RangeFrom,
869-
(None, Some(..), HalfOpen) => sym::RangeTo,
870-
(Some(..), Some(..), HalfOpen) => sym::Range,
871-
(None, Some(..), Closed) => sym::RangeToInclusive,
850+
let lang_item = match (e1, e2, lims) {
851+
(None, None, HalfOpen) => hir::LangItem::RangeFull,
852+
(Some(..), None, HalfOpen) => hir::LangItem::RangeFrom,
853+
(None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
854+
(Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
855+
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
872856
(Some(..), Some(..), Closed) => unreachable!(),
873857
(_, None, Closed) => {
874858
self.diagnostic().span_fatal(span, "inclusive range with no end").raise()
@@ -883,16 +867,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
883867
}),
884868
);
885869

886-
let is_unit = fields.is_empty();
887-
let struct_path = [sym::ops, path];
888-
let struct_path = self.std_path(span, &struct_path, None, is_unit);
889-
let struct_path = hir::QPath::Resolved(None, struct_path);
890-
891-
if is_unit {
892-
hir::ExprKind::Path(struct_path)
893-
} else {
894-
hir::ExprKind::Struct(self.arena.alloc(struct_path), fields, None)
895-
}
870+
hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None)
896871
}
897872

898873
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
@@ -1412,9 +1387,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
14121387
let match_expr = {
14131388
let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
14141389
let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
1415-
let next_path = &[sym::iter, sym::Iterator, sym::next];
1416-
let next_expr =
1417-
self.expr_call_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]);
1390+
let next_expr = self.expr_call_lang_item_fn(
1391+
desugared_span,
1392+
hir::LangItem::IteratorNext,
1393+
arena_vec![self; ref_mut_iter],
1394+
);
14181395
let arms = arena_vec![self; pat_arm, break_arm];
14191396

14201397
self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
@@ -1472,8 +1449,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
14721449

14731450
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
14741451
let into_iter_expr = {
1475-
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
1476-
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
1452+
self.expr_call_lang_item_fn(
1453+
into_iter_span,
1454+
hir::LangItem::IntoIterIntoIter,
1455+
arena_vec![self; head],
1456+
)
14771457
};
14781458

14791459
let match_expr = self.arena.alloc(self.expr_match(
@@ -1521,8 +1501,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
15211501
// expand <expr>
15221502
let sub_expr = self.lower_expr_mut(sub_expr);
15231503

1524-
let path = &[sym::ops, sym::Try, sym::into_result];
1525-
self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr])
1504+
self.expr_call_lang_item_fn(
1505+
unstable_span,
1506+
hir::LangItem::TryIntoResult,
1507+
arena_vec![self; sub_expr],
1508+
)
15261509
};
15271510

15281511
// `#[allow(unreachable_code)]`
@@ -1558,12 +1541,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
15581541
let err_ident = Ident::with_dummy_span(sym::err);
15591542
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
15601543
let from_expr = {
1561-
let from_path = &[sym::convert, sym::From, sym::from];
15621544
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
1563-
self.expr_call_std_path(try_span, from_path, arena_vec![self; err_expr])
1545+
self.expr_call_lang_item_fn(
1546+
try_span,
1547+
hir::LangItem::FromFrom,
1548+
arena_vec![self; err_expr],
1549+
)
15641550
};
1565-
let from_err_expr =
1566-
self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span);
1551+
let from_err_expr = self.wrap_in_try_constructor(
1552+
hir::LangItem::TryFromError,
1553+
unstable_span,
1554+
from_expr,
1555+
try_span,
1556+
);
15671557
let thin_attrs = ThinVec::from(attrs);
15681558
let catch_scope = self.catch_scopes.last().copied();
15691559
let ret_expr = if let Some(catch_node) = catch_scope {
@@ -1674,63 +1664,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
16741664
self.arena.alloc(self.expr_call_mut(span, e, args))
16751665
}
16761666

1677-
// Note: associated functions must use `expr_call_std_path`.
1678-
fn expr_call_std_path_mut(
1667+
fn expr_call_lang_item_fn_mut(
16791668
&mut self,
16801669
span: Span,
1681-
path_components: &[Symbol],
1670+
lang_item: hir::LangItem,
16821671
args: &'hir [hir::Expr<'hir>],
16831672
) -> hir::Expr<'hir> {
1684-
let path =
1685-
self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new()));
1673+
let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new()));
16861674
self.expr_call_mut(span, path, args)
16871675
}
16881676

1689-
fn expr_call_std_path(
1677+
fn expr_call_lang_item_fn(
16901678
&mut self,
16911679
span: Span,
1692-
path_components: &[Symbol],
1680+
lang_item: hir::LangItem,
16931681
args: &'hir [hir::Expr<'hir>],
16941682
) -> &'hir hir::Expr<'hir> {
1695-
self.arena.alloc(self.expr_call_std_path_mut(span, path_components, args))
1696-
}
1697-
1698-
// Create an expression calling an associated function of an std type.
1699-
//
1700-
// Associated functions cannot be resolved through the normal `std_path` function,
1701-
// as they are resolved differently and so cannot use `expr_call_std_path`.
1702-
//
1703-
// This function accepts the path component (`ty_path_components`) separately from
1704-
// the name of the associated function (`assoc_fn_name`) in order to facilitate
1705-
// separate resolution of the type and creation of a path referring to its associated
1706-
// function.
1707-
fn expr_call_std_assoc_fn(
1708-
&mut self,
1709-
ty_path_id: hir::HirId,
1710-
span: Span,
1711-
ty_path_components: &[Symbol],
1712-
assoc_fn_name: &str,
1713-
args: &'hir [hir::Expr<'hir>],
1714-
) -> hir::ExprKind<'hir> {
1715-
let ty_path = self.std_path(span, ty_path_components, None, false);
1716-
let ty =
1717-
self.arena.alloc(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path)));
1718-
let fn_seg = self.arena.alloc(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name)));
1719-
let fn_path = hir::QPath::TypeRelative(ty, fn_seg);
1720-
let fn_expr =
1721-
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
1722-
hir::ExprKind::Call(fn_expr, args)
1683+
self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
17231684
}
17241685

1725-
fn expr_std_path(
1686+
fn expr_lang_item_path(
17261687
&mut self,
17271688
span: Span,
1728-
components: &[Symbol],
1729-
params: Option<&'hir hir::GenericArgs<'hir>>,
1689+
lang_item: hir::LangItem,
17301690
attrs: AttrVec,
17311691
) -> hir::Expr<'hir> {
1732-
let path = self.std_path(span, components, params, true);
1733-
self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs)
1692+
self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs)
17341693
}
17351694

17361695
pub(super) fn expr_ident(

0 commit comments

Comments
 (0)