]>
Commit | Line | Data |
---|---|---|
46de9a89 FG |
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_errors::{struct_span_err, Applicability}; | |
7 | use rustc_hir as hir; | |
8 | use rustc_hir::def::{DefKind, PartialRes, Res}; | |
9 | use rustc_hir::def_id::DefId; | |
10 | use rustc_hir::GenericArg; | |
11 | use rustc_session::lint::BuiltinLintDiagnostics; | |
12 | use rustc_span::Span; | |
13 | use syntax::ast::{self, *}; | |
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.len() > 0 { | |
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 | FunctionRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()), | |
401 | FunctionRetTy::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 | } |