Skip to content

internal: Beginning of MIR #14040

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

Merged
merged 1 commit into from
Feb 28, 2023
Merged

internal: Beginning of MIR #14040

merged 1 commit into from
Feb 28, 2023

Conversation

HKalbasi
Copy link
Member

This pull request introduces the initial implementation of MIR lowering and interpreting in Rust Analyzer.

The implementation of MIR has potential to bring several benefits:

  • Executing a unit test without compiling it: This is my main goal. It can be useful for quickly testing code changes and print-debugging unit tests without the need for a full compilation (ideally in almost zero time, similar to languages like python and js). There is a probability that it goes nowhere, it might become slower than rustc, or it might need some unreasonable amount of memory, or we may fail to support a common pattern/function that make it unusable for most of the codes.
  • Constant evaluation: MIR allows for easier and more correct constant evaluation, on par with rustc. If r-a wants to fully support the type system, it needs full const eval, which means arbitrary code execution, which needs MIR or something similar.
  • Supporting more diagnostics: MIR can be used to detect errors, most famously borrow checker and lifetime errors, but also mutability errors and uninitialized variables, which can be difficult/impossible to detect in HIR.
  • Lowering closures: With MIR we can find out closure capture modes, which is useful in detecting if a closure implements the FnMut or Fn traits, and calculating its size and data layout.

But the current PR implements no diagnostics and doesn't support closures. About const eval, I removed the old const eval code and it now uses the mir interpreter. Everything that is supported in stable rustc is either implemented or is super easy to implement. About interpreting unit tests, I added an experimental config, disabled by default, that shows a pass or fail on hover of unit tests (ideally it should be a button similar to Run test button, but I didn't figured out how to add them). Currently, no real world test works, due to missing features including closures, heap allocation, dyn Trait and ... so at this point it is only useful for me selecting what to implement next.

