Terminal: Port to [NotNullWhen(true)] attribute#68
Terminal: Port to [NotNullWhen(true)] attribute#68XuuXiaolan merged 1 commit intoTeamXiaolan:mainfrom
Conversation
|
Actually there are more methods with an
and I'm not sure how to rename them! |
|
naming do be hard, that [NotNullWhen] attribute is pretty neat 👀 |
|
If changing argument type from Can't say for sure yet. |
Honestly i'm not sure anyone is using any of this (outside dawnlib itself internally) so I wouldn't worry too much about breaking changes. These were only just recently added over the last week or two and I still had adding documentation on my to-do list lol |
5e4dee9 to
a18af6e
Compare
|
I played around with attributes and signatures on a scratch project, and in Discord chat we came to a conclusion that adding The branch was force-pushed, the description was updated accordingly. For the record, here is the file I compiled: Extentions.csusing System.Diagnostics.CodeAnalysis;
namespace DotNetAbiOutVarNullable;
public class ClassToExtend
{
}
public class ClassArg
{
public string Keyword = "";
}
public static class ClassExtensions
{
public static bool TryClassNullable(this ClassToExtend self, string input, [NotNullWhen(true)] out ClassArg? arg)
{
arg = null;
return false;
}
public static bool TryClassNonNull(this ClassToExtend self, string input, out ClassArg arg)
{
arg = null!;
return false;
}
}
public struct StructArg
{
public int Price;
}
public static class StructExtensions
{
public static bool TryStructNullable(string input, [NotNullWhen(true)] out StructArg? word)
{
word = null;
return false;
}
public static bool TryStructNonNull(string input, out StructArg word)
{
word = new StructArg()
{
Price = 42,
};
return false;
}
}And this is how it looks like in ILSpy with "Select language to decompile to (Alt+L)" drop-down set to IL: ClassExtensions.class public auto ansi abstract sealed beforefieldinit DotNetAbiOutVarNullable.ClassExtensions
extends [netstandard]System.Object
{
.custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
.custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
// Methods
.method public hidebysig static
bool TryClassNullable (
class DotNetAbiOutVarNullable.ClassToExtend self,
string input,
[out] class DotNetAbiOutVarNullable.ClassArg& arg
) cil managed
{
.custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
.param [3]
.custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 02 00 00
)
.custom instance void [netstandard]System.Diagnostics.CodeAnalysis.NotNullWhenAttribute::.ctor(bool) = (
01 00 01 00 00
)
// Method begins at RVA 0x20b0
// Header size: 12
// Code size: 10 (0xa)
.maxstack 2
.locals init (
[0] bool
)
IL_0000: nop
IL_0001: ldarg.2
IL_0002: ldnull
IL_0003: stind.ref
IL_0004: ldc.i4.0
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method ClassExtensions::TryClassNullable
.method public hidebysig static
bool TryClassNonNull (
class DotNetAbiOutVarNullable.ClassToExtend self,
string input,
[out] class DotNetAbiOutVarNullable.ClassArg& arg
) cil managed
{
.custom instance void [netstandard]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = (
01 00 00 00
)
// Method begins at RVA 0x20c8
// Header size: 12
// Code size: 10 (0xa)
.maxstack 2
.locals init (
[0] bool
)
IL_0000: nop
IL_0001: ldarg.2
IL_0002: ldnull
IL_0003: stind.ref
IL_0004: ldc.i4.0
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method ClassExtensions::TryClassNonNull
} // end of class DotNetAbiOutVarNullable.ClassExtensionsStructExtensions.class public auto ansi abstract sealed beforefieldinit DotNetAbiOutVarNullable.StructExtensions
extends [netstandard]System.Object
{
.custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
01 00 01 00 00
)
.custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
01 00 00 00 00
)
// Methods
.method public hidebysig static
bool TryStructNullable (
string input,
[out] valuetype [netstandard]System.Nullable`1<valuetype DotNetAbiOutVarNullable.StructArg>& word
) cil managed
{
.param [2]
.custom instance void [netstandard]System.Diagnostics.CodeAnalysis.NotNullWhenAttribute::.ctor(bool) = (
01 00 01 00 00
)
// Method begins at RVA 0x20e0
// Header size: 12
// Code size: 14 (0xe)
.maxstack 1
.locals init (
[0] bool
)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: initobj valuetype [netstandard]System.Nullable`1<valuetype DotNetAbiOutVarNullable.StructArg>
IL_0008: ldc.i4.0
IL_0009: stloc.0
IL_000a: br.s IL_000c
IL_000c: ldloc.0
IL_000d: ret
} // end of method StructExtensions::TryStructNullable
.method public hidebysig static
bool TryStructNonNull (
string input,
[out] valuetype DotNetAbiOutVarNullable.StructArg& word
) cil managed
{
// Method begins at RVA 0x20fc
// Header size: 12
// Code size: 31 (0x1f)
.maxstack 3
.locals init (
[0] valuetype DotNetAbiOutVarNullable.StructArg,
[1] bool
)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldloca.s 0
IL_0004: initobj DotNetAbiOutVarNullable.StructArg
IL_000a: ldloca.s 0
IL_000c: ldc.i4.s 42
IL_000e: stfld int32 DotNetAbiOutVarNullable.StructArg::Price
IL_0013: ldloc.0
IL_0014: stobj DotNetAbiOutVarNullable.StructArg
IL_0019: ldc.i4.0
IL_001a: stloc.1
IL_001b: br.s IL_001d
IL_001d: ldloc.1
IL_001e: ret
} // end of method StructExtensions::TryStructNonNull
} // end of class DotNetAbiOutVarNullable.StructExtensionsAs you can see, both methods in |
In case of public methods, a brief investigation proved that `?` nullable mark is not part of method signature when applied to reference types; it just becomes a yet another parameter attribute in IL, namely [NullableAttribute], so it is a backward-compatible change that doesn't break ABI. Regarding source compatibility, API users might get a new warning CS8600 if they are using concrete type instead of a `var` keyword: > Converting null literal or possible null value to non-nullable type.
a18af6e to
068d40c
Compare
In case of public methods, a brief investigation proved that
?nullable mark is not part of method signature when applied to reference
types; it just becomes a yet another parameter attribute in IL,
namely [NullableAttribute], so it is a backward-compatible change that
doesn't break ABI. Regarding source compatibility, API users might get
a new warning CS8600 if they are using concrete type instead of a
varkeyword: