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

[10/n] Split constants and functions' arguments into disjoint bodies. #38449

Merged
merged 7 commits into from
Dec 28, 2016

Conversation

eddyb
Copy link
Member

@eddyb eddyb commented Dec 18, 2016

This is part of a series (prev | next) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. MIR-based early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments.


Finishes the signature-body split started in #37918, namely:

  • trait items are separated just like impl items were, for uniformity, closing Separate trait items from trait #37712
  • statics, consts (including associated ones), enum discriminants and array lengths get bodies
  • arguments' patterns are moved to the bodies, with the types staying in FnDecl
    • &self now desugars to self: &Self instead of self: &_ (similarly for other self forms)
    • astconv's and metadata's (for rustdoc) informative uses are explicitly ignored for the purposes of the dep graph. this could be fixed in the future by hashing the exact information being extracted about the arguments as opposed to generating a dependency on the whole body

@rust-highfive
Copy link
Collaborator

r? @arielb1

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

@eddyb
Copy link
Member Author

eddyb commented Dec 18, 2016

r? @nikomatsakis

@michaelwoerister
Copy link
Member

astconv's and metadata's (for rustdoc) informative uses are explicitly ignored for the purposes of the dep graph.

That sounds a bit troubling.

@eddyb
Copy link
Member Author

eddyb commented Dec 19, 2016

@michaelwoerister AFAIK astconv's use, which is only in case of error, couldn't be observed. But that one is fixable if need be, by representing the elision information in terms of the BodyId, not the data extracted from it.

The rustdoc use is more problematic. I'm not sure there is a scenario in which it could go wrong, but long-term we should really move away from the current cross-crate docs model which is becoming unsustainable. I'm leaning towards the save-analysis solution, more so for rustdoc than IDEs even.

@michaelwoerister
Copy link
Member

Are you sure that compilation really aborts in case find_implied_output_region() returns Err? If it does, it should not make a difference anyway because we don't save the dep-graph in that case.

@eddyb
Copy link
Member Author

eddyb commented Dec 19, 2016

@michaelwoerister The information (argument names) is only used in case of (elision) error, later on (and printed verbatim, not used in any decision).

@michaelwoerister
Copy link
Member

michaelwoerister commented Dec 19, 2016

I still think this is problematic. What you say might be true for now, but lots of people are modifying this code without global understanding. Can this be refactored to just access that information in case an actual error occurs? (Alternatively, for cases like this, we could have some opaque ErrorReportingInfo type that implements Display and makes it explicit this must only be used for error reporting).

Regarding metadata: Isn't this kind of a premature optimization? Metadata is full of overconservative edges anyway. I think it would better to review this together with the rest when the time comes. Or does it break existing tests?

@eddyb
Copy link
Member Author

eddyb commented Dec 19, 2016

@michaelwoerister Alright I'll try to see what I can do to astconv. As for the metadata thing, it breaks all the tests that modify the body, making the body separation sort of pointless metadata-wise.
I would prefer to somehow hash the actual data being encoded (the argument names), as it has a much much smaller footprint and it would cause less of a hassle overall (@nikomatsakis said he wanted this).

@michaelwoerister
Copy link
Member

Alright I'll try to see what I can do to astconv.

Cool :) Thanks!

I would prefer to somehow hash the actual data being encoded (the argument names), as it has a much much smaller footprint and it would cause less of a hassle overall.

I would prefer that too. I suspect we'll move away from monolithic Entrys in metadata and put independent things into separate tables. Or have individual DepNodes for Entry fields. In this case, where the data is just a list of plain strings, it would be easy to just hash that. However, it would require that we start refactoring metadata dep-tracking already, which is a bit much for this PR.

As long as this is just used in rustdoc, we should be fine. How about just adding an assertion to CrateMetadata::get_fn_arg_names() that incremental compilation is turned off?

@eddyb
Copy link
Member Author

eddyb commented Dec 19, 2016

