Skip to content
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

Refactor ProgramClauseData to remove Implies variant #514

Merged
merged 4 commits into from
Jun 13, 2020
Merged

Refactor ProgramClauseData to remove Implies variant #514

merged 4 commits into from
Jun 13, 2020

Conversation

declanvk
Copy link
Contributor

@declanvk declanvk commented Jun 11, 2020

Closes #511

As far as I can tell, I didn't change the logic of anything. However, when I checked the test suite there were still some failing tests. I've listed them here just in case they are relevant.

Initially failing tests

test test::coherence::downstream_impl_of_fundamental_43355 ... FAILED
test test::coherence::fundamental_traits ... FAILED
test test::coherence::local_negative_reasoning_in_coherence ... FAILED
test test::coherence::nonoverlapping_assoc_types ... FAILED
test test::coherence::overlapping_assoc_types ... FAILED
test test::coherence::overlapping_assoc_types_error ... FAILED
test test::coherence::two_blanket_impls ... FAILED
test test::misc::flounder_ambiguous ... FAILED
test test::projection::normalize_into_iterator ... FAILED
test test::projection::projection_from_env_a ... FAILED
test test::projection::projection_from_env_slow ... FAILED
test test::wf_goals::struct_wf ... FAILED
test test::wf_lowering::copy_constraints ... FAILED
test test::wf_lowering::drop_constraints ... FAILED
test test::wf_lowering::implied_bounds ... FAILED

Looking into the reason now.

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

Just quickly looking over this, the changes look correct. So there's something a bit more subtle here that I'll have to look more deeply at.

@declanvk
Copy link
Contributor Author

My best guess for the error is that by introducing an empty Binders it still changes the meaning, especially with respect to folding, via:

fn fold_with<'i>(
&self,
folder: &mut dyn Folder<'i, I, TI>,
outer_binder: DebruijnIndex,
) -> Fallible<Self::Result>
where
I: 'i,
TI: 'i,
{
let Binders {
binders: self_binders,
value: self_value,
} = self;
let value = self_value.fold_with(folder, outer_binder.shifted_in())?;
let binders = VariableKinds {
interned: TI::transfer_variable_kinds(self_binders.interned().clone()),
};
Ok(Binders::new(binders, value))
}

I managed to reproduce the same set of errors (the ones in the list above) with this commit alone: https://github.com/declanvk/chalk/commit/e96058569721eb71587ea294b82ee9c527ebcbf3

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

Your example made me realize what the problem probably is. Where we used to construct an Implies, but now what essentially was a ForAll, if there are bound vars in the ProgramClauseImplication, then we have to shift them in.

chalk-ir/src/cast.rs Outdated Show resolved Hide resolved
chalk-solve/src/clauses/builder.rs Show resolved Hide resolved
@declanvk
Copy link
Contributor Author

That fixed it! I had to export the Shift folder from chalk-ir, let me know if I should refactor this at all.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

I'm not 100% sure if I think we should change this here or in follow-up PRs, but I do feel like probably the "cast" impls shouldn't be doing shifting.

.intern(interner)
};

ProgramClauseData(Binders::empty(interner, implication.shifted_in(interner)))
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should make a helper for this -- i.e., for inserting a binders into something with no captures.

But also, this strikes me as a bit dubious. I wonder if in the Cast routines we could, instead of shifting, assert that !implication.needs_shift(interner).

In particular, I feel like we don't normally embed ProgramClauses within other binders, so I wouldn't expect any references to bound variables in outer scopes -- and if there are any, it feels like the "intent" from a cast operation is sort of ambiguous to me.

So I'd be happier if we don't use cast in these cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

That said, it seems like needs_shift needs to be rewritten from a hard-coded helper routine to a method that is available on anything that implements the Visit trait.

@jackh726
Copy link
Member

Yeah, that was going to be my next comment: if we got rid of the Cast impl for one that does the shift, can we find the root "cause" there

@nikomatsakis
Copy link
Contributor

I wonder if those cast impls are even used. Probably.

@jackh726
Copy link
Member

@nikomatsakis nope, neither Cast impl is used :/

@nikomatsakis
Copy link
Contributor

Well then let's just remove them and avoid the problem =)

@declanvk
Copy link
Contributor Author

I removed the Cast impls and fixed the locations that failed by wrapping empty Binders and unconditionally applying shifted_in. I was contemplating some sort of Binders helper that looks like:

impl<I, T> Binders<T>
where
    T: Visit<I> + Fold<I, I, Result = T> + HasInterner<Interner = I>,
    I: Interner,
{
    pub fn empty_shift_if_required(interner: &T::Interner, value: T) -> Self {
        let value = if value.has_free_vars(interner) {
            // If this type contains "bound" types/lifetimes, then it
            // needs to be shifted across binders.
            value.shifted_in(interner)
        } else {
            value
        };

        Self::empty(interner, value)
    }
}

instead of having to apply shifted_in every time Binders::empty is used.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

OK, I know I'm changing my mind, but seeing the diff makes me want to keep the impls -- or at least the one that goes from DomainGoal to ProgramClause.

It's hard to figure out the best API for dealing with debruijn indices, but I do think it's nice to have a way to say "here is some fact that contains types etc that are in scope, let me construct a program clause out of it" and not have to worry about the forall binder that would otherwise get added there.

chalk-ir/src/cast.rs Show resolved Hide resolved
chalk-ir/src/cast.rs Outdated Show resolved Hide resolved
chalk-ir/src/lib.rs Outdated Show resolved Hide resolved
chalk-solve/src/wf.rs Outdated Show resolved Hide resolved
@nikomatsakis
Copy link
Contributor

@declanvk

I was contemplating some sort of Binders helper that looks like

I would perhaps instead just make the shifted_in helper check if there are no free variables and return a clone if so -- although there is a bit of a complication in that we might need to account for the possibility of T::Result not being equal to T.

@nikomatsakis
Copy link
Contributor

But in any case that's just an optimization, so let's address it separately. It actually fits in with another theme of work I think we should pursue, which is propagating "flags" and the like, similar to what rustc has, which can enable us to create fast-paths quite efficiently.

@declanvk
Copy link
Contributor Author

I removed the unused Cast impls and put back the CastTo<ProgramClause<I>> for T one with a shifted_in inside of it.

Should I rebase/squash to address conflicts?

@jackh726
Copy link
Member

@declanvk Squashing doesn't matter. Rebase yes :)

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

Seems like rebase problems with recursive.rs

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

LGTM. I'll merge when CI is working again.

Just saw, guess CI is working again.

@jackh726 jackh726 merged commit 9846bdd into rust-lang:master Jun 13, 2020
@declanvk declanvk deleted the issue-511 branch June 13, 2020 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

simplify ProgramClauseImplication
3 participants