-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Allow where clauses involving types which don't include a type parameter. #27972
Conversation
…ter. There isn't any semantic reason to disallow a `where` clause based on the fact that it doesn't contain a type parameter.
☔ The latest upstream changes (presumably #27856) made this pull request unmergeable. Please resolve the merge conflicts. |
Be careful not to cause an ICE when translating a function that contains a bogus bound: #[no_mangle]
pub fn bogus<'a>(x: &'a mut ()) where &'a mut (): Clone {
<&'a mut ()>::clone(&x);
} |
The original RFC specified this behavior, but I think we all agree this is a fine change. |
Yes, I agree this is reasonable, but I think we may not want to just lift the restriction without possibly placing other restrictions. I had intended to write an RFC at some point, though it may be overkill. My thought is that we should make a best-effort to validate where-clauses, which means that if you define a function that contains a where-clause which is not satisfiable (e.g., This is probably fairly easy to implement. The existing |
cc @rust-lang/lang |
Nominating for "needs decision" by the @rust-lang/lang team. |
If I'm understanding correctly, the suggested rule is something along the lines of "all where clauses which don't contain a type parameter must be satisfiable if you replace all generic lifetimes with 'static"? That seems reasonable... |
I would prefer to check for satisfiability in intercrate mode after you instantiate type parameters by type variables. |
We already validate where clauses to an extent... trait ZZ {}
fn _f() where std::fmt::Display : ZZ {}
fn main() {}
Unfortunately, the current check completely ignores anything which includes a lifetime, for example: trait ZZ<'a> {}
fn _f<'a>() where std::fmt::Display : ZZ<'a> {}
fn main() {} I have no idea how to fix this. |
is this on a patched compiler? |
I think #27987 is related. |
Sorry for the delay here. This got overlooked in our lang team triage due to the silliness that our filter was looking for issues, not PRs. I think we DID discuss it at some point anyhow, in fact, but none of us can recall the decision that was reached. |
OK, so, sorry this took forever, but we talked about it in the lang team mtg and came to the conclusion that it is fine to lift this rule, and it does not have to be an error if a where clause is unsatisfied. Unfortunately, my notes from the discussion are kind of insufficient and I cannot remember all the reasoning that led to this conclusion. Certainly issuing hard errors is backwards incompatible, and feels in some sense a bit artificial, since in general we assume that where clauses hold, so this would require special code. I seem to recall that we realized that there were other equally invalid cases where we couldn't issue errors, so it was ok for such where clauses to be accepted, and we can always issue lint warnings later etc. @rust-lang/lang anybody remember more details? |
I'm removing the I-nominated and I-needs-decision tags, in any case. |
@eefriedman I'll happily r+ the patch if you rebase. |
What should be done to cover this case: #[no_mangle]
pub fn bogus<'a>(x: &'a mut ()) where &'a mut (): Clone {
<&'a mut ()>::clone(&x);
} I imagine a patch would require this not ICE-ing. |
@arielb1 Ah yes, good question. Your earlier comment got overlooked, thanks for bringing it up again. I guess I can see three options:
Seems in some way analogous to matching on an empty enum -- what do we do in that case again? |
What the hey, i'll nominate again to think this over :) |
I think generating an LLVM |
From a brief look, it appears that matching on an empty enum invokes LLVM unreachable, so I think I'm ok with that, just for consistency sake (though I don't particularly like that we use it for an empty enum). In the @rust-lang/lang meeting, @huonw mentioned something about an LLVM instruction that generates an illegal instruction, but I couldn't find any such thing (maybe I didn't look hard enough). @huonw any links? In general, some kind of failure or fault seems better than arbitrary undefined behavior -- but I think the same holds for Anyway I think ultimately I would prefer to handle all such "logically impossible" cases in the same way. |
The intrinsic to generate a trap is http://llvm.org/docs/LangRef.html#llvm-trap-intrinsic . Whether it makes sense to generate trap vs. just unreachable is basically just a question of how much hand-holding we want to do for unsafe code. |
What's your problem with matching on an empty enum being an That would however require adding an |
On Fri, Oct 23, 2015 at 01:03:58PM -0700, arielb1 wrote:
My problem is that it results in undefined behavior if somebody makes |
how could one |
@arielb1 one could create an instance of an empty enum by accident, or have the enum being empty by accident. Basically something went wrong in your logic if we go to that point, clearly, so doing undefined things doesn't seem like it's going to help anybody. |
/me suggests emitting a trap for such matches in debug-builds and an unreachable in release-builds. |
On Thu, Oct 29, 2015 at 02:38:37PM -0700, Felix S Klock II wrote:
I could get behind this, though I might prefer a panic in debug builds |
Anyway, a match on an empty enum is occasionally used to intentionally introduce an Creating an instance of an empty enum is not particularly easy. |
@arielb1 I know it is used that way; the question I think is whether a trap would be equally effective for optimization (and if not, what kind of impact we are talking about) |
What is the status of this PR? |
We talked about this in the @rust-lang/lang meeting but didn't reach a firm conclusion. I think at this point probably the most appealing option is to permit such where-clauses but report errors if they don't hold (at the definition site). Yes, this is the opposite of what I wrote before, but it sidesteps @arielb1's example, and there isn't really a compelling reason to go out of our way to permit such a fn. Furthermore, if we ever encounter such a reason, it is backwards compatible to permit such where-clauses. The only hazard is that this might break some code, given that it will presumably also apply to all elaborated where clauses. I'd be surprised, though, if that affected any real code in practice. In any case it seems that RFC 1214 is already enforced some of these regulations (but I think not all, right?). I'd have to go back over and check more carefully, can't remember off the top of my head. |
@eefriedman are you interested in trying to implement the "report errors at definition site if the where-clauses don't hold" semantics? I think it would be relatively straightforward -- there is already some code that is careful not to add such where-clauses into the parameter environment, presumably it could be made to return those clauses and then we could check them instead (or something like that, in any case). |
Closing in favor of issue #21203 |
There isn't any semantic reason to disallow a
where
clause based on the fact that it doesn't contain a type parameter.r? @nikomatsakis