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