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 <mjjasper1@gmail.com>
Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2020-08-04 14:34:24 +01:00
parent 7dee5f824d
commit 762137e212
No known key found for this signature in database
GPG Key ID: 2592E76C87381FD9
21 changed files with 289 additions and 314 deletions

View File

@ -449,7 +449,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `::std::ops::Try::from_ok($tail_expr)`
block.expr = Some(this.wrap_in_try_constructor(
sym::from_ok,
hir::LangItem::TryFromOk,
try_span,
tail_expr,
ok_wrapped_span,
@ -461,14 +461,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
fn wrap_in_try_constructor(
&mut self,
method: Symbol,
lang_item: hir::LangItem,
method_span: Span,
expr: &'hir hir::Expr<'hir>,
overall_span: Span,
) -> &'hir hir::Expr<'hir> {
let path = &[sym::ops, sym::Try, method];
let constructor =
self.arena.alloc(self.expr_std_path(method_span, path, None, ThinVec::new()));
self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, ThinVec::new()));
self.expr_call(overall_span, constructor, std::slice::from_ref(expr))
}
@ -558,12 +557,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `future::from_generator`:
let unstable_span =
self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone());
let gen_future = self.expr_std_path(
unstable_span,
&[sym::future, sym::from_generator],
None,
ThinVec::new(),
);
let gen_future =
self.expr_lang_item_path(unstable_span, hir::LangItem::FromGenerator, ThinVec::new());
// `future::from_generator(generator)`:
hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator])
@ -630,23 +625,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Use of `await` outside of an async context, we cannot use `task_context` here.
self.expr_err(span)
};
let pin_ty_id = self.next_id();
let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
pin_ty_id,
let new_unchecked = self.expr_call_lang_item_fn_mut(
span,
&[sym::pin, sym::Pin],
"new_unchecked",
hir::LangItem::PinNewUnchecked,
arena_vec![self; ref_mut_pinned],
);
let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new());
let get_context = self.expr_call_std_path_mut(
let get_context = self.expr_call_lang_item_fn_mut(
gen_future_span,
&[sym::future, sym::get_context],
hir::LangItem::GetContext,
arena_vec![self; task_context],
);
let call = self.expr_call_std_path(
let call = self.expr_call_lang_item_fn(
span,
&[sym::future, sym::Future, sym::poll],
hir::LangItem::FuturePoll,
arena_vec![self; new_unchecked, get_context],
);
self.arena.alloc(self.expr_unsafe(call))
@ -659,11 +650,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let x_ident = Ident::with_dummy_span(sym::result);
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
let ready_pat = self.pat_std_enum(
span,
&[sym::task, sym::Poll, sym::Ready],
arena_vec![self; x_pat],
);
let ready_field = self.single_pat_field(span, x_pat);
let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
let break_x = self.with_loop_scope(loop_node_id, move |this| {
let expr_break =
hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
@ -674,7 +662,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `::std::task::Poll::Pending => {}`
let pending_arm = {
let pending_pat = self.pat_std_enum(span, &[sym::task, sym::Poll, sym::Pending], &[]);
let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]);
let empty_block = self.expr_block_empty(span);
self.arm(pending_pat, empty_block)
};
@ -842,16 +830,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
let id = self.next_id();
let e1 = self.lower_expr_mut(e1);
let e2 = self.lower_expr_mut(e2);
self.expr_call_std_assoc_fn(
id,
span,
&[sym::ops, sym::RangeInclusive],
"new",
arena_vec![self; e1, e2],
)
let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
let fn_expr =
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
}
fn lower_expr_range(
@ -863,12 +847,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> hir::ExprKind<'hir> {
use rustc_ast::ast::RangeLimits::*;
let path = match (e1, e2, lims) {
(None, None, HalfOpen) => sym::RangeFull,
(Some(..), None, HalfOpen) => sym::RangeFrom,
(None, Some(..), HalfOpen) => sym::RangeTo,
(Some(..), Some(..), HalfOpen) => sym::Range,
(None, Some(..), Closed) => sym::RangeToInclusive,
let lang_item = match (e1, e2, lims) {
(None, None, HalfOpen) => hir::LangItem::RangeFull,
(Some(..), None, HalfOpen) => hir::LangItem::RangeFrom,
(None, Some(..), HalfOpen) => hir::LangItem::RangeTo,
(Some(..), Some(..), HalfOpen) => hir::LangItem::Range,
(None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
(Some(..), Some(..), Closed) => unreachable!(),
(_, None, Closed) => {
self.diagnostic().span_fatal(span, "inclusive range with no end").raise()
@ -883,16 +867,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
);
let is_unit = fields.is_empty();
let struct_path = [sym::ops, path];
let struct_path = self.std_path(span, &struct_path, None, is_unit);
let struct_path = hir::QPath::Resolved(None, struct_path);
if is_unit {
hir::ExprKind::Path(struct_path)
} else {
hir::ExprKind::Struct(self.arena.alloc(struct_path), fields, None)
}
hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None)
}
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
@ -1412,9 +1387,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let match_expr = {
let iter = self.expr_ident(desugared_span, iter, iter_pat_nid);
let ref_mut_iter = self.expr_mut_addr_of(desugared_span, iter);
let next_path = &[sym::iter, sym::Iterator, sym::next];
let next_expr =
self.expr_call_std_path(desugared_span, next_path, arena_vec![self; ref_mut_iter]);
let next_expr = self.expr_call_lang_item_fn(
desugared_span,
hir::LangItem::IteratorNext,
arena_vec![self; ref_mut_iter],
);
let arms = arena_vec![self; pat_arm, break_arm];
self.expr_match(desugared_span, next_expr, arms, hir::MatchSource::ForLoopDesugar)
@ -1472,8 +1449,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
let into_iter_path = &[sym::iter, sym::IntoIterator, sym::into_iter];
self.expr_call_std_path(into_iter_span, into_iter_path, arena_vec![self; head])
self.expr_call_lang_item_fn(
into_iter_span,
hir::LangItem::IntoIterIntoIter,
arena_vec![self; head],
)
};
let match_expr = self.arena.alloc(self.expr_match(
@ -1521,8 +1501,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
// expand <expr>
let sub_expr = self.lower_expr_mut(sub_expr);
let path = &[sym::ops, sym::Try, sym::into_result];
self.expr_call_std_path(unstable_span, path, arena_vec![self; sub_expr])
self.expr_call_lang_item_fn(
unstable_span,
hir::LangItem::TryIntoResult,
arena_vec![self; sub_expr],
)
};
// `#[allow(unreachable_code)]`
@ -1558,12 +1541,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
let err_ident = Ident::with_dummy_span(sym::err);
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
let from_expr = {
let from_path = &[sym::convert, sym::From, sym::from];
let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
self.expr_call_std_path(try_span, from_path, arena_vec![self; err_expr])
self.expr_call_lang_item_fn(
try_span,
hir::LangItem::FromFrom,
arena_vec![self; err_expr],
)
};
let from_err_expr =
self.wrap_in_try_constructor(sym::from_error, unstable_span, from_expr, try_span);
let from_err_expr = self.wrap_in_try_constructor(
hir::LangItem::TryFromError,
unstable_span,
from_expr,
try_span,
);
let thin_attrs = ThinVec::from(attrs);
let catch_scope = self.catch_scopes.last().copied();
let ret_expr = if let Some(catch_node) = catch_scope {
@ -1674,63 +1664,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.arena.alloc(self.expr_call_mut(span, e, args))
}
// Note: associated functions must use `expr_call_std_path`.
fn expr_call_std_path_mut(
fn expr_call_lang_item_fn_mut(
&mut self,
span: Span,
path_components: &[Symbol],
lang_item: hir::LangItem,
args: &'hir [hir::Expr<'hir>],
) -> hir::Expr<'hir> {
let path =
self.arena.alloc(self.expr_std_path(span, path_components, None, ThinVec::new()));
let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, ThinVec::new()));
self.expr_call_mut(span, path, args)
}
fn expr_call_std_path(
fn expr_call_lang_item_fn(
&mut self,
span: Span,
path_components: &[Symbol],
lang_item: hir::LangItem,
args: &'hir [hir::Expr<'hir>],
) -> &'hir hir::Expr<'hir> {
self.arena.alloc(self.expr_call_std_path_mut(span, path_components, args))
self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args))
}
// Create an expression calling an associated function of an std type.
//
// Associated functions cannot be resolved through the normal `std_path` function,
// as they are resolved differently and so cannot use `expr_call_std_path`.
//
// This function accepts the path component (`ty_path_components`) separately from
// the name of the associated function (`assoc_fn_name`) in order to facilitate
// separate resolution of the type and creation of a path referring to its associated
// function.
fn expr_call_std_assoc_fn(
&mut self,
ty_path_id: hir::HirId,
span: Span,
ty_path_components: &[Symbol],
assoc_fn_name: &str,
args: &'hir [hir::Expr<'hir>],
) -> hir::ExprKind<'hir> {
let ty_path = self.std_path(span, ty_path_components, None, false);
let ty =
self.arena.alloc(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path)));
let fn_seg = self.arena.alloc(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name)));
let fn_path = hir::QPath::TypeRelative(ty, fn_seg);
let fn_expr =
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
hir::ExprKind::Call(fn_expr, args)
}
fn expr_std_path(
fn expr_lang_item_path(
&mut self,
span: Span,
components: &[Symbol],
params: Option<&'hir hir::GenericArgs<'hir>>,
lang_item: hir::LangItem,
attrs: AttrVec,
) -> hir::Expr<'hir> {
let path = self.std_path(span, components, params, true);
self.expr(span, hir::ExprKind::Path(hir::QPath::Resolved(None, path)), attrs)
self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs)
}
pub(super) fn expr_ident(

View File

@ -85,8 +85,6 @@ const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx);
struct LoweringContext<'a, 'hir: 'a> {
crate_root: Option<Symbol>,
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
sess: &'a Session,
@ -189,16 +187,6 @@ pub trait ResolverAstLowering {
/// This should only return `None` during testing.
fn definitions(&mut self) -> &mut Definitions;
/// Given suffix `["b", "c", "d"]`, creates an AST path for `[::crate_root]::b::c::d` and
/// resolves it based on `is_value`.
fn resolve_str_path(
&mut self,
span: Span,
crate_root: Option<Symbol>,
components: &[Symbol],
ns: Namespace,
) -> (ast::Path, Res<NodeId>);
fn lint_buffer(&mut self) -> &mut LintBuffer;
fn next_node_id(&mut self) -> NodeId;
@ -305,7 +293,6 @@ pub fn lower_crate<'a, 'hir>(
let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
LoweringContext {
crate_root: sess.parse_sess.injected_crate_name.get().copied(),
sess,
resolver,
nt_to_tokenstream,
@ -2064,23 +2051,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
// "<Output = T>"
let future_params = self.arena.alloc(hir::GenericArgs {
let future_args = self.arena.alloc(hir::GenericArgs {
args: &[],
bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
parenthesized: false,
});
// ::std::future::Future<future_params>
let future_path =
self.std_path(span, &[sym::future, sym::Future], Some(future_params), false);
hir::GenericBound::Trait(
hir::PolyTraitRef {
trait_ref: hir::TraitRef { path: future_path, hir_ref_id: self.next_id() },
bound_generic_params: &[],
span,
},
hir::TraitBoundModifier::None,
hir::GenericBound::LangItemTrait(
// ::std::future::Future<future_params>
hir::LangItem::FutureTraitLangItem,
span,
self.next_id(),
future_args,
)
}
@ -2480,35 +2462,47 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], arena_vec![self; pat])
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
}
fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], arena_vec![self; pat])
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
}
fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], arena_vec![self; pat])
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field)
}
fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], &[])
self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[])
}
fn pat_std_enum(
fn single_pat_field(
&mut self,
span: Span,
components: &[Symbol],
subpats: &'hir [&'hir hir::Pat<'hir>],
) -> &'hir hir::Pat<'hir> {
let path = self.std_path(span, components, None, true);
let qpath = hir::QPath::Resolved(None, path);
let pt = if subpats.is_empty() {
hir::PatKind::Path(qpath)
} else {
hir::PatKind::TupleStruct(qpath, subpats, None)
pat: &'hir hir::Pat<'hir>,
) -> &'hir [hir::FieldPat<'hir>] {
let field = hir::FieldPat {
hir_id: self.next_id(),
ident: Ident::new(sym::integer(0), span),
is_shorthand: false,
pat,
span,
};
self.pat(span, pt)
arena_vec![self; field]
}
fn pat_lang_item_variant(
&mut self,
span: Span,
lang_item: hir::LangItem,
fields: &'hir [hir::FieldPat<'hir>],
) -> &'hir hir::Pat<'hir> {
let qpath = hir::QPath::LangItem(lang_item, span);
self.pat(span, hir::PatKind::Struct(qpath, fields, false))
}
fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) {
@ -2541,42 +2535,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
}
/// Given a suffix `["b", "c", "d"]`, returns path `::std::b::c::d` when
/// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
/// The path is also resolved according to `is_value`.
fn std_path(
&mut self,
span: Span,
components: &[Symbol],
params: Option<&'hir hir::GenericArgs<'hir>>,
is_value: bool,
) -> &'hir hir::Path<'hir> {
let ns = if is_value { Namespace::ValueNS } else { Namespace::TypeNS };
let (path, res) = self.resolver.resolve_str_path(span, self.crate_root, components, ns);
let mut segments: Vec<_> = path
.segments
.iter()
.map(|segment| {
let res = self.expect_full_res(segment.id);
hir::PathSegment {
ident: segment.ident,
hir_id: Some(self.lower_node_id(segment.id)),
res: Some(self.lower_res(res)),
infer_args: true,
args: None,
}
})
.collect();
segments.last_mut().unwrap().args = params;
self.arena.alloc(hir::Path {
span,
res: res.map_id(|_| panic!("unexpected `NodeId`")),
segments: self.arena.alloc_from_iter(segments),
})
}
fn ty_path(
&mut self,
mut hir_id: hir::HirId,

View File

@ -1,7 +1,7 @@
use crate::def::{DefKind, Namespace, Res};
use crate::def_id::DefId;
crate use crate::hir_id::HirId;
use crate::itemlikevisit;
use crate::{itemlikevisit, LangItem};
use rustc_ast::ast::{self, CrateSugar, LlvmAsmDialect};
use rustc_ast::ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
@ -363,6 +363,8 @@ pub enum TraitBoundModifier {
#[derive(Debug, HashStable_Generic)]
pub enum GenericBound<'hir> {
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
// FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
Outlives(Lifetime),
}
@ -377,6 +379,7 @@ impl GenericBound<'_> {
pub fn span(&self) -> Span {
match self {
&GenericBound::Trait(ref t, ..) => t.span,
&GenericBound::LangItemTrait(_, span, ..) => span,
&GenericBound::Outlives(ref l) => l.span,
}
}
@ -1419,10 +1422,10 @@ impl Expr<'_> {
self.is_place_expr(|_| true)
}
// Whether this is a place expression.
// `allow_projections_from` should return `true` if indexing a field or
// index expression based on the given expression should be considered a
// place expression.
/// Whether this is a place expression.
///
/// `allow_projections_from` should return `true` if indexing a field or index expression based
/// on the given expression should be considered a place expression.
pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
match self.kind {
ExprKind::Path(QPath::Resolved(_, ref path)) => match path.res {
@ -1441,6 +1444,9 @@ impl Expr<'_> {
allow_projections_from(base) || base.is_place_expr(allow_projections_from)
}
// Lang item paths cannot currently be local variables or statics.
ExprKind::Path(QPath::LangItem(..)) => false,
// Partially qualified paths in expressions can only legally
// refer to associated items which are always rvalues.
ExprKind::Path(QPath::TypeRelative(..))
@ -1677,6 +1683,40 @@ pub enum QPath<'hir> {
/// `<Vec>::new`, and `T::X::Y::method` into `<<<T>::X>::Y>::method`,
/// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`.
TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>),
/// Reference to a `#[lang = "foo"]` item.
LangItem(LangItem, Span),
}
impl<'hir> QPath<'hir> {
/// Returns the span of this `QPath`.
pub fn span(&self) -> Span {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(_, ps) => ps.ident.span,
QPath::LangItem(_, span) => span,
}
}
/// Returns the span of the qself of this `QPath`. For example, `()` in
/// `<() as Trait>::method`.
pub fn qself_span(&self) -> Span {
match *self {
QPath::Resolved(_, path) => path.span,
QPath::TypeRelative(qself, _) => qself.span,
QPath::LangItem(_, span) => span,
}
}
/// Returns the span of the last segment of this `QPath`. For example, `method` in
/// `<() as Trait>::method`.
pub fn last_segment_span(&self) -> Span {
match *self {
QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
QPath::TypeRelative(_, segment) => segment.ident.span,
QPath::LangItem(_, span) => span,
}
}
}
/// Hints at the original code for a let statement.

