Skip to content

Allow index initialisers to be used in fixed size buffers.#39805

Open
YairHalberstadt wants to merge 2 commits intodotnet:mainfrom
YairHalberstadt:fixed-size-buffer-index-initializers
Open

Allow index initialisers to be used in fixed size buffers.#39805
YairHalberstadt wants to merge 2 commits intodotnet:mainfrom
YairHalberstadt:fixed-size-buffer-index-initializers

Conversation

@YairHalberstadt
Copy link
Contributor

Fixes #39632

Code Gen requires no changes. We just remove an incorrect error.

@YairHalberstadt YairHalberstadt requested a review from a team as a code owner November 13, 2019 20:46
typeArgumentsWithAnnotations: default(ImmutableArray<TypeWithAnnotations>),
invoked: false,
indexed: false,
indexed: allInitialiserExpressionsAreIndexExpression(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like it would be better to just make this a local above this statement.

static void Main()
{
var b = new S();
b.V[0] = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused, wasn't this meant to test an object initializer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops

}
}";
CreateCompilation(source, options: TestOptions.UnsafeDebugDll)
.VerifyDiagnostics();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.VerifyDiagnostics(); [](start = 16, length = 21)

For success cases we prefer executing the code and observing that it behaves as expected.

@gafter
Copy link
Member

gafter commented Nov 13, 2019

This should be dependent on language version 7.3 (or probably preview) due to the fact that it depends on https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.3/indexing-movable-fixed-fields.md, for example in the translation of

class C
{
    unsafe void M()
    {
        C1 c = new C1()
        {
            S = { X = { [0] = 1, [2] = 2 } }
        };
    }
}

unsafe struct S1
{
    public fixed int X[10];
}

class C1
{
    public S1 S;
}

static void M()
{
var b = new S { V = { 1 } };
b = new S { V = { Prop = 1 } };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ Prop = 1 } [](start = 24, length = 12)

Consider also testing with an empty initializer and with an initializer that mixes assignments (indexed followed by non-indexed and in reversed order).

@AlekseyTs
Copy link
Contributor

Done with review pass (iteration 1)


static void Main()
{
var c = new C { S = new S { V =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a test that shows that the following fails: new S { V = { 0, 1, 2 } }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes in Unsafe tests (Semantic instead of CodeGen tests)

@YairHalberstadt
Copy link
Contributor Author

@jaredpar

Would you be able to assign someone to this please?

Thanks

@jaredpar jaredpar added Area-Compilers Community The pull request was submitted by a contributor who is not a Microsoft employee. labels Nov 20, 2019
@agocke
Copy link
Member

agocke commented Nov 20, 2019

I actually don't buy @gafter's reasoning here. The spec has this to say about fixed and moveable variables:

In precise terms, a fixed variable is one of the following:

  • A variable resulting from a simple_name (Simple names) that refers to a local variable or a value parameter, unless the variable is captured by an anonymous function.
  • A variable resulting from a member_access (Member access) of the form V.I, where V is a fixed variable of a struct_type.
  • A variable resulting from a pointer_indirection_expression (Pointer indirection) of the form *P, a pointer_member_access (Pointer member access) of the form P->I, or a pointer_element_access (Pointer element access) of the form P[E].

All other variables are classified as moveable variables.

My read of this is that V, in the context of an object initializer, refers via member access to the containing struct, which is an expression of the struct type. Further, my read of the spec is that this isn't described as a variable at all, which I suppose would leave behavior unspecified. However, it appears that we treat expressions of struct type (appropriately) as fixed.

In this case, the bug here has nothing to do with fixed-size buffer indexing, which was added in C# 7.3, but the simple fact that the unnamed temporary here is being incorrectly referred to as moveable, when it is actually supposed to be fixed.

@YairHalberstadt
Copy link
Contributor Author

@agocke
Are there any changes that have to be made here?

@YairHalberstadt
Copy link
Contributor Author

@agocke, @gafter

Should I close this? Or do you still have to discuss the spec?

Thanks

@agocke
Copy link
Member

agocke commented Mar 6, 2020

We should definitely take this. Only question is what language version to require. I haven't looked at the implementation yet, I'll try to get to that today.

Copy link
Member

@agocke agocke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, really messed up my local Git clone on Friday and had to fix it before I could review this

{
var memberName = (IdentifierNameSyntax)namedAssignment.Left;

var allInitializerExpressionsAreIndexExpressions =
Copy link
Member

@agocke agocke Mar 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this looks wrong. If my read of the spec is correct, the categorization of the receiver is non-moveable. So we shouldn't need to know if these are index expressions in the example

using System;

unsafe struct S
{
    public fixed double V[3];

    static void Main()
    {
        var s = new S { V = 
        {
            [0] = 0,
            [1] = 1,
            [2] = 2,
        } };
        
        Console.Write(s.V[0]);
        Console.Write(s.V[1]);
        Console.Write(s.V[2]);
    }
}

I think the problem may be in Binder.IsMoveableVariable. Initializers should create a BoundObjectOrCollectionValuePlaceholder and, by my read, that placeholder is always a local temporary and thus immoveable.

Base automatically changed from master to main March 3, 2021 23:52
@CyrusNajmabadi
Copy link
Contributor

@jaredpar @agocke any thoughts on what shoudl be done with this outstanding PR? THanks!

@jaredpar jaredpar added this to the Backlog milestone Jul 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Blocked Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot use index initializer with fixed sized buffer

7 participants