The implementation of MIR is based on the design of rustc, the data structures are almost copy paste (so it should be easy to migrate it to a possible future stable-mir), but the lowering and interpreting code is from me.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 27, 2023
@@ -180,7 +180,9 @@ impl Fixture {
let mut cfg_key_values = Vec::new();
let mut env = FxHashMap::default();
let mut introduce_new_source_root = None;
let mut target_data_layout = None;
let mut target_data_layout = Some(
Copy link
Member

Choose a reason for hiding this comment

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

Nit: some of the tests already have a layout annotation, should we also set it globally here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Currently all of const eval tests, and some of tests in infer need it, so I think it make sense to have it for default. If we keep this, those annotations can be removed.

Copy link
Member

Choose a reason for hiding this comment

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

My sight preference would be to make them explicit, since it seems like something that might catch people off-guard. But it's not very important tbh.

Copy link
Member Author

Choose a reason for hiding this comment

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

Your point is valid, but I think there are too much tests that needs it (and there will be more) so the visual noise doesn't worth it, and also keep them all in a same place makes future changes to it easier. So I would prefer it to be present by default.

Copy link
Member

Choose a reason for hiding this comment

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

Ye I think keeping a default here is fine. No need to remove the setting of this though, maybe we do want to specifically test different layouts in some places at some point

@@ -509,7 +509,7 @@ impl<'a> InferenceContext<'a> {
}
}

fn resolve_all(self) -> InferenceResult {
pub(crate) fn resolve_all(self) -> InferenceResult {
Copy link
Member

Choose a reason for hiding this comment

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

this doesn't actually get called from anywhere new, does it?

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 is called in evaluating const generics. I'm probably doing something wrong here. The problem is, const eval is called inside type inference, but the constant in const generics share their body with their parent and type check at the same time, so in evaluating constants, the types inside of the const are not resolved yet. I made a clone of InferenceContext and called resolve_all on it as a hacky workaround.

Copy link
Member

Choose a reason for hiding this comment

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

Can you put a FIXME on this/the call then?

/// the neccessary bits of memory of the const eval session to keep the constant
/// meaningful.
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct MemoryMap(pub HashMap<usize, Vec<u8>>);
Copy link
Member

Choose a reason for hiding this comment

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

should that maybe be a BTreeMap for sortedness / iteration order?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this should ever need to be iterated over.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it probably doesn't need to be sorted and iterated, the only problem I can think of is Hash implementation. I currently excluded memory map field from hash implementation of the ConstScalar. If it is fine, then I think it doesn't need to be a BTreeMap.

pub fn interpret_mir(
db: &dyn HirDatabase,
body: &MirBody,
assert_placeholder_ty_is_unused: bool,
Copy link
Member

Choose a reason for hiding this comment

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

what's this used for?

Copy link
Member Author

Choose a reason for hiding this comment

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

The interpret_mir function? It is used in const eval and interpreting unit tests. If you mean the assert_placeholder_ty_is_unused, it is another hack due const generics doesn't have a separate body. Currently it generates a local for every binding in the hir body, but in interpreting const generics, we don't know all bindings types. This arguments assumes that they are unused (which is clearly wrong, we don't know if there is a type with placeholder inside of the constant body) and will use zero as size of types with placeholder, instead of failing.

Copy link
Member

Choose a reason for hiding this comment

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

Likewise, can we put a FIXME comment regarding that somewhere? (ideally linking to the issue of lowering const generics maybe)

@HKalbasi HKalbasi force-pushed the mir branch 3 times, most recently from 6de59aa to 2ae1d4f Compare January 31, 2023 22:01
@bors
Copy link
Contributor

bors commented Feb 2, 2023

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

@HKalbasi HKalbasi force-pushed the mir branch 3 times, most recently from ef3389b to cfdf067 Compare February 3, 2023 11:16
@bors
Copy link
Contributor

bors commented Feb 6, 2023

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

@bors
Copy link
Contributor

bors commented Feb 14, 2023

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

@lnicola
Copy link
Member

lnicola commented Feb 16, 2023

This seems to increase the memory usage on analysis-stats self by around 2 MB, but I'm not sure if it's actually used.

@HKalbasi
Copy link
Member Author

It is used in const eval which is used in type checking, and it caches somethings, including MIR bodies and data layout of types, but since r-a code is not const-generic heavy, I don't know if this increase is natural or indicates a problem.

@lnicola
Copy link
Member

lnicola commented Feb 16, 2023

r-a and its dependencies. But yeah, the memory usage looks good for now.

@Veykril
Copy link
Member

Veykril commented Feb 16, 2023

Also note that the new MIR code itself is being analyzed itself now as well

@lnicola
Copy link
Member

lnicola commented Feb 16, 2023

No, I measured both for the code on this branch.

@HKalbasi
Copy link
Member Author

If you are agree with the general direction of this, and there is no problem in changes outside of MIR parts, I think we can merge this (probably after Monday to minimize damage of possible breakages) to unblock further progress on it. The implementation details of MIR are subject to change, so reviewing that doesn't have much value, and I can apply your suggestions after merge as well. Also please tell me if the current unresolved reviews need action.

@Veykril
Copy link
Member

Veykril commented Feb 27, 2023

I'm fine with merging this if you add the two FIXME comments

@HKalbasi
Copy link
Member Author

I added the FIXME comments.

@bors r+

@bors
Copy link
Contributor

bors commented Feb 28, 2023

📌 Commit cd67589 has been approved by HKalbasi

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Feb 28, 2023

⌛ Testing commit cd67589 with merge a0be16b...

@bors
Copy link
Contributor

bors commented Feb 28, 2023

☀️ Test successful - checks-actions
Approved by: HKalbasi
Pushing a0be16b to master...

1 similar comment
@bors
Copy link
Contributor

bors commented Feb 28, 2023

☀️ Test successful - checks-actions
Approved by: HKalbasi
Pushing a0be16b to master...

@bors
Copy link
Contributor

bors commented Feb 28, 2023

👀 Test was successful, but fast-forwarding failed: 422 Changes must be made through a pull request.

@bors bors merged commit a0be16b into rust-lang:master Feb 28, 2023
@lnicola lnicola changed the title Beginning of MIR internal: Beginning of MIR Mar 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants