|
| 1 | +// Licensed to the .NET Foundation under one or more agreements. |
| 2 | +// The .NET Foundation licenses this file to you under the MIT license. |
| 3 | +// See the LICENSE file in the project root for more information. |
| 4 | + |
| 5 | +using System; |
| 6 | + |
| 7 | +public sealed class X: IComparable<X> |
| 8 | +{ |
| 9 | + int ival; |
| 10 | + |
| 11 | + public X(int i) |
| 12 | + { |
| 13 | + ival = i; |
| 14 | + } |
| 15 | + |
| 16 | + public int CompareTo(X x) |
| 17 | + { |
| 18 | + return ival - x.ival; |
| 19 | + } |
| 20 | + |
| 21 | + public bool Equals(X x) |
| 22 | + { |
| 23 | + return ival == x.ival; |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +public class Y<T> where T : IComparable<T> |
| 28 | +{ |
| 29 | + public static int C(T x, T y) |
| 30 | + { |
| 31 | + // IL here is |
| 32 | + // ldarga 0 |
| 33 | + // ldarg 1 |
| 34 | + // constrained ... callvirt ... |
| 35 | + // |
| 36 | + // The ldarga blocks both caller-arg direct sub and type |
| 37 | + // propagation since the jit thinks arg0 might be redefined. |
| 38 | + // |
| 39 | + // For ref types the ldarga is undone in codegen just before |
| 40 | + // the call so we end up with *(&arg0) and we know this is |
| 41 | + // arg0. Ideally we'd also understand that this pattern can't |
| 42 | + // lead to reassignment, but our view of the callee and what |
| 43 | + // it does with address-taken args is quite limited. |
| 44 | + // |
| 45 | + // Even if we can't propagate the caller's value or type, we |
| 46 | + // might be able to retype the generic __Canon for arg0 as the |
| 47 | + // more specific type that the caller is using (here, X). |
| 48 | + // |
| 49 | + // An interesting variant on this would be to derive from X |
| 50 | + // (say with XD) and have the caller pass instances of XD |
| 51 | + // instead of instances of X. We'd need to make sure we retype |
| 52 | + // arg0 as X and not XD. |
| 53 | + return x.CompareTo(y); |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +public class Z |
| 58 | +{ |
| 59 | + public static int Main() |
| 60 | + { |
| 61 | + // Ideally inlining Y.C would enable the interface call in Y |
| 62 | + // to be devirtualized, since we know the exact type of the |
| 63 | + // first argument. We can't get this yet. |
| 64 | + int result = Y<X>.C(new X(103), new X(3)); |
| 65 | + return result; |
| 66 | + } |
| 67 | +} |
0 commit comments