# jack lcnr niko hackmd
## 2022-09-26
- current system does both: error reporting + logic
- could also rewrite logic, keep current for errors
- rewrite errors seems good :grin:
two possible strategies
* build a new diagnostic solver, leveraging "evaluation"-style queries
* start to work on the logic solver once that is in place
* once logic solver is done, can evaluate how best to merge
* unknown: "how long will it take" until it's ready
* danger:
* new diganostic solver may not be that close to logic solver in the end
* if we've built stuff on end, requires a double migration
* but:
* we can start building diagnostic stuff sooner and maybe that's helpful
* build a query for diagnostics based on existing solver, transition other code to logic slver, then create new diagnostic solver
* pro:
* errors probably fairly stable, hopefully easy to do
* unknown:
chalk integration thoughts:
- diagnostic reporting as a distinct thing
- will wind up using existing solver (or something based on it) the longest
- coherence as first use of logic solver
- creating predicate types (jackh726)
- stuck in some const thing :)
- uses of selection:
- codegen
- const eval (to find the method impl)
- projection
- remove uses of projection
- remove uses of fulfillment cx
selection vs projection, are these distinct concepts?
```rust
trait MyIterator<T> { fn next(&mut self) -> Option<T>; }
impl<T> MyIterator<T> for Vec<T> {
// ^ ^
// in HAskell land, this is called "functional dependency"
// and it's the more general version of an associated type
fn next(&)
}
impl<T> Iterator for Vec<T> {
type Item = T;
}
```
* interface niko is proposing is
* `solve obligation` yields back
* true (subst)
* ambig (subst)
* false
* and one obligation is
* `normalize(<T as Trait>::method_name, ?U)`
* get back a value of `?U`
* but
* then `?U` needs to be able to express everything
* option 1:
* add everything to types
* option 2:
* add a new kind for things that are not types
```rust
struct Foo { }
trait SomeOperation {
unsafe fn do_it();
}
impl SomeOperation for Foo {
#[refine]
fn do_it() {
// NB: not unsafe
}
}
fn main() {
let x : /* type from impl */ = <Foo as SomeOperation>::do_it;
let x : /* ? */ = <dyn SomeOperation as SomeOperation>::do_it;
// is this not (the equivalent of) VtableShim(DefId)?
let x : /* ? */ = <Foo as Drop>::drop;
// is this not DropGlue(Foo)?
}
```
## initial start
- https://github.com/rust-lang/rust/pull/102016
- merge lcnr pr
- can also merge jack pr
- rewrite to use query normalize (lcnr will look at it)
- longer term: ParamEnv -> ParamEnv
- error reporting select/fulfill
## lcnr fulfill
two different trait solvers:
- 1 for the happy path, doesn't care about errors:
- fast, sound
- 1 for error reporting
- slow, doesn't have too much about being sound
how the fast one should work:
```rust
fn fullfill_all() {
while changed {
for o in obligation {
let result = evaluation_query(o);
apply_result(result);
}
}
}
```
- `evaluation_query` returns:
- current select/eval
- sucess, ambig, or error
- not currently done
- On sucess: What impl was chosen?? (maybe as a separate entry point)
- (maybe) on which inference vars it's stuck
- which inference vars it constrained
- region obligations
### first step
stop using inner working of fullfil in errors by only using the `root_obligation` of `FulfillmentError`s for error reporting and recomputing everything else. Once that is done, the trait system can be improved.
The good thing, this doesn't interact too much with other parts of rustc while being worked on:
```diff
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index efdb1ace139..fa570b89f5f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -128,6 +128,15 @@ fn report_fulfillment_errors(
body_id: Option<hir::BodyId>,
fallback_has_occurred: bool,
) -> ErrorGuaranteed {
+ if self.tcx.sess.opts.unstable_opts.new_type_errors {
+ return super::error_reporting_new::report_fulfillment_errors_new(
+ self,
+ errors.into_iter().map(|f| f.root_obligation.clone()).collect(),
+ body_id,
+ fallback_has_occurred,
+ );
+ }
+
#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
predicate: ty::Predicate<'tcx>,
```