Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal]: breaking point for C# Primary Constructor #67796

Closed
ndepend opened this issue Apr 13, 2023 · 9 comments
Closed

[Proposal]: breaking point for C# Primary Constructor #67796

ndepend opened this issue Apr 13, 2023 · 9 comments

Comments

@ndepend
Copy link

ndepend commented Apr 13, 2023

I was investigating C# 12 class and struct primary constructors and figured out that no breakpoint can be set, unless a parameter is used within a property initialization. It can certainly be useful to break upon a primary constructor, the same way it is useful to be able to break upon a property get; or set;:
C# 12 class and struct Primary Constructor and breakpoint

@CyrusNajmabadi CyrusNajmabadi transferred this issue from dotnet/csharplang Apr 13, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Language Design untriaged Issues and PRs which have not yet been triaged by a lead labels Apr 13, 2023
@tmat
Copy link
Member

tmat commented Apr 13, 2023

There are 3 issues here:

  1. The compiler is not generating sequence points correctly for primary constructors of non-records. It works well for records.

Repro:

var s = new S(1, 2);
var p = new P(1, 2);
Console.WriteLine();

record struct S(int A, int B);
struct P(int A, int B) { }

Run and keep pressing F11 to step into all debuggable code (with "Just My Code" enabled):

1

image

2

image

3

image

4

image

Compiler issue - missing sequence points (initializer of P is skipped):

5

image

6

image

  1. The IDE is not allowing to place breakpoints for primary constructors (both records and non-records).

Repro: place cursor on int A in S or P and try to place a breakpoint (F9).

  1. Not sure why, but in step 2 and 3 the grey highlight should be on var s = new S(1, 2);, not on var p = new P(1, 2);. It could be a debugger issue.

The sequence points of <Main>$ look correct:

Method 'Program.<Main>$' (0x06000003)
  Locals: S, P (#22)
{
  // Code size       24 (0x18)
  .maxstack  3
 -IL_0000:  ldloca.s   V_0
  IL_0002:  ldc.i4.1
  IL_0003:  ldc.i4.2
  IL_0004:  call       'S..ctor' (0x06000005)

 -IL_0009:  ldloca.s   V_1
  IL_000b:  ldc.i4.1
  IL_000c:  ldc.i4.2
  IL_000d:  call       'P..ctor' (0x06000012)

 -IL_0012:  call       'System.Console.WriteLine' (0x0a00000f)
  IL_0017:  ret
}

Sequence points of S..ctor are:

Method 'S..ctor' (0x06000005)
{
  // Code size       15 (0xf)
  .maxstack  8
 -IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  stfld      '<A>k__BackingField' (0x04000002)

 -IL_0007:  ldarg.0
  IL_0008:  ldarg.2
  IL_0009:  stfld      '<B>k__BackingField' (0x04000003)
  IL_000e:  ret
}

I think we could add hidden sequence point to ret here, but not sure if necessary.

@tmat
Copy link
Member

tmat commented Apr 13, 2023

@AlekseyTs

@AlekseyTs
Copy link
Contributor

It works well for records.

I wouldn't say that. It looks to me that the issue is not specific to a particular flavor of a primary constructor, record or not. If a primary constructor doesn't have any user code, no sequence points generated for its body. For example, debugger doesn't stop for this record.

        record struct S(int A, int B)
        {
            public int A;
            public int B;
        }

Bottom line, this doesn't look like a new issue to me.

@tmat
Copy link
Member

tmat commented Apr 13, 2023

Ok, it may work accidentally for some records and not for others, so might not be new. That doesn't mean it shouldn't be fixed (possibly by removing the existing sequence points generated for records, if we don't want to step into the ctor).

@AlekseyTs
Copy link
Contributor

That doesn't mean it shouldn't be fixed

No argument here.

@ndepend
Copy link
Author

ndepend commented Apr 14, 2023

@tmat indeed I didn't notice one can step into record primary constructor parameter declaration.
image

Issue 1) No breaking point can be set with F9 in this context:
image

Issue 2) I cannot step-into with F11 in this context:
image

Issue 3) No breaking point can be set with F9 in this context:
image

@egvijayanand
Copy link

In my case, the object instantiation would be from the DI container, so it is necessary to place a breakpoint at the type definition level to inspect it during the debugging process.

Otherwise, I need to traverse through a hierarchy of instances to start from the invocation point (Application -> View -> ViewModel). This is just for the sample created. A real-world example would be much more complex. As we assess this feature to be useful esp for Services where the constructor parameter just gets assigned to the read-only field for its lifetime.

And most of the time, the parameter would be used in another command, which is independent of instantiation, unlike the property where the value would be set instantly.

So need an option that addresses this issue before this feature hits GA.

@tmat
Copy link
Member

tmat commented Jul 25, 2023

Breakpoints in primary constructors are implemented in VS 17.8 Preview 1: #68765

@tmat tmat closed this as completed Jul 25, 2023
@egvijayanand
Copy link

Breakpoints in primary constructors are implemented in VS 17.8 Preview 1

Glad that it's getting addressed. Clarify whether v17.8 is planned to release before/alongside .NET 8 GA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants