Skip to content

Conversation

@AlekseyTs
Copy link
Contributor

@AlekseyTs AlekseyTs commented Nov 25, 2025

First commit is a change that hopefully could be shared with "Closed Hierarchies" feature.

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Nov 26, 2025

@333fred, @RikkiGibson, @dotnet/roslyn-compiler Please review #Resolved

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Dec 1, 2025

@333fred, @RikkiGibson, @dotnet/roslyn-compiler Please review #Resolved

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Dec 3, 2025

@333fred, @RikkiGibson, @dotnet/roslyn-compiler Please review #Resolved

@RikkiGibson
Copy link
Member

RikkiGibson commented Dec 4, 2025

I have begun reviewing this, will need till tomorrow to finish. Thanks #Resolved

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Dec 4, 2025

@333fred, @RikkiGibson, @dotnet/roslyn-compiler Please review #Resolved

Copy link
Member

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

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

LGTM, only had some nits and a question.

When I proceed with closed class exhaustiveness checking I may try cherry picking the first commit as a starting point, I think it should be possible to add another implementation of ITypeUnionValueSetFactory for closed classes.

{
// We don't know for sure that test for T2 is going to match, but if it fails,
// that means that some previous test must match and we simply cannot get to this test.
// In other words, this test is either unreachanble or it will succeed.
Copy link
Member

@RikkiGibson RikkiGibson Dec 4, 2025

Choose a reason for hiding this comment

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

Suggested change
// In other words, this test is either unreachanble or it will succeed.
// In other words, this test is either unreachable or it will succeed.
``` #Resolved

falseTestImpliesTrueOther = true;
break;
case BoundDagTypeTest _:
case BoundDagTypeTest t:
Copy link
Member

@RikkiGibson RikkiGibson Dec 4, 2025

Choose a reason for hiding this comment

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

nit: this t looks unused #Resolved

{
if (easyOutForLowering != (object)planA && !forLowering && ValueSetFactory.TypeUnionValueSetFactoryForInput(planA.Input) is not null)
{
// We need a test about `null` peresent in the Dag to properly handle exhaustiveness
Copy link
Member

@RikkiGibson RikkiGibson Dec 4, 2025

Choose a reason for hiding this comment

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

Suggested change
// We need a test about `null` peresent in the Dag to properly handle exhaustiveness
// We need a test about `null` present in the Dag to properly handle exhaustiveness
``` #Resolved


string tryHandleTypeUnionLimits()
{
if (evaluations.IsEmpty && ValueSetFactory.TypeUnionValueSetFactoryForInput(input) is { } factory &&
Copy link
Member

@RikkiGibson RikkiGibson Dec 5, 2025

Choose a reason for hiding this comment

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

To check my understanding, and, in case it helps the second reviewer:

It looks like evaluations.IsEmpty ensures that we don't propose one of our unmatched types as an example pattern, in cases where we would move on to find a more suitable example further along in the process, For example, in test Exhaustiveness_04, this allows us to propose pattern false as an example rather than pattern bool. #Resolved


private static bool AnyTypeFromUnionMightMatch(ImmutableArray<TypeSymbol> typesInUnion, TypeSymbol type, ConversionsBase conversions, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
{
Debug.Assert(!typesInUnion.IsEmpty);
Copy link
Member

@RikkiGibson RikkiGibson Dec 5, 2025

Choose a reason for hiding this comment

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

I didn't follow how it is that we are certain of this. The other two assertions I understand, but, I didn't follow why it is not possible for a pattern matching against an empty union to make it here. #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 didn't follow how it is that we are certain of this. The other two assertions I understand, but, I didn't follow why it is not possible for a pattern matching against an empty union to make it here.

It is not possible because any type test for an empty Union will result in an ERR_PatternWrongType and, since we are forcing a null check first, we end up with an empty value set after it. However, it is better to not create a value set factory for an empty Union type. I am going to make this change.

@AlekseyTs
Copy link
Contributor Author

@333fred, @dotnet/roslyn-compiler For a second review

@AlekseyTs AlekseyTs requested a review from a team December 5, 2025 16:22
@AlekseyTs
Copy link
Contributor Author

@333fred, @dotnet/roslyn-compiler For a second review

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

Mostly LGTM. Couple of test suggestions and one small question.

Diagnostic(ErrorCode.ERR_PatternWrongType, "C3").WithArguments("S1", "C3").WithLocation(28, 46),
// (33,57): hidden CS9335: The pattern is redundant.
// return u switch { int => 1, I1 => 2, null => 3, C2 => 4 };
Diagnostic(ErrorCode.HDN_RedundantPattern, "C2").WithLocation(33, 57)
Copy link
Member

@333fred 333fred Dec 5, 2025

Choose a reason for hiding this comment

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

Does the prototype comment in _05 cover this diagnostic as well? #Resolved

Copy link
Contributor Author

@AlekseyTs AlekseyTs Dec 6, 2025

Choose a reason for hiding this comment

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

Does the prototype comment in _05 cover this diagnostic as well?

No. This case is a known behavior of the redundancy checker, that is why it is a hidden diagnostic.
It can be observed in the scenario below, for example. Basically the checker often "complains" if a pattern
always matches, suggesting to use _ instead. The case in _05 is different, replacing the reported
pattern with _ wouldn't be semantically equivalent, hence the comment there.

        [Fact]
        public void Test()
        {
            var src = @"
struct S1
{
    public bool Value => false;
}

class Program
{
    int M(S1 x)
    {
        return x switch {{Value: true} => 1, {Value: false} => 2};
    }
}
";
            var comp = CreateCompilation(src);
            CompileAndVerify(comp).VerifyDiagnostics(
                // (11,54): hidden CS9335: The pattern is redundant.
                //         return x switch {{Value: true} => 1, {Value: false} => 2};
                Diagnostic(ErrorCode.HDN_RedundantPattern, "false").WithLocation(11, 54)
                );
        }

Copy link
Member

Choose a reason for hiding this comment

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

Interesting. Thanks for the explanation, I would not have assumed this was by-design.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense, I forgot about this behavior.

@AlekseyTs AlekseyTs requested a review from RikkiGibson December 6, 2025 16:30
@AlekseyTs
Copy link
Contributor Author

@RikkiGibson I think I responded to your feedback/questions. Please let me know if you have additional feedback. Otherwise, I will rebase the branch to prepare it for merging.

@AlekseyTs AlekseyTs enabled auto-merge December 6, 2025 22:15
@AlekseyTs AlekseyTs merged commit e9489a5 into dotnet:features/Unions Dec 6, 2025
24 of 25 checks passed
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.

3 participants