Skip to content

Miscellaneous conformance cleanups #17994

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 4 commits into from
Jul 17, 2018
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
5 changes: 5 additions & 0 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ class alignas(1 << DeclAlignInBits) ProtocolConformance {
/// be satisfied.
ArrayRef<Requirement> getConditionalRequirements() const;

/// Substitute the conforming type and produce a ProtocolConformance that
/// applies to the substituted type.
ProtocolConformance *subst(Type substType,
SubstitutionMap subMap) const;

/// Substitute the conforming type and produce a ProtocolConformance that
/// applies to the substituted type.
ProtocolConformance *subst(Type substType,
Expand Down
26 changes: 21 additions & 5 deletions include/swift/AST/ProtocolConformanceRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ class ProtocolConformanceRef {
using UnionType = llvm::PointerUnion<ProtocolDecl*, ProtocolConformance*>;
UnionType Union;

explicit ProtocolConformanceRef(UnionType value) : Union(value) {
assert(value && "cannot construct ProtocolConformanceRef with null");
}
explicit ProtocolConformanceRef(UnionType value) : Union(value) {}

public:
/// Create an abstract protocol conformance reference.
explicit ProtocolConformanceRef(ProtocolDecl *proto) : Union(proto) {
Expand All @@ -63,17 +62,30 @@ class ProtocolConformanceRef {
"cannot construct ProtocolConformanceRef with null");
}

static ProtocolConformanceRef forInvalid() {
return ProtocolConformanceRef(UnionType((ProtocolDecl *)nullptr));
}

bool isInvalid() const {
return !Union;
}

/// Create either a concrete or an abstract protocol conformance reference,
/// depending on whether ProtocolConformance is null.
explicit ProtocolConformanceRef(ProtocolDecl *protocol,
ProtocolConformance *conf);

bool isConcrete() const { return Union.is<ProtocolConformance*>(); }
bool isConcrete() const {
return !isInvalid() && Union.is<ProtocolConformance*>();
}
ProtocolConformance *getConcrete() const {
return Union.get<ProtocolConformance*>();
}

bool isAbstract() const { return Union.is<ProtocolDecl*>(); }
bool isAbstract() const {
return !isInvalid() && Union.is<ProtocolDecl*>();
}

ProtocolDecl *getAbstract() const {
return Union.get<ProtocolDecl*>();
}
Expand All @@ -87,6 +99,10 @@ class ProtocolConformanceRef {
/// Return the protocol requirement.
ProtocolDecl *getRequirement() const;

/// Apply a substitution to the conforming type.
ProtocolConformanceRef subst(Type origType,
SubstitutionMap subMap) const;

/// Apply a substitution to the conforming type.
ProtocolConformanceRef subst(Type origType,
TypeSubstitutionFn subs,
Expand Down
4 changes: 1 addition & 3 deletions include/swift/SIL/TypeSubstCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {

ProtocolConformanceRef remapConformance(Type type,
ProtocolConformanceRef conf) {
return conf.subst(type,
QuerySubstitutionMap{SubsMap},
LookUpConformanceInSubstitutionMap(SubsMap));
return conf.subst(type, SubsMap);
}

SubstitutionMap remapSubstitutionMap(SubstitutionMap Subs) {
Expand Down
69 changes: 35 additions & 34 deletions include/swift/Serialization/DeclTypeRecordNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ TYPE(TUPLE)
TRAILING_INFO(TUPLE_TYPE_ELT)
TYPE(FUNCTION)
TYPE(METATYPE)
TYPE(LVALUE_unused)
TYPE(INOUT)
TYPE(ARCHETYPE)
TYPE(PROTOCOL_COMPOSITION)
Expand Down Expand Up @@ -144,42 +143,44 @@ PATTERN(ANY)
PATTERN(TYPED)
PATTERN(VAR)

OTHER(PARAMETERLIST, 226)
OTHER(PARAMETERLIST_ELT, 227)
OTHER(FOREIGN_ERROR_CONVENTION, 228)
OTHER(DECL_CONTEXT, 229)
OTHER(XREF_TYPE_PATH_PIECE, 230)
OTHER(XREF_VALUE_PATH_PIECE, 231)
OTHER(XREF_EXTENSION_PATH_PIECE, 232)
OTHER(XREF_OPERATOR_OR_ACCESSOR_PATH_PIECE, 233)
OTHER(XREF_GENERIC_PARAM_PATH_PIECE, 234)
OTHER(XREF_INITIALIZER_PATH_PIECE, 235)

OTHER(ABSTRACT_CLOSURE_EXPR_CONTEXT, 236)
OTHER(PATTERN_BINDING_INITIALIZER_CONTEXT, 237)
OTHER(DEFAULT_ARGUMENT_INITIALIZER_CONTEXT, 238)
OTHER(TOP_LEVEL_CODE_DECL_CONTEXT, 239)

OTHER(GENERIC_PARAM_LIST, 240)
OTHER(PARAMETERLIST, 210)
OTHER(PARAMETERLIST_ELT, 211)
OTHER(FOREIGN_ERROR_CONVENTION, 212)
OTHER(DECL_CONTEXT, 213)
OTHER(XREF_TYPE_PATH_PIECE, 214)
OTHER(XREF_VALUE_PATH_PIECE, 215)
OTHER(XREF_EXTENSION_PATH_PIECE, 216)
OTHER(XREF_OPERATOR_OR_ACCESSOR_PATH_PIECE, 217)
OTHER(XREF_GENERIC_PARAM_PATH_PIECE, 218)
OTHER(XREF_INITIALIZER_PATH_PIECE, 219)

OTHER(ABSTRACT_CLOSURE_EXPR_CONTEXT, 220)
OTHER(PATTERN_BINDING_INITIALIZER_CONTEXT, 221)
OTHER(DEFAULT_ARGUMENT_INITIALIZER_CONTEXT, 222)
OTHER(TOP_LEVEL_CODE_DECL_CONTEXT, 223)

OTHER(GENERIC_PARAM_LIST, 230)
TRAILING_INFO(GENERIC_PARAM)
TRAILING_INFO(GENERIC_REQUIREMENT)
TRAILING_INFO(LAYOUT_REQUIREMENT)
OTHER(GENERIC_SIGNATURE, 244)
OTHER(SIL_GENERIC_ENVIRONMENT, 245)
OTHER(SUBSTITUTION_MAP, 246)

OTHER(LOCAL_DISCRIMINATOR, 248)
OTHER(PRIVATE_DISCRIMINATOR, 249)

OTHER(ABSTRACT_PROTOCOL_CONFORMANCE, 250)
OTHER(NORMAL_PROTOCOL_CONFORMANCE, 251)
OTHER(SPECIALIZED_PROTOCOL_CONFORMANCE, 252)
OTHER(INHERITED_PROTOCOL_CONFORMANCE, 253)
OTHER(SIL_LAYOUT, 197) // FIXME: Note out-of-order
OTHER(NORMAL_PROTOCOL_CONFORMANCE_ID, 198) // FIXME: Note out-of-order
OTHER(PROTOCOL_CONFORMANCE_XREF, 199) // FIXME: Note out-of-order
OTHER(MEMBERS, 254)
OTHER(XREF, 255)
OTHER(GENERIC_SIGNATURE, 234)
OTHER(SIL_GENERIC_ENVIRONMENT, 235)
OTHER(SUBSTITUTION_MAP, 236)

OTHER(LOCAL_DISCRIMINATOR, 237)
OTHER(PRIVATE_DISCRIMINATOR, 238)

OTHER(ABSTRACT_PROTOCOL_CONFORMANCE, 240)
OTHER(NORMAL_PROTOCOL_CONFORMANCE, 241)
OTHER(SPECIALIZED_PROTOCOL_CONFORMANCE, 242)
OTHER(INHERITED_PROTOCOL_CONFORMANCE, 243)
OTHER(INVALID_PROTOCOL_CONFORMANCE, 244)

OTHER(SIL_LAYOUT, 245)
OTHER(NORMAL_PROTOCOL_CONFORMANCE_ID, 246)
OTHER(PROTOCOL_CONFORMANCE_XREF, 247)
OTHER(MEMBERS, 248)
OTHER(XREF, 249)

#undef RECORD
#undef DECLTYPERECORDNODES_HAS_RECORD_VAL
Expand Down
7 changes: 6 additions & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const uint16_t VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t VERSION_MINOR = 426; // SIL key path external components with local attempts
const uint16_t VERSION_MINOR = 427; // Invalid conformances

using DeclIDField = BCFixed<31>;

Expand Down Expand Up @@ -1287,6 +1287,11 @@ namespace decls_block {
DeclIDField // the protocol
>;

/// A placeholder for an invalid conformance.
using InvalidProtocolConformanceLayout = BCRecordLayout<
INVALID_PROTOCOL_CONFORMANCE
>;

using NormalProtocolConformanceLayout = BCRecordLayout<
NORMAL_PROTOCOL_CONFORMANCE,
DeclIDField, // the protocol
Expand Down
4 changes: 3 additions & 1 deletion lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2852,7 +2852,9 @@ static void dumpProtocolConformanceRefRec(
const ProtocolConformanceRef conformance, llvm::raw_ostream &out,
unsigned indent,
llvm::SmallPtrSetImpl<const ProtocolConformance *> &visited) {
if (conformance.isConcrete()) {
if (conformance.isInvalid()) {
out.indent(indent) << "(invalid_conformance)";
} else if (conformance.isConcrete()) {
dumpProtocolConformanceRec(conformance.getConcrete(), out, indent, visited);
} else {
out.indent(indent) << "(abstract_conformance protocol="
Expand Down
38 changes: 28 additions & 10 deletions lib/AST/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,30 @@ ProtocolConformanceRef::ProtocolConformanceRef(ProtocolDecl *protocol,
}

ProtocolDecl *ProtocolConformanceRef::getRequirement() const {
assert(!isInvalid());

if (isConcrete()) {
return getConcrete()->getProtocol();
} else {
return getAbstract();
}
}

ProtocolConformanceRef
ProtocolConformanceRef::subst(Type origType,
SubstitutionMap subMap) const {
return subst(origType,
QuerySubstitutionMap{subMap},
LookUpConformanceInSubstitutionMap(subMap));
}

ProtocolConformanceRef
ProtocolConformanceRef::subst(Type origType,
TypeSubstitutionFn subs,
LookupConformanceFn conformances) const {
if (isInvalid())
return *this;

auto substType = origType.subst(subs, conformances,
SubstFlags::UseErrorType);

Expand All @@ -96,8 +109,7 @@ ProtocolConformanceRef::subst(Type origType,
// If this is a class, we need to traffic in the actual type that
// implements the protocol, not 'Self' and not any subclasses (with their
// inherited conformances).
substType =
substType->eraseDynamicSelfType()->getSuperclassForDecl(classDecl);
substType = substType->getSuperclassForDecl(classDecl);
}
return ProtocolConformanceRef(
getConcrete()->subst(substType, subs, conformances));
Expand Down Expand Up @@ -130,6 +142,8 @@ ProtocolConformanceRef::getTypeWitnessByName(Type type,
ProtocolConformanceRef conformance,
Identifier name,
LazyResolver *resolver) {
assert(!conformance.isInvalid());

// Find the named requirement.
AssociatedTypeDecl *assocType = nullptr;
auto members = conformance.getRequirement()->lookupDirect(name);
Expand Down Expand Up @@ -739,9 +753,7 @@ ProtocolConformanceRef::getAssociatedConformance(Type conformingType,
SubstitutionMap::getProtocolSubstitutions(getRequirement(),
conformingType, *this);
auto abstractConf = ProtocolConformanceRef(protocol);
return abstractConf.subst(assocType,
QuerySubstitutionMap{subMap},
LookUpConformanceInSubstitutionMap(subMap));
return abstractConf.subst(assocType, subMap);
}

ProtocolConformanceRef
Expand Down Expand Up @@ -942,9 +954,7 @@ SpecializedProtocolConformance::getAssociatedConformance(Type assocType,
? conformance.getConcrete()->getType()
: GenericConformance->getAssociatedType(assocType, resolver));

return conformance.subst(origType,
QuerySubstitutionMap{subMap},
LookUpConformanceInSubstitutionMap(subMap));
return conformance.subst(origType, subMap);
}

ConcreteDeclRef
Expand Down Expand Up @@ -1027,6 +1037,14 @@ bool ProtocolConformance::isVisibleFrom(const DeclContext *dc) const {
return true;
}

ProtocolConformance *
ProtocolConformance::subst(Type substType,
SubstitutionMap subMap) const {
return subst(substType,
QuerySubstitutionMap{subMap},
LookUpConformanceInSubstitutionMap(subMap));
}

ProtocolConformance *
ProtocolConformance::subst(Type substType,
TypeSubstitutionFn subs,
Expand Down Expand Up @@ -1351,14 +1369,14 @@ ProtocolConformance *ProtocolConformance::getCanonicalConformance() {

/// Check of all types used by the conformance are canonical.
bool ProtocolConformanceRef::isCanonical() const {
if (isAbstract())
if (isAbstract() || isInvalid())
return true;
return getConcrete()->isCanonical();
}

ProtocolConformanceRef
ProtocolConformanceRef::getCanonicalConformanceRef() const {
if (isAbstract())
if (isAbstract() || isInvalid())
return *this;
return ProtocolConformanceRef(getConcrete()->getCanonicalConformance());
}
Expand Down
10 changes: 8 additions & 2 deletions lib/AST/SubstitutionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ SubstitutionMap SubstitutionMap::get(GenericSignature *genericSig,
auto protoType = req.getSecondType()->castTo<ProtocolType>();
auto proto = protoType->getDecl();
auto conformance = lookupConformance(depTy, replacement, proto)
.getValueOr(ProtocolConformanceRef(proto));
.getValueOr(ProtocolConformanceRef::forInvalid());
conformances.push_back(conformance);
}

Expand Down Expand Up @@ -369,6 +369,9 @@ SubstitutionMap::lookupConformance(CanType type, ProtocolDecl *proto) const {
continue;
}

if (conformance->isInvalid())
return conformance;

// If we've hit an abstract conformance, everything from here on out is
// abstract.
// FIXME: This may not always be true, but it holds for now.
Expand Down Expand Up @@ -444,7 +447,7 @@ SubstitutionMap SubstitutionMap::subst(TypeSubstitutionFn subs,
ProtocolDecl *proto) ->Optional<ProtocolConformanceRef> {
auto conformance =
lookupConformance(dependentType, proto)
.getValueOr(ProtocolConformanceRef(proto));
.getValueOr(ProtocolConformanceRef::forInvalid());
auto substType = dependentType.subst(*this, SubstFlags::UseErrorType);
return conformance.subst(substType, subs, conformances);
});
Expand Down Expand Up @@ -610,6 +613,9 @@ void SubstitutionMap::verify() const {

auto conformance = getConformances()[conformanceIndex];

if (conformance.isInvalid())
continue;

// An existential type can have an abstract conformance to
// AnyObject or an @objc protocol.
if (conformance.isAbstract() &&
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGenBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ MetatypeInst *SILGenBuilder::createMetatype(SILLocation loc, SILType metatype) {
if (!decl)
return false;

if (isa<ProtocolDecl>(decl))
return false;

auto *genericSig = decl->getGenericSignature();
if (!genericSig)
return false;
Expand Down
11 changes: 8 additions & 3 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1998,9 +1998,14 @@ Type simplifyTypeImpl(ConstraintSystem &cs, Type type, Fn getFixedTypeFn) {
Type lookupBaseType = newBase->getWithoutSpecifierType();

if (lookupBaseType->mayHaveMembers()) {
auto subs = lookupBaseType->getContextSubstitutionMap(
cs.DC->getParentModule(),
assocType->getDeclContext());
auto *proto = assocType->getProtocol();
auto conformance = cs.DC->getParentModule()->lookupConformance(
lookupBaseType, proto);
if (!conformance)
return DependentMemberType::get(lookupBaseType, assocType);

auto subs = SubstitutionMap::getProtocolSubstitutions(
proto, lookupBaseType, *conformance);
auto result = assocType->getDeclaredInterfaceType().subst(subs);

if (result && !result->hasError())
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,10 @@ ProtocolConformanceRef ModuleFile::readConformance(

unsigned kind = Cursor.readRecord(next.ID, scratch);
switch (kind) {
case INVALID_PROTOCOL_CONFORMANCE: {
return ProtocolConformanceRef::forInvalid();
}

case ABSTRACT_PROTOCOL_CONFORMANCE: {
DeclID protoID;
AbstractProtocolConformanceLayout::readRecord(scratch, protoID);
Expand Down
1 change: 1 addition & 0 deletions lib/Serialization/SILFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ namespace sil_block {
= decls_block::SPECIALIZED_PROTOCOL_CONFORMANCE,
INHERITED_PROTOCOL_CONFORMANCE
= decls_block::INHERITED_PROTOCOL_CONFORMANCE,
INVALID_PROTOCOL_CONFORMANCE = decls_block::INVALID_PROTOCOL_CONFORMANCE,
GENERIC_PARAM = decls_block::GENERIC_PARAM,
GENERIC_REQUIREMENT = decls_block::GENERIC_REQUIREMENT,
LAYOUT_REQUIREMENT = decls_block::LAYOUT_REQUIREMENT,
Expand Down
Loading