]> git.lizzy.rs Git - rust.git/blob - src/librustc_ast_lowering/path.rs
Auto merge of #69576 - matthiaskrgr:nightly_bootstrap_from_beta, r=Centril
[rust.git] / src / librustc_ast_lowering / path.rs
1 use super::{AnonymousLifetimeMode, ImplTraitContext, LoweringContext, ParamMode};
2 use super::{GenericArgsCtor, ParenthesizedGenericArgs};
3
4 use rustc::lint::builtin::ELIDED_LIFETIMES_IN_PATHS;
5 use rustc::span_bug;
6 use rustc_ast::ast::{self, *};
7 use rustc_errors::{struct_span_err, Applicability};
8 use rustc_hir as hir;
9 use rustc_hir::def::{DefKind, PartialRes, Res};
10 use rustc_hir::def_id::DefId;
11 use rustc_hir::GenericArg;
12 use rustc_session::lint::BuiltinLintDiagnostics;
13 use rustc_span::Span;
14
15 use log::debug;
16 use smallvec::smallvec;
17
18 impl<'a, 'hir> LoweringContext<'a, 'hir> {
19     crate fn lower_qpath(
20         &mut self,
21         id: NodeId,
22         qself: &Option<QSelf>,
23         p: &Path,
24         param_mode: ParamMode,
25         mut itctx: ImplTraitContext<'_, 'hir>,
26     ) -> hir::QPath<'hir> {
27         let qself_position = qself.as_ref().map(|q| q.position);
28         let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow()));
29
30         let partial_res =
31             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
32
33         let proj_start = p.segments.len() - partial_res.unresolved_segments();
34         let path = self.arena.alloc(hir::Path {
35             res: self.lower_res(partial_res.base_res()),
36             segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
37                 |(i, segment)| {
38                     let param_mode = match (qself_position, param_mode) {
39                         (Some(j), ParamMode::Optional) if i < j => {
40                             // This segment is part of the trait path in a
41                             // qualified path - one of `a`, `b` or `Trait`
42                             // in `<X as a::b::Trait>::T::U::method`.
43                             ParamMode::Explicit
44                         }
45                         _ => param_mode,
46                     };
47
48                     // Figure out if this is a type/trait segment,
49                     // which may need lifetime elision performed.
50                     let parent_def_id = |this: &mut Self, def_id: DefId| DefId {
51                         krate: def_id.krate,
52                         index: this.resolver.def_key(def_id).parent.expect("missing parent"),
53                     };
54                     let type_def_id = match partial_res.base_res() {
55                         Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
56                             Some(parent_def_id(self, def_id))
57                         }
58                         Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
59                             Some(parent_def_id(self, def_id))
60                         }
61                         Res::Def(DefKind::Struct, def_id)
62                         | Res::Def(DefKind::Union, def_id)
63                         | Res::Def(DefKind::Enum, def_id)
64                         | Res::Def(DefKind::TyAlias, def_id)
65                         | Res::Def(DefKind::Trait, def_id)
66                             if i + 1 == proj_start =>
67                         {
68                             Some(def_id)
69                         }
70                         _ => None,
71                     };
72                     let parenthesized_generic_args = match partial_res.base_res() {
73                         // `a::b::Trait(Args)`
74                         Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
75                             ParenthesizedGenericArgs::Ok
76                         }
77                         // `a::b::Trait(Args)::TraitItem`
78                         Res::Def(DefKind::Method, _)
79                         | Res::Def(DefKind::AssocConst, _)
80                         | Res::Def(DefKind::AssocTy, _)
81                             if i + 2 == proj_start =>
82                         {
83                             ParenthesizedGenericArgs::Ok
84                         }
85                         // Avoid duplicated errors.
86                         Res::Err => ParenthesizedGenericArgs::Ok,
87                         // An error
88                         _ => ParenthesizedGenericArgs::Err,
89                     };
90
91                     let num_lifetimes = type_def_id.map_or(0, |def_id| {
92                         if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
93                             return n;
94                         }
95                         assert!(!def_id.is_local());
96                         let n = self.resolver.item_generics_num_lifetimes(def_id, self.sess);
97                         self.type_def_lifetime_params.insert(def_id, n);
98                         n
99                     });
100                     self.lower_path_segment(
101                         p.span,
102                         segment,
103                         param_mode,
104                         num_lifetimes,
105                         parenthesized_generic_args,
106                         itctx.reborrow(),
107                         None,
108                     )
109                 },
110             )),
111             span: p.span,
112         });
113
114         // Simple case, either no projections, or only fully-qualified.
115         // E.g., `std::mem::size_of` or `<I as Iterator>::Item`.
116         if partial_res.unresolved_segments() == 0 {
117             return hir::QPath::Resolved(qself, path);
118         }
119
120         // Create the innermost type that we're projecting from.
121         let mut ty = if path.segments.is_empty() {
122             // If the base path is empty that means there exists a
123             // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`.
124             qself.expect("missing QSelf for <T>::...")
125         } else {
126             // Otherwise, the base path is an implicit `Self` type path,
127             // e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in
128             // `<I as Iterator>::Item::default`.
129             let new_id = self.next_id();
130             self.arena.alloc(self.ty_path(new_id, p.span, hir::QPath::Resolved(qself, path)))
131         };
132
133         // Anything after the base path are associated "extensions",
134         // out of which all but the last one are associated types,
135         // e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`:
136         // * base path is `std::vec::Vec<T>`
137         // * "extensions" are `IntoIter`, `Item` and `clone`
138         // * type nodes are:
139         //   1. `std::vec::Vec<T>` (created above)
140         //   2. `<std::vec::Vec<T>>::IntoIter`
141         //   3. `<<std::vec::Vec<T>>::IntoIter>::Item`
142         // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
143         for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
144             let segment = self.arena.alloc(self.lower_path_segment(
145                 p.span,
146                 segment,
147                 param_mode,
148                 0,
149                 ParenthesizedGenericArgs::Err,
150                 itctx.reborrow(),
151                 None,
152             ));
153             let qpath = hir::QPath::TypeRelative(ty, segment);
154
155             // It's finished, return the extension of the right node type.
156             if i == p.segments.len() - 1 {
157                 return qpath;
158             }
159
160             // Wrap the associated extension in another type node.
161             let new_id = self.next_id();
162             ty = self.arena.alloc(self.ty_path(new_id, p.span, qpath));
163         }
164
165         // We should've returned in the for loop above.
166         span_bug!(
167             p.span,
168             "lower_qpath: no final extension segment in {}..{}",
169             proj_start,
170             p.segments.len()
171         )
172     }
173
174     crate fn lower_path_extra(
175         &mut self,
176         res: Res,
177         p: &Path,
178         param_mode: ParamMode,
179         explicit_owner: Option<NodeId>,
180     ) -> &'hir hir::Path<'hir> {
181         self.arena.alloc(hir::Path {
182             res,
183             segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
184                 self.lower_path_segment(
185                     p.span,
186                     segment,
187                     param_mode,
188                     0,
189                     ParenthesizedGenericArgs::Err,
190                     ImplTraitContext::disallowed(),
191                     explicit_owner,
192                 )
193             })),
194             span: p.span,
195         })
196     }
197
198     crate fn lower_path(
199         &mut self,
200         id: NodeId,
201         p: &Path,
202         param_mode: ParamMode,
203     ) -> &'hir hir::Path<'hir> {
204         let res = self.expect_full_res(id);
205         let res = self.lower_res(res);
206         self.lower_path_extra(res, p, param_mode, None)
207     }
208
209     crate fn lower_path_segment(
210         &mut self,
211         path_span: Span,
212         segment: &PathSegment,
213         param_mode: ParamMode,
214         expected_lifetimes: usize,
215         parenthesized_generic_args: ParenthesizedGenericArgs,
216         itctx: ImplTraitContext<'_, 'hir>,
217         explicit_owner: Option<NodeId>,
218     ) -> hir::PathSegment<'hir> {
219         let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args {
220             let msg = "parenthesized type parameters may only be used with a `Fn` trait";
221             match **generic_args {
222                 GenericArgs::AngleBracketed(ref data) => {
223                     self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
224                 }
225                 GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
226                     ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
227                     ParenthesizedGenericArgs::Err => {
228                         let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
229                         err.span_label(data.span, "only `Fn` traits may use parentheses");
230                         if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
231                             // Do not suggest going from `Trait()` to `Trait<>`
232                             if !data.inputs.is_empty() {
233                                 if let Some(split) = snippet.find('(') {
234                                     let trait_name = &snippet[0..split];
235                                     let args = &snippet[split + 1..snippet.len() - 1];
236                                     err.span_suggestion(
237                                         data.span,
238                                         "use angle brackets instead",
239                                         format!("{}<{}>", trait_name, args),
240                                         Applicability::MaybeIncorrect,
241                                     );
242                                 }
243                             }
244                         };
245                         err.emit();
246                         (
247                             self.lower_angle_bracketed_parameter_data(
248                                 &data.as_angle_bracketed_args(),
249                                 param_mode,
250                                 itctx,
251                             )
252                             .0,
253                             false,
254                         )
255                     }
256                 },
257             }
258         } else {
259             self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode, itctx)
260         };
261
262         let has_lifetimes = generic_args.args.iter().any(|arg| match arg {
263             GenericArg::Lifetime(_) => true,
264             _ => false,
265         });
266         let first_generic_span = generic_args
267             .args
268             .iter()
269             .map(|a| a.span())
270             .chain(generic_args.bindings.iter().map(|b| b.span))
271             .next();
272         if !generic_args.parenthesized && !has_lifetimes {
273             generic_args.args = self
274                 .elided_path_lifetimes(path_span, expected_lifetimes)
275                 .map(|lt| GenericArg::Lifetime(lt))
276                 .chain(generic_args.args.into_iter())
277                 .collect();
278             if expected_lifetimes > 0 && param_mode == ParamMode::Explicit {
279                 let anon_lt_suggestion = vec!["'_"; expected_lifetimes].join(", ");
280                 let no_non_lt_args = generic_args.args.len() == expected_lifetimes;
281                 let no_bindings = generic_args.bindings.is_empty();
282                 let (incl_angl_brckt, insertion_sp, suggestion) = if no_non_lt_args && no_bindings {
283                     // If there are no (non-implicit) generic args or associated type
284                     // bindings, our suggestion includes the angle brackets.
285                     (true, path_span.shrink_to_hi(), format!("<{}>", anon_lt_suggestion))
286                 } else {
287                     // Otherwise (sorry, this is kind of gross) we need to infer the
288                     // place to splice in the `'_, ` from the generics that do exist.
289                     let first_generic_span = first_generic_span
290                         .expect("already checked that non-lifetime args or bindings exist");
291                     (false, first_generic_span.shrink_to_lo(), format!("{}, ", anon_lt_suggestion))
292                 };
293                 match self.anonymous_lifetime_mode {
294                     // In create-parameter mode we error here because we don't want to support
295                     // deprecated impl elision in new features like impl elision and `async fn`,
296                     // both of which work using the `CreateParameter` mode:
297                     //
298                     //     impl Foo for std::cell::Ref<u32> // note lack of '_
299                     //     async fn foo(_: std::cell::Ref<u32>) { ... }
300                     AnonymousLifetimeMode::CreateParameter => {
301                         let mut err = struct_span_err!(
302                             self.sess,
303                             path_span,
304                             E0726,
305                             "implicit elided lifetime not allowed here"
306                         );
307                         rustc::lint::add_elided_lifetime_in_path_suggestion(
308                             &self.sess,
309                             &mut err,
310                             expected_lifetimes,
311                             path_span,
312                             incl_angl_brckt,
313                             insertion_sp,
314                             suggestion,
315                         );
316                         err.emit();
317                     }
318                     AnonymousLifetimeMode::PassThrough | AnonymousLifetimeMode::ReportError => {
319                         self.resolver.lint_buffer().buffer_lint_with_diagnostic(
320                             ELIDED_LIFETIMES_IN_PATHS,
321                             CRATE_NODE_ID,
322                             path_span,
323                             "hidden lifetime parameters in types are deprecated",
324                             BuiltinLintDiagnostics::ElidedLifetimesInPaths(
325                                 expected_lifetimes,
326                                 path_span,
327                                 incl_angl_brckt,
328                                 insertion_sp,
329                                 suggestion,
330                             ),
331                         );
332                     }
333                 }
334             }
335         }
336
337         let res = self.expect_full_res(segment.id);
338         let id = if let Some(owner) = explicit_owner {
339             self.lower_node_id_with_owner(segment.id, owner)
340         } else {
341             self.lower_node_id(segment.id)
342         };
343         debug!(
344             "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
345             segment.ident, segment.id, id,
346         );
347
348         hir::PathSegment {
349             ident: segment.ident,
350             hir_id: Some(id),
351             res: Some(self.lower_res(res)),
352             infer_args,
353             args: if generic_args.is_empty() {
354                 None
355             } else {
356                 Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
357             },
358         }
359     }
360
361     fn lower_angle_bracketed_parameter_data(
362         &mut self,
363         data: &AngleBracketedArgs,
364         param_mode: ParamMode,
365         mut itctx: ImplTraitContext<'_, 'hir>,
366     ) -> (GenericArgsCtor<'hir>, bool) {
367         let &AngleBracketedArgs { ref args, ref constraints, .. } = data;
368         let has_non_lt_args = args.iter().any(|arg| match arg {
369             ast::GenericArg::Lifetime(_) => false,
370             ast::GenericArg::Type(_) => true,
371             ast::GenericArg::Const(_) => true,
372         });
373         (
374             GenericArgsCtor {
375                 args: args.iter().map(|a| self.lower_generic_arg(a, itctx.reborrow())).collect(),
376                 bindings: self.arena.alloc_from_iter(
377                     constraints.iter().map(|b| self.lower_assoc_ty_constraint(b, itctx.reborrow())),
378                 ),
379                 parenthesized: false,
380             },
381             !has_non_lt_args && param_mode == ParamMode::Optional,
382         )
383     }
384
385     fn lower_parenthesized_parameter_data(
386         &mut self,
387         data: &ParenthesizedArgs,
388     ) -> (GenericArgsCtor<'hir>, bool) {
389         // Switch to `PassThrough` mode for anonymous lifetimes; this
390         // means that we permit things like `&Ref<T>`, where `Ref` has
391         // a hidden lifetime parameter. This is needed for backwards
392         // compatibility, even in contexts like an impl header where
393         // we generally don't permit such things (see #51008).
394         self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
395             let &ParenthesizedArgs { ref inputs, ref output, span } = data;
396             let inputs = this.arena.alloc_from_iter(
397                 inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
398             );
399             let output_ty = match output {
400                 FnRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
401                 FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
402             };
403             let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
404             let binding = this.output_ty_binding(output_ty.span, output_ty);
405             (
406                 GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
407                 false,
408             )
409         })
410     }
411
412     /// An associated type binding `Output = $ty`.
413     crate fn output_ty_binding(
414         &mut self,
415         span: Span,
416         ty: &'hir hir::Ty<'hir>,
417     ) -> hir::TypeBinding<'hir> {
418         let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
419         let kind = hir::TypeBindingKind::Equality { ty };
420         hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
421     }
422 }