Open sandboxFocusImprove this doc

LAMA0265: Static interface members can't be accessed on a compile-time type parameter

Severity Error
Reported by Metalama.Framework
Message Accessing the static interface member '<Member>' is not supported on the compile-time template type parameter '<TypeParameter>'. Call a run-time generic method that accesses the member instead, or make the type parameter run-time.

Cause

A template method can have compile-time type parameters, marked with the [CompileTime] attribute. When Metalama expands the template, it replaces each compile-time type parameter with the type passed by the aspect, for instance int.

When a type parameter is constrained to an interface with static abstract members, like INumber, C# lets you access these members through the type parameter, for instance T.Zero. Metalama doesn't support this syntax when T is a compile-time template type parameter, and reports LAMA0265. In the message, <Member> is the name of the member and <TypeParameter> is the type parameter.

In the following example, the PrintZero template accesses T.Zero, where T is a compile-time type parameter.

1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5using System.Numerics;
6
7namespace Doc.LAMA0265.Error;
8
9public class AddPrintZeroAttribute : TypeAspect
10{
11    public override void BuildAspect( IAspectBuilder<INamedType> builder )
12    {
13        builder.IntroduceMethod( nameof(this.PrintZero), args: new { T = typeof(int) } );
14    }
15
16    [Template]
17    public void PrintZero<[CompileTime] T>()
18        where T : INumber<T>
19    {
20        // Error: T is a compile-time type parameter, so its static interface members cannot be accessed.
        Error LAMA0265: Accessing the static interface member 'Zero' is not supported on the compile-time template type parameter 'T'. Call a run-time generic method that accesses the member instead, or make the type parameter run-time.

21        Console.WriteLine( T.Zero );
22    }
23}
24
1namespace Doc.LAMA0265.Error;
2
3[AddPrintZero]
4internal partial class Calculator
5{
6    public int Add( int a, int b ) => a + b;
7}
8

Resolution

Do one of the following:

  • Move the access to a run-time generic helper method, and call this method from the template with T as the type argument. The generated code calls the helper with the actual type.
  • Remove the [CompileTime] attribute from the type parameter. The introduced method then becomes a generic method, and the static member is accessed at run time.

In the following example, the template calls a NumberHelper.Zero<T> helper method.

1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5using System.Numerics;
6
7namespace Doc.LAMA0265.Fixed;
8
9public class AddPrintZeroAttribute : TypeAspect
10{
11    public override void BuildAspect( IAspectBuilder<INamedType> builder )
12    {
13        builder.IntroduceMethod( nameof(this.PrintZero), args: new { T = typeof(int) } );
14    }
15
16    [Template]
17    public void PrintZero<[CompileTime] T>()
18        where T : INumber<T>
19    {
20        // Fixed: the static interface member is accessed by a run-time generic helper method.
21        Console.WriteLine( NumberHelper.Zero<T>() );
22    }
23}
24
25public static class NumberHelper
26{
27    public static T Zero<T>()
28        where T : INumber<T>
29        => T.Zero;
30}
31
Source Code
1namespace Doc.LAMA0265.Fixed;
2


3[AddPrintZero]
4internal partial class Calculator
5{
6    public int Add( int a, int b ) => a + b;
7}
8
Transformed Code
1using System;
2
3namespace Doc.LAMA0265.Fixed;
4
5[AddPrintZero]
6internal partial class Calculator
7{
8    public int Add(int a, int b) => a + b;
9
10    public void PrintZero()
11    {
12        Console.WriteLine(NumberHelper.Zero<int>());
13    }
14}
15

See also