Skip to content

Comments

Assert the shape of bound tree created fo user defined conversions#81896

Merged
AlekseyTs merged 2 commits intodotnet:mainfrom
AlekseyTs:InConversionGroupFlags
Jan 7, 2026
Merged

Assert the shape of bound tree created fo user defined conversions#81896
AlekseyTs merged 2 commits intodotnet:mainfrom
AlekseyTs:InConversionGroupFlags

Conversation

@AlekseyTs
Copy link
Contributor

No description provided.

Conversion is represented by a single BoundConversion.
-->
<Field Name="ConversionGroupOpt" Type="ConversionGroup?"/>
<Field Name="InConversionGroupFlags" Type="InConversionGroupFlags"/>
Copy link
Member

@jcouv jcouv Jan 7, 2026

Choose a reason for hiding this comment

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

nit: Is there a way we could avoid storing this in RELEASE build (if we only read it for assertions)? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nit: Is there a way we could avoid storing this in RELEASE build (if we only read it for assertions)?

I am planning to use this information in "production" code in upcoming changes

/// <summary>
/// Flags assigned to individual conversion nodes associated with
/// the same <see cref="ConversionGroup"/> instance.
/// </summary>
Copy link
Member

@jcouv jcouv Jan 7, 2026

Choose a reason for hiding this comment

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

Consider mentioning this is only meant to drive some assertions #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consider mentioning this is only meant to drive some assertions

That is not the intent long term

ExceptionUtilities.UnexpectedValue(InConversionGroupFlags);
}
}
}
Copy link
Member

@jcouv jcouv Jan 7, 2026

Choose a reason for hiding this comment

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

Is the goal to shrink usage of InConversionGroupFlags.Unspecified over time? Consider an assertion covering the remaining unspecified cases, hopefully that triggers when new conversion kinds are added. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is the goal to shrink usage of InConversionGroupFlags.Unspecified over time?

No, there is no such goal.

// Need to represent the implicit conversion as a node in order to be able to produce correct diagnostics.
left = new BoundConversion(left.Syntax, left, conversion, node.Operator.Kind.IsChecked(),
explicitCastInCode: false, conversionGroupOpt: null, constantValueOpt: null, type: node.Operator.LeftType);
left = node.LeftConversion;
Copy link
Member

@jcouv jcouv Jan 7, 2026

Choose a reason for hiding this comment

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

Is the above comment still applicable? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is the above comment still applicable?

I think it is.

new BoundConversion(boundRHS.Syntax, boundRHS, Conversion.Deconstruction, @checked: false, explicitCastInCode: false, conversionGroupOpt: null,
constantValueOpt: null, type: type, hasErrors: true),
new BoundConversion(boundRHS.Syntax, boundRHS, Conversion.Deconstruction, @checked: false, explicitCastInCode: false,
conversionGroupOpt: null, inConversionGroupFlags: InConversionGroupFlags.Unspecified, constantValueOpt: null, type: type, hasErrors: true),
Copy link
Member

@jcouv jcouv Jan 7, 2026

Choose a reason for hiding this comment

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

inConversionGroupFlags:

nit: I'd probably not specify parameter name for InConversionGroupFlags arguments, unless required because of existing ordering, as there is no risk of accidentally mixing up arguments. Applies to a bunch of locations #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd probably not specify parameter name for InConversionGroupFlags arguments, unless required

Done

public bool Equals(Conversion other)
{
return this.Kind == other.Kind && this.Method == other.Method;
return this.Kind == other.Kind && Equals(this._uncommonData, other._uncommonData);
Copy link
Member

@jcouv jcouv Jan 7, 2026

Choose a reason for hiding this comment

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

nit: just curious, how did you spot this? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

how did you spot this?

Some logic that I was adding to Validate wasn't quite working because of false positives from comparison operators. I think that logic was changed, but the problem got noticed.

@jcouv jcouv self-assigned this Jan 7, 2026
Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (commit 1)

@AlekseyTs AlekseyTs requested a review from a team January 7, 2026 19:08
@AlekseyTs
Copy link
Contributor Author

@dotnet/roslyn-compiler For a second review

[Flags]
internal enum InConversionGroupFlags : ushort
{
Unspecified = 0,
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Jan 7, 2026

Choose a reason for hiding this comment

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

Does 'unspecified' reflect in a point in time where we're just choosing to not provide more specific data? or is it a strong value that we woudl expect to stay the same in all the locations were currently passing it in.

My guess is the former, but it's not readily apparent to me. #Resolved

Copy link
Contributor

Choose a reason for hiding this comment

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

Put another way, will we likkely update some of the places that currently pass 'unspecified' to pass something more specific when we realize there are useful conversion checks we want?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Put another way, will we likkely update some of the places that currently pass 'unspecified' to pass something more specific when we realize there are useful conversion checks we want?

I think making a change like that in the future would be fine.

@checked: conversion.Checked,
explicitCastInCode: conversion.ExplicitCastInCode,
conversionGroupOpt: null,
conversionGroupOpt: null, inConversionGroupFlags: InConversionGroupFlags.TupleBinaryOperatorPendingLowering,
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Jan 7, 2026

Choose a reason for hiding this comment

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

could you wrap this to keep each arg on its own line like before? tnx. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

could you wrap this to keep each arg on its own line like before?

Done

// Need to represent the implicit conversion as a node in order to be able to produce correct diagnostics.
left = new BoundConversion(left.Syntax, left, conversion, node.Operator.Kind.IsChecked(),
explicitCastInCode: false, conversionGroupOpt: null, constantValueOpt: null, type: node.Operator.LeftType);
left = node.LeftConversion;
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Jan 7, 2026

Choose a reason for hiding this comment

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

i'm curious why this was changed. can you provide more info on that? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i'm curious why this was changed. can you provide more info on that?

We already have the conversion node, no need to "re-invent" it

Assert.Equal(expectedConversion, conversionOperation.GetConversion());
Conversion conversion = conversionOperation.GetConversion();
Assert.Equal(ConversionKind.CollectionExpression, conversion.Kind);
AssertEx.SequenceEqual(ImmutableArray.Create(Conversion.Boxing, Conversion.Boxing), conversion.UnderlyingConversions);
Copy link
Contributor

@CyrusNajmabadi CyrusNajmabadi Jan 7, 2026

Choose a reason for hiding this comment

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

since SeqEqual is really just validating same values in same order, the above may be clearer as

Suggested change
AssertEx.SequenceEqual(ImmutableArray.Create(Conversion.Boxing, Conversion.Boxing), conversion.UnderlyingConversions);
AssertEx.SequenceEqual([Conversion.Boxing, Conversion.Boxing], conversion.UnderlyingConversions);

as it's not really needed to specify the underlying temp collection type used to group the values. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@AlekseyTs AlekseyTs enabled auto-merge (squash) January 7, 2026 20:38
@AlekseyTs AlekseyTs merged commit b5872bb into dotnet:main Jan 7, 2026
28 of 29 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 7, 2026
@davidwengier davidwengier modified the milestones: Next, 18.4 Jan 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants