Open sandboxFocusImprove this doc

LAMA0245: A symbol combines run-time and compile-time elements

Severity Error
Reported by Metalama.Framework
Message '<Declaration>' is invalid because it combines run-time and compile-time elements.

Cause

Metalama assigns an execution scope, compile-time or run-time, to every symbol used in a template or in compile-time code. The scope of a generic method or type instance depends on the scopes of its type arguments. When these scopes are incompatible, the symbol has no valid scope.

Usually, Metalama can name the run-time element and the compile-time element that conflict, and reports LAMA0226. LAMA0245 is the fallback when Metalama can't identify the two elements. The placeholder of the message is the invalid symbol.

A known case is a call to meta.CompileTime with a value whose type is a compile-time type parameter of a template. Such a type parameter stands for a type of the target code, so a value of this type, like default(T), is a run-time value, while meta.CompileTime is a compile-time method. In the following example, the introduced method tries to print the default value of its type parameter at compile time.

1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5
6namespace Doc.LAMA0245.Error;
7
8public class PrintDefaultValueAttribute : TypeAspect
9{
10    public override void BuildAspect( IAspectBuilder<INamedType> builder )
11    {
12        builder.IntroduceMethod( nameof(this.PrintDefaultValue), args: new { T = typeof(int) } );
13    }
14
15    [Template]
16    public void PrintDefaultValue<[CompileTime] T>()
17    {
18        // Error: T stands for a run-time type, so default(T) cannot be evaluated by meta.CompileTime.
        Error LAMA0245: 'meta.CompileTime<T>(T?)' is invalid because it combines run-time and compile-time elements.

19        Console.WriteLine( meta.CompileTime( default(T) ) );
20    }
21}
22
1namespace Doc.LAMA0245.Error;
2
3[PrintDefaultValue]
4internal partial class Counter
5{
6    public int Value { get; set; }
7}
8

Resolution

Decide whether the expression must be evaluated at compile time or at run time, and remove the elements of the other scope:

  • If the value belongs to the target code, as with default(T), use it in run-time code, without meta.CompileTime, as in the following example. Metalama replaces T with the actual type in the generated code.
  • If you need a compile-time value, compute it from compile-time information, like the IType of the target declaration, instead of a run-time type.

1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5
6namespace Doc.LAMA0245.Fixed;
7
8public class PrintDefaultValueAttribute : TypeAspect
9{
10    public override void BuildAspect( IAspectBuilder<INamedType> builder )
11    {
12        builder.IntroduceMethod( nameof(this.PrintDefaultValue), args: new { T = typeof(int) } );
13    }
14
15    [Template]
16    public void PrintDefaultValue<[CompileTime] T>()
17    {
18        // Fixed: default(T) is emitted as run-time code, where T is replaced by the actual type.
19        Console.WriteLine( default(T) );
20    }
21}
22
Source Code
1namespace Doc.LAMA0245.Fixed;
2


3[PrintDefaultValue]
4internal partial class Counter
5{
6    public int Value { get; set; }
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0245.Fixed;
4
5[PrintDefaultValue]
6internal partial class Counter
7{
8    public int Value { get; set; }
9
10    public void PrintDefaultValue()
11    {
12        Console.WriteLine(default(int));
13    }
14}
15

See also