I think "limited global inference" isn't specific enough to make it clear just how limited it is.
The Rust compiler always did, and still does, inference only in "function/constant body + nested closures" groups.
impl Trait
and still-unimplemented features like typeof
, const X: _
and diagnostic-only "-> _
", share a certain property that makes them much simpler than global type inference:
Full type information is required to be locally inferred before being made available to the rest of the world, and cycles are forbidden (i.e. the type information dependencies between non-closure fn
/const
bodies forms a DAG).
Note that it also must be easy to tell, syntactically and/or by using name resolution results, the direction of edges on that DAG, e.g. whether a const
's type is declared and used for checking its body ("inwards"), or whether the type obtained by checking the body should be used as the type of the const
("outwards").
I'm not sure I understand the context for this. Are we talking about some impl Bar for S<_>
that wants to see the type of x
from its construction, i.e. foo()
?
The main problem I see with a x: _
field is that it needs the body of the original function to fully type-check before it can (soundly) have a "globally available type". We could make it so the original function sees the "in-progress type", since it's the one responsible for its inference (if we can even determine that's the case).
We do something like this for closures, but those are more limited in their interactions, than struct/enum fields.
A while back I "proposed" a syntax like this, for a similar purpose:
let s = struct {
x: foo(),
y: Default::default(),
} impl Bar {
fn baz(&self) -> Self {
Self {
x: self.x.clone(),
y: -1,
}
}
}
I included a field y
that we could infer from the baz
method into the original function, but we can only do this if we treat such an impl
body like we treat closures, which requires that the struct
is "globally unnameable".
And this is where some subtlety comes into play: items defined inside a function body are still "globally relevant", even if perhaps somewhat private - the trait system lets you do e.g.:
impl OutsideTrait for OutsideType {
type AssocType = S;
}
I don't even know that my proposed solution is fully workable but it's very unlikely we'll ever implement anything in rustc
that doesn't have its type information dependency DAG and inference groups simple and computed from syntax/name-resolutions (Haskell does something similar, after all, it's just simpler in their case because name resolution is enough AFAICT).
Which means that soundness issues would be caught by "cyclic dependency" compiler errors, with no truly global mutable state in sight.