-
Notifications
You must be signed in to change notification settings - Fork 826
Description
Following #17519, we should see if it is possible for the F# compiler to emit a call to the System.Diagnostics.Debug.Assert
overload that takes a message defaulting to CallerArgumentExpression
for all usages of the assert
keyword.
I.e., an expression like this
assert not true
would be translated to
System.Diagnostics.Debug.Assert (not true, "not true")
Likewise:
assert (x = 3)
β
System.Diagnostics.Debug.Assert ((x = 3), "(x = 3)")
etc.
The C# compiler now does this for System.Diagnostics.Debug.Assert(booleanExpr)
by means of the OverloadResolutionPriorityAttribute
, which F# does not currently support: #16967 (comment)
dotnet/csharplang#7906: developers can add weight to which methods are better in overload resolution. This seems unlikely to impact F# as much.
Want to point out one place this will intersect with F#. Consider that very likely
Debug
will end up looking like the following:public static class Debug { [OverloadResolutionPriority(-1)] public static void Assert(bool condition) { ... } public static void Assert(bool condition, [CallerArgumentExpression] string? message = "") { ... } }Nothing will break for F# here when this happens, code will still compile as it used to. The experience for C# though will improve from a lot of
Debug.Assert failed
messages to the actual expression that passed into the assert. This is one part I thought might be interesting to F# .
See the BCL source:
[Conditional("DEBUG")]
[OverloadResolutionPriority(-1)] // lower priority than (bool, string) overload so that the compiler prefers using CallerArgumentExpression
public static void Assert([DoesNotReturnIf(false)] bool condition) =>
Assert(condition, string.Empty, string.Empty);
[Conditional("DEBUG")]
public static void Assert([DoesNotReturnIf(false)] bool condition, [CallerArgumentExpression(nameof(condition))] string? message = null) =>
Assert(condition, message, string.Empty);
We could in theory do this in the F# compiler specifically for the assert
keyword, without needing to support OverloadResolutionPriorityAttribute
in general, by emitting a call to the new overload when it is available here:
fsharp/src/Compiler/Checking/Expressions/CheckExpressions.fs
Lines 7699 to 7706 in 69be2cd
// Check an 'assert x' expression. | |
and TcAssertExpr cenv overallTy env (m: range) tpenv x = | |
let synm = m.MakeSynthetic() // Mark as synthetic so the language service won't pick it up. | |
let callDiagnosticsExpr = SynExpr.App (ExprAtomicFlag.Atomic, false, mkSynLidGet synm ["System";"Diagnostics";"Debug"] "Assert", | |
// wrap an extra parentheses so 'assert(x=1) isn't considered a named argument to a method call | |
SynExpr.Paren (x, range0, None, synm), synm) | |
TcExpr cenv overallTy env tpenv callDiagnosticsExpr |
Metadata
Metadata
Assignees
Labels
Type
Projects
Status