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

rustc_typeck: use subtyping on the LHS of binops. #45435

Merged
merged 1 commit into from
Nov 1, 2017

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Oct 21, 2017

Fixes #45425.

r? @nikomatsakis

@kennytm kennytm added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 21, 2017
@eddyb
Copy link
Member Author

eddyb commented Oct 22, 2017

Crater report has only false positives.

@bluss bluss added the relnotes Marks issues that should be documented in the release notes of the next release. label Oct 22, 2017
Copy link
Contributor

@nikomatsakis nikomatsakis left a 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))
Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Member Author

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.

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| {
Copy link
Contributor

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))

Copy link
Member Author

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,
Copy link
Contributor

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 ==.

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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 =)

fn try_to_add(input: &Foo) {
let local = Foo;
&*input + &local; // ok
input + &local; // Error!
Copy link
Contributor

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

Copy link
Member Author

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.


use std::ops::Add;

struct Foo;
Copy link
Contributor

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.

@eddyb
Copy link
Member Author

eddyb commented Oct 28, 2017

@nikomatsakis Let me know if you want more changes to this.

@nikomatsakis
Copy link
Contributor

@eddyb are you going to either comment or remove the "resolve type variables" line? I'm ok either way. Other than that, r=me.

@eddyb eddyb force-pushed the binop-subtype-lhs branch from 7a2a638 to 1a7fb7d Compare October 31, 2017 15:35
@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Oct 31, 2017

📌 Commit 1a7fb7d has been approved by nikomatsakis

@kennytm kennytm added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 1, 2017
@bors
Copy link
Contributor

bors commented Nov 1, 2017

⌛ Testing commit 1a7fb7d with merge 2f581cf...

bors added a commit that referenced this pull request Nov 1, 2017
rustc_typeck: use subtyping on the LHS of binops.

Fixes #45425.

r? @nikomatsakis
@bors
Copy link
Contributor

bors commented Nov 1, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 2f581cf to master...

@bors bors merged commit 1a7fb7d into rust-lang:master Nov 1, 2017
@eddyb eddyb deleted the binop-subtype-lhs branch November 1, 2017 13:04
@alexcrichton
Copy link
Member

It looks like this may have regressed the inflate benchmark by ~5%?

@eddyb
Copy link
Member Author

eddyb commented Nov 4, 2017

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?

jturner314 added a commit to jturner314/ndarray that referenced this pull request Nov 23, 2017
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.)
jturner314 added a commit to jturner314/ndarray that referenced this pull request May 10, 2018
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.)
jturner314 added a commit to jturner314/ndarray that referenced this pull request May 10, 2018
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.)
jturner314 added a commit to jturner314/ndarray that referenced this pull request May 10, 2018
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.)
jturner314 added a commit to jturner314/ndarray that referenced this pull request Jun 13, 2018
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.)
bors added a commit that referenced this pull request Jul 22, 2018
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants