Stream: t-compiler/rust-analyzer

Topic: #3750


Lukas Wirth (Oct 01 2020 at 14:15, on Zulip):

I'd be interested in working on https://github.com/rust-analyzer/rust-analyzer/issues/3750 aka shortening iterator type hints, but frankly speaking I'm missing quite a lot of knowledge when it comes to working with the hirdb. How would I go about actually checking if a type implements the Iterator trait and how would I find the iterator trait in the first place as it is no lang item?

Kirill Bulatov (Oct 02 2020 at 08:07, on Zulip):

I cannot help you with the original question alas, but would like to warn you that testing this feature might be hard: RA does not use stdlib in its regular tests, so there will be no Iterator trait and related.

Lukas Wirth (Oct 02 2020 at 08:09, on Zulip):

Ye that I know as well, so I figured using crate names in the tests via the comment annotations but those seem to break the inlay hints for some reason.

Kirill Bulatov (Oct 02 2020 at 08:25, on Zulip):

It's hard to say what's broken without seeing the test code, but if you decided to emulate the actual Iterator trait this way, this might be very hard, see https://github.com/rust-analyzer/rust-analyzer/pull/5997#issuecomment-694173448

Lukas Wirth (Oct 02 2020 at 08:32, on Zulip):

Ah I see that makes sense, well with broken I meant type resolution just completely failed when I tried using the comment annotation syntax.

Lukas Wirth (Oct 06 2020 at 13:50, on Zulip):

I'm tackling this once more and got the test structure to not fail type resolution for me now( I imagine I just made a few dumb mistakes before), and now I have both the struct to check whether it implements Iterator and the Iterator trait itself. But the question is still there as to how to check if the struct implements said trait and if it does figure out what the the impl's Item type is. Type::impls_trait doesn't really work as I don't know the Item associated type's type.

Lukas Wirth (Oct 06 2020 at 13:53, on Zulip):

I imagine to do this one would require things that aren't exposed directly atm, similar to how Type::impls_future works? But even then that would only help in figuring out if it implements the trait, that still leaves the task of figuring out the item type.

Florian Diebold (Oct 06 2020 at 13:58, on Zulip):

Type::impls_trait should work to check whether the type implements Iterator. Normalizing the associated type would be a separate step. We could add a method to Type that takes a TypeAlias (and &[Type] for potential type parameters for the trait) and does the normalization, it'd look pretty similar to impls_trait except it'd use Obligation::Projection

Lukas Wirth (Oct 06 2020 at 14:08, on Zulip):

Type::impls_trait should work to check whether the type implements Iterator

Ah okay you are right this works, my specific test case didn't seem to work due to how function pointer types work(looks like fn foo() -> Option<i32> is not considered equal with the type arg fn() -> Option<i32>)

Florian Diebold (Oct 06 2020 at 14:30, on Zulip):

yes, those are different types

Florian Diebold (Oct 06 2020 at 14:35, on Zulip):

(every function has its own type; which is not the same as the function pointer type, but can be coerced to that)

Lukas Wirth (Oct 06 2020 at 14:50, on Zulip):

That they are different types I knew, but I thought the coercion would allow the impl to work :sweat_smile: Well not that it matters.

Lukas Wirth (Oct 06 2020 at 14:51, on Zulip):

Im having trouble understanding how to use the ProjectionPredicate now tho:

    pub fn normalize_trait_assoc_type(
        &self,
        db: &dyn HirDatabase,
        trait_: Trait,
        args: &[Type],
        alias: TypeAlias,
    ) -> bool {
        let subst = Substs::build_for_def(db, trait_.id)
            .push(self.ty.value.clone())
            .fill(args.iter().map(|t| t.ty.value.clone()))
            .build();
        let predicate = ProjectionPredicate {
            projection_ty: ProjectionTy { associated_ty: alias.id, parameters: subst },
            ty: <--- ???
        };
        let goal = Canonical {
            value: hir_ty::InEnvironment::new(
                self.ty.environment.clone(),
                hir_ty::Obligation::Projection(predicate),
            ),
            kinds: Arc::new([]), <--- ???
        };

        db.trait_solve(self.krate, goal).is_some()
    }

This is what I roughly have, I think I got most of it right but there are two parts Im uncertain about/I dont really understand what to do with them( annotated with <---)

Florian Diebold (Oct 06 2020 at 14:51, on Zulip):

nope, coercions only apply in certain places where the target type is known :sweat_smile:

Lukas Wirth (Oct 06 2020 at 14:54, on Zulip):

Tried to understand it better by looking at other places that use the ProjectionPredicate but that didn't help too much. :sweat_smile:

Florian Diebold (Oct 06 2020 at 14:55, on Zulip):

ah yeah, what you need is to put a variable into the ty so that you get as an answer what the normalized type is. So I think that would need to be Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)). And then kinds defines what kind of variable that is, so you need one element there with TyKind::General

Lukas Wirth (Oct 06 2020 at 15:03, on Zulip):

Ah perfect this seems to work, I had the BoundVar part before but ended up with an oob panic probably cause I was missing the kinds var. Thanks a lot :smile:

Last update: Jul 27 2021 at 22:00UTC