Skip to content

check_match: Dereference ref x before comparing it and some other type #23313

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

Merged
merged 1 commit into from
Mar 15, 2015

Conversation

barosl
Copy link
Contributor

@barosl barosl commented Mar 12, 2015

The arity of ref x is always 1, so it needs to be dereferenced before being compared with some other type whose arity is not 1.

Fixes #23009.

@rust-highfive
Copy link
Contributor

r? @nrc

(rust_highfive has picked a reviewer for you, use r? to override)

@barosl
Copy link
Contributor Author

barosl commented Mar 12, 2015

I'm really not sure if this is the right way to fix the issue, so I beg for forgiveness in advance.

// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Related issue: #23009
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment to tests saying what is being tested - why it should fail, why it shouldn't ICE. This is helpful for future contributors who break your test and need to know if it is important.

@nrc
Copy link
Member

nrc commented Mar 12, 2015

Afraid I don't know this code well enough to review, sorry. Perhaps r? @pnkfelix

@rust-highfive rust-highfive assigned pnkfelix and unassigned nrc Mar 12, 2015
@@ -864,7 +864,10 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
} else {
None
},
_ => Some(repeat(DUMMY_WILD_PAT).take(arity).collect())
_ => match *constructor {
ConstantValue(..) => Some(vec![]),
Copy link
Member

Choose a reason for hiding this comment

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

so I'm not totally familiar with this code; I'm looking at what you've added here, and I do not immediately see why it suffices to add a special case for ConstantValue(..) but not need one for e.g. ConstantRange . Can you enlighten me?

@pnkfelix
Copy link
Member

(i'm going to be out until wedneday; handing off to @nikomatsakis to find a reviewer to replace me.)

r? @nikomatsakis

@ghost
Copy link

ghost commented Mar 13, 2015

I'll take this.

@barosl Thanks for tackling this. I don't think your fix is the appropriate one here. If you notice, the example will compile fine if you drop the ref from the binding.

It looks like we're getting bitten by our old problem of ref x having a type of '&T' as opposed to just 'T'. In this case, this is problematic for the check_match::constructor_arity function. For non-structural types such as usize in this case, the arity of ref x should be 0 but is instead 1 due to the misleading type information.

The place to hunt for a solution will be around https://github.com/rust-lang/rust/blob/ee7696383f3423cdd17373ff9e75c01acd8e3417/src/librustc/middle/check_match.rs#L649-658.

    let left_ty = if real_pat.id == DUMMY_NODE_ID {
        ty::mk_nil(cx.tcx)
    } else {
        ty::pat_ty(cx.tcx, &*real_pat)
    };

One way or another, we will need this to be the type of the value being destructured, free from the idiosyncracies of ref x.

@ghost ghost assigned ghost and unassigned nikomatsakis Mar 13, 2015
@ghost
Copy link

ghost commented Mar 13, 2015

Also, could you add the following assertion:

assert!(rows.iter().all(|row| row.len() == v.len()));

above this line:

let real_pat = match rows.iter().find(|r| (*r)[0].id != DUMMY_NODE_ID) {

@barosl barosl force-pushed the match-specialize-ice branch from b66f35d to bcb4974 Compare March 14, 2015 12:28
@barosl
Copy link
Contributor Author

barosl commented Mar 14, 2015

If we sanitize left_ty before passing it to another function, as you said, the following code would work:

let left_ty = match (&real_pat.node, &left_ty.sty) {
    (&ast::PatIdent(..), &ty::ty_rptr(_, ty::mt { ty, .. })) => match ty.sty {
        ty_int(..) | ty_uint(..) | ty_bool | ty_char | ty_float(..) => ty,
        _ => left_ty,
    },
    _ => left_ty,
};

But I find this ugly, as it hard-codes the list of the non-structural types. It also has a nested match which is too deep, in my opinion. (Possibly due to my inexperiences)

How about modifying constructor_arity() directly? In that case, we can utilize ctor to guess the type of the previous row. I've updated the code in my pull request to reflect this approach. If it is not appropriate, I will change it again to apply the code above.

@barosl barosl changed the title check_match: Expand a pattern correctly if the ctor is a constant value check_match: Regard the arity of a ref to a non-structural type as 0 Mar 14, 2015
@ghost
Copy link

ghost commented Mar 14, 2015

@barosl left_ty is used for various things across the board so I am afraid it needs to be correct.

I don't think we need the nested match at all. Any time you see the pattern ref x, the real type we're interested in is ty::deref(left_ty), no matter what the inner type is.

left_ty = match left_ty {
    ast::PatIdent(ByRef, _, _) => ty::deref(left_ty, true).unwrap().ty,
    _ => left_ty
};

@ghost
Copy link

ghost commented Mar 14, 2015

Sorry, I realise I'd misled you by talking about non-structural and structural types. My only point was that non-structural types should always have arity of 0 but that for ref x it's always 1, hence this bug.

@barosl
Copy link
Contributor Author

barosl commented Mar 14, 2015

Oh, I see! So the arity itself wasn't wrong.

It seems that you coded the most part, though 😄. I'll update my pull request based on your comment, and run tests locally.

@barosl barosl force-pushed the match-specialize-ice branch from bcb4974 to a11c4bf Compare March 14, 2015 14:27
The arity of `ref x` is always 1, so it needs to be dereferenced before
being compared with some other type whose arity is not 1.

Fixes rust-lang#23009.
@barosl barosl force-pushed the match-specialize-ice branch from a11c4bf to edbc0e5 Compare March 14, 2015 14:35
@barosl
Copy link
Contributor Author

barosl commented Mar 14, 2015

@jakub- Ok, I've done it. The tests pass locally.

Also, I changed the code to pass explicit=false to ty::deref(), in order to make sure the type is not ty_ptr. Would that be OK?

@barosl barosl changed the title check_match: Regard the arity of a ref to a non-structural type as 0 check_match: Dereference ref x before comparing it and some other type Mar 14, 2015
@ghost
Copy link

ghost commented Mar 14, 2015

@bors: r+ edbc0e5

@ghost
Copy link

ghost commented Mar 14, 2015

@barosl: Sure, that's fine. :) Thanks!

@bors
Copy link
Collaborator

bors commented Mar 15, 2015

⌛ Testing commit edbc0e5 with merge 8c85a9d...

bors added a commit that referenced this pull request Mar 15, 2015
The arity of `ref x` is always 1, so it needs to be dereferenced before being compared with some other type whose arity is not 1.

Fixes #23009.
@bors
Copy link
Collaborator

bors commented Mar 15, 2015

@bors bors merged commit edbc0e5 into rust-lang:master Mar 15, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

unexpected panic in pattern matching
6 participants