Skip to content

[SourceKit] Add fully resolved generics into CursorInfo #68908

@barinsim

Description

@barinsim

Motivation
In SourceKit there's currently no reliable way to fully resolve references of generic declarations. For example, in this snippet:

struct A<T> { init<F>(_ f: F) {} func foo<E>(_ e: E) -> E { return e } } let a = /*<caret1>*/A<Double>("hello") let fooResult = a./*<caret2>*/foo(42)

For cursor info on <caret1> I would like to know what types were substituted for T and F (the answer is Double and String). Where do I find the declarations for Double and String? Where do I find the declarations for T and E?

Similarly for <caret2>, just for the type parameters T and E.

Solution

We can add key.substitutions field into the source.request.cursorinfo response. The output for <caret2> would look like this (omitting unimportant fields):

{ key.kind: source.lang.swift.ref.function.method.instance, key.name: "foo(_:)", key.usr: "s:4main1AV3fooyqd__qd__lF", key.line: 3, key.column: 10, key.typename: "<T, E> (A<T>) -> (E) -> E", key.substitutions: [ { key.substitution_mapping: "T -> Double" }, { key.substitution_mapping: "E -> Int" } ], } 

Which provides basic type information for the substitutions. To resolve type declarations for these types (T, E, Double, Int) we can add boolean key.expand_substitutions field into the request. If set to true the response contains the resolved declarations in the already existing key.secondary_symbols field and additional usr reference in the key.substitutions. For <caret2> this would look like this (omitting unimportant fields):

{ key.kind: source.lang.swift.ref.function.method.instance, key.name: "foo(_:)", key.usr: "s:4main1AV3fooyqd__qd__lF", key.line: 3, key.column: 10, key.typename: "<T, E> (A<T>) -> (E) -> E", key.substitutions: [ { key.substitution_mapping: "T -> Double", key.generic_type_usr: "s:4main1AV1Txmfp", key.replacement_type_usr: "s:Sd" }, { key.substitution_mapping: "E -> Int", key.generic_type_usr: "s:4main1AV3fooyqd__qd__lF1EL_qd__mfp", key.replacement_type_usr: "s:Si" } ], key.secondary_symbols: [ { key.kind: source.lang.swift.ref.struct, key.name: "Double", key.usr: "s:Sd", key.typename: "Double.Type", key.is_system: 1, key.typeusr: "$sSdmD", key.groupname: "Math/Floating", key.modulename: "Swift", }, { key.kind: source.lang.swift.ref.generic_type_param, key.name: "T", key.usr: "s:4main1AV1Txmfp", key.line: 1, key.column: 10, key.filepath: <filepath>, key.typename: "T.Type", }, { key.kind: source.lang.swift.ref.struct, key.name: "Int", key.usr: "s:Si", key.typename: "Int.Type", key.is_system: 1, key.typeusr: "$sSimD", key.groupname: "Math/Integers", key.modulename: "Swift", }, { key.kind: source.lang.swift.ref.generic_type_param, key.name: "E", key.usr: "s:4main1AV3fooyqd__qd__lF1EL_qd__mfp", key.line: 3, key.column: 14, key.filepath: <filepath>, key.typename: "E.Type", } ] } 

In case this is a desirable improvement, I would be happy to work on this. I already implemented the described solution in this draft #68909. Of course, I would welcome suggestions and other possible solutions. 🙂

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureA feature request or implementationtriage neededThis issue needs more specific labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions