-
Notifications
You must be signed in to change notification settings - Fork 13.1k
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 coercions from never-type when ref binding is involved #118270
base: master
Are you sure you want to change the base?
Conversation
(rustbot has picked a reviewer for you, use r? to override) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've only got one concern about changing the check_expr_with_needs
.
Can you add a test where the source type is an associated type that normalizes to !
?
trait Call {
type Out;
fn call(self) -> Self::Out;
}
impl<F: FnOnce() -> T, T> Call for F {
type Out = T;
fn call(self) -> T { (self)() }
}
pub struct Foo {
bar: u8
}
fn diverge() -> ! { todo!() }
#[allow(unused_variables)]
fn main() {
let Foo { ref bar } = diverge.call();
}
Just so we don't make sure to subtly regress this when lazy normalization comes around.
let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); | ||
let mut init_ty = self.check_expr_with_expectation_and_needs( | ||
init, | ||
ExpectHasType(local_ty), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, I wonder if this has subtle inference implications. Did you look into this?
Also, why did you add this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the call made by check_expr_coercible_to_type
(which we call in the non-bindings case) - I wanted to align them more closely.
When we type-check a binding that uses ref patterns, we do not perform coercions between the expression type and the pattern type. However, this has the unfortunate result of disallow code like: `let Foo { ref my_field } = diverging_expr();`. This code is accepted without the `ref` keyword. We now explicitly allow coercions when the expression type is ! In all other cases, we still avoid performing coersions. This avoids causing broader changes in type-checking (with potential soundness implications for 'ref mut'),
36404ce
to
b82416b
Compare
@compiler-errors I've added an additional test |
Sorry for taking so long to get to this. I think this behavior is fine, but I don't feel comfortable approving this without some consensus. I'll start a types FCP. @rfcbot fcp merge See description and test for what this enables. Seems pretty clear to me. |
Team member @compiler-errors has proposed to merge this. The next step is review by the rest of the tagged team members: Concerns:
Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
// to be unreachable, so the soundness concerns with 'ref mut' do not apply. | ||
if init_ty.is_never() { | ||
init_ty = self.demand_coerce(init, init_ty, local_ty, None, AllowTwoPhase::No); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
}; | |
} |
this should possibly be a lang question too as to whether we would want the behaviour to be a check for |
@rfcbot concern want to look into always enabling coercions even if there is a |
We don't coerce uninhabited types in general today, only |
This seems the exact opposite decision to the one made in #117288 (comment) |
In my understanding, this is consistent: #117288 is about whether constructing a place of type let _val: () = *x; //~ Insta-UB. |
@rfcbot resolve want to look into always enabling coercions while I still lack quite a lot of context here, I will sadly not get to actually spend significantly more time on this :/ relying on
cc @RalfJung @digama0 who seem to have a lot more context here given their comments in #117288. I think that assuming we actually convert the place to a value in the following example, I feel fairly confident that it's a step in the right direction, regardless of whether we want to also allow more general coercions if there are struct Foo(u8);
// This currently does not coerce but afaict will with this PR.
// Please add this as a test.
fn should_coerce_with_this_pr() {
let ref foo: Foo = loop {};
}
// this currently coerces and afaict it should ideally
// not do so according to RalfJ in #117288.
fn already_coerces() {
let _: Foo = loop {};
} Can I get some confirmation whether use std::cell::Cell;
fn ref_pat(x: &Cell<bool>) {
let ref new_val_same_place = *x;
new_val_same_place.set(true);
}
fn main() {
let x = Cell::new(false);
ref_pat(&x);
assert!(x.get());
} Footnotes
|
It's not at all clear to me that For |
The example in #118113 is a bit different, since But I don't think we want to accept code like this: let raw_ptr = 16 as *const !;
let Foo { ref my_field } = *raw_ptr; This is taking a place of type |
@RalfJung to make sure I understand you correctly: First a question: is there currently a consensus whether a place expression of type
You believe that You therefore believe that the PR as is is not desirable. We should only apply coercions from Assuming that 1) we have not yet decided that a place of type @rfcbot concern coerce place vs value I am not confident that I fully understand what is going on here and how this fits into the greater picture, but I would like to definitely involve @rust-lang/opsem to make sure the behavior here is consistent |
I believe @RalfJung and I were in agreement on #117288 that constructing places of type As it relates to this PR, I think it's okay provided that it only triggers on expressions that are already value expressions (like |
I think that is the general opinion in @rust-lang/opsem, yes.
If the source is a value expression. Yes. |
☔ The latest upstream changes (presumably #126462) made this pull request unmergeable. Please resolve the merge conflicts. |
Having re-familiarized myself with #117288 and the current hazards the HIR typeck introduces due to its not distinguishing place and value expressions sufficiently w.r.t. divergence, never coercions, and pointers-to-never, I'd rather we close this until we figure out that story first. |
given the blocking concern and that quite a lot of time elapsed since first opening this PR, I agree with @compiler-errors and am going to cancel the FCP for now. Given the concern by @compiler-errors I would like us to also properly figure out how to handle the place/value distinction in general before landing this change. @rfcbot cancel |
@lcnr proposal cancelled. |
@lcnr |
This PR is blocked on only allowing coercions from values, but it should be possible to implement this rn 🤔 i think waiting-on-author is correct here |
Fixes #118113
When we type-check a binding that uses ref patterns, we do not perform coercions between the expression type and the pattern type.
However, this has the unfortunate result of disallow code like:
let Foo { ref my_field } = diverging_expr();
. This code is accepted without theref
keyword.We now explicitly allow coercions when the expression type is ! In all other cases, we still avoid performing coersions. This avoids causing broader changes in type-checking (with potential soundness implications for 'ref mut'),