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: remove ty::MethodOrigin and replace its uses with equivalent logic. #26694

Merged
merged 8 commits into from
Jul 4, 2015

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Jun 30, 2015

MethodCallee now has no information about the method, other than its DefId.
The previous bits of information can be recovered as follows:

let method_item = tcx.impl_or_trait_item(callee.def_id);
let container = method_item.container();

The method is inherent if container is a ty::ImplContainer:

  • the impl the method comes from is container.id()

The method is a trait method if container is a ty::TraitContainer:

  • the trait the method is part of is container.id()
  • a ty::TraitRef can be constructed by putting together:
    • container.id() as the trait ID
    • callee.substs.clone().method_to_trait() as the trait substs (including Self)
  • the above trait_ref is a valid T: Trait<A, B, C> predicate
  • selecting trait_ref could result in one of the following:
    • traits::VtableImpl(data): static dispatch to data.impl_def_id
    • traits::VtableObject(data): dynamic dispatch, with the vtable index:
      traits::get_vtable_index_of_object_method(tcx, data, callee.def_id)
    • other variants of traits::Vtable: various other impl sources

@rust-highfive
Copy link
Collaborator

r? @Aatch

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

@eddyb
Copy link
Member Author

eddyb commented Jul 1, 2015

Your "lints" are only unconditional_recursion, and you can get the impl relatively easily (by selecting on the trait - you can copy trans::common::fulfill_obligation).

@arielb1 Right, by "lints" I meant librustc_lint.
I didn't want to jump the gun because it wasn't an obvious cost (all changes that I can think of in this PR have a constant amortized cost difference associated with them).
It's probably not as bad as vtable_index, which can be reused for multiple monomorphizations (but trans could still cache vtable layouts in a more general fashion).

@arielb1
Copy link
Contributor

arielb1 commented Jul 1, 2015

unconditional_recursion is only called once per method call - this is amortized O(1).

@arielb1
Copy link
Contributor

arielb1 commented Jul 1, 2015

r+ modulo not storing the vtable + passing tests.

@bors
Copy link
Contributor

bors commented Jul 2, 2015

☔ The latest upstream changes (presumably #26677) made this pull request unmergeable. Please resolve the merge conflicts.

@eddyb
Copy link
Member Author

eddyb commented Jul 4, 2015

I ended up making all the changes anyway. Original PR description was:

MethodOrigin now only holds the optional impl_def_id, for trait methods, and vtable_index, for object methods.

They could be both removed, at the cost of offloading computation to lints and trans, respectively.
In the case of impl_def_id, using traits::select in lints will provide a more accurate result.
As for vtable_index, it's possible we don't want middle or typeck to deal with vtable layout - or at least, it could be stored outside of MethodOrigin.

MethodOrigin::Inherent could be distinguished from the other cases by checking that the container of the method is an impl.
MethodOrigin::Object can be replaced by an optimization for VtableObject in trans::meth - so that object.method() and Trait::method(object) produce the same IR (currently the latter always goes through the <Trait as Trait>::method shim).

I haven't attempted to implement any of those potential refactors as they might not be entirely beneficial, though they should all be possible (with all of them, MethodOrigin would be gone).

@eddyb eddyb changed the title rustc: do not use indices inside a trait's items to refer to methods. rustc: remove ty::MethodOrigin and replace its uses with equivalent logic. Jul 4, 2015
@eddyb
Copy link
Member Author

eddyb commented Jul 4, 2015

cc @huonw The commit named "rustc_lint: use traits::select for methods in unconditional_recursion." produces warnings for overloaded operators (and probably other things I haven't thought of):

struct Foo;
impl std::ops::Deref for Foo {
    type Target = Foo;
    // warning: function cannot return without recurring
    fn deref(&self) -> &Foo { &**self }
}
impl std::ops::Index<usize> for Foo {
    type Output = Foo;
    // warning: function cannot return without recurring
    fn index(&self, x: usize) -> &Foo { &self[x] }
}

We might want some tests for these.

@arielb1
Copy link
Contributor

arielb1 commented Jul 4, 2015

@bors r+

@bors
Copy link
Contributor

bors commented Jul 4, 2015

📌 Commit d877cfd has been approved by arielb1

@bors
Copy link
Contributor

bors commented Jul 4, 2015

⌛ Testing commit d877cfd with merge 411a5bf...

@bors
Copy link
Contributor

bors commented Jul 4, 2015

💔 Test failed - auto-linux-64-nopt-t

@eddyb
Copy link
Member Author

eddyb commented Jul 4, 2015

@bors r=arielb1

@bors
Copy link
Contributor

bors commented Jul 4, 2015

📌 Commit d256eb1 has been approved by arielb1

@bluss
Copy link
Member

bluss commented Jul 4, 2015

Since this fixes a memory safety bug, can we backport it?

@eddyb
Copy link
Member Author

eddyb commented Jul 4, 2015

@bluss the refactoring parts are pretty huge, though maybe just the vtable upcasting logic could be... I'm not sure.

@bors
Copy link
Contributor

bors commented Jul 4, 2015

⌛ Testing commit d256eb1 with merge a993275...

@bors
Copy link
Contributor

bors commented Jul 4, 2015

💔 Test failed - auto-mac-64-opt

@eddyb
Copy link
Member Author

eddyb commented Jul 4, 2015

@bors retry

@bors
Copy link
Contributor

bors commented Jul 4, 2015

⌛ Testing commit d256eb1 with merge 42e545f...

bors added a commit that referenced this pull request Jul 4, 2015
`MethodCallee` now has no information about the method, other than its `DefId`.
The previous bits of information can be recovered as follows:
```rust
let method_item = tcx.impl_or_trait_item(callee.def_id);
let container = method_item.container();
```
The method is inherent if `container` is a `ty::ImplContainer`:
* the `impl` the method comes from is `container.id()`

The method is a trait method if `container` is a `ty::TraitContainer:
* the `trait` the method is part of is `container.id()`
* a `ty::TraitRef` can be constructed by putting together:
 * `container.id()` as the `trait` ID
 * `callee.substs.clone().method_to_trait()` as the `trait` substs (including `Self`)
* the above `trait_ref` is a valid `T: Trait<A, B, C>` predicate
* selecting `trait_ref` could result in one of the following:
 * `traits::VtableImpl(data)`: static dispatch to `data.impl_def_id`
 * `traits::VtableObject(data)`: dynamic dispatch, with the vtable index:
`traits::get_vtable_index_of_object_method(tcx, data, callee.def_id)`
 * other variants of `traits::Vtable`: various other `impl` sources
@bors bors merged commit d256eb1 into rust-lang:master Jul 4, 2015
@eddyb eddyb deleted the method-nan branch July 4, 2015 20:34
bors added a commit that referenced this pull request Aug 3, 2015
After #26694, the overloaded operator and "impl not known at method lookup time" cases started triggering the lint.
I've also added checks for overloaded autoderef and method calls via paths (i.e. `T::method()`).
All new 8 test cases did not trigger the lint before #26694.
r? @huonw
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.

6 participants