|
1 | 1 | //! This module provides primitives for showing type and function parameter information when editing
|
2 | 2 | //! a call or use-site.
|
3 | 3 |
|
| 4 | +use std::collections::BTreeSet; |
| 5 | + |
4 | 6 | use either::Either;
|
5 |
| -use hir::{GenericParam, HasAttrs, HirDisplay, Semantics}; |
| 7 | +use hir::{AssocItem, GenericParam, HasAttrs, HirDisplay, Semantics, Trait}; |
6 | 8 | use ide_db::{active_parameter::callable_for_node, base_db::FilePosition};
|
7 | 9 | use stdx::format_to;
|
8 | 10 | use syntax::{
|
@@ -316,11 +318,52 @@ fn signature_help_for_generics(
|
316 | 318 | format_to!(buf, "{}", param.display(db));
|
317 | 319 | res.push_generic_param(&buf);
|
318 | 320 | }
|
| 321 | + if let hir::GenericDef::Trait(tr) = generics_def { |
| 322 | + add_assoc_type_bindings(db, &mut res, tr, arg_list); |
| 323 | + } |
319 | 324 | res.signature.push('>');
|
320 | 325 |
|
321 | 326 | Some(res)
|
322 | 327 | }
|
323 | 328 |
|
| 329 | +fn add_assoc_type_bindings( |
| 330 | + db: &RootDatabase, |
| 331 | + res: &mut SignatureHelp, |
| 332 | + tr: Trait, |
| 333 | + args: ast::GenericArgList, |
| 334 | +) { |
| 335 | + if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() { |
| 336 | + // Assoc type bindings are only valid in type bound position. |
| 337 | + return; |
| 338 | + } |
| 339 | + |
| 340 | + let present_bindings = args |
| 341 | + .generic_args() |
| 342 | + .filter_map(|arg| match arg { |
| 343 | + ast::GenericArg::AssocTypeArg(arg) => arg.name_ref().map(|n| n.to_string()), |
| 344 | + _ => None, |
| 345 | + }) |
| 346 | + .collect::<BTreeSet<_>>(); |
| 347 | + |
| 348 | + let mut buf = String::new(); |
| 349 | + for binding in &present_bindings { |
| 350 | + buf.clear(); |
| 351 | + format_to!(buf, "{} = …", binding); |
| 352 | + res.push_generic_param(&buf); |
| 353 | + } |
| 354 | + |
| 355 | + for item in tr.items_with_supertraits(db) { |
| 356 | + if let AssocItem::TypeAlias(ty) = item { |
| 357 | + let name = ty.name(db).to_smol_str(); |
| 358 | + if !present_bindings.contains(&*name) { |
| 359 | + buf.clear(); |
| 360 | + format_to!(buf, "{} = …", name); |
| 361 | + res.push_generic_param(&buf); |
| 362 | + } |
| 363 | + } |
| 364 | + } |
| 365 | +} |
| 366 | + |
324 | 367 | #[cfg(test)]
|
325 | 368 | mod tests {
|
326 | 369 | use std::iter;
|
@@ -368,10 +411,11 @@ mod tests {
|
368 | 411 | panic!("parameter ranges out of order: {:?}", sig_help.parameter_ranges())
|
369 | 412 | });
|
370 | 413 | rendered.extend(iter::repeat(' ').take(gap as usize));
|
371 |
| - let width = u32::from(range.end() - range.start()); |
| 414 | + let param_text = &sig_help.signature[*range]; |
| 415 | + let width = param_text.chars().count(); // … |
372 | 416 | let marker = if is_active { '^' } else { '-' };
|
373 |
| - rendered.extend(iter::repeat(marker).take(width as usize)); |
374 |
| - offset += gap + width; |
| 417 | + rendered.extend(iter::repeat(marker).take(width)); |
| 418 | + offset += gap + u32::from(range.len()); |
375 | 419 | }
|
376 | 420 | if !sig_help.parameter_ranges().is_empty() {
|
377 | 421 | format_to!(rendered, "\n");
|
@@ -1124,6 +1168,134 @@ fn f() {
|
1124 | 1168 | );
|
1125 | 1169 | }
|
1126 | 1170 |
|
| 1171 | + #[test] |
| 1172 | + fn test_trait_assoc_types() { |
| 1173 | + check( |
| 1174 | + r#" |
| 1175 | +trait Trait<'a, T> { |
| 1176 | + type Assoc; |
| 1177 | +} |
| 1178 | +fn f() -> impl Trait<(), $0 |
| 1179 | + "#, |
| 1180 | + expect![[r#" |
| 1181 | + trait Trait<'a, T, Assoc = …> |
| 1182 | + -- - ^^^^^^^^^ |
| 1183 | + "#]], |
| 1184 | + ); |
| 1185 | + check( |
| 1186 | + r#" |
| 1187 | +trait Iterator { |
| 1188 | + type Item; |
| 1189 | +} |
| 1190 | +fn f() -> impl Iterator<$0 |
| 1191 | + "#, |
| 1192 | + expect![[r#" |
| 1193 | + trait Iterator<Item = …> |
| 1194 | + ^^^^^^^^ |
| 1195 | + "#]], |
| 1196 | + ); |
| 1197 | + check( |
| 1198 | + r#" |
| 1199 | +trait Iterator { |
| 1200 | + type Item; |
| 1201 | +} |
| 1202 | +fn f() -> impl Iterator<Item = $0 |
| 1203 | + "#, |
| 1204 | + expect![[r#" |
| 1205 | + trait Iterator<Item = …> |
| 1206 | + ^^^^^^^^ |
| 1207 | + "#]], |
| 1208 | + ); |
| 1209 | + check( |
| 1210 | + r#" |
| 1211 | +trait Tr { |
| 1212 | + type A; |
| 1213 | + type B; |
| 1214 | +} |
| 1215 | +fn f() -> impl Tr<$0 |
| 1216 | + "#, |
| 1217 | + expect![[r#" |
| 1218 | + trait Tr<A = …, B = …> |
| 1219 | + ^^^^^ ----- |
| 1220 | + "#]], |
| 1221 | + ); |
| 1222 | + check( |
| 1223 | + r#" |
| 1224 | +trait Tr { |
| 1225 | + type A; |
| 1226 | + type B; |
| 1227 | +} |
| 1228 | +fn f() -> impl Tr<B$0 |
| 1229 | + "#, |
| 1230 | + expect![[r#" |
| 1231 | + trait Tr<A = …, B = …> |
| 1232 | + ^^^^^ ----- |
| 1233 | + "#]], |
| 1234 | + ); |
| 1235 | + check( |
| 1236 | + r#" |
| 1237 | +trait Tr { |
| 1238 | + type A; |
| 1239 | + type B; |
| 1240 | +} |
| 1241 | +fn f() -> impl Tr<B = $0 |
| 1242 | + "#, |
| 1243 | + expect![[r#" |
| 1244 | + trait Tr<B = …, A = …> |
| 1245 | + ^^^^^ ----- |
| 1246 | + "#]], |
| 1247 | + ); |
| 1248 | + check( |
| 1249 | + r#" |
| 1250 | +trait Tr { |
| 1251 | + type A; |
| 1252 | + type B; |
| 1253 | +} |
| 1254 | +fn f() -> impl Tr<B = (), $0 |
| 1255 | + "#, |
| 1256 | + expect![[r#" |
| 1257 | + trait Tr<B = …, A = …> |
| 1258 | + ----- ^^^^^ |
| 1259 | + "#]], |
| 1260 | + ); |
| 1261 | + } |
| 1262 | + |
| 1263 | + #[test] |
| 1264 | + fn test_supertrait_assoc() { |
| 1265 | + check( |
| 1266 | + r#" |
| 1267 | +trait Super { |
| 1268 | + type SuperTy; |
| 1269 | +} |
| 1270 | +trait Sub: Super + Super { |
| 1271 | + type SubTy; |
| 1272 | +} |
| 1273 | +fn f() -> impl Sub<$0 |
| 1274 | + "#, |
| 1275 | + expect![[r#" |
| 1276 | + trait Sub<SubTy = …, SuperTy = …> |
| 1277 | + ^^^^^^^^^ ----------- |
| 1278 | + "#]], |
| 1279 | + ); |
| 1280 | + } |
| 1281 | + |
| 1282 | + #[test] |
| 1283 | + fn no_assoc_types_outside_type_bounds() { |
| 1284 | + check( |
| 1285 | + r#" |
| 1286 | +trait Tr<T> { |
| 1287 | + type Assoc; |
| 1288 | +} |
| 1289 | +
|
| 1290 | +impl Tr<$0 |
| 1291 | + "#, |
| 1292 | + expect![[r#" |
| 1293 | + trait Tr<T> |
| 1294 | + ^ |
| 1295 | + "#]], |
| 1296 | + ); |
| 1297 | + } |
| 1298 | + |
1127 | 1299 | #[test]
|
1128 | 1300 | fn impl_trait() {
|
1129 | 1301 | // FIXME: Substitute type vars in impl trait (`U` -> `i8`)
|
|
0 commit comments