-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Generalization in type inference needs to generalize unbound type variables too #18653
Comments
Hmm, the fix as expressed seems to have some issues as well, particularly around the test for #11384. |
(The problem with the fix, for reference, is that it creates an unbounded number of type variables, so somehow inference seems to get into a loop. I haven't dug deeply enough yet to really understand what's going on; I'm hoping to workaround this issue instead for time being in the place it's blocking me.) |
looks like some mix of rust-lang#18653 and `projection_must_outlive`, but that needs to be investigated further (crater run?)
looks like some mix of rust-lang#18653 and `projection_must_outlive`, but that needs to be investigated further (crater run?)
By RFC1214: > Before calling a fn, we check that its argument and return types are WF. The previous code only checked the trait-ref, which was not enough in several cases. As this is a soundness fix, it is a [breaking-change]. Some new annotations are needed, which I think are because of #18653 and the imperfection of `projection_must_outlive` (that can probably be worked around by moving the wf obligation later). Fixes #28609 r? @nikomatsakis
An updated code sample: use std::cell::RefCell;
enum Wrap<A> {
WrapSome(A),
WrapNone
}
use Wrap::*;
struct T;
struct U;
trait Get<T: ?Sized> {
fn get(&self) -> &T;
}
impl Get<MyShow + 'static> for Wrap<T> {
fn get(&self) -> &(MyShow + 'static) {
static x: usize = 42;
&x
}
}
impl Get<usize> for Wrap<U> {
fn get(&self) -> &usize {
static x: usize = 55;
&x
}
}
trait MyShow { fn dummy(&self) { } }
impl<'a> MyShow for &'a (MyShow + 'a) { }
impl MyShow for usize { }
fn constrain<'a>(rc: RefCell<&'a (MyShow + 'a)>) { }
fn main() {
let mut collection: Wrap<_> = WrapNone;
{
let __arg0 = Get::get(&collection);
let __args_cell = RefCell::new(__arg0);
constrain(__args_cell);
}
collection = WrapSome(T);
}fn constrain<'a>(rc: RefCell<&'a (MyShow + 'a)>) { }
fn main() {
let mut collection: Wrap<_> = WrapNone;
{
let __arg0 = Get::get(&collection);
let __args_cell = RefCell::new(__arg0);
constrain(__args_cell);
}
collection = WrapSome(T);
} Today's error:
|
I've been doing some investigation here. Just backporting the patch above definitely leads to trouble (unconstrained type variables, at the moment). I'm trying to figure out the full story here, I'm not quite sure what's going wrong yet. |
Update: I've got this mostly working atop of PR #40570. Still working through some minor changes in behavior in the compile-fail tests, trying to decide how many lengths to go through to preserve the existing errors. Not sure yet of the best way to produce a backportable patch. |
When we are generalizing a super/sub-type, we have to replace type variables with a fresh variable (and not just region variables). So if we know that `Box<?T> <: ?U`, for example, we instantiate `?U` with `Box<?V>` and then relate `Box<?T>` to `Box<?V>` (and hence require that `?T <: ?V`). This change has some complex interactions, however: First, the occurs check must be updated to detect constraints like `?T <: ?U` and `?U <: Box<?T>`. If we're not careful, we'll create a never-ending sequence of new variables. To address this, we add a second unification set into `type_variables` that tracks type variables related through **either** equality **or** subtyping, and use that during the occurs-check. Second, the "fudge regions if ok" code was expecting no new type variables to be created. It must be updated to create new type variables outside of the probe. This is relatively straight-forward under the new scheme, since type variables are now independent from one another, and any relations are moderated by pending subtype obliations and so forth. This part would be tricky to backport though. cc rust-lang#18653 cc rust-lang#40951
This is fixed by #40570 |
Hash completion items to properly match them during /resolve
I came across this subtle bug while working on the operator-dispatch branch. It has taken me quite some time to reduce it to a standalone test case. The fundamental problem is that, as currently implemented, when the type inferencer process a constraint like
&'_0 _1 <: _2
, where'_0
,_1
, and_2
are variables, it will create a new region variable but leave the type variable alone, so that_2
winds up being instantiated with&'_3 _1
, where_0 : _3
. That is good as far as it goes, but if_1
winds up being instantiated with something that contains regions, we lose degrees of freedom. Imagine for example that_1
winds up being instantiated with&'_4 int
, then (substituting back to our original constraint), we have&'_0 &'_4 int <: &'_3 &'_4 int
where'_0 : '_3
. Again, this is true, but not as flexible we as we might like, since'_4
appears on both sides, depriving the region inferencer the change to adjust them independently.To actually make this bug have a problem you seem to need a lot of moving ingredients. Here is my reduced (but probably not maximally...) example of code that ought to compile but doesn't:
I've spelled out what happens in comments. The fix for this is this simple patch:
which causes unbound variables to be replaced with fresh variables. I am unsure of the performance impact of this patch, though, and I want to test.
The text was updated successfully, but these errors were encountered: