- Notifications
You must be signed in to change notification settings - Fork 10.6k
Description
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. 🙂