Open sandboxFocusImprove this doc

LAMA0536: The pull strategy must provide a value for the forwarding constructor

Severity Error
Reported by Metalama.Framework
Message The aspect '<AspectType>' cannot generate the forwarding constructor '<Forwarder>' because the pull strategy returned '<ReturnedKind>' for the parameter '<IntroducedParameter>'. For a forwarding constructor, the pull strategy must provide a value, for instance with PullAction.UseExpression, and must not return PullAction.None.

Cause

When an aspect introduces a parameter into a constructor with the IntroduceParameter method and an overloading strategy like ForwardSourceConstructors, Metalama generates a forwarding constructor. This constructor keeps the original signature and calls the modified constructor with : this(...). It must pass a value for the new parameter, and it asks the pull strategy, an IPullStrategy, for this value.

Because the signature of the forwarding constructor is fixed, the pull strategy must return an action that provides a value. Metalama reports LAMA0536 when the strategy returns None, which means that no value is passed. In the message, <ReturnedKind> is the internal name of the returned action, for example DoNotPull for PullAction.None.

In the following example, the custom pull strategy of the AddTimestamp aspect returns PullAction.None.

1using System;
2using Metalama.Framework.Advising;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5
6namespace Doc.LAMA0536.Error;
7
8public class TimestampPullStrategy : IPullStrategy
9{
10    // Error: PullAction.None gives no value for the forwarding constructor to pass.
11    public PullAction GetPullAction( IParameter pulledParameter, IHasParameters targetMember ) => PullAction.None;
12}
13
14public class AddTimestampAttribute : TypeAspect
15{
16    public override void BuildAspect( IAspectBuilder<INamedType> builder )
17    {
18        foreach ( var constructor in builder.Target.Constructors )
19        {
20            builder.With( constructor )
21                .IntroduceParameter(
22                    "creationTime",
23                    typeof(DateTime),
24                    pullStrategy: new TimestampPullStrategy(),
25                    overloadingStrategy: ConstructorOverloadingStrategy.ForwardSourceConstructors );
26        }
27    }
28}
29
1namespace Doc.LAMA0536.Error;
2
3// The [AddTimestamp] aspect adds a creationTime parameter and a forwarding constructor.
4[AddTimestamp]
Error LAMA0536: The aspect 'AddTimestamp' cannot generate the forwarding constructor 'Order.Order(int)' because the pull strategy returned 'PullAction.None' for the parameter 'Order.Order(int)@creationTime'. For a forwarding constructor, the pull strategy must provide a value, for instance with PullAction.UseExpression, and must not return PullAction.None.

5internal class Order
6{
7    public Order( int id )
8    {
9        this.Id = id;
10    }
11
12    public int Id { get; }
13}
14

Resolution

Make the pull strategy return an action that provides a value:

If you don't need a custom strategy, use one of the built-in strategies of the PullStrategy class, for example UseExpression.

1using System;
2using Metalama.Framework.Advising;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5using Metalama.Framework.Code.SyntaxBuilders;
6
7namespace Doc.LAMA0536.Fixed;
8
9public class TimestampPullStrategy : IPullStrategy
10{
11    // Fixed: the forwarding constructor passes the current time.
12    public PullAction GetPullAction( IParameter pulledParameter, IHasParameters targetMember )
13        => PullAction.UseExpression( ExpressionFactory.Parse( "global::System.DateTime.Now" ) );
14}
15
16public class AddTimestampAttribute : TypeAspect
17{
18    public override void BuildAspect( IAspectBuilder<INamedType> builder )
19    {
20        foreach ( var constructor in builder.Target.Constructors )
21        {
22            builder.With( constructor )
23                .IntroduceParameter(
24                    "creationTime",
25                    typeof(DateTime),
26                    pullStrategy: new TimestampPullStrategy(),
27                    overloadingStrategy: ConstructorOverloadingStrategy.ForwardSourceConstructors );
28        }
29    }
30}
31
Source Code
1namespace Doc.LAMA0536.Fixed;
2


3// The [AddTimestamp] aspect adds a creationTime parameter and a forwarding constructor.
4[AddTimestamp]
5internal class Order
6{
7    public Order( int id )
8    {
9        this.Id = id;
10    }
11
12    public int Id { get; }
13}
14
Transformed Code
1using System;
2
3namespace Doc.LAMA0536.Fixed;
4
5// The [AddTimestamp] aspect adds a creationTime parameter and a forwarding constructor.
6[AddTimestamp]
7internal class Order
8{
9    public Order(int id, DateTime creationTime)
10    {
11        this.Id = id;
12    }
13
14    public int Id { get; }
15
16    public Order(int id) : this(id: id, creationTime: DateTime.Now)
17    {
18    }
19}
20

See also