Skip to content

Fix enum inspection of a no-payload enum inside another enum #72290

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

Merged
merged 2 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions stdlib/public/RemoteInspection/TypeLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,21 @@ class TrivialEnumTypeInfo: public EnumTypeInfo {
}
};

// Given a count, return a mask that is just
// big enough to preserve values less than that count.
// E.g., given a count of 6, max value is 5 (binary 0101),
// so we want to return binary 0111.
static uint32_t maskForCount(uint32_t t) {
t -= 1; // Convert count => max value
// Set all bits below highest bit...
t |= t >> 16;
t |= t >> 8;
t |= t >> 4;
t |= t >> 2;
t |= t >> 1;
return t;
}

// Enum with 2 or more non-payload cases and no payload cases
class NoPayloadEnumTypeInfo: public EnumTypeInfo {
public:
Expand Down Expand Up @@ -489,6 +504,9 @@ class NoPayloadEnumTypeInfo: public EnumTypeInfo {
if (!reader.readInteger(address, getSize(), &tag)) {
return false;
}
// Strip bits that might be used by a containing MPE:
uint32_t mask = maskForCount(getNumCases());
tag &= mask;
if (tag < getNumCases()) {
*CaseIndex = tag;
return true;
Expand Down
49 changes: 49 additions & 0 deletions validation-test/Reflection/reflect_Enum_values4.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// RUN: %empty-directory(%t)
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values4
// RUN: %target-codesign %t/reflect_Enum_values4

// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values4 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants

// REQUIRES: objc_interop
// REQUIRES: executable_test
// UNSUPPORTED: use_os_stdlib

import SwiftReflectionTest

enum NonPayloadEnum {
case one
case two
}

enum SmallMultipayloadEnum {
case empty
case a(NonPayloadEnum)
case b(NonPayloadEnum)
}

reflect(enumValue: SmallMultipayloadEnum.b(.two))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values4.SmallMultipayloadEnum)
// CHECKALL-NEXT: Value: .b(.two)

reflect(enumValue: SmallMultipayloadEnum.empty)

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values4.SmallMultipayloadEnum)
// CHECKALL-NEXT: Value: .empty

reflect(enumValue: SmallMultipayloadEnum.a(.one))

// CHECKALL: Reflecting an enum value.
// CHECKALL-NEXT: Type reference:
// CHECKALL-NEXT: (enum reflect_Enum_values4.SmallMultipayloadEnum)
// CHECKALL-NEXT: Value: .a(.one)


doneReflecting()

// CHECKALL: Done.