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