Skip to content

Sema: Treat the implicit RawRepresentable conformance for enums as Synthesized again. #7345

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
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
8 changes: 5 additions & 3 deletions lib/AST/ConformanceLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,8 @@ void ConformanceLookupTable::addSynthesizedConformance(NominalTypeDecl *nominal,
}

void ConformanceLookupTable::registerProtocolConformance(
ProtocolConformance *conformance) {
ProtocolConformance *conformance,
bool synthesized) {
auto protocol = conformance->getProtocol();
auto dc = conformance->getDeclContext();
auto nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext();
Expand All @@ -879,8 +880,9 @@ void ConformanceLookupTable::registerProtocolConformance(
// Otherwise, add a new entry.
auto inherited = dyn_cast<InheritedProtocolConformance>(conformance);
ConformanceSource source
= inherited ? ConformanceSource::forInherited(cast<ClassDecl>(nominal))
: ConformanceSource::forExplicit(dc);
= inherited ? ConformanceSource::forInherited(cast<ClassDecl>(nominal)) :
synthesized ? ConformanceSource::forSynthesized(nominal) :
ConformanceSource::forExplicit(dc);

ASTContext &ctx = nominal->getASTContext();
ConformanceEntry *entry = new (ctx) ConformanceEntry(SourceLoc(),
Expand Down
3 changes: 2 additions & 1 deletion lib/AST/ConformanceLookupTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,8 @@ class ConformanceLookupTable {
ProtocolDecl *protocol);

/// Register an externally-supplied protocol conformance.
void registerProtocolConformance(ProtocolConformance *conformance);
void registerProtocolConformance(ProtocolConformance *conformance,
bool synthesized = false);

/// Look for conformances to the given protocol.
///
Expand Down
12 changes: 4 additions & 8 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,14 +628,10 @@ void NominalTypeDecl::prepareConformanceTable() const {
if (resolver)
resolver->resolveRawType(theEnum);
if (theEnum->hasRawType()) {
if (auto rawRepresentable = ctx.getProtocol(KnownProtocolKind::RawRepresentable)) {

// The presence of a raw type is an explicit declaration that
// the compiler should derive a RawRepresentable conformance.
auto conformance = ctx.getConformance(mutableThis->getDeclaredTypeInContext(), rawRepresentable,
mutableThis->getNameLoc(), mutableThis->getInnermostDeclContext(),
ProtocolConformanceState::Incomplete);
ConformanceTable->registerProtocolConformance(conformance);
if (auto rawRepresentable =
ctx.getProtocol(KnownProtocolKind::RawRepresentable)) {
ConformanceTable->addSynthesizedConformance(mutableThis,
rawRepresentable);
}
}
}
Expand Down
12 changes: 11 additions & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2784,6 +2784,10 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
llvm::SmallDenseMap<RawValueKey, RawValueSource, 8> uniqueRawValues;

for (auto elt : ED->getAllElements()) {
// Skip if the raw value expr has already been checked.
if (elt->getTypeCheckedRawValueExpr())
continue;

// Make sure the element is checked out before we poke at it.
TC.validateDecl(elt);

Expand Down Expand Up @@ -6307,6 +6311,12 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
if (auto extendedTy = ED->getExtendedType()) {
if (auto nominal = extendedTy->getAnyNominal()) {
TC.validateDecl(nominal);
// Check the raw values of an enum, since we might synthesize
// RawRepresentable while checking conformances on this extension.
if (auto enumDecl = dyn_cast<EnumDecl>(nominal)) {
if (enumDecl->hasRawType())
checkEnumRawValues(TC, enumDecl);
}
}
}

Expand Down Expand Up @@ -7472,7 +7482,7 @@ void TypeChecker::validateExtension(ExtensionDecl *ext) {
ext->setGenericEnvironment(env);
return;
}

// If we're extending a protocol, check the generic parameters.
//
// Canonicalize the type to work around the fact that getAs<> cannot
Expand Down
7 changes: 4 additions & 3 deletions lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5516,9 +5516,10 @@ void TypeChecker::checkConformancesInContext(DeclContext *dc,
// Special case: explain that 'RawRepresentable' conformance
// is implied for enums which already declare a raw type.
if (auto enumDecl = dyn_cast<EnumDecl>(existingDecl)) {
if (diag.Protocol->isSpecificProtocol(KnownProtocolKind::RawRepresentable) &&
enumDecl->derivesProtocolConformance(diag.Protocol) &&
enumDecl->hasRawType()) {
if (diag.Protocol->isSpecificProtocol(KnownProtocolKind::RawRepresentable)
&& enumDecl->derivesProtocolConformance(diag.Protocol)
&& enumDecl->hasRawType()
&& enumDecl->getInherited()[0].getSourceRange().isValid()) {
diagnose(enumDecl->getInherited()[0].getSourceRange().Start,
diag::enum_declares_rawrep_with_raw_type,
dc->getDeclaredInterfaceType(), enumDecl->getRawType());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

extension Foo: RawRepresentable {}

enum Bar: Int { case A }

// expected-error@+1{{redundant conformance of 'Bas' to protocol 'RawRepresentable'}}
extension Bas: RawRepresentable {}

1 change: 1 addition & 0 deletions test/Sema/Inputs/enum_with_raw_type.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public enum Foo: Int { case A }
9 changes: 9 additions & 0 deletions test/Sema/enum_post_hoc_raw_representable_with_raw_type.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: %target-swift-frontend -emit-module -o %t/enum_with_raw_type.swiftmodule %S/Inputs/enum_with_raw_type.swift
// RUN: %target-swift-frontend -I %t -typecheck -verify %s

import enum_with_raw_type

// expected-error@+1{{redundant conformance of 'Foo' to protocol 'RawRepresentable'}}
extension Foo: RawRepresentable {}
15 changes: 15 additions & 0 deletions test/Sema/enum_raw_representable_explicit.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %target-swift-frontend -typecheck -verify %s

enum Foo: Int, RawRepresentable { case A }

enum Bar: Int { case A }

extension Bar: RawRepresentable {}

enum Bas: Int { case A }

// expected-note@+1{{'Bas' declares conformance to protocol 'RawRepresentable' here}}
extension Bas: RawRepresentable {}

// expected-error@+1{{redundant conformance of 'Bas' to protocol 'RawRepresentable'}}
extension Bas: RawRepresentable {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: %target-swift-frontend -typecheck -verify %s

enum Foo: Int { case A }
extension Foo: RawRepresentable {}
10 changes: 10 additions & 0 deletions test/Sema/enum_raw_representable_explicit_multi_file.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %target-swift-frontend -typecheck -primary-file %s %S/Inputs/enum_raw_representable_explicit_multi_file_2.swift
// RUN: %target-swift-frontend -typecheck -verify %s -primary-file %S/Inputs/enum_raw_representable_explicit_multi_file_2.swift

enum Foo: Int { case A }

extension Bar: RawRepresentable {}

enum Bas: Int { case A }
// expected-note@+1 {{'Bas' declares conformance to protocol 'RawRepresentable' here}}
extension Bas: RawRepresentable {}
2 changes: 1 addition & 1 deletion test/decl/protocol/conforms/Inputs/placement_2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ class MFSynthesizedSubClass3 : MFSynthesizedClass1 { }

extension MFSynthesizedSubClass4 : AnyObjectRefinement { }

enum MFSynthesizedEnum1 : Int { case a } // expected-note {{'MFSynthesizedEnum1' declares raw type 'Int', which implies RawRepresentable}}
enum MFSynthesizedEnum1 : Int { case a }
extension MFSynthesizedEnum2 : RawRepresentable { }

8 changes: 4 additions & 4 deletions test/decl/protocol/conforms/placement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,10 @@ class SynthesizedSubClass3 : SynthesizedClass1, AnyObjectRefinement { }
class SynthesizedSubClass4 : SynthesizedClass2 { }
extension SynthesizedSubClass4 : AnyObjectRefinement { }

enum SynthesizedEnum1 : Int, RawRepresentable { case none = 0 } // expected-error{{redundant conformance of 'SynthesizedEnum1' to protocol 'RawRepresentable'}} expected-note{{'SynthesizedEnum1' declares raw type 'Int', which implies RawRepresentable}}
enum SynthesizedEnum1 : Int, RawRepresentable { case none = 0 }

enum SynthesizedEnum2 : Int { case none = 0 } // expected-note {{'SynthesizedEnum2' declares raw type 'Int', which implies RawRepresentable}}
extension SynthesizedEnum2 : RawRepresentable { } // expected-error{{redundant conformance of 'SynthesizedEnum2' to protocol 'RawRepresentable'}}
enum SynthesizedEnum2 : Int { case none = 0 }
extension SynthesizedEnum2 : RawRepresentable { }


// ===========================================================================
Expand Down Expand Up @@ -182,7 +182,7 @@ extension MFSynthesizedSubClass3 : AnyObjectRefinement { }

class MFSynthesizedSubClass4 : MFSynthesizedClass2 { }

extension MFSynthesizedEnum1 : RawRepresentable { } // expected-error{{redundant conformance of 'MFSynthesizedEnum1' to protocol 'RawRepresentable'}}
extension MFSynthesizedEnum1 : RawRepresentable { }

enum MFSynthesizedEnum2 : Int { case none = 0 }

Expand Down