diff options
Diffstat (limited to 'compiler/rustc_span/src/symbol.rs')
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 1693 |
1 files changed, 1693 insertions, 0 deletions
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs new file mode 100644 index 00000000000..5092b945f72 --- /dev/null +++ b/compiler/rustc_span/src/symbol.rs @@ -0,0 +1,1693 @@ +//! An "interner" is a data structure that associates values with usize tags and +//! allows bidirectional lookup; i.e., given a value, one can easily find the +//! type, and vice versa. + +use rustc_arena::DroplessArena; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_macros::HashStable_Generic; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + +use std::cmp::{Ord, PartialEq, PartialOrd}; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::str; + +use crate::{Span, DUMMY_SP, SESSION_GLOBALS}; + +#[cfg(test)] +mod tests; + +// The proc macro code for this is in `src/librustc_macros/src/symbols.rs`. +symbols! { + // After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`, + // this should be rarely necessary though if the keywords are kept in alphabetic order. + Keywords { + // Special reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. + Invalid: "", + PathRoot: "{{root}}", + DollarCrate: "$crate", + Underscore: "_", + + // Keywords that are used in stable Rust. + As: "as", + Break: "break", + Const: "const", + Continue: "continue", + Crate: "crate", + Else: "else", + Enum: "enum", + Extern: "extern", + False: "false", + Fn: "fn", + For: "for", + If: "if", + Impl: "impl", + In: "in", + Let: "let", + Loop: "loop", + Match: "match", + Mod: "mod", + Move: "move", + Mut: "mut", + Pub: "pub", + Ref: "ref", + Return: "return", + SelfLower: "self", + SelfUpper: "Self", + Static: "static", + Struct: "struct", + Super: "super", + Trait: "trait", + True: "true", + Type: "type", + Unsafe: "unsafe", + Use: "use", + Where: "where", + While: "while", + + // Keywords that are used in unstable Rust or reserved for future use. + Abstract: "abstract", + Become: "become", + Box: "box", + Do: "do", + Final: "final", + Macro: "macro", + Override: "override", + Priv: "priv", + Typeof: "typeof", + Unsized: "unsized", + Virtual: "virtual", + Yield: "yield", + + // Edition-specific keywords that are used in stable Rust. + Async: "async", // >= 2018 Edition only + Await: "await", // >= 2018 Edition only + Dyn: "dyn", // >= 2018 Edition only + + // Edition-specific keywords that are used in unstable Rust or reserved for future use. + Try: "try", // >= 2018 Edition only + + // Special lifetime names + UnderscoreLifetime: "'_", + StaticLifetime: "'static", + + // Weak keywords, have special meaning only in specific contexts. + Auto: "auto", + Catch: "catch", + Default: "default", + MacroRules: "macro_rules", + Raw: "raw", + Union: "union", + } + + // Pre-interned symbols that can be referred to with `rustc_span::sym::*`. + // + // The symbol is the stringified identifier unless otherwise specified, in + // which case the name should mention the non-identifier punctuation. + // E.g. `sym::proc_dash_macro` represents "proc-macro", and it shouldn't be + // called `sym::proc_macro` because then it's easy to mistakenly think it + // represents "proc_macro". + // + // As well as the symbols listed, there are symbols for the the strings + // "0", "1", ..., "9", which are accessible via `sym::integer`. + // + // The proc macro will abort if symbols are not in alphabetical order (as + // defined by `impl Ord for str`) or if any symbols are duplicated. Vim + // users can sort the list by selecting it and executing the command + // `:'<,'>!LC_ALL=C sort`. + // + // There is currently no checking that all symbols are used; that would be + // nice to have. + Symbols { + Alignment, + Arc, + Argument, + ArgumentV1, + Arguments, + C, + Center, + Clone, + Copy, + Count, + Debug, + Decodable, + Decoder, + Default, + Encodable, + Encoder, + Eq, + Equal, + Err, + Error, + FormatSpec, + Formatter, + From, + Future, + FxHashMap, + FxHashSet, + GlobalAlloc, + Hash, + HashMap, + HashSet, + Hasher, + Implied, + Input, + IntoIterator, + Is, + ItemContext, + Iterator, + Layout, + Left, + LintPass, + None, + Ok, + Option, + Ord, + Ordering, + Output, + Param, + PartialEq, + PartialOrd, + Pending, + Pin, + Poll, + ProcMacro, + ProcMacroHack, + ProceduralMasqueradeDummyType, + Range, + RangeFrom, + RangeFull, + RangeInclusive, + RangeTo, + RangeToInclusive, + Rc, + Ready, + Result, + Return, + Right, + RustcDecodable, + RustcEncodable, + Send, + Some, + StructuralEq, + StructuralPartialEq, + Sync, + Target, + Try, + Ty, + TyCtxt, + TyKind, + Unknown, + Vec, + Yield, + _DECLS, + _Self, + __D, + __H, + __S, + __next, + __try_var, + _d, + _e, + _task_context, + aarch64_target_feature, + abi, + abi_amdgpu_kernel, + abi_avr_interrupt, + abi_efiapi, + abi_msp430_interrupt, + abi_ptx, + abi_sysv64, + abi_thiscall, + abi_unadjusted, + abi_vectorcall, + abi_x86_interrupt, + abort, + aborts, + add, + add_assign, + add_with_overflow, + address, + advanced_slice_patterns, + adx_target_feature, + alias, + align, + align_offset, + alignstack, + all, + alloc, + alloc_error_handler, + alloc_layout, + alloc_zeroed, + allocator, + allocator_internals, + allow, + allow_fail, + allow_internal_unsafe, + allow_internal_unstable, + allow_internal_unstable_backcompat_hack, + allowed, + always, + and, + and_then, + any, + arbitrary_enum_discriminant, + arbitrary_self_types, + arith_offset, + arm_target_feature, + array, + arrays, + as_str, + asm, + assert, + assert_inhabited, + assert_receiver_is_total_eq, + assert_uninit_valid, + assert_zero_valid, + associated_consts, + associated_type_bounds, + associated_type_defaults, + associated_types, + assume, + assume_init, + async_await, + async_closure, + atomics, + att_syntax, + attr, + attr_literals, + attributes, + augmented_assignments, + automatically_derived, + avx512_target_feature, + await_macro, + bang, + begin_panic, + bench, + bin, + bind_by_move_pattern_guards, + bindings_after_at, + bitand, + bitand_assign, + bitor, + bitor_assign, + bitreverse, + bitxor, + bitxor_assign, + block, + bool, + borrowck_graphviz_format, + borrowck_graphviz_postflow, + borrowck_graphviz_preflow, + box_free, + box_patterns, + box_syntax, + braced_empty_structs, + breakpoint, + bridge, + bswap, + c_variadic, + call, + call_mut, + call_once, + caller_location, + cdylib, + ceilf32, + ceilf64, + cfg, + cfg_accessible, + cfg_attr, + cfg_attr_multi, + cfg_doctest, + cfg_sanitize, + cfg_target_feature, + cfg_target_has_atomic, + cfg_target_thread_local, + cfg_target_vendor, + cfg_version, + char, + client, + clippy, + clone, + clone_closures, + clone_from, + closure_to_fn_coercion, + cmp, + cmpxchg16b_target_feature, + coerce_unsized, + cold, + column, + compile_error, + compiler_builtins, + concat, + concat_idents, + conservative_impl_trait, + console, + const_compare_raw_pointers, + const_constructor, + const_eval_limit, + const_extern_fn, + const_fn, + const_fn_transmute, + const_fn_union, + const_generics, + const_if_match, + const_in_array_repeat_expressions, + const_indexing, + const_let, + const_loop, + const_mut_refs, + const_panic, + const_precise_live_drops, + const_ptr, + const_raw_ptr_deref, + const_raw_ptr_to_usize_cast, + const_slice_ptr, + const_trait_bound_opt_out, + const_trait_impl, + const_transmute, + contents, + context, + convert, + copy, + copy_closures, + copy_nonoverlapping, + copysignf32, + copysignf64, + core, + core_intrinsics, + cosf32, + cosf64, + crate_id, + crate_in_paths, + crate_local, + crate_name, + crate_type, + crate_visibility_modifier, + crt_dash_static: "crt-static", + ctlz, + ctlz_nonzero, + ctpop, + cttz, + cttz_nonzero, + custom_attribute, + custom_derive, + custom_inner_attributes, + custom_test_frameworks, + d, + dead_code, + dealloc, + debug, + debug_assertions, + debug_struct, + debug_trait, + debug_trait_builder, + debug_tuple, + decl_macro, + declare_lint_pass, + decode, + default_lib_allocator, + default_type_parameter_fallback, + default_type_params, + delay_span_bug_from_inside_query, + deny, + deprecated, + deref, + deref_mut, + derive, + diagnostic, + direct, + discriminant_kind, + discriminant_type, + discriminant_value, + dispatch_from_dyn, + div, + div_assign, + doc, + doc_alias, + doc_cfg, + doc_keyword, + doc_masked, + doc_spotlight, + doctest, + document_private_items, + dotdot_in_tuple_patterns, + dotdoteq_in_patterns, + double_braced_closure: "{{closure}}", + double_braced_constant: "{{constant}}", + double_braced_constructor: "{{constructor}}", + double_braced_crate: "{{crate}}", + double_braced_impl: "{{impl}}", + double_braced_misc: "{{misc}}", + double_braced_opaque: "{{opaque}}", + drop, + drop_in_place, + drop_types_in_const, + dropck_eyepatch, + dropck_parametricity, + dylib, + dyn_trait, + eh_catch_typeinfo, + eh_personality, + emit_enum, + emit_enum_variant, + emit_enum_variant_arg, + emit_struct, + emit_struct_field, + enable, + enclosing_scope, + encode, + env, + eq, + err, + exact_div, + except, + exchange_malloc, + exclusive_range_pattern, + exhaustive_integer_patterns, + exhaustive_patterns, + existential_type, + exp2f32, + exp2f64, + expected, + expf32, + expf64, + export_name, + expr, + extern_absolute_paths, + extern_crate_item_prelude, + extern_crate_self, + extern_in_paths, + extern_prelude, + extern_types, + external_doc, + f, + f16c_target_feature, + f32, + f32_runtime, + f64, + f64_runtime, + fabsf32, + fabsf64, + fadd_fast, + fdiv_fast, + feature, + ffi_const, + ffi_pure, + ffi_returns_twice, + field, + field_init_shorthand, + file, + fill, + finish, + flags, + float_to_int_unchecked, + floorf32, + floorf64, + fmaf32, + fmaf64, + fmt, + fmt_internals, + fmul_fast, + fn_must_use, + fn_mut, + fn_once, + fn_once_output, + forbid, + forget, + format, + format_args, + format_args_capture, + format_args_nl, + freeze, + frem_fast, + from, + from_desugaring, + from_error, + from_generator, + from_method, + from_ok, + from_size_align_unchecked, + from_trait, + from_usize, + fsub_fast, + fundamental, + future, + future_trait, + ge, + gen_future, + gen_kill, + generator, + generator_state, + generators, + generic_associated_types, + generic_param_attrs, + get_context, + global_allocator, + global_asm, + globs, + gt, + half_open_range_patterns, + hash, + hexagon_target_feature, + hidden, + homogeneous_aggregate, + html_favicon_url, + html_logo_url, + html_no_source, + html_playground_url, + html_root_url, + i, + i128, + i128_type, + i16, + i32, + i64, + i8, + ident, + if_let, + if_let_guard, + if_while_or_patterns, + ignore, + impl_header_lifetime_elision, + impl_lint_pass, + impl_macros, + impl_trait_in_bindings, + import_shadowing, + in_band_lifetimes, + include, + include_bytes, + include_str, + inclusive_range_syntax, + index, + index_mut, + infer_outlives_requirements, + infer_static_outlives_requirements, + inlateout, + inline, + inout, + intel, + into_iter, + into_result, + intrinsics, + irrefutable_let_patterns, + isize, + issue, + issue_5723_bootstrap, + issue_tracker_base_url, + item, + item_like_imports, + iter, + keyword, + kind, + label, + label_break_value, + lang, + lang_items, + lateout, + lazy_normalization_consts, + le, + let_chains, + lhs, + lib, + libc, + lifetime, + likely, + line, + link, + link_args, + link_cfg, + link_llvm_intrinsics, + link_name, + link_ordinal, + link_section, + linkage, + lint_reasons, + literal, + llvm_asm, + local_inner_macros, + log10f32, + log10f64, + log2f32, + log2f64, + log_syntax, + logf32, + logf64, + loop_break_value, + lt, + macro_at_most_once_rep, + macro_escape, + macro_export, + macro_lifetime_matcher, + macro_literal_matcher, + macro_reexport, + macro_use, + macro_vis_matcher, + macros_in_extern, + main, + managed_boxes, + manually_drop, + map, + marker, + marker_trait_attr, + masked, + match_beginning_vert, + match_default_bindings, + maxnumf32, + maxnumf64, + may_dangle, + maybe_uninit, + maybe_uninit_uninit, + maybe_uninit_zeroed, + mem_uninitialized, + mem_zeroed, + member_constraints, + memory, + message, + meta, + min_align_of, + min_align_of_val, + min_const_fn, + min_const_generics, + min_const_unsafe_fn, + min_specialization, + minnumf32, + minnumf64, + mips_target_feature, + mmx_target_feature, + module, + module_path, + more_struct_aliases, + movbe_target_feature, + move_ref_pattern, + move_val_init, + mul, + mul_assign, + mul_with_overflow, + must_use, + mut_ptr, + mut_slice_ptr, + naked, + naked_functions, + name, + ne, + nearbyintf32, + nearbyintf64, + needs_allocator, + needs_drop, + needs_panic_runtime, + neg, + negate_unsigned, + negative_impls, + never, + never_type, + never_type_fallback, + new, + new_unchecked, + next, + nll, + no, + no_builtins, + no_core, + no_crate_inject, + no_debug, + no_default_passes, + no_implicit_prelude, + no_inline, + no_link, + no_main, + no_mangle, + no_niche, + no_sanitize, + no_stack_check, + no_start, + no_std, + nomem, + non_ascii_idents, + non_exhaustive, + non_modrs_mods, + none_error, + nontemporal_store, + nontrapping_dash_fptoint: "nontrapping-fptoint", + noreturn, + nostack, + not, + note, + object_safe_for_dispatch, + of, + offset, + omit_gdb_pretty_printer_section, + on, + on_unimplemented, + oom, + opaque, + ops, + opt_out_copy, + optimize, + optimize_attribute, + optin_builtin_traits, + option, + option_env, + option_type, + options, + or, + or_patterns, + other, + out, + overlapping_marker_traits, + owned_box, + packed, + panic, + panic_abort, + panic_bounds_check, + panic_handler, + panic_impl, + panic_implementation, + panic_info, + panic_location, + panic_runtime, + panic_unwind, + param_attrs, + parent_trait, + partial_cmp, + partial_ord, + passes, + pat, + path, + pattern_parentheses, + phantom_data, + pin, + pinned, + platform_intrinsics, + plugin, + plugin_registrar, + plugins, + pointer, + poll, + position, + post_dash_lto: "post-lto", + powerpc_target_feature, + powf32, + powf64, + powif32, + powif64, + pre_dash_lto: "pre-lto", + precise_pointer_size_matching, + precision, + pref_align_of, + prefetch_read_data, + prefetch_read_instruction, + prefetch_write_data, + prefetch_write_instruction, + prelude, + prelude_import, + preserves_flags, + primitive, + proc_dash_macro: "proc-macro", + proc_macro, + proc_macro_attribute, + proc_macro_def_site, + proc_macro_derive, + proc_macro_expr, + proc_macro_gen, + proc_macro_hygiene, + proc_macro_internals, + proc_macro_mod, + proc_macro_non_items, + proc_macro_path_invoc, + profiler_builtins, + profiler_runtime, + ptr_guaranteed_eq, + ptr_guaranteed_ne, + ptr_offset_from, + pub_restricted, + pure, + pushpop_unsafe, + quad_precision_float, + question_mark, + quote, + range_inclusive_new, + raw_dylib, + raw_identifiers, + raw_ref_op, + re_rebalance_coherence, + read_enum, + read_enum_variant, + read_enum_variant_arg, + read_struct, + read_struct_field, + readonly, + realloc, + reason, + receiver, + recursion_limit, + reexport_test_harness_main, + reference, + reflect, + register_attr, + register_tool, + relaxed_adts, + rem, + rem_assign, + repr, + repr128, + repr_align, + repr_align_enum, + repr_no_niche, + repr_packed, + repr_simd, + repr_transparent, + result, + result_type, + rhs, + rintf32, + rintf64, + riscv_target_feature, + rlib, + rotate_left, + rotate_right, + roundf32, + roundf64, + rt, + rtm_target_feature, + rust, + rust_2015_preview, + rust_2018_preview, + rust_begin_unwind, + rust_eh_catch_typeinfo, + rust_eh_personality, + rust_eh_register_frames, + rust_eh_unregister_frames, + rust_oom, + rustc, + rustc_allocator, + rustc_allocator_nounwind, + rustc_allow_const_fn_ptr, + rustc_args_required_const, + rustc_attrs, + rustc_builtin_macro, + rustc_clean, + rustc_const_stable, + rustc_const_unstable, + rustc_conversion_suggestion, + rustc_def_path, + rustc_deprecated, + rustc_diagnostic_item, + rustc_diagnostic_macros, + rustc_dirty, + rustc_dummy, + rustc_dump_env_program_clauses, + rustc_dump_program_clauses, + rustc_dump_user_substs, + rustc_error, + rustc_expected_cgu_reuse, + rustc_if_this_changed, + rustc_inherit_overflow_checks, + rustc_layout, + rustc_layout_scalar_valid_range_end, + rustc_layout_scalar_valid_range_start, + rustc_macro_transparency, + rustc_mir, + rustc_nonnull_optimization_guaranteed, + rustc_object_lifetime_default, + rustc_on_unimplemented, + rustc_outlives, + rustc_paren_sugar, + rustc_partition_codegened, + rustc_partition_reused, + rustc_peek, + rustc_peek_definite_init, + rustc_peek_indirectly_mutable, + rustc_peek_liveness, + rustc_peek_maybe_init, + rustc_peek_maybe_uninit, + rustc_polymorphize_error, + rustc_private, + rustc_proc_macro_decls, + rustc_promotable, + rustc_regions, + rustc_reservation_impl, + rustc_serialize, + rustc_specialization_trait, + rustc_stable, + rustc_std_internal_symbol, + rustc_symbol_name, + rustc_synthetic, + rustc_test_marker, + rustc_then_this_would_need, + rustc_unsafe_specialization_marker, + rustc_variance, + rustfmt, + rvalue_static_promotion, + sanitize, + sanitizer_runtime, + saturating_add, + saturating_sub, + self_in_typedefs, + self_struct_ctor, + semitransparent, + send_trait, + shl, + shl_assign, + should_panic, + shr, + shr_assign, + simd, + simd_add, + simd_and, + simd_bitmask, + simd_cast, + simd_ceil, + simd_div, + simd_eq, + simd_extract, + simd_fabs, + simd_fcos, + simd_fexp, + simd_fexp2, + simd_ffi, + simd_flog, + simd_flog10, + simd_flog2, + simd_floor, + simd_fma, + simd_fmax, + simd_fmin, + simd_fpow, + simd_fpowi, + simd_fsin, + simd_fsqrt, + simd_gather, + simd_ge, + simd_gt, + simd_insert, + simd_le, + simd_lt, + simd_mul, + simd_ne, + simd_or, + simd_reduce_add_ordered, + simd_reduce_add_unordered, + simd_reduce_all, + simd_reduce_and, + simd_reduce_any, + simd_reduce_max, + simd_reduce_max_nanless, + simd_reduce_min, + simd_reduce_min_nanless, + simd_reduce_mul_ordered, + simd_reduce_mul_unordered, + simd_reduce_or, + simd_reduce_xor, + simd_rem, + simd_saturating_add, + simd_saturating_sub, + simd_scatter, + simd_select, + simd_select_bitmask, + simd_shl, + simd_shr, + simd_sub, + simd_xor, + since, + sinf32, + sinf64, + size, + size_of, + size_of_val, + sized, + slice, + slice_alloc, + slice_patterns, + slice_u8, + slice_u8_alloc, + slicing_syntax, + soft, + specialization, + speed, + spotlight, + sqrtf32, + sqrtf64, + sse4a_target_feature, + stable, + staged_api, + start, + state, + static_in_const, + static_nobundle, + static_recursion, + staticlib, + std, + std_inject, + stmt, + stmt_expr_attributes, + stop_after_dataflow, + str, + str_alloc, + string_type, + stringify, + struct_field_attributes, + struct_inherit, + struct_variant, + structural_match, + structural_peq, + structural_teq, + sty, + sub, + sub_assign, + sub_with_overflow, + suggestion, + sym, + sync, + sync_trait, + target_arch, + target_endian, + target_env, + target_family, + target_feature, + target_feature_11, + target_has_atomic, + target_has_atomic_load_store, + target_os, + target_pointer_width, + target_target_vendor, + target_thread_local, + target_vendor, + task, + tbm_target_feature, + termination, + termination_trait, + termination_trait_test, + test, + test_2018_feature, + test_accepted_feature, + test_case, + test_removed_feature, + test_runner, + then_with, + thread, + thread_local, + tool_attributes, + tool_lints, + trace_macros, + track_caller, + trait_alias, + transmute, + transparent, + transparent_enums, + transparent_unions, + trivial_bounds, + truncf32, + truncf64, + try_blocks, + try_trait, + tt, + tuple, + tuple_indexing, + two_phase, + ty, + type_alias_enum_variants, + type_alias_impl_trait, + type_ascription, + type_id, + type_length_limit, + type_macros, + type_name, + u128, + u16, + u32, + u64, + u8, + unaligned_volatile_load, + unaligned_volatile_store, + unboxed_closures, + unchecked_add, + unchecked_div, + unchecked_mul, + unchecked_rem, + unchecked_shl, + unchecked_shr, + unchecked_sub, + underscore_const_names, + underscore_imports, + underscore_lifetimes, + uniform_paths, + unit, + universal_impl_trait, + unix, + unlikely, + unmarked_api, + unpin, + unreachable, + unreachable_code, + unrestricted_attribute_tokens, + unsafe_block_in_unsafe_fn, + unsafe_cell, + unsafe_no_drop_flag, + unsize, + unsized_locals, + unsized_tuple_coercion, + unstable, + untagged_unions, + unused_qualifications, + unwind, + unwind_attributes, + unwrap_or, + use_extern_macros, + use_nested_groups, + used, + usize, + v1, + va_arg, + va_copy, + va_end, + va_list, + va_start, + val, + var, + variant_count, + vec, + vec_type, + version, + vis, + visible_private_types, + volatile, + volatile_copy_memory, + volatile_copy_nonoverlapping_memory, + volatile_load, + volatile_set_memory, + volatile_store, + warn, + wasm_import_module, + wasm_target_feature, + while_let, + width, + windows, + windows_subsystem, + wrapping_add, + wrapping_mul, + wrapping_sub, + write_bytes, + } +} + +#[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] +pub struct Ident { + pub name: Symbol, + pub span: Span, +} + +impl Ident { + #[inline] + /// Constructs a new identifier from a symbol and a span. + pub const fn new(name: Symbol, span: Span) -> Ident { + Ident { name, span } + } + + /// Constructs a new identifier with a dummy span. + #[inline] + pub const fn with_dummy_span(name: Symbol) -> Ident { + Ident::new(name, DUMMY_SP) + } + + #[inline] + pub fn invalid() -> Ident { + Ident::with_dummy_span(kw::Invalid) + } + + /// Maps a string to an identifier with a dummy span. + pub fn from_str(string: &str) -> Ident { + Ident::with_dummy_span(Symbol::intern(string)) + } + + /// Maps a string and a span to an identifier. + pub fn from_str_and_span(string: &str, span: Span) -> Ident { + Ident::new(Symbol::intern(string), span) + } + + /// Replaces `lo` and `hi` with those from `span`, but keep hygiene context. + pub fn with_span_pos(self, span: Span) -> Ident { + Ident::new(self.name, span.with_ctxt(self.span.ctxt())) + } + + pub fn without_first_quote(self) -> Ident { + Ident::new(Symbol::intern(self.as_str().trim_start_matches('\'')), self.span) + } + + /// "Normalize" ident for use in comparisons using "item hygiene". + /// Identifiers with same string value become same if they came from the same macro 2.0 macro + /// (e.g., `macro` item, but not `macro_rules` item) and stay different if they came from + /// different macro 2.0 macros. + /// Technically, this operation strips all non-opaque marks from ident's syntactic context. + pub fn normalize_to_macros_2_0(self) -> Ident { + Ident::new(self.name, self.span.normalize_to_macros_2_0()) + } + + /// "Normalize" ident for use in comparisons using "local variable hygiene". + /// Identifiers with same string value become same if they came from the same non-transparent + /// macro (e.g., `macro` or `macro_rules!` items) and stay different if they came from different + /// non-transparent macros. + /// Technically, this operation strips all transparent marks from ident's syntactic context. + pub fn normalize_to_macro_rules(self) -> Ident { + Ident::new(self.name, self.span.normalize_to_macro_rules()) + } + + /// Convert the name to a `SymbolStr`. This is a slowish operation because + /// it requires locking the symbol interner. + pub fn as_str(self) -> SymbolStr { + self.name.as_str() + } +} + +impl PartialEq for Ident { + fn eq(&self, rhs: &Self) -> bool { + self.name == rhs.name && self.span.ctxt() == rhs.span.ctxt() + } +} + +impl Hash for Ident { + fn hash<H: Hasher>(&self, state: &mut H) { + self.name.hash(state); + self.span.ctxt().hash(state); + } +} + +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f)?; + fmt::Debug::fmt(&self.span.ctxt(), f) + } +} + +/// This implementation is supposed to be used in error messages, so it's expected to be identical +/// to printing the original identifier token written in source code (`token_to_string`), +/// except that AST identifiers don't keep the rawness flag, so we have to guess it. +impl fmt::Display for Ident { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f) + } +} + +/// This is the most general way to print identifiers. +/// AST pretty-printer is used as a fallback for turning AST structures into token streams for +/// proc macros. Additionally, proc macros may stringify their input and expect it survive the +/// stringification (especially true for proc macro derives written between Rust 1.15 and 1.30). +/// So we need to somehow pretty-print `$crate` in a way preserving at least some of its +/// hygiene data, most importantly name of the crate it refers to. +/// As a result we print `$crate` as `crate` if it refers to the local crate +/// and as `::other_crate_name` if it refers to some other crate. +/// Note, that this is only done if the ident token is printed from inside of AST pretty-pringing, +/// but not otherwise. Pretty-printing is the only way for proc macros to discover token contents, +/// so we should not perform this lossy conversion if the top level call to the pretty-printer was +/// done for a token stream or a single token. +pub struct IdentPrinter { + symbol: Symbol, + is_raw: bool, + /// Span used for retrieving the crate name to which `$crate` refers to, + /// if this field is `None` then the `$crate` conversion doesn't happen. + convert_dollar_crate: Option<Span>, +} + +impl IdentPrinter { + /// The most general `IdentPrinter` constructor. Do not use this. + pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option<Span>) -> IdentPrinter { + IdentPrinter { symbol, is_raw, convert_dollar_crate } + } + + /// This implementation is supposed to be used when printing identifiers + /// as a part of pretty-printing for larger AST pieces. + /// Do not use this either. + pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter { + IdentPrinter::new(ident.name, is_raw, Some(ident.span)) + } +} + +impl fmt::Display for IdentPrinter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.is_raw { + f.write_str("r#")?; + } else { + if self.symbol == kw::DollarCrate { + if let Some(span) = self.convert_dollar_crate { + let converted = span.ctxt().dollar_crate_name(); + if !converted.is_path_segment_keyword() { + f.write_str("::")?; + } + return fmt::Display::fmt(&converted, f); + } + } + } + fmt::Display::fmt(&self.symbol, f) + } +} + +/// An newtype around `Ident` that calls [Ident::normalize_to_macro_rules] on +/// construction. +// FIXME(matthewj, petrochenkov) Use this more often, add a similar +// `ModernIdent` struct and use that as well. +#[derive(Copy, Clone, Eq, PartialEq, Hash)] +pub struct MacroRulesNormalizedIdent(Ident); + +impl MacroRulesNormalizedIdent { + pub fn new(ident: Ident) -> Self { + Self(ident.normalize_to_macro_rules()) + } +} + +impl fmt::Debug for MacroRulesNormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl fmt::Display for MacroRulesNormalizedIdent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +/// An interned string. +/// +/// Internally, a `Symbol` is implemented as an index, and all operations +/// (including hashing, equality, and ordering) operate on that index. The use +/// of `rustc_index::newtype_index!` means that `Option<Symbol>` only takes up 4 bytes, +/// because `rustc_index::newtype_index!` reserves the last 256 values for tagging purposes. +/// +/// Note that `Symbol` cannot directly be a `rustc_index::newtype_index!` because it +/// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Symbol(SymbolIndex); + +rustc_index::newtype_index! { + pub struct SymbolIndex { .. } +} + +impl Symbol { + const fn new(n: u32) -> Self { + Symbol(SymbolIndex::from_u32(n)) + } + + /// Maps a string to its interned representation. + pub fn intern(string: &str) -> Self { + with_interner(|interner| interner.intern(string)) + } + + /// Access the symbol's chars. This is a slowish operation because it + /// requires locking the symbol interner. + pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R { + with_interner(|interner| f(interner.get(self))) + } + + /// Convert to a `SymbolStr`. This is a slowish operation because it + /// requires locking the symbol interner. + pub fn as_str(self) -> SymbolStr { + with_interner(|interner| unsafe { + SymbolStr { string: std::mem::transmute::<&str, &str>(interner.get(self)) } + }) + } + + pub fn as_u32(self) -> u32 { + self.0.as_u32() + } + + /// This method is supposed to be used in error messages, so it's expected to be + /// identical to printing the original identifier token written in source code + /// (`token_to_string`, `Ident::to_string`), except that symbols don't keep the rawness flag + /// or edition, so we have to guess the rawness using the global edition. + pub fn to_ident_string(self) -> String { + Ident::with_dummy_span(self).to_string() + } +} + +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.with(|str| fmt::Debug::fmt(&str, f)) + } +} + +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.with(|str| fmt::Display::fmt(&str, f)) + } +} + +impl<S: Encoder> Encodable<S> for Symbol { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + self.with(|string| s.emit_str(string)) + } +} + +impl<D: Decoder> Decodable<D> for Symbol { + #[inline] + fn decode(d: &mut D) -> Result<Symbol, D::Error> { + Ok(Symbol::intern(&d.read_str()?)) + } +} + +impl<CTX> HashStable<CTX> for Symbol { + #[inline] + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.as_str().hash_stable(hcx, hasher); + } +} + +impl<CTX> ToStableHashKey<CTX> for Symbol { + type KeyType = SymbolStr; + + #[inline] + fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr { + self.as_str() + } +} + +// The `&'static str`s in this type actually point into the arena. +// +// The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278 +// found that to regress performance up to 2% in some cases. This might be +// revisited after further improvements to `indexmap`. +#[derive(Default)] +pub struct Interner { + arena: DroplessArena, + names: FxHashMap<&'static str, Symbol>, + strings: Vec<&'static str>, +} + +impl Interner { + fn prefill(init: &[&'static str]) -> Self { + Interner { + strings: init.into(), + names: init.iter().copied().zip((0..).map(Symbol::new)).collect(), + ..Default::default() + } + } + + #[inline] + pub fn intern(&mut self, string: &str) -> Symbol { + if let Some(&name) = self.names.get(string) { + return name; + } + + let name = Symbol::new(self.strings.len() as u32); + + // `from_utf8_unchecked` is safe since we just allocated a `&str` which is known to be + // UTF-8. + let string: &str = + unsafe { str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes())) }; + // It is safe to extend the arena allocation to `'static` because we only access + // these while the arena is still alive. + let string: &'static str = unsafe { &*(string as *const str) }; + self.strings.push(string); + self.names.insert(string, name); + name + } + + // Get the symbol as a string. `Symbol::as_str()` should be used in + // preference to this function. + pub fn get(&self, symbol: Symbol) -> &str { + self.strings[symbol.0.as_usize()] + } +} + +// This module has a very short name because it's used a lot. +/// This module contains all the defined keyword `Symbol`s. +/// +/// Given that `kw` is imported, use them like `kw::keyword_name`. +/// For example `kw::Loop` or `kw::Break`. +pub mod kw { + use super::Symbol; + keywords!(); +} + +// This module has a very short name because it's used a lot. +/// This module contains all the defined non-keyword `Symbol`s. +/// +/// Given that `sym` is imported, use them like `sym::symbol_name`. +/// For example `sym::rustfmt` or `sym::u8`. +#[allow(rustc::default_hash_types)] +pub mod sym { + use super::Symbol; + use std::convert::TryInto; + + define_symbols!(); + + // Used from a macro in `librustc_feature/accepted.rs` + pub use super::kw::MacroRules as macro_rules; + + // Get the symbol for an integer. The first few non-negative integers each + // have a static symbol and therefore are fast. + pub fn integer<N: TryInto<usize> + Copy + ToString>(n: N) -> Symbol { + if let Result::Ok(idx) = n.try_into() { + if let Option::Some(&sym_) = digits_array.get(idx) { + return sym_; + } + } + Symbol::intern(&n.to_string()) + } +} + +impl Symbol { + fn is_used_keyword_2018(self) -> bool { + self >= kw::Async && self <= kw::Dyn + } + + fn is_unused_keyword_2018(self) -> bool { + self == kw::Try + } + + /// Used for sanity checking rustdoc keyword sections. + pub fn is_doc_keyword(self) -> bool { + self <= kw::Union + } + + /// A keyword or reserved identifier that can be used as a path segment. + pub fn is_path_segment_keyword(self) -> bool { + self == kw::Super + || self == kw::SelfLower + || self == kw::SelfUpper + || self == kw::Crate + || self == kw::PathRoot + || self == kw::DollarCrate + } + + /// Returns `true` if the symbol is `true` or `false`. + pub fn is_bool_lit(self) -> bool { + self == kw::True || self == kw::False + } + + /// This symbol can be a raw identifier. + pub fn can_be_raw(self) -> bool { + self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword() + } +} + +impl Ident { + // Returns `true` for reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. + pub fn is_special(self) -> bool { + self.name <= kw::Underscore + } + + /// Returns `true` if the token is a keyword used in the language. + pub fn is_used_keyword(self) -> bool { + // Note: `span.edition()` is relatively expensive, don't call it unless necessary. + self.name >= kw::As && self.name <= kw::While + || self.name.is_used_keyword_2018() && self.span.rust_2018() + } + + /// Returns `true` if the token is a keyword reserved for possible future use. + pub fn is_unused_keyword(self) -> bool { + // Note: `span.edition()` is relatively expensive, don't call it unless necessary. + self.name >= kw::Abstract && self.name <= kw::Yield + || self.name.is_unused_keyword_2018() && self.span.rust_2018() + } + + /// Returns `true` if the token is either a special identifier or a keyword. + pub fn is_reserved(self) -> bool { + self.is_special() || self.is_used_keyword() || self.is_unused_keyword() + } + + /// A keyword or reserved identifier that can be used as a path segment. + pub fn is_path_segment_keyword(self) -> bool { + self.name.is_path_segment_keyword() + } + + /// We see this identifier in a normal identifier position, like variable name or a type. + /// How was it written originally? Did it use the raw form? Let's try to guess. + pub fn is_raw_guess(self) -> bool { + self.name.can_be_raw() && self.is_reserved() + } +} + +#[inline] +fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T { + SESSION_GLOBALS.with(|session_globals| f(&mut *session_globals.symbol_interner.lock())) +} + +/// An alternative to `Symbol`, useful when the chars within the symbol need to +/// be accessed. It deliberately has limited functionality and should only be +/// used for temporary values. +/// +/// Because the interner outlives any thread which uses this type, we can +/// safely treat `string` which points to interner data, as an immortal string, +/// as long as this type never crosses between threads. +// +// FIXME: ensure that the interner outlives any thread which uses `SymbolStr`, +// by creating a new thread right after constructing the interner. +#[derive(Clone, Eq, PartialOrd, Ord)] +pub struct SymbolStr { + string: &'static str, +} + +// This impl allows a `SymbolStr` to be directly equated with a `String` or +// `&str`. +impl<T: std::ops::Deref<Target = str>> std::cmp::PartialEq<T> for SymbolStr { + fn eq(&self, other: &T) -> bool { + self.string == other.deref() + } +} + +impl !Send for SymbolStr {} +impl !Sync for SymbolStr {} + +/// This impl means that if `ss` is a `SymbolStr`: +/// - `*ss` is a `str`; +/// - `&*ss` is a `&str` (and `match &*ss { ... }` is a common pattern). +/// - `&ss as &str` is a `&str`, which means that `&ss` can be passed to a +/// function expecting a `&str`. +impl std::ops::Deref for SymbolStr { + type Target = str; + #[inline] + fn deref(&self) -> &str { + self.string + } +} + +impl fmt::Debug for SymbolStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.string, f) + } +} + +impl fmt::Display for SymbolStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.string, f) + } +} + +impl<CTX> HashStable<CTX> for SymbolStr { + #[inline] + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.string.hash_stable(hcx, hasher) + } +} + +impl<CTX> ToStableHashKey<CTX> for SymbolStr { + type KeyType = SymbolStr; + + #[inline] + fn to_stable_hash_key(&self, _: &CTX) -> SymbolStr { + self.clone() + } +} |
