profile
viewpoint
Esteban Kuber estebank San Francisco, CA http://esteban.kuber.com.ar/resume/ Off-by-one error fixer/introducer. I 💖@rust-lang⚙️ PST tz

estebank/galvanize 9

Galvanize: Pure Rust CDB reader/writer

commure/hazy 5

OpaqueDebug implementation

estebank/jsmk 4

Javascript Canvas based fighting game engine

estebank/panorama 2

HTML5+JS diff display

estebank/resume 2

My HTML resume. It's self-contained with no external dependencies. Emphasis on readability across User Agents.

estebank/difference.rs 1

Rust text diffing and assertion library

estebank/galvanize_cli 1

CLI Tool to interact with CDBs.

estebank/pysmell 1

PySmell is an attempt to create an IDE completion helper for python.

estebank/atom 0

trying things out

issue commentrust-lang/rust

Surpress, mark, or order superflous trait resolution type errors correctly

Current output:

error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `u8`
 --> src/main.rs:2:38
  |
2 |      let v: Vec<_> = "1, 2, 3".split(b',').collect();
  |                                      ^^^^ expected an `FnMut<(char,)>` closure, found `u8`
  |
  = help: the trait `std::ops::FnMut<(char,)>` is not implemented for `u8`
  = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `u8`

error[E0599]: no method named `collect` found for struct `std::str::Split<'_, u8>` in the current scope
   --> src/main.rs:2:44
    |
2   |      let v: Vec<_> = "1, 2, 3".split(b',').collect();
    |                                            ^^^^^^^ method not found in `std::str::Split<'_, u8>`
    |
    = note: the method `collect` exists but the following trait bounds were not satisfied:
            `u8: std::str::pattern::Pattern<'_>`
            which is required by `std::str::Split<'_, u8>: std::iter::Iterator`
            `std::str::Split<'_, u8>: std::iter::Iterator`
            which is required by `&mut std::str::Split<'_, u8>: std::iter::Iterator`
Kimundi

comment created time in 35 minutes

startednbaksalyar/headcrab

started time in 2 hours

pull request commentrust-lang/rust

Detect tuple struct incorrectly used as struct pat

@bors r=petrochenkov

estebank

comment created time in 5 hours

pull request commentrust-lang/rust

typeck: report placeholder type error w/out span

@bors r+

davidtwco

comment created time in 9 hours

Pull request review commentrust-lang/rust

typeck: report placeholder type error w/out span

 fn test7(x: _) { let _x: usize = x; }  fn test8(_f: fn() -> _) { } //~^ ERROR the type placeholder `_` is not allowed within types on item signatures+//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures

Unfortunate.

davidtwco

comment created time in 9 hours

push eventestebank/rust

Esteban Küber

commit sha 5daedea3dbeb8fb2639d3d142b008135f4fd2b43

Detect tuple struct incorrectly used as struct pat

view details

push time in 9 hours

pull request commentrust-lang/rust

Provide structured suggestion on unsized fields and fn params

@bors r+

estebank

comment created time in 9 hours

Pull request review commentrust-lang/rust

Provide structured suggestion on unsized fields and fn params

 error[E0277]: the size for values of type `T` cannot be known at compilation time-  --> $DIR/union-sized-field.rs:4:5+  --> $DIR/union-sized-field.rs:4:12    | LL | union Foo<T: ?Sized> {    |           - this type parameter needs to be `std::marker::Sized` LL |     value: T,-   |     ^^^^^^^^ doesn't have a size known at compile-time+   |            ^ doesn't have a size known at compile-time    |-   = help: the trait `std::marker::Sized` is not implemented for `T`-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>    = note: no field of a union may have a dynamically sized type+   = help: change the field's type to have a statically known size+help: borrowed types always have a statically known size+   |+LL |     value: &T,+   |            ^+help: boxed trait objects have a statically known size

I wanted to introduce a bit of jargon here, as Box is already mentioned in the code suggestion itself, to tie the concept of "heap allocations" and "Box". That being said I see your point. Lets merge this as is to avoid bitrot (I don't think the wording is outright wrong, just suboptimal), but let's open a follow up PR to improve the wording?

estebank

comment created time in 9 hours

push eventestebank/rust

Esteban Küber

commit sha 58e241bf515f69c2f0212592de5180f2c7482da0

Detect tuple struct incorrectly used as struct pat

view details

push time in 21 hours

push eventestebank/rust

Esteban Küber

commit sha bea3b8855e568debac43f54d5f40e5daa35b851a

tweak logic to suggest more cases

view details

push time in a day

Pull request review commentrust-lang/rust

Structured suggestion when not using struct pattern

 impl<'a> LateResolutionVisitor<'a, '_, '_> {                             ),                         );                     }-                    suggested = true;                 }-                _ => {}-            }-            if !suggested {-                if let Some(span) = self.r.opt_span(def_id) {-                    err.span_label(span, &format!("`{}` defined here", path_str));+                PathSource::TupleStruct(span) => {+                    err.set_span(span);+                    if let Some(span) = self.r.opt_span(def_id) {+                        err.span_label(span, &format!("`{}` defined here", path_str));+                    }+                    let (fields, appl) = match self.r.field_names.get(&def_id) {+                        Some(fields) => (+                            fields+                                .iter()+                                .map(|f| f.node.to_string())+                                .collect::<Vec<String>>()+                                .join(", "),+                            Applicability::MachineApplicable,+                        ),+                        None => ("/* fields */".to_string(), Applicability::HasPlaceholders),+                    };+                    err.span_suggestion(+                        span,+                        "use struct pattern syntax instead",+                        format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad),+                        appl,+                    );+                }+                PathSource::Expr(Some(Expr {+                    span: call_span,+                    kind: ExprKind::Call(expr, _),+                    ..+                })) if expr.span == span => {+                    err.set_span(*call_span);+                    if let Some(span) = self.r.opt_span(def_id) {+                        err.span_label(span, &format!("`{}` defined here", path_str));+                    }+                    let fields = match self.r.field_names.get(&def_id) {+                        Some(fields) => fields+                            .iter()+                            .map(|f| format!("{}: val", f.node))+                            .collect::<Vec<String>>()+                            .join(", "),+                        None => "/* fields */".to_string(),+                    };+                    err.span_suggestion(+                        *call_span,+                        "use struct literal syntax instead",+                        format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad),+                        Applicability::HasPlaceholders,+                    );+                }+                PathSource::Pat if matches!(self.diagnostic_metadata.current_expr, Some(_)) => {

Changed for this PR, I'll look at the other one in a bit.

estebank

comment created time in a day

push eventestebank/rust

Yoshua Wuyts

commit sha a31f103fd27bde3f83b9dd54af8e41d64e5001f4

Add core::future::{poll_fn, PollFn}

view details

Chris Denton

commit sha 912963bd0856239828253af8d04e4f62e75cafd7

Remove legacy InnoSetup GUI installer On Windows the InnoSetup installer was superseded by the MSI installer. It's no longer needed.

view details

djugei

commit sha b4337ab8c387658b7012fa242e429f46c5f31141

added .collect() into String from Box<str> with fake feature/stability annotation

view details

Yoshua Wuyts

commit sha 8bc6b5b45c9f9710852e2b9c57eb3d44d08ad245

stabilize leading_trailing_ones

view details

Tomasz Miąsko

commit sha 291dce91b24d70382ebf1116fa836fd91960de84

Fallback to xml.etree.ElementTree The xml.etree.cElementTree has been deprecated since Python 3.3 and removed in Python 3.9 https://bugs.python.org/issue36543.

view details

Alexis Bourget

commit sha 049f6eaa792fbbf2b727fc278ddd23d1e11d57bd

Fixing broken link for the Eq trait

view details

Caleb Zulawski

commit sha 144206e6d8c1ab4ffdbaf6d7b0f5a4201c0f2da4

Don't implement Fn* traits for #[target_feature] functions

view details

Caleb Zulawski

commit sha c98b4c8fdde7812d7af5a060a1e22fd7e3775d3f

Add error note when trying fn as Fn trait

view details

pankajchaudhary5

commit sha 46bfc48272ba5312c439557e2901e1a4778e9487

Added proper explanation of ErrorCode-E0687

view details

mark

commit sha 3f6928f1f6eff367e6ddbfb63ebc5e568ffe0eb1

move contributing.md to rustc-dev-guide and point at getting started

view details

Matthias Krüger

commit sha 1d0378c454de72ddcfc08bcc105744923ef2d4d4

impl From<char> for String This allows us to write fn char_to_string() -> String { 'a'.into() } which was not possible before.

view details

Tomasz Miąsko

commit sha 5c20ef433b48fce78c07208710bcc8b53965eeb1

bootstrap: Configurable musl libdir Make it possible to customize the location of musl libdir using musl-libdir in config.toml, e.g., to use lib64 instead of lib.

view details

Matthias Krüger

commit sha 2cde4932c7e8bd6000378af41029299ccf6eea69

add test for char into string

view details

Alexis Bourget

commit sha 6e8251742071d56545b6ce160ed71bb60597ee01

Documenting the separate behaviors of edition 2015 and 2018

view details

Alexis Bourget

commit sha 59701360dc0c76bfa45204d307ac5055f8bff538

Fix some small mistakes

view details

Anirban

commit sha 886f81e1d0883f67fbc81b8ece61b1c33f6923d2

Fix sentence structure Fixed grammar and sentence structure on appropriate instances.

view details

Dylan McKay

commit sha 50f20ec576ae72ceff6bf5a50c940cf574990e56

[AVR] Update the rust-lang/llvm-project submodule to include AVR fixes recently merged This commit updates rustc's LLVM submodule to include new AVR-specific fixes recently merged on the Rust LLVM 'rustc/10.0-2020-05-05' branch. All of these cherry-picked commits exist in upstream LLVM and were cherry-picked into Rust's LLVM fork in commit 6c040dd86ed. |- 6c040dd86ed Merge pull request #66 from dylanmckay/avr-pick-upstream-llvm-fixes |- 12dfdd3aed7 [AVR] Rewrite the function calling convention. |- 118ac53f12b [AVR] Don't adjust for instruction size |- bc27c282e13 [AVR] Fix miscompilation of zext + add |- cfbe205a7e8 [AVR] Remove faulty stack pushing behavior |- 143e1469e96 [AVR] Fix stack size in functions with a frame pointer |- 6b2445d841e [LLVM][AVR] Support for R_AVR_6 fixup |- 93ee4da19cf [AVR] Fix I/O instructions on XMEGA |- 962c2415ffb [AVR] Do not place functions in .progmem.data |- 65b8b170aef [AVR] Do not use divmod calls for bigger integers |- 93a3b595d1c [AVR] Generalize the previous interrupt bugfix to signal |- handlers too |- cc4286349b4 [AVR] Respect the 'interrupt' function attribute |- 954d0a92205 [AVR] Fix reads of uninitialized variables from constructor of AVRSubtarget |- 1c0ddae73c9 [AVR] Fix read of uninitialized variable AVRSubtarget:::ELFArch |- 0ed0823fe60 [AVR] Fix incorrect register state for LDRdPtr |- 96075fc433d [AVR] Don't adjust addresses by 2 for absolute values |- 6dfc55ba53b [AVR] Use correct register class for mul instructions These changes include both correctness fixes and LLVM assertion error fixes. Once all of these commits have been cherry-picked, all of the LLVM plumbing for rust-lang/master to compile the AVR blink program will be in place. Once this commit is merged, only PR rust-lang/rust#73270 will be blocking successful compilation and emission of the AVR LED blink program.

view details

Keno Fischer

commit sha 0c88dd663a7095ccc405a2036047a90981137a51

Update Box::from_raw example to generalize better I know very little about rust, so I saw this example and tried to generalize it by writing, ``` let layout = Layout::new::<T>(); let new_obj = unsafe { let ptr = alloc(layout) as *mut T; *ptr = obj; Box::from_raw(ptr) }; ``` for some more complicated `T`, which ended up crashing with SIGSEGV, because it tried to `drop_in_place` the previous object in `ptr` which is of course garbage. I also added a comment that explains why `.write` is used, but I think adding that comment is optional and may be too verbose here. I do however think that changing this example is a good idea to suggest the correct generalization. `.write` is also used in most of the rest of the documentation here, even if the example is `i32`, so it would additionally be more consistent.

view details

Anirban

commit sha 3b5d7f8cf66c6704d36b021f7173241d6351ad32

Minor correction to sentence structure

view details

David Hewitt

commit sha 6b95f3102d657a5cd0549213a073b28c7e0fe609

Add `format_args_capture` feature

view details

push time in a day

pull request commentrust-lang/rust

Remove an unwrap in layout computation

@bors r+

erikdesjardins

comment created time in a day

push eventestebank/rust

Esteban Küber

commit sha 13800269d788b5fc2a3fa2f9d586c05572f6f4e4

Suggest boxing or borrowing unsized fields

view details

Esteban Küber

commit sha 675507613237f18aa54cb1a4a2343e0a47628065

Remove `Sized` `on_unimplemented` note

view details

Esteban Küber

commit sha 424902abb4ce17ca876e0c35bd9d9b3b48330f4a

Suggest borrowing in more unsized fn param cases

view details

Esteban Küber

commit sha 2d0f3ebcd06f259562b36fd39e42dd89f3ac883c

Remove redundant explanatory `note` for type parameters

view details

push time in a day

push eventestebank/rust

Esteban Küber

commit sha 77773aee09154fed221b12098bb9398b03d627ce

Detect tuple struct incorrectly used as struct pat

view details

push time in a day

pull request commentrust-lang/rust

typeck: check for infer before type impls trait

@bors r+

davidtwco

comment created time in a day

push eventestebank/rust

Yoshua Wuyts

commit sha a31f103fd27bde3f83b9dd54af8e41d64e5001f4

Add core::future::{poll_fn, PollFn}

view details

Oliver Scherer

commit sha 7e682d3f6f5761471e05fefc21e5de6ce4a52444

Stabilize casts and coercions to `&[T]` in const fn

view details

Dodo

commit sha a065096ff40f7910fd58aa36a76be6cb1c5f1d4d

stabilize const mem::forget

view details

Vadim Petrochenkov

commit sha 8e256b19d529ebf9021030e17791e23a1212ff1e

parser: Break float tokens into parts in tuple field positions

view details

David Tolnay

commit sha 40a21707b4c0e7e5a8cb5a03ddebecdd59ab705c

Add test of tuple nested indexing

view details

David Tolnay

commit sha 0432f63acf5b08c23ad206a87e3ad4a2a171cf7f

Test even deeper nested indexing

view details

David Tolnay

commit sha 776deb6b9f326f5ba5984e4d55cb5010a17ce559

Test a range, which is not nested indexing

view details

David Tolnay

commit sha 6dfa549fb5719034b829955384e1e198f4d66c04

Add tests in which the token really is a float

view details

David Tolnay

commit sha 3814eec087c6e5695c92956b7a738f4c2ffd7649

Add test for tuple indexed with float in macro input

view details

David Tolnay

commit sha 63f95a4858bbe8cef9a6e1b0e7e5273255d60926

Add test for errors triggered on parts of decomposed index

view details

Vadim Petrochenkov

commit sha 64a88db762bc13b37508d44e09731a3b8349110a

Update dtolnay's tests that now work

view details

Vadim Petrochenkov

commit sha 52bdaaa0edb2824af1610b67664f06580335fd78

Add some requested tests

view details

Ralf Jung

commit sha fb9fa5ba3ee08171e7d2ff35d28ec0dd93b0287b

adjust ub-enum test to be endianess-independent

view details

Tomasz Miąsko

commit sha bcef848a6971217d4b8df50c17e047174018d316

Explain effects of debugging options from config.toml Co-authored-by: Teymour Aldridge <42674621+teymour-aldridge@users.noreply.github.com>

view details

Jon Gjengset

commit sha 7fb26938b1b88d9f3c0d3046712375e48aeb91ae

Add VecDeque::range* methods This patch adds `VecDeque::range` and `VecDeque::range_mut` to provide iterators over a sub-range of a `VecDeque`. This behavior can be emulated with `skip` and `take`, but directly providing a `Range` is more ergonomic. This also partially makes up for `VecDeque`'s lack of `SliceIndex` support.

view details

Jon Gjengset

commit sha 8872ec37600114e3e1a07c18443a119788bbb052

fixups

view details

Gary Guo

commit sha 5702e0289f7d19f0ea133d43da7dcd7cbfc5b557

Only allow `repr(i128/u128)` on enum

view details

Gary Guo

commit sha 97867bbe5cd09df7754864c826f58d3029f4422e

Add UI test for issue 74082

view details

Aleksey Kladov

commit sha b82df31bf30e43402619d42acba78245acca22ee

:arrow_up: rust-analyzer

view details

Eric Huss

commit sha b50c13cc28b3c6c5968ec3f8cf0c1aa11e463d9f

Update books

view details

push time in a day

pull request commentrust-lang/rust

Provide structured suggestion on unsized fields and fn params

after squashing a little

Should I squash all into one commit or just squash the fixup commits where they belong?

estebank

comment created time in a day

Pull request review commentrust-lang/rust

Provide structured suggestion on unsized fields and fn params

 error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied-  --> $DIR/wf-in-fn-type-arg.rs:9:5+  --> $DIR/wf-in-fn-type-arg.rs:9:8    | LL | struct MustBeCopy<T:Copy> {    |                     ---- required by this bound in `MustBeCopy` ... LL |     x: fn(MustBeCopy<T>)-   |     ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`+   |        ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`

I'm continue in my war path to make the underlines as short as possible :)

estebank

comment created time in a day

push eventestebank/rust

Esteban Küber

commit sha fea83d27055abe99b3a0ed2750c1854b97fc78d0

Reword suggestion to account for `?Sized` type params

view details

push time in a day

Pull request review commentrust-lang/rust

Provide structured suggestion on unsized fields and fn params

 error[E0277]: the size for values of type `T` cannot be known at compilation time-  --> $DIR/union-sized-field.rs:4:5+  --> $DIR/union-sized-field.rs:4:12    | LL | union Foo<T: ?Sized> {    |           - this type parameter needs to be `std::marker::Sized` LL |     value: T,-   |     ^^^^^^^^ doesn't have a size known at compile-time+   |            ^ doesn't have a size known at compile-time    |-   = help: the trait `std::marker::Sized` is not implemented for `T`-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>    = note: no field of a union may have a dynamically sized type+   = help: change the field's type to have a statically known size+help: borrowed types always have a statically known size+   |+LL |     value: &T,+   |            ^+help: boxed trait objects have a statically known size

What about "heap allocated types always have a statically known size"?

estebank

comment created time in a day

Pull request review commentrust-lang/rust

Provide structured suggestion on unsized fields and fn params

 error[E0277]: the size for values of type `T` cannot be known at compilation time-  --> $DIR/union-sized-field.rs:4:5+  --> $DIR/union-sized-field.rs:4:12    | LL | union Foo<T: ?Sized> {    |           - this type parameter needs to be `std::marker::Sized` LL |     value: T,-   |     ^^^^^^^^ doesn't have a size known at compile-time+   |            ^ doesn't have a size known at compile-time    |-   = help: the trait `std::marker::Sized` is not implemented for `T`-   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>    = note: no field of a union may have a dynamically sized type+   = help: change the field's type to have a statically known size+help: borrowed types always have a statically known size+   |+LL |     value: &T,+   |            ^+help: boxed trait objects have a statically known size

This is a good point. I could say boxed types have... and that would be more accurate always at the cost of not giving people some jargon to google... I'll see if I can make it conditional on the type.

estebank

comment created time in a day

push eventestebank/rust

Esteban Küber

commit sha c3391fc126640ba075aa33996598ee8949af8067

revert spurious stderr change

view details

push time in a day

push eventestebank/rust

Esteban Küber

commit sha 0acd88d8b5dc0a39134bf5942127d10d6e7c3efb

fmt

view details

push time in 2 days

push eventestebank/rust

Esteban Küber

commit sha c7c77683c48430b146a9fcc6c5f213a1de37f656

Remove redundant explanatory `note` for type parameters

view details

push time in 2 days

PR opened rust-lang/rust

Provide structured suggestion on unsized fields and fn params
  • Suggest borrowing or boxing unsized fields
  • Suggest borrowing fn parameters
  • Remove some verbosity of unsized errors
  • Remove on_unimplemented note from trait Sized

Fix #23286, fix #28653.

r? @davidtwco

+547 -349

0 comment

111 changed files

pr created time in 2 days

create barnchestebank/rust

branch : unsized-param

created branch time in 2 days

pull request commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

I would like an answer about my last comment, but I don't think it needs to block the PR to avoid bitrotting.

estebank

comment created time in 2 days

push eventestebank/rust

Chris Denton

commit sha 912963bd0856239828253af8d04e4f62e75cafd7

Remove legacy InnoSetup GUI installer On Windows the InnoSetup installer was superseded by the MSI installer. It's no longer needed.

view details

djugei

commit sha b4337ab8c387658b7012fa242e429f46c5f31141

added .collect() into String from Box<str> with fake feature/stability annotation

view details

Yoshua Wuyts

commit sha 8bc6b5b45c9f9710852e2b9c57eb3d44d08ad245

stabilize leading_trailing_ones

view details

Tomasz Miąsko

commit sha 291dce91b24d70382ebf1116fa836fd91960de84

Fallback to xml.etree.ElementTree The xml.etree.cElementTree has been deprecated since Python 3.3 and removed in Python 3.9 https://bugs.python.org/issue36543.

view details

Alexis Bourget

commit sha 049f6eaa792fbbf2b727fc278ddd23d1e11d57bd

Fixing broken link for the Eq trait

view details

Caleb Zulawski

commit sha 144206e6d8c1ab4ffdbaf6d7b0f5a4201c0f2da4

Don't implement Fn* traits for #[target_feature] functions

view details

Caleb Zulawski

commit sha c98b4c8fdde7812d7af5a060a1e22fd7e3775d3f

Add error note when trying fn as Fn trait

view details

pankajchaudhary5

commit sha 46bfc48272ba5312c439557e2901e1a4778e9487

Added proper explanation of ErrorCode-E0687

view details

mark

commit sha 3f6928f1f6eff367e6ddbfb63ebc5e568ffe0eb1

move contributing.md to rustc-dev-guide and point at getting started

view details

Matthias Krüger

commit sha 1d0378c454de72ddcfc08bcc105744923ef2d4d4

impl From<char> for String This allows us to write fn char_to_string() -> String { 'a'.into() } which was not possible before.

view details

Tomasz Miąsko

commit sha 5c20ef433b48fce78c07208710bcc8b53965eeb1

bootstrap: Configurable musl libdir Make it possible to customize the location of musl libdir using musl-libdir in config.toml, e.g., to use lib64 instead of lib.

view details

Matthias Krüger

commit sha 2cde4932c7e8bd6000378af41029299ccf6eea69

add test for char into string

view details

Alexis Bourget

commit sha 6e8251742071d56545b6ce160ed71bb60597ee01

Documenting the separate behaviors of edition 2015 and 2018

view details

Alexis Bourget

commit sha 59701360dc0c76bfa45204d307ac5055f8bff538

Fix some small mistakes

view details

Anirban

commit sha 886f81e1d0883f67fbc81b8ece61b1c33f6923d2

Fix sentence structure Fixed grammar and sentence structure on appropriate instances.

view details

Dylan McKay

commit sha 50f20ec576ae72ceff6bf5a50c940cf574990e56

[AVR] Update the rust-lang/llvm-project submodule to include AVR fixes recently merged This commit updates rustc's LLVM submodule to include new AVR-specific fixes recently merged on the Rust LLVM 'rustc/10.0-2020-05-05' branch. All of these cherry-picked commits exist in upstream LLVM and were cherry-picked into Rust's LLVM fork in commit 6c040dd86ed. |- 6c040dd86ed Merge pull request #66 from dylanmckay/avr-pick-upstream-llvm-fixes |- 12dfdd3aed7 [AVR] Rewrite the function calling convention. |- 118ac53f12b [AVR] Don't adjust for instruction size |- bc27c282e13 [AVR] Fix miscompilation of zext + add |- cfbe205a7e8 [AVR] Remove faulty stack pushing behavior |- 143e1469e96 [AVR] Fix stack size in functions with a frame pointer |- 6b2445d841e [LLVM][AVR] Support for R_AVR_6 fixup |- 93ee4da19cf [AVR] Fix I/O instructions on XMEGA |- 962c2415ffb [AVR] Do not place functions in .progmem.data |- 65b8b170aef [AVR] Do not use divmod calls for bigger integers |- 93a3b595d1c [AVR] Generalize the previous interrupt bugfix to signal |- handlers too |- cc4286349b4 [AVR] Respect the 'interrupt' function attribute |- 954d0a92205 [AVR] Fix reads of uninitialized variables from constructor of AVRSubtarget |- 1c0ddae73c9 [AVR] Fix read of uninitialized variable AVRSubtarget:::ELFArch |- 0ed0823fe60 [AVR] Fix incorrect register state for LDRdPtr |- 96075fc433d [AVR] Don't adjust addresses by 2 for absolute values |- 6dfc55ba53b [AVR] Use correct register class for mul instructions These changes include both correctness fixes and LLVM assertion error fixes. Once all of these commits have been cherry-picked, all of the LLVM plumbing for rust-lang/master to compile the AVR blink program will be in place. Once this commit is merged, only PR rust-lang/rust#73270 will be blocking successful compilation and emission of the AVR LED blink program.

view details

Keno Fischer

commit sha 0c88dd663a7095ccc405a2036047a90981137a51

Update Box::from_raw example to generalize better I know very little about rust, so I saw this example and tried to generalize it by writing, ``` let layout = Layout::new::<T>(); let new_obj = unsafe { let ptr = alloc(layout) as *mut T; *ptr = obj; Box::from_raw(ptr) }; ``` for some more complicated `T`, which ended up crashing with SIGSEGV, because it tried to `drop_in_place` the previous object in `ptr` which is of course garbage. I also added a comment that explains why `.write` is used, but I think adding that comment is optional and may be too verbose here. I do however think that changing this example is a good idea to suggest the correct generalization. `.write` is also used in most of the rest of the documentation here, even if the example is `i32`, so it would additionally be more consistent.

view details

Anirban

commit sha 3b5d7f8cf66c6704d36b021f7173241d6351ad32

Minor correction to sentence structure

view details

David Hewitt

commit sha 6b95f3102d657a5cd0549213a073b28c7e0fe609

Add `format_args_capture` feature

view details

Anirban

commit sha d6cf8fc63ee24269bd4df20ad9fe19a219b5c9f5

Update README.md

view details

push time in 2 days

pull request commentrust-lang/rust

diagnostics: shorten paths of unique symbols

Also, should we allow users to disable this with a -Z in case issues arise, to ease debugging in nightly?

Yes.

da-x

comment created time in 2 days

push eventestebank/rust

Esteban Küber

commit sha 4afee56b3d15e21b34a2652ae9943e523e44c23b

Detect tuple struct incorrectly used as struct pat

view details

Esteban Küber

commit sha aa019763c2bafd0fa3aa1151ee2d74c7ecfd372b

Avoid building unnecessary error in happy path

view details

push time in 2 days

push eventestebank/rust

Esteban Küber

commit sha e7fe658867162d83fd68e78b5319be4df371d6e5

Avoid building unnecessary error in happy path

view details

push time in 2 days

push eventestebank/rust

Esteban Küber

commit sha 07da615283dd33ed061af522cd65a357d1bb7ac4

review comments: reword message

view details

push time in 2 days

PR opened rust-lang/rust

Structured suggestion when not using struct pattern

r? @petrochenkov

+221 -195

0 comment

23 changed files

pr created time in 3 days

push eventestebank/rust

Esteban Küber

commit sha 683072af7aad031d23b82979b5aab4f881dc0809

Suggest struct pat on incorrect unit or tuple pat

view details

Esteban Küber

commit sha 3763689400e54f468e3c0afcaccc468ad7274bdc

Keep track of fields in variants Use `insert_field_names_local` when evaluating variants and store field names even when the list is empty in order to produce accurate structured suggestions.

view details

Esteban Küber

commit sha 4f061124dda9305879a019d525e50a54c2e1e365

fix rebase

view details

push time in 3 days

PR opened rust-lang/rust

Deduplicate `::` -> `:` typo errors

r? @petrochenkov

+122 -84

0 comment

10 changed files

pr created time in 3 days

push eventestebank/rust

Esteban Küber

commit sha 8a1545b2f12ad2666825d2ea468fd7264d39861c

Remove duplicated `:` -> `::` suggestion from parse error

view details

Esteban Küber

commit sha b36e245cf6f66b2a03b9be19d75c8255337926c1

Tweak wording to be more accurate

view details

Esteban Küber

commit sha af493d29eb12de7c92da8894a49b9bc2f1f9a9cb

Further deduplicate type ascription errors

view details

push time in 3 days

create barnchestebank/rust

branch : struct-pat-as-unit

created branch time in 3 days

push eventestebank/rust

Esteban Küber

commit sha 68a3ac5562f95951561753914d90179c0eeb422a

Tweak wording to be more accurate

view details

push time in 3 days

create barnchestebank/rust

branch : type-ascriptomatic

created branch time in 3 days

pull request commentrust-lang/rust

Don't pollute docs/suggestions with libstd deps

r=me on the diagnostic affecting changes, but feel free to continue the conversation around rustdoc

alexcrichton

comment created time in 3 days

pull request commentrust-lang/rust

diagnostics: shorten paths of unique symbols

@estebank Separating uniqueness for trait symbols and type symbols seems to sort out the overlap between std::fmt::Display and std::path::Display. Also, allowing type aliases to be superseded in uniqueness by the types of the same name will take care of the std::io::Result vs std::result::Result overlap, with std::result::Result winning for Result.

WDYT?

I'm of diverging opinions. I was originally going to dismiss this alternative out of hand as I fear it would be confusing to do this deduplication on a per type basis. But then I thought a bit about it and 1) it makes absolute sense to ignore type aliases (at least for now) because we never refer to them in type errors and 2) we already give a short description of what we are talking about (expected type 'Result', found trait 'Display'), which would make that work out nicely. The only case where I am slightly concerned is when both "expected" and "found" clash: expected type 'Display', found trait 'Display' could be confusing in of itself. Could we have a way to handle that case specifically? I feel that we can do these things as a follow up PR, what do you think?

da-x

comment created time in 3 days

Pull request review commentrust-lang/rust

Reword incorrect `self` token suggestion

 impl<'a> LateResolutionVisitor<'a, '_, '_> {         if ["this", "my"].contains(&&*item_str.as_str())             && self.self_value_is_available(path[0].ident.span, span)         {-            err.span_suggestion(+            err.span_suggestion_short(                 span,-                "did you mean",+                "you might have meant to use `self` here instead",

The conclusion was don't frame things as a question and make the message make sense mostly on its own. For a while now I've been changing "Did you mean" to more explicit messages. There aren't that many left anymore.

estebank

comment created time in 3 days

PR opened rust-lang/rust

Reword incorrect `self` token suggestion
+5 -5

0 comment

2 changed files

pr created time in 3 days

create barnchestebank/rust

branch : self-sugg

created branch time in 3 days

PR opened rust-lang/rust

Tweak `::` -> `:` typo heuristic and reduce verbosity

Do not trigger on correct type ascription expressions with trailing operators and do trigger on likely path typos where a turbofish is used.

On likely path typos, remove note explaining type ascription.

Clean up indentation.

r? @petrochenkov

+57 -61

0 comment

10 changed files

pr created time in 3 days

create barnchestebank/rust

branch : tweak-ascription-typo-heuristic

created branch time in 3 days

PR opened rust-lang/rust

Detect tuple struct incorrectly used as struct pat

Subpart of #74005.

r? @petrochenkov

+114 -63

0 comment

12 changed files

pr created time in 4 days

create barnchestebank/rust

branch : struct-pat-as-enum

created branch time in 4 days

Pull request review commentrust-lang/rust

Permit evaluation of assoc items on `Self` by avoiding cycle error

 impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {         param_ty: Ty<'tcx>,         ast_bounds: &[hir::GenericBound<'_>],         bounds: &mut Bounds<'tcx>,+        skip_self_param_evaluation: bool,     ) {         let mut trait_bounds = Vec::new();         let mut region_bounds = Vec::new(); +        /// Walk each bound to see if they reference an associated type of `Self` without+        /// specifying a trait (using a Resolved path `Self::Foo` instead of fully qualified path+        /// `<Self as Bar>::Foo`) and if so, skip them if `skip_self_param_evaluation` is `true`.+        /// This way, we avoid cycle errors and are able to resolve the associated type+        /// successfully.+        struct SelfFinder(bool);++        impl<'v> Visitor<'v> for SelfFinder {+            type Map = intravisit::ErasedMap<'v>;++            fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {+                intravisit::NestedVisitorMap::None+            }++            fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {+                if let hir::TyKind::Path(hir::QPath::TypeRelative(+                    hir::Ty {+                        kind:+                            hir::TyKind::Path(+                                hir::QPath::Resolved(+                                    None,+                                    hir::Path { res: Res::SelfTy(Some(_), None), .. },+                                ),+                                ..,+                            ),+                        ..+                    },+                    _,+                )) = t.kind+                {+                    self.0 = true;+                }+                intravisit::walk_ty(self, t)+            }+        }+         let constness = self.default_constness_for_trait_bounds();         for ast_bound in ast_bounds {             match *ast_bound {-                hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {-                    trait_bounds.push((b, constness))+                hir::GenericBound::Trait(ref b, modif @ hir::TraitBoundModifier::None) => {+                    let mut visitor = SelfFinder(false);+                    visitor.visit_poly_trait_ref(b, modif);++                    let is_self_param = match param_ty.kind {+                        ty::Param(param) if param.name == kw::SelfUpper => true,+                        _ => false,+                    };+                    if !(visitor.0 && skip_self_param_evaluation && is_self_param) {

Ideally instead of just skipping super traits we would synthesize a new PolyTraitRef with a TraitRef with paramus set to some placeholder to avoid the weird edge cases I mentioned before, but couldn't see a good way to do that to a hir node.

estebank

comment created time in 4 days

startedKogia-sima/sailfish

started time in 4 days

pull request commentrust-lang/rust

Permit evaluation of assoc items on `Self` by avoiding cycle error

@craterbot check

estebank

comment created time in 5 days

starteddylanaraps/pywal

started time in 5 days

Pull request review commentrust-lang/rust

Separate projection bounds and predicates

+error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied+  --> $DIR/bounds-are-checked-2.rs:6:13+   |+LL | type X<T> = impl Clone;+   |             ^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `T`+   |+help: consider restricting type parameter `T`+   |+LL | type X<T: std::clone::Clone> = impl Clone;+   |         ^^^^^^^^^^^^^^^^^^^

Re: my last comment. Oh, I see that you are unifying their behavior. This will very likely fail the crater run.

matthewjasper

comment created time in 5 days

Pull request review commentrust-lang/rust

Separate projection bounds and predicates

+warning: unnecessary lifetime parameter `'a`+  --> $DIR/bounds-are-checked.rs:9:6+   |+LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {+   |      ^^^^^^^^^^^+   |+   = help: you can use the `'static` lifetime directly, in place of `'a`++error[E0308]: mismatched types+  --> $DIR/bounds-are-checked.rs:6:14+   |+LL | type X<'a> = impl Into<&'static str> + From<&'a str>;+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch+   |+   = note: expected type `std::convert::From<&'a str>`+              found type `std::convert::From<&'static str>`+note: the lifetime `'a` as defined on the item at 6:8...+  --> $DIR/bounds-are-checked.rs:6:8+   |+LL | type X<'a> = impl Into<&'static str> + From<&'a str>;+   |        ^^+   = note: ...does not necessarily outlive the static lifetime+

Having type aliases for traits (namely, trait aliases) evaluating their obligations at the definition point is counter to how type aliases in general currently behave. Wouldn't we want to unify the behavior, one way or the other?

matthewjasper

comment created time in 5 days

Pull request review commentrust-lang/rust

Separate projection bounds and predicates

 LL |     <i32 as Add<u32>>::add(1, 2);    |     ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32`    |    = help: the trait `std::ops::Add<u32>` is not implemented for `i32`+   = note: required by `std::ops::Add::add`

I'll take a look later how it can be done, but it would be better if we didn't add this redundant note.

matthewjasper

comment created time in 5 days

pull request commentrust-lang/rust

Permit evaluation of assoc items on `Self` by avoiding cycle error

@rust-lang/lang this PR introduces new behavior letting us refer to associated types in super-trait arguments without using a fully qualified path. Only edge case I've been able to come up with is the following:

trait Foo<T> {
    type B;
}
trait Bar<T> {}
trait Baz {
    type A;
}
trait Qux: Foo<Self::A> + Bar<Self::B> + Baz {}

which causes the compile to fail because we proactively skip all bounds that reference Self when evaluating associated types.

You can still make it work with fully qualified paths:

trait Foo<T> {
    type B;
}
trait Bar<T> {}
trait Baz {
    type A;
}
trait Qux: Foo<<Self as Baz>::A> + Bar<<Self as Foo<<Self as Baz>::A>>::B> + Baz {}

or even rely on the new behavior to reduce the verbosity:

trait Foo<T> {
    type B;
}
trait Bar<T> {}
trait Baz {
    type A;
}
trait Qux: Foo<<Self as Baz>::A> + Bar<Self::B> + Baz {}

but I don't know if we want such a "special case" in the language. I think it is worth it (particularly if we at least improve the diagnostics to suggest the appropriate syntax).

estebank

comment created time in 5 days

Pull request review commentrust-lang/rust

Separate projection bounds and predicates

 pub fn elaborate_obligations<'tcx>(  fn predicate_obligation<'tcx>(     predicate: ty::Predicate<'tcx>,-    span: Option<Span>,+    param_env: ty::ParamEnv<'tcx>,+    cause: ObligationCause<'tcx>, ) -> PredicateObligation<'tcx> {-    let cause = if let Some(span) = span {-        ObligationCause::dummy_with_span(span)-    } else {-        ObligationCause::dummy()-    };--    Obligation { cause, param_env: ty::ParamEnv::empty(), recursion_depth: 0, predicate }

Pretty sure I'm the culprit 👋

matthewjasper

comment created time in 5 days

pull request commentrust-lang/rust

Permit evaluation of assoc items on `Self` by avoiding cycle error

@bors try @rust-timer queue

estebank

comment created time in 5 days

push eventestebank/rust

Esteban Küber

commit sha 759a56dcc21e49eac014e195d579f5a26effa251

Permit evaluation of assoc items on `Self` by avoiding cycle error Skip the recursive evaluation of super-traits that reference associated types on `Self` directly (without using a fully-qualified path) in order to allow its use. The following code would previously emit a cycle evaluation error and will now successfuly compile: ```rust trait Bar<T> { fn foo() -> T; } trait Foo: Bar<Self::Qux> { type Qux; } ``` The following will also work: ```rust trait Bar<T> { fn foo() -> T; } trait Baz { type Qux; } trait Foo: Bar<Self::Qux> + Baz {} ``` Fix #35237.

view details

push time in 5 days

pull request commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

ping

estebank

comment created time in 5 days

pull request commentrust-lang/rust

Permit evaluation of assoc items on `Self` by avoiding cycle error

cc @nikomatsakis @joshtriplett

estebank

comment created time in 5 days

push eventestebank/rust

Esteban Küber

commit sha 54c092766cee3f9b389404cf345abce28f0cff67

Permit evaluation of assoc items on `Self` by avoiding cycle error Skip the recursive evaluation of super-traits that reference associated types on `Self` directly (without using a fully-qualified path) in order to allow its use. The following code would previously emit a cycle evaluation error and will now successfuly compile: ```rust trait Bar<T> { fn foo() -> T; } trait Foo: Bar<Self::Qux> { type Qux; } ``` The following will also work: ```rust trait Bar<T> { fn foo() -> T; } trait Baz { type Qux; } trait Foo: Bar<Self::Qux> + Baz {} ``` Fix #35237.

view details

push time in 5 days

push eventestebank/rust

Esteban Küber

commit sha a4a675cad719788486fbadf2535227c9c8210c5b

Permit evaluation of assoc items on `Self` by avoiding cycle error Skip the recursive evaluation of super-traits that reference associated types on `Self` directly (without using a fully-qualified path) in order to allow its use. The following code would previously emit a cycle evaluation error and will now successfuly compile: ```rust trait Bar<T> { fn foo() -> T; } trait Foo: Bar<Self::Qux> { type Qux; } ``` The following will also work: ```rust trait Bar<T> { fn foo() -> T; } trait Baz { type Qux; } trait Foo: Bar<Self::Qux> + Baz {} ``` Fix #35237.

view details

push time in 5 days

push eventestebank/rust

Esteban Küber

commit sha 13ca685be6b3a6814b7293fe7f2ebc00a2ec4efa

Permit evaluation of assoc items on `Self` by avoiding cycle error Skip the recursive evaluation of super-traits that reference associated types on `Self` directly (without using a fully-qualified path) in order to allow its use. The following code would previously emit a cycle evaluation error and will now successfuly compile: ```rust trait Bar<T> { fn foo() -> T; } trait Foo: Bar<Self::Qux> { type Qux; } ``` The following will also work: ```rust trait Bar<T> { fn foo() -> T; } trait Baz { type Qux; } trait Foo: Bar<Self::Qux> + Baz {} ``` Fix #35237.

view details

push time in 5 days

push eventestebank/rust

Esteban Küber

commit sha 1589c20f7dd1005a12bb2eaa6ad957d0c4fbfe6e

Permit evaluation of assoc items on `Self` by avoiding cycle error Skip the recursive evaluation of super-traits that reference associated types on `Self` directly (without using a fully-qualified path) in order to allow its use. The following code would previously emit a cycle evaluation error and will now successfuly compile: ```rust trait Bar<T> { fn foo() -> T; } trait Foo: Bar<Self::Qux> { type Qux; } ``` The following will also work: ```rust trait Bar<T> { fn foo() -> T; } trait Baz { type Qux; } trait Foo: Bar<Self::Qux> + Baz {} ``` Fix #35237.

view details

push time in 5 days

issue commentrust-lang/rust

Trait inheritance gives unexpected compile error when inherited traits use associated types defined in trait

I got the behavior I was aiming at last night and just published a cleaned up PR with it.

It works in exactly the way you would expect. The following builds:

trait Foo {
    type Bar;
}
trait Qux: Foo + AsRef<Self::Bar> {}
trait Foo2 {}

trait Qux2: Foo2 + AsRef<Self::Bar> {
    type Bar;
}

and the following fails because of ambiguity, providing a good suggestion:

trait Foo {
    type Bar;
}
trait Qux: Foo + AsRef<Self::Bar> { //~ ERROR ambiguous associated type `Bar` in bounds of `Self`
    type Bar;
}
error[E0221]: ambiguous associated type `Bar` in bounds of `Self`
  --> $DIR/super-trait-referencing-self-name-clash.rs:4:24
   |
LL |     type Bar;
   |     --------- ambiguous `Bar` from `Foo`
LL | }
LL | trait Qux: Foo + AsRef<Self::Bar> {
   |                        ^^^^^^^^^ ambiguous associated type `Bar`
LL |     type Bar;
   |     --------- ambiguous `Bar` from `Qux`
   |
help: use fully qualified syntax to disambiguate
   |
LL | trait Qux: Foo + AsRef<<Self as Qux>::Bar> {
   |                        ^^^^^^^^^^^^^^^^^^
help: use fully qualified syntax to disambiguate
   |
LL | trait Qux: Foo + AsRef<<Self as Foo>::Bar> {
   |                        ^^^^^^^^^^^^^^^^^^

The code has a special case when it recognizes it is converting an hir path written like Self::Foo and uses an evaluation mode that then skips all super traits that reference Self. When doing so, we won't expand those, making the cycle error go away. The only thing that wouldn't work is trying to reference Self::Assoc in a super-trait that has Assoc, that will continue (correctly) emitting a cycle error (although its output could be made a bit nicer).

Osspial

comment created time in 5 days

PR opened rust-lang/rust

Permit evaluation of assoc items on `Self` by avoiding cycle error

Skip the recursive evaluation of super-traits that reference associated types on Self directly (without using a fully-qualified path) in order to allow its use.

The following code would previously emit a cycle evaluation error and will now successfuly compile:

trait Bar<T> {
    fn foo() -> T;
}
trait Foo: Bar<Self::Qux> {
    type Qux;
}

The following will also work:

trait Bar<T> {
    fn foo() -> T;
}
trait Baz {
    type Qux;
}
trait Foo: Bar<Self::Qux> + Baz {}

Fix #35237.

+240 -53

0 comment

11 changed files

pr created time in 5 days

create barnchestebank/rust

branch : self-param-assoc-item

created branch time in 5 days

issue commentrust-lang/rust

Strange .cloned() error message mentioning iterators

A method fn cloned(&self) exists in Iterator. The note is telling you that method that does exist is not callable on Option<_> because Option<_> doesn't implement Iterator. We can probably reword this to make that clearer.

enterprisey

comment created time in 5 days

issue commentrust-lang/rust

Parameter usage is not properly propagated through trait aliases

type alias doesn't propagate obligations, it's not only for impl Trait that this is the case. This might change in the future.

vandenheuvel

comment created time in 6 days

Pull request review commentrust-lang/rust

diagnostics: shorten paths of unique symbols

 pub struct GlobalCtxt<'tcx> {      maybe_unused_trait_imports: FxHashSet<LocalDefId>,     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,++    pub unique_symbols: FxHashMap<DefId, Symbol>,

Can you add a short docstring for this field?

da-x

comment created time in 9 days

pull request commentrust-lang/rust

diagnostics: shorten paths of unique symbols

  • The String-related hints in src/test/ui/span/issue-39018.stderr are gone.

rustc_on_unimplemented uses the string representation of the path for types to select what message to give. We'll need to change the code in src/librustc_trait_selection/traits/error_reporting/mod.rs:report_selection_error to always use the full path.

da-x

comment created time in 6 days

issue commentrust-lang/rust

Confusing error message when not having a variable name

Btw, the parser was expecting a comma because let doesn't just take identifiers, but patterns, which let's you write let Struct { name, ..} = struct_val;.

Would the following have been enough to help you?

error: expected `,`
  --> src/main.rs:10:13
   |
 9 |     let Test {
   |         ---- while parsing this pattern
10 |       name: "a".to_owned()
   |             ^^^
AZanellato

comment created time in 7 days

issue openedrust-lang/rust

Detect invalid turbofish `foo.bar::Type<T>()`in the parser

Detect when the user has likely forgotten to wrap the type param with the type param delimiters:

fn main() {
    let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
}

where we currently emit:

error: expected one of `(`, `.`, `;`, `?`, or an operator, found `::`
 --> src/main.rs:2:46
  |
2 |     let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
  |                                              ^^ expected one of `(`, `.`, `;`, `?`, or an operator

created time in 7 days

issue commentrust-lang/rust

Trait inheritance gives unexpected compile error when inherited traits use associated types defined in trait

I think I just found out a trivial way of making this work for associated types on the base trait. What do we want to do for super traits, like the following case?

trait Foo: AsRef<Self::Bar> {
    type Bar;
}
trait Bar: Foo + AsRef<Self::Bar> {}

I can easily make the first one work, but for the later 1) I don't know how easy it will be to make it work, but probably doable, 2) don't know if we want to make it work when there's a single unambiguous assoc type that can be used from a super trait 3) I would imagine if more than one assoc type that could match we would want to error like we do for assoc fns:

error[E0034]: multiple applicable items in scope
  --> fil12.rs:16:25
   |
16 |     fn bar(&self) {self.foo()}
   |                         ^^^ multiple `foo` found
   |
note: candidate #1 is defined in the trait `Foo`
  --> fil12.rs:9:5
   |
9  |     fn foo(&self);
   |     ^^^^^^^^^^^^^^
note: candidate #2 is defined in the trait `Baz`
  --> fil12.rs:12:5
   |
12 |     fn foo(&self);
   |     ^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #1
   |
16 |     fn bar(&self) {Foo::foo(&self)}
   |                    ^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #2
   |
16 |     fn bar(&self) {Baz::foo(&self)}
   |                    ^^^^^^^^^^^^^^^
Osspial

comment created time in 7 days

startedwillmcgugan/rich

started time in 7 days

pull request commentrust-lang/cargo

Add support for rustc's `-Z terminal-width`.

I'm not sure if there's an actual use case for manually passing in the width?

I could see third party tools working through cargo instead or rustc directly to use it to make output fit the users viewport, but I guess most tools will be using rustc directly.

davidtwco

comment created time in 8 days

pull request commentrust-lang/rust

Audit hidden/short code suggestions

@bors r+

JohnTitor

comment created time in 9 days

push eventestebank/rust

Esteban Küber

commit sha cc7fe89d9cfe85fc08f48ec1b6dcfb0f60948b94

Provide structured suggestions for incorrect patterns * Provide structured suggestion for tuple struct used as struct pattern. * Provide structured suggestion for struct used as tuple struct pattern. Address most of #61326.

view details

Esteban Küber

commit sha 9fb5ead989cbe32f74de5d8db0254f7f097b66ef

Further tweak output

view details

Esteban Küber

commit sha 9784cac4d104ca18ed94d356987201d6307a976b

Span tweaking to avoid weird output

view details

push time in 9 days

PR opened rust-lang/rust

Clean up errors caused by `::` -> `:` typos

Deduplicate errors caused by the same type ascription typo, including ones suggested during parsing that would get reported again during resolve. Fix #70382.

Remove link to type ascription tracking issue when this is a likely typoed path to reduce unnecessary verbosity.

Tweak typo inference to ignore things that look like types and include things that look like paths (Foo<Bar> is ignored while Foo::<Bar> is accepted).

Mark more tests as run-rustfix.

CC #34255.

+310 -132

0 comment

26 changed files

pr created time in 9 days

create barnchestebank/rust

branch : type-ascription-redux

created branch time in 9 days

pull request commentrust-lang/rust

diagnostics: shorten paths of unique symbols

The point about consistency doesn't sway me much as I would like people to be able to copy things from the output and paste them where the error happened and have things just work, but the later point makes a lot of sense: people will just get the follow up suggestion for imports. This last thing is something we already rely on other cases and I feel is a perfectly fine workflow. I'll review today but now I think this is a perfectly reasonable approach. It will still obviously not address the case of repeated identifiers but it's already a huge improvement.

da-x

comment created time in 9 days

pull request commentrust-lang/rust

diagnostics: shorten paths of unique symbols

This is an ingenious solution that as shown can get us quite far and love it's simplicity. I'm concerned about two things:

  • the memory implications of this change on larger projects, but the Symbols are interned so this shouldn't be a huge impact and is at worst linear

  • now we use the name only, even if the type is not in scope

This last point has a couple of implications. Types that haven't been imported might produce errors that don't let you figure out how to suggest them. Also I didn't see the whole PR yet but there are use suggestions

da-x

comment created time in 9 days

issue commentrust-lang/rust

Trait inheritance gives unexpected compile error when inherited traits use associated types defined in trait

It feels to me that it should be accepted code, but I think that decision falls under @rust-lang/lang's purview. If they decide against it, then either proposed solution seems fine, with the former looking easiest to implement. Even if we decide to fix this so the code compiles it'd be nice to have a better message with a suggestion in the meantime.

Osspial

comment created time in 9 days

Pull request review commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

  use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError;-use rustc_errors::{struct_span_err, Applicability, ErrorReported};-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};-use rustc_middle::ty::RegionKind;+use crate::infer::{SubregionOrigin, TypeTrace};+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};+use rustc_hir::def_id::DefId;+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};+use rustc_hir::{+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,+    TyKind,+};+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};+use rustc_span::{MultiSpan, Span};  impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {-    /// Print the error message for lifetime errors when the return type is a static impl Trait.+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {         debug!("try_report_static_impl_trait(error={:?})", self.error);-        if let Some(RegionResolutionError::SubSupConflict(-            _,-            var_origin,-            ref sub_origin,-            sub_r,-            ref sup_origin,-            sup_r,-        )) = self.error-        {-            debug!(-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",-                var_origin, sub_origin, sub_r, sup_origin, sup_r-            );-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);-            if fn_returns.is_empty() {+        let tcx = self.tcx();+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {+            RegionResolutionError::SubSupConflict(+                _,+                var_origin,+                sub_origin,+                sub_r,+                sup_origin,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)+            }+            RegionResolutionError::ConcreteFailure(+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),+                sub_r,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                    let param = self.find_param_with_region(sup_r, sub_r)?;+                    let lifetime = if sup_r.has_name() {+                        format!("lifetime `{}`", sup_r)+                    } else {+                        "an anonymous lifetime `'_`".to_string()+                    };+                    let mut err = struct_span_err!(+                        tcx.sess,+                        cause.span,+                        E0767,+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param+                            .param+                            .pat+                            .simple_ident()+                            .map(|s| format!("`{}`", s))+                            .unwrap_or_else(|| "`fn` parameter".to_string()),+                        lifetime,+                        ctxt.assoc_item.ident,+                    );+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+                    err.span_label(+                        cause.span,+                        &format!(+                            "...is captured and required to live as long as `'static` here \+                             because of an implicit lifetime bound on the {}",+                            match ctxt.assoc_item.container {+                                AssocItemContainer::TraitContainer(id) =>+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),+                                AssocItemContainer::ImplContainer(_) =>+                                    "inherent `impl`".to_string(),+                            },+                        ),+                    );+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {+                        err.emit();+                        return Some(ErrorReported);+                    } else {+                        err.cancel();+                    }+                }                 return None;             }-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);-            if *sub_r == RegionKind::ReStatic {-                let sp = var_origin.span();-                let return_sp = sub_origin.span();-                let param_info = self.find_param_with_region(sup_r, sub_r)?;-                let (lifetime_name, lifetime) = if sup_r.has_name() {-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))-                } else {-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())-                };-                let mut err = struct_span_err!(-                    self.tcx().sess,-                    sp,-                    E0759,-                    "cannot infer an appropriate lifetime"-                );-                err.span_label(-                    param_info.param_ty_span,-                    &format!("this data with {}...", lifetime),-                );-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);+            _ => return None,+        };+        debug!(+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",+            var_origin, sub_origin, sub_r, sup_origin, sup_r+        );+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);+        let sp = var_origin.span();+        let return_sp = sub_origin.span();+        let param = self.find_param_with_region(sup_r, sub_r)?;+        let (lifetime_name, lifetime) = if sup_r.has_name() {+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))+        } else {+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())+        };+        let param_name = param+            .param+            .pat+            .simple_ident()+            .map(|s| format!("`{}`", s))+            .unwrap_or_else(|| "`fn` parameter".to_string());+        let mut err = struct_span_err!(+            tcx.sess,+            sp,+            E0759,+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",+            param_name,+            lifetime,+        );+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+        debug!("try_report_static_impl_trait: param_info={:?}", param);++        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); -                // We try to make the output have fewer overlapping spans if possible.-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))-                    && sup_origin.span() != return_sp+        let mut postfix = String::new();+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)+                    && fn_returns.is_empty()                 {-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`--                    // Customize the spans and labels depending on their relative order so-                    // that split sentences flow correctly.-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {-                        // Avoid the following:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                      ---------^--                        //-                        // and instead show:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                               ^-                        err.span_label(-                            sup_origin.span(),-                            "...is captured here, requiring it to live as long as `'static`",-                        );-                    } else {-                        err.span_label(sup_origin.span(), "...is captured here...");-                        if return_sp < sup_origin.span() {-                            err.span_note(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        } else {-                            err.span_label(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        }-                    }+                    err.code(rustc_errors::error_code!(E0767));+                    err.set_primary_message(&format!(+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param_name, lifetime, ctxt.assoc_item.ident,+                    ));+                    postfix = format!(+                        " because of an implicit lifetime on the {}",+                        match ctxt.assoc_item.container {+                            AssocItemContainer::TraitContainer(id) =>+                                format!("`impl` of `{}`", tcx.def_path_str(id)),+                            AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(),+                        },+                    );+                }+                // }+            }+        }++        // We try to make the output have fewer overlapping spans if possible.+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))+            && sup_origin.span() != return_sp+        {+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`++            // Customize the spans and labels depending on their relative order so+            // that split sentences flow correctly.+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {+                // Avoid the following:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                      ---------^-+                //+                // and instead show:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                               ^+                err.span_label(+                    sup_origin.span(),+                    &format!(+                        "...is captured here, requiring it to live as long as `'static`{}",+                        postfix+                    ),+                );+            } else {+                err.span_label(sup_origin.span(), "...is captured here...");+                if return_sp < sup_origin.span() {+                    err.span_note(+                        return_sp,+                        &format!("...and is required to live as long as `'static` here{}", postfix),+                    );                 } else {                     err.span_label(                         return_sp,-                        "...is captured and required to live as long as `'static` here",+                        &format!("...and is required to live as long as `'static` here{}", postfix),                     );                 }+            }+        } else {+            err.span_label(+                return_sp,+                &format!(+                    "...is captured and required to live as long as `'static` here{}",+                    postfix+                ),+            );+        } -                // FIXME: account for the need of parens in `&(dyn Trait + '_)`-                let consider = "consider changing the";-                let declare = "to declare that the";-                let arg = match param_info.param.pat.simple_ident() {-                    Some(simple_ident) => format!("argument `{}`", simple_ident),-                    None => "the argument".to_string(),-                };-                let explicit =-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);-                let explicit_static =-                    format!("explicit `'static` bound to the lifetime of {}", arg);-                let captures = format!("captures data from {}", arg);-                let add_static_bound =-                    "alternatively, add an explicit `'static` bound to this reference";-                let plus_lt = format!(" + {}", lifetime_name);-                for fn_return in fn_returns {-                    if fn_return.span.desugaring_kind().is_some() {-                        // Skip `async` desugaring `impl Future`.-                        continue;+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`+        let consider = "consider changing the";+        let declare = "to declare that the";+        let arg = match param.param.pat.simple_ident() {+            Some(simple_ident) => format!("argument `{}`", simple_ident),+            None => "the argument".to_string(),+        };+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);+        let captures = format!("captures data from {}", arg);+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";+        let plus_lt = format!(" + {}", lifetime_name);+        for fn_return in fn_returns {+            if fn_return.span.desugaring_kind().is_some() {+                // Skip `async` desugaring `impl Future`.+                continue;+            }+            match fn_return.kind {+                TyKind::OpaqueDef(item_id, _) => {+                    let item = tcx.hir().item(item_id.id);+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {+                        opaque+                    } else {+                        err.emit();+                        return Some(ErrorReported);+                    };++                    if let Some(span) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime {+                                name: LifetimeName::Static,+                                span,+                                ..+                            }) => Some(*span),+                            _ => None,+                        })+                        .next()+                    {+                        err.span_suggestion_verbose(+                            span,+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    } else if let Some(_) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime { name, span, .. })+                                if name.ident().to_string() == lifetime_name =>+                            {+                                Some(*span)+                            }+                            _ => None,+                        })+                        .next()+                    {+                    } else {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} `impl Trait` {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );                     }-                    match fn_return.kind {-                        TyKind::OpaqueDef(item_id, _) => {-                            let item = self.tcx().hir().item(item_id.id);-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {-                                opaque-                            } else {-                                err.emit();-                                return Some(ErrorReported);-                            };--                            if let Some(span) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime {-                                        name: LifetimeName::Static,-                                        span,+                }+                TyKind::TraitObject(_, lt) => match lt.name {+                    LifetimeName::ImplicitObjectLifetimeDefault => {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} trait object {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    name if name.ident().to_string() != lifetime_name => {+                        // With this check we avoid suggesting redundant bounds. This+                        // would happen if there are nested impl/dyn traits and only+                        // one of them has the bound we'd suggest already there, like+                        // in `impl Foo<X = dyn Bar> + '_`.+                        err.span_suggestion_verbose(+                            lt.span,+                            &format!("{} trait object's {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    _ => {}+                },+                _ => {}+            }+        }+        err.emit();+        Some(ErrorReported)+    }++    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default+    /// `'static` obligation. Suggest relaxing that implicit bound.+    fn find_impl_on_dyn_trait(+        &self,+        err: &mut DiagnosticBuilder<'_>,+        ty: Ty<'_>,+        ctxt: &UnifyReceiverContext<'tcx>,+    ) -> bool {+        let tcx = self.tcx();+        let mut suggested = false;++        // Find the method being called.+        let instance = match ty::Instance::resolve(+            tcx,+            ctxt.param_env,+            ctxt.assoc_item.def_id,+            self.infcx.resolve_vars_if_possible(&ctxt.substs),+        ) {+            Ok(Some(instance)) => instance,+            _ => return false,+        };++        let mut v = TraitObjectVisitor(vec![]);+        v.visit_ty(ty);++        // Get the `Ident` of the method being called and the corresponding `impl` (to point at+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).+        let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) {+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {+                        (ident, self_ty)+                    }+                    _ => return false,+                }+            }+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {+                let parent_id = tcx.hir().get_parent_item(*hir_id);+                match tcx.hir().find(parent_id) {+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {+                        // The method being called is defined in the `trait`, but the `'static`

I'm satisfied with the cases I'm handling. I'll revisit this in the future for further improvement but I think can be merged. (Of courses take a last review pass to make sure I didn't introduce anything by accident.)

estebank

comment created time in 9 days

issue commentrust-lang/rust

Misleading error message on typo "Type ascription"

https://github.com/rust-lang/rust/issues/73777 brought up the possibility of issues when it comes to typos in macro calls. I feel that the approach of leaving this to macro authors like in that ticket is reasonable enough.

https://github.com/rust-lang/rust/issues/70382 brings up a specific case of bad output when recovering some paths.

danielpclark

comment created time in 10 days

issue closedrust-lang/rust

Type ascription misdiagnosis when trying to use serde_json::json!

Hi @estebank I didn't forget about your encouragement on Twitter: https://twitter.com/ekuber/status/1255881826855313409?s=20

I forgot a comma at the end of the first key-value pair:

fn main() {
    let json = serde_json::json!({
        "domain_name": "redjack.com"
        "passive_provenance": [420, 69],
    });
}

On the latest nightly compiler this is explicitly diagnosed as an attempt to use type ascription:

error: expected type, found `"redjack.com"`
 --> src/main.rs:3:24
  |
3 |         "domain_name": "redjack.com"
  |                      - ^^^^^^^^^^^^^ expected type
  |                      |
  |                      tried to parse a type due to this type ascription
  |
  = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `<expr>: <type>`
  = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information

On stable, it's arguably much worse, the error only makes sense if you know the compiler thinks this is type ascription but feature is not mentioned:

error: expected type, found `"redjack.com"`
 --> src/main.rs:3:24
  |
3 |         "domain_name": "redjack.com"
  |                      - ^^^^^^^^^^^^^ expected type
  |                      |
  |                      tried to parse a type due to this

closed time in 10 days

saethlin

issue commentrust-lang/rust

Type ascription misdiagnosis when trying to use serde_json::json!

Closing as per the fix in serde and CCing https://github.com/rust-lang/rust/issues/34255 which tracks the work around type ascription more generally.

saethlin

comment created time in 10 days

Pull request review commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

  use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError;-use rustc_errors::{struct_span_err, Applicability, ErrorReported};-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};-use rustc_middle::ty::RegionKind;+use crate::infer::{SubregionOrigin, TypeTrace};+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};+use rustc_hir::def_id::DefId;+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};+use rustc_hir::{+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,+    TyKind,+};+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};+use rustc_span::{MultiSpan, Span};  impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {-    /// Print the error message for lifetime errors when the return type is a static impl Trait.+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {         debug!("try_report_static_impl_trait(error={:?})", self.error);-        if let Some(RegionResolutionError::SubSupConflict(-            _,-            var_origin,-            ref sub_origin,-            sub_r,-            ref sup_origin,-            sup_r,-        )) = self.error-        {-            debug!(-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",-                var_origin, sub_origin, sub_r, sup_origin, sup_r-            );-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);-            if fn_returns.is_empty() {+        let tcx = self.tcx();+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {+            RegionResolutionError::SubSupConflict(+                _,+                var_origin,+                sub_origin,+                sub_r,+                sup_origin,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)+            }+            RegionResolutionError::ConcreteFailure(+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),+                sub_r,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                    let param = self.find_param_with_region(sup_r, sub_r)?;+                    let lifetime = if sup_r.has_name() {+                        format!("lifetime `{}`", sup_r)+                    } else {+                        "an anonymous lifetime `'_`".to_string()+                    };+                    let mut err = struct_span_err!(+                        tcx.sess,+                        cause.span,+                        E0767,+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param+                            .param+                            .pat+                            .simple_ident()+                            .map(|s| format!("`{}`", s))+                            .unwrap_or_else(|| "`fn` parameter".to_string()),+                        lifetime,+                        ctxt.assoc_item.ident,+                    );+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+                    err.span_label(+                        cause.span,+                        &format!(+                            "...is captured and required to live as long as `'static` here \+                             because of an implicit lifetime bound on the {}",+                            match ctxt.assoc_item.container {+                                AssocItemContainer::TraitContainer(id) =>+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),+                                AssocItemContainer::ImplContainer(_) =>+                                    "inherent `impl`".to_string(),+                            },+                        ),+                    );+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {+                        err.emit();+                        return Some(ErrorReported);+                    } else {+                        err.cancel();+                    }+                }                 return None;             }-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);-            if *sub_r == RegionKind::ReStatic {-                let sp = var_origin.span();-                let return_sp = sub_origin.span();-                let param_info = self.find_param_with_region(sup_r, sub_r)?;-                let (lifetime_name, lifetime) = if sup_r.has_name() {-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))-                } else {-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())-                };-                let mut err = struct_span_err!(-                    self.tcx().sess,-                    sp,-                    E0759,-                    "cannot infer an appropriate lifetime"-                );-                err.span_label(-                    param_info.param_ty_span,-                    &format!("this data with {}...", lifetime),-                );-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);+            _ => return None,+        };+        debug!(+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",+            var_origin, sub_origin, sub_r, sup_origin, sup_r+        );+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);+        let sp = var_origin.span();+        let return_sp = sub_origin.span();+        let param = self.find_param_with_region(sup_r, sub_r)?;+        let (lifetime_name, lifetime) = if sup_r.has_name() {+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))+        } else {+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())+        };+        let param_name = param+            .param+            .pat+            .simple_ident()+            .map(|s| format!("`{}`", s))+            .unwrap_or_else(|| "`fn` parameter".to_string());+        let mut err = struct_span_err!(+            tcx.sess,+            sp,+            E0759,+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",+            param_name,+            lifetime,+        );+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+        debug!("try_report_static_impl_trait: param_info={:?}", param);++        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); -                // We try to make the output have fewer overlapping spans if possible.-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))-                    && sup_origin.span() != return_sp+        let mut postfix = String::new();+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)+                    && fn_returns.is_empty()                 {-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`--                    // Customize the spans and labels depending on their relative order so-                    // that split sentences flow correctly.-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {-                        // Avoid the following:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                      ---------^--                        //-                        // and instead show:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                               ^-                        err.span_label(-                            sup_origin.span(),-                            "...is captured here, requiring it to live as long as `'static`",-                        );-                    } else {-                        err.span_label(sup_origin.span(), "...is captured here...");-                        if return_sp < sup_origin.span() {-                            err.span_note(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        } else {-                            err.span_label(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        }-                    }+                    err.code(rustc_errors::error_code!(E0767));+                    err.set_primary_message(&format!(+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param_name, lifetime, ctxt.assoc_item.ident,+                    ));+                    postfix = format!(+                        " because of an implicit lifetime on the {}",+                        match ctxt.assoc_item.container {+                            AssocItemContainer::TraitContainer(id) =>+                                format!("`impl` of `{}`", tcx.def_path_str(id)),+                            AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(),+                        },+                    );+                }+                // }+            }+        }++        // We try to make the output have fewer overlapping spans if possible.+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))+            && sup_origin.span() != return_sp+        {+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`++            // Customize the spans and labels depending on their relative order so+            // that split sentences flow correctly.+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {+                // Avoid the following:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                      ---------^-+                //+                // and instead show:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                               ^+                err.span_label(+                    sup_origin.span(),+                    &format!(+                        "...is captured here, requiring it to live as long as `'static`{}",+                        postfix+                    ),+                );+            } else {+                err.span_label(sup_origin.span(), "...is captured here...");+                if return_sp < sup_origin.span() {+                    err.span_note(+                        return_sp,+                        &format!("...and is required to live as long as `'static` here{}", postfix),+                    );                 } else {                     err.span_label(                         return_sp,-                        "...is captured and required to live as long as `'static` here",+                        &format!("...and is required to live as long as `'static` here{}", postfix),                     );                 }+            }+        } else {+            err.span_label(+                return_sp,+                &format!(+                    "...is captured and required to live as long as `'static` here{}",+                    postfix+                ),+            );+        } -                // FIXME: account for the need of parens in `&(dyn Trait + '_)`-                let consider = "consider changing the";-                let declare = "to declare that the";-                let arg = match param_info.param.pat.simple_ident() {-                    Some(simple_ident) => format!("argument `{}`", simple_ident),-                    None => "the argument".to_string(),-                };-                let explicit =-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);-                let explicit_static =-                    format!("explicit `'static` bound to the lifetime of {}", arg);-                let captures = format!("captures data from {}", arg);-                let add_static_bound =-                    "alternatively, add an explicit `'static` bound to this reference";-                let plus_lt = format!(" + {}", lifetime_name);-                for fn_return in fn_returns {-                    if fn_return.span.desugaring_kind().is_some() {-                        // Skip `async` desugaring `impl Future`.-                        continue;+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`+        let consider = "consider changing the";+        let declare = "to declare that the";+        let arg = match param.param.pat.simple_ident() {+            Some(simple_ident) => format!("argument `{}`", simple_ident),+            None => "the argument".to_string(),+        };+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);+        let captures = format!("captures data from {}", arg);+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";+        let plus_lt = format!(" + {}", lifetime_name);+        for fn_return in fn_returns {+            if fn_return.span.desugaring_kind().is_some() {+                // Skip `async` desugaring `impl Future`.+                continue;+            }+            match fn_return.kind {+                TyKind::OpaqueDef(item_id, _) => {+                    let item = tcx.hir().item(item_id.id);+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {+                        opaque+                    } else {+                        err.emit();+                        return Some(ErrorReported);+                    };++                    if let Some(span) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime {+                                name: LifetimeName::Static,+                                span,+                                ..+                            }) => Some(*span),+                            _ => None,+                        })+                        .next()+                    {+                        err.span_suggestion_verbose(+                            span,+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    } else if let Some(_) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime { name, span, .. })+                                if name.ident().to_string() == lifetime_name =>+                            {+                                Some(*span)+                            }+                            _ => None,+                        })+                        .next()+                    {+                    } else {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} `impl Trait` {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );                     }-                    match fn_return.kind {-                        TyKind::OpaqueDef(item_id, _) => {-                            let item = self.tcx().hir().item(item_id.id);-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {-                                opaque-                            } else {-                                err.emit();-                                return Some(ErrorReported);-                            };--                            if let Some(span) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime {-                                        name: LifetimeName::Static,-                                        span,+                }+                TyKind::TraitObject(_, lt) => match lt.name {+                    LifetimeName::ImplicitObjectLifetimeDefault => {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} trait object {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    name if name.ident().to_string() != lifetime_name => {+                        // With this check we avoid suggesting redundant bounds. This+                        // would happen if there are nested impl/dyn traits and only+                        // one of them has the bound we'd suggest already there, like+                        // in `impl Foo<X = dyn Bar> + '_`.+                        err.span_suggestion_verbose(+                            lt.span,+                            &format!("{} trait object's {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    _ => {}+                },+                _ => {}+            }+        }+        err.emit();+        Some(ErrorReported)+    }++    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default+    /// `'static` obligation. Suggest relaxing that implicit bound.+    fn find_impl_on_dyn_trait(+        &self,+        err: &mut DiagnosticBuilder<'_>,+        ty: Ty<'_>,+        ctxt: &UnifyReceiverContext<'tcx>,+    ) -> bool {+        let tcx = self.tcx();+        let mut suggested = false;++        // Find the method being called.+        let instance = match ty::Instance::resolve(+            tcx,+            ctxt.param_env,+            ctxt.assoc_item.def_id,+            self.infcx.resolve_vars_if_possible(&ctxt.substs),+        ) {+            Ok(Some(instance)) => instance,+            _ => return false,+        };++        let mut v = TraitObjectVisitor(vec![]);+        v.visit_ty(ty);++        // Get the `Ident` of the method being called and the corresponding `impl` (to point at+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).+        let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) {+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {+                        (ident, self_ty)+                    }+                    _ => return false,+                }+            }+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {+                let parent_id = tcx.hir().get_parent_item(*hir_id);+                match tcx.hir().find(parent_id) {+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {+                        // The method being called is defined in the `trait`, but the `'static`

I did a quick test modifying Instance::resolve and I caused a bunch of unrelated ICEs. I'll do that in a follow up PR.

estebank

comment created time in 10 days

pull request commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

The original ping was for a subpar way of getting the right impl items. Now it's using Instance::resolve except for the cases involving a method with a default body (so we need to search for the impl after the fact) and for calling the fully qualified path (because then we don't have the context). Can you take a look at that part, mainly the new methods where I'm fetching all impls for a given trait? Also, I would like to get your feedback on the new diagnostics output. Other than that I feel this is ready for merging.

estebank

comment created time in 10 days

Pull request review commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

  use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError;-use rustc_errors::{struct_span_err, Applicability, ErrorReported};-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};-use rustc_middle::ty::RegionKind;+use crate::infer::{SubregionOrigin, TypeTrace};+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};+use rustc_hir::def_id::DefId;+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};+use rustc_hir::{+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,+    TyKind,+};+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};+use rustc_span::{MultiSpan, Span};  impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {-    /// Print the error message for lifetime errors when the return type is a static impl Trait.+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {         debug!("try_report_static_impl_trait(error={:?})", self.error);-        if let Some(RegionResolutionError::SubSupConflict(-            _,-            var_origin,-            ref sub_origin,-            sub_r,-            ref sup_origin,-            sup_r,-        )) = self.error-        {-            debug!(-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",-                var_origin, sub_origin, sub_r, sup_origin, sup_r-            );-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);-            if fn_returns.is_empty() {+        let tcx = self.tcx();+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {+            RegionResolutionError::SubSupConflict(+                _,+                var_origin,+                sub_origin,+                sub_r,+                sup_origin,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)+            }+            RegionResolutionError::ConcreteFailure(+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),+                sub_r,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                    let param = self.find_param_with_region(sup_r, sub_r)?;+                    let lifetime = if sup_r.has_name() {+                        format!("lifetime `{}`", sup_r)+                    } else {+                        "an anonymous lifetime `'_`".to_string()+                    };+                    let mut err = struct_span_err!(+                        tcx.sess,+                        cause.span,+                        E0767,+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param+                            .param+                            .pat+                            .simple_ident()+                            .map(|s| format!("`{}`", s))+                            .unwrap_or_else(|| "`fn` parameter".to_string()),+                        lifetime,+                        ctxt.assoc_item.ident,+                    );+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+                    err.span_label(+                        cause.span,+                        &format!(+                            "...is captured and required to live as long as `'static` here \+                             because of an implicit lifetime bound on the {}",+                            match ctxt.assoc_item.container {+                                AssocItemContainer::TraitContainer(id) =>+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),+                                AssocItemContainer::ImplContainer(_) =>+                                    "inherent `impl`".to_string(),+                            },+                        ),+                    );+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {+                        err.emit();+                        return Some(ErrorReported);+                    } else {+                        err.cancel();+                    }+                }                 return None;             }-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);-            if *sub_r == RegionKind::ReStatic {-                let sp = var_origin.span();-                let return_sp = sub_origin.span();-                let param_info = self.find_param_with_region(sup_r, sub_r)?;-                let (lifetime_name, lifetime) = if sup_r.has_name() {-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))-                } else {-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())-                };-                let mut err = struct_span_err!(-                    self.tcx().sess,-                    sp,-                    E0759,-                    "cannot infer an appropriate lifetime"-                );-                err.span_label(-                    param_info.param_ty_span,-                    &format!("this data with {}...", lifetime),-                );-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);+            _ => return None,+        };+        debug!(+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",+            var_origin, sub_origin, sub_r, sup_origin, sup_r+        );+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);+        let sp = var_origin.span();+        let return_sp = sub_origin.span();+        let param = self.find_param_with_region(sup_r, sub_r)?;+        let (lifetime_name, lifetime) = if sup_r.has_name() {+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))+        } else {+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())+        };+        let param_name = param+            .param+            .pat+            .simple_ident()+            .map(|s| format!("`{}`", s))+            .unwrap_or_else(|| "`fn` parameter".to_string());+        let mut err = struct_span_err!(+            tcx.sess,+            sp,+            E0759,+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",+            param_name,+            lifetime,+        );+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+        debug!("try_report_static_impl_trait: param_info={:?}", param);++        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); -                // We try to make the output have fewer overlapping spans if possible.-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))-                    && sup_origin.span() != return_sp+        let mut postfix = String::new();+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)+                    && fn_returns.is_empty()                 {-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`--                    // Customize the spans and labels depending on their relative order so-                    // that split sentences flow correctly.-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {-                        // Avoid the following:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                      ---------^--                        //-                        // and instead show:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                               ^-                        err.span_label(-                            sup_origin.span(),-                            "...is captured here, requiring it to live as long as `'static`",-                        );-                    } else {-                        err.span_label(sup_origin.span(), "...is captured here...");-                        if return_sp < sup_origin.span() {-                            err.span_note(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        } else {-                            err.span_label(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        }-                    }+                    err.code(rustc_errors::error_code!(E0767));+                    err.set_primary_message(&format!(+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param_name, lifetime, ctxt.assoc_item.ident,+                    ));+                    postfix = format!(+                        " because of an implicit lifetime on the {}",+                        match ctxt.assoc_item.container {+                            AssocItemContainer::TraitContainer(id) =>+                                format!("`impl` of `{}`", tcx.def_path_str(id)),+                            AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(),+                        },+                    );+                }+                // }+            }+        }++        // We try to make the output have fewer overlapping spans if possible.+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))+            && sup_origin.span() != return_sp+        {+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`++            // Customize the spans and labels depending on their relative order so+            // that split sentences flow correctly.+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {+                // Avoid the following:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                      ---------^-+                //+                // and instead show:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                               ^+                err.span_label(+                    sup_origin.span(),+                    &format!(+                        "...is captured here, requiring it to live as long as `'static`{}",+                        postfix+                    ),+                );+            } else {+                err.span_label(sup_origin.span(), "...is captured here...");+                if return_sp < sup_origin.span() {+                    err.span_note(+                        return_sp,+                        &format!("...and is required to live as long as `'static` here{}", postfix),+                    );                 } else {                     err.span_label(                         return_sp,-                        "...is captured and required to live as long as `'static` here",+                        &format!("...and is required to live as long as `'static` here{}", postfix),                     );                 }+            }+        } else {+            err.span_label(+                return_sp,+                &format!(+                    "...is captured and required to live as long as `'static` here{}",+                    postfix+                ),+            );+        } -                // FIXME: account for the need of parens in `&(dyn Trait + '_)`-                let consider = "consider changing the";-                let declare = "to declare that the";-                let arg = match param_info.param.pat.simple_ident() {-                    Some(simple_ident) => format!("argument `{}`", simple_ident),-                    None => "the argument".to_string(),-                };-                let explicit =-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);-                let explicit_static =-                    format!("explicit `'static` bound to the lifetime of {}", arg);-                let captures = format!("captures data from {}", arg);-                let add_static_bound =-                    "alternatively, add an explicit `'static` bound to this reference";-                let plus_lt = format!(" + {}", lifetime_name);-                for fn_return in fn_returns {-                    if fn_return.span.desugaring_kind().is_some() {-                        // Skip `async` desugaring `impl Future`.-                        continue;+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`+        let consider = "consider changing the";+        let declare = "to declare that the";+        let arg = match param.param.pat.simple_ident() {+            Some(simple_ident) => format!("argument `{}`", simple_ident),+            None => "the argument".to_string(),+        };+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);+        let captures = format!("captures data from {}", arg);+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";+        let plus_lt = format!(" + {}", lifetime_name);+        for fn_return in fn_returns {+            if fn_return.span.desugaring_kind().is_some() {+                // Skip `async` desugaring `impl Future`.+                continue;+            }+            match fn_return.kind {+                TyKind::OpaqueDef(item_id, _) => {+                    let item = tcx.hir().item(item_id.id);+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {+                        opaque+                    } else {+                        err.emit();+                        return Some(ErrorReported);+                    };++                    if let Some(span) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime {+                                name: LifetimeName::Static,+                                span,+                                ..+                            }) => Some(*span),+                            _ => None,+                        })+                        .next()+                    {+                        err.span_suggestion_verbose(+                            span,+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    } else if let Some(_) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime { name, span, .. })+                                if name.ident().to_string() == lifetime_name =>+                            {+                                Some(*span)+                            }+                            _ => None,+                        })+                        .next()+                    {+                    } else {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} `impl Trait` {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );                     }-                    match fn_return.kind {-                        TyKind::OpaqueDef(item_id, _) => {-                            let item = self.tcx().hir().item(item_id.id);-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {-                                opaque-                            } else {-                                err.emit();-                                return Some(ErrorReported);-                            };--                            if let Some(span) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime {-                                        name: LifetimeName::Static,-                                        span,+                }+                TyKind::TraitObject(_, lt) => match lt.name {+                    LifetimeName::ImplicitObjectLifetimeDefault => {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} trait object {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    name if name.ident().to_string() != lifetime_name => {+                        // With this check we avoid suggesting redundant bounds. This+                        // would happen if there are nested impl/dyn traits and only+                        // one of them has the bound we'd suggest already there, like+                        // in `impl Foo<X = dyn Bar> + '_`.+                        err.span_suggestion_verbose(+                            lt.span,+                            &format!("{} trait object's {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    _ => {}+                },+                _ => {}+            }+        }+        err.emit();+        Some(ErrorReported)+    }++    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default+    /// `'static` obligation. Suggest relaxing that implicit bound.+    fn find_impl_on_dyn_trait(+        &self,+        err: &mut DiagnosticBuilder<'_>,+        ty: Ty<'_>,+        ctxt: &UnifyReceiverContext<'tcx>,+    ) -> bool {+        let tcx = self.tcx();+        let mut suggested = false;++        // Find the method being called.+        let instance = match ty::Instance::resolve(+            tcx,+            ctxt.param_env,+            ctxt.assoc_item.def_id,+            self.infcx.resolve_vars_if_possible(&ctxt.substs),+        ) {+            Ok(Some(instance)) => instance,+            _ => return false,+        };++        let mut v = TraitObjectVisitor(vec![]);+        v.visit_ty(ty);++        // Get the `Ident` of the method being called and the corresponding `impl` (to point at+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).+        let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) {+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {+                        (ident, self_ty)+                    }+                    _ => return false,+                }+            }+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {+                let parent_id = tcx.hir().get_parent_item(*hir_id);+                match tcx.hir().find(parent_id) {+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {+                        // The method being called is defined in the `trait`, but the `'static`

I just reused this method for the Trait::method(binding) case, but I'll look into modifying Instance::resolve regardless.

estebank

comment created time in 11 days

Pull request review commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

  use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError;-use rustc_errors::{struct_span_err, Applicability, ErrorReported};-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};-use rustc_middle::ty::RegionKind;+use crate::infer::{SubregionOrigin, TypeTrace};+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};+use rustc_hir::def_id::DefId;+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};+use rustc_hir::{+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,+    TyKind,+};+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};+use rustc_span::{MultiSpan, Span};  impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {-    /// Print the error message for lifetime errors when the return type is a static impl Trait.+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {         debug!("try_report_static_impl_trait(error={:?})", self.error);-        if let Some(RegionResolutionError::SubSupConflict(-            _,-            var_origin,-            ref sub_origin,-            sub_r,-            ref sup_origin,-            sup_r,-        )) = self.error-        {-            debug!(-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",-                var_origin, sub_origin, sub_r, sup_origin, sup_r-            );-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);-            if fn_returns.is_empty() {+        let tcx = self.tcx();+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {+            RegionResolutionError::SubSupConflict(+                _,+                var_origin,+                sub_origin,+                sub_r,+                sup_origin,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)+            }+            RegionResolutionError::ConcreteFailure(+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),+                sub_r,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                    let param = self.find_param_with_region(sup_r, sub_r)?;+                    let lifetime = if sup_r.has_name() {+                        format!("lifetime `{}`", sup_r)+                    } else {+                        "an anonymous lifetime `'_`".to_string()+                    };+                    let mut err = struct_span_err!(+                        tcx.sess,+                        cause.span,+                        E0767,+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param+                            .param+                            .pat+                            .simple_ident()+                            .map(|s| format!("`{}`", s))+                            .unwrap_or_else(|| "`fn` parameter".to_string()),+                        lifetime,+                        ctxt.assoc_item.ident,+                    );+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+                    err.span_label(+                        cause.span,+                        &format!(+                            "...is captured and required to live as long as `'static` here \+                             because of an implicit lifetime bound on the {}",+                            match ctxt.assoc_item.container {+                                AssocItemContainer::TraitContainer(id) =>+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),+                                AssocItemContainer::ImplContainer(_) =>+                                    "inherent `impl`".to_string(),+                            },+                        ),+                    );+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {+                        err.emit();+                        return Some(ErrorReported);+                    } else {+                        err.cancel();+                    }+                }                 return None;             }-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);-            if *sub_r == RegionKind::ReStatic {-                let sp = var_origin.span();-                let return_sp = sub_origin.span();-                let param_info = self.find_param_with_region(sup_r, sub_r)?;-                let (lifetime_name, lifetime) = if sup_r.has_name() {-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))-                } else {-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())-                };-                let mut err = struct_span_err!(-                    self.tcx().sess,-                    sp,-                    E0759,-                    "cannot infer an appropriate lifetime"-                );-                err.span_label(-                    param_info.param_ty_span,-                    &format!("this data with {}...", lifetime),-                );-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);+            _ => return None,+        };+        debug!(+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",+            var_origin, sub_origin, sub_r, sup_origin, sup_r+        );+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);+        let sp = var_origin.span();+        let return_sp = sub_origin.span();+        let param = self.find_param_with_region(sup_r, sub_r)?;+        let (lifetime_name, lifetime) = if sup_r.has_name() {+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))+        } else {+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())+        };+        let param_name = param+            .param+            .pat+            .simple_ident()+            .map(|s| format!("`{}`", s))+            .unwrap_or_else(|| "`fn` parameter".to_string());+        let mut err = struct_span_err!(+            tcx.sess,+            sp,+            E0759,+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",+            param_name,+            lifetime,+        );+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+        debug!("try_report_static_impl_trait: param_info={:?}", param);++        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); -                // We try to make the output have fewer overlapping spans if possible.-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))-                    && sup_origin.span() != return_sp+        let mut postfix = String::new();+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)+                    && fn_returns.is_empty()                 {-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`--                    // Customize the spans and labels depending on their relative order so-                    // that split sentences flow correctly.-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {-                        // Avoid the following:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                      ---------^--                        //-                        // and instead show:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                               ^-                        err.span_label(-                            sup_origin.span(),-                            "...is captured here, requiring it to live as long as `'static`",-                        );-                    } else {-                        err.span_label(sup_origin.span(), "...is captured here...");-                        if return_sp < sup_origin.span() {-                            err.span_note(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        } else {-                            err.span_label(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        }-                    }+                    err.code(rustc_errors::error_code!(E0767));+                    err.set_primary_message(&format!(+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param_name, lifetime, ctxt.assoc_item.ident,+                    ));+                    postfix = format!(+                        " because of an implicit lifetime on the {}",+                        match ctxt.assoc_item.container {+                            AssocItemContainer::TraitContainer(id) =>+                                format!("`impl` of `{}`", tcx.def_path_str(id)),+                            AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(),+                        },+                    );+                }+                // }+            }+        }++        // We try to make the output have fewer overlapping spans if possible.+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))+            && sup_origin.span() != return_sp+        {+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`++            // Customize the spans and labels depending on their relative order so+            // that split sentences flow correctly.+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {+                // Avoid the following:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                      ---------^-+                //+                // and instead show:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                               ^+                err.span_label(+                    sup_origin.span(),+                    &format!(+                        "...is captured here, requiring it to live as long as `'static`{}",+                        postfix+                    ),+                );+            } else {+                err.span_label(sup_origin.span(), "...is captured here...");+                if return_sp < sup_origin.span() {+                    err.span_note(+                        return_sp,+                        &format!("...and is required to live as long as `'static` here{}", postfix),+                    );                 } else {                     err.span_label(                         return_sp,-                        "...is captured and required to live as long as `'static` here",+                        &format!("...and is required to live as long as `'static` here{}", postfix),                     );                 }+            }+        } else {+            err.span_label(+                return_sp,+                &format!(+                    "...is captured and required to live as long as `'static` here{}",+                    postfix+                ),+            );+        } -                // FIXME: account for the need of parens in `&(dyn Trait + '_)`-                let consider = "consider changing the";-                let declare = "to declare that the";-                let arg = match param_info.param.pat.simple_ident() {-                    Some(simple_ident) => format!("argument `{}`", simple_ident),-                    None => "the argument".to_string(),-                };-                let explicit =-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);-                let explicit_static =-                    format!("explicit `'static` bound to the lifetime of {}", arg);-                let captures = format!("captures data from {}", arg);-                let add_static_bound =-                    "alternatively, add an explicit `'static` bound to this reference";-                let plus_lt = format!(" + {}", lifetime_name);-                for fn_return in fn_returns {-                    if fn_return.span.desugaring_kind().is_some() {-                        // Skip `async` desugaring `impl Future`.-                        continue;+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`+        let consider = "consider changing the";+        let declare = "to declare that the";+        let arg = match param.param.pat.simple_ident() {+            Some(simple_ident) => format!("argument `{}`", simple_ident),+            None => "the argument".to_string(),+        };+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);+        let captures = format!("captures data from {}", arg);+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";+        let plus_lt = format!(" + {}", lifetime_name);+        for fn_return in fn_returns {+            if fn_return.span.desugaring_kind().is_some() {+                // Skip `async` desugaring `impl Future`.+                continue;+            }+            match fn_return.kind {+                TyKind::OpaqueDef(item_id, _) => {+                    let item = tcx.hir().item(item_id.id);+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {+                        opaque+                    } else {+                        err.emit();+                        return Some(ErrorReported);+                    };++                    if let Some(span) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime {+                                name: LifetimeName::Static,+                                span,+                                ..+                            }) => Some(*span),+                            _ => None,+                        })+                        .next()+                    {+                        err.span_suggestion_verbose(+                            span,+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    } else if let Some(_) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime { name, span, .. })+                                if name.ident().to_string() == lifetime_name =>+                            {+                                Some(*span)+                            }+                            _ => None,+                        })+                        .next()+                    {+                    } else {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} `impl Trait` {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );                     }-                    match fn_return.kind {-                        TyKind::OpaqueDef(item_id, _) => {-                            let item = self.tcx().hir().item(item_id.id);-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {-                                opaque-                            } else {-                                err.emit();-                                return Some(ErrorReported);-                            };--                            if let Some(span) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime {-                                        name: LifetimeName::Static,-                                        span,+                }+                TyKind::TraitObject(_, lt) => match lt.name {+                    LifetimeName::ImplicitObjectLifetimeDefault => {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} trait object {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    name if name.ident().to_string() != lifetime_name => {+                        // With this check we avoid suggesting redundant bounds. This+                        // would happen if there are nested impl/dyn traits and only+                        // one of them has the bound we'd suggest already there, like+                        // in `impl Foo<X = dyn Bar> + '_`.+                        err.span_suggestion_verbose(+                            lt.span,+                            &format!("{} trait object's {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    _ => {}+                },+                _ => {}+            }+        }+        err.emit();+        Some(ErrorReported)+    }++    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default+    /// `'static` obligation. Suggest relaxing that implicit bound.+    fn find_impl_on_dyn_trait(+        &self,+        err: &mut DiagnosticBuilder<'_>,+        ty: Ty<'_>,+        ctxt: &UnifyReceiverContext<'tcx>,+    ) -> bool {+        let tcx = self.tcx();+        let mut suggested = false;++        // Find the method being called.+        let instance = match ty::Instance::resolve(+            tcx,+            ctxt.param_env,+            ctxt.assoc_item.def_id,+            self.infcx.resolve_vars_if_possible(&ctxt.substs),+        ) {+            Ok(Some(instance)) => instance,+            _ => return false,+        };++        let mut v = TraitObjectVisitor(vec![]);+        v.visit_ty(ty);++        // Get the `Ident` of the method being called and the corresponding `impl` (to point at+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).+        let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) {+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {+                        (ident, self_ty)+                    }+                    _ => return false,+                }+            }+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {+                let parent_id = tcx.hir().get_parent_item(*hir_id);+                match tcx.hir().find(parent_id) {+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {+                        // The method being called is defined in the `trait`, but the `'static`+                        // obligation comes from the `impl`. Find that `impl` so that we can point+                        // at it in the suggestion.+                        let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();+                        match tcx+                            .hir()+                            .trait_impls(trait_did)+                            .iter()+                            .filter_map(|impl_node| {+                                let impl_did = tcx.hir().local_def_id(*impl_node);+                                match tcx.hir().get_if_local(impl_did.to_def_id()) {+                                    Some(Node::Item(Item {+                                        kind: ItemKind::Impl { self_ty, .. },                                         ..-                                    }) => Some(*span),-                                    _ => None,-                                })-                                .next()-                            {-                                err.span_suggestion_verbose(-                                    span,-                                    &format!("{} `impl Trait`'s {}", consider, explicit_static),-                                    lifetime_name.clone(),-                                    Applicability::MaybeIncorrect,-                                );-                                err.span_suggestion_verbose(-                                    param_info.param_ty_span,-                                    add_static_bound,-                                    param_info.param_ty.to_string(),-                                    Applicability::MaybeIncorrect,-                                );-                            } else if let Some(_) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime { name, span, .. })-                                        if name.ident().to_string() == lifetime_name =>+                                    })) if v.0.iter().all(|did| {+                                        // FIXME: we should check `self_ty` against the receiver+                                        // type in the `UnifyReceiver` context, but for now, use+                                        // this imperfect proxy. This will fail if there are+                                        // multiple `impl`s for the same trait like+                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.+                                        // In that case, only the first one will get suggestions.+                                        let mut hir_v = HirTraitObjectVisitor(vec![], *did);+                                        hir_v.visit_ty(self_ty);+                                        !hir_v.0.is_empty()+                                    }) =>                                     {-                                        Some(*span)+                                        Some(self_ty)                                     }                                     _ => None,-                                })-                                .next()-                            {-                            } else {-                                err.span_suggestion_verbose(-                                    fn_return.span.shrink_to_hi(),-                                    &format!(-                                        "{declare} `impl Trait` {captures}, {explicit}",-                                        declare = declare,-                                        captures = captures,-                                        explicit = explicit,-                                    ),-                                    plus_lt.clone(),-                                    Applicability::MaybeIncorrect,-                                );-                            }+                                }+                            })+                            .next()+                        {+                            Some(self_ty) => (ident, self_ty),+                            _ => return false,                         }-                        TyKind::TraitObject(_, lt) => match lt.name {-                            LifetimeName::ImplicitObjectLifetimeDefault => {-                                err.span_suggestion_verbose(-                                    fn_return.span.shrink_to_hi(),-                                    &format!(-                                        "{declare} trait object {captures}, {explicit}",-                                        declare = declare,-                                        captures = captures,-                                        explicit = explicit,-                                    ),-                                    plus_lt.clone(),-                                    Applicability::MaybeIncorrect,-                                );-                            }-                            name if name.ident().to_string() != lifetime_name => {-                                // With this check we avoid suggesting redundant bounds. This-                                // would happen if there are nested impl/dyn traits and only-                                // one of them has the bound we'd suggest already there, like-                                // in `impl Foo<X = dyn Bar> + '_`.-                                err.span_suggestion_verbose(-                                    lt.span,-                                    &format!("{} trait object's {}", consider, explicit_static),-                                    lifetime_name.clone(),-                                    Applicability::MaybeIncorrect,-                                );-                                err.span_suggestion_verbose(-                                    param_info.param_ty_span,-                                    add_static_bound,-                                    param_info.param_ty.to_string(),-                                    Applicability::MaybeIncorrect,-                                );-                            }-                            _ => {}+                    }+                    _ => return false,+                }+            }+            _ => return false,+        };++        // Find the trait object types in the argument, so we point at *only* the trait object.+        for found_did in &v.0 {

Done.

estebank

comment created time in 11 days

Pull request review commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

  use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError;-use rustc_errors::{struct_span_err, Applicability, ErrorReported};-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};-use rustc_middle::ty::RegionKind;+use crate::infer::{SubregionOrigin, TypeTrace};+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};+use rustc_hir::def_id::DefId;+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};+use rustc_hir::{+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,+    TyKind,+};+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};+use rustc_span::{MultiSpan, Span};  impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {-    /// Print the error message for lifetime errors when the return type is a static impl Trait.+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {         debug!("try_report_static_impl_trait(error={:?})", self.error);-        if let Some(RegionResolutionError::SubSupConflict(-            _,-            var_origin,-            ref sub_origin,-            sub_r,-            ref sup_origin,-            sup_r,-        )) = self.error-        {-            debug!(-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",-                var_origin, sub_origin, sub_r, sup_origin, sup_r-            );-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);-            if fn_returns.is_empty() {+        let tcx = self.tcx();+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {+            RegionResolutionError::SubSupConflict(+                _,+                var_origin,+                sub_origin,+                sub_r,+                sup_origin,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)+            }+            RegionResolutionError::ConcreteFailure(+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),+                sub_r,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                    let param = self.find_param_with_region(sup_r, sub_r)?;+                    let lifetime = if sup_r.has_name() {+                        format!("lifetime `{}`", sup_r)+                    } else {+                        "an anonymous lifetime `'_`".to_string()+                    };+                    let mut err = struct_span_err!(+                        tcx.sess,+                        cause.span,+                        E0767,+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param+                            .param+                            .pat+                            .simple_ident()+                            .map(|s| format!("`{}`", s))+                            .unwrap_or_else(|| "`fn` parameter".to_string()),+                        lifetime,+                        ctxt.assoc_item.ident,+                    );+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+                    err.span_label(+                        cause.span,+                        &format!(+                            "...is captured and required to live as long as `'static` here \+                             because of an implicit lifetime bound on the {}",+                            match ctxt.assoc_item.container {+                                AssocItemContainer::TraitContainer(id) =>+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),+                                AssocItemContainer::ImplContainer(_) =>+                                    "inherent `impl`".to_string(),+                            },+                        ),+                    );+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {+                        err.emit();+                        return Some(ErrorReported);+                    } else {+                        err.cancel();+                    }+                }                 return None;             }-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);-            if *sub_r == RegionKind::ReStatic {-                let sp = var_origin.span();-                let return_sp = sub_origin.span();-                let param_info = self.find_param_with_region(sup_r, sub_r)?;-                let (lifetime_name, lifetime) = if sup_r.has_name() {-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))-                } else {-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())-                };-                let mut err = struct_span_err!(-                    self.tcx().sess,-                    sp,-                    E0759,-                    "cannot infer an appropriate lifetime"-                );-                err.span_label(-                    param_info.param_ty_span,-                    &format!("this data with {}...", lifetime),-                );-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);+            _ => return None,+        };+        debug!(+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",+            var_origin, sub_origin, sub_r, sup_origin, sup_r+        );+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);+        let sp = var_origin.span();+        let return_sp = sub_origin.span();+        let param = self.find_param_with_region(sup_r, sub_r)?;+        let (lifetime_name, lifetime) = if sup_r.has_name() {+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))+        } else {+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())+        };+        let param_name = param+            .param+            .pat+            .simple_ident()+            .map(|s| format!("`{}`", s))+            .unwrap_or_else(|| "`fn` parameter".to_string());+        let mut err = struct_span_err!(+            tcx.sess,+            sp,+            E0759,+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",+            param_name,+            lifetime,+        );+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+        debug!("try_report_static_impl_trait: param_info={:?}", param);++        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); -                // We try to make the output have fewer overlapping spans if possible.-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))-                    && sup_origin.span() != return_sp+        let mut postfix = String::new();+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)+                    && fn_returns.is_empty()                 {-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`--                    // Customize the spans and labels depending on their relative order so-                    // that split sentences flow correctly.-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {-                        // Avoid the following:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                      ---------^--                        //-                        // and instead show:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                               ^-                        err.span_label(-                            sup_origin.span(),-                            "...is captured here, requiring it to live as long as `'static`",-                        );-                    } else {-                        err.span_label(sup_origin.span(), "...is captured here...");-                        if return_sp < sup_origin.span() {-                            err.span_note(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        } else {-                            err.span_label(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        }-                    }+                    err.code(rustc_errors::error_code!(E0767));+                    err.set_primary_message(&format!(+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param_name, lifetime, ctxt.assoc_item.ident,+                    ));+                    postfix = format!(+                        " because of an implicit lifetime on the {}",+                        match ctxt.assoc_item.container {+                            AssocItemContainer::TraitContainer(id) =>+                                format!("`impl` of `{}`", tcx.def_path_str(id)),+                            AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(),+                        },+                    );+                }+                // }+            }+        }++        // We try to make the output have fewer overlapping spans if possible.+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))+            && sup_origin.span() != return_sp+        {+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`++            // Customize the spans and labels depending on their relative order so+            // that split sentences flow correctly.+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {+                // Avoid the following:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                      ---------^-+                //+                // and instead show:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                               ^+                err.span_label(+                    sup_origin.span(),+                    &format!(+                        "...is captured here, requiring it to live as long as `'static`{}",+                        postfix+                    ),+                );+            } else {+                err.span_label(sup_origin.span(), "...is captured here...");+                if return_sp < sup_origin.span() {+                    err.span_note(+                        return_sp,+                        &format!("...and is required to live as long as `'static` here{}", postfix),+                    );                 } else {                     err.span_label(                         return_sp,-                        "...is captured and required to live as long as `'static` here",+                        &format!("...and is required to live as long as `'static` here{}", postfix),                     );                 }+            }+        } else {+            err.span_label(+                return_sp,+                &format!(+                    "...is captured and required to live as long as `'static` here{}",+                    postfix+                ),+            );+        } -                // FIXME: account for the need of parens in `&(dyn Trait + '_)`-                let consider = "consider changing the";-                let declare = "to declare that the";-                let arg = match param_info.param.pat.simple_ident() {-                    Some(simple_ident) => format!("argument `{}`", simple_ident),-                    None => "the argument".to_string(),-                };-                let explicit =-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);-                let explicit_static =-                    format!("explicit `'static` bound to the lifetime of {}", arg);-                let captures = format!("captures data from {}", arg);-                let add_static_bound =-                    "alternatively, add an explicit `'static` bound to this reference";-                let plus_lt = format!(" + {}", lifetime_name);-                for fn_return in fn_returns {-                    if fn_return.span.desugaring_kind().is_some() {-                        // Skip `async` desugaring `impl Future`.-                        continue;+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`+        let consider = "consider changing the";+        let declare = "to declare that the";+        let arg = match param.param.pat.simple_ident() {+            Some(simple_ident) => format!("argument `{}`", simple_ident),+            None => "the argument".to_string(),+        };+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);+        let captures = format!("captures data from {}", arg);+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";+        let plus_lt = format!(" + {}", lifetime_name);+        for fn_return in fn_returns {+            if fn_return.span.desugaring_kind().is_some() {+                // Skip `async` desugaring `impl Future`.+                continue;+            }+            match fn_return.kind {+                TyKind::OpaqueDef(item_id, _) => {+                    let item = tcx.hir().item(item_id.id);+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {+                        opaque+                    } else {+                        err.emit();+                        return Some(ErrorReported);+                    };++                    if let Some(span) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime {+                                name: LifetimeName::Static,+                                span,+                                ..+                            }) => Some(*span),+                            _ => None,+                        })+                        .next()+                    {+                        err.span_suggestion_verbose(+                            span,+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    } else if let Some(_) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime { name, span, .. })+                                if name.ident().to_string() == lifetime_name =>+                            {+                                Some(*span)+                            }+                            _ => None,+                        })+                        .next()+                    {+                    } else {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} `impl Trait` {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );                     }-                    match fn_return.kind {-                        TyKind::OpaqueDef(item_id, _) => {-                            let item = self.tcx().hir().item(item_id.id);-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {-                                opaque-                            } else {-                                err.emit();-                                return Some(ErrorReported);-                            };--                            if let Some(span) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime {-                                        name: LifetimeName::Static,-                                        span,+                }+                TyKind::TraitObject(_, lt) => match lt.name {+                    LifetimeName::ImplicitObjectLifetimeDefault => {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} trait object {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    name if name.ident().to_string() != lifetime_name => {+                        // With this check we avoid suggesting redundant bounds. This+                        // would happen if there are nested impl/dyn traits and only+                        // one of them has the bound we'd suggest already there, like+                        // in `impl Foo<X = dyn Bar> + '_`.+                        err.span_suggestion_verbose(+                            lt.span,+                            &format!("{} trait object's {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    _ => {}+                },+                _ => {}+            }+        }+        err.emit();+        Some(ErrorReported)+    }++    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default+    /// `'static` obligation. Suggest relaxing that implicit bound.+    fn find_impl_on_dyn_trait(+        &self,+        err: &mut DiagnosticBuilder<'_>,+        ty: Ty<'_>,+        ctxt: &UnifyReceiverContext<'tcx>,+    ) -> bool {+        let tcx = self.tcx();+        let mut suggested = false;++        // Find the method being called.+        let instance = match ty::Instance::resolve(+            tcx,+            ctxt.param_env,+            ctxt.assoc_item.def_id,+            self.infcx.resolve_vars_if_possible(&ctxt.substs),+        ) {+            Ok(Some(instance)) => instance,+            _ => return false,+        };++        let mut v = TraitObjectVisitor(vec![]);+        v.visit_ty(ty);++        // Get the `Ident` of the method being called and the corresponding `impl` (to point at+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).+        let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) {+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {+                        (ident, self_ty)+                    }+                    _ => return false,+                }+            }+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {+                let parent_id = tcx.hir().get_parent_item(*hir_id);+                match tcx.hir().find(parent_id) {+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {+                        // The method being called is defined in the `trait`, but the `'static`+                        // obligation comes from the `impl`. Find that `impl` so that we can point+                        // at it in the suggestion.+                        let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();+                        match tcx+                            .hir()+                            .trait_impls(trait_did)+                            .iter()+                            .filter_map(|impl_node| {+                                let impl_did = tcx.hir().local_def_id(*impl_node);+                                match tcx.hir().get_if_local(impl_did.to_def_id()) {+                                    Some(Node::Item(Item {+                                        kind: ItemKind::Impl { self_ty, .. },                                         ..-                                    }) => Some(*span),-                                    _ => None,-                                })-                                .next()-                            {-                                err.span_suggestion_verbose(-                                    span,-                                    &format!("{} `impl Trait`'s {}", consider, explicit_static),-                                    lifetime_name.clone(),-                                    Applicability::MaybeIncorrect,-                                );-                                err.span_suggestion_verbose(-                                    param_info.param_ty_span,-                                    add_static_bound,-                                    param_info.param_ty.to_string(),-                                    Applicability::MaybeIncorrect,-                                );-                            } else if let Some(_) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime { name, span, .. })-                                        if name.ident().to_string() == lifetime_name =>+                                    })) if v.0.iter().all(|did| {+                                        // FIXME: we should check `self_ty` against the receiver

Done and now I handle the case above as well.

estebank

comment created time in 11 days

Pull request review commentrust-lang/rust

Detect when `'static` obligation might come from an `impl`

  use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError;-use rustc_errors::{struct_span_err, Applicability, ErrorReported};-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};-use rustc_middle::ty::RegionKind;+use crate::infer::{SubregionOrigin, TypeTrace};+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};+use rustc_hir::def_id::DefId;+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};+use rustc_hir::{+    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,+    TyKind,+};+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};+use rustc_span::{MultiSpan, Span};  impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {-    /// Print the error message for lifetime errors when the return type is a static impl Trait.+    /// Print the error message for lifetime errors when the return type is a static `impl Trait`,+    /// `dyn Trait` or if a method call on a trait object introduces a static requirement.     pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {         debug!("try_report_static_impl_trait(error={:?})", self.error);-        if let Some(RegionResolutionError::SubSupConflict(-            _,-            var_origin,-            ref sub_origin,-            sub_r,-            ref sup_origin,-            sup_r,-        )) = self.error-        {-            debug!(-                "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",-                var_origin, sub_origin, sub_r, sup_origin, sup_r-            );-            let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;-            debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);-            let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);-            if fn_returns.is_empty() {+        let tcx = self.tcx();+        let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {+            RegionResolutionError::SubSupConflict(+                _,+                var_origin,+                sub_origin,+                sub_r,+                sup_origin,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                (var_origin, sub_origin, sub_r, sup_origin, sup_r)+            }+            RegionResolutionError::ConcreteFailure(+                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),+                sub_r,+                sup_r,+            ) if **sub_r == RegionKind::ReStatic => {+                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.+                if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                    let param = self.find_param_with_region(sup_r, sub_r)?;+                    let lifetime = if sup_r.has_name() {+                        format!("lifetime `{}`", sup_r)+                    } else {+                        "an anonymous lifetime `'_`".to_string()+                    };+                    let mut err = struct_span_err!(+                        tcx.sess,+                        cause.span,+                        E0767,+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param+                            .param+                            .pat+                            .simple_ident()+                            .map(|s| format!("`{}`", s))+                            .unwrap_or_else(|| "`fn` parameter".to_string()),+                        lifetime,+                        ctxt.assoc_item.ident,+                    );+                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+                    err.span_label(+                        cause.span,+                        &format!(+                            "...is captured and required to live as long as `'static` here \+                             because of an implicit lifetime bound on the {}",+                            match ctxt.assoc_item.container {+                                AssocItemContainer::TraitContainer(id) =>+                                    format!("`impl` of `{}`", tcx.def_path_str(id)),+                                AssocItemContainer::ImplContainer(_) =>+                                    "inherent `impl`".to_string(),+                            },+                        ),+                    );+                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {+                        err.emit();+                        return Some(ErrorReported);+                    } else {+                        err.cancel();+                    }+                }                 return None;             }-            debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);-            if *sub_r == RegionKind::ReStatic {-                let sp = var_origin.span();-                let return_sp = sub_origin.span();-                let param_info = self.find_param_with_region(sup_r, sub_r)?;-                let (lifetime_name, lifetime) = if sup_r.has_name() {-                    (sup_r.to_string(), format!("lifetime `{}`", sup_r))-                } else {-                    ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())-                };-                let mut err = struct_span_err!(-                    self.tcx().sess,-                    sp,-                    E0759,-                    "cannot infer an appropriate lifetime"-                );-                err.span_label(-                    param_info.param_ty_span,-                    &format!("this data with {}...", lifetime),-                );-                debug!("try_report_static_impl_trait: param_info={:?}", param_info);+            _ => return None,+        };+        debug!(+            "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",+            var_origin, sub_origin, sub_r, sup_origin, sup_r+        );+        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;+        debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);+        let sp = var_origin.span();+        let return_sp = sub_origin.span();+        let param = self.find_param_with_region(sup_r, sub_r)?;+        let (lifetime_name, lifetime) = if sup_r.has_name() {+            (sup_r.to_string(), format!("lifetime `{}`", sup_r))+        } else {+            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())+        };+        let param_name = param+            .param+            .pat+            .simple_ident()+            .map(|s| format!("`{}`", s))+            .unwrap_or_else(|| "`fn` parameter".to_string());+        let mut err = struct_span_err!(+            tcx.sess,+            sp,+            E0759,+            "{} has {} but it needs to satisfy a `'static` lifetime requirement",+            param_name,+            lifetime,+        );+        err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));+        debug!("try_report_static_impl_trait: param_info={:?}", param);++        let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); -                // We try to make the output have fewer overlapping spans if possible.-                if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))-                    && sup_origin.span() != return_sp+        let mut postfix = String::new();+        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {+            if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {+                if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt)+                    && fn_returns.is_empty()                 {-                    // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`--                    // Customize the spans and labels depending on their relative order so-                    // that split sentences flow correctly.-                    if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {-                        // Avoid the following:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                      ---------^--                        //-                        // and instead show:-                        //-                        // error: cannot infer an appropriate lifetime-                        //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50-                        //    |-                        // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }-                        //    |           ----                               ^-                        err.span_label(-                            sup_origin.span(),-                            "...is captured here, requiring it to live as long as `'static`",-                        );-                    } else {-                        err.span_label(sup_origin.span(), "...is captured here...");-                        if return_sp < sup_origin.span() {-                            err.span_note(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        } else {-                            err.span_label(-                                return_sp,-                                "...and is required to live as long as `'static` here",-                            );-                        }-                    }+                    err.code(rustc_errors::error_code!(E0767));+                    err.set_primary_message(&format!(+                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \+                         requirement",+                        param_name, lifetime, ctxt.assoc_item.ident,+                    ));+                    postfix = format!(+                        " because of an implicit lifetime on the {}",+                        match ctxt.assoc_item.container {+                            AssocItemContainer::TraitContainer(id) =>+                                format!("`impl` of `{}`", tcx.def_path_str(id)),+                            AssocItemContainer::ImplContainer(_) => "inherent `impl`".to_string(),+                        },+                    );+                }+                // }+            }+        }++        // We try to make the output have fewer overlapping spans if possible.+        if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))+            && sup_origin.span() != return_sp+        {+            // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`++            // Customize the spans and labels depending on their relative order so+            // that split sentences flow correctly.+            if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {+                // Avoid the following:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                      ---------^-+                //+                // and instead show:+                //+                // error: cannot infer an appropriate lifetime+                //   --> $DIR/must_outlive_least_region_or_bound.rs:18:50+                //    |+                // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }+                //    |           ----                               ^+                err.span_label(+                    sup_origin.span(),+                    &format!(+                        "...is captured here, requiring it to live as long as `'static`{}",+                        postfix+                    ),+                );+            } else {+                err.span_label(sup_origin.span(), "...is captured here...");+                if return_sp < sup_origin.span() {+                    err.span_note(+                        return_sp,+                        &format!("...and is required to live as long as `'static` here{}", postfix),+                    );                 } else {                     err.span_label(                         return_sp,-                        "...is captured and required to live as long as `'static` here",+                        &format!("...and is required to live as long as `'static` here{}", postfix),                     );                 }+            }+        } else {+            err.span_label(+                return_sp,+                &format!(+                    "...is captured and required to live as long as `'static` here{}",+                    postfix+                ),+            );+        } -                // FIXME: account for the need of parens in `&(dyn Trait + '_)`-                let consider = "consider changing the";-                let declare = "to declare that the";-                let arg = match param_info.param.pat.simple_ident() {-                    Some(simple_ident) => format!("argument `{}`", simple_ident),-                    None => "the argument".to_string(),-                };-                let explicit =-                    format!("you can add an explicit `{}` lifetime bound", lifetime_name);-                let explicit_static =-                    format!("explicit `'static` bound to the lifetime of {}", arg);-                let captures = format!("captures data from {}", arg);-                let add_static_bound =-                    "alternatively, add an explicit `'static` bound to this reference";-                let plus_lt = format!(" + {}", lifetime_name);-                for fn_return in fn_returns {-                    if fn_return.span.desugaring_kind().is_some() {-                        // Skip `async` desugaring `impl Future`.-                        continue;+        debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);+        // FIXME: account for the need of parens in `&(dyn Trait + '_)`+        let consider = "consider changing the";+        let declare = "to declare that the";+        let arg = match param.param.pat.simple_ident() {+            Some(simple_ident) => format!("argument `{}`", simple_ident),+            None => "the argument".to_string(),+        };+        let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);+        let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);+        let captures = format!("captures data from {}", arg);+        let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";+        let plus_lt = format!(" + {}", lifetime_name);+        for fn_return in fn_returns {+            if fn_return.span.desugaring_kind().is_some() {+                // Skip `async` desugaring `impl Future`.+                continue;+            }+            match fn_return.kind {+                TyKind::OpaqueDef(item_id, _) => {+                    let item = tcx.hir().item(item_id.id);+                    let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {+                        opaque+                    } else {+                        err.emit();+                        return Some(ErrorReported);+                    };++                    if let Some(span) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime {+                                name: LifetimeName::Static,+                                span,+                                ..+                            }) => Some(*span),+                            _ => None,+                        })+                        .next()+                    {+                        err.span_suggestion_verbose(+                            span,+                            &format!("{} `impl Trait`'s {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    } else if let Some(_) = opaque+                        .bounds+                        .iter()+                        .filter_map(|arg| match arg {+                            GenericBound::Outlives(Lifetime { name, span, .. })+                                if name.ident().to_string() == lifetime_name =>+                            {+                                Some(*span)+                            }+                            _ => None,+                        })+                        .next()+                    {+                    } else {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} `impl Trait` {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );                     }-                    match fn_return.kind {-                        TyKind::OpaqueDef(item_id, _) => {-                            let item = self.tcx().hir().item(item_id.id);-                            let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {-                                opaque-                            } else {-                                err.emit();-                                return Some(ErrorReported);-                            };--                            if let Some(span) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime {-                                        name: LifetimeName::Static,-                                        span,+                }+                TyKind::TraitObject(_, lt) => match lt.name {+                    LifetimeName::ImplicitObjectLifetimeDefault => {+                        err.span_suggestion_verbose(+                            fn_return.span.shrink_to_hi(),+                            &format!(+                                "{declare} trait object {captures}, {explicit}",+                                declare = declare,+                                captures = captures,+                                explicit = explicit,+                            ),+                            plus_lt.clone(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    name if name.ident().to_string() != lifetime_name => {+                        // With this check we avoid suggesting redundant bounds. This+                        // would happen if there are nested impl/dyn traits and only+                        // one of them has the bound we'd suggest already there, like+                        // in `impl Foo<X = dyn Bar> + '_`.+                        err.span_suggestion_verbose(+                            lt.span,+                            &format!("{} trait object's {}", consider, explicit_static),+                            lifetime_name.clone(),+                            Applicability::MaybeIncorrect,+                        );+                        err.span_suggestion_verbose(+                            param.param_ty_span,+                            add_static_bound,+                            param.param_ty.to_string(),+                            Applicability::MaybeIncorrect,+                        );+                    }+                    _ => {}+                },+                _ => {}+            }+        }+        err.emit();+        Some(ErrorReported)+    }++    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default+    /// `'static` obligation. Suggest relaxing that implicit bound.+    fn find_impl_on_dyn_trait(+        &self,+        err: &mut DiagnosticBuilder<'_>,+        ty: Ty<'_>,+        ctxt: &UnifyReceiverContext<'tcx>,+    ) -> bool {+        let tcx = self.tcx();+        let mut suggested = false;++        // Find the method being called.+        let instance = match ty::Instance::resolve(+            tcx,+            ctxt.param_env,+            ctxt.assoc_item.def_id,+            self.infcx.resolve_vars_if_possible(&ctxt.substs),+        ) {+            Ok(Some(instance)) => instance,+            _ => return false,+        };++        let mut v = TraitObjectVisitor(vec![]);+        v.visit_ty(ty);++        // Get the `Ident` of the method being called and the corresponding `impl` (to point at+        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).+        let (ident, self_ty) = match tcx.hir().get_if_local(instance.def_id()) {+            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {+                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {+                    Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {+                        (ident, self_ty)+                    }+                    _ => return false,+                }+            }+            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {+                let parent_id = tcx.hir().get_parent_item(*hir_id);+                match tcx.hir().find(parent_id) {+                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {+                        // The method being called is defined in the `trait`, but the `'static`+                        // obligation comes from the `impl`. Find that `impl` so that we can point+                        // at it in the suggestion.+                        let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();+                        match tcx+                            .hir()+                            .trait_impls(trait_did)+                            .iter()+                            .filter_map(|impl_node| {+                                let impl_did = tcx.hir().local_def_id(*impl_node);+                                match tcx.hir().get_if_local(impl_did.to_def_id()) {+                                    Some(Node::Item(Item {+                                        kind: ItemKind::Impl { self_ty, .. },                                         ..-                                    }) => Some(*span),-                                    _ => None,-                                })-                                .next()-                            {-                                err.span_suggestion_verbose(-                                    span,-                                    &format!("{} `impl Trait`'s {}", consider, explicit_static),-                                    lifetime_name.clone(),-                                    Applicability::MaybeIncorrect,-                                );-                                err.span_suggestion_verbose(-                                    param_info.param_ty_span,-                                    add_static_bound,-                                    param_info.param_ty.to_string(),-                                    Applicability::MaybeIncorrect,-                                );-                            } else if let Some(_) = opaque-                                .bounds-                                .iter()-                                .filter_map(|arg| match arg {-                                    GenericBound::Outlives(Lifetime { name, span, .. })-                                        if name.ident().to_string() == lifetime_name =>+                                    })) if v.0.iter().all(|did| {+                                        // FIXME: we should check `self_ty` against the receiver

Adding a test for this, but it also made me notice that we're ignoring fully qualified paths:

Screen Shot 2020-07-01 at 11 39 40 AM

estebank

comment created time in 11 days

Pull request review commentrust-lang/rust

expand: Stop using nonterminals for passing tokens to attribute and derive macros

 impl Nonterminal {             NtTT(tt) => tt.span(),         }     }++    /// This nonterminal looks like some specific enums from+    /// `proc-macro-hack` and `procedural-masquerade` crates.+    /// We need to maintain some special pretty-printing behavior for them due to incorrect+    /// asserts in old versions of those crates and their wide use in the ecosystem.+    /// See issue #73345 for more details.+    /// FIXME: Remove this eventually.+    pub fn tokenization_compatibility_hack(&self) -> bool {+        if let NtItem(item) = self {+            let name = item.ident.name;+            if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack {

