Skip to content

C#: Replace old-style unbind with pragmas.#21685

Merged
aschackmull merged 1 commit intogithub:mainfrom
aschackmull:csharp/unbind-new
Apr 10, 2026
Merged

C#: Replace old-style unbind with pragmas.#21685
aschackmull merged 1 commit intogithub:mainfrom
aschackmull:csharp/unbind-new

Conversation

@aschackmull
Copy link
Copy Markdown
Contributor

I found a couple of old-style "unbinds". These are straightforward to translate to binding pragmas, which results in a much improved join order:
Before:

Pipeline standard for Conversion::Variance::convTypeArguments/4#7e0015a0@410b3cwd was evaluated in 10 iterations totaling 6995ms (delta sizes total: 651293).
            263741       ~0%    {3} r1 = SCAN `Conversion::Variance::convRefTypeTypeArgumentIn/3#18d7491a#prev_delta` OUTPUT In.0, In.2, In.1
            263741       ~0%    {3}    | JOIN WITH `_Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_42#join_rhs_project#Conversion::GenericType.__#join_rhs` ON FIRST 2 OUTPUT Lhs.1, Lhs.0, Lhs.2
            263741       ~3%    {3}    | JOIN WITH `Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_24#join_rhs` ON FIRST 2 OUTPUT Lhs.2, Lhs.1, Lhs.0
            263741       ~0%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0
            263741       ~0%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2
            263741       ~2%    {4}    | JOIN WITH num#Conversion::Variance::TIn#d1e9c73a CARTESIAN PRODUCT OUTPUT Lhs.2, Lhs.0, Lhs.1, Rhs.0
                            
           1721838       ~0%    {3} r2 = SCAN `Conversion::Variance::convRefTypeTypeArgumentOut/3#0abae63d#prev_delta` OUTPUT In.1, In.2, In.0
           1721838       ~0%    {3}    | JOIN WITH `_Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_42#join_rhs_project#Conversion::GenericType.__#join_rhs` ON FIRST 2 OUTPUT Lhs.1, Lhs.0, Lhs.2
           1721838       ~0%    {3}    | JOIN WITH `Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_24#join_rhs` ON FIRST 2 OUTPUT Lhs.2, Lhs.1, Lhs.0
           1721838       ~0%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0
           1721838       ~0%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2
           1721838       ~0%    {4}    | JOIN WITH num#Conversion::Variance::TOut#3284c37f CARTESIAN PRODUCT OUTPUT Lhs.2, Lhs.0, Lhs.1, Rhs.0
                            
           1985579       ~0%    {4} r3 = r1 UNION r2
           1985579       ~0%    {4}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Lhs.2, Lhs.3
        1462314465   ~87737%    {5}    | JOIN WITH `Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_40123#join_rhs` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0, Lhs.3, Rhs.3
         755611249   ~72386%    {5}    | REWRITE WITH TEST InOut.4 <= InOut.1
                                {5}    | REWRITE WITH TEST InOut.1 <= InOut.4
         726087386  ~118582%    {4}    | SCAN OUTPUT In.2, In.0, In.4, In.3
         249676353   ~40703%    {4}    | AND NOT `Conversion::Variance::convTypeArguments/4#7e0015a0#prev`(FIRST 4)
                                return r3

After:

Pipeline standard for Conversion::Variance::convTypeArguments/4#7e0015a0@5905bcw1 was evaluated in 10 iterations totaling 53ms (delta sizes total: 647814).
         263741   ~0%    {3} r1 = SCAN `Conversion::Variance::convRefTypeTypeArgumentIn/3#18d7491a#prev_delta` OUTPUT In.1, In.2, In.0
         261109   ~0%    {3}    | JOIN WITH `_Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_42#join_rhs_project#Conversion::GenericType.__#join_rhs` ON FIRST 2 OUTPUT Lhs.0, Lhs.1, Lhs.2
         261109   ~5%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.2, Lhs.0, Lhs.1
         261109   ~0%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0
         261109   ~2%    {4}    | JOIN WITH num#Conversion::Variance::TIn#d1e9c73a CARTESIAN PRODUCT OUTPUT Lhs.0, Lhs.2, Lhs.1, Rhs.0
                     
        1721838   ~3%    {3} r2 = SCAN `Conversion::Variance::convRefTypeTypeArgumentOut/3#0abae63d#prev_delta` OUTPUT In.0, In.2, In.1
         386705   ~6%    {3}    | JOIN WITH `_Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_42#join_rhs_project#Conversion::GenericType.__#join_rhs` ON FIRST 2 OUTPUT Lhs.0, Lhs.1, Lhs.2
         386705   ~0%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.2, Lhs.0, Lhs.1
         386705   ~6%    {3}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.1, Lhs.2, Lhs.0
         386705   ~0%    {4}    | JOIN WITH num#Conversion::Variance::TOut#3284c37f CARTESIAN PRODUCT OUTPUT Lhs.0, Lhs.2, Lhs.1, Rhs.0
                     
         647814   ~0%    {4} r3 = r1 UNION r2
                         {4}    | AND NOT `Conversion::Variance::convTypeArguments/4#7e0015a0#prev`(FIRST 4)
         647814   ~4%    {4}    | SCAN OUTPUT In.1, In.0, In.2, In.3
         647814   ~0%    {4}    | JOIN WITH `project#Conversion::GenericType.getTypeArgument/1#dispred#2f38ae5e#2` ON FIRST 1 OUTPUT Lhs.2, Lhs.0, Lhs.1, Lhs.3
         647814   ~0%    {4}    | JOIN WITH `Conversion::Variance::getTypeArgumentRanked/4#e9a4f598_24#join_rhs` ON FIRST 2 OUTPUT Lhs.2, Lhs.1, Lhs.0, Lhs.3
                         return r3

@aschackmull aschackmull requested a review from a team as a code owner April 9, 2026 14:00
Copilot AI review requested due to automatic review settings April 9, 2026 14:00
@aschackmull aschackmull added the no-change-note-required This PR does not need a change note label Apr 9, 2026
@github-actions github-actions bot added the C# label Apr 9, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the C# conversion library to replace “old-style unbind” patterns with pragma[only_bind_into] binding pragmas in type-argument conversion predicates, improving join order/performance in the Conversion/Variance logic.

Changes:

  • Refactors Identity::convTypeArguments/3 to bind i via pragma[only_bind_into] instead of using an existential j with i <= j / j <= i.
  • Refactors Variance::convTypeArguments/4 similarly, and aligns subsequent calls to use i directly for the variance-specific predicates.
Show a summary per file
File Description
csharp/ql/lib/semmle/code/csharp/Conversion.qll Replaces old-style unbind idioms with binding pragmas in convTypeArguments predicates to improve join order/performance.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@aschackmull aschackmull merged commit dfa8d72 into github:main Apr 10, 2026
28 checks passed
@aschackmull aschackmull deleted the csharp/unbind-new branch April 10, 2026 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C# no-change-note-required This PR does not need a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants