Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show the used type variable when issuing a "can't use type parameters from outer function" error message #47574

Merged
merged 4 commits into from
Mar 10, 2018

Conversation

zilbuz
Copy link
Contributor

@zilbuz zilbuz commented Jan 19, 2018

Fix #14844

r? @estebank

@zilbuz
Copy link
Contributor Author

zilbuz commented Jan 19, 2018

@estebank I've got a compile error with my current edits that I don't understand:

error[E0119]: conflicting implementations of trait `iter_private::TrustedRandomAccess` for type `iter::Cloned<_>`:
   --> libcore\iter\mod.rs:593:1
    |
581 | / default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
582 | |     where I: TrustedRandomAccess<Item=&'a T>, T: Clone
583 | | {
584 | |     unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
...   |
589 | |     fn may_have_side_effect() -> bool { true }
590 | | }
    | |_- first implementation here
...
593 | / unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
594 | |     where I: TrustedRandomAccess<Item=&'a T>, T: Copy
595 | | {
596 | |     unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
...   |
601 | |     fn may_have_side_effect() -> bool { false }
602 | | }
    | |_^ conflicting implementation for `iter::Cloned<_>`

error: aborting due to previous error

error: Could not compile `core`.

Do you have an idea of where that could come from? How could I gather more informations to debug this kind of error, because the error seems very far from the edits that I did?

@zilbuz
Copy link
Contributor Author

zilbuz commented Jan 19, 2018

Alright some more details: the compilation seems to fail when I copy the span argument of the ParamTy::new() function to the structure.

With:

#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct ParamTy {
    pub idx: u32,
    pub name: Name,
    pub span: Span,
}

This works:

    pub fn new(index: u32, name: Name, _span: Span) -> ParamTy {
        ParamTy { idx: index, name: name, span: DUMMY_SP }
    }

This doesn't (compilation error: #47574 (comment)):

    pub fn new(index: u32, name: Name, span: Span) -> ParamTy {
        ParamTy { idx: index, name: name, span: span }
    }

@estebank
Copy link
Contributor

You're indeed right that it doesn't seem to be caused by your code, but somehow triggered by the change. It is indeed quite weird.

The code you've written looks correct to me. Can you provide the full compiler output? I'm intrigued as to what stage this is happening in.

@zilbuz
Copy link
Contributor Author

zilbuz commented Jan 19, 2018

It's failing when compiling stage 1 std artifacts.

Build log:

Updating submodules
    Finished dev [unoptimized] target(s) in 0.0 secs
Building stage0 std artifacts (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc)
    Finished release [optimized] target(s) in 0.0 secs
Copying stage0 std from stage0 (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc / x86_64-pc-windows-msvc)
Building stage0 test artifacts (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc)
    Finished release [optimized] target(s) in 0.0 secs
Copying stage0 test from stage0 (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc / x86_64-pc-windows-msvc)
Building stage0 compiler artifacts (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc)
   Compiling rustc v0.0.0 (file:///C:/rust/src/librustc)
   Compiling rustc_incremental v0.0.0 (file:///C:/rust/src/librustc_incremental)
   Compiling rustc_typeck v0.0.0 (file:///C:/rust/src/librustc_typeck)
   Compiling rustc_metadata v0.0.0 (file:///C:/rust/src/librustc_metadata)
   Compiling rustc_allocator v0.0.0 (file:///C:/rust/src/librustc_allocator)
   Compiling rustc_trans_utils v0.0.0 (file:///C:/rust/src/librustc_trans_utils)
   Compiling rustc_resolve v0.0.0 (file:///C:/rust/src/librustc_resolve)
   Compiling rustc_const_eval v0.0.0 (file:///C:/rust/src/librustc_const_eval)
   Compiling rustc_plugin v0.0.0 (file:///C:/rust/src/librustc_plugin)
   Compiling rustc_passes v0.0.0 (file:///C:/rust/src/librustc_passes)
   Compiling rustc_lint v0.0.0 (file:///C:/rust/src/librustc_lint)
   Compiling rustc_mir v0.0.0 (file:///C:/rust/src/librustc_mir)
   Compiling rustc_privacy v0.0.0 (file:///C:/rust/src/librustc_privacy)
   Compiling rustc_save_analysis v0.0.0 (file:///C:/rust/src/librustc_save_analysis)
   Compiling rustc_trans v0.0.0 (file:///C:/rust/src/librustc_trans)
   Compiling rustc_borrowck v0.0.0 (file:///C:/rust/src/librustc_borrowck)
   Compiling rustc_driver v0.0.0 (file:///C:/rust/src/librustc_driver)
   Compiling rustc-main v0.0.0 (file:///C:/rust/src/rustc)
    Finished release [optimized] target(s) in 207.72 secs
Copying stage0 rustc from stage0 (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc / x86_64-pc-windows-msvc)
Assembling stage1 compiler (x86_64-pc-windows-msvc)
Building stage1 std artifacts (x86_64-pc-windows-msvc -> x86_64-pc-windows-msvc)
   Compiling cc v1.0.4
   Compiling core v0.0.0 (file:///C:/rust/src/libcore)
   Compiling unwind v0.0.0 (file:///C:/rust/src/libunwind)
   Compiling cfg-if v0.1.2
   Compiling filetime v0.1.15
   Compiling build_helper v0.1.0 (file:///C:/rust/src/build_helper)
   Compiling std v0.0.0 (file:///C:/rust/src/libstd)
   Compiling compiler_builtins v0.0.0 (file:///C:/rust/src/rustc/compiler_builtins_shim)
error[E0119]: conflicting implementations of trait `iter_private::TrustedRandomAccess` for type `iter::Cloned<_>`:
   --> libcore\iter\mod.rs:593:1
    |
581 | / default unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
582 | |     where I: TrustedRandomAccess<Item=&'a T>, T: Clone
583 | | {
584 | |     unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
...   |
589 | |     fn may_have_side_effect() -> bool { true }
590 | | }
    | |_- first implementation here
...
593 | / unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned<I>
594 | |     where I: TrustedRandomAccess<Item=&'a T>, T: Copy
595 | | {
596 | |     unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
...   |
601 | |     fn may_have_side_effect() -> bool { false }
602 | | }
    | |_^ conflicting implementation for `iter::Cloned<_>`

error: aborting due to previous error

error: Could not compile `core`.

Caused by:
  process didn't exit successfully: `C:\rust\build\bootstrap/debug/rustc --crate-name core libcore\lib.rs --error-format json --crate-type lib --emit=dep-info,link -C opt-level=2 -C metadata=10ce4b4b7843f587 -C extra-filename=-10ce4b4b7843f587 --out-dir C:\rust\build\x86_64-pc-windows-msvc\stage1-std\x86_64-pc-windows-msvc\release\deps --target x86_64-pc-windows-msvc -L dependency=C:\rust\build\x86_64-pc-windows-msvc\stage1-std\x86_64-pc-windows-msvc\release\deps -L dependency=C:\rust\build\x86_64-pc-windows-msvc\stage1-std\release\deps` (exit code: 101)
thread 'main' panicked at 'command did not execute successfully: "C:\\rust\\build\\x86_64-pc-windows-msvc\\stage0/bin\\cargo.exe" "build" "--target" "x86_64-pc-windows-msvc" "-j" "4" "--release" "--features" "panic-unwind backtrace" "--manifest-path" "C:\\rust\\src/libstd/Cargo.toml" "--message-format" "json"
expected success, got: exit code: 101', bootstrap\compile.rs:881:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
failed to run: C:\rust\build\bootstrap\debug\bootstrap build src/libstd --stage 1 --incremental
Build completed unsuccessfully in 0:05:00

@estebank
Copy link
Contributor

Thinking about this a bit more, it makes sense that this was introduced by your change. I have to dig a bit deeper to check where, but I'm guessing there's some equality check or similar code somewhere in librustc/traits/specialize that fails (or incorrectly succeeds) due to the span field.

@shepmaster shepmaster added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 20, 2018
@kennytm
Copy link
Member

kennytm commented Jan 24, 2018

Review ping for you @estebank! Have you checked why the Span field caused the conflicting impl error?

resolve_error(self, span,
ResolutionError::TypeParametersFromOuterFunction);
ResolutionError::TypeParametersFromOuterFunction(&span));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, this line is >100 chars, failing the CI.

[00:06:14] tidy error: /checkout/src/librustc_resolve/lib.rs:3200: line longer than 100 chars
[00:06:16] some tidy checks failed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I'll update that before finalizing the PR :) (and run tidy again to check for other errors)

@zilbuz zilbuz changed the title Show the used type variable when issuing a "can't use type parameters from outer function" error message [WIP] Show the used type variable when issuing a "can't use type parameters from outer function" error message Jan 24, 2018
@estebank
Copy link
Contributor

I'm stumped, I haven't figured out why this is happening, although the only working theory I have at the moment is around derive(Hash) and the query system, but it's just a guess.

@rust-lang/compiler, apologies for the wide shout out but can someone help @zilbuz with this issue? This is also blocking @gaurikholkar on a PR that also requires adding spans to TyParams.

@kennytm kennytm added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 25, 2018
@nikomatsakis
Copy link
Contributor

r? @nikomatsakis

I'll try to take a look. Assigning review to myself so I remember. Does seem likely to be an unrelated bug, but I've not reviewed the diffs yet.

@nikomatsakis
Copy link
Contributor

Hmm, I wonder if it has to do w/ incremental compilation somehow.

@kennytm kennytm added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). labels Jan 26, 2018
@@ -862,23 +863,24 @@ impl<'tcx> PolyFnSig<'tcx> {
pub struct ParamTy {
pub idx: u32,
pub name: Name,
pub span: Span,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking more closely at this diff, I'm not sure how I feel about adding a span to ty::ParamTy in any case. Actually, I would prefer to remove name too, and just have idx. I can in any case imagine that adding span information in here might be messing with the equality and hash tests and causing problems with trait selection, though I don't exactly now why that would be true off-hand -- I guess it should be ok as long as we are consistent about what span we use.

Copy link
Member

@eddyb eddyb Jan 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just add a DefId if we want to get back the definition, Span is a very bad idea within anything reachable from Ty.
(e.g. cross-crate Span is not that cheap to decode and behaves a bit strangely)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, definitely not a span. I have been resisting the idea of going back to DefId, because I'd rather we move towards just an index, but that would require having more context about the currently "in scope" parameters somewhere to give good error messages. Maybe a DefId is the right step for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we use DefId in Region, don't we?

@bors
Copy link
Contributor

bors commented Jan 26, 2018

☔ The latest upstream changes (presumably #47748) made this pull request unmergeable. Please resolve the merge conflicts.

@zilbuz
Copy link
Contributor Author

zilbuz commented Jan 29, 2018

For information @nikomatsakis, I tried to compile without incremental compilation, but I have the same compilation error.

I'll try to make a summary of the situation.

Objective

The goal of this PR is to clarify the error message for E0401. I have two examples that trigger this error.

First example

pub trait Bar { fn m(&self); }

pub fn foo<T>() {
    struct S<T>;
    impl Bar for S<T> {
        fn m(&self) { println!("Hello World"); }
    }
    let s = S::<T>;
    s.m();
}

pub fn main() {
}

Current error message:

error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
 --> src/main.rs:5:20
  |
5 |     impl Bar for S<T> {
  |                    ^ use of type variable from outer function

Ideal error message:

error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
 --> src/main.rs:5:20
3 | pub fn foo<T>() {
  |            - type variable from outer function
...
5 |     impl Bar for S<T> {
  |                    ^ use of type variable from outer function
note: try using a local type parameter instead
  |
5 |     impl<T> Bar for S<T> {
  |         ^^^

Second example

struct A<T> {
    inner: T,
}

impl<T> Iterator for A<T> {
    type Item = u8;
    fn next(&mut self) -> Option<u8> {
        fn helper(sel: &Self) -> u8 {
            unimplemented!();
        }
        Some(helper(self))
    }
}

fn main() {
}

Current error message:

error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
 --> src/main.rs:8:25
  |
8 |         fn helper(sel: &Self) -> u8 {
  |                         ^^^^ use of type variable from outer function

I don't really know what the ideal error message is here. The Self type parameter doesn't appear explicitly so we can't show its span. I suppose the note can be added, but we need to either use T arbitrarily every time or choose an unused letter as type parameter when generating the error message. I don't know if that's possible.

Implementation

Step one: adjust enum ResolutionError to add the necessary spans

The function resolve_error() is used to print the error message. The function takes the main span and a ResolutionError value as parameters. For "E0401", the enum has the value TypeParametersFromOuterFunction. This value needs to carry two more spans to be able to generate the ideal error message.

Open questions:

  • Are the spans OK for this use case or should we have DefId or indexes?
    Other enum values seems to use spans for this purpose;
  • Should we copy the spans inside the enum value or use a reference? The other
    enum values seem to use one or the other indiscriminately;
  • Should we use a fixed type name in the suggestion of the error message or
    generate one when constructing the error? If we generate one, should we do it
    before calling resolve_error() and pass it to the enum value or should we
    generate it inside resolve_error()?

Step two: retrieve the extra spans when triggering the error

The E0401 error is triggered in adjust_local_ref(). Here we have access to:

  • A span given to the function that corresponds to the type
    parameter incorrectly used. This span is currently used for the error message;
  • The DefIds of the Def::TyParam(..) and Def::SelfTy(..) that triggered
    the error. I think that these ids correspond to the same span as above, but I
    may be a bit confused about that;
  • A Rib of kind ItemRibKind. Unfortunately in both examples above, the
    bindings struct member was empty so I don't know what informations are
    available in this struct.

I feel that I'm missing something here, because I don't see how I can retrieve the necessary spans here, and I don't really know why I was trying to add a span to ParamTy since I don't see a value of this type here :/

Open questions:

  • How should we retrieve the necessary spans here?
  • Do we really need new informations on struct ParamTy here? And if so, should we add a DefId or an index?
  • I also wanted to ask how to retrieve the span of a DefId?

Sorry to be a bother, I feel like I'm asking a lot but I'm a bit lost :/. Feel free to contact me on Gitter if some of you want to discuss this more directly.

@pietroalbini
Copy link
Member

@nikomatsakis, ping from triage (also pinged on IRC)!

@nikomatsakis
Copy link
Contributor

@zilbuz sorry for not responding earlier. I keep diving into your list and then getting a bit lost myself. =)

@nikomatsakis
Copy link
Contributor

The last time, I got into a discussion with @eddyb about how we really want to be handling the Param type. My preference ultimately woudl be to just have an index, and to get the contextual information (e.g., its name, spans, etc) out of the TLS somehow (basically, when doing display, we'd set up the "environment that we are in")

@pietroalbini
Copy link
Member

@nikomatsakis what's the status on this?

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Feb 14, 2018

@zilbuz

Sorry for the delay. So, I've finally taken some time to catch up on what the original goal was here. The good news is that I think there is really no need to be changing the Ty<'tcx> and doing the other controversial things. The error that we are trying to fix is limited to the librustc_resolve section of the code, and the types in question don't even exist yet!

I'll try to leave some comments in the code itself, but also, a quick note on your second example:

struct A<T> {
    inner: T,
}

impl<T> Iterator for A<T> {
    type Item = u8;
    fn next(&mut self) -> Option<u8> {
        fn helper(sel: &Self) -> u8 {
            unimplemented!();
        }
        Some(helper(self))
    }
}

fn main() {
}

for this, may I suggest the following error?

error[E0401]: can't use type parameters from outer function; try using a local type parameter instead
 --> src/main.rs:8:25
5 | impl<T> Iterator for A<T> {
  | ^^^^ `Self` type implicitly declared here, on the `impl`
...
  |
8 |         fn helper(sel: &Self) -> u8 {
  |                         ^^^^ use of type variable from outer function

The truth is that it is not a type parameter in the context of an impl, not really, more like a type alias, but that may not be worth clarifying.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I left some comments, hopefully that helps!

resolve_error(self, span,
ResolutionError::TypeParametersFromOuterFunction);
ResolutionError::TypeParametersFromOuterFunction(None));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so, here def.def_id() gives you the DefId of the thing we want -- annoyingly, I'm not sure how to get the span from that. Normally I'd say to use the hir-map, but it's not available in resolve. Perhaps @eddyb or @petrochenkov can answer that -- what is the best way to get the span where def was declared here?

@@ -3275,8 +3278,10 @@ impl<'a> Resolver<'a> {
// This was an attempt to use a type parameter outside
// its scope.
if record_used {
debug!("rib: {:?}", rib);
resolve_error(self, span,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can kill all the diffs that are not part of this file.

@@ -122,7 +122,7 @@ impl Ord for BindingError {

enum ResolutionError<'a> {
/// error E0401: can't use type parameters from outer function
TypeParametersFromOuterFunction,
TypeParametersFromOuterFunction(Option<&'a Span>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May I suggest, instead of passing the span, that you pass the Def? (See other comments)

@@ -172,13 +172,16 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
resolution_error: ResolutionError<'a>)
-> DiagnosticBuilder<'sess> {
match resolution_error {
ResolutionError::TypeParametersFromOuterFunction => {
ResolutionError::TypeParametersFromOuterFunction(outer_span) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have the full Def here, we can match on it and see whether it is Def::SelfType or some other kind of def. If it is a self-type, we can customize the error message to highlight the trait/impl. The tricky bit is still getting the span from a Def.

@bors
Copy link
Contributor

bors commented Mar 10, 2018

💔 Test failed - status-travis

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Mar 10, 2018
@Mark-Simulacrum
Copy link
Member

@bors retry

cc @alexcrichton

[01:16:18] Cannot create directory /Users/travis/build/rust-lang/rust/build/x86_64-apple-darwin/openssl/install: File exists

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 10, 2018
@bors
Copy link
Contributor

bors commented Mar 10, 2018

⌛ Testing commit 0e68bb9 with merge ac2cc996bd392f81fecba27f69f5588778c956d7...

@bors
Copy link
Contributor

bors commented Mar 10, 2018

💔 Test failed - status-travis

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Mar 10, 2018
@kennytm
Copy link
Member

kennytm commented Mar 10, 2018

check x86_64-apple-darwin failed, but looks spurious.

@bors retry

[02:10:35] test net::tcp::tests::multiple_connect_interleaved_greedy_schedule ... FAILED

[02:10:35] 

[02:10:35] failures:

[02:10:35] 

[02:10:35] ---- net::tcp::tests::multiple_connect_interleaved_greedy_schedule stdout ----

[02:10:35] 	thread 'net::tcp::tests::multiple_connect_interleaved_greedy_schedule' panicked at 'called `Option::unwrap()` on a `None` value', libcore/option.rs:335:21

[02:10:35] 

[02:10:35] 

[02:10:35] failures:

[02:10:35]     net::tcp::tests::multiple_connect_interleaved_greedy_schedule

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Mar 10, 2018
@bors
Copy link
Contributor

bors commented Mar 10, 2018

⌛ Testing commit 0e68bb9 with merge 87344aa...

bors added a commit that referenced this pull request Mar 10, 2018
Show the used type variable when issuing a "can't use type parameters from outer function" error message

Fix #14844

r? @estebank
@bors
Copy link
Contributor

bors commented Mar 10, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 87344aa to master...

@bors bors merged commit 0e68bb9 into rust-lang:master Mar 10, 2018
estebank added a commit to estebank/rust that referenced this pull request Mar 14, 2018
kennytm added a commit to kennytm/rust that referenced this pull request Mar 15, 2018
Some tweaks to "type parameters from outer function" diagnostic

Follow up to rust-lang#47574.
@zilbuz zilbuz deleted the issue-14844 branch August 27, 2018 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants