Skip to content

Commit 306e878

Browse files
authored
Merge pull request #15268 from huonw/dont-infer-conditional
Make ConformanceLookupTable less recursive and don't imply conformances from conditional ones
2 parents 4a0a2c1 + c104452 commit 306e878

17 files changed

+613
-137
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,16 @@ ERROR(objc_generics_cannot_conditionally_conform,none,
14431443
"type %0 cannot conditionally conform to protocol %1 because "
14441444
"the type uses the Objective-C generics model",
14451445
(Type, Type))
1446+
ERROR(conditional_conformances_cannot_imply_conformances,none,
1447+
"conditional conformance of type %0 to protocol %1 does not imply conformance to "
1448+
"inherited protocol %2",
1449+
(Type, Type, Type))
1450+
NOTE(note_explicitly_state_conditional_conformance_different,none,
1451+
"did you mean to explicitly state the conformance with different bounds?", ())
1452+
NOTE(note_explicitly_state_conditional_conformance_relaxed,none,
1453+
"did you mean to explicitly state the conformance with relaxed bounds?", ())
1454+
NOTE(note_explicitly_state_conditional_conformance_same,none,
1455+
"did you mean to explicitly state the conformance with the same bounds?", ())
14461456
ERROR(protocol_has_missing_requirements,none,
14471457
"type %0 cannot conform to protocol %1 because it has requirements that "
14481458
"cannot be satisfied", (Type, Type))

include/swift/AST/LazyResolver.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ class LazyResolver {
9090
/// considered to be members of the extended type.
9191
virtual void resolveExtension(ExtensionDecl *ext) = 0;
9292

93+
using ConformanceConstructionInfo = std::pair<SourceLoc, ProtocolDecl *>;
94+
/// Resolve enough of an extension to find which protocols it is declaring
95+
/// conformance to.
96+
///
97+
/// This can be called to ensure that the "extension Foo: Bar, Baz" part of
98+
/// the extension is understood.
99+
virtual void resolveExtensionForConformanceConstruction(
100+
ExtensionDecl *ext,
101+
SmallVectorImpl<ConformanceConstructionInfo> &protocols) = 0;
102+
93103
/// Resolve any implicitly-declared constructors within the given nominal.
94104
virtual void resolveImplicitConstructors(NominalTypeDecl *nominal) = 0;
95105

include/swift/AST/ProtocolConformance.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
115115
/// Retrieve the state of this conformance.
116116
ProtocolConformanceState getState() const;
117117

118+
/// Get the kind of source from which this conformance comes.
119+
ConformanceEntryKind getSourceKind() const;
120+
/// Get the protocol conformance which implied this implied conformance.
121+
NormalProtocolConformance *getImplyingConformance() const;
122+
118123
/// Determine whether this conformance is complete.
119124
bool isComplete() const {
120125
return getState() == ProtocolConformanceState::Complete;
@@ -349,6 +354,20 @@ class NormalProtocolConformance : public ProtocolConformance,
349354
/// Also stores the "invalid" bit.
350355
llvm::PointerIntPair<Context, 1, bool> ContextAndInvalid;
351356

357+
/// \brief The reason that this conformance exists.
358+
///
359+
/// Either Explicit (e.g. 'struct Foo: Protocol {}' or 'extension Foo:
360+
/// Protocol {}'), Synthesized (e.g. RawRepresentable for 'enum Foo: Int {}')
361+
/// or Implied (e.g. 'Foo : Protocol' in 'protocol Other: Protocol {} struct
362+
/// Foo: Other {}'). In only the latter case, the conformance is non-null and
363+
/// points to the conformance that implies this one.
364+
///
365+
/// This should never be Inherited: that is handled by
366+
/// InheritedProtocolConformance.
367+
llvm::PointerIntPair<NormalProtocolConformance *, 2, ConformanceEntryKind>
368+
SourceKindAndImplyingConformance = {nullptr,
369+
ConformanceEntryKind::Explicit};
370+
352371
/// \brief The mapping of individual requirements in the protocol over to
353372
/// the declarations that satisfy those requirements.
354373
mutable WitnessMap Mapping;
@@ -447,6 +466,28 @@ class NormalProtocolConformance : public ProtocolConformance,
447466
SignatureConformances = {};
448467
}
449468

469+
/// Get the kind of source from which this conformance comes.
470+
ConformanceEntryKind getSourceKind() const {
471+
return SourceKindAndImplyingConformance.getInt();
472+
}
473+
474+
/// Get the protocol conformance which implied this implied conformance.
475+
NormalProtocolConformance *getImplyingConformance() const {
476+
assert(getSourceKind() == ConformanceEntryKind::Implied);
477+
return SourceKindAndImplyingConformance.getPointer();
478+
}
479+
480+
void setSourceKindAndImplyingConformance(
481+
ConformanceEntryKind sourceKind,
482+
NormalProtocolConformance *implyingConformance) {
483+
assert(sourceKind != ConformanceEntryKind::Inherited &&
484+
"a normal conformance cannot be inherited");
485+
assert((sourceKind == ConformanceEntryKind::Implied) ==
486+
(bool)implyingConformance &&
487+
"an implied conformance needs something that implies it");
488+
SourceKindAndImplyingConformance = {implyingConformance, sourceKind};
489+
}
490+
450491
/// Determine whether this conformance is lazily loaded.
451492
///
452493
/// This only matters to the AST verifier.
@@ -666,6 +707,15 @@ class SpecializedProtocolConformance : public ProtocolConformance,
666707
return GenericConformance->getState();
667708
}
668709

710+
/// Get the kind of source from which this conformance comes.
711+
ConformanceEntryKind getSourceKind() const {
712+
return GenericConformance->getSourceKind();
713+
}
714+
/// Get the protocol conformance which implied this implied conformance.
715+
NormalProtocolConformance *getImplyingConformance() const {
716+
return GenericConformance->getImplyingConformance();
717+
}
718+
669719
bool hasTypeWitness(AssociatedTypeDecl *assocType,
670720
LazyResolver *resolver = nullptr) const;
671721

@@ -768,6 +818,13 @@ class InheritedProtocolConformance : public ProtocolConformance,
768818
return InheritedConformance->getState();
769819
}
770820

821+
/// Get the kind of source from which this conformance comes.
822+
ConformanceEntryKind getSourceKind() const {
823+
return ConformanceEntryKind::Inherited;
824+
}
825+
/// Get the protocol conformance which implied this implied conformance.
826+
NormalProtocolConformance *getImplyingConformance() const { return nullptr; }
827+
771828
bool hasTypeWitness(AssociatedTypeDecl *assocType,
772829
LazyResolver *resolver = nullptr) const {
773830
return InheritedConformance->hasTypeWitness(assocType, resolver);

include/swift/Parse/Lexer.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,11 @@ class Lexer {
318318

319319
/// Retrieve the string used to indent the line that contains the given
320320
/// source location.
321-
static StringRef getIndentationForLine(SourceManager &SM, SourceLoc Loc);
321+
///
322+
/// If \c ExtraIndentation is not null, it will be set to an appropriate
323+
/// additional intendation for adding code in a smaller scope "within" \c Loc.
324+
static StringRef getIndentationForLine(SourceManager &SM, SourceLoc Loc,
325+
StringRef *ExtraIndentation = nullptr);
322326

323327
/// \brief Determines if the given string is a valid non-operator
324328
/// identifier, without escaping characters.

0 commit comments

Comments
 (0)