Open sandboxFocusImprove this doc

LAMA1014: The interceptor returned an invalid result

Severity Error
Reported by Metalama.Extensions.Interceptors
Message The <Source> returned an invalid result for the <Site>. <Detail>

Cause

The Metalama.Extensions.Interceptors package lets an aspect or a fabric replace the calls to selected methods with calls to another method, called an interceptor. With RedirectToSynthesizedMethod, Metalama generates the interceptor method from a template. A Configure delegate can adjust the generated method for each call site, for instance by adding parameters and type parameters.

Metalama reports LAMA1014 when the result returned for a call site can't be turned into a valid interceptor. In the message, <Source> is the interceptor and the aspect or fabric that registered it, <Site> describes the call, and <Detail> gives the specific problem. Typical details are:

  • the Configure delegate adds a type parameter but doesn't give its type argument with SetTypeArgument, or the type argument violates the constraints of the type parameter;
  • the Configure delegate sets a name that isn't a valid identifier;
  • an added parameter receives a value both from WithArgs and from SetArgument;
  • the delegate changes the type of a parameter that is passed by reference;
  • the result applies to a method reference, which interceptors generated from templates don't support in this version;
  • the method returned for a registration doesn't exist in the current compilation.

In the following example, the aspect adds the type parameter TValue to the generated interceptor, but doesn't say which type argument to use at each call site.

1using Metalama.Extensions.Interceptors;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5
6namespace Doc.LAMA1014.Error;
7
8public class InterceptLoggingAttribute : TypeAspect
9{
10    public override void BuildAspect( IAspectBuilder<INamedType> builder )
11        => builder.InterceptMethods(
12            i => i
13                .Type( typeof(Logger) )
14                .Methods( "Write" )
15                .RedirectToSynthesizedMethod( nameof(this.Intercept) )
16                .PlaceInCallingType()
17                .Configure(
18                    b =>
19                    {
20                        // The type parameter has no type argument at the call site.
21                        b.Method.Parameters[0].Type = b.Method.AddTypeParameter( "TValue" );
22                    } ) );
23
24    [Template]
25    public dynamic? Intercept()
26    {
27        Console.WriteLine( "Writing a message." );
28
29        return meta.Proceed();
30    }
31}
32
1using System;
2
3namespace Doc.LAMA1014.Error;
4
5internal static class Logger
6{
7    public static void Write( object message ) => Console.WriteLine( message );
8}
9
10[InterceptLogging]
11internal static class Checkout
12{
    Error LAMA1014: The interceptor template 'Intercept' registered by the aspect [InterceptLoggingAttribute] applied to 'Checkout' returned an invalid result for the call to 'Logger.Write(object)'. The type parameter 'TValue' of the interceptor method has no type argument.

13    public static void Run() => Logger.Write( 42 );
14}
15

Resolution

Fix the result according to the detail given in the message. In the following example, the Configure delegate calls SetTypeArgument with the type of the argument at the call site, so the generated interceptor method is generic.

1using Metalama.Extensions.Interceptors;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5
6namespace Doc.LAMA1014.Fixed;
7
8public class InterceptLoggingAttribute : TypeAspect
9{
10    public override void BuildAspect( IAspectBuilder<INamedType> builder )
11        => builder.InterceptMethods(
12            i => i
13                .Type( typeof(Logger) )
14                .Methods( "Write" )
15                .RedirectToSynthesizedMethod( nameof(this.Intercept) )
16                .PlaceInCallingType()
17                .Configure(
18                    b =>
19                    {
20                        var typeParameter = b.Method.AddTypeParameter( "TValue" );
21                        b.Method.Parameters[0].Type = typeParameter;
22
23                        // The type argument is the type of the argument at the call site.
24                        b.SetTypeArgument( typeParameter, b.Context.Arguments[0].Type! );
25                    } ) );
26
27    [Template]
28    public dynamic? Intercept()
29    {
30        Console.WriteLine( "Writing a message." );
31
32        return meta.Proceed();
33    }
34}
35
Source Code
1using System;
2
3namespace Doc.LAMA1014.Fixed;
4
5internal static class Logger
6{
7    public static void Write( object message ) => Console.WriteLine( message );
8}
9
10[InterceptLogging]
11internal static class Checkout
12{
13    public static void Run() => Logger.Write( 42 );
14}




15
Transformed Code
1using System;
2
3namespace Doc.LAMA1014.Fixed;
4
5internal static class Logger
6{
7    public static void Write(object message) => Console.WriteLine(message);
8}
9
10[InterceptLogging]
11internal static class Checkout
12{
13    public static void Run() => Logger_Write_Interceptor(message: 42);
14
15    private static void Logger_Write_Interceptor<TValue>(TValue message)
16    {
17        Console.WriteLine("Writing a message.");
18        Logger.Write((object)message);
19    }
20}
21