Open sandboxFocusImprove this doc

LAMA0241: An expression mixes compile-time and run-time sub-expressions

Severity Error
Reported by Metalama.Framework
Message Execution scope mismatch in the expression '<ParentExpression>': the sub-expression '<SubExpression>' is <SubExpressionScope>, but the other sub-expression '<OtherSubExpression>' is <OtherSubExpressionScope>.

Cause

In a T# template, Metalama classifies every expression as either compile-time, which it evaluates while generating the code, or run-time, which it copies into the generated code. A sub-expression whose value is a compile-time object, such as an IProperty or an IMethod, can't become part of the generated code. A sub-expression whose value is run-time, such as meta.Proceed() or the Value of a declaration, can't be evaluated at compile time.

Metalama reports LAMA0241 when an expression combines two such sub-expressions, so that it can be neither compile-time nor run-time. The message gives the two sub-expressions and their scopes. This typically happens in a condition that joins a compile-time test and a run-time test with && or ||, in an array initializer, or in a cast of a compile-time value to a run-time type.

In the following example, the isLoggerAvailable condition checks at compile time that the target type has a Logger property, and at run time that the value of this property isn't null.

1using Metalama.Framework.Aspects;
2using System.Linq;
3
4namespace Doc.LAMA0241.Error;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        var loggerProperty = meta.Target.Type.Properties.OfName( "Logger" ).SingleOrDefault();
11
12        // Error: the left operand is compile-time, but the right operand is run-time.
        Error LAMA0241: Execution scope mismatch in the expression 'loggerProperty != null && loggerProperty.Value != null': the sub-expression 'loggerProperty != null' is compile-time, but the other sub-expression 'loggerProperty.Value != null' is run-time.

13        bool isLoggerAvailable = loggerProperty != null && loggerProperty.Value != null;
14
15        if ( isLoggerAvailable )
16        {
17            loggerProperty!.Value!.WriteLine( $"Executing {meta.Target.Method}." );
18        }
19
20        return meta.Proceed();
21    }
22}
23
1using System;
2using System.IO;
3
4namespace Doc.LAMA0241.Error;
5
6internal class OrderService
7{
8    public TextWriter? Logger { get; set; } = Console.Out;
9
10    [Log]
11    public void PlaceOrder( int quantity ) { }
12}
13

Resolution

Split the expression so that each part is entirely compile-time or entirely run-time. For a condition, test the compile-time part in a compile-time if statement and, inside it, test the run-time part in a run-time expression or if statement. The following example uses this fix.

1using Metalama.Framework.Aspects;
2using System.Linq;
3
4namespace Doc.LAMA0241.Fixed;
5
6public class LogAttribute : OverrideMethodAspect
7{
8    public override dynamic? OverrideMethod()
9    {
10        var loggerProperty = meta.Target.Type.Properties.OfName( "Logger" ).SingleOrDefault();
11
12        // Fixed: the compile-time test is in a compile-time if statement, and the run-time test is inside it.
13        if ( loggerProperty != null )
14        {
15            bool isLoggerAvailable = loggerProperty.Value != null;
16
17            if ( isLoggerAvailable )
18            {
19                loggerProperty.Value!.WriteLine( $"Executing {meta.Target.Method}." );
20            }
21        }
22
23        return meta.Proceed();
24    }
25}
26
Source Code
1using System;
2using System.IO;
3
4namespace Doc.LAMA0241.Fixed;
5
6internal class OrderService
7{
8    public TextWriter? Logger { get; set; } = Console.Out;
9
10    [Log]
11    public void PlaceOrder( int quantity ) { }
12}
13
Transformed Code
1using System;
2using System.IO;
3
4namespace Doc.LAMA0241.Fixed;
5
6internal class OrderService
7{
8    public TextWriter? Logger { get; set; } = Console.Out;
9
10    [Log]
11    public void PlaceOrder(int quantity)
12    {
13        bool isLoggerAvailable = Logger != null;
14        if (isLoggerAvailable)
15        {
16            Logger.WriteLine("Executing OrderService.PlaceOrder(int).");
17        }
18    }
19}
20

See also