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