-// ignore-tidy-filelength
-
//! Lowers the AST to the HIR.
//!
//! Since the AST and HIR are fairly similar, this is mostly a simple procedure,
use rustc::dep_graph::DepGraph;
use rustc::hir::map::definitions::{DefKey, DefPathData, Definitions};
use rustc::hir::map::Map;
-use rustc::lint;
-use rustc::lint::builtin::{self, ELIDED_LIFETIMES_IN_PATHS};
-use rustc::middle::cstore::CrateStore;
-use rustc::util::captures::Captures;
-use rustc::util::common::FN_OUTPUT_NAME;
use rustc::{bug, span_bug};
+use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_error_codes::*;
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{DefId, DefIdMap, DefIndex, CRATE_DEF_INDEX};
use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::IndexVec;
use rustc_session::config::nightly_options;
+use rustc_session::lint::{builtin, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::node_id::NodeMap;
use rustc_session::Session;
use rustc_span::hygiene::ExpnId;
mod expr;
mod item;
mod pat;
+mod path;
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
}
pub trait Resolver {
- fn cstore(&self) -> &dyn CrateStore;
+ fn def_key(&mut self, id: DefId) -> DefKey;
+
+ fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize;
/// Obtains resolution for a `NodeId` with a single resolution.
fn get_partial_res(&mut self, id: NodeId) -> Option<PartialRes>;
ns: Namespace,
) -> (ast::Path, Res<NodeId>);
- fn lint_buffer(&mut self) -> &mut lint::LintBuffer;
+ fn lint_buffer(&mut self) -> &mut LintBuffer;
fn next_node_id(&mut self) -> NodeId;
}
// incr. comp. yet.
dep_graph.assert_ignored();
- let _prof_timer = sess.prof.generic_activity("hir_lowering");
+ let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
LoweringContext {
crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
ret
}
- fn def_key(&mut self, id: DefId) -> DefKey {
- if id.is_local() {
- self.resolver.definitions().def_key(id.index)
- } else {
- self.resolver.cstore().def_key(id)
- }
- }
-
fn lower_attrs(&mut self, attrs: &[Attribute]) -> &'hir [Attribute] {
self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)))
}
)
}
- fn lower_qpath(
- &mut self,
- id: NodeId,
- qself: &Option<QSelf>,
- p: &Path,
- param_mode: ParamMode,
- mut itctx: ImplTraitContext<'_, 'hir>,
- ) -> hir::QPath<'hir> {
- let qself_position = qself.as_ref().map(|q| q.position);
- let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
-
- let partial_res =
- self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
-
- let proj_start = p.segments.len() - partial_res.unresolved_segments();
- let path = self.arena.alloc(hir::Path {
- res: self.lower_res(partial_res.base_res()),
- segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
- |(i, segment)| {
- let param_mode = match (qself_position, param_mode) {
- (Some(j), ParamMode::Optional) if i < j => {
- // This segment is part of the trait path in a
- // qualified path - one of `a`, `b` or `Trait`
- // in `<X as a::b::Trait>::T::U::method`.
- ParamMode::Explicit
- }
- _ => param_mode,
- };
-
- // Figure out if this is a type/trait segment,
- // which may need lifetime elision performed.
- let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
- krate: def_id.krate,
- index: this.def_key(def_id).parent.expect("missing parent"),
- };
- let type_def_id = match partial_res.base_res() {
- Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
- Some(parent_def_id(self, def_id))
- }
- Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
- Some(parent_def_id(self, def_id))
- }
- Res::Def(DefKind::Struct, def_id)
- | Res::Def(DefKind::Union, def_id)
- | Res::Def(DefKind::Enum, def_id)
- | Res::Def(DefKind::TyAlias, def_id)
- | Res::Def(DefKind::Trait, def_id)
- if i + 1 == proj_start =>
- {
- Some(def_id)
- }
- _ => None,
- };
- let parenthesized_generic_args = match partial_res.base_res() {
- // `a::b::Trait(Args)`
- Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
- ParenthesizedGenericArgs::Ok
- }
- // `a::b::Trait(Args)::TraitItem`
- Res::Def(DefKind::Method, _)
- | Res::Def(DefKind::AssocConst, _)
- | Res::Def(DefKind::AssocTy, _)
- if i + 2 == proj_start =>
- {
- ParenthesizedGenericArgs::Ok
- }
- // Avoid duplicated errors.
- Res::Err => ParenthesizedGenericArgs::Ok,
- // An error
- _ => ParenthesizedGenericArgs::Err,
- };
-
- let num_lifetimes = type_def_id.map_or(0, |def_id| {
- if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
- return n;
- }
- assert!(!def_id.is_local());
- let item_generics = self
- .resolver
- .cstore()
- .item_generics_cloned_untracked(def_id, self.sess);
- let n = item_generics.own_counts().lifetimes;
- self.type_def_lifetime_params.insert(def_id, n);
- n
- });
- self.lower_path_segment(
- p.span,
- segment,
- param_mode,
- num_lifetimes,
- parenthesized_generic_args,
- itctx.reborrow(),
- None,
- )
- },
- )),
- span: p.span,
- });
-
- // Simple case, either no projections, or only fully-qualified.
- // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
- if partial_res.unresolved_segments() == 0 {
- return hir::QPath::Resolved(qself, path);
- }
-
- // Create the innermost type that we're projecting from.
- let mut ty = if path.segments.is_empty() {
- // If the base path is empty that means there exists a
- // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
- qself.expect("missing QSelf for <T>::...")
- } else {
- // Otherwise, the base path is an implicit `Self` type path,
- // e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
- // `<I as Iterator>::Item::default`.
- let new_id = self.next_id();
- self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)))
- };
-
- // Anything after the base path are associated "extensions",
- // out of which all but the last one are associated types,
- // e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
- // * base path is `std::vec::Vec<T>`
- // * "extensions" are `IntoIter`, `Item` and `clone`
- // * type nodes are:
- // 1. `std::vec::Vec<T>` (created above)
- // 2. `<std::vec::Vec<T>>::IntoIter`
- // 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
- // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
- for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
- let segment = self.arena.alloc(self.lower_path_segment(
- p.span,
- segment,
- param_mode,
- 0,
- ParenthesizedGenericArgs::Err,
- itctx.reborrow(),
- None,
- ));
- let qpath = hir::QPath::TypeRelative(ty, segment);
-
- // It's finished, return the extension of the right node type.
- if i == p.segments.len() - 1 {
- return qpath;
- }
-
- // Wrap the associated extension in another type node.
- let new_id = self.next_id();
- ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath));
- }
-
- // We should've returned in the for loop above.
- span_bug!(
- p.span,
- "lower_qpath: no final extension segment in {}..{}",
- proj_start,
- p.segments.len()
- )
- }
-
- fn lower_path_extra(
- &mut self,
- res: Res,
- p: &Path,
- param_mode: ParamMode,
- explicit_owner: Option<NodeId>,
- ) -> &'hir hir::Path<'hir> {
- self.arena.alloc(hir::Path {
- res,
- segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
- self.lower_path_segment(
- p.span,
- segment,
- param_mode,
- 0,
- ParenthesizedGenericArgs::Err,
- ImplTraitContext::disallowed(),
- explicit_owner,
- )
- })),
- span: p.span,
- })
- }
-
- fn lower_path(&mut self, id: NodeId, p: &Path, param_mode: ParamMode) -> &'hir hir::Path<'hir> {
- let res = self.expect_full_res(id);
- let res = self.lower_res(res);
- self.lower_path_extra(res, p, param_mode, None)
- }
-
- fn lower_path_segment(
- &mut self,
- path_span: Span,
- segment: &PathSegment,
- param_mode: ParamMode,
- expected_lifetimes: usize,
- parenthesized_generic_args: ParenthesizedGenericArgs,
- itctx: ImplTraitContext<'_, 'hir>,
- explicit_owner: Option<NodeId>,
- ) -> hir::PathSegment<'hir> {
- let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
- let msg = "parenthesized type parameters may only be used with a `Fn` trait";
- match **generic_args {
- GenericArgs::AngleBracketed(ref data) => {
- self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
- }
- GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
- ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
- ParenthesizedGenericArgs::Err => {
- let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
- err.span_label(data.span, "only `Fn` traits may use parentheses");
- if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
- // Do not suggest going from `Trait()` to `Trait<>`
- if data.inputs.len() > 0 {
- if let Some(split) = snippet.find('(') {
- let trait_name = &snippet[0..split];
- let args = &snippet[split + 1..snippet.len() - 1];
- err.span_suggestion(
- data.span,
- "use angle brackets instead",
- format!("{}<{}>", trait_name, args),
- Applicability::MaybeIncorrect,
- );
- }
- }
- };
- err.emit();
- (
- self.lower_angle_bracketed_parameter_data(
- &data.as_angle_bracketed_args(),
- param_mode,
- itctx,
- )
- .0,
- false,
- )
- }
- },
- }
- } else {
- self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
- };
-
- let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
- GenericArg::Lifetime(_) => true,
- _ => false,
- });
- let first_generic_span = generic_args
- .args
- .iter()
- .map(|a| a.span())
- .chain(generic_args.bindings.iter().map(|b| b.span))
- .next();
- if !generic_args.parenthesized && !has_lifetimes {
- generic_args.args = self
- .elided_path_lifetimes(path_span, expected_lifetimes)
- .map(|lt| GenericArg::Lifetime(lt))
- .chain(generic_args.args.into_iter())
- .collect();
- if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
- let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
- let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
- let no_bindings = generic_args.bindings.is_empty();
- let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
- // If there are no (non-implicit) generic args or associated type
- // bindings, our suggestion includes the angle brackets.
- (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
- } else {
- // Otherwise (sorry, this is kind of gross) we need to infer the
- // place to splice in the `'_, ` from the generics that do exist.
- let first_generic_span = first_generic_span
- .expect("already checked that non-lifetime args or bindings exist");
- (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
- };
- match self.anonymous_lifetime_mode {
- // In create-parameter mode we error here because we don't want to support
- // deprecated impl elision in new features like impl elision and `async fn`,
- // both of which work using the `CreateParameter` mode:
- //
- // impl Foo for std::cell::Ref<u32> // note lack of '_
- // async fn foo(_: std::cell::Ref<u32>) { ... }
- AnonymousLifetimeMode::CreateParameter => {
- let mut err = struct_span_err!(
- self.sess,
- path_span,
- E0726,
- "implicit elided lifetime not allowed here"
- );
- crate::lint::builtin::add_elided_lifetime_in_path_suggestion(
- &self.sess,
- &mut err,
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- );
- err.emit();
- }
- AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
- self.resolver.lint_buffer().buffer_lint_with_diagnostic(
- ELIDED_LIFETIMES_IN_PATHS,
- CRATE_NODE_ID,
- path_span,
- "hidden lifetime parameters in types are deprecated",
- builtin::BuiltinLintDiagnostics::ElidedLifetimesInPaths(
- expected_lifetimes,
- path_span,
- incl_angl_brckt,
- insertion_sp,
- suggestion,
- ),
- );
- }
- }
- }
- }
-
- let res = self.expect_full_res(segment.id);
- let id = if let Some(owner) = explicit_owner {
- self.lower_node_id_with_owner(segment.id, owner)
- } else {
- self.lower_node_id(segment.id)
- };
- debug!(
- "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
- segment.ident, segment.id, id,
- );
-
- hir::PathSegment {
- ident: segment.ident,
- hir_id: Some(id),
- res: Some(self.lower_res(res)),
- infer_args,
- args: if generic_args.is_empty() {
- None
- } else {
- Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
- },
- }
- }
-
- fn lower_angle_bracketed_parameter_data(
- &mut self,
- data: &AngleBracketedArgs,
- param_mode: ParamMode,
- mut itctx: ImplTraitContext<'_, 'hir>,
- ) -> (GenericArgsCtor<'hir>, bool) {
- let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
- let has_non_lt_args = args.iter().any(|arg| match arg {
- ast::GenericArg::Lifetime(_) => false,
- ast::GenericArg::Type(_) => true,
- ast::GenericArg::Const(_) => true,
- });
- (
- GenericArgsCtor {
- args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
- bindings: self.arena.alloc_from_iter(
- constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
- ),
- parenthesized: false,
- },
- !has_non_lt_args && param_mode == ParamMode::Optional,
- )
- }
-
- fn lower_parenthesized_parameter_data(
- &mut self,
- data: &ParenthesizedArgs,
- ) -> (GenericArgsCtor<'hir>, bool) {
- // Switch to `PassThrough` mode for anonymous lifetimes; this
- // means that we permit things like `&Ref<T>`, where `Ref` has
- // a hidden lifetime parameter. This is needed for backwards
- // compatibility, even in contexts like an impl header where
- // we generally don't permit such things (see #51008).
- self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
- let &ParenthesizedArgs { ref inputs, ref output, span } = data;
- let inputs = this.arena.alloc_from_iter(
- inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
- );
- let output_ty = match output {
- FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
- FunctionRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
- };
- let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
- let binding = hir::TypeBinding {
- hir_id: this.next_id(),
- ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
- span: output_ty.span,
- kind: hir::TypeBindingKind::Equality { ty: output_ty },
- };
- (
- GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
- false,
- )
- })
- }
-
fn lower_local(&mut self, l: &Local) -> (hir::Local<'hir>, SmallVec<[NodeId; 1]>) {
let mut ids = SmallVec::<[NodeId; 1]>::new();
if self.sess.features_untracked().impl_trait_in_bindings {
// "<Output = T>"
let future_params = self.arena.alloc(hir::GenericArgs {
args: &[],
- bindings: arena_vec![self; hir::TypeBinding {
- ident: Ident::with_dummy_span(FN_OUTPUT_NAME),
- kind: hir::TypeBindingKind::Equality { ty: output_ty },
- hir_id: self.next_id(),
- span,
- }],
+ bindings: arena_vec![self; self.output_ty_binding(span, output_ty)],
parenthesized: false,
});
(hir::ParamName::Plain(param.ident), kind)
}
- GenericParamKind::Const { ref ty } => (
- hir::ParamName::Plain(param.ident),
- hir::GenericParamKind::Const {
- ty: self.lower_ty(&ty, ImplTraitContext::disallowed()),
- },
- ),
+ GenericParamKind::Const { ref ty } => {
+ let ty = self
+ .with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
+ this.lower_ty(&ty, ImplTraitContext::disallowed())
+ });
+
+ (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty })
+ }
};
hir::GenericParam {
p: &PolyTraitRef,
mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::PolyTraitRef<'hir> {
+ if p.trait_ref.constness.is_some() {
+ self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
+ }
+
let bound_generic_params = self.lower_generic_params(
&p.bound_generic_params,
&NodeMap::default(),
}
}
- fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
- match *b {
- BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
- BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
- BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
- BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
- }
- }
-
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
match u {
CompilerGenerated => hir::UnsafeSource::CompilerGenerated,
id,
span,
"trait objects without an explicit `dyn` are deprecated",
- builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global),
+ BuiltinLintDiagnostics::BareTraitObject(span, is_global),
)
}
}