1 //! See [`CompletionContext`] structure. 2 3 mod analysis; 4 #[cfg(test)] 5 mod tests; 6 7 use std::iter; 8 9 use hir::{ 10 HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo, 11 }; 12 use ide_db::{ 13 base_db::{FilePosition, SourceDatabase}, 14 famous_defs::FamousDefs, 15 helpers::is_editable_crate, 16 FxHashMap, FxHashSet, RootDatabase, 17 }; 18 use syntax::{ 19 ast::{self, AttrKind, NameOrNameRef}, 20 AstNode, SmolStr, 21 SyntaxKind::{self, *}, 22 SyntaxToken, TextRange, TextSize, T, 23 }; 24 use text_edit::Indel; 25 26 use crate::{ 27 context::analysis::{expand_and_analyze, AnalysisResult}, 28 CompletionConfig, 29 }; 30 31 const COMPLETION_MARKER: &str = "intellijRulezz"; 32 33 #[derive(Copy, Clone, Debug, PartialEq, Eq)] 34 pub(crate) enum PatternRefutability { 35 Refutable, 36 Irrefutable, 37 } 38 39 #[derive(Debug)] 40 pub(crate) enum Visible { 41 Yes, 42 Editable, 43 No, 44 } 45 46 /// Existing qualifiers for the thing we are currently completing. 47 #[derive(Debug, Default)] 48 pub(super) struct QualifierCtx { 49 pub(super) unsafe_tok: Option<SyntaxToken>, 50 pub(super) vis_node: Option<ast::Visibility>, 51 } 52 53 impl QualifierCtx { none(&self) -> bool54 pub(super) fn none(&self) -> bool { 55 self.unsafe_tok.is_none() && self.vis_node.is_none() 56 } 57 } 58 59 /// The state of the path we are currently completing. 60 #[derive(Debug)] 61 pub(crate) struct PathCompletionCtx { 62 /// If this is a call with () already there (or {} in case of record patterns) 63 pub(super) has_call_parens: bool, 64 /// If this has a macro call bang ! 65 pub(super) has_macro_bang: bool, 66 /// The qualifier of the current path. 67 pub(super) qualified: Qualified, 68 /// The parent of the path we are completing. 69 pub(super) parent: Option<ast::Path>, 70 #[allow(dead_code)] 71 /// The path of which we are completing the segment 72 pub(super) path: ast::Path, 73 /// The path of which we are completing the segment in the original file 74 pub(crate) original_path: Option<ast::Path>, 75 pub(super) kind: PathKind, 76 /// Whether the path segment has type args or not. 77 pub(super) has_type_args: bool, 78 /// Whether the qualifier comes from a use tree parent or not 79 pub(crate) use_tree_parent: bool, 80 } 81 82 impl PathCompletionCtx { is_trivial_path(&self) -> bool83 pub(super) fn is_trivial_path(&self) -> bool { 84 matches!( 85 self, 86 PathCompletionCtx { 87 has_call_parens: false, 88 has_macro_bang: false, 89 qualified: Qualified::No, 90 parent: None, 91 has_type_args: false, 92 .. 93 } 94 ) 95 } 96 } 97 98 /// The kind of path we are completing right now. 99 #[derive(Debug, PartialEq, Eq)] 100 pub(super) enum PathKind { 101 Expr { 102 expr_ctx: ExprCtx, 103 }, 104 Type { 105 location: TypeLocation, 106 }, 107 Attr { 108 attr_ctx: AttrCtx, 109 }, 110 Derive { 111 existing_derives: ExistingDerives, 112 }, 113 /// Path in item position, that is inside an (Assoc)ItemList 114 Item { 115 kind: ItemListKind, 116 }, 117 Pat { 118 pat_ctx: PatternContext, 119 }, 120 Vis { 121 has_in_token: bool, 122 }, 123 Use, 124 } 125 126 pub(crate) type ExistingDerives = FxHashSet<hir::Macro>; 127 128 #[derive(Debug, PartialEq, Eq)] 129 pub(crate) struct AttrCtx { 130 pub(crate) kind: AttrKind, 131 pub(crate) annotated_item_kind: Option<SyntaxKind>, 132 } 133 134 #[derive(Debug, PartialEq, Eq)] 135 pub(crate) struct ExprCtx { 136 pub(crate) in_block_expr: bool, 137 pub(crate) in_loop_body: bool, 138 pub(crate) after_if_expr: bool, 139 /// Whether this expression is the direct condition of an if or while expression 140 pub(crate) in_condition: bool, 141 pub(crate) incomplete_let: bool, 142 pub(crate) ref_expr_parent: Option<ast::RefExpr>, 143 /// The surrounding RecordExpression we are completing a functional update 144 pub(crate) is_func_update: Option<ast::RecordExpr>, 145 pub(crate) self_param: Option<hir::SelfParam>, 146 pub(crate) innermost_ret_ty: Option<hir::Type>, 147 pub(crate) impl_: Option<ast::Impl>, 148 /// Whether this expression occurs in match arm guard position: before the 149 /// fat arrow token 150 pub(crate) in_match_guard: bool, 151 } 152 153 /// Original file ast nodes 154 #[derive(Clone, Debug, PartialEq, Eq)] 155 pub(crate) enum TypeLocation { 156 TupleField, 157 TypeAscription(TypeAscriptionTarget), 158 GenericArgList(Option<ast::GenericArgList>), 159 TypeBound, 160 ImplTarget, 161 ImplTrait, 162 Other, 163 } 164 165 #[derive(Clone, Debug, PartialEq, Eq)] 166 pub(crate) enum TypeAscriptionTarget { 167 Let(Option<ast::Pat>), 168 FnParam(Option<ast::Pat>), 169 RetType(Option<ast::Expr>), 170 Const(Option<ast::Expr>), 171 } 172 173 /// The kind of item list a [`PathKind::Item`] belongs to. 174 #[derive(Debug, PartialEq, Eq)] 175 pub(super) enum ItemListKind { 176 SourceFile, 177 Module, 178 Impl, 179 TraitImpl(Option<ast::Impl>), 180 Trait, 181 ExternBlock, 182 } 183 184 #[derive(Debug)] 185 pub(super) enum Qualified { 186 No, 187 With { 188 path: ast::Path, 189 resolution: Option<PathResolution>, 190 /// How many `super` segments are present in the path 191 /// 192 /// This would be None, if path is not solely made of 193 /// `super` segments, e.g. 194 /// 195 /// ```rust 196 /// use super::foo; 197 /// ``` 198 /// 199 /// Otherwise it should be Some(count of `super`) 200 super_chain_len: Option<usize>, 201 }, 202 /// <_>:: 203 TypeAnchor { 204 ty: Option<hir::Type>, 205 trait_: Option<hir::Trait>, 206 }, 207 /// Whether the path is an absolute path 208 Absolute, 209 } 210 211 /// The state of the pattern we are completing. 212 #[derive(Debug, Clone, PartialEq, Eq)] 213 pub(super) struct PatternContext { 214 pub(super) refutability: PatternRefutability, 215 pub(super) param_ctx: Option<ParamContext>, 216 pub(super) has_type_ascription: bool, 217 pub(super) parent_pat: Option<ast::Pat>, 218 pub(super) ref_token: Option<SyntaxToken>, 219 pub(super) mut_token: Option<SyntaxToken>, 220 /// The record pattern this name or ref is a field of 221 pub(super) record_pat: Option<ast::RecordPat>, 222 pub(super) impl_: Option<ast::Impl>, 223 /// List of missing variants in a match expr 224 pub(super) missing_variants: Vec<hir::Variant>, 225 } 226 227 #[derive(Debug, Clone, PartialEq, Eq)] 228 pub(super) struct ParamContext { 229 pub(super) param_list: ast::ParamList, 230 pub(super) param: ast::Param, 231 pub(super) kind: ParamKind, 232 } 233 234 /// The state of the lifetime we are completing. 235 #[derive(Debug)] 236 pub(super) struct LifetimeContext { 237 pub(super) lifetime: Option<ast::Lifetime>, 238 pub(super) kind: LifetimeKind, 239 } 240 241 /// The kind of lifetime we are completing. 242 #[derive(Debug)] 243 pub(super) enum LifetimeKind { 244 LifetimeParam { is_decl: bool, param: ast::LifetimeParam }, 245 Lifetime, 246 LabelRef, 247 LabelDef, 248 } 249 250 /// The state of the name we are completing. 251 #[derive(Debug)] 252 pub(super) struct NameContext { 253 #[allow(dead_code)] 254 pub(super) name: Option<ast::Name>, 255 pub(super) kind: NameKind, 256 } 257 258 /// The kind of the name we are completing. 259 #[derive(Debug)] 260 #[allow(dead_code)] 261 pub(super) enum NameKind { 262 Const, 263 ConstParam, 264 Enum, 265 Function, 266 IdentPat(PatternContext), 267 MacroDef, 268 MacroRules, 269 /// Fake node 270 Module(ast::Module), 271 RecordField, 272 Rename, 273 SelfParam, 274 Static, 275 Struct, 276 Trait, 277 TypeAlias, 278 TypeParam, 279 Union, 280 Variant, 281 } 282 283 /// The state of the NameRef we are completing. 284 #[derive(Debug)] 285 pub(super) struct NameRefContext { 286 /// NameRef syntax in the original file 287 pub(super) nameref: Option<ast::NameRef>, 288 pub(super) kind: NameRefKind, 289 } 290 291 /// The kind of the NameRef we are completing. 292 #[derive(Debug)] 293 pub(super) enum NameRefKind { 294 Path(PathCompletionCtx), 295 DotAccess(DotAccess), 296 /// Position where we are only interested in keyword completions 297 Keyword(ast::Item), 298 /// The record expression this nameref is a field of and whether a dot precedes the completion identifier. 299 RecordExpr { 300 dot_prefix: bool, 301 expr: ast::RecordExpr, 302 }, 303 Pattern(PatternContext), 304 } 305 306 /// The identifier we are currently completing. 307 #[derive(Debug)] 308 pub(super) enum CompletionAnalysis { 309 Name(NameContext), 310 NameRef(NameRefContext), 311 Lifetime(LifetimeContext), 312 /// The string the cursor is currently inside 313 String { 314 /// original token 315 original: ast::String, 316 /// fake token 317 expanded: Option<ast::String>, 318 }, 319 /// Set if we are currently completing in an unexpanded attribute, this usually implies a builtin attribute like `allow($0)` 320 UnexpandedAttrTT { 321 colon_prefix: bool, 322 fake_attribute_under_caret: Option<ast::Attr>, 323 }, 324 } 325 326 /// Information about the field or method access we are completing. 327 #[derive(Debug)] 328 pub(super) struct DotAccess { 329 pub(super) receiver: Option<ast::Expr>, 330 pub(super) receiver_ty: Option<TypeInfo>, 331 pub(super) kind: DotAccessKind, 332 } 333 334 #[derive(Debug)] 335 pub(super) enum DotAccessKind { 336 Field { 337 /// True if the receiver is an integer and there is no ident in the original file after it yet 338 /// like `0.$0` 339 receiver_is_ambiguous_float_literal: bool, 340 }, 341 Method { 342 has_parens: bool, 343 }, 344 } 345 346 #[derive(Clone, Debug, PartialEq, Eq)] 347 pub(crate) enum ParamKind { 348 Function(ast::Fn), 349 Closure(ast::ClosureExpr), 350 } 351 352 /// `CompletionContext` is created early during completion to figure out, where 353 /// exactly is the cursor, syntax-wise. 354 #[derive(Debug)] 355 pub(crate) struct CompletionContext<'a> { 356 pub(super) sema: Semantics<'a, RootDatabase>, 357 pub(super) scope: SemanticsScope<'a>, 358 pub(super) db: &'a RootDatabase, 359 pub(super) config: &'a CompletionConfig, 360 pub(super) position: FilePosition, 361 362 /// The token before the cursor, in the original file. 363 pub(super) original_token: SyntaxToken, 364 /// The token before the cursor, in the macro-expanded file. 365 pub(super) token: SyntaxToken, 366 /// The crate of the current file. 367 pub(super) krate: hir::Crate, 368 /// The module of the `scope`. 369 pub(super) module: hir::Module, 370 /// Whether nightly toolchain is used. Cached since this is looked up a lot. 371 is_nightly: bool, 372 373 /// The expected name of what we are completing. 374 /// This is usually the parameter name of the function argument we are completing. 375 pub(super) expected_name: Option<NameOrNameRef>, 376 /// The expected type of what we are completing. 377 pub(super) expected_type: Option<Type>, 378 379 pub(super) qualifier_ctx: QualifierCtx, 380 381 pub(super) locals: FxHashMap<Name, Local>, 382 383 /// The module depth of the current module of the cursor position. 384 /// - crate-root 385 /// - mod foo 386 /// - mod bar 387 /// Here depth will be 2 388 pub(super) depth_from_crate_root: usize, 389 } 390 391 impl CompletionContext<'_> { 392 /// The range of the identifier that is being completed. source_range(&self) -> TextRange393 pub(crate) fn source_range(&self) -> TextRange { 394 let kind = self.original_token.kind(); 395 match kind { 396 CHAR => { 397 // assume we are completing a lifetime but the user has only typed the ' 398 cov_mark::hit!(completes_if_lifetime_without_idents); 399 TextRange::at(self.original_token.text_range().start(), TextSize::from(1)) 400 } 401 IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(), 402 _ if kind.is_keyword() => self.original_token.text_range(), 403 _ => TextRange::empty(self.position.offset), 404 } 405 } 406 famous_defs(&self) -> FamousDefs<'_, '_>407 pub(crate) fn famous_defs(&self) -> FamousDefs<'_, '_> { 408 FamousDefs(&self.sema, self.krate) 409 } 410 411 /// Checks if an item is visible and not `doc(hidden)` at the completion site. def_is_visible(&self, item: &ScopeDef) -> Visible412 pub(crate) fn def_is_visible(&self, item: &ScopeDef) -> Visible { 413 match item { 414 ScopeDef::ModuleDef(def) => match def { 415 hir::ModuleDef::Module(it) => self.is_visible(it), 416 hir::ModuleDef::Function(it) => self.is_visible(it), 417 hir::ModuleDef::Adt(it) => self.is_visible(it), 418 hir::ModuleDef::Variant(it) => self.is_visible(it), 419 hir::ModuleDef::Const(it) => self.is_visible(it), 420 hir::ModuleDef::Static(it) => self.is_visible(it), 421 hir::ModuleDef::Trait(it) => self.is_visible(it), 422 hir::ModuleDef::TraitAlias(it) => self.is_visible(it), 423 hir::ModuleDef::TypeAlias(it) => self.is_visible(it), 424 hir::ModuleDef::Macro(it) => self.is_visible(it), 425 hir::ModuleDef::BuiltinType(_) => Visible::Yes, 426 }, 427 ScopeDef::GenericParam(_) 428 | ScopeDef::ImplSelfType(_) 429 | ScopeDef::AdtSelfType(_) 430 | ScopeDef::Local(_) 431 | ScopeDef::Label(_) 432 | ScopeDef::Unknown => Visible::Yes, 433 } 434 } 435 436 /// Checks if an item is visible and not `doc(hidden)` at the completion site. is_visible<I>(&self, item: &I) -> Visible where I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,437 pub(crate) fn is_visible<I>(&self, item: &I) -> Visible 438 where 439 I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy, 440 { 441 let vis = item.visibility(self.db); 442 let attrs = item.attrs(self.db); 443 self.is_visible_impl(&vis, &attrs, item.krate(self.db)) 444 } 445 doc_aliases<I>(&self, item: &I) -> Vec<SmolStr> where I: hir::HasAttrs + Copy,446 pub(crate) fn doc_aliases<I>(&self, item: &I) -> Vec<SmolStr> 447 where 448 I: hir::HasAttrs + Copy, 449 { 450 let attrs = item.attrs(self.db); 451 attrs.doc_aliases().collect() 452 } 453 454 /// Check if an item is `#[doc(hidden)]`. is_item_hidden(&self, item: &hir::ItemInNs) -> bool455 pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool { 456 let attrs = item.attrs(self.db); 457 let krate = item.krate(self.db); 458 match (attrs, krate) { 459 (Some(attrs), Some(krate)) => self.is_doc_hidden(&attrs, krate), 460 _ => false, 461 } 462 } 463 464 /// Checks whether this item should be listed in regards to stability. Returns `true` if we should. check_stability(&self, attrs: Option<&hir::Attrs>) -> bool465 pub(crate) fn check_stability(&self, attrs: Option<&hir::Attrs>) -> bool { 466 let Some(attrs) = attrs else { return true; }; 467 !attrs.is_unstable() || self.is_nightly 468 } 469 470 /// Whether the given trait is an operator trait or not. is_ops_trait(&self, trait_: hir::Trait) -> bool471 pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool { 472 match trait_.attrs(self.db).lang() { 473 Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()), 474 None => false, 475 } 476 } 477 478 /// Returns the traits in scope, with the [`Drop`] trait removed. traits_in_scope(&self) -> hir::VisibleTraits479 pub(crate) fn traits_in_scope(&self) -> hir::VisibleTraits { 480 let mut traits_in_scope = self.scope.visible_traits(); 481 if let Some(drop) = self.famous_defs().core_ops_Drop() { 482 traits_in_scope.0.remove(&drop.into()); 483 } 484 traits_in_scope 485 } 486 iterate_path_candidates( &self, ty: &hir::Type, mut cb: impl FnMut(hir::AssocItem), )487 pub(crate) fn iterate_path_candidates( 488 &self, 489 ty: &hir::Type, 490 mut cb: impl FnMut(hir::AssocItem), 491 ) { 492 let mut seen = FxHashSet::default(); 493 ty.iterate_path_candidates( 494 self.db, 495 &self.scope, 496 &self.traits_in_scope(), 497 Some(self.module), 498 None, 499 |item| { 500 // We might iterate candidates of a trait multiple times here, so deduplicate 501 // them. 502 if seen.insert(item) { 503 cb(item) 504 } 505 None::<()> 506 }, 507 ); 508 } 509 510 /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items and 511 /// passes all doc-aliases along, to funnel it into [`Completions::add_path_resolution`]. process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>))512 pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef, Vec<SmolStr>)) { 513 let _p = profile::span("CompletionContext::process_all_names"); 514 self.scope.process_all_names(&mut |name, def| { 515 if self.is_scope_def_hidden(def) { 516 return; 517 } 518 let doc_aliases = self.doc_aliases_in_scope(def); 519 f(name, def, doc_aliases); 520 }); 521 } 522 process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef))523 pub(crate) fn process_all_names_raw(&self, f: &mut dyn FnMut(Name, ScopeDef)) { 524 let _p = profile::span("CompletionContext::process_all_names_raw"); 525 self.scope.process_all_names(f); 526 } 527 is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool528 fn is_scope_def_hidden(&self, scope_def: ScopeDef) -> bool { 529 if let (Some(attrs), Some(krate)) = (scope_def.attrs(self.db), scope_def.krate(self.db)) { 530 return self.is_doc_hidden(&attrs, krate); 531 } 532 533 false 534 } 535 is_visible_impl( &self, vis: &hir::Visibility, attrs: &hir::Attrs, defining_crate: hir::Crate, ) -> Visible536 fn is_visible_impl( 537 &self, 538 vis: &hir::Visibility, 539 attrs: &hir::Attrs, 540 defining_crate: hir::Crate, 541 ) -> Visible { 542 if !vis.is_visible_from(self.db, self.module.into()) { 543 if !self.config.enable_private_editable { 544 return Visible::No; 545 } 546 // If the definition location is editable, also show private items 547 return if is_editable_crate(defining_crate, self.db) { 548 Visible::Editable 549 } else { 550 Visible::No 551 }; 552 } 553 554 if self.is_doc_hidden(attrs, defining_crate) { 555 Visible::No 556 } else { 557 Visible::Yes 558 } 559 } 560 is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool561 fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool { 562 // `doc(hidden)` items are only completed within the defining crate. 563 self.krate != defining_crate && attrs.has_doc_hidden() 564 } 565 doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec<SmolStr>566 pub(crate) fn doc_aliases_in_scope(&self, scope_def: ScopeDef) -> Vec<SmolStr> { 567 if let Some(attrs) = scope_def.attrs(self.db) { 568 attrs.doc_aliases().collect() 569 } else { 570 vec![] 571 } 572 } 573 } 574 575 // CompletionContext construction 576 impl<'a> CompletionContext<'a> { 577 pub(super) fn new( 578 db: &'a RootDatabase, 579 position @ FilePosition { file_id, offset }: FilePosition, 580 config: &'a CompletionConfig, 581 ) -> Option<(CompletionContext<'a>, CompletionAnalysis)> { 582 let _p = profile::span("CompletionContext::new"); 583 let sema = Semantics::new(db); 584 585 let original_file = sema.parse(file_id); 586 587 // Insert a fake ident to get a valid parse tree. We will use this file 588 // to determine context, though the original_file will be used for 589 // actual completion. 590 let file_with_fake_ident = { 591 let parse = db.parse(file_id); 592 let edit = Indel::insert(offset, COMPLETION_MARKER.to_string()); 593 parse.reparse(&edit).tree() 594 }; 595 596 // always pick the token to the immediate left of the cursor, as that is what we are actually 597 // completing on 598 let original_token = original_file.syntax().token_at_offset(offset).left_biased()?; 599 600 // try to skip completions on path with invalid colons 601 // this approach works in normal path and inside token tree 602 if original_token.kind() == T![:] { 603 // return if no prev token before colon 604 let prev_token = original_token.prev_token()?; 605 606 // only has a single colon 607 if prev_token.kind() != T![:] { 608 return None; 609 } 610 611 // has 3 colon or 2 coloncolon in a row 612 // special casing this as per discussion in https://github.com/rust-lang/rust-analyzer/pull/13611#discussion_r1031845205 613 // and https://github.com/rust-lang/rust-analyzer/pull/13611#discussion_r1032812751 614 if prev_token 615 .prev_token() 616 .map(|t| t.kind() == T![:] || t.kind() == T![::]) 617 .unwrap_or(false) 618 { 619 return None; 620 } 621 } 622 623 let AnalysisResult { 624 analysis, 625 expected: (expected_type, expected_name), 626 qualifier_ctx, 627 token, 628 offset, 629 } = expand_and_analyze( 630 &sema, 631 original_file.syntax().clone(), 632 file_with_fake_ident.syntax().clone(), 633 offset, 634 &original_token, 635 )?; 636 637 // adjust for macro input, this still fails if there is no token written yet 638 let scope = sema.scope_at_offset(&token.parent()?, offset)?; 639 640 let krate = scope.krate(); 641 let module = scope.module(); 642 643 let toolchain = db.crate_graph()[krate.into()].channel; 644 // `toolchain == None` means we're in some detached files. Since we have no information on 645 // the toolchain being used, let's just allow unstable items to be listed. 646 let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None); 647 648 let mut locals = FxHashMap::default(); 649 scope.process_all_names(&mut |name, scope| { 650 if let ScopeDef::Local(local) = scope { 651 locals.insert(name, local); 652 } 653 }); 654 655 let depth_from_crate_root = iter::successors(module.parent(db), |m| m.parent(db)).count(); 656 657 let ctx = CompletionContext { 658 sema, 659 scope, 660 db, 661 config, 662 position, 663 original_token, 664 token, 665 krate, 666 module, 667 is_nightly, 668 expected_name, 669 expected_type, 670 qualifier_ctx, 671 locals, 672 depth_from_crate_root, 673 }; 674 Some((ctx, analysis)) 675 } 676 } 677 678 const OP_TRAIT_LANG_NAMES: &[&str] = &[ 679 "add_assign", 680 "add", 681 "bitand_assign", 682 "bitand", 683 "bitor_assign", 684 "bitor", 685 "bitxor_assign", 686 "bitxor", 687 "deref_mut", 688 "deref", 689 "div_assign", 690 "div", 691 "eq", 692 "fn_mut", 693 "fn_once", 694 "fn", 695 "index_mut", 696 "index", 697 "mul_assign", 698 "mul", 699 "neg", 700 "not", 701 "partial_ord", 702 "rem_assign", 703 "rem", 704 "shl_assign", 705 "shl", 706 "shr_assign", 707 "shr", 708 "sub", 709 ]; 710