View File

@ -724,6 +724,7 @@ pub fn walk_qpath<'v, V: Visitor<'v>>(
visitor.visit_ty(qself);
visitor.visit_path_segment(span, segment);
}
QPath::LangItem(..) => {}
}
}
@ -838,6 +839,10 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
GenericBound::Trait(ref typ, modifier) => {
visitor.visit_poly_trait_ref(typ, modifier);
}
GenericBound::LangItemTrait(_, span, hir_id, args) => {
visitor.visit_id(hir_id);
visitor.visit_generic_args(span, args);
}
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
}
}

View File

@ -1729,6 +1729,11 @@ impl<'a> State<'a> {
colons_before_params,
)
}
hir::QPath::LangItem(lang_item, span) => {
self.s.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), span));
self.s.word("\"]");
}
}
}
@ -2142,6 +2147,11 @@ impl<'a> State<'a> {
}
self.print_poly_trait_ref(tref);
}
GenericBound::LangItemTrait(lang_item, span, ..) => {
self.s.word("#[lang = \"");
self.print_ident(Ident::new(lang_item.name(), *span));
self.s.word("\"]");
}
GenericBound::Outlives(lt) => {
self.print_lifetime(lt);
}

View File

@ -1057,7 +1057,7 @@ impl TypeAliasBounds {
_ => false,
}
}
hir::QPath::Resolved(..) => false,
hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false,
}
}

View File

@ -703,7 +703,7 @@ impl<'tcx> LateContext<'tcx> {
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
match *qpath {
hir::QPath::Resolved(_, ref path) => path.res,
hir::QPath::TypeRelative(..) => self
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
.maybe_typeck_results()
.and_then(|typeck_results| typeck_results.type_dependent_def(id))
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),

View File

@ -445,7 +445,7 @@ impl<'tcx> TypeckResults<'tcx> {
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
match *qpath {
hir::QPath::Resolved(_, ref path) => path.res,
hir::QPath::TypeRelative(..) => self
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
.type_dependent_def(id)
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
}

View File

@ -526,7 +526,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) {
| hir::ExprKind::Yield(..)
| hir::ExprKind::Type(..)
| hir::ExprKind::Err
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => {
intravisit::walk_expr(ir, expr);
}
}
@ -1310,7 +1311,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::Lit(..)
| hir::ExprKind::Err
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => succ,
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
// Note that labels have been resolved, so we don't need to look
// at the label ident

View File

@ -1325,7 +1325,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
Res::Def(kind, def_id) => Some((kind, def_id)),
_ => None,
},
hir::QPath::TypeRelative(..) => self
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
.maybe_typeck_results
.and_then(|typeck_results| typeck_results.type_dependent_def(id)),
};
@ -1340,7 +1340,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
let sess = self.tcx.sess;
let sm = sess.source_map();
let name = match qpath {
hir::QPath::Resolved(_, path) => sm.span_to_snippet(path.span).ok(),
hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => {
sm.span_to_snippet(qpath.span()).ok()
}
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};
let kind = kind.descr(def_id);

View File

@ -1076,37 +1076,6 @@ impl ResolverAstLowering for Resolver<'_> {
self.cstore().item_generics_num_lifetimes(def_id, sess)
}
fn resolve_str_path(
&mut self,
span: Span,
crate_root: Option<Symbol>,
components: &[Symbol],
ns: Namespace,
) -> (ast::Path, Res) {
let root = if crate_root.is_some() { kw::PathRoot } else { kw::Crate };
let segments = iter::once(Ident::with_dummy_span(root))
.chain(
crate_root
.into_iter()
.chain(components.iter().cloned())
.map(Ident::with_dummy_span),
)
.map(|i| self.new_ast_path_segment(i))
.collect::<Vec<_>>();
let path = ast::Path { span, segments };
let parent_scope = &ParentScope::module(self.graph_root);
let res = match self.resolve_ast_path(&path, ns, parent_scope) {
Ok(res) => res,
Err((span, error)) => {
self.report_error(span, error);
Res::Err
}
};
(path, res)
}
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes> {
self.partial_res_map.get(&id).cloned()
}

View File

@ -705,6 +705,7 @@ impl<'tcx> DumpVisitor<'tcx> {
let trait_ref = match *super_bound {
hir::GenericBound::Trait(ref trait_ref, _) => trait_ref,
hir::GenericBound::Outlives(..) => continue,
hir::GenericBound::LangItemTrait(..) => unimplemented!(),
};
let trait_ref = &trait_ref.trait_ref;
@ -765,6 +766,7 @@ impl<'tcx> DumpVisitor<'tcx> {
let span = match path {
hir::QPath::Resolved(_, path) => path.span,
hir::QPath::TypeRelative(_, segment) => segment.ident.span,
hir::QPath::LangItem(..) => unimplemented!(),
};
if self.span.filter_generated(span) {
return;
@ -783,6 +785,7 @@ impl<'tcx> DumpVisitor<'tcx> {
self.visit_ty(ty);
std::slice::from_ref(*segment)
}
hir::QPath::LangItem(..) => unimplemented!(),
};
for seg in segments {
if let Some(ref generic_args) = seg.args {
@ -1358,6 +1361,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
let sub_span = match path {
hir::QPath::Resolved(_, path) => path.segments.last().unwrap().ident.span,
hir::QPath::TypeRelative(_, segment) => segment.ident.span,
hir::QPath::LangItem(..) => unimplemented!(),
};
let span = self.span_from_span(sub_span);
self.dumper.dump_ref(Ref {

View File

@ -555,6 +555,7 @@ impl<'tcx> SaveContext<'tcx> {
let segment = match qpath {
hir::QPath::Resolved(_, path) => path.segments.last().unwrap(),
hir::QPath::TypeRelative(_, segment) => segment,
hir::QPath::LangItem(..) => unimplemented!(),
};
match ty.kind {
ty::Adt(def, _) => {
@ -639,6 +640,7 @@ impl<'tcx> SaveContext<'tcx> {
hir::QPath::TypeRelative(..) => self
.maybe_typeck_results
.map_or(Res::Err, |typeck_results| typeck_results.qpath_res(qpath, hir_id)),
hir::QPath::LangItem(..) => unimplemented!(),
},
Node::Binding(&hir::Pat {
@ -653,6 +655,7 @@ impl<'tcx> SaveContext<'tcx> {
let segment = match path {
hir::QPath::Resolved(_, path) => path.segments.last(),
hir::QPath::TypeRelative(_, segment) => Some(*segment),
hir::QPath::LangItem(..) => unimplemented!(),
};
segment.and_then(|seg| {
self.get_path_segment_data(seg).or_else(|| self.get_path_segment_data_with_id(seg, id))

View File

@ -286,6 +286,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
refs: vec![SigElement { id, start, end }],
})
}
hir::TyKind::Path(hir::QPath::LangItem(..)) => unimplemented!(),
hir::TyKind::TraitObject(bounds, ..) => {
// FIXME recurse into bounds
let bounds: Vec<hir::GenericBound<'_>> = bounds

View File

@ -1202,6 +1202,36 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
)
}
pub fn instantiate_lang_item_trait_ref(
&self,
lang_item: hir::LangItem,
span: Span,
hir_id: hir::HirId,
args: &GenericArgs<'_>,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
) {
let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
let (substs, assoc_bindings, _) =
self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty));
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
let mut dup_bindings = FxHashMap::default();
for binding in assoc_bindings {
let _: Result<_, ErrorReported> = self.add_predicates_for_ast_type_binding(
hir_id,
poly_trait_ref,
&binding,
bounds,
false,
&mut dup_bindings,
span,
);
}
}
fn ast_path_to_mono_trait_ref(
&self,
span: Span,
@ -1392,6 +1422,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait_bounds.push((b, Constness::NotConst))
}
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
.instantiate_lang_item_trait_ref(
lang_item, span, hir_id, args, param_ty, bounds,
),
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
}
}
@ -2960,6 +2994,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.map(|(ty, _, _)| ty)
.unwrap_or_else(|_| tcx.ty_error())
}
hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => {
let def_id = tcx.require_lang_item(lang_item, Some(span));
let (substs, _, _) = self.create_substs_for_ast_path(
span,
def_id,
&[],
&GenericArgs::none(),
true,
None,
);
self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
}
hir::TyKind::Array(ref ty, ref length) => {
let length_def_id = tcx.hir().local_def_id(length.hir_id);
let length = ty::Const::from_anon_const(tcx, length_def_id);

View File

@ -236,6 +236,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
}
ExprKind::Path(QPath::LangItem(lang_item, _)) => {
self.check_lang_item_path(lang_item, expr)
}
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
ExprKind::LlvmInlineAsm(ref asm) => {
@ -447,6 +450,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
fn check_lang_item_path(
&self,
lang_item: hir::LangItem,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
}
fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
let tcx = self.tcx;
let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
@ -1077,11 +1088,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return self.tcx.ty_error();
};
let path_span = match *qpath {
QPath::Resolved(_, ref path) => path.span,
QPath::TypeRelative(ref qself, _) => qself.span,
};
// Prohibit struct expressions when non-exhaustive flag is set.
let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
if !adt.did.is_local() && variant.is_field_list_non_exhaustive() {
@ -1099,7 +1105,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
adt_ty,
expected,
expr.hir_id,
path_span,
qpath.span(),
variant,
fields,
base_expr.is_none(),

View File

@ -122,10 +122,9 @@ use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
use rustc_middle::ty::{
self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
ToPredicate, Ty, TyCtxt, UserType, WithConstness,
};
use rustc_middle::ty::WithConstness;
use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind};
use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType};
use rustc_session::config::{self, EntryFnType};
use rustc_session::lint;
use rustc_session::parse::feature_err;
@ -4430,10 +4429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
qpath: &QPath<'_>,
hir_id: hir::HirId,
) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
let path_span = match *qpath {
QPath::Resolved(_, ref path) => path.span,
QPath::TypeRelative(ref qself, _) => qself.span,
};
let path_span = qpath.qself_span();
let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
let variant = match def {
Res::Err => {
@ -4511,9 +4507,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
}
QPath::LangItem(lang_item, span) => {
self.resolve_lang_item_path(lang_item, span, hir_id)
}
}
}
fn resolve_lang_item_path(
&self,
lang_item: hir::LangItem,
span: Span,
hir_id: hir::HirId,
) -> (Res, Ty<'tcx>) {
let def_id = self.tcx.require_lang_item(lang_item, Some(span));
let def_kind = self.tcx.def_kind(def_id);
let item_ty = if let DefKind::Variant = def_kind {
self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
} else {
self.tcx.type_of(def_id)
};
let substs = self.infcx.fresh_substs_for_item(span, def_id);
let ty = item_ty.subst(self.tcx, substs);
self.write_resolution(hir_id, Ok((def_kind, def_id)));
self.add_required_obligations(span, def_id, &substs);
(Res::Def(def_kind, def_id), ty)
}
/// Resolves an associated value path into a base type and associated constant, or method
/// resolution. The newly resolved definition is written into `type_dependent_defs`.
pub fn resolve_ty_and_res_ufcs<'b>(
@ -4532,6 +4553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
};
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
{

View File

@ -947,13 +947,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// |
// L | let A(()) = A(());
// | ^ ^
[] => {
let qpath_span = match qpath {
hir::QPath::Resolved(_, path) => path.span,
hir::QPath::TypeRelative(_, ps) => ps.ident.span,
};
(qpath_span.shrink_to_hi(), pat_span)
}
[] => (qpath.span().shrink_to_hi(), pat_span),
// Easy case. Just take the "lo" of the first sub-pattern and the "hi" of the
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
// This looks like:

View File

@ -1959,6 +1959,20 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
predicates.extend(bounds.predicates(tcx, ty));
}
&hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
let mut bounds = Bounds::default();
AstConv::instantiate_lang_item_trait_ref(
&icx,
lang_item,
span,
hir_id,
args,
ty,
&mut bounds,
);
predicates.extend(bounds.predicates(tcx, ty));
}
&hir::GenericBound::Outlives(ref lifetime) => {
let region = AstConv::ast_region_to_region(&icx, lifetime, None);
predicates.push((
@ -2108,6 +2122,18 @@ fn predicates_from_bound<'tcx>(
let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
bounds.predicates(astconv.tcx(), param_ty)
}
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
let mut bounds = Bounds::default();
astconv.instantiate_lang_item_trait_ref(
lang_item,
span,
hir_id,
args,
param_ty,
&mut bounds,
);
bounds.predicates(astconv.tcx(), param_ty)
}
hir::GenericBound::Outlives(ref lifetime) => {
let region = astconv.ast_region_to_region(lifetime, None);
let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region))

View File

@ -1,27 +1,4 @@
//~ ERROR failed to resolve: could not find `future` in `std` [E0433]
//~^ ERROR failed to resolve: could not find `pin` in `std` [E0433]
//~^^ ERROR failed to resolve: could not find `future` in `std` [E0433]
//~^^^ ERROR failed to resolve: could not find `future` in `std` [E0433]
//~^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433]
//~^^^^^ ERROR failed to resolve: could not find `task` in `std` [E0433]
//~^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433]
//~^^^^^^^ ERROR failed to resolve: could not find `future` in `std` [E0433]
//~^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433]
//~^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433]
//~^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433]
//~^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433]
//~^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433]
//~^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433]
//~^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433]
//~^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `option` in `std` [E0433]
//~^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433]
//~^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `iter` in `std` [E0433]
//~^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433]
//~^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433]
//~^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `convert` in `std` [E0433]
//~^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `ops` in `std` [E0433]
//~^^^^^^^^^^^^^^^^^^^^^^ ERROR failed to resolve: could not find `result` in `std` [E0433]
// check-pass
// edition:2018
// aux-build:not-libstd.rs

View File

@ -1,49 +0,0 @@
error[E0433]: failed to resolve: could not find `future` in `std`
error[E0433]: failed to resolve: could not find `pin` in `std`
error[E0433]: failed to resolve: could not find `future` in `std`
error[E0433]: failed to resolve: could not find `future` in `std`
error[E0433]: failed to resolve: could not find `task` in `std`
error[E0433]: failed to resolve: could not find `task` in `std`
error[E0433]: failed to resolve: could not find `future` in `std`
error[E0433]: failed to resolve: could not find `future` in `std`
error[E0433]: failed to resolve: could not find `ops` in `std`
error[E0433]: failed to resolve: could not find `option` in `std`
error[E0433]: failed to resolve: could not find `option` in `std`
error[E0433]: failed to resolve: could not find `iter` in `std`
error[E0433]: failed to resolve: could not find `iter` in `std`
error[E0433]: failed to resolve: could not find `ops` in `std`
error[E0433]: failed to resolve: could not find `option` in `std`
error[E0433]: failed to resolve: could not find `option` in `std`
error[E0433]: failed to resolve: could not find `iter` in `std`
error[E0433]: failed to resolve: could not find `iter` in `std`
error[E0433]: failed to resolve: could not find `ops` in `std`
error[E0433]: failed to resolve: could not find `result` in `std`
error[E0433]: failed to resolve: could not find `convert` in `std`
error[E0433]: failed to resolve: could not find `ops` in `std`
error[E0433]: failed to resolve: could not find `result` in `std`
error: aborting due to 23 previous errors
For more information about this error, try `rustc --explain E0433`.