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

Associated types can be specified multiple times in trait objects #50589

Closed
Marwes opened this issue May 9, 2018 · 6 comments
Closed

Associated types can be specified multiple times in trait objects #50589

Marwes opened this issue May 9, 2018 · 6 comments
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. C-enhancement Category: An issue proposing an enhancement or a PR with one. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.

Comments

@Marwes
Copy link
Contributor

Marwes commented May 9, 2018

fn test() ->  Box<Iterator<Item = (), Item = ()>> {
    Box::new(None.into_iter())
}

It seems rather surprising that the above code actually compiles. Making it an error wouldn't be backwards compatible but a warning would be nice (the same happens with impl Future<Item = (), Item = ()> which is where I got burnt, thinking I had specified the Error type).

@abonander
Copy link
Contributor

Implementing a lint for this would be a good beginner's task I think.

@estebank estebank added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. C-enhancement Category: An issue proposing an enhancement or a PR with one. A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. E-needs-mentor labels May 9, 2018
@gootorov
Copy link
Contributor

I'd like to work on this starting from Tuesday, if that's ok. Never hacked on a compiler before, anything I need to know besides the rustc guide for this particular issue? Would appreciate any help!

@F001
Copy link
Contributor

F001 commented May 11, 2018

Hi @abonander , I find it is easier to implement this warning based on normal diagnostics than lint in parser.rs.

We just need to add a new argument enable_warning : bool for the function fn parse_generic_args, and then detect whether there are duplicates in bindings, finally report issues by self.diagnostic().struct_span_warn(). Whereas, constructing a new lint is more complicated.

Is this solution acceptable?

@abonander
Copy link
Contributor

abonander commented May 11, 2018

@F001 Hardcoded warnings are strongly discouraged, but it's not that difficult to create a lint anyway. This should get you started; add the following to src/librustc_lint/builtin.rs:

declare_lint! {
    // we can bikeshed the lint name
    DUP_ASSOC_TYPE_BINDING,
    Warn,
    "warns about duplicate associated type bindings in generics, e.g. `Iterator<Item = (), Item = ()>`"
}

pub struct DupAssocTypeBinding;

impl LintPass for DupAssocTypeBinding {
    fn get_lints(&self) -> LintArray {
        lint_array!(DUP_ASSOC_TYPE_BINDING)
    }
}

impl EarlyLintPass for DupAssocTypeBinding {
    fn check_path(&self, ctxt: &EarlyContext, path: &ast::Path) {
        // could be `Iterator` or `std::iter::Iterator` or `Iterator<Item = ()>::next`
        // need to check all segments
        for segment in &path.segments {
            // if its `Iterator<..>` or `Iterator(...)` (for closure traits)
            if let Some(ref params) = segment.parameters {
                // if it's `Iterator<...>`
                if let ast::AngleBracketed(ref params_data) = &**params {
                    // in `params_data.bindings`, if two elements have the same 
                    // `ident` and `ty` fields but differing `id` fields,
                    // emit a lint message with:
                    ctxt.span_lint(DUP_ASSOC_TYPE_BINDING, 
                                   vec![param_span_1, param_span_2], 
                                   "duplicate associated type binding");
                }
            }
        }
    }
}

We can bikeshed the lint message.

Also, try to avoid emitting a lint for the same pair twice if you're doing a nested for loop; the inner loop should only iterate the elements after the current one. In fact, you should accumulate the duplicated spans inside the inner loop and then emit the lint message in the outer loop, so you lint for all the same duplicated type bindings at once, e.g. Iterator<Item = (), Item = (), Item = ()> emits one lint message pointing to them all.

And then in src/librustc_lint/lib.rs, in this macro invocation add DupAssocTypeBinding where it fits alphabetically.

Then you'll need to implement a UI test (which you would need to implement if you were emitting the warning in the parser anyway). I can add instructions for that if you need it.

@F001
Copy link
Contributor

F001 commented May 11, 2018

Wow, what an informative instruction. Thanks very much. I will create a merge request tomorrow.

@abonander
Copy link
Contributor

@F001 I had to edit my comment because check_generics() was not the right method, just making sure you've seen the latest version.

bors added a commit that referenced this issue May 23, 2018
Add lint for multiple associated types

Fix #50589. cc @abonander
pietroalbini added a commit to pietroalbini/rust that referenced this issue Nov 10, 2018
Take supertraits into account when calculating associated types

Fixes rust-lang#24010 and rust-lang#23856. Applies to trait aliases too.

As a by-product, this PR also makes repeated bindings of the same associated item in the same definition a hard error. This was previously a warning with a note about it becoming a hard error in the future. See rust-lang#50589 for more info.

I talked about this with @nikomatsakis recently, but only very superficially, so this shouldn't stop anyone from assigning it to themself to review and r+.

N.B. The "WIP" commits represent imperfect attempts to solve the problem just for trait objects, but I've left them in for reference for the sake of whomever is reviewing this.

CC @carllerche @theemathas @durka @mbrubeck
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lints Area: Lints (warnings about flaws in source code) such as unused_mut. C-enhancement Category: An issue proposing an enhancement or a PR with one. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
Projects
None yet
Development

No branches or pull requests

5 participants