From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_error_messages/Cargo.toml | 18 + .../locales/en-US/borrowck.ftl | 18 + .../locales/en-US/builtin_macros.ftl | 5 + .../locales/en-US/const_eval.ftl | 31 ++ .../rustc_error_messages/locales/en-US/expand.ftl | 5 + .../rustc_error_messages/locales/en-US/lint.ftl | 395 +++++++++++++++++ .../rustc_error_messages/locales/en-US/parser.ftl | 34 ++ .../rustc_error_messages/locales/en-US/passes.ftl | 264 +++++++++++ .../rustc_error_messages/locales/en-US/privacy.ftl | 21 + .../rustc_error_messages/locales/en-US/typeck.ftl | 125 ++++++ compiler/rustc_error_messages/src/lib.rs | 489 +++++++++++++++++++++ 11 files changed, 1405 insertions(+) create mode 100644 compiler/rustc_error_messages/Cargo.toml create mode 100644 compiler/rustc_error_messages/locales/en-US/borrowck.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/const_eval.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/expand.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/lint.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/parser.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/passes.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/privacy.ftl create mode 100644 compiler/rustc_error_messages/locales/en-US/typeck.ftl create mode 100644 compiler/rustc_error_messages/src/lib.rs (limited to 'compiler/rustc_error_messages') diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml new file mode 100644 index 000000000..fc84c7c86 --- /dev/null +++ b/compiler/rustc_error_messages/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "rustc_error_messages" +version = "0.0.0" +edition = "2021" + +[lib] +doctest = false + +[dependencies] +fluent-bundle = "0.15.2" +fluent-syntax = "0.11" +intl-memoizer = "0.5.1" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_macros = { path = "../rustc_macros" } +tracing = "0.1" +unic-langid = { version = "0.9.0", features = ["macros"] } diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl new file mode 100644 index 000000000..645673ef4 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl @@ -0,0 +1,18 @@ +borrowck-move-unsized = + cannot move a value of type `{$ty}` + .label = the size of `{$ty}` cannot be statically determined + +borrowck-higher-ranked-lifetime-error = + higher-ranked lifetime error + +borrowck-could-not-prove = + could not prove `{$predicate}` + +borrowck-could-not-normalize = + could not normalize `{$value}` + +borrowck-higher-ranked-subtype-error = + higher-ranked subtype error + +generic-does-not-live-long-enough = + `{$kind}` does not live long enough \ No newline at end of file diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl new file mode 100644 index 000000000..1d3e33c81 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl @@ -0,0 +1,5 @@ +builtin-macros-requires-cfg-pattern = + macro requires a cfg-pattern as an argument + .label = cfg-pattern required + +builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl new file mode 100644 index 000000000..3f2ff8610 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl @@ -0,0 +1,31 @@ +const-eval-unstable-in-stable = + const-stable function cannot use `#[feature({$gate})]` + .unstable-sugg = if it is not part of the public API, make this function unstably const + .bypass-sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks + +const-eval-thread-local-access = + thread-local statics cannot be accessed at compile-time + +const-eval-static-access = + {$kind}s cannot refer to statics + .help = consider extracting the value of the `static` to a `const`, and referring to that + .teach-note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. + .teach-help = To fix this, the value can be extracted to a `const` and then used. + +const-eval-raw-ptr-to-int = + pointers cannot be cast to integers during const eval + .note = at compile-time, pointers do not have an integer value + .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior + +const-eval-raw-ptr-comparison = + pointers cannot be reliably compared during const eval + .note = see issue #53020 for more information + +const-eval-panic-non-str = argument to `panic!()` in a const context must have type `&str` + +const-eval-mut-deref = + mutation through a reference is not allowed in {$kind}s + +const-eval-transient-mut-borrow = mutable references are not allowed in {$kind}s + +const-eval-transient-mut-borrow-raw = raw mutable references are not allowed in {$kind}s diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl new file mode 100644 index 000000000..8d506a3ea --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl @@ -0,0 +1,5 @@ +expand-explain-doc-comment-outer = + outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match + +expand-explain-doc-comment-inner = + inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl new file mode 100644 index 000000000..55e96e58e --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -0,0 +1,395 @@ +lint-array-into-iter = + this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021 + .use-iter-suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity + .remove-into-iter-suggestion = or remove `.into_iter()` to iterate by value + .use-explicit-into-iter-suggestion = + or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value + +lint-enum-intrinsics-mem-discriminant = + the return value of `mem::discriminant` is unspecified when called with a non-enum type + .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum. + +lint-enum-intrinsics-mem-variant = + the return value of `mem::variant_count` is unspecified when called with a non-enum type + .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum. + +lint-expectation = this lint expectation is unfulfilled + .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message + +lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of text present in {$label} + .label = this {$label} contains {$count -> + [one] an invisible + *[other] invisible + } unicode text flow control {$count -> + [one] codepoint + *[other] codepoints + } + .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + .suggestion-remove = if their presence wasn't intentional, you can remove them + .suggestion-escape = if you want to keep them but make them visible in your source code, you can escape them + .no-suggestion-note-escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} + +lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better performance + .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary + +lint-query-instability = using `{$query}` can result in unstable query results + .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale + +lint-tykind-kind = usage of `ty::TyKind::` + .suggestion = try using `ty::` directly + +lint-tykind = usage of `ty::TyKind` + .help = try using `Ty` instead + +lint-ty-qualified = usage of qualified `ty::{$ty}` + .suggestion = try importing it and using it unqualified + +lint-lintpass-by-hand = implementing `LintPass` by hand + .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead + +lint-non-existant-doc-keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]` + .help = only existing keywords are allowed in core/std + +lint-diag-out-of-impl = + diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls + +lint-untranslatable-diag = diagnostics should be created using translatable messages + +lint-cstring-ptr = getting the inner pointer of a temporary `CString` + .as-ptr-label = this pointer will be invalid + .unwrap-label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + .help = for more information, see https://doc.rust-lang.org/reference/destructors.html + +lint-identifier-non-ascii-char = identifier contains non-ASCII characters + +lint-identifier-uncommon-codepoints = identifier contains uncommon Unicode codepoints + +lint-confusable-identifier-pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}` + .label = this is where the previous identifier occurred + +lint-mixed-script-confusables = + the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables + .includes-note = the usage includes {$includes} + .note = please recheck to make sure their usages are indeed what you want + +lint-non-fmt-panic = panic message is not a string literal + .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021 + .more-info-note = for more information, see + .supports-fmt-note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here + .supports-fmt-suggestion = remove the `format!(..)` macro call + .display-suggestion = add a "{"{"}{"}"}" format string to `Display` the message + .debug-suggestion = + add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}` + .panic-suggestion = {$already_suggested -> + [true] or use + *[false] use + } std::panic::panic_any instead + +lint-non-fmt-panic-unused = + panic message contains {$count -> + [one] an unused + *[other] unused + } formatting {$count -> + [one] placeholder + *[other] placeholders + } + .note = this message is not used as a format string when given without arguments, but will be in Rust 2021 + .add-args-suggestion = add the missing {$count -> + [one] argument + *[other] arguments + } + .add-fmt-suggestion = or add a "{"{"}{"}"}" format string to use the message literally + +lint-non-fmt-panic-braces = + panic message contains {$count -> + [one] a brace + *[other] braces + } + .note = this message is not used as a format string, but will be in Rust 2021 + .suggestion = add a "{"{"}{"}"}" format string to use the message literally + +lint-non-camel-case-type = {$sort} `{$name}` should have an upper camel case name + .suggestion = convert the identifier to upper camel case + .label = should have an UpperCamelCase name + +lint-non-snake-case = {$sort} `{$name}` should have a snake case name + .rename-or-convert-suggestion = rename the identifier or convert it to a snake case raw identifier + .cannot-convert-note = `{$sc}` cannot be used as a raw identifier + .rename-suggestion = rename the identifier + .convert-suggestion = convert the identifier to snake case + .help = convert the identifier to snake case: `{$sc}` + .label = should have a snake_case name + +lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name + .suggestion = convert the identifier to upper case + .label = should have an UPPER_CASE name + +lint-noop-method-call = call to `.{$method}()` on a reference in this situation does nothing + .label = unnecessary method call + .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed + +lint-pass-by-value = passing `{$ty}` by reference + .suggestion = try passing by value + +lint-redundant-semicolons = + unnecessary trailing {$multiple -> + [true] semicolons + *[false] semicolon + } + .suggestion = remove {$multiple -> + [true] these semicolons + *[false] this semicolon + } + +lint-drop-trait-constraints = + bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped + +lint-drop-glue = + types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped + +lint-range-endpoint-out-of-range = range endpoint is out of range for `{$ty}` + .suggestion = use an inclusive range instead + +lint-overflowing-bin-hex = literal out of range for `{$ty}` + .negative-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` + .negative-becomes-note = and the value `-{$lit}` will become `{$actually}{$ty}` + .positive-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}` + .suggestion = consider using the type `{$suggestion_ty}` instead + .help = consider using the type `{$suggestion_ty}` instead + +lint-overflowing-int = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + .help = consider using the type `{$suggestion_ty}` instead + +lint-only-cast-u8-to-char = only `u8` can be cast into `char` + .suggestion = use a `char` literal instead + +lint-overflowing-uint = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}` + +lint-overflowing-literal = literal out of range for `{$ty}` + .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY` + +lint-unused-comparisons = comparison is useless due to type limits + +lint-improper-ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe + .label = not FFI-safe + .note = the type is defined here + +lint-improper-ctypes-opaque = opaque types have no C equivalent + +lint-improper-ctypes-fnptr-reason = this function pointer has Rust-specific calling convention +lint-improper-ctypes-fnptr-help = consider using an `extern fn(...) -> ...` function pointer instead + +lint-improper-ctypes-tuple-reason = tuples have unspecified layout +lint-improper-ctypes-tuple-help = consider using a struct instead + +lint-improper-ctypes-str-reason = string slices have no C equivalent +lint-improper-ctypes-str-help = consider using `*const u8` and a length instead + +lint-improper-ctypes-dyn = trait objects have no C equivalent + +lint-improper-ctypes-slice-reason = slices have no C equivalent +lint-improper-ctypes-slice-help = consider using a raw pointer instead + +lint-improper-ctypes-128bit = 128-bit integers don't currently have a known stable ABI + +lint-improper-ctypes-char-reason = the `char` type has no C equivalent +lint-improper-ctypes-char-help = consider using `u32` or `libc::wchar_t` instead + +lint-improper-ctypes-non-exhaustive = this enum is non-exhaustive +lint-improper-ctypes-non-exhaustive-variant = this enum has non-exhaustive variants + +lint-improper-ctypes-enum-repr-reason = enum has no representation hint +lint-improper-ctypes-enum-repr-help = + consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + +lint-improper-ctypes-struct-fieldless-reason = this struct has no fields +lint-improper-ctypes-struct-fieldless-help = consider adding a member to this struct + +lint-improper-ctypes-union-fieldless-reason = this union has no fields +lint-improper-ctypes-union-fieldless-help = consider adding a member to this union + +lint-improper-ctypes-struct-non-exhaustive = this struct is non-exhaustive +lint-improper-ctypes-union-non-exhaustive = this union is non-exhaustive + +lint-improper-ctypes-struct-layout-reason = this struct has unspecified layout +lint-improper-ctypes-struct-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + +lint-improper-ctypes-union-layout-reason = this union has unspecified layout +lint-improper-ctypes-union-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union + +lint-improper-ctypes-box = box cannot be represented as a single pointer + +lint-improper-ctypes-enum-phantomdata = this enum contains a PhantomData field + +lint-improper-ctypes-struct-zst = this struct contains only zero-sized fields + +lint-improper-ctypes-array-reason = passing raw arrays by value is not FFI-safe +lint-improper-ctypes-array-help = consider passing a pointer to the array + +lint-improper-ctypes-only-phantomdata = composed only of `PhantomData` + +lint-variant-size-differences = + enum variant is more than three times larger ({$largest} bytes) than the next largest + +lint-atomic-ordering-load = atomic loads cannot have `Release` or `AcqRel` ordering + .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed` + +lint-atomic-ordering-store = atomic stores cannot have `Acquire` or `AcqRel` ordering + .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed` + +lint-atomic-ordering-fence = memory fences cannot have `Relaxed` ordering + .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst` + +lint-atomic-ordering-invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write + .label = invalid failure ordering + .help = consider using `Acquire` or `Relaxed` failure ordering instead + +lint-unused-op = unused {$op} that must be used + .label = the {$op} produces a value + .suggestion = use `let _ = ...` to ignore the resulting value + +lint-unused-result = unused result of type `{$ty}` + +lint-unused-closure = + unused {$pre}{$count -> + [one] closure + *[other] closures + }{$post} that must be used + .note = closures are lazy and do nothing unless called + +lint-unused-generator = + unused {$pre}{$count -> + [one] generator + *[other] generator + }{$post} that must be used + .note = generators are lazy and do nothing unless resumed + +lint-unused-def = unused {$pre}`{$def}`{$post} that must be used + +lint-path-statement-drop = path statement drops value + .suggestion = use `drop` to clarify the intent + +lint-path-statement-no-effect = path statement with no effect + +lint-unused-delim = unnecessary {$delim} around {$item} + .suggestion = remove these {$delim} + +lint-unused-import-braces = braces around {$node} is unnecessary + +lint-unused-allocation = unnecessary allocation, use `&` instead +lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead + +lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}` + .suggestion = use `loop` + +lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty} + +lint-builtin-non-shorthand-field-patterns = the `{$ident}:` in this pattern is redundant + .suggestion = use shorthand field pattern + +lint-builtin-overridden-symbol-name = + the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them + +lint-builtin-overridden-symbol-section = + the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them + +lint-builtin-allow-internal-unsafe = + `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site + +lint-builtin-unsafe-block = usage of an `unsafe` block + +lint-builtin-unsafe-trait = declaration of an `unsafe` trait + +lint-builtin-unsafe-impl = implementation of an `unsafe` trait + +lint-builtin-no-mangle-fn = declaration of a `no_mangle` function +lint-builtin-export-name-fn = declaration of a function with `export_name` +lint-builtin-link-section-fn = declaration of a function with `link_section` + +lint-builtin-no-mangle-static = declaration of a `no_mangle` static +lint-builtin-export-name-static = declaration of a static with `export_name` +lint-builtin-link-section-static = declaration of a static with `link_section` + +lint-builtin-no-mangle-method = declaration of a `no_mangle` method +lint-builtin-export-name-method = declaration of a method with `export_name` + +lint-builtin-decl-unsafe-fn = declaration of an `unsafe` function +lint-builtin-decl-unsafe-method = declaration of an `unsafe` method +lint-builtin-impl-unsafe-method = implementation of an `unsafe` method + +lint-builtin-missing-doc = missing documentation for {$article} {$desc} + +lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `impl Copy` + +lint-builtin-missing-debug-impl = + type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation + +lint-builtin-anonymous-params = anonymous parameters are deprecated and will be removed in the next edition + .suggestion = try naming the parameter or explicitly ignoring it + +lint-builtin-deprecated-attr-link = use of deprecated attribute `{$name}`: {$reason}. See {$link} +lint-builtin-deprecated-attr-used = use of deprecated attribute `{$name}`: no longer used. +lint-builtin-deprecated-attr-default-suggestion = remove this attribute + +lint-builtin-unused-doc-comment = unused doc comment + .label = rustdoc does not generate documentation for {$kind} + .plain-help = use `//` for a plain comment + .block-help = use `/* */` for a plain comment + +lint-builtin-no-mangle-generic = functions generic over types or consts must be mangled + .suggestion = remove this attribute + +lint-builtin-const-no-mangle = const items should never be `#[no_mangle]` + .suggestion = try a static value + +lint-builtin-mutable-transmutes = + transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell + +lint-builtin-unstable-features = unstable feature + +lint-builtin-unreachable-pub = unreachable `pub` {$what} + .suggestion = consider restricting its visibility + .help = or consider exporting it for use by other crates + +lint-builtin-type-alias-bounds-help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases + +lint-builtin-type-alias-where-clause = where clauses are not enforced in type aliases + .suggestion = the clause will not be checked when the type alias is used, and should be removed + +lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not enforced in type aliases + .suggestion = the bound will not be checked when the type alias is used, and should be removed + +lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters + +lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprecated + .suggestion = use `..=` for an inclusive range + +lint-builtin-unnameable-test-items = cannot test inner items + +lint-builtin-keyword-idents = `{$kw}` is a keyword in the {$next} edition + .suggestion = you can use a raw identifier to stay compatible + +lint-builtin-explicit-outlives = outlives requirements can be inferred + .suggestion = remove {$count -> + [one] this bound + *[other] these bounds + } + +lint-builtin-incomplete-features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes + .note = see issue #{$n} for more information + .help = consider using `min_{$name}` instead, which is more stable and complete + +lint-builtin-clashing-extern-same-name = `{$this_fi}` redeclared with a different signature + .previous-decl-label = `{$orig}` previously declared here + .mismatch-label = this signature doesn't match the previous declaration +lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with a different signature + .previous-decl-label = `{$orig}` previously declared here + .mismatch-label = this signature doesn't match the previous declaration + +lint-builtin-deref-nullptr = dereferencing a null pointer + .label = this code causes undefined behavior when executed + +lint-builtin-asm-labels = avoid using named labels in inline assembly diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl new file mode 100644 index 000000000..076b1b1ca --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -0,0 +1,34 @@ +parser-struct-literal-body-without-path = + struct literal body without path + .suggestion = you might have forgotten to add the struct literal inside the block + +parser-maybe-report-ambiguous-plus = + ambiguous `+` in a type + .suggestion = use parentheses to disambiguate + +parser-maybe-recover-from-bad-type-plus = + expected a path on the left-hand side of `+`, not `{$ty}` + +parser-add-paren = try adding parentheses + +parser-forgot-paren = perhaps you forgot parentheses? + +parser-expect-path = expected a path + +parser-maybe-recover-from-bad-qpath-stage-2 = + missing angle brackets in associated item path + .suggestion = try: `{$ty}` + +parser-incorrect-semicolon = + expected item, found `;` + .suggestion = remove this semicolon + .help = {$name} declarations are not followed by a semicolon + +parser-incorrect-use-of-await = + incorrect use of `await` + .parentheses-suggestion = `await` is not a method call, remove the parentheses + .postfix-suggestion = `await` is a postfix operation + +parser-in-in-typo = + expected iterable, found keyword `in` + .suggestion = remove the duplicated `in` diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl new file mode 100644 index 000000000..b17eb9c2d --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -0,0 +1,264 @@ +-passes-previously-accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +-passes-see-issue = + see issue #{$issue} for more information + +passes-outer-crate-level-attr = + crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + +passes-inner-crate-level-attr = + crate-level attribute should be in the root module + +passes-ignored-attr-with-macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "80564")} + +passes-ignored-attr = `#[{$sym}]` is ignored on struct fields and match arms + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "80564")} + +passes-inline-ignored-function-prototype = `#[inline]` is ignored on function prototypes + +passes-inline-ignored-constants = `#[inline]` is ignored on constants + .warn = {-passes-previously-accepted} + .note = {-passes-see-issue(issue: "65833")} + +passes-inline-not-fn-or-closure = attribute should be applied to function or closure + .label = not a function or closure + +passes-no-coverage-ignored-function-prototype = `#[no_coverage]` is ignored on function prototypes + +passes-no-coverage-propagate = + `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly + +passes-no-coverage-fn-defn = `#[no_coverage]` may only be applied to function definitions + +passes-no-coverage-not-coverable = `#[no_coverage]` must be applied to coverable code + .label = not coverable code + +passes-should-be-applied-to-fn = attribute should be applied to a function definition + .label = not a function definition + +passes-naked-tracked-caller = cannot use `#[track_caller]` with `#[naked]` + +passes-should-be-applied-to-struct-enum = attribute should be applied to a struct or enum + .label = not a struct or enum + +passes-should-be-applied-to-trait = attribute should be applied to a trait + .label = not a trait + +passes-target-feature-on-statement = {passes-should-be-applied-to-fn} + .warn = {-passes-previously-accepted} + .label = {passes-should-be-applied-to-fn.label} + +passes-should-be-applied-to-static = attribute should be applied to a static + .label = not a static + +passes-doc-expect-str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] + +passes-doc-alias-empty = {$attr_str} attribute cannot have empty value + +passes-doc-alias-bad-char = {$char_} character isn't allowed in {$attr_str} + +passes-doc-alias-start-end = {$attr_str} cannot start or end with ' ' + +passes-doc-alias-bad-location = {$attr_str} isn't allowed on {$location} + +passes-doc-alias-not-an-alias = {$attr_str} is the same as the item's name + +passes-doc-alias-duplicated = doc alias is duplicated + .label = first defined here + +passes-doc-alias-not-string-literal = `#[doc(alias("a"))]` expects string literals + +passes-doc-alias-malformed = + doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + +passes-doc-keyword-empty-mod = `#[doc(keyword = "...")]` should be used on empty modules + +passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules + +passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier + +passes-doc-fake-variadic-not-valid = + `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity + +passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks + +passes-doc-inline-conflict-first = this attribute... +passes-doc-inline-conflict-second = ...conflicts with this attribute +passes-doc-inline-conflict = conflicting doc inlining attributes + .help = remove one of the conflicting attributes + +passes-doc-inline-only-use = this attribute can only be applied to a `use` item + .label = only applicable on `use` items + .not-a-use-item-label = not a `use` item + .note = read for more information + +passes-doc-attr-not-crate-level = + `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute + +passes-attr-crate-level = this attribute can only be applied at the crate level + .suggestion = to apply to the crate, use an inner attribute + .help = to apply to the crate, use an inner attribute + .note = read for more information + +passes-doc-test-unknown = unknown `doc(test)` attribute `{$path}` + +passes-doc-test-takes-list = `#[doc(test(...)]` takes a list of attributes + +passes-doc-primitive = `doc(primitive)` should never have been stable + +passes-doc-test-unknown-any = unknown `doc` attribute `{$path}` + +passes-doc-test-unknown-spotlight = unknown `doc` attribute `{$path}` + .note = `doc(spotlight)` was renamed to `doc(notable_trait)` + .suggestion = use `notable_trait` instead + .no-op-note = `doc(spotlight)` is now a no-op + +passes-doc-test-unknown-include = unknown `doc` attribute `{$path}` + .suggestion = use `doc = include_str!` instead + +passes-doc-invalid = invalid `doc` attribute + +passes-pass-by-value = `pass_by_value` attribute should be applied to a struct, enum or type alias + .label = is not a struct, enum or type alias + +passes-allow-incoherent-impl = + `rustc_allow_incoherent_impl` attribute should be applied to impl items. + .label = the only currently supported targets are inherent methods + +passes-has-incoherent-inherent-impl = + `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits. + .label = only adts, extern types and traits are supported + +passes-must-use-async = + `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within + .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` + +passes-must-use-no-effect = `#[must_use]` has no effect when applied to {$article} {$target} + +passes-must-not-suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait + .label = is not a struct, enum, or trait + +passes-cold = {passes-should-be-applied-to-fn} + .warn = {-passes-previously-accepted} + .label = {passes-should-be-applied-to-fn.label} + +passes-link = attribute should be applied to an `extern` block with non-Rust ABI + .warn = {-passes-previously-accepted} + .label = not an `extern` block + +passes-link-name = attribute should be applied to a foreign function or static + .warn = {-passes-previously-accepted} + .label = not a foreign function or static + .help = try `#[link(name = "{$value}")]` instead + +passes-no-link = attribute should be applied to an `extern crate` item + .label = not an `extern crate` item + +passes-export-name = attribute should be applied to a free function, impl method or static + .label = not a free function, impl method or static + +passes-rustc-layout-scalar-valid-range-not-struct = attribute should be applied to a struct + .label = not a struct + +passes-rustc-layout-scalar-valid-range-arg = expected exactly one integer literal argument + +passes-rustc-legacy-const-generics-only = #[rustc_legacy_const_generics] functions must only have const generics + .label = non-const generic parameter + +passes-rustc-legacy-const-generics-index = #[rustc_legacy_const_generics] must have one index for each generic parameter + .label = generic parameters + +passes-rustc-legacy-const-generics-index-exceed = index exceeds number of arguments + .label = there {$arg_count -> + [one] is + *[other] are + } only {$arg_count} {$arg_count -> + [one] argument + *[other] arguments + } + +passes-rustc-legacy-const-generics-index-negative = arguments should be non-negative integers + +passes-rustc-dirty-clean = attribute requires -Z query-dep-graph to be enabled + +passes-link-section = attribute should be applied to a function or static + .warn = {-passes-previously-accepted} + .label = not a function or static + +passes-no-mangle-foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} + .warn = {-passes-previously-accepted} + .label = foreign {$foreign_item_kind} + .note = symbol names in extern blocks are not mangled + .suggestion = remove this attribute + +passes-no-mangle = attribute should be applied to a free function, impl method or static + .warn = {-passes-previously-accepted} + .label = not a free function, impl method or static + +passes-repr-ident = meta item in `repr` must be an identifier + +passes-repr-conflicting = conflicting representation hints + +passes-used-static = attribute must be applied to a `static` variable + +passes-used-compiler-linker = `used(compiler)` and `used(linker)` can't be used together + +passes-allow-internal-unstable = attribute should be applied to a macro + .label = not a macro + +passes-debug-visualizer-placement = attribute should be applied to a module + +passes-debug-visualizer-invalid = invalid argument + .note-1 = expected: `natvis_file = "..."` + .note-2 = OR + .note-3 = expected: `gdb_script_file = "..."` + +passes-rustc-allow-const-fn-unstable = attribute should be applied to `const fn` + .label = not a `const fn` + +passes-rustc-std-internal-symbol = attribute should be applied to functions or statics + .label = not a function or static + +passes-const-trait = attribute should be applied to a trait + +passes-stability-promotable = attribute cannot be applied to an expression + +passes-deprecated = attribute is ignored here + +passes-macro-use = `#[{$name}]` only has an effect on `extern crate` and modules + +passes-macro-export = `#[macro_export]` only has an effect on macro definitions + +passes-plugin-registrar = `#[plugin_registrar]` only has an effect on functions + +passes-unused-empty-lints-note = attribute `{$name}` with an empty list has no effect + +passes-unused-no-lints-note = attribute `{$name}` without any lints has no effect + +passes-unused-default-method-body-const-note = + `default_method_body_is_const` has been replaced with `#[const_trait]` on traits + +passes-unused = unused attribute + .suggestion = remove this attribute + +passes-non-exported-macro-invalid-attrs = attribute should be applied to function or closure + .label = not a function or closure + +passes-unused-duplicate = unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-passes-previously-accepted} + +passes-unused-multiple = multiple `{$name}` attributes + .suggestion = remove this attribute + .note = attribute also specified here + +passes-rustc-lint-opt-ty = `#[rustc_lint_opt_ty]` should be applied to a struct + .label = not a struct + +passes-rustc-lint-opt-deny-field-access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field + .label = not a field diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl new file mode 100644 index 000000000..f8a750da9 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl @@ -0,0 +1,21 @@ +privacy-field-is-private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private +privacy-field-is-private-is-update-syntax-label = field `{$field_name}` is private +privacy-field-is-private-label = private field + +privacy-item-is-private = {$kind} `{$descr}` is private + .label = private {$kind} +privacy-unnamed-item-is-private = {$kind} is private + .label = private {$kind} + +privacy-in-public-interface = {$vis_descr} {$kind} `{$descr}` in public interface + .label = can't leak {$vis_descr} {$kind} + .visibility-label = `{$descr}` declared as {$vis_descr} + +privacy-from-private-dep-in-public-interface = + {$kind} `{$descr}` from private dependency '{$krate}' in public interface + +private-in-public-lint = + {$vis_descr} {$kind} `{$descr}` in public interface (error {$kind -> + [trait] E0445 + *[other] E0446 + }) diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl new file mode 100644 index 000000000..c61735a57 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -0,0 +1,125 @@ +typeck-field-multiply-specified-in-initializer = + field `{$ident}` specified more than once + .label = used more than once + .previous-use-label = first use of `{$ident}` + +typeck-unrecognized-atomic-operation = + unrecognized atomic operation function: `{$op}` + .label = unrecognized atomic operation + +typeck-wrong-number-of-generic-arguments-to-intrinsic = + intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} + .label = expected {$expected} {$descr} {$expected -> + [one] parameter + *[other] parameters + } + +typeck-unrecognized-intrinsic-function = + unrecognized intrinsic function: `{$name}` + .label = unrecognized intrinsic + +typeck-lifetimes-or-bounds-mismatch-on-trait = + lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration + .label = lifetimes do not match {$item_kind} in trait + .generics-label = lifetimes in impl do not match this {$item_kind} in trait + +typeck-drop-impl-on-wrong-item = + the `Drop` trait may only be implemented for structs, enums, and unions + .label = must be a struct, enum, or union + +typeck-field-already-declared = + field `{$field_name}` is already declared + .label = field already declared + .previous-decl-label = `{$field_name}` first declared here + +typeck-copy-impl-on-type-with-dtor = + the trait `Copy` may not be implemented for this type; the type has a destructor + .label = `Copy` not allowed on types with destructors + +typeck-multiple-relaxed-default-bounds = + type parameter has more than one relaxed default bound, only one is supported + +typeck-copy-impl-on-non-adt = + the trait `Copy` may not be implemented for this type + .label = type is not a structure or enumeration + +typeck-trait-object-declared-with-no-traits = + at least one trait is required for an object type + .alias-span = this alias does not contain a trait + +typeck-ambiguous-lifetime-bound = + ambiguous lifetime bound, explicit lifetime bound required + +typeck-assoc-type-binding-not-allowed = + associated type bindings are not allowed here + .label = associated type not allowed here + +typeck-functional-record-update-on-non-struct = + functional record update syntax requires a struct + +typeck-typeof-reserved-keyword-used = + `typeof` is a reserved keyword but unimplemented + .suggestion = consider replacing `typeof(...)` with an actual type + .label = reserved keyword + +typeck-return-stmt-outside-of-fn-body = + return statement outside of function body + .encl-body-label = the return is part of this body... + .encl-fn-label = ...not the enclosing function body + +typeck-yield-expr-outside-of-generator = + yield expression outside of generator literal + +typeck-struct-expr-non-exhaustive = + cannot create non-exhaustive {$what} using struct expression + +typeck-method-call-on-unknown-type = + the type of this value must be known to call a method on a raw pointer on it + +typeck-value-of-associated-struct-already-specified = + the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified + .label = re-bound here + .previous-bound-label = `{$item_name}` bound here first + +typeck-address-of-temporary-taken = cannot take address of a temporary + .label = temporary value + +typeck-add-return-type-add = try adding a return type + +typeck-add-return-type-missing-here = a return type might be missing here + +typeck-expected-default-return-type = expected `()` because of default return type + +typeck-expected-return-type = expected `{$expected}` because of return type + +typeck-unconstrained-opaque-type = unconstrained opaque type + .note = `{$name}` must be used in combination with a concrete type within the same module + +typeck-missing-type-params = + the type {$parameterCount -> + [one] parameter + *[other] parameters + } {$parameters} must be explicitly specified + .label = type {$parameterCount -> + [one] parameter + *[other] parameters + } {$parameters} must be specified for this + .suggestion = set the type {$parameterCount -> + [one] parameter + *[other] parameters + } to the desired {$parameterCount -> + [one] type + *[other] types + } + .no-suggestion-label = missing {$parameterCount -> + [one] reference + *[other] references + } to {$parameters} + .note = because of the default `Self` reference, type parameters must be specified on object types + +typeck-manual-implementation = + manual implementations of `{$trait_name}` are experimental + .label = manual implementations of `{$trait_name}` are experimental + .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable + +typeck-substs-on-overridden-impl = could not resolve substs on overridden impl diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs new file mode 100644 index 000000000..02bb04d98 --- /dev/null +++ b/compiler/rustc_error_messages/src/lib.rs @@ -0,0 +1,489 @@ +#![feature(let_chains)] +#![feature(once_cell)] +#![feature(rustc_attrs)] +#![feature(type_alias_impl_trait)] + +use fluent_bundle::FluentResource; +use fluent_syntax::parser::ParserError; +use rustc_data_structures::sync::Lrc; +use rustc_macros::{fluent_messages, Decodable, Encodable}; +use rustc_span::Span; +use std::borrow::Cow; +use std::error::Error; +use std::fmt; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; +use tracing::{instrument, trace}; + +#[cfg(not(parallel_compiler))] +use std::cell::LazyCell as Lazy; +#[cfg(parallel_compiler)] +use std::sync::LazyLock as Lazy; + +#[cfg(parallel_compiler)] +use intl_memoizer::concurrent::IntlLangMemoizer; +#[cfg(not(parallel_compiler))] +use intl_memoizer::IntlLangMemoizer; + +pub use fluent_bundle::{FluentArgs, FluentError, FluentValue}; +pub use unic_langid::{langid, LanguageIdentifier}; + +// Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module. +fluent_messages! { + borrowck => "../locales/en-US/borrowck.ftl", + builtin_macros => "../locales/en-US/builtin_macros.ftl", + const_eval => "../locales/en-US/const_eval.ftl", + expand => "../locales/en-US/expand.ftl", + lint => "../locales/en-US/lint.ftl", + parser => "../locales/en-US/parser.ftl", + passes => "../locales/en-US/passes.ftl", + privacy => "../locales/en-US/privacy.ftl", + typeck => "../locales/en-US/typeck.ftl", +} + +pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; + +pub type FluentBundle = fluent_bundle::bundle::FluentBundle; + +#[cfg(parallel_compiler)] +fn new_bundle(locales: Vec) -> FluentBundle { + FluentBundle::new_concurrent(locales) +} + +#[cfg(not(parallel_compiler))] +fn new_bundle(locales: Vec) -> FluentBundle { + FluentBundle::new(locales) +} + +#[derive(Debug)] +pub enum TranslationBundleError { + /// Failed to read from `.ftl` file. + ReadFtl(io::Error), + /// Failed to parse contents of `.ftl` file. + ParseFtl(ParserError), + /// Failed to add `FluentResource` to `FluentBundle`. + AddResource(FluentError), + /// `$sysroot/share/locale/$locale` does not exist. + MissingLocale, + /// Cannot read directory entries of `$sysroot/share/locale/$locale`. + ReadLocalesDir(io::Error), + /// Cannot read directory entry of `$sysroot/share/locale/$locale`. + ReadLocalesDirEntry(io::Error), + /// `$sysroot/share/locale/$locale` is not a directory. + LocaleIsNotDir, +} + +impl fmt::Display for TranslationBundleError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TranslationBundleError::ReadFtl(e) => write!(f, "could not read ftl file: {}", e), + TranslationBundleError::ParseFtl(e) => { + write!(f, "could not parse ftl file: {}", e) + } + TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e), + TranslationBundleError::MissingLocale => write!(f, "missing locale directory"), + TranslationBundleError::ReadLocalesDir(e) => { + write!(f, "could not read locales dir: {}", e) + } + TranslationBundleError::ReadLocalesDirEntry(e) => { + write!(f, "could not read locales dir entry: {}", e) + } + TranslationBundleError::LocaleIsNotDir => { + write!(f, "`$sysroot/share/locales/$locale` is not a directory") + } + } + } +} + +impl Error for TranslationBundleError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + TranslationBundleError::ReadFtl(e) => Some(e), + TranslationBundleError::ParseFtl(e) => Some(e), + TranslationBundleError::AddResource(e) => Some(e), + TranslationBundleError::MissingLocale => None, + TranslationBundleError::ReadLocalesDir(e) => Some(e), + TranslationBundleError::ReadLocalesDirEntry(e) => Some(e), + TranslationBundleError::LocaleIsNotDir => None, + } + } +} + +impl From<(FluentResource, Vec)> for TranslationBundleError { + fn from((_, mut errs): (FluentResource, Vec)) -> Self { + TranslationBundleError::ParseFtl(errs.pop().expect("failed ftl parse with no errors")) + } +} + +impl From> for TranslationBundleError { + fn from(mut errs: Vec) -> Self { + TranslationBundleError::AddResource( + errs.pop().expect("failed adding resource to bundle with no errors"), + ) + } +} + +/// Returns Fluent bundle with the user's locale resources from +/// `$sysroot/share/locale/$requested_locale/*.ftl`. +/// +/// If `-Z additional-ftl-path` was provided, load that resource and add it to the bundle +/// (overriding any conflicting messages). +#[instrument(level = "trace")] +pub fn fluent_bundle( + mut user_provided_sysroot: Option, + mut sysroot_candidates: Vec, + requested_locale: Option, + additional_ftl_path: Option<&Path>, + with_directionality_markers: bool, +) -> Result>, TranslationBundleError> { + if requested_locale.is_none() && additional_ftl_path.is_none() { + return Ok(None); + } + + let fallback_locale = langid!("en-US"); + let requested_fallback_locale = requested_locale.as_ref() == Some(&fallback_locale); + + // If there is only `-Z additional-ftl-path`, assume locale is "en-US", otherwise use user + // provided locale. + let locale = requested_locale.clone().unwrap_or(fallback_locale); + trace!(?locale); + let mut bundle = new_bundle(vec![locale]); + + // Fluent diagnostics can insert directionality isolation markers around interpolated variables + // indicating that there may be a shift from right-to-left to left-to-right text (or + // vice-versa). These are disabled because they are sometimes visible in the error output, but + // may be worth investigating in future (for example: if type names are left-to-right and the + // surrounding diagnostic messages are right-to-left, then these might be helpful). + bundle.set_use_isolating(with_directionality_markers); + + // If the user requests the default locale then don't try to load anything. + if !requested_fallback_locale && let Some(requested_locale) = requested_locale { + let mut found_resources = false; + for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) { + sysroot.push("share"); + sysroot.push("locale"); + sysroot.push(requested_locale.to_string()); + trace!(?sysroot); + + if !sysroot.exists() { + trace!("skipping"); + continue; + } + + if !sysroot.is_dir() { + return Err(TranslationBundleError::LocaleIsNotDir); + } + + for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? { + let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?; + let path = entry.path(); + trace!(?path); + if path.extension().and_then(|s| s.to_str()) != Some("ftl") { + trace!("skipping"); + continue; + } + + let resource_str = + fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?; + let resource = + FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; + trace!(?resource); + bundle.add_resource(resource).map_err(TranslationBundleError::from)?; + found_resources = true; + } + } + + if !found_resources { + return Err(TranslationBundleError::MissingLocale); + } + } + + if let Some(additional_ftl_path) = additional_ftl_path { + let resource_str = + fs::read_to_string(additional_ftl_path).map_err(TranslationBundleError::ReadFtl)?; + let resource = + FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; + trace!(?resource); + bundle.add_resource_overriding(resource); + } + + let bundle = Lrc::new(bundle); + Ok(Some(bundle)) +} + +/// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily +/// evaluated fluent bundle. +pub type LazyFallbackBundle = Lrc FluentBundle>>; + +/// Return the default `FluentBundle` with standard "en-US" diagnostic messages. +#[instrument(level = "trace")] +pub fn fallback_fluent_bundle( + resources: &'static [&'static str], + with_directionality_markers: bool, +) -> LazyFallbackBundle { + Lrc::new(Lazy::new(move || { + let mut fallback_bundle = new_bundle(vec![langid!("en-US")]); + // See comment in `fluent_bundle`. + fallback_bundle.set_use_isolating(with_directionality_markers); + + for resource in resources { + let resource = FluentResource::try_new(resource.to_string()) + .expect("failed to parse fallback fluent resource"); + trace!(?resource); + fallback_bundle.add_resource_overriding(resource); + } + + fallback_bundle + })) +} + +/// Identifier for the Fluent message/attribute corresponding to a diagnostic message. +type FluentId = Cow<'static, str>; + +/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both +/// translatable and non-translatable diagnostic messages. +/// +/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent +/// message so messages of this type must be combined with a `DiagnosticMessage` (using +/// `DiagnosticMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from +/// the `SessionSubdiagnostic` derive refer to Fluent identifiers directly. +#[rustc_diagnostic_item = "SubdiagnosticMessage"] +pub enum SubdiagnosticMessage { + /// Non-translatable diagnostic message. + // FIXME(davidtwco): can a `Cow<'static, str>` be used here? + Str(String), + /// Identifier of a Fluent message. Instances of this variant are generated by the + /// `SessionSubdiagnostic` derive. + FluentIdentifier(FluentId), + /// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an + /// actual translated message. Instances of this variant are generated by the `fluent_messages` + /// macro. + /// + /// + FluentAttr(FluentId), +} + +/// `From` impl that enables existing diagnostic calls to functions which now take +/// `impl Into` to continue to work as before. +impl> From for SubdiagnosticMessage { + fn from(s: S) -> Self { + SubdiagnosticMessage::Str(s.into()) + } +} + +/// Abstraction over a message in a diagnostic to support both translatable and non-translatable +/// diagnostic messages. +/// +/// Intended to be removed once diagnostics are entirely translatable. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] +#[rustc_diagnostic_item = "DiagnosticMessage"] +pub enum DiagnosticMessage { + /// Non-translatable diagnostic message. + // FIXME(davidtwco): can a `Cow<'static, str>` be used here? + Str(String), + /// Identifier for a Fluent message (with optional attribute) corresponding to the diagnostic + /// message. + /// + /// + /// + FluentIdentifier(FluentId, Option), +} + +impl DiagnosticMessage { + /// Given a `SubdiagnosticMessage` which may contain a Fluent attribute, create a new + /// `DiagnosticMessage` that combines that attribute with the Fluent identifier of `self`. + /// + /// - If the `SubdiagnosticMessage` is non-translatable then return the message as a + /// `DiagnosticMessage`. + /// - If `self` is non-translatable then return `self`'s message. + pub fn with_subdiagnostic_message(&self, sub: SubdiagnosticMessage) -> Self { + let attr = match sub { + SubdiagnosticMessage::Str(s) => return DiagnosticMessage::Str(s), + SubdiagnosticMessage::FluentIdentifier(id) => { + return DiagnosticMessage::FluentIdentifier(id, None); + } + SubdiagnosticMessage::FluentAttr(attr) => attr, + }; + + match self { + DiagnosticMessage::Str(s) => DiagnosticMessage::Str(s.clone()), + DiagnosticMessage::FluentIdentifier(id, _) => { + DiagnosticMessage::FluentIdentifier(id.clone(), Some(attr)) + } + } + } + + /// Returns the `String` contained within the `DiagnosticMessage::Str` variant, assuming that + /// this diagnostic message is of the legacy, non-translatable variety. Panics if this + /// assumption does not hold. + /// + /// Don't use this - it exists to support some places that do comparison with diagnostic + /// strings. + pub fn expect_str(&self) -> &str { + match self { + DiagnosticMessage::Str(s) => s, + _ => panic!("expected non-translatable diagnostic message"), + } + } +} + +/// `From` impl that enables existing diagnostic calls to functions which now take +/// `impl Into` to continue to work as before. +impl> From for DiagnosticMessage { + fn from(s: S) -> Self { + DiagnosticMessage::Str(s.into()) + } +} + +/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but +/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the +/// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be +/// able to convert between these, as much as they'll be converted back into `DiagnosticMessage` +/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive. +impl Into for DiagnosticMessage { + fn into(self) -> SubdiagnosticMessage { + match self { + DiagnosticMessage::Str(s) => SubdiagnosticMessage::Str(s), + DiagnosticMessage::FluentIdentifier(id, None) => { + SubdiagnosticMessage::FluentIdentifier(id) + } + // There isn't really a sensible behaviour for this because it loses information but + // this is the most sensible of the behaviours. + DiagnosticMessage::FluentIdentifier(_, Some(attr)) => { + SubdiagnosticMessage::FluentAttr(attr) + } + } + } +} + +/// A span together with some additional data. +#[derive(Clone, Debug)] +pub struct SpanLabel { + /// The span we are going to include in the final snippet. + pub span: Span, + + /// Is this a primary span? This is the "locus" of the message, + /// and is indicated with a `^^^^` underline, versus `----`. + pub is_primary: bool, + + /// What label should we attach to this span (if any)? + pub label: Option, +} + +/// A collection of `Span`s. +/// +/// Spans have two orthogonal attributes: +/// +/// - They can be *primary spans*. In this case they are the locus of +/// the error, and would be rendered with `^^^`. +/// - They can have a *label*. In this case, the label is written next +/// to the mark in the snippet when we render. +#[derive(Clone, Debug, Hash, PartialEq, Eq, Encodable, Decodable)] +pub struct MultiSpan { + primary_spans: Vec, + span_labels: Vec<(Span, DiagnosticMessage)>, +} + +impl MultiSpan { + #[inline] + pub fn new() -> MultiSpan { + MultiSpan { primary_spans: vec![], span_labels: vec![] } + } + + pub fn from_span(primary_span: Span) -> MultiSpan { + MultiSpan { primary_spans: vec![primary_span], span_labels: vec![] } + } + + pub fn from_spans(mut vec: Vec) -> MultiSpan { + vec.sort(); + MultiSpan { primary_spans: vec, span_labels: vec![] } + } + + pub fn push_span_label(&mut self, span: Span, label: impl Into) { + self.span_labels.push((span, label.into())); + } + + /// Selects the first primary span (if any). + pub fn primary_span(&self) -> Option { + self.primary_spans.first().cloned() + } + + /// Returns all primary spans. + pub fn primary_spans(&self) -> &[Span] { + &self.primary_spans + } + + /// Returns `true` if any of the primary spans are displayable. + pub fn has_primary_spans(&self) -> bool { + !self.is_dummy() + } + + /// Returns `true` if this contains only a dummy primary span with any hygienic context. + pub fn is_dummy(&self) -> bool { + self.primary_spans.iter().all(|sp| sp.is_dummy()) + } + + /// Replaces all occurrences of one Span with another. Used to move `Span`s in areas that don't + /// display well (like std macros). Returns whether replacements occurred. + pub fn replace(&mut self, before: Span, after: Span) -> bool { + let mut replacements_occurred = false; + for primary_span in &mut self.primary_spans { + if *primary_span == before { + *primary_span = after; + replacements_occurred = true; + } + } + for span_label in &mut self.span_labels { + if span_label.0 == before { + span_label.0 = after; + replacements_occurred = true; + } + } + replacements_occurred + } + + /// Returns the strings to highlight. We always ensure that there + /// is an entry for each of the primary spans -- for each primary + /// span `P`, if there is at least one label with span `P`, we return + /// those labels (marked as primary). But otherwise we return + /// `SpanLabel` instances with empty labels. + pub fn span_labels(&self) -> Vec { + let is_primary = |span| self.primary_spans.contains(&span); + + let mut span_labels = self + .span_labels + .iter() + .map(|&(span, ref label)| SpanLabel { + span, + is_primary: is_primary(span), + label: Some(label.clone()), + }) + .collect::>(); + + for &span in &self.primary_spans { + if !span_labels.iter().any(|sl| sl.span == span) { + span_labels.push(SpanLabel { span, is_primary: true, label: None }); + } + } + + span_labels + } + + /// Returns `true` if any of the span labels is displayable. + pub fn has_span_labels(&self) -> bool { + self.span_labels.iter().any(|(sp, _)| !sp.is_dummy()) + } +} + +impl From for MultiSpan { + fn from(span: Span) -> MultiSpan { + MultiSpan::from_span(span) + } +} + +impl From> for MultiSpan { + fn from(spans: Vec) -> MultiSpan { + MultiSpan::from_spans(spans) + } +} -- cgit v1.2.3