| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The compile-time expression '<Expression>' cannot be set here because the assignment is in a block whose execution depends on a run-time condition ('<RunTimeCondition>'). In such a block, only compile-time local variables declared in the block can be set. |
Cause
In a T# template, compile-time code runs once, while Metalama generates the target code. Run-time statements such as an if with a run-time condition, a catch or finally block, or a local function are only emitted into the generated code: whether their body executes is decided later, when the program runs. When Metalama expands the template, it always walks through such a block, so it can't know whether a compile-time assignment in that block should happen.
For this reason, Metalama reports LAMA0280 when, inside a run-time-conditional block, a template modifies a compile-time expression that isn't a local variable. The modification can be an assignment, a compound assignment like +=, an increment or decrement, or passing the expression as an out or ref argument. The expression can be, for instance, a field or property of a compile-time object, an array element, or an element of a tuple on the left side of a deconstructing assignment such as (i, j) = (3, 4). Each element of the tuple is checked separately, so the assignment is accepted when all its elements are compile-time local variables declared in the block. The first placeholder of the message is the expression, and the second one describes the run-time condition. For a compile-time local variable declared outside the block, Metalama reports LAMA0108 instead.
In the following example, the aspect counts null arguments with a property of a compile-time object, but the property is incremented inside an if statement whose condition, parameter.Value == null, is a run-time expression.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0280.Error;
5
6[CompileTime]
7internal class ArgumentStatistics
8{
9 public int NullCount { get; set; }
10}
11
12public class LogNullArgumentsAttribute : OverrideMethodAspect
13{
14 public override dynamic? OverrideMethod()
15 {
16 var statistics = new ArgumentStatistics();
17
18 foreach ( var parameter in meta.Target.Parameters )
19 {
20 if ( parameter.Value == null )
21 {
22 // Error: a property of a compile-time object is incremented under a run-time condition.
Error LAMA0280: The compile-time expression 'statistics.NullCount' cannot be set here because the assignment is in a block whose execution depends on a run-time condition ('if ( parameter.Value == null )'). In such a block, only compile-time local variables declared in the block can be set.
23 statistics.NullCount++;
24 }
25 }
26
27 Console.WriteLine( $"{meta.Target.Method.Name} received {statistics.NullCount} null argument(s)." );
28
29 return meta.Proceed();
30 }
31}
32
1namespace Doc.LAMA0280.Error;
2
3internal class CustomerService
4{
5 [LogNullArguments]
6 public void Register( string? name, string? email ) { }
7}
8
Resolution
Depending on your intent, do one of the following:
- If the value depends on run-time data, use a run-time variable: initialize a local variable with a literal, without meta.CompileTime. Metalama then emits the variable and its modifications into the generated code. The following example uses this fix.
- If the assignment doesn't depend on the run-time condition, move it out of the run-time-conditional block.
- If the condition can be evaluated at compile time, make it a compile-time expression, for example by testing properties of meta.Target instead of run-time values, so that the
ifstatement becomes compile-time.
1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0280.Fixed;
5
6public class LogNullArgumentsAttribute : OverrideMethodAspect
7{
8 public override dynamic? OverrideMethod()
9 {
10 // Fixed: the counter is a run-time variable because its value depends on run-time arguments.
11 var nullCount = 0;
12
13 foreach ( var parameter in meta.Target.Parameters )
14 {
15 if ( parameter.Value == null )
16 {
17 nullCount++;
18 }
19 }
20
21 Console.WriteLine( $"{meta.Target.Method.Name} received {nullCount} null argument(s)." );
22
23 return meta.Proceed();
24 }
25}
26
1namespace Doc.LAMA0280.Fixed;
2
3internal class CustomerService
4{
5 [LogNullArguments]
6 public void Register( string? name, string? email ) { }
7}
8
1using System;
2
3namespace Doc.LAMA0280.Fixed;
4
5internal class CustomerService
6{
7 [LogNullArguments]
8 public void Register(string? name, string? email)
9 {
10 var nullCount = 0;
11 if (name == null)
12 {
13 nullCount++;
14 }
15
16 if (email == null)
17 {
18 nullCount++;
19 }
20
21 Console.WriteLine($"Register received {nullCount} null argument(s).");
22 }
23}
24