1use rustc_ast::{
2 self as ast, AttrVec, DUMMY_NODE_ID, GenericBounds, GenericParam, GenericParamKind, TyKind,
3 WhereClause, WherePredicate, token,
4};
5use rustc_errors::{Applicability, Diag, PResult};
6use rustc_span::{Ident, Span, kw, sym};
7use thin_vec::ThinVec;
8
9use super::{ForceCollect, Parser, Trailing, UsePreAttrPos};
10use crate::diagnostics::{
11 self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
12 UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
13 WhereClauseBeforeTupleStructBodySugg,
14};
15use crate::exp;
16
17enum PredicateKindOrStructBody {
18 PredicateKind(ast::WherePredicateKind),
19 StructBody(ThinVec<ast::FieldDef>),
20}
21
22impl<'a> Parser<'a> {
23 pub(crate) fn parse_lt_param_bounds(&mut self) -> GenericBounds {
29 let mut lifetimes = ThinVec::new();
30 while self.check_lifetime() {
31 lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime()));
32
33 if !self.eat_plus() {
34 break;
35 }
36 }
37 lifetimes
38 }
39
40 fn parse_ty_param(&mut self, preceding_attrs: AttrVec) -> PResult<'a, GenericParam> {
42 let ident = self.parse_ident()?;
43
44 if self.may_recover()
46 && ident.name.as_str().to_ascii_lowercase() == kw::Const.as_str()
47 && self.check_ident()
48 {
50 return self.recover_const_param_with_mistyped_const(preceding_attrs, ident);
51 }
52
53 let mut colon_span = None;
55 let bounds = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
56 colon_span = Some(self.prev_token.span);
57 if self.token.is_keyword(kw::Impl) {
59 let impl_span = self.token.span;
60 let snapshot = self.create_snapshot_for_diagnostic();
61 match self.parse_ty() {
62 Ok(p) => {
63 if let TyKind::ImplTrait(_, bounds) = &p.kind {
64 let span = impl_span.to(self.token.span.shrink_to_lo());
65 let mut err = self.dcx().struct_span_err(
66 span,
67 "expected trait bound, found `impl Trait` type",
68 );
69 err.span_label(span, "not a trait");
70 if let [bound, ..] = &bounds[..] {
71 err.span_suggestion_verbose(
72 impl_span.until(bound.span()),
73 "use the trait bounds directly",
74 String::new(),
75 Applicability::MachineApplicable,
76 );
77 }
78 return Err(err);
79 }
80 }
81 Err(err) => {
82 err.cancel();
83 }
84 }
85 self.restore_snapshot(snapshot);
86 }
87 self.parse_generic_bounds()?
88 } else {
89 ThinVec::new()
90 };
91
92 let default = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) { Some(self.parse_ty()?) } else { None };
93 Ok(GenericParam {
94 ident,
95 id: ast::DUMMY_NODE_ID,
96 attrs: preceding_attrs,
97 bounds,
98 kind: GenericParamKind::Type { default },
99 is_placeholder: false,
100 colon_span,
101 })
102 }
103
104 pub(crate) fn parse_const_param(
105 &mut self,
106 preceding_attrs: AttrVec,
107 ) -> PResult<'a, GenericParam> {
108 let const_span = self.token.span;
109
110 self.expect_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const))?;
111 let ident = self.parse_ident()?;
112 if let Err(mut err) = self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
113 return if self.token.kind == token::Comma || self.token.kind == token::Gt {
114 let span = const_span.to(ident.span);
116 err.span_suggestion_verbose(
117 ident.span.shrink_to_hi(),
118 "you likely meant to write the type of the const parameter here",
119 ": /* Type */".to_string(),
120 Applicability::HasPlaceholders,
121 );
122 let kind = TyKind::Err(err.emit_err());
123 let ty = self.mk_ty(span, kind);
124 Ok(GenericParam {
125 ident,
126 id: ast::DUMMY_NODE_ID,
127 attrs: preceding_attrs,
128 bounds: ThinVec::new(),
129 kind: GenericParamKind::Const { ty, span, default: None },
130 is_placeholder: false,
131 colon_span: None,
132 })
133 } else {
134 Err(err)
135 };
136 }
137 let ty = self.parse_ty()?;
138
139 let default = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) { Some(self.parse_const_arg()?) } else { None };
141 let span = if let Some(ref default) = default {
142 const_span.to(default.value.span)
143 } else {
144 const_span.to(ty.span)
145 };
146
147 Ok(GenericParam {
148 ident,
149 id: ast::DUMMY_NODE_ID,
150 attrs: preceding_attrs,
151 bounds: ThinVec::new(),
152 kind: GenericParamKind::Const { ty, span, default },
153 is_placeholder: false,
154 colon_span: None,
155 })
156 }
157
158 pub(crate) fn recover_const_param_with_mistyped_const(
159 &mut self,
160 preceding_attrs: AttrVec,
161 mistyped_const_ident: Ident,
162 ) -> PResult<'a, GenericParam> {
163 let ident = self.parse_ident()?;
164 self.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon))?;
165 let ty = self.parse_ty()?;
166
167 let default = if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) { Some(self.parse_const_arg()?) } else { None };
169 let span = if let Some(ref default) = default {
170 mistyped_const_ident.span.to(default.value.span)
171 } else {
172 mistyped_const_ident.span.to(ty.span)
173 };
174
175 self.dcx()
176 .struct_span_err(
177 mistyped_const_ident.span,
178 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`const` keyword was mistyped as `{0}`",
mistyped_const_ident.as_str()))
})format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()),
179 )
180 .with_span_suggestion_verbose(
181 mistyped_const_ident.span,
182 "use the `const` keyword",
183 kw::Const,
184 Applicability::MachineApplicable,
185 )
186 .emit();
187
188 Ok(GenericParam {
189 ident,
190 id: ast::DUMMY_NODE_ID,
191 attrs: preceding_attrs,
192 bounds: ThinVec::new(),
193 kind: GenericParamKind::Const { ty, span, default },
194 is_placeholder: false,
195 colon_span: None,
196 })
197 }
198
199 pub(super) fn parse_generic_params(&mut self) -> PResult<'a, ThinVec<ast::GenericParam>> {
205 let mut params = ThinVec::new();
206 let mut done = false;
207 let prev = self.parsing_generics;
208 self.parsing_generics = true;
209 while !done {
210 let attrs = self.parse_outer_attributes()?;
211 let param = match self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
212 if this.eat_keyword_noexpect(kw::SelfUpper) {
213 this.dcx()
216 .emit_err(UnexpectedSelfInGenericParameters { span: this.prev_token.span });
217
218 let _ = this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
220 }
221
222 let param = if this.check_lifetime() {
223 let lifetime = this.expect_lifetime();
224 let (colon_span, bounds) = if this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
226 (Some(this.prev_token.span), this.parse_lt_param_bounds())
227 } else {
228 (None, ThinVec::new())
229 };
230
231 if this.check_noexpect(&token::Eq) && this.look_ahead(1, |t| t.is_lifetime()) {
232 let lo = this.token.span;
233 this.bump(); this.bump(); let span = lo.to(this.prev_token.span);
237 this.dcx().emit_err(UnexpectedDefaultValueForLifetimeInGenericParameters {
238 span,
239 });
240 }
241
242 Some(ast::GenericParam {
243 ident: lifetime.ident,
244 id: lifetime.id,
245 attrs,
246 bounds,
247 kind: ast::GenericParamKind::Lifetime,
248 is_placeholder: false,
249 colon_span,
250 })
251 } else if this.check_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Const,
token_type: crate::parser::token_type::TokenType::KwConst,
}exp!(Const)) {
252 Some(this.parse_const_param(attrs)?)
254 } else if this.check_ident() {
255 Some(this.parse_ty_param(attrs)?)
257 } else if this.token.can_begin_type() {
258 let snapshot = this.create_snapshot_for_diagnostic();
260 let lo = this.token.span;
261 match this.parse_ty_where_predicate_kind() {
262 Ok(_) => {
263 this.dcx().emit_err(diagnostics::BadAssocTypeBounds {
264 span: lo.to(this.prev_token.span),
265 });
266 }
268 Err(err) => {
269 err.cancel();
270 this.restore_snapshot(snapshot);
272 }
273 }
274 return Ok((None, Trailing::No, UsePreAttrPos::No));
275 } else {
276 if !attrs.is_empty() {
278 if !params.is_empty() {
279 this.dcx()
280 .emit_err(diagnostics::AttrAfterGeneric { span: attrs[0].span });
281 } else {
282 this.dcx()
283 .emit_err(diagnostics::AttrWithoutGenerics { span: attrs[0].span });
284 }
285 }
286 return Ok((None, Trailing::No, UsePreAttrPos::No));
287 };
288
289 if !this.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma)) {
290 done = true;
291 }
292 Ok((param, Trailing::No, UsePreAttrPos::No))
294 }) {
295 Ok(param) => param,
296 Err(err) => {
297 self.parsing_generics = prev;
298 return Err(err);
299 }
300 };
301
302 if let Some(param) = param {
303 params.push(param);
304 } else {
305 break;
306 }
307 }
308 self.parsing_generics = prev;
309 Ok(params)
310 }
311
312 pub(super) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> {
320 if self.eat_noexpect(&token::PathSep) {
323 self.dcx()
324 .emit_err(diagnostics::InvalidPathSepInFnDefinition { span: self.prev_token.span });
325 }
326
327 let span_lo = self.token.span;
328 let (params, span) = if self.eat_lt() {
329 let params = self.parse_generic_params()?;
330 self.expect_gt_or_maybe_suggest_closing_generics(¶ms)?;
331 (params, span_lo.to(self.prev_token.span))
332 } else {
333 (ThinVec::new(), self.prev_token.span.shrink_to_hi())
334 };
335 Ok(ast::Generics {
336 params,
337 where_clause: WhereClause {
338 has_where_token: false,
339 predicates: ThinVec::new(),
340 span: self.prev_token.span.shrink_to_hi(),
341 },
342 span,
343 })
344 }
345
346 pub(super) fn parse_contract(&mut self) -> PResult<'a, Option<Box<ast::FnContract>>> {
349 let (declarations, requires) = self.parse_contract_requires()?;
350 let ensures = self.parse_contract_ensures()?;
351
352 if requires.is_none() && ensures.is_none() {
353 Ok(None)
354 } else {
355 Ok(Some(Box::new(ast::FnContract { declarations, requires, ensures })))
356 }
357 }
358
359 fn parse_contract_requires(
360 &mut self,
361 ) -> PResult<'a, (ThinVec<rustc_ast::Stmt>, Option<Box<rustc_ast::Expr>>)> {
362 Ok(if self.eat_keyword_noexpect(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::ContractRequires,
token_type: crate::parser::token_type::TokenType::KwContractRequires,
}exp!(ContractRequires).kw) {
363 self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
364 let mut decls_and_precond = self.parse_block()?;
365
366 let precond = match decls_and_precond.stmts.pop() {
367 Some(precond) => match precond.kind {
368 rustc_ast::StmtKind::Expr(expr) => expr,
369 _ => self.mk_unit_expr(decls_and_precond.span),
372 },
373 None => self.mk_unit_expr(decls_and_precond.span),
374 };
375 let precond = self.mk_closure_expr(precond.span, precond);
376 let decls = decls_and_precond.stmts;
377 (decls, Some(precond))
378 } else {
379 (Default::default(), None)
380 })
381 }
382
383 fn parse_contract_ensures(&mut self) -> PResult<'a, Option<Box<rustc_ast::Expr>>> {
384 Ok(if self.eat_keyword_noexpect(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::ContractEnsures,
token_type: crate::parser::token_type::TokenType::KwContractEnsures,
}exp!(ContractEnsures).kw) {
385 self.psess.gated_spans.gate(sym::contracts_internals, self.prev_token.span);
386 let postcond = self.parse_expr()?;
387 Some(postcond)
388 } else {
389 None
390 })
391 }
392
393 pub(super) fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> {
399 self.parse_where_clause_common(None).map(|(clause, _)| clause)
400 }
401
402 pub(super) fn parse_struct_where_clause(
403 &mut self,
404 struct_name: Ident,
405 body_insertion_point: Span,
406 ) -> PResult<'a, (WhereClause, Option<ThinVec<ast::FieldDef>>)> {
407 self.parse_where_clause_common(Some((struct_name, body_insertion_point)))
408 }
409
410 fn parse_where_clause_common(
411 &mut self,
412 struct_: Option<(Ident, Span)>,
413 ) -> PResult<'a, (WhereClause, Option<ThinVec<ast::FieldDef>>)> {
414 if !self.eat_keyword(crate::parser::token_type::ExpKeywordPair {
kw: rustc_span::symbol::kw::Where,
token_type: crate::parser::token_type::TokenType::KwWhere,
}exp!(Where)) {
415 return Ok((
416 WhereClause {
417 has_where_token: false,
418 predicates: ThinVec::new(),
419 span: self.prev_token.span.shrink_to_hi(),
420 },
421 None,
422 ));
423 }
424
425 if self.eat_noexpect(&token::Colon) {
426 let colon_span = self.prev_token.span;
427 self.dcx()
428 .struct_span_err(colon_span, "unexpected colon after `where`")
429 .with_span_suggestion_short(
430 colon_span,
431 "remove the colon",
432 "",
433 Applicability::MachineApplicable,
434 )
435 .emit();
436 }
437
438 let where_lo = self.prev_token.span;
439
440 if self.choose_generics_over_qpath(0) {
444 let generics = self.parse_generics()?;
445 self.dcx().emit_err(diagnostics::WhereOnGenerics { span: generics.span });
446 }
447
448 let (predicates, tuple_struct_body) =
449 self.parse_where_clause_predicates(struct_, where_lo)?;
450 let where_clause = WhereClause {
451 has_where_token: true,
452 predicates,
453 span: where_lo.to(self.prev_token.span),
454 };
455 Ok((where_clause, tuple_struct_body))
456 }
457
458 pub(super) fn parse_where_clause_predicates(
459 &mut self,
460 struct_: Option<(Ident, Span)>,
461 where_lo: Span,
462 ) -> PResult<'a, (ThinVec<WherePredicate>, Option<ThinVec<ast::FieldDef>>)> {
463 let mut predicates = ThinVec::new();
464 let mut tuple_struct_body = None;
465
466 loop {
467 let where_sp = where_lo.to(self.prev_token.span);
468 let attrs = self.parse_outer_attributes()?;
469 let pred_lo = self.token.span;
470 let predicate = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| {
471 for attr in &attrs {
472 self.psess.gated_spans.gate(sym::where_clause_attrs, attr.span);
473 }
474 let kind = if this.check_lifetime() && this.look_ahead(1, |t| !t.is_like_plus()) {
475 let lifetime = this.expect_lifetime();
476 this.expect(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon))?;
478 let bounds = this.parse_lt_param_bounds();
479 Some(ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate {
480 lifetime,
481 bounds,
482 }))
483 } else if this.check_type() {
484 match this.parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
485 struct_, pred_lo, where_sp,
486 )? {
487 PredicateKindOrStructBody::PredicateKind(kind) => Some(kind),
488 PredicateKindOrStructBody::StructBody(body) => {
489 tuple_struct_body = Some(body);
490 None
491 }
492 }
493 } else {
494 if let [.., last] = &attrs[..] {
495 if last.is_doc_comment() {
496 this.dcx().emit_err(diagnostics::DocCommentDoesNotDocumentAnything {
497 span: last.span,
498 missing_comma: None,
499 });
500 } else {
501 this.dcx().emit_err(diagnostics::AttrWithoutWherePredicates {
502 span: last.span,
503 });
504 }
505 }
506 None
507 };
508 let predicate = kind.map(|kind| ast::WherePredicate {
509 attrs,
510 kind,
511 id: DUMMY_NODE_ID,
512 span: pred_lo.to(this.prev_token.span),
513 is_placeholder: false,
514 });
515 Ok((predicate, Trailing::No, UsePreAttrPos::No))
516 })?;
517 match predicate {
518 Some(predicate) => predicates.push(predicate),
519 None => break,
520 }
521
522 let prev_token = self.prev_token.span;
523 let ate_comma = self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Comma,
token_type: crate::parser::token_type::TokenType::Comma,
}exp!(Comma));
524
525 if self.eat_keyword_noexpect(kw::Where) {
526 self.dcx().emit_err(MultipleWhereClauses {
527 span: self.token.span,
528 previous: pred_lo,
529 between: prev_token.shrink_to_hi().to(self.prev_token.span),
530 });
531 } else if !ate_comma {
532 break;
533 }
534 }
535
536 Ok((predicates, tuple_struct_body))
537 }
538
539 fn parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
540 &mut self,
541 struct_: Option<(Ident, Span)>,
542 pred_lo: Span,
543 where_sp: Span,
544 ) -> PResult<'a, PredicateKindOrStructBody> {
545 let mut snapshot = None;
546
547 if let Some(struct_) = struct_
548 && self.may_recover()
549 && self.token == token::OpenParen
550 {
551 snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
552 };
553
554 match self.parse_ty_where_predicate_kind() {
555 Ok(pred) => Ok(PredicateKindOrStructBody::PredicateKind(
556 ast::WherePredicateKind::BoundPredicate(pred),
557 )),
558 Err(type_err) => {
559 let Some(((struct_name, body_insertion_point), mut snapshot)) = snapshot else {
560 return Err(type_err);
561 };
562
563 match snapshot.parse_tuple_struct_body() {
565 Ok(body)
571 if #[allow(non_exhaustive_omitted_patterns)] match snapshot.token.kind {
token::Semi | token::Eof => true,
_ => false,
}matches!(snapshot.token.kind, token::Semi | token::Eof)
572 || snapshot.token.can_begin_item() =>
573 {
574 type_err.cancel();
575
576 let body_sp = pred_lo.to(snapshot.prev_token.span);
577 let map = self.psess.source_map();
578
579 self.dcx().emit_err(WhereClauseBeforeTupleStructBody {
580 span: where_sp,
581 name: struct_name.span,
582 body: body_sp,
583 sugg: map.span_to_snippet(body_sp).ok().map(|body| {
584 WhereClauseBeforeTupleStructBodySugg {
585 left: body_insertion_point.shrink_to_hi(),
586 snippet: body,
587 right: map.end_point(where_sp).to(body_sp),
588 }
589 }),
590 });
591
592 self.restore_snapshot(snapshot);
593 Ok(PredicateKindOrStructBody::StructBody(body))
594 }
595 Ok(_) => Err(type_err),
596 Err(body_err) => {
597 body_err.cancel();
598 Err(type_err)
599 }
600 }
601 }
602 }
603 }
604
605 pub(crate) fn parse_ty_where_predicate_kind(
606 &mut self,
607 ) -> PResult<'a, ast::WhereBoundPredicate> {
608 let (bound_vars, _) = self.parse_higher_ranked_binder()?;
616
617 let ty = self.parse_ty_for_where_clause()?;
618
619 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Colon,
token_type: crate::parser::token_type::TokenType::Colon,
}exp!(Colon)) {
620 let bounds = self.parse_generic_bounds()?;
622
623 return Ok(ast::WhereBoundPredicate {
624 bound_generic_params: bound_vars,
625 bounded_ty: ty,
626 bounds,
627 });
628 }
629
630 if self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::Eq,
token_type: crate::parser::token_type::TokenType::Eq,
}exp!(Eq)) || self.eat(crate::parser::token_type::ExpTokenPair {
tok: rustc_ast::token::EqEq,
token_type: crate::parser::token_type::TokenType::EqEq,
}exp!(EqEq)) {
633 let lhs_ty = ty;
634 let rhs_ty = self.parse_ty()?;
635
636 let _ = bound_vars;
639
640 let mut diag = self.dcx().struct_span_err(
641 lhs_ty.span.to(rhs_ty.span),
642 "general type equality constraints are not supported",
643 );
644 diag.note(
645 "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
646 for more information",
647 );
648 diag.span(lhs_ty.span.to(rhs_ty.span));
649 diag.span_label(lhs_ty.span.to(rhs_ty.span), "not supported");
650
651 suggest_replacing_equality_pred_with_assoc_item_constraint(&mut diag, *lhs_ty, *rhs_ty);
652
653 return Err(diag);
654 }
655
656 self.maybe_recover_bounds_doubled_colon(&ty)?;
657 self.unexpected_any()
658 }
659
660 pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
661 self.look_ahead(start, |t| t == &token::Lt)
680 && (self.look_ahead(start + 1, |t| t == &token::Pound || t == &token::Gt)
681 || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
682 && self.look_ahead(start + 2, |t| {
683 #[allow(non_exhaustive_omitted_patterns)] match t.kind {
token::Gt | token::Comma | token::Colon | token::Eq => true,
_ => false,
}matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
684 || t.kind == token::Question
687 })
688 || self.is_keyword_ahead(start + 1, &[kw::Const]))
689 }
690}
691
692fn suggest_replacing_equality_pred_with_assoc_item_constraint(
693 diag: &mut Diag<'_>,
694 lhs_ty: ast::Ty,
695 rhs_ty: ast::Ty,
696) {
697 let TyKind::Path(qself, ast::Path { segments, .. }) = lhs_ty.kind else { return };
698
699 let mut parts = Vec::new();
700 let applicability = match qself {
701 None if let [self_ty_seg, assoc_item_seg] = &segments[..]
703 && self_ty_seg.ident.name != kw::PathRoot =>
704 {
705 parts.push((
706 self_ty_seg.span().between(assoc_item_seg.span()),
707 ": /* Trait */</* ... */".into(),
708 ));
709 Applicability::HasPlaceholders
710 }
711 Some(qself) if let [assoc_item_seg] = &segments[qself.position..] => {
712 parts.push((lhs_ty.span.until(qself.ty.span), String::new()));
713
714 if let trait_segs @ [.., final_trait_seg] = &segments[..qself.position] {
716 parts.push((qself.ty.span.between(trait_segs[0].span()), ": ".into()));
717 let (span, snippet) = match &final_trait_seg.args {
718 Some(args) => {
719 let ast::GenericArgs::AngleBracketed(args) = args else { return };
720 let Some(args) = args.args.last() else { return };
721 (args.span(), ", ")
722 }
723 None => (final_trait_seg.span(), "<"),
724 };
725 parts.push((span.between(assoc_item_seg.span()), snippet.into()));
726 Applicability::MaybeIncorrect
727 }
728 else {
730 parts.push((
731 qself.ty.span.between(assoc_item_seg.span()),
732 ": /* Trait */</* ... */".into(),
733 ));
734 Applicability::HasPlaceholders
735 }
736 }
737 _ => return,
738 };
739
740 parts.push((lhs_ty.span.between(rhs_ty.span), " = ".into()));
741 parts.push((rhs_ty.span.shrink_to_hi(), ">".into()));
742
743 diag.multipart_suggestion(
744 "replace it with an associated item constraint if possible",
745 parts,
746 applicability,
747 );
748}