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