Open sandboxFocusImprove this doc

LAMA0108: A compile-time variable can't be set under a run-time condition

Severity Error
Reported by Metalama.Framework
Message The compile-time variable '<VariableName>' cannot be set here because the assignment is in a block whose execution depends on a run-time condition ('<RunTimeCondition>'), and the variable is not declared in that block. Move the assignment out of this block, or declare the variable inside the block.

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, or a run-time for, foreach, while, switch, catch, or finally, 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 the body of such a block, so it can't know whether a compile-time assignment in that body should happen.

For this reason, Metalama reports LAMA0108 when, inside a run-time-conditional block, a template modifies a compile-time local variable that's declared outside the block. The modification can be an assignment, a compound assignment like +=, an increment or decrement, or passing the variable as an out or ref argument. The first placeholder of the message is the variable, and the second one is the statement that introduces the run-time condition.

In the following example, the aspect tries to count null arguments with a compile-time variable, but the counter 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.LAMA0108.Error;
5
6public class LogNullArgumentsAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        var nullArgumentCount = meta.CompileTime( 0 );
11
12        foreach ( var parameter in meta.Target.Parameters )
13        {
14            if ( parameter.Value == null )
15            {
16                // Error: a compile-time variable is incremented under a run-time condition.
                Error LAMA0108: The compile-time variable 'nullArgumentCount' cannot be set here because the assignment is in a block whose execution depends on a run-time condition ('if ( parameter.Value == null )'), and the variable is not declared in that block. Move the assignment out of this block, or declare the variable inside the block.

17                nullArgumentCount++;
18            }
19        }
20
21        Console.WriteLine( $"{meta.Target.Method.Name} received {nullArgumentCount} null argument(s)." );
22
23        return meta.Proceed();
24    }
25}
26
1namespace Doc.LAMA0108.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 of the variable depends on run-time data, make it a run-time variable: initialize it without meta.CompileTime, for instance with a literal. 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 variable is only used inside the block, declare it inside the 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 if statement becomes compile-time.

1using Metalama.Framework.Aspects;
2using System;
3
4namespace Doc.LAMA0108.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 nullArgumentCount = 0;
12
13        foreach ( var parameter in meta.Target.Parameters )
14        {
15            if ( parameter.Value == null )
16            {
17                nullArgumentCount++;
18            }
19        }
20
21        Console.WriteLine( $"{meta.Target.Method.Name} received {nullArgumentCount} null argument(s)." );
22
23        return meta.Proceed();
24    }
25}
26
Source Code
1namespace Doc.LAMA0108.Fixed;
2


3internal class CustomerService
4{
5    [LogNullArguments]
6    public void Register( string? name, string? email ) { }
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0108.Fixed;
4
5internal class CustomerService
6{
7    [LogNullArguments]
8    public void Register(string? name, string? email)
9    {
10        var nullArgumentCount = 0;
11        if (name == null)
12        {
13            nullArgumentCount++;
14        }
15
16        if (email == null)
17        {
18            nullArgumentCount++;
19        }
20
21        Console.WriteLine($"Register received {nullArgumentCount} null argument(s).");
22    }
23}
24

See also