-
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
rustc_typeck: use subtyping on the LHS of binops. #45435
Conversation
Crater report has only false positives. |
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.
Seems ok for the most part. I left a few questions to make sure I'm following along.
@@ -763,7 +763,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { | |||
|
|||
let (adjustments, _) = self.register_infer_ok_obligations(ok); | |||
self.apply_adjustments(expr, adjustments); | |||
Ok(target) | |||
Ok(self.resolve_type_vars_with_obligations(target)) |
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.
Is there a reason for this? Just to improve debug output, or something else?
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.
It's used to avoid repeatedly doing this in the callers.
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.
So you mean that the callers rely on type variables having been resolved in the return value?
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.
Yeah, in the changed binop code.
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.
Then I think we should add some comment that this is important, and also comment the interface of the coercion function. I'm not all that keen on having such a guarantee, though -- it's a subtle link between code imo -- but if you can at least document who cares about it, it would be helpful.
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.
Well then I'll just throw away most of the changes, I guess... I thought this API was much nicer but I can just as well have two extra lines in op.rs
instead.
src/librustc_typeck/check/demand.rs
Outdated
let expected = self.resolve_type_vars_with_obligations(expected); | ||
|
||
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) { | ||
self.try_coerce(expr, checked_ty, self.diverges.get(), expected).map_err(|e| { |
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.
Nit: this whole foo.map_err().map().unwrap_or
is getting a bit over the top and kind of hard to follow. Can we just rewrite this with a match
?
Something like:
let e = match self.try_coerce(...) {
Ok(ty) => return (ty, None),
Err(e) => e,
};
...
(expected, some(err))
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 wanted to avoid intending the whole function right, but I'm okay with a match either.
// trait matching creating lifetime constraints that are too strict. | ||
// E.g. adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result | ||
// in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. | ||
let lhs_ty = self.check_expr_coercable_to_type_with_lvalue_pref(lhs_expr, |
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.
Why use coercion here rather than subtyping? I guess it is equivalent anyway, at least for the way we handle coercions now, since if you coerce with a target type of a variable you just get subtyping anyway, right?
OTOH, if we ever support "deferred coercion", I don't see any reason not to use coercion here, at least for by-value operators like +
-- not entirely sure about ==
.
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.
Subtyping is trickier to get right, I'm far more comfortable using coercion instead.
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.
Trickier in what sense? Coercing is a superset of subtyping, so using it can only cause more things to happen.
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 mean doing subtyping manually - I know coercion uses subtyping correctly and I'd rather use an API where it's obvious how not to misuse it.
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 guess I'm just nervous that, if coercion gets smarter, we'll now be performing random coercions here -- as opposed to just subtyping -- which maybe we do not want to do. But I can't really think of a good reason not to use coercion.
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.
We already coerce the RHS FWIW.
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.
That does make me feel better =)
src/test/run-pass/issue-32008.rs
Outdated
fn try_to_add(input: &Foo) { | ||
let local = Foo; | ||
&*input + &local; // ok | ||
input + &local; // Error! |
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.
Can you remove the // Error!
comment
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.
Heh I was considering it.
src/test/run-pass/issue-32008.rs
Outdated
|
||
use std::ops::Add; | ||
|
||
struct Foo; |
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.
Can you add a comment explaining what this is all about? i.e,. "Check that we permit subtyping for operator LHS" or something.
73af9d7
to
7a2a638
Compare
@nikomatsakis Let me know if you want more changes to this. |
@eddyb are you going to either comment or remove the "resolve type variables" line? I'm ok either way. Other than that, r=me. |
7a2a638
to
1a7fb7d
Compare
@bors r+ |
📌 Commit 1a7fb7d has been approved by |
rustc_typeck: use subtyping on the LHS of binops. Fixes #45425. r? @nikomatsakis
☀️ Test successful - status-appveyor, status-travis |
It looks like this may have regressed the |
I suppose that more inference variables are created even without any lifetimes being involved. @nikomatsakis, are there any plans to handle lifetime subtyping/generalization more efficiently during typeck? |
Rust 1.22 fixes the original issue (rust-ndarray#103) that required `'b` to be added. (See rust-lang/rust#32008 and rust-lang/rust#45435 for the issue and fix in Rust.)
Rust 1.23 fixes the original issue (rust-ndarray#103) that required `'b` to be added. (See rust-lang/rust#32008 and rust-lang/rust#45435 for the issue and fix in Rust.)
Rust 1.23 fixed the original issue (rust-ndarray#103) that required `'b` to be added. (See rust-lang/rust#32008 and rust-lang/rust#45435 for the issue and fix in Rust.)
Rust 1.23 fixed the original issue (rust-ndarray#103) that required `'b` to be added. (See rust-lang/rust#32008, rust-lang/rust#45425, and rust-lang/rust#45435 for the relevant Rust issues/PRs.)
Rust 1.23 fixed the original issue (rust-ndarray#103) that required `'b` to be added. (See rust-lang/rust#32008, rust-lang/rust#45425, and rust-lang/rust#45435 for the relevant Rust issues/PRs.)
…iant, r=eddyb LHS of assign op is invariant This addresses a bug injected by #45435. That PR changed the way we type-check `LHS <op> RHS` to coerce the LHS to the expected supertype in much the same way that we coerce the RHS. The problem is that when we have a case of `LHS <op>= RHS`, we do not want to coerce to a supertype; we need the type to remain invariant. Otherwise we risk leaking a value with short-lifetimes into a expression context that needs to satisfy a long lifetime. Fix #52126
Fixes #45425.
r? @nikomatsakis