]>
Commit | Line | Data |
---|---|---|
5099ac24 FG |
1 | use crate::ImplTraitPosition; |
2 | ||
923072b8 | 3 | use super::ResolverAstLoweringExt; |
04454e1e FG |
4 | use super::{GenericArgsCtor, LifetimeRes, ParenthesizedGenericArgs}; |
5 | use super::{ImplTraitContext, LoweringContext, ParamMode}; | |
dfeec247 | 6 | |
3dfed10e | 7 | use rustc_ast::{self as ast, *}; |
dfeec247 XL |
8 | use rustc_errors::{struct_span_err, Applicability}; |
9 | use rustc_hir as hir; | |
10 | use rustc_hir::def::{DefKind, PartialRes, Res}; | |
dfeec247 | 11 | use rustc_hir::GenericArg; |
04454e1e | 12 | use rustc_span::symbol::{kw, 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> { | |
923072b8 FG |
19 | #[instrument(level = "trace", skip(self))] |
20 | pub(crate) fn lower_qpath( | |
dfeec247 XL |
21 | &mut self, |
22 | id: NodeId, | |
23 | qself: &Option<QSelf>, | |
24 | p: &Path, | |
25 | param_mode: ParamMode, | |
923072b8 | 26 | itctx: ImplTraitContext, |
dfeec247 XL |
27 | ) -> hir::QPath<'hir> { |
28 | let qself_position = qself.as_ref().map(|q| q.position); | |
923072b8 | 29 | let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); |
dfeec247 XL |
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 | ||
dfeec247 XL |
50 | let parenthesized_generic_args = match partial_res.base_res() { |
51 | // `a::b::Trait(Args)` | |
52 | Res::Def(DefKind::Trait, _) if i + 1 == proj_start => { | |
53 | ParenthesizedGenericArgs::Ok | |
54 | } | |
55 | // `a::b::Trait(Args)::TraitItem` | |
ba9703b0 | 56 | Res::Def(DefKind::AssocFn, _) |
dfeec247 XL |
57 | | Res::Def(DefKind::AssocConst, _) |
58 | | Res::Def(DefKind::AssocTy, _) | |
59 | if i + 2 == proj_start => | |
60 | { | |
61 | ParenthesizedGenericArgs::Ok | |
62 | } | |
63 | // Avoid duplicated errors. | |
64 | Res::Err => ParenthesizedGenericArgs::Ok, | |
65 | // An error | |
66 | _ => ParenthesizedGenericArgs::Err, | |
67 | }; | |
68 | ||
dfeec247 XL |
69 | self.lower_path_segment( |
70 | p.span, | |
71 | segment, | |
72 | param_mode, | |
dfeec247 | 73 | parenthesized_generic_args, |
923072b8 | 74 | itctx, |
dfeec247 XL |
75 | ) |
76 | }, | |
77 | )), | |
94222f64 XL |
78 | span: self.lower_span( |
79 | p.segments[..proj_start] | |
80 | .last() | |
81 | .map_or(path_span_lo, |segment| path_span_lo.to(segment.span())), | |
82 | ), | |
dfeec247 XL |
83 | }); |
84 | ||
85 | // Simple case, either no projections, or only fully-qualified. | |
86 | // E.g., `std::mem::size_of` or `<I as Iterator>::Item`. | |
87 | if partial_res.unresolved_segments() == 0 { | |
88 | return hir::QPath::Resolved(qself, path); | |
89 | } | |
90 | ||
91 | // Create the innermost type that we're projecting from. | |
92 | let mut ty = if path.segments.is_empty() { | |
93 | // If the base path is empty that means there exists a | |
94 | // syntactical `Self`, e.g., `&i32` in `<&i32>::clone`. | |
95 | qself.expect("missing QSelf for <T>::...") | |
96 | } else { | |
97 | // Otherwise, the base path is an implicit `Self` type path, | |
98 | // e.g., `Vec` in `Vec::new` or `<I as Iterator>::Item` in | |
99 | // `<I as Iterator>::Item::default`. | |
100 | let new_id = self.next_id(); | |
6a06907d | 101 | self.arena.alloc(self.ty_path(new_id, path.span, hir::QPath::Resolved(qself, path))) |
dfeec247 XL |
102 | }; |
103 | ||
104 | // Anything after the base path are associated "extensions", | |
105 | // out of which all but the last one are associated types, | |
106 | // e.g., for `std::vec::Vec::<T>::IntoIter::Item::clone`: | |
107 | // * base path is `std::vec::Vec<T>` | |
108 | // * "extensions" are `IntoIter`, `Item` and `clone` | |
109 | // * type nodes are: | |
110 | // 1. `std::vec::Vec<T>` (created above) | |
111 | // 2. `<std::vec::Vec<T>>::IntoIter` | |
112 | // 3. `<<std::vec::Vec<T>>::IntoIter>::Item` | |
113 | // * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone` | |
114 | for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { | |
6a06907d | 115 | let hir_segment = self.arena.alloc(self.lower_path_segment( |
dfeec247 XL |
116 | p.span, |
117 | segment, | |
118 | param_mode, | |
dfeec247 | 119 | ParenthesizedGenericArgs::Err, |
923072b8 | 120 | itctx, |
dfeec247 | 121 | )); |
6a06907d | 122 | let qpath = hir::QPath::TypeRelative(ty, hir_segment); |
dfeec247 XL |
123 | |
124 | // It's finished, return the extension of the right node type. | |
125 | if i == p.segments.len() - 1 { | |
126 | return qpath; | |
127 | } | |
128 | ||
129 | // Wrap the associated extension in another type node. | |
130 | let new_id = self.next_id(); | |
6a06907d | 131 | ty = self.arena.alloc(self.ty_path(new_id, path_span_lo.to(segment.span()), qpath)); |
dfeec247 XL |
132 | } |
133 | ||
134 | // We should've returned in the for loop above. | |
ba9703b0 XL |
135 | |
136 | self.sess.diagnostic().span_bug( | |
dfeec247 | 137 | p.span, |
ba9703b0 XL |
138 | &format!( |
139 | "lower_qpath: no final extension segment in {}..{}", | |
140 | proj_start, | |
141 | p.segments.len() | |
142 | ), | |
143 | ); | |
dfeec247 XL |
144 | } |
145 | ||
923072b8 | 146 | pub(crate) fn lower_path_extra( |
dfeec247 XL |
147 | &mut self, |
148 | res: Res, | |
149 | p: &Path, | |
150 | param_mode: ParamMode, | |
dfeec247 XL |
151 | ) -> &'hir hir::Path<'hir> { |
152 | self.arena.alloc(hir::Path { | |
153 | res, | |
154 | segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| { | |
155 | self.lower_path_segment( | |
156 | p.span, | |
157 | segment, | |
158 | param_mode, | |
dfeec247 | 159 | ParenthesizedGenericArgs::Err, |
5099ac24 | 160 | ImplTraitContext::Disallowed(ImplTraitPosition::Path), |
dfeec247 XL |
161 | ) |
162 | })), | |
94222f64 | 163 | span: self.lower_span(p.span), |
dfeec247 XL |
164 | }) |
165 | } | |
166 | ||
923072b8 | 167 | pub(crate) fn lower_path( |
dfeec247 XL |
168 | &mut self, |
169 | id: NodeId, | |
170 | p: &Path, | |
171 | param_mode: ParamMode, | |
172 | ) -> &'hir hir::Path<'hir> { | |
173 | let res = self.expect_full_res(id); | |
174 | let res = self.lower_res(res); | |
c295e0f8 | 175 | self.lower_path_extra(res, p, param_mode) |
dfeec247 XL |
176 | } |
177 | ||
923072b8 | 178 | pub(crate) fn lower_path_segment( |
dfeec247 XL |
179 | &mut self, |
180 | path_span: Span, | |
181 | segment: &PathSegment, | |
182 | param_mode: ParamMode, | |
dfeec247 | 183 | parenthesized_generic_args: ParenthesizedGenericArgs, |
923072b8 | 184 | itctx: ImplTraitContext, |
dfeec247 | 185 | ) -> hir::PathSegment<'hir> { |
04454e1e | 186 | debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,); |
dfeec247 XL |
187 | let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { |
188 | let msg = "parenthesized type parameters may only be used with a `Fn` trait"; | |
189 | match **generic_args { | |
190 | GenericArgs::AngleBracketed(ref data) => { | |
191 | self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) | |
192 | } | |
193 | GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args { | |
923072b8 | 194 | ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), |
dfeec247 XL |
195 | ParenthesizedGenericArgs::Err => { |
196 | let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); | |
197 | err.span_label(data.span, "only `Fn` traits may use parentheses"); | |
923072b8 FG |
198 | // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>` |
199 | if !data.inputs.is_empty() { | |
200 | // Start of the span to the 1st character of 1st argument | |
201 | let open_param = data.inputs_span.shrink_to_lo().to(data | |
202 | .inputs | |
203 | .first() | |
204 | .unwrap() | |
205 | .span | |
206 | .shrink_to_lo()); | |
207 | // Last character position of last argument to the end of the span | |
208 | let close_param = data | |
209 | .inputs | |
210 | .last() | |
211 | .unwrap() | |
212 | .span | |
213 | .shrink_to_hi() | |
214 | .to(data.inputs_span.shrink_to_hi()); | |
215 | err.multipart_suggestion( | |
216 | &format!("use angle brackets instead",), | |
217 | vec![ | |
218 | (open_param, String::from("<")), | |
219 | (close_param, String::from(">")), | |
220 | ], | |
221 | Applicability::MaybeIncorrect, | |
222 | ); | |
223 | } | |
dfeec247 XL |
224 | err.emit(); |
225 | ( | |
226 | self.lower_angle_bracketed_parameter_data( | |
227 | &data.as_angle_bracketed_args(), | |
228 | param_mode, | |
229 | itctx, | |
230 | ) | |
231 | .0, | |
232 | false, | |
233 | ) | |
234 | } | |
235 | }, | |
236 | } | |
237 | } else { | |
17df50a5 XL |
238 | ( |
239 | GenericArgsCtor { | |
240 | args: Default::default(), | |
241 | bindings: &[], | |
242 | parenthesized: false, | |
243 | span: path_span.shrink_to_hi(), | |
244 | }, | |
245 | param_mode == ParamMode::Optional, | |
246 | ) | |
dfeec247 XL |
247 | }; |
248 | ||
29967ef6 XL |
249 | let has_lifetimes = |
250 | generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); | |
04454e1e FG |
251 | if !generic_args.parenthesized && !has_lifetimes { |
252 | self.maybe_insert_elided_lifetimes_in_path( | |
253 | path_span, | |
254 | segment.id, | |
255 | segment.ident.span, | |
256 | &mut generic_args, | |
257 | ); | |
dfeec247 XL |
258 | } |
259 | ||
260 | let res = self.expect_full_res(segment.id); | |
c295e0f8 | 261 | let id = self.lower_node_id(segment.id); |
dfeec247 XL |
262 | debug!( |
263 | "lower_path_segment: ident={:?} original-id={:?} new-id={:?}", | |
264 | segment.ident, segment.id, id, | |
265 | ); | |
266 | ||
267 | hir::PathSegment { | |
94222f64 | 268 | ident: self.lower_ident(segment.ident), |
dfeec247 XL |
269 | hir_id: Some(id), |
270 | res: Some(self.lower_res(res)), | |
271 | infer_args, | |
17df50a5 | 272 | args: if generic_args.is_empty() && generic_args.span.is_empty() { |
dfeec247 XL |
273 | None |
274 | } else { | |
94222f64 | 275 | Some(generic_args.into_generic_args(self)) |
dfeec247 XL |
276 | }, |
277 | } | |
278 | } | |
279 | ||
04454e1e FG |
280 | fn maybe_insert_elided_lifetimes_in_path( |
281 | &mut self, | |
282 | path_span: Span, | |
283 | segment_id: NodeId, | |
284 | segment_ident_span: Span, | |
285 | generic_args: &mut GenericArgsCtor<'hir>, | |
286 | ) { | |
287 | let (start, end) = match self.resolver.get_lifetime_res(segment_id) { | |
288 | Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end), | |
289 | None => return, | |
290 | Some(_) => panic!(), | |
291 | }; | |
292 | let expected_lifetimes = end.as_usize() - start.as_usize(); | |
293 | debug!(expected_lifetimes); | |
294 | ||
295 | // Note: these spans are used for diagnostics when they can't be inferred. | |
296 | // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label | |
297 | let elided_lifetime_span = if generic_args.span.is_empty() { | |
298 | // If there are no brackets, use the identifier span. | |
299 | // HACK: we use find_ancestor_inside to properly suggest elided spans in paths | |
300 | // originating from macros, since the segment's span might be from a macro arg. | |
301 | segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span) | |
302 | } else if generic_args.is_empty() { | |
303 | // If there are brackets, but not generic arguments, then use the opening bracket | |
304 | generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) | |
305 | } else { | |
306 | // Else use an empty span right after the opening bracket. | |
307 | generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() | |
308 | }; | |
309 | ||
310 | generic_args.args.insert_many( | |
311 | 0, | |
312 | (start.as_u32()..end.as_u32()).map(|i| { | |
313 | let id = NodeId::from_u32(i); | |
314 | let l = self.lower_lifetime(&Lifetime { | |
315 | id, | |
316 | ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span), | |
317 | }); | |
318 | GenericArg::Lifetime(l) | |
319 | }), | |
320 | ); | |
321 | } | |
322 | ||
5869c6ff | 323 | pub(crate) fn lower_angle_bracketed_parameter_data( |
dfeec247 XL |
324 | &mut self, |
325 | data: &AngleBracketedArgs, | |
326 | param_mode: ParamMode, | |
923072b8 | 327 | itctx: ImplTraitContext, |
dfeec247 | 328 | ) -> (GenericArgsCtor<'hir>, bool) { |
ba9703b0 XL |
329 | let has_non_lt_args = data.args.iter().any(|arg| match arg { |
330 | AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_)) | |
331 | | AngleBracketedArg::Constraint(_) => false, | |
332 | AngleBracketedArg::Arg(ast::GenericArg::Type(_) | ast::GenericArg::Const(_)) => true, | |
dfeec247 | 333 | }); |
ba9703b0 XL |
334 | let args = data |
335 | .args | |
336 | .iter() | |
337 | .filter_map(|arg| match arg { | |
923072b8 | 338 | AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx)), |
ba9703b0 XL |
339 | AngleBracketedArg::Constraint(_) => None, |
340 | }) | |
341 | .collect(); | |
342 | let bindings = self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg { | |
923072b8 | 343 | AngleBracketedArg::Constraint(c) => Some(self.lower_assoc_ty_constraint(c, itctx)), |
ba9703b0 XL |
344 | AngleBracketedArg::Arg(_) => None, |
345 | })); | |
17df50a5 | 346 | let ctor = GenericArgsCtor { args, bindings, parenthesized: false, span: data.span }; |
ba9703b0 | 347 | (ctor, !has_non_lt_args && param_mode == ParamMode::Optional) |
dfeec247 XL |
348 | } |
349 | ||
350 | fn lower_parenthesized_parameter_data( | |
351 | &mut self, | |
352 | data: &ParenthesizedArgs, | |
353 | ) -> (GenericArgsCtor<'hir>, bool) { | |
354 | // Switch to `PassThrough` mode for anonymous lifetimes; this | |
355 | // means that we permit things like `&Ref<T>`, where `Ref` has | |
356 | // a hidden lifetime parameter. This is needed for backwards | |
357 | // compatibility, even in contexts like an impl header where | |
358 | // we generally don't permit such things (see #51008). | |
923072b8 FG |
359 | let ParenthesizedArgs { span, inputs, inputs_span, output } = data; |
360 | let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { | |
361 | self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) | |
362 | })); | |
363 | let output_ty = match output { | |
364 | FnRetTy::Ty(ty) => { | |
365 | self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) | |
366 | } | |
367 | FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), | |
368 | }; | |
369 | let args = smallvec![GenericArg::Type(self.ty_tup(*inputs_span, inputs))]; | |
370 | let binding = self.output_ty_binding(output_ty.span, output_ty); | |
371 | ( | |
372 | GenericArgsCtor { | |
373 | args, | |
374 | bindings: arena_vec![self; binding], | |
375 | parenthesized: true, | |
376 | span: data.inputs_span, | |
377 | }, | |
378 | false, | |
379 | ) | |
dfeec247 XL |
380 | } |
381 | ||
382 | /// An associated type binding `Output = $ty`. | |
923072b8 | 383 | pub(crate) fn output_ty_binding( |
dfeec247 XL |
384 | &mut self, |
385 | span: Span, | |
386 | ty: &'hir hir::Ty<'hir>, | |
387 | ) -> hir::TypeBinding<'hir> { | |
388 | let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME); | |
5099ac24 | 389 | let kind = hir::TypeBindingKind::Equality { term: ty.into() }; |
5869c6ff XL |
390 | let args = arena_vec![self;]; |
391 | let bindings = arena_vec![self;]; | |
17df50a5 XL |
392 | let gen_args = self.arena.alloc(hir::GenericArgs { |
393 | args, | |
394 | bindings, | |
395 | parenthesized: false, | |
396 | span_ext: DUMMY_SP, | |
397 | }); | |
94222f64 XL |
398 | hir::TypeBinding { |
399 | hir_id: self.next_id(), | |
400 | gen_args, | |
401 | span: self.lower_span(span), | |
402 | ident, | |
403 | kind, | |
404 | } | |
dfeec247 XL |
405 | } |
406 | } |