Can we add an allow by default lint here? That way we can make it warn by default in 6 months acting as a nudge so that we can outright remove this code in a year.

petrochenkov

comment created time in 11 days

issue commentrust-lang/rust

Add a macro to track a file

Isn't this already supported using build.rs?

GuillaumeGomez

comment created time in 11 days

issue openedrust-lang/rust

Suggest named lifetime on methods like we do for functions

The following fn foo provides a structured suggestion to add a new named lifetime:

fn foo(x: &i32, y: &i32) -> Option<&i32> {
    Some(y)
}
error[E0106]: missing lifetime specifier
 --> src/lib.rs:1:36
  |
1 | fn foo(x: &i32, y: &i32) -> Option<&i32> {
  |           ----     ----            ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
  |
1 | fn foo<'a>(x: &'a i32, y: &'a i32) -> Option<&'a i32> {
  |       ^^^^    ^^^^^^^     ^^^^^^^            ^^^

But similar code in a trait, doesn't:

trait T {
    fn foo(&self, x: &i32, y: &i32) -> Option<&i32> {
        Some(y)
    }
}
error[E0623]: lifetime mismatch
 --> src/lib.rs:3:9
  |
2 |     fn foo(&self, x: &i32, y: &i32) -> Option<&i32> {
  |                               ----     ------------
  |                               |
  |                               this parameter and the return type are declared with different lifetimes...
3 |         Some(y)
  |         ^^^^^^^ ...but data from `y` is returned here

The method add_missing_lifetime_specifiers_label is the one responsible for the former suggestion and can probably be easily reused where the method lifetime issue is emitted.

created time in 11 days

IssuesEvent
more