File is large — showing lines 1–2,000 of 2,669.
1//! This module provides primitives for showing type and function parameter information when editing2//! a call or use-site.34use std::collections::BTreeSet;56use either::Either;7use hir::{8 AssocItem, DisplayTarget, GenericDef, GenericParam, HirDisplay, ModuleDef, PathResolution,9 Semantics, Trait,10};11use ide_db::{12 FilePosition, FxIndexMap,13 active_parameter::{callable_for_arg_list, generic_def_for_node},14 documentation::{Documentation, HasDocs},15};16use itertools::Itertools;17use span::Edition;18use stdx::format_to;19use syntax::{20 AstNode, Direction, NodeOrToken, SyntaxElementChildren, SyntaxNode, SyntaxToken, T, TextRange,21 TextSize, ToSmolStr, algo,22 ast::{self, AstChildren},23 match_ast,24};2526use crate::RootDatabase;2728/// Contains information about an item signature as seen from a use site.29///30/// This includes the "active parameter", which is the parameter whose value is currently being31/// edited.32#[derive(Debug)]33pub struct SignatureHelp {34 pub doc: Option<Documentation<'static>>,35 pub signature: String,36 pub active_parameter: Option<usize>,37 parameters: Vec<TextRange>,38}3940impl SignatureHelp {41 pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {42 self.parameters.iter().map(move |&it| &self.signature[it])43 }4445 pub fn parameter_ranges(&self) -> &[TextRange] {46 &self.parameters47 }4849 fn push_call_param(&mut self, param: &str) {50 self.push_param("(", param);51 }5253 fn push_generic_param(&mut self, param: &str) {54 self.push_param("<", param);55 }5657 fn push_record_field(&mut self, param: &str) {58 self.push_param("{ ", param);59 }6061 fn push_param(&mut self, opening_delim: &str, param: &str) {62 if !self.signature.ends_with(opening_delim) {63 self.signature.push_str(", ");64 }65 let start = TextSize::of(&self.signature);66 self.signature.push_str(param);67 let end = TextSize::of(&self.signature);68 self.parameters.push(TextRange::new(start, end))69 }70}7172/// Computes parameter information for the given position.73pub(crate) fn signature_help(74 db: &RootDatabase,75 FilePosition { file_id, offset }: FilePosition,76) -> Option<SignatureHelp> {77 let sema = Semantics::new(db);78 let file = sema.parse_guess_edition(file_id);79 let file = file.syntax();80 let token = file81 .token_at_offset(offset)82 .left_biased()83 // if the cursor is sandwiched between two space tokens and the call is unclosed84 // this prevents us from leaving the CallExpression85 .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;86 let token = sema.descend_into_macros_single_exact(token);87 let edition = sema.attach_first_edition(file_id).edition(db);88 let display_target = sema.first_crate(file_id)?.to_display_target(db);8990 for node in token.parent_ancestors() {91 match_ast! {92 match node {93 ast::ArgList(arg_list) => {94 let cursor_outside = arg_list.r_paren_token().as_ref() == Some(&token);95 if cursor_outside {96 continue;97 }98 return signature_help_for_call(&sema, arg_list, token, edition, display_target);99 },100 ast::GenericArgList(garg_list) => {101 let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token);102 if cursor_outside {103 continue;104 }105 return signature_help_for_generics(&sema, garg_list, token, edition, display_target);106 },107 ast::RecordExpr(record) => {108 let cursor_outside = record.record_expr_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);109 if cursor_outside {110 continue;111 }112 return signature_help_for_record_lit(&sema, record, token, edition, display_target);113 },114 ast::RecordPat(record) => {115 let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token);116 if cursor_outside {117 continue;118 }119 return signature_help_for_record_pat(&sema, record, token, edition, display_target);120 },121 ast::TupleStructPat(tuple_pat) => {122 let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);123 if cursor_outside {124 continue;125 }126 return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition, display_target);127 },128 ast::TuplePat(tuple_pat) => {129 let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token);130 if cursor_outside {131 continue;132 }133 return signature_help_for_tuple_pat(&sema, tuple_pat, token, display_target);134 },135 ast::TupleExpr(tuple_expr) => {136 let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token);137 if cursor_outside {138 continue;139 }140 return signature_help_for_tuple_expr(&sema, tuple_expr, token, display_target);141 },142 _ => (),143 }144 }145146 // Stop at multi-line expressions, since the signature of the outer call is not very147 // helpful inside them.148 if let Some(expr) = ast::Expr::cast(node.clone())149 && !matches!(expr, ast::Expr::RecordExpr(..))150 && expr.syntax().text().contains_char('\n')151 {152 break;153 }154 }155156 None157}158159fn signature_help_for_call(160 sema: &Semantics<'_, RootDatabase>,161 arg_list: ast::ArgList,162 token: SyntaxToken,163 edition: Edition,164 display_target: DisplayTarget,165) -> Option<SignatureHelp> {166 let (callable, active_parameter) =167 callable_for_arg_list(sema, arg_list, token.text_range().start())?;168169 let mut res =170 SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };171172 let db = sema.db;173 let mut fn_params = None;174 match callable.kind() {175 hir::CallableKind::Function(func) => {176 res.doc = func.docs(db).map(Documentation::into_owned);177 if func.is_async(db) {178 format_to!(res.signature, "async ");179 }180 format_to!(res.signature, "fn {}", func.name(db).display(db, edition));181182 let generic_params = GenericDef::Function(func)183 .params(db)184 .iter()185 .filter(|param| match param {186 GenericParam::TypeParam(type_param) => !type_param.is_implicit(db),187 GenericParam::ConstParam(_) | GenericParam::LifetimeParam(_) => true,188 })189 .map(|param| param.display(db, display_target))190 .join(", ");191 if !generic_params.is_empty() {192 format_to!(res.signature, "<{}>", generic_params);193 }194195 fn_params = Some(match callable.receiver_param(db) {196 Some(_self) => func.params_without_self(db),197 None => func.assoc_fn_params(db),198 });199 }200 hir::CallableKind::TupleStruct(strukt) => {201 res.doc = strukt.docs(db).map(Documentation::into_owned);202 format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition));203204 let generic_params = GenericDef::Adt(strukt.into())205 .params(db)206 .iter()207 .map(|param| param.display(db, display_target))208 .join(", ");209 if !generic_params.is_empty() {210 format_to!(res.signature, "<{}>", generic_params);211 }212 }213 hir::CallableKind::TupleEnumVariant(variant) => {214 res.doc = variant.docs(db).map(Documentation::into_owned);215 format_to!(216 res.signature,217 "enum {}",218 variant.parent_enum(db).name(db).display(db, edition),219 );220221 let generic_params = GenericDef::Adt(variant.parent_enum(db).into())222 .params(db)223 .iter()224 .map(|param| param.display(db, display_target))225 .join(", ");226 if !generic_params.is_empty() {227 format_to!(res.signature, "<{}>", generic_params);228 }229230 format_to!(res.signature, "::{}", variant.name(db).display(db, edition))231 }232 hir::CallableKind::Closure(closure) => {233 let fn_trait = closure.fn_trait(db);234 format_to!(res.signature, "impl {fn_trait}")235 }236 hir::CallableKind::FnPtr => format_to!(res.signature, "fn"),237 hir::CallableKind::FnImpl(fn_trait) => match callable.ty().as_adt() {238 // FIXME: Render docs of the concrete trait impl function239 Some(adt) => format_to!(240 res.signature,241 "<{} as {fn_trait}>::{}",242 adt.name(db).display(db, edition),243 fn_trait.function_name()244 ),245 None => format_to!(res.signature, "impl {fn_trait}"),246 },247 }248249 res.signature.push('(');250 {251 if let Some((self_param, _)) = callable.receiver_param(db) {252 format_to!(res.signature, "{}", self_param.display(db, display_target))253 }254 let mut buf = String::new();255 for (idx, p) in callable.params().into_iter().enumerate() {256 buf.clear();257 if let Some(param) = sema.source(p.clone()) {258 match param.value {259 Either::Right(param) => match param.pat() {260 Some(pat) => format_to!(buf, "{}: ", pat),261 None => format_to!(buf, "?: "),262 },263 Either::Left(_) => format_to!(buf, "self: "),264 }265 }266 // APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is267 // in the middle of entering call arguments.268 // In that case, fall back to render definitions of the respective parameters.269 // This is overly conservative: we do not substitute known type vars270 // (see FIXME in tests::impl_trait) and falling back on any unknowns.271 match (p.ty().contains_unknown(), fn_params.as_deref()) {272 (true, Some(fn_params)) => {273 format_to!(buf, "{}", fn_params[idx].ty().display(db, display_target))274 }275 _ => format_to!(buf, "{}", p.ty().display(db, display_target)),276 }277 res.push_call_param(&buf);278 }279 }280 res.signature.push(')');281282 let mut render = |ret_type: hir::Type<'_>| {283 if !ret_type.is_unit() {284 format_to!(res.signature, " -> {}", ret_type.display(db, display_target));285 }286 };287 match callable.kind() {288 hir::CallableKind::Function(func) => render(func.async_ret_type(db).unwrap_or_else(|| {289 if callable.return_type().contains_unknown() {290 func.ret_type(db)291 } else {292 callable.return_type()293 }294 })),295 hir::CallableKind::Closure(_) | hir::CallableKind::FnPtr | hir::CallableKind::FnImpl(_) => {296 render(callable.return_type())297 }298 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}299 }300 Some(res)301}302303fn signature_help_for_generics(304 sema: &Semantics<'_, RootDatabase>,305 arg_list: ast::GenericArgList,306 token: SyntaxToken,307 edition: Edition,308 display_target: DisplayTarget,309) -> Option<SignatureHelp> {310 let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) =311 generic_def_for_node(sema, &arg_list, &token)?;312 let mut res = SignatureHelp {313 doc: None,314 signature: String::new(),315 parameters: vec![],316 active_parameter: None,317 };318319 let db = sema.db;320 match generics_def {321 hir::GenericDef::Function(it) => {322 res.doc = it.docs(db).map(Documentation::into_owned);323 format_to!(res.signature, "fn {}", it.name(db).display(db, edition));324 }325 hir::GenericDef::Adt(hir::Adt::Enum(it)) => {326 res.doc = it.docs(db).map(Documentation::into_owned);327 format_to!(res.signature, "enum {}", it.name(db).display(db, edition));328 if let Some(variant) = variant {329 // In paths, generics of an enum can be specified *after* one of its variants.330 // eg. `None::<u8>`331 // We'll use the signature of the enum, but include the docs of the variant.332 res.doc = variant.docs(db).map(Documentation::into_owned);333 }334 }335 hir::GenericDef::Adt(hir::Adt::Struct(it)) => {336 res.doc = it.docs(db).map(Documentation::into_owned);337 format_to!(res.signature, "struct {}", it.name(db).display(db, edition));338 }339 hir::GenericDef::Adt(hir::Adt::Union(it)) => {340 res.doc = it.docs(db).map(Documentation::into_owned);341 format_to!(res.signature, "union {}", it.name(db).display(db, edition));342 }343 hir::GenericDef::Trait(it) => {344 res.doc = it.docs(db).map(Documentation::into_owned);345 format_to!(res.signature, "trait {}", it.name(db).display(db, edition));346 }347 hir::GenericDef::TypeAlias(it) => {348 res.doc = it.docs(db).map(Documentation::into_owned);349 format_to!(res.signature, "type {}", it.name(db).display(db, edition));350 }351 // These don't have generic args that can be specified352 hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) | hir::GenericDef::Static(_) => {353 return None;354 }355 }356357 let params = generics_def.params(sema.db);358 let num_lifetime_params =359 params.iter().take_while(|param| matches!(param, GenericParam::LifetimeParam(_))).count();360 if first_arg_is_non_lifetime {361 // Lifetime parameters were omitted.362 active_parameter += num_lifetime_params;363 }364 res.active_parameter = Some(active_parameter);365366 res.signature.push('<');367 let mut buf = String::new();368 for param in params {369 if let hir::GenericParam::TypeParam(ty) = param370 && ty.is_implicit(db)371 {372 continue;373 }374375 buf.clear();376 format_to!(buf, "{}", param.display(db, display_target));377 match param {378 GenericParam::TypeParam(param) => {379 if let Some(ty) = param.default(db) {380 format_to!(buf, " = {}", ty.display(db, display_target));381 }382 }383 GenericParam::ConstParam(param) => {384 if let Some(expr) = param.default(db, display_target).and_then(|konst| konst.expr())385 {386 format_to!(buf, " = {}", expr);387 }388 }389 _ => {}390 }391 res.push_generic_param(&buf);392 }393 if let hir::GenericDef::Trait(tr) = generics_def {394 add_assoc_type_bindings(db, &mut res, tr, arg_list, edition);395 }396 res.signature.push('>');397398 Some(res)399}400401fn add_assoc_type_bindings(402 db: &RootDatabase,403 res: &mut SignatureHelp,404 tr: Trait,405 args: ast::GenericArgList,406 edition: Edition,407) {408 if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() {409 // Assoc type bindings are only valid in type bound position.410 return;411 }412413 let present_bindings = args414 .generic_args()415 .filter_map(|arg| match arg {416 ast::GenericArg::AssocTypeArg(arg) => arg.name_ref().map(|n| n.to_string()),417 _ => None,418 })419 .collect::<BTreeSet<_>>();420421 let mut buf = String::new();422 for binding in &present_bindings {423 buf.clear();424 format_to!(buf, "{} = …", binding);425 res.push_generic_param(&buf);426 }427428 for item in tr.items_with_supertraits(db) {429 if let AssocItem::TypeAlias(ty) = item {430 let name = ty.name(db).display_no_db(edition).to_smolstr();431 if !present_bindings.contains(&*name) {432 buf.clear();433 format_to!(buf, "{} = …", name);434 res.push_generic_param(&buf);435 }436 }437 }438}439440fn signature_help_for_record_lit(441 sema: &Semantics<'_, RootDatabase>,442 record: ast::RecordExpr,443 token: SyntaxToken,444 edition: Edition,445 display_target: DisplayTarget,446) -> Option<SignatureHelp> {447 signature_help_for_record_(448 sema,449 record.record_expr_field_list()?.syntax().children_with_tokens(),450 &record.path()?,451 record452 .record_expr_field_list()?453 .fields()454 .filter_map(|field| sema.resolve_record_field(&field))455 .map(|(field, _, ty)| (field, ty)),456 token,457 edition,458 display_target,459 )460}461462fn signature_help_for_record_pat(463 sema: &Semantics<'_, RootDatabase>,464 record: ast::RecordPat,465 token: SyntaxToken,466 edition: Edition,467 display_target: DisplayTarget,468) -> Option<SignatureHelp> {469 signature_help_for_record_(470 sema,471 record.record_pat_field_list()?.syntax().children_with_tokens(),472 &record.path()?,473 record474 .record_pat_field_list()?475 .fields()476 .filter_map(|field| sema.resolve_record_pat_field(&field)),477 token,478 edition,479 display_target,480 )481}482483fn signature_help_for_tuple_struct_pat(484 sema: &Semantics<'_, RootDatabase>,485 pat: ast::TupleStructPat,486 token: SyntaxToken,487 edition: Edition,488 display_target: DisplayTarget,489) -> Option<SignatureHelp> {490 let path = pat.path()?;491 let path_res = sema.resolve_path(&path)?;492 let mut res = SignatureHelp {493 doc: None,494 signature: String::new(),495 parameters: vec![],496 active_parameter: None,497 };498 let db = sema.db;499500 let fields: Vec<_> = if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res {501 let en = variant.parent_enum(db);502503 res.doc = en.docs(db).map(Documentation::into_owned);504 format_to!(505 res.signature,506 "enum {}::{} (",507 en.name(db).display(db, edition),508 variant.name(db).display(db, edition)509 );510 variant.fields(db)511 } else {512 let adt = match path_res {513 PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?,514 PathResolution::Def(ModuleDef::Adt(adt)) => adt,515 _ => return None,516 };517518 match adt {519 hir::Adt::Struct(it) => {520 res.doc = it.docs(db).map(Documentation::into_owned);521 format_to!(res.signature, "struct {} (", it.name(db).display(db, edition));522 it.fields(db)523 }524 _ => return None,525 }526 };527 Some(signature_help_for_tuple_pat_ish(528 db,529 res,530 pat.syntax(),531 token,532 pat.fields(),533 fields.into_iter().map(|it| it.ty(db).to_type(db)),534 display_target,535 ))536}537538fn signature_help_for_tuple_pat(539 sema: &Semantics<'_, RootDatabase>,540 pat: ast::TuplePat,541 token: SyntaxToken,542 display_target: DisplayTarget,543) -> Option<SignatureHelp> {544 let db = sema.db;545 let field_pats = pat.fields();546 let pat = pat.into();547 let ty = sema.type_of_pat(&pat)?;548 let fields = ty.original.tuple_fields(db);549550 Some(signature_help_for_tuple_pat_ish(551 db,552 SignatureHelp {553 doc: None,554 signature: String::from('('),555 parameters: vec![],556 active_parameter: None,557 },558 pat.syntax(),559 token,560 field_pats,561 fields.into_iter(),562 display_target,563 ))564}565566fn signature_help_for_tuple_expr(567 sema: &Semantics<'_, RootDatabase>,568 expr: ast::TupleExpr,569 token: SyntaxToken,570 display_target: DisplayTarget,571) -> Option<SignatureHelp> {572 let active_parameter = Some(573 expr.syntax()574 .children_with_tokens()575 .filter_map(NodeOrToken::into_token)576 .filter(|t| t.kind() == T![,])577 .take_while(|t| t.text_range().start() <= token.text_range().start())578 .count(),579 );580581 let db = sema.db;582 let mut res = SignatureHelp {583 doc: None,584 signature: String::from('('),585 parameters: vec![],586 active_parameter,587 };588 let expr = sema.type_of_expr(&expr.into())?;589 let fields = expr.original.tuple_fields(db);590 let mut buf = String::new();591 for ty in fields {592 format_to!(buf, "{}", ty.display_truncated(db, Some(20), display_target));593 res.push_call_param(&buf);594 buf.clear();595 }596 res.signature.push(')');597 Some(res)598}599600fn signature_help_for_record_<'db>(601 sema: &Semantics<'db, RootDatabase>,602 field_list_children: SyntaxElementChildren,603 path: &ast::Path,604 fields2: impl Iterator<Item = (hir::Field, hir::Type<'db>)>,605 token: SyntaxToken,606 edition: Edition,607 display_target: DisplayTarget,608) -> Option<SignatureHelp> {609 let active_parameter = field_list_children610 .filter_map(NodeOrToken::into_token)611 .filter(|t| t.kind() == T![,])612 .take_while(|t| t.text_range().start() <= token.text_range().start())613 .count();614615 let mut res = SignatureHelp {616 doc: None,617 signature: String::new(),618 parameters: vec![],619 active_parameter: Some(active_parameter),620 };621622 let fields;623624 let db = sema.db;625 let path_res = sema.resolve_path(path)?;626 if let PathResolution::Def(ModuleDef::EnumVariant(variant)) = path_res {627 fields = variant.fields(db);628 let en = variant.parent_enum(db);629630 res.doc = en.docs(db).map(Documentation::into_owned);631 format_to!(632 res.signature,633 "enum {}::{} {{ ",634 en.name(db).display(db, edition),635 variant.name(db).display(db, edition)636 );637 } else {638 let adt = match path_res {639 PathResolution::SelfType(imp) => imp.self_ty(db).as_adt()?,640 PathResolution::Def(ModuleDef::Adt(adt)) => adt,641 _ => return None,642 };643644 match adt {645 hir::Adt::Struct(it) => {646 fields = it.fields(db);647 res.doc = it.docs(db).map(Documentation::into_owned);648 format_to!(res.signature, "struct {} {{ ", it.name(db).display(db, edition));649 }650 hir::Adt::Union(it) => {651 fields = it.fields(db);652 res.doc = it.docs(db).map(Documentation::into_owned);653 format_to!(res.signature, "union {} {{ ", it.name(db).display(db, edition));654 }655 _ => return None,656 }657 }658659 let mut fields =660 fields.into_iter().map(|field| (field.name(db), Some(field))).collect::<FxIndexMap<_, _>>();661 let mut buf = String::new();662 for (field, ty) in fields2 {663 let name = field.name(db);664 format_to!(665 buf,666 "{}: {}",667 name.display(db, edition),668 ty.display_truncated(db, Some(20), display_target)669 );670 res.push_record_field(&buf);671 buf.clear();672673 if let Some(field) = fields.get_mut(&name) {674 *field = None;675 }676 }677 for (name, field) in fields {678 let Some(field) = field else { continue };679 format_to!(680 buf,681 "{}: {}",682 name.display(db, edition),683 field.ty(db).display_truncated(db, Some(20), display_target)684 );685 res.push_record_field(&buf);686 buf.clear();687 }688 res.signature.push_str(" }");689 Some(res)690}691692fn signature_help_for_tuple_pat_ish<'db>(693 db: &'db RootDatabase,694 mut res: SignatureHelp,695 pat: &SyntaxNode,696 token: SyntaxToken,697 mut field_pats: AstChildren<ast::Pat>,698 fields: impl ExactSizeIterator<Item = hir::Type<'db>>,699 display_target: DisplayTarget,700) -> SignatureHelp {701 let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_)));702 let is_left_of_rest_pat =703 rest_pat.is_none_or(|it| token.text_range().start() < it.syntax().text_range().end());704705 let commas = pat706 .children_with_tokens()707 .filter_map(NodeOrToken::into_token)708 .filter(|t| t.kind() == T![,]);709710 res.active_parameter = {711 Some(if is_left_of_rest_pat {712 commas.take_while(|t| t.text_range().start() <= token.text_range().start()).count()713 } else {714 let n_commas = commas715 .collect::<Vec<_>>()716 .into_iter()717 .rev()718 .take_while(|t| t.text_range().start() > token.text_range().start())719 .count();720 fields.len().saturating_sub(1).saturating_sub(n_commas)721 })722 };723724 let mut buf = String::new();725 for ty in fields {726 format_to!(buf, "{}", ty.display_truncated(db, Some(20), display_target));727 res.push_call_param(&buf);728 buf.clear();729 }730 res.signature.push(')');731 res732}733#[cfg(test)]734mod tests {735736 use expect_test::{Expect, expect};737 use ide_db::FilePosition;738 use stdx::format_to;739 use test_fixture::ChangeFixture;740741 use crate::RootDatabase;742743 /// Creates analysis from a multi-file fixture, returns positions marked with $0.744 pub(crate) fn position(745 #[rust_analyzer::rust_fixture] ra_fixture: &str,746 ) -> (RootDatabase, FilePosition) {747 let mut database = RootDatabase::default();748 let change_fixture = ChangeFixture::parse(ra_fixture);749 database.apply_change(change_fixture.change);750 let (file_id, range_or_offset) =751 change_fixture.file_position.expect("expected a marker ($0)");752 let offset = range_or_offset.expect_offset();753 let position = FilePosition { file_id: file_id.file_id(), offset };754 (database, position)755 }756757 #[track_caller]758 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {759 let (db, position) = position(ra_fixture);760 let sig_help = hir::attach_db(&db, || crate::signature_help::signature_help(&db, position));761 let actual = match sig_help {762 Some(sig_help) => {763 let mut rendered = String::new();764 if let Some(docs) = &sig_help.doc {765 format_to!(rendered, "{}\n------\n", docs.as_str());766 }767 format_to!(rendered, "{}\n", sig_help.signature);768 let mut offset = 0;769 for (i, range) in sig_help.parameter_ranges().iter().enumerate() {770 let is_active = sig_help.active_parameter == Some(i);771772 let start = u32::from(range.start());773 let gap = start.checked_sub(offset).unwrap_or_else(|| {774 panic!("parameter ranges out of order: {:?}", sig_help.parameter_ranges())775 });776 rendered.extend(std::iter::repeat_n(' ', gap as usize));777 let param_text = &sig_help.signature[*range];778 let width = param_text.chars().count(); // …779 let marker = if is_active { '^' } else { '-' };780 rendered.extend(std::iter::repeat_n(marker, width));781 offset += gap + u32::from(range.len());782 }783 if !sig_help.parameter_ranges().is_empty() {784 format_to!(rendered, "\n");785 }786 rendered787 }788 None => String::new(),789 };790 expect.assert_eq(&actual);791 }792793 #[test]794 fn test_fn_signature_two_args() {795 check(796 r#"797//- minicore: sized, fn798fn foo(x: u32, y: u32) -> u32 {x + y}799fn bar() { foo($03, ); }800"#,801 expect![[r#"802 fn foo(x: u32, y: u32) -> u32803 ^^^^^^ ------804 "#]],805 );806 check(807 r#"808//- minicore: sized, fn809fn foo(x: u32, y: u32) -> u32 {x + y}810fn bar() { foo(3$0, ); }811"#,812 expect![[r#"813 fn foo(x: u32, y: u32) -> u32814 ^^^^^^ ------815 "#]],816 );817 check(818 r#"819//- minicore: sized, fn820fn foo(x: u32, y: u32) -> u32 {x + y}821fn bar() { foo(3,$0 ); }822"#,823 expect![[r#"824 fn foo(x: u32, y: u32) -> u32825 ------ ^^^^^^826 "#]],827 );828 check(829 r#"830//- minicore: sized, fn831fn foo(x: u32, y: u32) -> u32 {x + y}832fn bar() { foo(3, $0); }833"#,834 expect![[r#"835 fn foo(x: u32, y: u32) -> u32836 ------ ^^^^^^837 "#]],838 );839 }840841 #[test]842 fn test_fn_signature_two_args_empty() {843 check(844 r#"845//- minicore: sized, fn846fn foo(x: u32, y: u32) -> u32 {x + y}847fn bar() { foo($0); }848"#,849 expect![[r#"850 fn foo(x: u32, y: u32) -> u32851 ^^^^^^ ------852 "#]],853 );854 }855856 #[test]857 fn test_fn_signature_two_args_first_generics() {858 check(859 r#"860//- minicore: sized, fn861fn foo<T, U: Copy + Display>(x: T, y: U) -> u32862 where T: Copy + Display, U: Debug863{ x + y }864865fn bar() { foo($03, ); }866"#,867 expect![[r#"868 fn foo<T, U>(x: i32, y: U) -> u32869 ^^^^^^ ----870 "#]],871 );872 }873874 #[test]875 fn test_fn_signature_no_params() {876 check(877 r#"878//- minicore: sized, fn879fn foo<T>() -> T where T: Copy + Display {}880fn bar() { foo($0); }881"#,882 expect![[r#"883 fn foo<T>() -> T884 "#]],885 );886 }887888 #[test]889 fn test_fn_signature_for_impl() {890 check(891 r#"892//- minicore: sized, fn893struct F;894impl F { pub fn new() { } }895fn bar() {896 let _ : F = F::new($0);897}898"#,899 expect![[r#"900 fn new()901 "#]],902 );903 }904905 #[test]906 fn test_fn_signature_for_method_self() {907 check(908 r#"909//- minicore: sized, fn910struct S;911impl S { pub fn do_it(&self) {} }912913fn bar() {914 let s: S = S;915 s.do_it($0);916}917"#,918 expect![[r#"919 fn do_it(&self)920 "#]],921 );922 }923924 #[test]925 fn test_fn_signature_for_method_with_arg() {926 check(927 r#"928//- minicore: sized, fn929struct S;930impl S {931 fn foo(&self, x: i32) {}932}933934fn main() { S.foo($0); }935"#,936 expect![[r#"937 fn foo(&self, x: i32)938 ^^^^^^939 "#]],940 );941 }942943 #[test]944 fn test_fn_signature_for_generic_method() {945 check(946 r#"947//- minicore: sized, fn948struct S<T>(T);949impl<T> S<T> {950 fn foo(&self, x: T) {}951}952953fn main() { S(1u32).foo($0); }954"#,955 expect![[r#"956 fn foo(&self, x: u32)957 ^^^^^^958 "#]],959 );960 }961962 #[test]963 fn test_fn_signature_for_method_with_arg_as_assoc_fn() {964 check(965 r#"966//- minicore: sized, fn967struct S;968impl S {969 fn foo(&self, x: i32) {}970}971972fn main() { S::foo($0); }973"#,974 expect![[r#"975 fn foo(self: &S, x: i32)976 ^^^^^^^^ ------977 "#]],978 );979 }980981 #[test]982 fn test_fn_signature_with_docs_simple() {983 check(984 r#"985//- minicore: sized, fn986/// test987// non-doc-comment988fn foo(j: u32) -> u32 {989 j990}991992fn bar() {993 let _ = foo($0);994}995"#,996 expect![[r#"997 test998 ------999 fn foo(j: u32) -> u321000 ^^^^^^1001 "#]],1002 );1003 }10041005 #[test]1006 fn test_fn_signature_with_docs() {1007 check(1008 r#"1009//- minicore: sized, fn1010/// Adds one to the number given.1011///1012/// # Examples1013///1014/// ```1015/// let five = 5;1016///1017/// assert_eq!(6, my_crate::add_one(5));1018/// ```1019pub fn add_one(x: i32) -> i32 {1020 x + 11021}10221023pub fn r#do() {1024 add_one($01025}"#,1026 expect![[r##"1027 Adds one to the number given.10281029 # Examples10301031 ```1032 let five = 5;10331034 assert_eq!(6, my_crate::add_one(5));1035 ```1036 ------1037 fn add_one(x: i32) -> i321038 ^^^^^^1039 "##]],1040 );1041 }10421043 #[test]1044 fn test_fn_signature_with_docs_impl() {1045 check(1046 r#"1047//- minicore: sized, fn1048struct addr;1049impl addr {1050 /// Adds one to the number given.1051 ///1052 /// # Examples1053 ///1054 /// ```1055 /// let five = 5;1056 ///1057 /// assert_eq!(6, my_crate::add_one(5));1058 /// ```1059 pub fn add_one(x: i32) -> i32 {1060 x + 11061 }1062}10631064pub fn do_it() {1065 addr {};1066 addr::add_one($0);1067}1068"#,1069 expect![[r##"1070 Adds one to the number given.10711072 # Examples10731074 ```1075 let five = 5;10761077 assert_eq!(6, my_crate::add_one(5));1078 ```1079 ------1080 fn add_one(x: i32) -> i321081 ^^^^^^1082 "##]],1083 );1084 }10851086 #[test]1087 fn test_fn_signature_with_docs_from_actix() {1088 check(1089 r#"1090//- minicore: sized, fn1091trait Actor {1092 /// Actor execution context type1093 type Context;1094}1095trait WriteHandler<E>1096where1097 Self: Actor1098{1099 /// Method is called when writer finishes.1100 ///1101 /// By default this method stops actor's `Context`.1102 fn finished(&mut self, ctx: &mut Self::Context) {}1103}11041105fn foo(mut r: impl WriteHandler<()>) {1106 r.finished($0);1107}1108"#,1109 expect![[r#"1110 Method is called when writer finishes.11111112 By default this method stops actor's `Context`.1113 ------1114 fn finished(&mut self, ctx: &mut <impl WriteHandler<()> as Actor>::Context)1115 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1116 "#]],1117 );1118 }11191120 #[test]1121 fn call_info_bad_offset() {1122 check(1123 r#"1124//- minicore: sized, fn1125fn foo(x: u32, y: u32) -> u32 {x + y}1126fn bar() { foo $0 (3, ); }1127"#,1128 expect![[""]],1129 );1130 }11311132 #[test]1133 fn outside_of_arg_list() {1134 check(1135 r#"1136//- minicore: sized, fn1137fn foo(a: u8) {}1138fn f() {1139 foo(123)$01140}1141"#,1142 expect![[]],1143 );1144 check(1145 r#"1146//- minicore: sized, fn1147fn foo<T>(a: u8) {}1148fn f() {1149 foo::<u32>$0()1150}1151"#,1152 expect![[]],1153 );1154 check(1155 r#"1156//- minicore: sized, fn1157fn foo(a: u8) -> u8 {a}1158fn bar(a: u8) -> u8 {a}1159fn f() {1160 foo(bar(123)$0)1161}1162"#,1163 expect![[r#"1164 fn foo(a: u8) -> u81165 ^^^^^1166 "#]],1167 );1168 check(1169 r#"1170//- minicore: sized, fn1171struct Vec<T>(T);1172struct Vec2<T>(T);1173fn f() {1174 let _: Vec2<Vec<u8>$0>1175}1176"#,1177 expect![[r#"1178 struct Vec2<T>1179 ^1180 "#]],1181 );1182 }11831184 #[test]1185 fn test_nested_method_in_lambda() {1186 check(1187 r#"1188//- minicore: sized, fn1189struct Foo;1190impl Foo { fn bar(&self, _: u32) { } }11911192fn bar(_: u32) { }11931194fn main() {1195 let foo = Foo;1196 std::thread::spawn(move || foo.bar($0));1197}1198"#,1199 expect![[r#"1200 fn bar(&self, _: u32)1201 ^^^^^^1202 "#]],1203 );1204 }12051206 #[test]1207 fn works_for_tuple_structs() {1208 check(1209 r#"1210//- minicore: sized, fn1211/// A cool tuple struct1212struct S(u32, i32);1213fn main() {1214 let s = S(0, $0);1215}1216"#,1217 expect![[r#"1218 A cool tuple struct1219 ------1220 struct S(u32, i32)1221 --- ^^^1222 "#]],1223 );1224 }12251226 #[test]1227 fn tuple_struct_pat() {1228 check(1229 r#"1230//- minicore: sized, fn1231/// A cool tuple struct1232struct S(u32, i32);1233fn main() {1234 let S(0, $0);1235}1236"#,1237 expect![[r#"1238 A cool tuple struct1239 ------1240 struct S (u32, i32)1241 --- ^^^1242 "#]],1243 );1244 }12451246 #[test]1247 fn tuple_struct_pat_rest() {1248 check(1249 r#"1250//- minicore: sized, fn1251/// A cool tuple struct1252struct S(u32, i32, f32, u16);1253fn main() {1254 let S(0, .., $0);1255}1256"#,1257 expect![[r#"1258 A cool tuple struct1259 ------1260 struct S (u32, i32, f32, u16)1261 --- --- --- ^^^1262 "#]],1263 );1264 check(1265 r#"1266//- minicore: sized, fn1267/// A cool tuple struct1268struct S(u32, i32, f32, u16, u8);1269fn main() {1270 let S(0, .., $0, 0);1271}1272"#,1273 expect![[r#"1274 A cool tuple struct1275 ------1276 struct S (u32, i32, f32, u16, u8)1277 --- --- --- ^^^ --1278 "#]],1279 );1280 check(1281 r#"1282//- minicore: sized, fn1283/// A cool tuple struct1284struct S(u32, i32, f32, u16);1285fn main() {1286 let S($0, .., 1);1287}1288"#,1289 expect![[r#"1290 A cool tuple struct1291 ------1292 struct S (u32, i32, f32, u16)1293 ^^^ --- --- ---1294 "#]],1295 );1296 check(1297 r#"1298//- minicore: sized, fn1299/// A cool tuple struct1300struct S(u32, i32, f32, u16, u8);1301fn main() {1302 let S(1, .., 1, $0, 2);1303}1304"#,1305 expect![[r#"1306 A cool tuple struct1307 ------1308 struct S (u32, i32, f32, u16, u8)1309 --- --- --- ^^^ --1310 "#]],1311 );1312 check(1313 r#"1314//- minicore: sized, fn1315/// A cool tuple struct1316struct S(u32, i32, f32, u16);1317fn main() {1318 let S(1, $0.., 1);1319}1320"#,1321 expect![[r#"1322 A cool tuple struct1323 ------1324 struct S (u32, i32, f32, u16)1325 --- ^^^ --- ---1326 "#]],1327 );1328 check(1329 r#"1330//- minicore: sized, fn1331/// A cool tuple struct1332struct S(u32, i32, f32, u16);1333fn main() {1334 let S(1, ..$0, 1);1335}1336"#,1337 expect![[r#"1338 A cool tuple struct1339 ------1340 struct S (u32, i32, f32, u16)1341 --- ^^^ --- ---1342 "#]],1343 );1344 }13451346 #[test]1347 fn generic_struct() {1348 check(1349 r#"1350//- minicore: sized, fn1351struct S<T>(T);1352fn main() {1353 let s = S($0);1354}1355"#,1356 expect![[r#"1357 struct S<T>({unknown})1358 ^^^^^^^^^1359 "#]],1360 );1361 }13621363 #[test]1364 fn works_for_enum_variants() {1365 check(1366 r#"1367//- minicore: sized, fn1368enum E {1369 /// A Variant1370 A(i32),1371 /// Another1372 B,1373 /// And C1374 C { a: i32, b: i32 }1375}13761377fn main() {1378 let a = E::A($0);1379}1380"#,1381 expect![[r#"1382 A Variant1383 ------1384 enum E::A(i32)1385 ^^^1386 "#]],1387 );1388 }13891390 #[test]1391 fn cant_call_struct_record() {1392 check(1393 r#"1394//- minicore: sized, fn1395struct S { x: u32, y: i32 }1396fn main() {1397 let s = S($0);1398}1399"#,1400 expect![[""]],1401 );1402 }14031404 #[test]1405 fn cant_call_enum_record() {1406 check(1407 r#"1408//- minicore: sized, fn1409enum E {1410 /// A Variant1411 A(i32),1412 /// Another1413 B,1414 /// And C1415 C { a: i32, b: i32 }1416}14171418fn main() {1419 let a = E::C($0);1420}1421"#,1422 expect![[""]],1423 );1424 }14251426 #[test]1427 fn fn_signature_for_call_in_macro() {1428 check(1429 r#"1430//- minicore: sized, fn1431macro_rules! id { ($($tt:tt)*) => { $($tt)* } }1432fn foo() { }1433id! {1434 fn bar() { foo($0); }1435}1436"#,1437 expect![[r#"1438 fn foo()1439 "#]],1440 );1441 }14421443 #[test]1444 fn fn_signature_for_method_call_defined_in_macro() {1445 check(1446 r#"1447//- minicore: sized, fn1448macro_rules! id { ($($tt:tt)*) => { $($tt)* } }1449struct S;1450id! {1451 impl S {1452 fn foo<'a>(&'a mut self) {}1453 }1454}1455fn test() { S.foo($0); }1456"#,1457 expect![[r#"1458 fn foo<'a>(&'a mut self)1459 "#]],1460 );1461 }14621463 #[test]1464 fn call_info_for_lambdas() {1465 check(1466 r#"1467//- minicore: sized, fn1468struct S;1469fn foo(s: S) -> i32 { 92 }1470fn main() {1471 let _move = S;1472 (|s| {{_move}; foo(s)})($0)1473}1474 "#,1475 expect![[r#"1476 impl FnOnce(s: S) -> i321477 ^^^^1478 "#]],1479 );1480 check(1481 r#"1482//- minicore: sized, fn1483struct S;1484fn foo(s: S) -> i32 { 92 }1485fn main() {1486 (|s| foo(s))($0)1487}1488 "#,1489 expect![[r#"1490 impl Fn(s: S) -> i321491 ^^^^1492 "#]],1493 );1494 check(1495 r#"1496//- minicore: sized, fn1497struct S;1498fn foo(s: S) -> i32 { 92 }1499fn main() {1500 let mut mutate = 0;1501 (|s| { mutate = 1; foo(s) })($0)1502}1503 "#,1504 expect![[r#"1505 impl FnMut(s: S) -> i321506 ^^^^1507 "#]],1508 );1509 }15101511 #[test]1512 fn call_info_for_fn_def_over_reference() {1513 check(1514 r#"1515//- minicore: sized, fn1516struct S;1517fn foo(s: S) -> i32 { 92 }1518fn main() {1519 let bar = &&&&&foo;1520 bar($0);1521}1522 "#,1523 expect![[r#"1524 fn foo(s: S) -> i321525 ^^^^1526 "#]],1527 )1528 }15291530 #[test]1531 fn call_info_for_fn_ptr() {1532 check(1533 r#"1534//- minicore: sized, fn1535fn main(f: fn(i32, f64) -> char) {1536 f(0, $0)1537}1538 "#,1539 expect![[r#"1540 fn(i32, f64) -> char1541 --- ^^^1542 "#]],1543 )1544 }15451546 #[test]1547 fn call_info_for_fn_impl() {1548 check(1549 r#"1550//- minicore: sized, fn1551struct S;1552impl core::ops::FnOnce<(i32, f64)> for S {1553 type Output = char;1554}1555impl core::ops::FnMut<(i32, f64)> for S {}1556impl core::ops::Fn<(i32, f64)> for S {}1557fn main() {1558 S($0);1559}1560 "#,1561 expect![[r#"1562 <S as Fn>::call(i32, f64) -> char1563 ^^^ ---1564 "#]],1565 );1566 check(1567 r#"1568//- minicore: sized, fn1569struct S;1570impl core::ops::FnOnce<(i32, f64)> for S {1571 type Output = char;1572}1573impl core::ops::FnMut<(i32, f64)> for S {}1574impl core::ops::Fn<(i32, f64)> for S {}1575fn main() {1576 S(1, $0);1577}1578 "#,1579 expect![[r#"1580 <S as Fn>::call(i32, f64) -> char1581 --- ^^^1582 "#]],1583 );1584 check(1585 r#"1586//- minicore: sized, fn1587struct S;1588impl core::ops::FnOnce<(i32, f64)> for S {1589 type Output = char;1590}1591impl core::ops::FnOnce<(char, char)> for S {1592 type Output = f64;1593}1594fn main() {1595 S($0);1596}1597 "#,1598 expect![""],1599 );1600 check(1601 r#"1602//- minicore: sized, fn1603struct S;1604impl core::ops::FnOnce<(i32, f64)> for S {1605 type Output = char;1606}1607impl core::ops::FnOnce<(char, char)> for S {1608 type Output = f64;1609}1610fn main() {1611 // FIXME: The ide layer loses the calling info here so we get an ambiguous trait solve result1612 S(0i32, $0);1613}1614 "#,1615 expect![""],1616 );1617 }16181619 #[test]1620 fn call_info_for_unclosed_call() {1621 check(1622 r#"1623//- minicore: sized, fn1624fn foo(foo: u32, bar: u32) {}1625fn main() {1626 foo($01627}"#,1628 expect![[r#"1629 fn foo(foo: u32, bar: u32)1630 ^^^^^^^^ --------1631 "#]],1632 );1633 // check with surrounding space1634 check(1635 r#"1636//- minicore: sized, fn1637fn foo(foo: u32, bar: u32) {}1638fn main() {1639 foo( $01640}"#,1641 expect![[r#"1642 fn foo(foo: u32, bar: u32)1643 ^^^^^^^^ --------1644 "#]],1645 )1646 }16471648 #[test]1649 fn test_multiline_argument() {1650 check(1651 r#"1652//- minicore: sized, fn1653fn callee(a: u8, b: u8) {}1654fn main() {1655 callee(match 0 {1656 0 => 1,$01657 })1658}"#,1659 expect![[r#""#]],1660 );1661 check(1662 r#"1663//- minicore: sized, fn1664fn callee(a: u8, b: u8) {}1665fn main() {1666 callee(match 0 {1667 0 => 1,1668 },$0)1669}"#,1670 expect![[r#"1671 fn callee(a: u8, b: u8)1672 ----- ^^^^^1673 "#]],1674 );1675 check(1676 r#"1677//- minicore: sized, fn1678fn callee(a: u8, b: u8) {}1679fn main() {1680 callee($0match 0 {1681 0 => 1,1682 })1683}"#,1684 expect![[r#"1685 fn callee(a: u8, b: u8)1686 ^^^^^ -----1687 "#]],1688 );1689 }16901691 #[test]1692 fn test_generics_simple() {1693 check(1694 r#"1695//- minicore: sized, fn1696/// Option docs.1697enum Option<T> {1698 Some(T),1699 None,1700}17011702fn f() {1703 let opt: Option<$01704}1705 "#,1706 expect![[r#"1707 Option docs.1708 ------1709 enum Option<T>1710 ^1711 "#]],1712 );1713 }17141715 #[test]1716 fn test_generics_on_variant() {1717 check(1718 r#"1719//- minicore: sized, fn1720/// Option docs.1721enum Option<T> {1722 /// Some docs.1723 Some(T),1724 /// None docs.1725 None,1726}17271728use Option::*;17291730fn f() {1731 None::<$01732}1733 "#,1734 expect![[r#"1735 None docs.1736 ------1737 enum Option<T>1738 ^1739 "#]],1740 );1741 }17421743 #[test]1744 fn test_lots_of_generics() {1745 check(1746 r#"1747//- minicore: sized, fn1748trait Tr<T> {}17491750struct S<T>(T);17511752impl<T> S<T> {1753 fn f<G, H>(g: G, h: impl Tr<G>) where G: Tr<()> {}1754}17551756fn f() {1757 S::<u8>::f::<(), $01758}1759 "#,1760 expect![[r#"1761 fn f<G: Tr<()>, H>1762 --------- ^1763 "#]],1764 );1765 }17661767 #[test]1768 fn test_generics_in_trait_ufcs() {1769 check(1770 r#"1771//- minicore: sized, fn1772trait Tr {1773 fn f<T: Tr, U>() {}1774}17751776struct S;17771778impl Tr for S {}17791780fn f() {1781 <S as Tr>::f::<$01782}1783 "#,1784 expect![[r#"1785 fn f<T: Tr, U>1786 ^^^^^ -1787 "#]],1788 );1789 }17901791 #[test]1792 fn test_generics_in_method_call() {1793 check(1794 r#"1795//- minicore: sized, fn1796struct S;17971798impl S {1799 fn f<T>(&self) {}1800}18011802fn f() {1803 S.f::<$01804}1805 "#,1806 expect![[r#"1807 fn f<T>1808 ^1809 "#]],1810 );1811 }18121813 #[test]1814 fn test_generic_param_in_method_call() {1815 check(1816 r#"1817//- minicore: sized, fn1818struct Foo;1819impl Foo {1820 fn test<V>(&mut self, val: V) {}1821}1822fn sup() {1823 Foo.test($0)1824}1825"#,1826 expect![[r#"1827 fn test<V>(&mut self, val: V)1828 ^^^^^^1829 "#]],1830 );1831 }18321833 #[test]1834 fn test_generic_kinds() {1835 check(1836 r#"1837//- minicore: sized, fn1838fn callee<'a, const A: u8, T, const C: u8>() {}18391840fn f() {1841 callee::<'static, $01842}1843 "#,1844 expect![[r#"1845 fn callee<'a, const A: u8, T, const C: u8>1846 -- ^^^^^^^^^^^ - -----------1847 "#]],1848 );1849 check(1850 r#"1851//- minicore: sized, fn1852fn callee<'a, const A: u8, T, const C: u8>() {}18531854fn f() {1855 callee::<NON_LIFETIME$01856}1857 "#,1858 expect![[r#"1859 fn callee<'a, const A: u8, T, const C: u8>1860 -- ^^^^^^^^^^^ - -----------1861 "#]],1862 );1863 }18641865 #[test]1866 fn test_trait_assoc_types() {1867 check(1868 r#"1869//- minicore: sized, fn1870trait Trait<'a, T> {1871 type Assoc;1872}1873fn f() -> impl Trait<(), $01874 "#,1875 expect![[r#"1876 trait Trait<'a, T, Assoc = …>1877 -- - ^^^^^^^^^1878 "#]],1879 );1880 check(1881 r#"1882//- minicore: sized, fn1883trait Iterator {1884 type Item;1885}1886fn f() -> impl Iterator<$01887 "#,1888 expect![[r#"1889 trait Iterator<Item = …>1890 ^^^^^^^^1891 "#]],1892 );1893 check(1894 r#"1895//- minicore: sized, fn1896trait Iterator {1897 type Item;1898}1899fn f() -> impl Iterator<Item = $01900 "#,1901 expect![[r#"1902 trait Iterator<Item = …>1903 ^^^^^^^^1904 "#]],1905 );1906 check(1907 r#"1908//- minicore: sized, fn1909trait Tr {1910 type A;1911 type B;1912}1913fn f() -> impl Tr<$01914 "#,1915 expect![[r#"1916 trait Tr<A = …, B = …>1917 ^^^^^ -----1918 "#]],1919 );1920 check(1921 r#"1922//- minicore: sized, fn1923trait Tr {1924 type A;1925 type B;1926}1927fn f() -> impl Tr<B$01928 "#,1929 expect![[r#"1930 trait Tr<A = …, B = …>1931 ^^^^^ -----1932 "#]],1933 );1934 check(1935 r#"1936//- minicore: sized, fn1937trait Tr {1938 type A;1939 type B;1940}1941fn f() -> impl Tr<B = $01942 "#,1943 expect![[r#"1944 trait Tr<B = …, A = …>1945 ^^^^^ -----1946 "#]],1947 );1948 check(1949 r#"1950//- minicore: sized, fn1951trait Tr {1952 type A;1953 type B;1954}1955fn f() -> impl Tr<B = (), $01956 "#,1957 expect![[r#"1958 trait Tr<B = …, A = …>1959 ----- ^^^^^1960 "#]],1961 );1962 }19631964 #[test]1965 fn test_supertrait_assoc() {1966 check(1967 r#"1968//- minicore: sized, fn1969trait Super {1970 type SuperTy;1971}1972trait Sub: Super + Super {1973 type SubTy;1974}1975fn f() -> impl Sub<$01976 "#,1977 expect![[r#"1978 trait Sub<SubTy = …, SuperTy = …>1979 ^^^^^^^^^ -----------1980 "#]],1981 );1982 }19831984 #[test]1985 fn no_assoc_types_outside_type_bounds() {1986 check(1987 r#"1988//- minicore: sized, fn1989trait Tr<T> {1990 type Assoc;1991}19921993impl Tr<$01994 "#,1995 expect![[r#"1996 trait Tr<T>1997 ^1998 "#]],1999 );2000 }