How about just adding an assertion to CrateMetadata::get_fn_arg_names() that incremental compilation is turned off?

Oh that is brilliant, thanks for the idea! I assume it would replace the usual read(Metadata(def_id))?

@michaelwoerister
Copy link
Member

Oh that is brilliant, thanks for the idea! I assume it would replace the usual read(Metadata(def_id))?

Sounds reasonable.

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.

Waiting on the commit to come. Looks good; we chatted about some of my comments on IRC. The thing about omitting the repeat expressions etc from borrowck is my biggest concern, though I'm not sure the best way to test it right now. Still seems like we should do it right.


use syntax::ast::*;
use syntax::ext::hygiene::Mark;
use syntax::visit;
use syntax::symbol::{Symbol, keywords};

/// Creates def ids for nodes in the HIR.
/// Creates def ids for nodes in the AST.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you intentionally change this from HIR to AST?

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, since it never touches the HIR anymore.

@@ -68,7 +68,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BorrowckCtxt<'a, 'tcx> {
}

fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
b: hir::ExprId, s: Span, id: ast::NodeId) {
b: hir::BodyId, s: Span, id: ast::NodeId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I can't find a way to make an error out of this (yet), but it seems like we are failing to borrowck embedded bodies -- e.g., in an expression like [22; X], we don't borrowck the expression X, right? The main reason I can't make an error here is that the set of constant expressions we accept in that context is pretty limited, but it seems like it wouldn't necessarily stay that way...

I did run across this, which seems like a bug, but a pre-existing one (this code compiles on nightly today...but it shouldn't...):

#![feature(const_fn)]

struct Foo(usize);

const fn get(x: Foo) -> usize {
    x.0
}

const X: Foo = Foo(22);
static Y: usize = get(*&X);

fn main() {
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't it? That's equivalent to ({*&Foo(22)}).0 which is perfectly fine AFAIK.
The problem would be if X where static (and only until we get miri).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not because Foo is not Copy, and we are moving it from a &Foo -- e.g., this does not compile: https://is.gd/zU2BVo

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filed #38520

@@ -839,7 +839,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
_ => None,
},
mir: match item.node {
hir::ItemStatic(..) |
hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this just a pre-existing bug?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it was, there were a few things in the PR introducing this that are less than ideal. They skipped review because they weren't in the original PR state but rather in "fixes for tests".

@@ -26,7 +26,9 @@ impl Foo for Def {

pub fn test<A: Foo, B: Foo>() {
let _array: [u32; <A as Foo>::Y];
//~^ ERROR the trait bound `A: Foo` is not satisfied
//~^ ERROR cannot use an outer type parameter in this context [E0402]
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 backwards compatibility concern here? Probably not, since this sort of doesn't work now -- but I feel like it should work someday, so it seems odd to be considering A as an "outer" type parameter.

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, I didn't really make anything worse, just better encoded the existing semantics.
We'll be able to clean this up in the future, when everything is body-based.

@@ -66,8 +66,10 @@ const CONST_CHANGE_TYPE_2: Option<u64> = None;
const CONST_CHANGE_VALUE_1: i16 = 1;

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail2")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -303,7 +303,7 @@ trait TraitChangeModeSelfOwnToMut: Sized {
#[cfg(not(cfail1))]
#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail2")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make an ICH test targeting exactly this change? Seems easily do-able. In particular, if you have something like fn foo(x: u32) { } and you change it to fn foo(y: u32) { }, the hash of the trait should not change (just the body). Right?

That said, if you don't provide a default, based on my read of the code above, then the fn names would still be included in the hash... which doesn't seem exactly right. We could I guess just ignore them manually in the hasher code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, if you don't provide a default, based on my read of the code above, then the fn names would still be included in the hash... which doesn't seem exactly right.

To me this seems like the correct way to handle this. If you remove a method decl from a trait, don't you have to re-run many computations depending on that trait?

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 think @nikomatsakis meant the fn argument names.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that makes sense then.

@bors
Copy link
Contributor

bors commented Dec 21, 2016

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

@eddyb eddyb force-pushed the lazy-10 branch 2 times, most recently from b7286b9 to 53e745b Compare December 21, 2016 10:34
@nikomatsakis
Copy link
Contributor

This all looks good to me I think except that I'd still like to run borrowck expressions like the N in [T; N] etc. It annoys me that I cannot find a way to write a test for this though, because constant expressions are too restrictive. Still it seems like we should try to get it right. =)

@bors
Copy link
Contributor

bors commented Dec 26, 2016

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

@eddyb eddyb force-pushed the lazy-10 branch 4 times, most recently from 31bd067 to 353a194 Compare December 27, 2016 13:02
@bors
Copy link
Contributor

bors commented Dec 28, 2016

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

@eddyb
Copy link
Member Author

eddyb commented Dec 28, 2016

@bors r=nikomatsakis

@bors
Copy link
Contributor

bors commented Dec 28, 2016

📌 Commit ee0ea95 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Dec 28, 2016

⌛ Testing commit ee0ea95 with merge dd07f36...

@bors
Copy link
Contributor

bors commented Dec 28, 2016

💔 Test failed - status-travis

@eddyb
Copy link
Member Author

eddyb commented Dec 28, 2016

@bors retry

@bors
Copy link
Contributor

bors commented Dec 28, 2016

⌛ Testing commit ee0ea95 with merge 4ecc85b...

bors added a commit that referenced this pull request Dec 28, 2016
[10/n] Split constants and functions' arguments into disjoint bodies.

_This is part of a series ([prev](#38053) | [next]()) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._

<hr>

Finishes the signature-body split started in #37918, namely:
* `trait` items are separated just like `impl` items were, for uniformity, closing #37712
* `static`s, `const`s (including associated ones), `enum` discriminants and array lengths get bodies
  * even the count in "repeat expressions", i.e. `n` in `[x; n]`, which fixes #24414
* arguments' patterns are moved to the bodies, with the types staying in `FnDecl`
  * `&self` now desugars to `self: &Self` instead of `self: &_` (similarly for other `self` forms)
  * `astconv`'s and metadata's (for rustdoc) informative uses are explicitly ignored for the purposes of the dep graph. this could be fixed in the future by hashing the exact information being extracted about the arguments as opposed to generating a dependency on *the whole body*
@bors
Copy link
Contributor

bors commented Dec 28, 2016

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

@bors bors merged commit ee0ea95 into rust-lang:master Dec 28, 2016
@eddyb eddyb deleted the lazy-10 branch January 2, 2017 16:15
bors added a commit that referenced this pull request Jan 8, 2017
[11/n] Separate ty::Tables into one per each body.

_This is part of a series ([prev](#38449) | [next]()) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._

<hr>

In order to track the results of type-checking and inference for incremental recompilation, they must be stored separately for each function or constant value, instead of lumped together.

These side-`Tables` also have to be tracked by various passes, as they visit through bodies (all of which have `Tables`, even if closures share the ones from their parent functions). This is usually done by switching a `tables` field in an override of `visit_nested_body` before recursing through `visit_body`, to the relevant one and then restoring it - however, in many cases the nesting is unnecessary and creating the visitor for each body in the crate and then visiting that body, would be a much cleaner solution.

To simplify handling of inlined HIR & its side-tables, their `NodeId` remapping and entries HIR map were fully stripped out, which means that `NodeId`s from inlined HIR must not be used where a local `NodeId` is expected. It might be possible to make the nodes (`Expr`, `Block`, `Pat`, etc.) that only show up within a `Body` have IDs that are scoped to that `Body`, which would also allow `Tables` to use `Vec`s.

That last part also fixes #38790 which was accidentally introduced in a previous refactor.
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.

Improve "no type for local variable" error when in check_const_with_ty
7 participants