1use std::sync::Arc;
2
3use rustc_ast::{self as ast, *};
4use rustc_hir::def::{DefKind, PartialRes, PerNS, Res};
5use rustc_hir::def_id::DefId;
6use rustc_hir::{self as hir, GenericArg};
7use rustc_middle::{span_bug, ty};
8use rustc_session::parse::add_feature_diagnostics;
9use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
10use smallvec::smallvec;
11use tracing::{debug, instrument};
12
13use super::errors::{
14 AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation,
15 GenericTypeWithParentheses, RTNSuggestion, UseAngleBrackets,
16};
17use super::{
18 AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition,
19 LifetimeRes, LoweringContext, ParamMode, ResolverAstLoweringExt,
20};
21
22impl<'a, 'hir> LoweringContext<'a, 'hir> {
23 #[instrument(level = "trace", skip(self))]
24 pub(crate) fn lower_qpath(
25 &mut self,
26 id: NodeId,
27 qself: &Option<ptr::P<QSelf>>,
28 p: &Path,
29 param_mode: ParamMode,
30 allow_return_type_notation: AllowReturnTypeNotation,
31 itctx: ImplTraitContext,
32 modifiers: Option<ast::TraitBoundModifiers>,
34 ) -> hir::QPath<'hir> {
35 let qself_position = qself.as_ref().map(|q| q.position);
36 let qself = qself
37 .as_ref()
38 .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
40
41 let partial_res =
42 self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
43 let base_res = partial_res.base_res();
44 let unresolved_segments = partial_res.unresolved_segments();
45
46 let mut res = self.lower_res(base_res);
47
48 if let Some(TraitBoundModifiers { asyncness: BoundAsyncness::Async(_), .. }) = modifiers {
50 match res {
51 Res::Def(DefKind::Trait, def_id) => {
52 if let Some(async_def_id) = self.map_trait_to_async_trait(def_id) {
53 res = Res::Def(DefKind::Trait, async_def_id);
54 } else {
55 self.dcx().emit_err(AsyncBoundOnlyForFnTraits { span: p.span });
56 }
57 }
58 Res::Err => {
59 }
61 _ => {
62 self.dcx().emit_err(AsyncBoundNotOnTrait { span: p.span, descr: res.descr() });
66 }
67 }
68 }
69
70 let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res
73 && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some()
74 {
75 Some(Arc::clone(&self.allow_async_fn_traits))
76 } else {
77 None
78 };
79
80 let itctx = |i| {
83 if i + 1 == p.segments.len() {
84 itctx
85 } else {
86 ImplTraitContext::Disallowed(ImplTraitPosition::Path)
87 }
88 };
89
90 let path_span_lo = p.span.shrink_to_lo();
91 let proj_start = p.segments.len() - unresolved_segments;
92 let path = self.arena.alloc(hir::Path {
93 res,
94 segments: self.arena.alloc_from_iter(p.segments[..proj_start].iter().enumerate().map(
95 |(i, segment)| {
96 let param_mode = match (qself_position, param_mode) {
97 (Some(j), ParamMode::Optional) if i < j => {
98 ParamMode::Explicit
102 }
103 _ => param_mode,
104 };
105
106 let generic_args_mode = match base_res {
107 Res::Def(DefKind::Trait, _) if i + 1 == proj_start => {
109 GenericArgsMode::ParenSugar
110 }
111 Res::Def(DefKind::AssocFn, _)
113 | Res::Def(DefKind::AssocConst, _)
114 | Res::Def(DefKind::AssocTy, _)
115 if i + 2 == proj_start =>
116 {
117 GenericArgsMode::ParenSugar
118 }
119 Res::Def(DefKind::AssocFn, _) if i + 1 == proj_start => {
120 match allow_return_type_notation {
121 AllowReturnTypeNotation::Yes => GenericArgsMode::ReturnTypeNotation,
122 AllowReturnTypeNotation::No => GenericArgsMode::Err,
123 }
124 }
125 Res::Err => GenericArgsMode::Silence,
127 _ => GenericArgsMode::Err,
129 };
130
131 self.lower_path_segment(
132 p.span,
133 segment,
134 param_mode,
135 generic_args_mode,
136 itctx(i),
137 bound_modifier_allowed_features.clone(),
138 )
139 },
140 )),
141 span: self.lower_span(
142 p.segments[..proj_start]
143 .last()
144 .map_or(path_span_lo, |segment| path_span_lo.to(segment.span())),
145 ),
146 });
147
148 if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
149 path.span = self.mark_span_with_reason(
150 DesugaringKind::BoundModifier,
151 path.span,
152 Some(bound_modifier_allowed_features),
153 );
154 }
155
156 if unresolved_segments == 0 {
159 return hir::QPath::Resolved(qself, path);
160 }
161
162 let mut ty = if path.segments.is_empty() {
164 qself.expect("missing QSelf for <T>::...")
167 } else {
168 let new_id = self.next_id();
172 self.arena.alloc(self.ty_path(new_id, path.span, hir::QPath::Resolved(qself, path)))
173 };
174
175 for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
186 let generic_args_mode = if i + 1 == p.segments.len()
188 && matches!(allow_return_type_notation, AllowReturnTypeNotation::Yes)
189 {
190 GenericArgsMode::ReturnTypeNotation
191 } else {
192 GenericArgsMode::Err
193 };
194
195 let hir_segment = self.arena.alloc(self.lower_path_segment(
196 p.span,
197 segment,
198 param_mode,
199 generic_args_mode,
200 itctx(i),
201 None,
202 ));
203 let qpath = hir::QPath::TypeRelative(ty, hir_segment);
204
205 if i == p.segments.len() - 1 {
207 return qpath;
208 }
209
210 let new_id = self.next_id();
212 ty = self.arena.alloc(self.ty_path(new_id, path_span_lo.to(segment.span()), qpath));
213 }
214
215 self.dcx().span_bug(
218 p.span,
219 format!(
220 "lower_qpath: no final extension segment in {}..{}",
221 proj_start,
222 p.segments.len()
223 ),
224 );
225 }
226
227 pub(crate) fn lower_use_path(
228 &mut self,
229 res: PerNS<Option<Res>>,
230 p: &Path,
231 param_mode: ParamMode,
232 ) -> &'hir hir::UsePath<'hir> {
233 assert!(!res.is_empty());
234 self.arena.alloc(hir::UsePath {
235 res,
236 segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
237 self.lower_path_segment(
238 p.span,
239 segment,
240 param_mode,
241 GenericArgsMode::Err,
242 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
243 None,
244 )
245 })),
246 span: self.lower_span(p.span),
247 })
248 }
249
250 pub(crate) fn lower_path_segment(
251 &mut self,
252 path_span: Span,
253 segment: &PathSegment,
254 param_mode: ParamMode,
255 generic_args_mode: GenericArgsMode,
256 itctx: ImplTraitContext,
257 bound_modifier_allowed_features: Option<Arc<[Symbol]>>,
261 ) -> hir::PathSegment<'hir> {
262 debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
263 let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
264 match generic_args {
265 GenericArgs::AngleBracketed(data) => {
266 self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
267 }
268 GenericArgs::Parenthesized(data) => match generic_args_mode {
269 GenericArgsMode::ReturnTypeNotation => {
270 let err = match (&data.inputs[..], &data.output) {
271 ([_, ..], FnRetTy::Default(_)) => {
272 BadReturnTypeNotation::Inputs { span: data.inputs_span }
273 }
274 ([], FnRetTy::Default(_)) => {
275 BadReturnTypeNotation::NeedsDots { span: data.inputs_span }
276 }
277 (_, FnRetTy::Ty(ty)) => {
279 let span = data.inputs_span.shrink_to_hi().to(ty.span);
280 BadReturnTypeNotation::Output {
281 span,
282 suggestion: RTNSuggestion {
283 output: span,
284 input: data.inputs_span,
285 },
286 }
287 }
288 };
289 let mut err = self.dcx().create_err(err);
290 if !self.tcx.features().return_type_notation()
291 && self.tcx.sess.is_nightly_build()
292 {
293 add_feature_diagnostics(
294 &mut err,
295 &self.tcx.sess,
296 sym::return_type_notation,
297 );
298 }
299 err.emit();
300 (
301 GenericArgsCtor {
302 args: Default::default(),
303 constraints: &[],
304 parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
305 span: path_span,
306 },
307 false,
308 )
309 }
310 GenericArgsMode::ParenSugar | GenericArgsMode::Silence => self
311 .lower_parenthesized_parameter_data(
312 data,
313 itctx,
314 bound_modifier_allowed_features,
315 ),
316 GenericArgsMode::Err => {
317 let sub = if !data.inputs.is_empty() {
319 let open_param = data.inputs_span.shrink_to_lo().to(data
321 .inputs
322 .first()
323 .unwrap()
324 .span
325 .shrink_to_lo());
326 let close_param = data
328 .inputs
329 .last()
330 .unwrap()
331 .span
332 .shrink_to_hi()
333 .to(data.inputs_span.shrink_to_hi());
334
335 Some(UseAngleBrackets { open_param, close_param })
336 } else {
337 None
338 };
339 self.dcx().emit_err(GenericTypeWithParentheses { span: data.span, sub });
340 (
341 self.lower_angle_bracketed_parameter_data(
342 &data.as_angle_bracketed_args(),
343 param_mode,
344 itctx,
345 )
346 .0,
347 false,
348 )
349 }
350 },
351 GenericArgs::ParenthesizedElided(span) => {
352 match generic_args_mode {
353 GenericArgsMode::ReturnTypeNotation | GenericArgsMode::Silence => {
354 }
356 GenericArgsMode::ParenSugar | GenericArgsMode::Err => {
357 self.dcx().emit_err(BadReturnTypeNotation::Position { span: *span });
358 }
359 }
360 (
361 GenericArgsCtor {
362 args: Default::default(),
363 constraints: &[],
364 parenthesized: hir::GenericArgsParentheses::ReturnTypeNotation,
365 span: *span,
366 },
367 false,
368 )
369 }
370 }
371 } else {
372 (
373 GenericArgsCtor {
374 args: Default::default(),
375 constraints: &[],
376 parenthesized: hir::GenericArgsParentheses::No,
377 span: path_span.shrink_to_hi(),
378 },
379 param_mode == ParamMode::Optional,
380 )
381 };
382
383 let has_lifetimes =
384 generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));
385
386 if generic_args.parenthesized != hir::GenericArgsParentheses::ParenSugar && !has_lifetimes {
388 self.maybe_insert_elided_lifetimes_in_path(
389 path_span,
390 segment.id,
391 segment.ident.span,
392 &mut generic_args,
393 );
394 }
395
396 let res = self.expect_full_res(segment.id);
397 let hir_id = self.lower_node_id(segment.id);
398 debug!(
399 "lower_path_segment: ident={:?} original-id={:?} new-id={:?}",
400 segment.ident, segment.id, hir_id,
401 );
402
403 hir::PathSegment {
404 ident: self.lower_ident(segment.ident),
405 hir_id,
406 res: self.lower_res(res),
407 infer_args,
408 args: if generic_args.is_empty() && generic_args.span.is_empty() {
409 None
410 } else {
411 Some(generic_args.into_generic_args(self))
412 },
413 }
414 }
415
416 fn maybe_insert_elided_lifetimes_in_path(
417 &mut self,
418 path_span: Span,
419 segment_id: NodeId,
420 segment_ident_span: Span,
421 generic_args: &mut GenericArgsCtor<'hir>,
422 ) {
423 let (start, end) = match self.resolver.get_lifetime_res(segment_id) {
424 Some(LifetimeRes::ElidedAnchor { start, end }) => (start, end),
425 None => return,
426 Some(res) => {
427 span_bug!(path_span, "expected an elided lifetime to insert. found {res:?}")
428 }
429 };
430 let expected_lifetimes = end.as_usize() - start.as_usize();
431 debug!(expected_lifetimes);
432
433 let (elided_lifetime_span, angle_brackets) = if generic_args.span.is_empty() {
436 (
440 segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span),
441 hir::AngleBrackets::Missing,
442 )
443 } else {
444 (
446 generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(),
447 if generic_args.is_empty() {
448 hir::AngleBrackets::Empty
449 } else {
450 hir::AngleBrackets::Full
451 },
452 )
453 };
454
455 generic_args.args.insert_many(
456 0,
457 (start..end).map(|id| {
458 let l =
459 self.lower_lifetime_hidden_in_path(id, elided_lifetime_span, angle_brackets);
460 GenericArg::Lifetime(l)
461 }),
462 );
463 }
464
465 pub(crate) fn lower_angle_bracketed_parameter_data(
466 &mut self,
467 data: &AngleBracketedArgs,
468 param_mode: ParamMode,
469 itctx: ImplTraitContext,
470 ) -> (GenericArgsCtor<'hir>, bool) {
471 let has_non_lt_args = data.args.iter().any(|arg| match arg {
472 AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_))
473 | AngleBracketedArg::Constraint(_) => false,
474 AngleBracketedArg::Arg(ast::GenericArg::Type(_) | ast::GenericArg::Const(_)) => true,
475 });
476 let args = data
477 .args
478 .iter()
479 .filter_map(|arg| match arg {
480 AngleBracketedArg::Arg(arg) => Some(self.lower_generic_arg(arg, itctx)),
481 AngleBracketedArg::Constraint(_) => None,
482 })
483 .collect();
484 let constraints =
485 self.arena.alloc_from_iter(data.args.iter().filter_map(|arg| match arg {
486 AngleBracketedArg::Constraint(c) => {
487 Some(self.lower_assoc_item_constraint(c, itctx))
488 }
489 AngleBracketedArg::Arg(_) => None,
490 }));
491 let ctor = GenericArgsCtor {
492 args,
493 constraints,
494 parenthesized: hir::GenericArgsParentheses::No,
495 span: data.span,
496 };
497 (ctor, !has_non_lt_args && param_mode == ParamMode::Optional)
498 }
499
500 fn lower_parenthesized_parameter_data(
501 &mut self,
502 data: &ParenthesizedArgs,
503 itctx: ImplTraitContext,
504 bound_modifier_allowed_features: Option<Arc<[Symbol]>>,
505 ) -> (GenericArgsCtor<'hir>, bool) {
506 let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
512 let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
513 self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
514 }));
515 let output_ty = match output {
516 FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
522 if self.tcx.features().impl_trait_in_fn_trait_return() {
523 self.lower_ty(ty, itctx)
524 } else {
525 self.lower_ty(
526 ty,
527 ImplTraitContext::FeatureGated(
528 ImplTraitPosition::FnTraitReturn,
529 sym::impl_trait_in_fn_trait_return,
530 ),
531 )
532 }
533 }
534 FnRetTy::Ty(ty) => {
535 self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
536 }
537 FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
538 };
539 let args = smallvec![GenericArg::Type(
540 self.arena.alloc(self.ty_tup(*inputs_span, inputs)).try_as_ambig_ty().unwrap()
541 )];
542
543 let mut output_span = output_ty.span;
546 if let Some(bound_modifier_allowed_features) = bound_modifier_allowed_features {
547 output_span = self.mark_span_with_reason(
548 DesugaringKind::BoundModifier,
549 output_span,
550 Some(bound_modifier_allowed_features),
551 );
552 }
553 let constraint = self.assoc_ty_binding(sym::Output, output_span, output_ty);
554
555 (
556 GenericArgsCtor {
557 args,
558 constraints: arena_vec![self; constraint],
559 parenthesized: hir::GenericArgsParentheses::ParenSugar,
560 span: data.inputs_span,
561 },
562 false,
563 )
564 }
565
566 pub(crate) fn assoc_ty_binding(
568 &mut self,
569 assoc_ty_name: rustc_span::Symbol,
570 span: Span,
571 ty: &'hir hir::Ty<'hir>,
572 ) -> hir::AssocItemConstraint<'hir> {
573 let ident = Ident::with_dummy_span(assoc_ty_name);
574 let kind = hir::AssocItemConstraintKind::Equality { term: ty.into() };
575 let args = arena_vec![self;];
576 let constraints = arena_vec![self;];
577 let gen_args = self.arena.alloc(hir::GenericArgs {
578 args,
579 constraints,
580 parenthesized: hir::GenericArgsParentheses::No,
581 span_ext: DUMMY_SP,
582 });
583 hir::AssocItemConstraint {
584 hir_id: self.next_id(),
585 gen_args,
586 span: self.lower_span(span),
587 ident,
588 kind,
589 }
590 }
591
592 fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<DefId> {
599 let lang_items = self.tcx.lang_items();
600 match self.tcx.fn_trait_kind_from_def_id(def_id)? {
601 ty::ClosureKind::Fn => lang_items.async_fn_trait(),
602 ty::ClosureKind::FnMut => lang_items.async_fn_mut_trait(),
603 ty::ClosureKind::FnOnce => lang_items.async_fn_once_trait(),
604 }
605 }
606}