Repository navigation
馃洜 introduce abstraction layer between trait solver and type checker聽#48895
Description
Activity
Mentoring instructions (part 1)
How it works today
The main interaction that the type checker has with the fulfillment context is to "register" obligations with it and try to solve them. Registering is primarily done with this method:
rust/src/librustc/traits/fulfill.rs
Lines 147 to 149 in fedce67
pub fn register_predicate_obligation(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>) Solving is done with
select_where_possible, which selects obligations when it can, but defers in the case of ambiguity:rust/src/librustc/traits/fulfill.rs
Lines 193 to 195 in fedce67
pub fn select_where_possible(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec<FulfillmentError<'tcx>>> And
select_all_or_error, which selects obligations and reports errors if anything comes up as ambiguous (maybe true, maybe false):rust/src/librustc/traits/fulfill.rs
Lines 175 to 177 in fedce67
pub fn select_all_or_error(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec<FulfillmentError<'tcx>>> Step 1: Introduce
TraitEnginetraitWe should introduce a new module, let's call it
rustc::traits::engine. In there would be a traitTraitEnginethat (to start) encapsulates aFulfilllmentContext:pub trait TraitEngine<'tcx> { fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>, ); // ... mirror the other fulfillment cx methods as needed ... }
Then we can have
FulfillmentContextimplement this trait. This could be done by forwarding to the inherent methods, or by moving them out from the inherent impl:impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>, ) { // forward to the inherent method self.register_predicate_obligation(infcx, obligation); } }Finally, we create a factory method on
TraitEngine; for now it can always create a fulfillment context. The important part is that it returns aBox<dyn TraitEngine<'tcx>>:impl dyn TraitEngine<'tcx> { pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box<Self> { Box::new(FulfillmentContext::new()) } }
Next, we want to modify typeck to use this. For that, we would modify this field from having type
RefCell<traits::FulfillmentContext<'tcx>>toRefCell<Box<dyn TraitEngine<'tcx>>>:rust/src/librustc_typeck/check/mod.rs
Line 198 in fedce67
fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>, There may be other uses of
FulfillmentContextwithinlibrustc_typeck, you can ripgrep around. We should be able to convert them all.Step 2: Add compiler flag and alternative implementation
I'll leave this step for later. =)
- addedT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.A-trait-systemArea: Trait systemArea: Trait system
on Mar 9, 2018 cc @rust-lang/wg-traits -- this is the refactoring step that will allow us to introduce
-Zchalkand change implementations. Mentoring instructions are included, looking for someone to pick it up!This is the sort of structural change that is right up my alley (but I also have a non-zero number of things already on my plate so if someone else is looking for a thing to do, go for it)
- addedC-cleanupCategory: PRs that clean code up or issues documenting cleanup.Category: PRs that clean code up or issues documenting cleanup.
on Mar 10, 2018 This work looks not so hard for a rustlang newbie from the mentoring instructions up to now.
If I didn鈥檛 underestimate the difficulty, please consider me for this.
- changed the title
[-]introduce abstraction layer between trait solver and type checker[/-][+]馃洜 introduce abstraction layer between trait solver and type checker[/+]on Mar 12, 2018 @csmoe How goes? Have you had a chance to take a look at this yet? It would be very useful. =)
@nikomatsakis I have done mostly, but stuck at the lifetime errors.
This is basically done enough for now I think
The purpose of this issue is to setup a trait-solving structure that can change between the current trait solver and the type checker, allowing for us to easily switch to the chalk-style solving when a command line flag is given.
Currently, the interface between the two is the
FulfillmentContext, so we have a relationship like this:The first phase then is to introduce another layer in between, let's call it the
TraitEngine:When we're done with this phase, everything should work exactly the same, but that the type checker never interacts directly with the fulfillment context.