Merge pull request #10064 from CodaFi/thats-not-my-name
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 14852dc..9416e6d 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -2372,6 +2372,9 @@
return D->getKind() >= DeclKind::First_TypeDecl &&
D->getKind() <= DeclKind::Last_TypeDecl;
}
+
+ /// Compute an ordering between two type declarations that is ABI-stable.
+ static int compare(const TypeDecl *type1, const TypeDecl *type2);
};
/// A type declaration that can have generic parameters attached to it. Because
diff --git a/include/swift/AST/DeclContext.h b/include/swift/AST/DeclContext.h
index aafc243..b3ba662 100644
--- a/include/swift/AST/DeclContext.h
+++ b/include/swift/AST/DeclContext.h
@@ -494,6 +494,19 @@
= nullptr,
bool sorted = false) const;
+ /// Retrieve the syntactic depth of this declaration context, i.e.,
+ /// the number of non-module-scoped contexts.
+ ///
+ /// For an extension of a nested type, the extension is depth 1.
+ unsigned getSyntacticDepth() const;
+
+ /// Retrieve the semantic depth of this declaration context, i.e.,
+ /// the number of non-module-scoped contexts.
+ ///
+ /// For an extension of a nested type, the depth of the nested type itself
+ /// is also included.
+ unsigned getSemanticDepth() const;
+
/// \returns true if traversal was aborted, false otherwise.
bool walkContext(ASTWalker &Walker);
diff --git a/include/swift/AST/GenericSignatureBuilder.h b/include/swift/AST/GenericSignatureBuilder.h
index cac90b3..f44ad76 100644
--- a/include/swift/AST/GenericSignatureBuilder.h
+++ b/include/swift/AST/GenericSignatureBuilder.h
@@ -1248,7 +1248,7 @@
Identifier name;
/// The associated type or typealias for a resolved nested type.
- TypeDecl *assocTypeOrAlias;
+ TypeDecl *assocTypeOrConcrete;
/// The generic parameter key for a root.
GenericParamKey genericParam;
@@ -1256,10 +1256,10 @@
PAIdentifier(Identifier name) : name(name) { }
PAIdentifier(AssociatedTypeDecl *assocType)
- : assocTypeOrAlias(assocType) { }
+ : assocTypeOrConcrete(assocType) { }
- PAIdentifier(TypeAliasDecl *typeAlias)
- : assocTypeOrAlias(typeAlias) { }
+ PAIdentifier(TypeDecl *concreteDecl)
+ : assocTypeOrConcrete(concreteDecl) { }
PAIdentifier(GenericParamKey genericParam) : genericParam(genericParam) { }
} identifier;
@@ -1342,9 +1342,9 @@
assert(parent != nullptr && "Not an associated type?");
}
- /// \brief Construct a new potential archetype for a type alias.
- PotentialArchetype(PotentialArchetype *parent, TypeAliasDecl *typeAlias)
- : parentOrBuilder(parent), identifier(typeAlias),
+ /// \brief Construct a new potential archetype for a concrete declaration.
+ PotentialArchetype(PotentialArchetype *parent, TypeDecl *concreteDecl)
+ : parentOrBuilder(parent), identifier(concreteDecl),
isUnresolvedNestedType(false),
IsRecursive(false), Invalid(false),
DiagnosedRename(false)
@@ -1396,16 +1396,19 @@
if (isUnresolvedNestedType)
return nullptr;
- return dyn_cast<AssociatedTypeDecl>(identifier.assocTypeOrAlias);
+ return dyn_cast<AssociatedTypeDecl>(identifier.assocTypeOrConcrete);
}
+ /// Determine whether this PA is still unresolved.
+ bool isUnresolved() const { return isUnresolvedNestedType; }
+
/// Resolve the potential archetype to the given associated type.
void resolveAssociatedType(AssociatedTypeDecl *assocType,
GenericSignatureBuilder &builder);
/// Resolve the potential archetype to the given typealias.
- void resolveTypeAlias(TypeAliasDecl *typealias,
- GenericSignatureBuilder &builder);
+ void resolveConcreteType(TypeDecl *concreteDecl,
+ GenericSignatureBuilder &builder);
/// Determine whether this is a generic parameter.
bool isGenericParam() const {
@@ -1436,16 +1439,19 @@
if (isUnresolvedNestedType)
return identifier.name;
- return identifier.assocTypeOrAlias->getName();
+ return identifier.assocTypeOrConcrete->getName();
}
- /// Retrieve the type alias.
- TypeAliasDecl *getTypeAliasDecl() const {
+ /// Retrieve the concrete type declaration.
+ TypeDecl *getConcreteTypeDecl() const {
assert(getParent() && "not a nested type");
if (isUnresolvedNestedType)
return nullptr;
- return dyn_cast<TypeAliasDecl>(identifier.assocTypeOrAlias);
+ if (isa<AssociatedTypeDecl>(identifier.assocTypeOrConcrete))
+ return nullptr;
+
+ return identifier.assocTypeOrConcrete;
}
/// Retrieve the set of protocols to which this potential archetype
@@ -1548,8 +1554,9 @@
PotentialArchetype *getNestedType(AssociatedTypeDecl *assocType,
GenericSignatureBuilder &builder);
- /// \brief Retrieve (or create) a nested type with a known typealias.
- PotentialArchetype *getNestedType(TypeAliasDecl *typealias,
+ /// \brief Retrieve (or create) a nested type with a known concrete type
+ /// declaration.
+ PotentialArchetype *getNestedType(TypeDecl *concreteDecl,
GenericSignatureBuilder &builder);
/// Describes the kind of update that is performed.
@@ -1581,7 +1588,7 @@
/// type or typealias of the given protocol, unless the \c kind implies that
/// a potential archetype should not be created if it's missing.
PotentialArchetype *updateNestedTypeForConformance(
- PointerUnion<AssociatedTypeDecl *, TypeAliasDecl *> type,
+ PointerUnion<AssociatedTypeDecl *, TypeDecl *> type,
NestedTypeUpdate kind);
/// Update the named nested type when we know this type conforms to the given
diff --git a/lib/AST/ASTVerifier.cpp b/lib/AST/ASTVerifier.cpp
index 7c8a676..27e9145 100644
--- a/lib/AST/ASTVerifier.cpp
+++ b/lib/AST/ASTVerifier.cpp
@@ -697,6 +697,11 @@
if (!shouldVerify(cast<Expr>(expr)))
return false;
+ // In rare instances we clear the opaque value because we no
+ // longer have a subexpression that references it.
+ if (!expr->getOpaqueValue())
+ return true;
+
assert(!OpaqueValues.count(expr->getOpaqueValue()));
OpaqueValues[expr->getOpaqueValue()] = 0;
assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==0);
@@ -705,6 +710,11 @@
}
void cleanup(OpenExistentialExpr *expr) {
+ // In rare instances we clear the opaque value because we no
+ // longer have a subexpression that references it.
+ if (!expr->getOpaqueValue())
+ return;
+
assert(OpaqueValues.count(expr->getOpaqueValue()));
OpaqueValues.erase(expr->getOpaqueValue());
assert(OpenedExistentialArchetypes.count(expr->getOpenedArchetype())==1);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 412a0ab..e3014bc 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1165,7 +1165,13 @@
case DeclKind::Class:
// Final properties can always be direct, even in classes.
- return !storage->isFinal();
+ if (storage->isFinal())
+ return false;
+ // Extension properties are statically dispatched, unless they're @objc.
+ if (storage->getDeclContext()->isExtensionContext()
+ && !storage->isObjC())
+ return false;
+ return true;
}
llvm_unreachable("bad DeclKind");
}
@@ -2067,6 +2073,47 @@
return interfaceType->castTo<MetatypeType>()->getInstanceType();
}
+int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) {
+ // Order based on the enclosing declaration.
+ auto dc1 = type1->getDeclContext();
+ auto dc2 = type2->getDeclContext();
+
+ // Prefer lower depths.
+ auto depth1 = dc1->getSemanticDepth();
+ auto depth2 = dc2->getSemanticDepth();
+ if (depth1 != depth2)
+ return depth1 < depth2 ? -1 : +1;
+
+ // Prefer module names earlier in the alphabet.
+ if (dc1->isModuleScopeContext() && dc2->isModuleScopeContext()) {
+ auto module1 = dc1->getParentModule();
+ auto module2 = dc2->getParentModule();
+ if (int result = module1->getName().str().compare(module2->getName().str()))
+ return result;
+ }
+
+ auto nominal1 = dc1->getAsNominalTypeOrNominalTypeExtensionContext();
+ auto nominal2 = dc2->getAsNominalTypeOrNominalTypeExtensionContext();
+ if (static_cast<bool>(nominal1) != static_cast<bool>(nominal2)) {
+ return static_cast<bool>(nominal1) ? -1 : +1;
+ }
+ if (nominal1 && nominal2) {
+ if (int result = compare(nominal1, nominal2))
+ return result;
+ }
+
+ if (int result = type1->getBaseName().getIdentifier().str().compare(
+ type2->getBaseName().getIdentifier().str()))
+ return result;
+
+ // Error case: two type declarations that cannot be distinguished.
+ if (type1 < type2)
+ return -1;
+ if (type1 > type2)
+ return +1;
+ return 0;
+}
+
bool NominalTypeDecl::hasFixedLayout() const {
// Private and (unversioned) internal types always have a
// fixed layout.
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index 4926db3..4d5bfdb 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -656,6 +656,30 @@
return getParent()->isCascadingContextForLookup(true);
}
+unsigned DeclContext::getSyntacticDepth() const {
+ // Module scope == depth 0.
+ if (isModuleScopeContext())
+ return 0;
+
+ return 1 + getParent()->getSyntacticDepth();
+}
+
+unsigned DeclContext::getSemanticDepth() const {
+ // For extensions, count the depth of the nominal type being extended.
+ if (auto ext = dyn_cast<ExtensionDecl>(this)) {
+ if (auto nominal = getAsNominalTypeOrNominalTypeExtensionContext())
+ return nominal->getSemanticDepth();
+
+ return 1;
+ }
+
+ // Module scope == depth 0.
+ if (isModuleScopeContext())
+ return 0;
+
+ return 1 + getParent()->getSemanticDepth();
+}
+
bool DeclContext::walkContext(ASTWalker &Walker) {
switch (getContextKind()) {
case DeclContextKind::Module:
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 0bc4f85..afe512e 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -316,19 +316,25 @@
void visitOpenExistentialExpr(OpenExistentialExpr *E,
AccessKind accessKind) {
- bool opaqueValueHadAK = E->getOpaqueValue()->hasLValueAccessKind();
- AccessKind oldOpaqueValueAK =
- (opaqueValueHadAK ? E->getOpaqueValue()->getLValueAccessKind()
- : AccessKind::Read);
+ AccessKind oldOpaqueValueAK;
+ bool opaqueValueHadAK;
+ if (E->getOpaqueValue()) {
+ opaqueValueHadAK = E->getOpaqueValue()->hasLValueAccessKind();
+ oldOpaqueValueAK =
+ (opaqueValueHadAK ? E->getOpaqueValue()->getLValueAccessKind()
+ : AccessKind::Read);
+ }
visit(E->getSubExpr(), accessKind);
- // Propagate the new access kind from the OVE to the original existential
- // if we just set or changed it on the OVE.
- if (E->getOpaqueValue()->hasLValueAccessKind()) {
- auto newOpaqueValueAK = E->getOpaqueValue()->getLValueAccessKind();
- if (!opaqueValueHadAK || newOpaqueValueAK != oldOpaqueValueAK)
- visit(E->getExistentialValue(), newOpaqueValueAK);
+ if (E->getOpaqueValue()) {
+ // Propagate the new access kind from the OVE to the original
+ // existential if we just set or changed it on the OVE.
+ if (E->getOpaqueValue()->hasLValueAccessKind()) {
+ auto newOpaqueValueAK = E->getOpaqueValue()->getLValueAccessKind();
+ if (!opaqueValueHadAK || newOpaqueValueAK != oldOpaqueValueAK)
+ visit(E->getExistentialValue(), newOpaqueValueAK);
+ }
}
}
diff --git a/lib/AST/GenericEnvironment.cpp b/lib/AST/GenericEnvironment.cpp
index 1292e2f..979f899 100644
--- a/lib/AST/GenericEnvironment.cpp
+++ b/lib/AST/GenericEnvironment.cpp
@@ -33,17 +33,6 @@
Type());
}
-/// Compute the depth of the \c DeclContext chain.
-static unsigned declContextDepth(const DeclContext *dc) {
- unsigned depth = 0;
- while (auto parentDC = dc->getParent()) {
- ++depth;
- dc = parentDC;
- }
-
- return depth;
-}
-
void GenericEnvironment::setOwningDeclContext(DeclContext *newOwningDC) {
if (!OwningDC) {
OwningDC = newOwningDC;
@@ -54,8 +43,8 @@
return;
// Find the least common ancestor context to be the owner.
- unsigned oldDepth = declContextDepth(OwningDC);
- unsigned newDepth = declContextDepth(newOwningDC);
+ unsigned oldDepth = OwningDC->getSyntacticDepth();
+ unsigned newDepth = newOwningDC->getSyntacticDepth();
while (oldDepth > newDepth) {
OwningDC = OwningDC->getParent();
diff --git a/lib/AST/GenericSignatureBuilder.cpp b/lib/AST/GenericSignatureBuilder.cpp
index 4e4ca68..283779a 100644
--- a/lib/AST/GenericSignatureBuilder.cpp
+++ b/lib/AST/GenericSignatureBuilder.cpp
@@ -1057,8 +1057,9 @@
ProtocolDecl *proto = nullptr;
if (auto assocType = getResolvedAssociatedType()) {
proto = assocType->getProtocol();
- } else if (auto typeAlias = getTypeAliasDecl()) {
- proto = typeAlias->getParent()->getAsProtocolOrProtocolExtensionContext();
+ } else if (auto concreteDecl = getConcreteTypeDecl()) {
+ proto = concreteDecl->getDeclContext()
+ ->getAsProtocolOrProtocolExtensionContext();
}
if (proto) {
@@ -1086,20 +1087,20 @@
GenericSignatureBuilder &builder) {
assert(isUnresolvedNestedType && "associated type is already resolved");
isUnresolvedNestedType = false;
- identifier.assocTypeOrAlias = assocType;
+ identifier.assocTypeOrConcrete = assocType;
assert(assocType->getName() == getNestedName());
assert(builder.Impl->NumUnresolvedNestedTypes > 0 &&
"Mismatch in number of unresolved nested types");
--builder.Impl->NumUnresolvedNestedTypes;
}
-void GenericSignatureBuilder::PotentialArchetype::resolveTypeAlias(
- TypeAliasDecl *typealias,
+void GenericSignatureBuilder::PotentialArchetype::resolveConcreteType(
+ TypeDecl *concreteDecl,
GenericSignatureBuilder &builder) {
assert(isUnresolvedNestedType && "nested type is already resolved");
isUnresolvedNestedType = false;
- identifier.assocTypeOrAlias = typealias;
- assert(typealias->getName() == getNestedName());
+ identifier.assocTypeOrConcrete = concreteDecl;
+ assert(concreteDecl->getName() == getNestedName());
assert(builder.Impl->NumUnresolvedNestedTypes > 0 &&
"Mismatch in number of unresolved nested types");
--builder.Impl->NumUnresolvedNestedTypes;
@@ -1285,7 +1286,7 @@
if (!superSource) return;
auto assocType = nestedPA->getResolvedAssociatedType();
- assert(assocType && "Not resolved to an associated type?");
+ if (!assocType) return;
// Dig out the type witness.
auto superConformance = superSource->getProtocolConformance();
@@ -1408,30 +1409,6 @@
return 0;
}
-/// Compare two typealiases in protocols.
-static int compareTypeAliases(TypeAliasDecl *typealias1,
- TypeAliasDecl *typealias2) {
- // - by name.
- if (int result = typealias1->getName().str().compare(
- typealias2->getName().str()))
- return result;
-
- // - by protocol, so t_n_m.`P.T` < t_n_m.`Q.T` (given P < Q)
- auto proto1 =
- typealias1->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
- auto proto2 =
- typealias2->getDeclContext()->getAsProtocolOrProtocolExtensionContext();
- if (int compareProtocols = ProtocolType::compareProtocols(&proto1, &proto2))
- return compareProtocols;
-
- // Error case: if we have two associated types with the same name in the
- // same protocol, just tie-break based on address.
- if (typealias1 != typealias2)
- return typealias1 < typealias2 ? -1 : +1;
-
- return 0;
-}
-
/// Canonical ordering for dependent types in generic signatures.
static int compareDependentTypes(PotentialArchetype * const* pa,
PotentialArchetype * const* pb) {
@@ -1441,12 +1418,12 @@
if (a == b)
return 0;
- // Typealiases must be ordered *after* everything else, to ensure they
- // don't become representatives in the case where a typealias is equated
+ // Concrete types must be ordered *after* everything else, to ensure they
+ // don't become representatives in the case where a concrete type is equated
// with an associated type.
if (a->getParent() && b->getParent() &&
- !!a->getTypeAliasDecl() != !!b->getTypeAliasDecl())
- return a->getTypeAliasDecl() ? +1 : -1;
+ !!a->getConcreteTypeDecl() != !!b->getConcreteTypeDecl())
+ return a->getConcreteTypeDecl() ? +1 : -1;
// Types that are equivalent to concrete types follow types that are still
// type parameters.
@@ -1489,12 +1466,13 @@
return +1;
}
- // Make sure typealiases are properly ordered, to avoid crashers.
- if (auto *aa = a->getTypeAliasDecl()) {
- auto *ab = b->getTypeAliasDecl();
+ // Make sure concrete type declarations are properly ordered, to avoid
+ // crashers.
+ if (auto *aa = a->getConcreteTypeDecl()) {
+ auto *ab = b->getConcreteTypeDecl();
assert(ab != nullptr && "Should have handled this case above");
- if (int result = compareTypeAliases(aa, ab))
+ if (int result = TypeDecl::compare(aa, ab))
return result;
}
@@ -1575,11 +1553,11 @@
PotentialArchetype *pa;
void operator()(Type type1, Type type2) const {
- if (pa->getParent() && pa->getTypeAliasDecl() &&
+ if (pa->getParent() && pa->getConcreteTypeDecl() &&
source->getLoc().isInvalid()) {
- diags.diagnose(pa->getTypeAliasDecl()->getLoc(),
+ diags.diagnose(pa->getConcreteTypeDecl()->getLoc(),
diag::protocol_typealias_conflict,
- pa->getTypeAliasDecl()->getName(),
+ pa->getConcreteTypeDecl()->getName(),
type1, type2);
return;
}
@@ -1658,9 +1636,9 @@
}
PotentialArchetype *PotentialArchetype::getNestedType(
- TypeAliasDecl *typealias,
+ TypeDecl *getConcreteTypeDecl,
GenericSignatureBuilder &builder) {
- return updateNestedTypeForConformance(typealias,
+ return updateNestedTypeForConformance(getConcreteTypeDecl,
NestedTypeUpdate::AddIfMissing);
}
@@ -1668,24 +1646,24 @@
Identifier name,
GenericSignatureBuilder &builder,
NestedTypeUpdate kind) {
- // Look for the best associated type or typealias within the protocols
+ // Look for the best associated type or concrete type within the protocols
// we know about.
AssociatedTypeDecl *bestAssocType = nullptr;
- TypeAliasDecl *bestTypeAlias = nullptr;
- SmallVector<TypeAliasDecl *, 4> typealiases;
+ TypeDecl *bestConcreteDecl = nullptr;
+ SmallVector<TypeDecl *, 4> concreteDecls;
auto rep = getRepresentative();
for (auto proto : rep->getConformsTo()) {
- // Look for an associated type and/or typealias with this name.
+ // Look for an associated type and/or concrete type with this name.
AssociatedTypeDecl *assocType = nullptr;
- TypeAliasDecl *typealias = nullptr;
+ TypeDecl *concreteDecl = nullptr;
for (auto member : proto->lookupDirect(name,
/*ignoreNewExtensions=*/true)) {
if (!assocType)
assocType = dyn_cast<AssociatedTypeDecl>(member);
- // FIXME: Filter out typealiases that aren't in the protocol itself?
- if (!typealias)
- typealias = dyn_cast<TypeAliasDecl>(member);
+ // FIXME: Filter out type declarations that aren't in the protocol itself?
+ if (!concreteDecl && !isa<AssociatedTypeDecl>(member))
+ concreteDecl = dyn_cast<TypeDecl>(member);
}
if (assocType &&
@@ -1693,13 +1671,14 @@
compareAssociatedTypes(assocType, bestAssocType) < 0))
bestAssocType = assocType;
- if (typealias) {
- // Record every typealias.
- typealiases.push_back(typealias);
+ if (concreteDecl) {
+ // Record every concrete type.
+ concreteDecls.push_back(concreteDecl);
- // Track the best typealias.
- if (!bestTypeAlias || compareTypeAliases(typealias, bestTypeAlias) < 0)
- bestTypeAlias = typealias;
+ // Track the best concrete type.
+ if (!bestConcreteDecl ||
+ TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0)
+ bestConcreteDecl = concreteDecl;
}
}
@@ -1710,25 +1689,47 @@
NestedTypeUpdate::AddIfMissing);
}
- // If we have an associated type, drop any typealiases that aren't in
+ // If we have an associated type, drop any concrete decls that aren't in
// the same module as the protocol.
// FIXME: This is an unprincipled hack for an unprincipled feature.
- typealiases.erase(
- std::remove_if(typealiases.begin(), typealiases.end(),
- [&](TypeAliasDecl *typealias) {
- return typealias->getParentModule() !=
- typealias->getDeclContext()
+ concreteDecls.erase(
+ std::remove_if(concreteDecls.begin(), concreteDecls.end(),
+ [&](TypeDecl *concreteDecl) {
+ return concreteDecl->getDeclContext()->getParentModule() !=
+ concreteDecl->getDeclContext()
->getAsNominalTypeOrNominalTypeExtensionContext()->getParentModule();
}),
- typealiases.end());
+ concreteDecls.end());
- // Update for all of the typealiases with this name, which will introduce
+ // If we haven't found anything yet but have a superclass, look for a type
+ // in the superclass.
+ if (!resultPA && concreteDecls.empty()) {
+ if (auto superclass = getSuperclass()) {
+ if (auto classDecl = superclass->getClassOrBoundGenericClass()) {
+ SmallVector<ValueDecl *, 2> superclassMembers;
+ classDecl->getParentModule()->lookupQualified(superclass, name, NL_QualifiedDefault | NL_OnlyTypes | NL_ProtocolMembers, nullptr,
+ superclassMembers);
+ for (auto member : superclassMembers) {
+ if (auto concreteDecl = dyn_cast<TypeDecl>(member)) {
+ // Track the best concrete type.
+ if (!bestConcreteDecl ||
+ TypeDecl::compare(concreteDecl, bestConcreteDecl) < 0)
+ bestConcreteDecl = concreteDecl;
+
+ concreteDecls.push_back(concreteDecl);
+ }
+ }
+ }
+ }
+ }
+
+ // Update for all of the concrete decls with this name, which will introduce
// various same-type constraints.
- for (auto typealias : typealiases) {
- auto typealiasPA = updateNestedTypeForConformance(typealias,
+ for (auto concreteDecl : concreteDecls) {
+ auto concreteDeclPA = updateNestedTypeForConformance(concreteDecl,
NestedTypeUpdate::AddIfMissing);
- if (!resultPA && typealias == bestTypeAlias)
- resultPA = typealiasPA;
+ if (!resultPA && concreteDecl == bestConcreteDecl)
+ resultPA = concreteDeclPA;
}
if (resultPA)
@@ -1771,48 +1772,49 @@
Identifier name,
ProtocolDecl *proto,
NestedTypeUpdate kind) {
- /// Determine whether there is an associated type or typealias with this name
- /// in this protocol. If not, there's nothing to do.
+ /// Determine whether there is an associated type or concrete type with this
+ /// name in this protocol. If not, there's nothing to do.
AssociatedTypeDecl *assocType = nullptr;
- TypeAliasDecl *typealias = nullptr;
+ TypeDecl *concreteDecl = nullptr;
for (auto member : proto->lookupDirect(name, /*ignoreNewExtensions=*/true)) {
if (!assocType)
assocType = dyn_cast<AssociatedTypeDecl>(member);
- // FIXME: Filter out typealiases that aren't in the protocol itself?
- if (!typealias)
- typealias = dyn_cast<TypeAliasDecl>(member);
+ // FIXME: Filter out concrete types that aren't in the protocol itself?
+ if (!concreteDecl && !isa<AssociatedTypeDecl>(member))
+ concreteDecl = dyn_cast<TypeDecl>(member);
}
- // There is no associated type or typealias with this name in this protocol
- if (!assocType && !typealias)
+ // There is no associated type or concrete type with this name in this
+ // protocol
+ if (!assocType && !concreteDecl)
return nullptr;
- // If we had both an associated type and a typealias, ignore the latter. This
- // is for ill-formed code.
+ // If we had both an associated type and a concrete type, ignore the latter.
+ // This is for ill-formed code.
if (assocType)
return updateNestedTypeForConformance(assocType, kind);
- return updateNestedTypeForConformance(typealias, kind);
+ return updateNestedTypeForConformance(concreteDecl, kind);
}
PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
- PointerUnion<AssociatedTypeDecl *, TypeAliasDecl *> type,
+ PointerUnion<AssociatedTypeDecl *, TypeDecl *> type,
NestedTypeUpdate kind) {
auto *assocType = type.dyn_cast<AssociatedTypeDecl *>();
- auto *typealias = type.dyn_cast<TypeAliasDecl *>();
- if (!assocType && !typealias)
+ auto *concreteDecl = type.dyn_cast<TypeDecl *>();
+ if (!assocType && !concreteDecl)
return nullptr;
- Identifier name = assocType ? assocType->getName() : typealias->getName();
+ Identifier name = assocType ? assocType->getName() : concreteDecl->getName();
ProtocolDecl *proto =
assocType ? assocType->getProtocol()
- : typealias->getDeclContext()
+ : concreteDecl->getDeclContext()
->getAsProtocolOrProtocolExtensionContext();
// Look for either an unresolved potential archetype (which we can resolve
// now) or a potential archetype with the appropriate associated type or
- // typealias.
+ // concrete type.
PotentialArchetype *resultPA = nullptr;
auto knownNestedTypes = NestedTypes.find(name);
bool shouldUpdatePA = false;
@@ -1824,7 +1826,7 @@
if (assocType) {
existingPA->resolveAssociatedType(assocType, builder);
} else {
- existingPA->resolveTypeAlias(typealias, builder);
+ existingPA->resolveConcreteType(concreteDecl, builder);
}
// We've resolved this nested type; nothing more to do.
@@ -1839,8 +1841,8 @@
break;
}
- // Do we have a typealias match?
- if (typealias && existingPA->getTypeAliasDecl() == typealias) {
+ // Do we have a concrete type match?
+ if (concreteDecl && existingPA->getConcreteTypeDecl() == concreteDecl) {
resultPA = existingPA;
break;
}
@@ -1860,7 +1862,7 @@
if (assocType)
resultPA = new PotentialArchetype(this, assocType);
else
- resultPA = new PotentialArchetype(this, typealias);
+ resultPA = new PotentialArchetype(this, concreteDecl);
auto &allNested = NestedTypes[name];
allNested.push_back(resultPA);
@@ -1903,28 +1905,38 @@
// If we have a potential archetype that requires more processing, do so now.
if (shouldUpdatePA) {
- // For typealiases, introduce a same-type requirement to the aliased type.
- if (typealias) {
+ // For concrete types, introduce a same-type requirement to the aliased
+ // type.
+ if (concreteDecl) {
// FIXME (recursive decl validation): if the alias doesn't have an
// interface type when getNestedType is called while building a
// protocol's generic signature (i.e. during validation), then it'll
// fail completely, because building that alias's interface type
// requires the protocol to be validated. This seems to occur when the
// alias's RHS involves archetypes from the protocol.
- if (!typealias->hasInterfaceType())
- builder.getLazyResolver()->resolveDeclSignature(typealias);
- if (typealias->hasInterfaceType()) {
- // The protocol typealias has an underlying type written in terms
+ if (!concreteDecl->hasInterfaceType())
+ builder.getLazyResolver()->resolveDeclSignature(concreteDecl);
+ if (concreteDecl->hasInterfaceType()) {
+ // The protocol concrete type has an underlying type written in terms
// of the protocol's 'Self' type.
- auto type = typealias->getDeclaredInterfaceType();
+ auto type = concreteDecl->getDeclaredInterfaceType();
- // Substitute in the type of the current PotentialArchetype in
- // place of 'Self' here.
- auto subMap = SubstitutionMap::getProtocolSubstitutions(
- proto, getDependentType(/*genericParams=*/{},
- /*allowUnresolved=*/true),
- ProtocolConformanceRef(proto));
- type = type.subst(subMap, SubstFlags::UseErrorType);
+ if (proto) {
+ // Substitute in the type of the current PotentialArchetype in
+ // place of 'Self' here.
+ auto subMap = SubstitutionMap::getProtocolSubstitutions(
+ proto, getDependentType(/*genericParams=*/{},
+ /*allowUnresolved=*/true),
+ ProtocolConformanceRef(proto));
+ type = type.subst(subMap, SubstFlags::UseErrorType);
+ } else {
+ // Substitute in the superclass type.
+ auto superclass = getSuperclass();
+ auto superclassDecl = superclass->getClassOrBoundGenericClass();
+ type = superclass->getTypeOfMember(
+ superclassDecl->getParentModule(), concreteDecl,
+ concreteDecl->getDeclaredInterfaceType());
+ }
builder.addSameTypeRequirement(
UnresolvedType(resultPA),
@@ -1936,8 +1948,12 @@
// If there's a superclass constraint that conforms to the protocol,
// add the appropriate same-type relationship.
- if (auto superSource = builder.resolveSuperConformance(this, proto))
- maybeAddSameTypeRequirementForNestedType(resultPA, superSource, builder);
+ if (proto) {
+ if (auto superSource = builder.resolveSuperConformance(this, proto)) {
+ maybeAddSameTypeRequirementForNestedType(resultPA, superSource,
+ builder);
+ }
+ }
// We know something concrete about the parent PA, so we need to propagate
// that information to this new archetype.
@@ -2398,18 +2414,6 @@
if (!pa) return None;
}
- auto rep = pa->getRepresentative();
- if (!rep->getParent() || !rep->getTypeAliasDecl())
- return ResolvedType::forPotentialArchetype(pa);
-
- // We're assuming that an equivalence class with a type alias representative
- // doesn't have a "true" (i.e. associated type) potential archetype.
- assert(llvm::all_of(rep->getEquivalenceClassMembers(),
- [&](PotentialArchetype *pa) {
- return pa->getParent() && pa->getTypeAliasDecl();
- }) &&
- "unexpected typealias representative with non-typealias equivalent");
-
return ResolvedType::forPotentialArchetype(pa);
}
@@ -2607,16 +2611,16 @@
assocType);
}
- if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
- // Resolve the underlying type, if we haven't done so yet.
- if (!typealias->hasInterfaceType()) {
- getLazyResolver()->resolveDeclSignature(typealias);
- }
+ // Resolve the underlying type, if we haven't done so yet.
+ if (!typeDecl->hasInterfaceType()) {
+ getLazyResolver()->resolveDeclSignature(typeDecl);
+ }
+ if (auto typealias = dyn_cast<TypeAliasDecl>(typeDecl)) {
return typealias->getUnderlyingTypeLoc().getType();
}
- return Type();
+ return typeDecl->getDeclaredInterfaceType();
};
// An inferred same-type requirement between the two type declarations
@@ -2845,11 +2849,24 @@
}
};
+ // Local function to resolve nested types found in the superclass.
+ auto updateSuperclassNestedTypes = [&] {
+ for (auto &nested : T->getNestedTypes()) {
+ if (nested.second.empty()) continue;
+ if (nested.second.front()->isUnresolved()) {
+ (void)T->getNestedArchetypeAnchor(nested.first, *this,
+ PotentialArchetype::NestedTypeUpdate::ResolveExisting);
+ }
+ }
+ };
+
// If we haven't yet recorded a superclass constraint for this equivalence
// class, do so now.
if (!equivClass->superclass) {
equivClass->superclass = superclass;
updateSuperclassConformances();
+ updateSuperclassNestedTypes();
+
// Presence of a superclass constraint implies a _Class layout
// constraint.
auto layoutReqSource = source->viaSuperclass(*this, nullptr);
@@ -2880,6 +2897,7 @@
// We've strengthened the bound, so update superclass conformances.
updateSuperclassConformances();
+ updateSuperclassNestedTypes();
return;
}
@@ -4023,10 +4041,7 @@
if (Impl->NumUnresolvedNestedTypes > 0) {
visitPotentialArchetypes([&](PotentialArchetype *pa) {
// We only care about nested types that haven't been resolved.
- if (pa->getParent() == nullptr || pa->getResolvedAssociatedType() ||
- pa->getTypeAliasDecl() ||
- /* FIXME: Should be able to handle this earlier */pa->getSuperclass())
- return;
+ if (!pa->isUnresolved()) return;
// Try to typo correct to a nested type name.
Identifier correction = typoCorrectNestedType(pa);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index dc254fe..860ff42 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -948,17 +948,7 @@
/// \brief Compare two protocols to establish an ordering between them.
int ProtocolType::compareProtocols(ProtocolDecl * const* PP1,
ProtocolDecl * const* PP2) {
- auto *P1 = *PP1;
- auto *P2 = *PP2;
- ModuleDecl *M1 = P1->getParentModule();
- ModuleDecl *M2 = P2->getParentModule();
-
- // Try ordering based on module name, first.
- if (int result = M1->getName().str().compare(M2->getName().str()))
- return result;
-
- // Order based on protocol name.
- return P1->getName().str().compare(P2->getName().str());
+ return TypeDecl::compare(*PP1, *PP2);
}
bool ProtocolType::visitAllProtocols(
diff --git a/lib/IDE/APIDigesterData.cpp b/lib/IDE/APIDigesterData.cpp
index 78f4ec5..8e7450d 100644
--- a/lib/IDE/APIDigesterData.cpp
+++ b/lib/IDE/APIDigesterData.cpp
@@ -251,7 +251,9 @@
case APIDiffItemKind::ADK_CommonDiffItem: {
auto *Left = static_cast<const CommonDiffItem*>(this);
auto *Right = static_cast<const CommonDiffItem*>(&Other);
- return Left->ChildIndex == Right->ChildIndex;
+ return
+ Left->DiffKind == Right->DiffKind &&
+ Left->ChildIndex == Right->ChildIndex;
}
case APIDiffItemKind::ADK_NoEscapeFuncParam: {
auto *Left = static_cast<const NoEscapeFuncParam*>(this);
diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp
index 729fd34..0edd00e 100644
--- a/lib/SILOptimizer/Utils/Generics.cpp
+++ b/lib/SILOptimizer/Utils/Generics.cpp
@@ -170,7 +170,8 @@
// ReabstractionInfo
// =============================================================================
-static bool shouldNotSpecializeCallee(SILFunction *Callee) {
+static bool shouldNotSpecializeCallee(SILFunction *Callee,
+ SubstitutionList Subs = {}) {
if (!Callee->shouldOptimize()) {
DEBUG(llvm::dbgs() << " Cannot specialize function " << Callee->getName()
<< " marked to be excluded from optimizations.\n");
@@ -180,6 +181,10 @@
if (Callee->hasSemanticsAttr("optimize.sil.specialize.generic.never"))
return true;
+ if (!Subs.empty() &&
+ Callee->hasSemanticsAttr("optimize.sil.specialize.generic.partial.never"))
+ return true;
+
return false;
}
@@ -291,6 +296,10 @@
// We need a generic environment for the partial specialization.
if (!CalleeGenericEnv)
return false;
+
+ // Bail if the callee should not be partially specialized.
+ if (shouldNotSpecializeCallee(Callee, ParamSubs))
+ return false;
}
return true;
diff --git a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
index 7aecd66..bf5f9f3 100644
--- a/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
+++ b/lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp
@@ -591,6 +591,31 @@
return false;
}
+// Returns true if a given apply site should be skipped during the
+// early inlining pass.
+//
+// NOTE: Add here the checks for any specific @_semantics/@_effects
+// attributes causing a given callee to be excluded from the inlining
+// during the early inlining pass.
+static bool shouldSkipApplyDuringEarlyInlining(FullApplySite AI) {
+ // Add here the checks for any specific @_semantics attributes that need
+ // to be skipped during the early inlining pass.
+ ArraySemanticsCall ASC(AI.getInstruction());
+ if (ASC && !ASC.canInlineEarly())
+ return true;
+
+ SILFunction *Callee = AI.getReferencedFunction();
+ if (!Callee)
+ return false;
+
+ // Add here the checks for any specific @_effects attributes that need
+ // to be skipped during the early inlining pass.
+ if (Callee->hasEffectsKind())
+ return true;
+
+ return false;
+}
+
// Returns the callee of an apply_inst if it is basically inlineable.
SILFunction *swift::getEligibleFunction(FullApplySite AI,
InlineSelection WhatToInline) {
@@ -606,8 +631,7 @@
// attribute if the inliner is asked not to inline them.
if (Callee->hasSemanticsAttrs() || Callee->hasEffectsKind()) {
if (WhatToInline == InlineSelection::NoSemanticsAndGlobalInit) {
- ArraySemanticsCall ASC(AI.getInstruction());
- if (!ASC.canInlineEarly())
+ if (shouldSkipApplyDuringEarlyInlining(AI))
return nullptr;
}
// The "availability" semantics attribute is treated like global-init.
diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp
index ed10d77..f72f956 100644
--- a/lib/Sema/CSApply.cpp
+++ b/lib/Sema/CSApply.cpp
@@ -760,6 +760,12 @@
if (result == nullptr) {
result = new (tc.Context) ErrorExpr(range);
cs.setType(result, erasedTy);
+ // The opaque value is no longer reachable in an AST walk as
+ // a result of the result above being replaced with an
+ // ErrorExpr, but there is code expecting to have a type set
+ // on it. Since we no longer have a reachable reference,
+ // we'll null this out.
+ record.OpaqueValue = nullptr;
}
}
@@ -768,7 +774,7 @@
// means this is our only chance to propagate the l-value access kind
// down to the original existential value. Otherwise, propagateLVAK
// will handle this.
- if (record.OpaqueValue->hasLValueAccessKind())
+ if (record.OpaqueValue && record.OpaqueValue->hasLValueAccessKind())
cs.propagateLValueAccessKind(record.ExistentialValue,
record.OpaqueValue->getLValueAccessKind());
@@ -5861,6 +5867,8 @@
Expr *ExprRewriter::buildObjCBridgeExpr(Expr *expr, Type toType,
ConstraintLocatorBuilder locator) {
+ auto &tc = cs.getTypeChecker();
+
Type fromType = cs.getType(expr);
// Bridged collection casts always succeed, so we treat them as
@@ -5883,6 +5891,20 @@
if (!objcExpr)
return nullptr;
+ // We might have a coercion of a Swift type to a CF type toll-free
+ // bridged to Objective-C.
+ //
+ // FIXME: Ideally we would instead have already recorded a restriction
+ // when solving the constraint, and we wouldn't need to duplicate this
+ // part of coerceToType() here.
+ if (auto foreignClass = toType->getClassOrBoundGenericClass()) {
+ if (foreignClass->getForeignClassKind() ==
+ ClassDecl::ForeignKind::CFType) {
+ return cs.cacheType(
+ new (tc.Context) ForeignObjectConversionExpr(objcExpr, toType));
+ }
+ }
+
return coerceToType(objcExpr, toType, locator);
}
diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp
index ba4600b..88277eb 100644
--- a/lib/Sema/CSRanking.cpp
+++ b/lib/Sema/CSRanking.cpp
@@ -83,6 +83,10 @@
case SK_KeyPathSubscript:
log << "key path subscript";
break;
+
+ case SK_StringToPointerConversion:
+ log << "string-to-pointer conversion";
+ break;
}
log << ")\n";
}
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index b665bcb..041895a 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -4397,6 +4397,8 @@
// If we haven't resolved the element type, generate constraints.
if (baseType2->isTypeVariableOrMember()) {
if (flags.contains(TMF_GenerateConstraints)) {
+ increaseScore(SK_StringToPointerConversion);
+
auto int8Con = Constraint::create(*this, ConstraintKind::Bind,
baseType2, TC.getInt8Type(DC),
getConstraintLocator(locator));
@@ -4418,6 +4420,8 @@
if (!isStringCompatiblePointerBaseType(TC, DC, baseType2)) {
return SolutionKind::Error;
}
+
+ increaseScore(SK_StringToPointerConversion);
return SolutionKind::Solved;
}
diff --git a/lib/Sema/CSSolver.cpp b/lib/Sema/CSSolver.cpp
index 6674481..2171fe2 100644
--- a/lib/Sema/CSSolver.cpp
+++ b/lib/Sema/CSSolver.cpp
@@ -1461,7 +1461,8 @@
return std::move(solutions[0]);
}
-bool ConstraintSystem::Candidate::solve() {
+bool ConstraintSystem::Candidate::solve(
+ llvm::SmallDenseSet<Expr *> &shrunkExprs) {
// Don't attempt to solve candidate if there is closure
// expression involved, because it's handled specially
// by parent constraint system (e.g. parameter lists).
@@ -1504,6 +1505,11 @@
return true;
}
+ // If this candidate is too complex given the number
+ // of the domains we have reduced so far, let's bail out early.
+ if (isTooComplexGiven(&cs, shrunkExprs))
+ return false;
+
if (TC.getLangOpts().DebugConstraintSolver) {
auto &log = cs.getASTContext().TypeCheckerDebug->getStream();
log << "--- Solving candidate for shrinking at ";
@@ -1557,7 +1563,7 @@
}
// Record found solutions as suggestions.
- this->applySolutions(solutions);
+ this->applySolutions(solutions, shrunkExprs);
// Let's double-check if we have any implicit expressions
// with type variables and nullify their types.
@@ -1569,7 +1575,8 @@
}
void ConstraintSystem::Candidate::applySolutions(
- llvm::SmallVectorImpl<Solution> &solutions) const {
+ llvm::SmallVectorImpl<Solution> &solutions,
+ llvm::SmallDenseSet<Expr *> &shrunkExprs) const {
// A collection of OSRs with their newly reduced domains,
// it's domains are sets because multiple solutions can have the same
// choice for one of the type variables, and we want no duplication.
@@ -1616,6 +1623,9 @@
= TC.Context.AllocateUninitialized<ValueDecl *>(choices.size());
std::uninitialized_copy(choices.begin(), choices.end(), decls.begin());
OSR->setDecls(decls);
+
+ // Record successfully shrunk expression.
+ shrunkExprs.insert(OSR);
}
}
@@ -1684,7 +1694,8 @@
auto func = applyExpr->getFn();
// Let's record this function application for post-processing
// as well as if it contains overload set, see walkToExprPost.
- ApplyExprs.push_back({applyExpr, isa<OverloadSetRefExpr>(func)});
+ ApplyExprs.push_back(
+ {applyExpr, isa<OverloadSetRefExpr>(func) || isa<TypeExpr>(func)});
}
return { true, expr };
@@ -1918,11 +1929,12 @@
// so we can start solving them separately.
expr->walk(collector);
+ llvm::SmallDenseSet<Expr *> shrunkExprs;
for (auto &candidate : collector.Candidates) {
// If there are no results, let's forget everything we know about the
// system so far. This actually is ok, because some of the expressions
// might require manual salvaging.
- if (candidate.solve()) {
+ if (candidate.solve(shrunkExprs)) {
// Let's restore all of the original OSR domains for this sub-expression,
// this means that we can still make forward progress with solving of the
// top sub-expressions.
@@ -1933,6 +1945,7 @@
return childExpr;
OSR->setDecls(domain->getSecond());
+ shrunkExprs.erase(OSR);
}
return childExpr;
@@ -2480,8 +2493,9 @@
auto afterDisjunction = InactiveConstraints.erase(disjunction);
CG.removeConstraint(disjunction);
+ Score initialScore = CurrentScore;
Optional<DisjunctionChoice> lastSolvedChoice;
- Optional<DisjunctionChoice> firstNonGenericOperatorSolution;
+ Optional<Score> bestNonGenericScore;
++solverState->NumDisjunctions;
auto constraints = disjunction->getNestedConstraints();
@@ -2507,9 +2521,13 @@
// already have a solution involving non-generic operators,
// but continue looking for a better non-generic operator
// solution.
- if (firstNonGenericOperatorSolution &&
- currentChoice.isGenericOperatorOrUnavailable())
- continue;
+ if (bestNonGenericScore && currentChoice.isGenericOperatorOrUnavailable()) {
+ // If non-generic solution increased the score by applying any
+ // fixes or restrictions to the solution, let's not skip generic
+ // overloads because they could produce a better solution.
+ if (bestNonGenericScore <= initialScore)
+ continue;
+ }
// We already have a solution; check whether we should
// short-circuit the disjunction.
@@ -2542,11 +2560,12 @@
DisjunctionChoices.push_back({locator, index});
}
- if (currentChoice.solve(solutions, allowFreeTypeVariables)) {
- if (!firstNonGenericOperatorSolution &&
- !currentChoice.isGenericOperatorOrUnavailable() &&
- currentChoice.isSymmetricOperator())
- firstNonGenericOperatorSolution = currentChoice;
+ if (auto score = currentChoice.solve(solutions, allowFreeTypeVariables)) {
+ if (!currentChoice.isGenericOperatorOrUnavailable() &&
+ currentChoice.isSymmetricOperator()) {
+ if (!bestNonGenericScore || score < bestNonGenericScore)
+ bestNonGenericScore = score;
+ }
lastSolvedChoice = currentChoice;
@@ -2578,10 +2597,12 @@
return tooComplex || !lastSolvedChoice;
}
-bool DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
- FreeTypeVariableBinding allowFreeTypeVariables) {
+Optional<Score>
+DisjunctionChoice::solve(SmallVectorImpl<Solution> &solutions,
+ FreeTypeVariableBinding allowFreeTypeVariables) {
CS->simplifyDisjunctionChoice(Choice);
- return !CS->solveRec(solutions, allowFreeTypeVariables);
+ bool failed = CS->solveRec(solutions, allowFreeTypeVariables);
+ return failed ? None : Optional<Score>(CS->CurrentScore);
}
bool DisjunctionChoice::isGenericOperatorOrUnavailable() const {
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index 27ae6ac..d81b0a4 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -416,8 +416,10 @@
SK_EmptyExistentialConversion,
/// A key path application subscript.
SK_KeyPathSubscript,
-
- SK_LastScoreKind = SK_KeyPathSubscript,
+ // A conversion from a string to a pointer.
+ SK_StringToPointerConversion,
+
+ SK_LastScoreKind = SK_StringToPointerConversion,
};
/// The number of score kinds.
@@ -998,15 +1000,45 @@
/// \brief Try to solve this candidate sub-expression
/// and re-write it's OSR domains afterwards.
///
+ /// \param shrunkExprs The set of expressions which
+ /// domains have been successfully shrunk so far.
+ ///
/// \returns true on solver failure, false otherwise.
- bool solve();
+ bool solve(llvm::SmallDenseSet<Expr *> &shrunkExprs);
/// \brief Apply solutions found by solver as reduced OSR sets for
/// for current and all of it's sub-expressions.
///
/// \param solutions The solutions found by running solver on the
/// this candidate expression.
- void applySolutions(llvm::SmallVectorImpl<Solution> &solutions) const;
+ ///
+ /// \param shrunkExprs The set of expressions which
+ /// domains have been successfully shrunk so far.
+ void applySolutions(llvm::SmallVectorImpl<Solution> &solutions,
+ llvm::SmallDenseSet<Expr *> &shrunkExprs) const;
+
+ /// Check if attempt at solving of the candidate makes sense given
+ /// the current conditions - number of shrunk domains which is related
+ /// to the given candidate over the total number of disjunctions present.
+ static bool isTooComplexGiven(ConstraintSystem *const cs,
+ llvm::SmallDenseSet<Expr *> &shrunkExprs) {
+ SmallVector<Constraint *, 8> disjunctions;
+ cs->collectDisjunctions(disjunctions);
+
+ unsigned unsolvedDisjunctions = disjunctions.size();
+ for (auto *disjunction : disjunctions) {
+ auto *locator = disjunction->getLocator();
+ if (!locator)
+ continue;
+
+ if (auto *anchor = locator->getAnchor()) {
+ if (shrunkExprs.count(anchor) > 0)
+ --unsolvedDisjunctions;
+ }
+ }
+
+ return unsolvedDisjunctions >= 5;
+ }
};
/// \brief Describes the current solver state.
@@ -2671,8 +2703,8 @@
bool isSymmetricOperator() const;
/// \brief Apply given choice to the system and try to solve it.
- bool solve(SmallVectorImpl<Solution> &solutions,
- FreeTypeVariableBinding allowFreeTypeVariables);
+ Optional<Score> solve(SmallVectorImpl<Solution> &solutions,
+ FreeTypeVariableBinding allowFreeTypeVariables);
private:
static ValueDecl *getOperatorDecl(Constraint *constraint) {
diff --git a/lib/Sema/ITCDecl.cpp b/lib/Sema/ITCDecl.cpp
index 76ae9cc..4602340 100644
--- a/lib/Sema/ITCDecl.cpp
+++ b/lib/Sema/ITCDecl.cpp
@@ -108,14 +108,24 @@
// Validate the type of this inherited clause entry.
// FIXME: Recursion into existing type checker.
- GenericTypeToArchetypeResolver resolver(dc);
- if (TC.validateType(*inherited, dc, options, &resolver,
+ Optional<ProtocolRequirementTypeResolver> protoResolver;
+ Optional<GenericTypeToArchetypeResolver> archetypeResolver;
+ GenericTypeResolver *resolver;
+ if (auto *proto = dyn_cast<ProtocolDecl>(dc)) {
+ protoResolver.emplace(proto);
+ resolver = protoResolver.getPointer();
+ } else {
+ archetypeResolver.emplace(dc);
+ resolver = archetypeResolver.getPointer();
+ }
+
+ if (TC.validateType(*inherited, dc, options, resolver,
&unsatisfiedDependency)) {
inherited->setInvalidType(getASTContext());
}
auto type = inherited->getType();
- if (!type.isNull())
+ if (!type.isNull() && !isa<ProtocolDecl>(dc))
inherited->setType(dc->mapTypeOutOfContext(type));
}
diff --git a/lib/Sema/TypeCheckGeneric.cpp b/lib/Sema/TypeCheckGeneric.cpp
index d1f4f49..7d76f18 100644
--- a/lib/Sema/TypeCheckGeneric.cpp
+++ b/lib/Sema/TypeCheckGeneric.cpp
@@ -209,35 +209,37 @@
return DependentMemberType::get(baseTy, assocType);
}
- // If the nested type comes from a type alias, use either the alias's
- // concrete type, or resolve its components down to another dependent member.
- if (auto alias = nestedPA->getTypeAliasDecl()) {
- assert(!alias->getGenericParams() && "Generic typealias in protocol");
- ref->setValue(alias);
- return TC.substMemberTypeWithBase(DC->getParentModule(), alias, baseTy);
- }
-
- Identifier name = ref->getIdentifier();
- SourceLoc nameLoc = ref->getIdLoc();
+ // If the nested type comes from a concrete type, substitute the base type
+ // into it.
+ if (auto concrete = nestedPA->getConcreteTypeDecl()) {
+ ref->setValue(concrete);
- // Check whether the name can be found in the superclass.
- // FIXME: The generic signature builder should be doing this and mapping down to a
- // concrete type.
- if (auto superclassTy = basePA->getSuperclass()) {
- if (auto lookup = TC.lookupMemberType(DC, superclassTy, name)) {
- if (lookup.isAmbiguous()) {
- TC.diagnoseAmbiguousMemberType(baseTy, baseRange, name, nameLoc,
- lookup);
- return ErrorType::get(TC.Context);
+ if (baseTy->isTypeParameter()) {
+ if (auto proto =
+ concrete->getDeclContext()
+ ->getAsProtocolOrProtocolExtensionContext()) {
+ auto subMap = SubstitutionMap::getProtocolSubstitutions(
+ proto, baseTy, ProtocolConformanceRef(proto));
+ return concrete->getDeclaredInterfaceType().subst(subMap);
}
- ref->setValue(lookup.front().first);
- // FIXME: Record (via type sugar) that this was referenced via baseTy.
- return lookup.front().second;
+ if (auto superclass = basePA->getSuperclass()) {
+ return superclass->getTypeOfMember(
+ DC->getParentModule(), concrete,
+ concrete->getDeclaredInterfaceType());
+ }
+
+ llvm_unreachable("shouldn't have a concrete decl here");
}
+
+ return TC.substMemberTypeWithBase(DC->getParentModule(), concrete, baseTy);
}
+ assert(nestedPA->isUnresolved() && "meaningless unresolved type");
+
// Complain that there is no suitable type.
+ Identifier name = ref->getIdentifier();
+ SourceLoc nameLoc = ref->getIdLoc();
TC.diagnose(nameLoc, diag::invalid_member_type, name, baseTy)
.highlight(baseRange);
return ErrorType::get(TC.Context);
diff --git a/stdlib/public/core/Integers.swift.gyb b/stdlib/public/core/Integers.swift.gyb
index 7540998..1c47aca 100644
--- a/stdlib/public/core/Integers.swift.gyb
+++ b/stdlib/public/core/Integers.swift.gyb
@@ -2271,6 +2271,7 @@
}
extension FixedWidthInteger {
+ @_semantics("optimize.sil.specialize.generic.partial.never")
public init<Other: BinaryInteger>(clamping source: Other) {
if _slowPath(source < Self.min) {
self = Self.min
@@ -2416,6 +2417,7 @@
}
extension UnsignedInteger where Self : FixedWidthInteger {
+ @_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init<T : BinaryInteger>(_ source: T) {
// This check is potentially removable by the optimizer
@@ -2430,6 +2432,7 @@
self.init(extendingOrTruncating: source)
}
+ @_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init?<T : BinaryInteger>(exactly source: T) {
// This check is potentially removable by the optimizer
@@ -2494,6 +2497,7 @@
}
extension SignedInteger where Self : FixedWidthInteger {
+ @_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init<T : BinaryInteger>(_ source: T) {
// This check is potentially removable by the optimizer
@@ -2510,6 +2514,7 @@
self.init(extendingOrTruncating: source)
}
+ @_semantics("optimize.sil.specialize.generic.partial.never")
@inline(__always)
public init?<T : BinaryInteger>(exactly source: T) {
// This check is potentially removable by the optimizer
diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift
index e404fc6..0a4dd9f 100644
--- a/stdlib/public/core/String.swift
+++ b/stdlib/public/core/String.swift
@@ -211,6 +211,7 @@
}
}
+ @_semantics("optimize.sil.specialize.generic.partial.never")
internal func _withCSubstringAndLength<
Result, TargetEncoding: Unicode.Encoding
>(
diff --git a/test/Constraints/overload.swift b/test/Constraints/overload.swift
index 05338ee..4b06f4d 100644
--- a/test/Constraints/overload.swift
+++ b/test/Constraints/overload.swift
@@ -222,3 +222,4 @@
// Ensure that we consider these unambiguous
let _ = curry(+)(1)
let _ = [0].reduce(0, +)
+let _ = curry(+)("string vs. pointer")
diff --git a/test/Generics/superclass_constraint.swift b/test/Generics/superclass_constraint.swift
index efb35a3..0d585e3 100644
--- a/test/Generics/superclass_constraint.swift
+++ b/test/Generics/superclass_constraint.swift
@@ -152,3 +152,18 @@
}
func genericFunc<T : Elementary, U : Classical>(_: T, _: U) where T.Element == U.Element {}
+
+// Lookup within superclass constraints.
+protocol P8 {
+ associatedtype B
+}
+
+class C8 {
+ struct A { }
+}
+
+func superclassLookup1<T: C8 & P8>(_: T) where T.A == T.B { }
+
+func superclassLookup2<T: P8>(_: T) where T.A == T.B, T: C8 { }
+
+func superclassLookup3<T>(_: T) where T.A == T.B, T: C8, T: P8 { }
diff --git a/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h b/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h
index f628500..3f96927 100644
--- a/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h
+++ b/test/Inputs/clang-importer-sdk/usr/include/CoreFoundation.h
@@ -14,6 +14,10 @@
typedef struct __CFTree *CFTreeRef;
typedef const struct __attribute__((objc_bridge(CFURL))) __CFURL * CFURLRef;
+typedef struct __attribute__((objc_bridge(NSDictionary))) __CFDictionary const *CFDictionaryRef;
+typedef struct __attribute__((objc_bridge(NSArray))) __CFArray const *CFArrayRef;
+typedef struct __attribute__((objc_bridge(NSSet))) __CFSet const *CFSetRef;
+
typedef CFTypeRef CFAliasForTypeRef;
diff --git a/test/Migrator/API.json b/test/Migrator/API.json
index 64d8858..610a9dd 100644
--- a/test/Migrator/API.json
+++ b/test/Migrator/API.json
@@ -31,6 +31,28 @@
{
"DiffItemKind": "CommonDiffItem",
"NodeKind": "Function",
+ "NodeAnnotation": "WrapOptional",
+ "ChildIndex": "0",
+ "LeftUsr": "c:objc(cs)PropertyUserInterface(cm)methodPlus",
+ "LeftComment": "",
+ "RightUsr": "",
+ "RightComment": "",
+ "ModuleName": "bar"
+ },
+ {
+ "DiffItemKind": "CommonDiffItem",
+ "NodeKind": "Function",
+ "NodeAnnotation": "Rename",
+ "ChildIndex": "0",
+ "LeftUsr": "c:objc(cs)PropertyUserInterface(cm)methodPlus",
+ "LeftComment": "",
+ "RightUsr": "",
+ "RightComment": "newMethodPlus()",
+ "ModuleName": "bar"
+ },
+ {
+ "DiffItemKind": "CommonDiffItem",
+ "NodeKind": "Function",
"NodeAnnotation": "Rename",
"ChildIndex": "0",
"LeftUsr": "c:objc(cs)BarForwardDeclaredClass(im)barInstanceFunc1:anotherValue:anotherValue1:anotherValue2:",
diff --git a/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h b/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h
index 2a38c2e..eea572a 100644
--- a/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h
+++ b/test/Migrator/mock-sdk/Bar.framework/Headers/Bar.h
@@ -26,6 +26,7 @@
- (void) setField:(int)info;
+ (int) fieldPlus;
+ (void) methodPlus:(int)info;
++ (void) methodPlus;
@end
#define BAR_MACRO_1 0
diff --git a/test/Migrator/rename.swift b/test/Migrator/rename.swift
index 5089922..924318b 100644
--- a/test/Migrator/rename.swift
+++ b/test/Migrator/rename.swift
@@ -16,6 +16,7 @@
b.barInstanceFunc1(0, anotherValue: 1, anotherValue1: 2, anotherValue2: 3)
barGlobalFuncOldName(2)
_ = barGlobalVariableOldEnumElement
+ _ = PropertyUserInterface.methodPlus()
}
func foo1(_ b: BarForwardDeclaredClass) {
diff --git a/test/Migrator/rename.swift.expected b/test/Migrator/rename.swift.expected
index a97ba0a..08f23ff 100644
--- a/test/Migrator/rename.swift.expected
+++ b/test/Migrator/rename.swift.expected
@@ -16,6 +16,7 @@
b.barNewInstanceFunc1(newlabel1: 0, newlabel2: 1, newlabel3: 2, newlabel4: 3)
barGlobalFuncNewName(newlabel: 2)
_ = NewEnum.enumElement
+ _ = PropertyUserInterface.newMethodPlus()
}
func foo1(_ b: BarForwardDeclaredClass) {
diff --git a/test/SILGen/keypaths_objc.swift b/test/SILGen/keypaths_objc.swift
index ad3b6f1..8bbaf94 100644
--- a/test/SILGen/keypaths_objc.swift
+++ b/test/SILGen/keypaths_objc.swift
@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-keypath-components -emit-silgen -import-objc-header %S/Inputs/keypaths_objc.h %s | %FileCheck %s
+// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-experimental-keypath-components -emit-ir -import-objc-header %S/Inputs/keypaths_objc.h %s
// REQUIRES: objc_interop
import Foundation
@@ -55,3 +56,23 @@
// CHECK: keypath $KeyPath<Foo, Int>, (objc "int"; {{.*}} id #Foo.int!getter.1 :
_ = \Foo.int
}
+
+struct X {}
+
+extension NSObject {
+ var x: X { return X() }
+ @objc var objc: Int { return 0 }
+ @objc dynamic var dynamic: Int { return 0 }
+}
+
+// CHECK-LABEL: sil hidden @{{.*}}nonobjcExtensionOfObjCClass
+func nonobjcExtensionOfObjCClass() {
+ // Should be treated as a statically-dispatch property
+ // CHECK: keypath $KeyPath<NSObject, X>, ({{.*}} id @
+ _ = \NSObject.x
+ // CHECK: keypath $KeyPath<NSObject, Int>, ({{.*}} id #NSObject.objc!getter.1.foreign
+ _ = \NSObject.objc
+ // CHECK: keypath $KeyPath<NSObject, Int>, ({{.*}} id #NSObject.dynamic!getter.1.foreign
+ _ = \NSObject.dynamic
+
+}
diff --git a/test/SILOptimizer/inline_semantics.sil b/test/SILOptimizer/inline_semantics.sil
index 0b06397..8947788 100644
--- a/test/SILOptimizer/inline_semantics.sil
+++ b/test/SILOptimizer/inline_semantics.sil
@@ -12,10 +12,13 @@
return %1 : $Int32 // id: %2
}
+//Not every @_semantics should be skipped during the early inlining pass, but
+//only those ones which are explicitly listed in shouldSkipApplyDuringEarlyInlining.
+
//CHECK-LABEL: caller_func
-//CHECK: function_ref
-//CHECK: apply
-//CHECK-NEXT: ret
+//CHECK-NOT: function_ref
+//CHECK-NOT: apply
+//CHECK: end sil function 'caller_func'
sil @caller_func : $@convention(thin) () -> Int32 {
bb0:
%0 = function_ref @callee_func : $@convention(thin) () -> Int32 // user: %1
@@ -23,6 +26,29 @@
return %1 : $Int32 // id: %2
}
+sil [_semantics "array.make_mutable"] @callee_func_with_to_be_skipped_during_inlining_semantics : $@convention(method) (@inout Int32) -> Int32 {
+bb0(%self : $*Int32):
+ %0 = integer_literal $Builtin.Int32, 3 // user: %1
+ %1 = struct $Int32 (%0 : $Builtin.Int32) // user: %2
+ return %1 : $Int32 // id: %2
+}
+
+//Not every @_semantics should be skipped during the early inlining pass, but
+//only those ones which are explicitly listed in shouldSkipApplyDuringEarlyInlining.
+
+//CHECK-LABEL: caller_func2
+//CHECK: function_ref
+//CHECK: apply
+//CHECK: end sil function 'caller_func2'
+sil @caller_func2 : $@convention(thin) () -> Int32 {
+bb0:
+ %self = alloc_stack $Int32
+ %0 = function_ref @callee_func_with_to_be_skipped_during_inlining_semantics : $@convention(method) (@inout Int32) -> Int32 // user: %1
+ %1 = apply %0(%self) : $@convention(method) (@inout Int32) -> Int32 // user: %2
+ dealloc_stack %self : $*Int32
+ return %1 : $Int32 // id: %2
+}
+
// A function annotated with the @effects(readonly) attribute.
sil [readonly] @callee_func2 : $@convention(thin) () -> Int32 {
bb0:
diff --git a/test/Sema/circular_decl_checking.swift b/test/Sema/circular_decl_checking.swift
index 1e556fb..efe76cd 100644
--- a/test/Sema/circular_decl_checking.swift
+++ b/test/Sema/circular_decl_checking.swift
@@ -43,9 +43,10 @@
var TopLevelVar: TopLevelVar? { return nil } // expected-error 2 {{use of undeclared type 'TopLevelVar'}}
-protocol AProtocol {
- // FIXME: Should produce an error here, but it's currently causing problems.
- associatedtype e : e
+// FIXME: The first error is redundant, isn't correct in what it states, and
+// also should be emitted on the inheritance clause.
+protocol AProtocol { // expected-error {{first type 'Self.e' in conformance requirement does not refer to a generic parameter or associated type}}
+ associatedtype e : e // expected-error {{inheritance from non-protocol, non-class type 'Self.e'}}
}
diff --git a/test/Sema/complex_expressions.swift b/test/Sema/complex_expressions.swift
index 8ad6c52..27e02e3 100644
--- a/test/Sema/complex_expressions.swift
+++ b/test/Sema/complex_expressions.swift
@@ -117,3 +117,12 @@
8: { $0 != $1 }, 9: { $0 != $1 }, 10: { $0 != $1 }, 11: { $0 != $1 },
12: { $0 != $1 }, 13: { $0 != $1 }, 14: { $0 != $1 }, 15: { $0 != $1 },
16: { $0 != $1 }, 17: { $0 != $1 }, 18: { $0 != $1 }, 19: { $0 != $1 } ]
+
+// rdar://problem/32034560 - type-checker hangs trying to solve expression
+struct R32034560 {
+ private var R32034560: Array<Array<UInt32>>
+ private func foo(x: UInt32) -> UInt32 {
+ return ((self.R32034560[0][Int(x >> 24) & 0xFF] &+ self.R32034560[1][Int(x >> 16) & 0xFF]) ^ self.R32034560[2][Int(x >> 8) & 0xFF]) &+ self.R32034560[3][Int(x & 0xFF)]
+ // expected-error@-1 {{expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions}}
+ }
+}
diff --git a/test/decl/nested/protocol.swift b/test/decl/nested/protocol.swift
index e10d600..231c457 100644
--- a/test/decl/nested/protocol.swift
+++ b/test/decl/nested/protocol.swift
@@ -72,5 +72,6 @@
class OtherGenericClass<T> {
protocol InnerProtocol : OtherGenericClass { }
- // expected-error@-1{{protocol 'InnerProtocol' cannot be nested inside another declaration}}
+ // expected-error@-1{{non-class type 'InnerProtocol' cannot inherit from class 'OtherGenericClass<T>'}}
+ // expected-error@-2{{protocol 'InnerProtocol' cannot be nested inside another declaration}}
}
diff --git a/test/decl/protocol/req/unsatisfiable.swift b/test/decl/protocol/req/unsatisfiable.swift
index 03eec2d..6c10773 100644
--- a/test/decl/protocol/req/unsatisfiable.swift
+++ b/test/decl/protocol/req/unsatisfiable.swift
@@ -30,3 +30,21 @@
func f<T: P3>(_: T) where T.A == Self.A, T.A: C // expected-error{{instance method requirement 'f' cannot add constraint 'Self.A: C' on 'Self'}}
func g<T: P3>(_: T) where T.A: C, T.A == Self.A // expected-error{{instance method requirement 'g' cannot add constraint 'Self.A: C' on 'Self'}}
}
+
+protocol Base {
+ associatedtype Assoc
+}
+
+// FIXME: The first error is redundant, isn't correct in what it states, and
+// also should be emitted on the inheritance clause.
+// FIXME: This used to /not/ error in Swift 3. It didn't impose any statically-
+// enforced requirements, but the compiler crashed if you used anything but the
+// same type.
+protocol Sub1: Base { // expected-error {{first type 'Self.Assoc' in conformance requirement does not refer to a generic parameter or associated type}}
+ associatedtype SubAssoc: Assoc // expected-error {{inheritance from non-protocol, non-class type 'Self.Assoc'}}
+}
+// FIXME: This error is incorrect in what it states and should be emitted on
+// the where-clause.
+protocol Sub2: Base { // expected-error {{first type 'Self.Assoc' in conformance requirement does not refer to a generic parameter or associated type}}
+ associatedtype SubAssoc where SubAssoc: Assoc
+}
diff --git a/test/expr/cast/cf.swift b/test/expr/cast/cf.swift
index 90d1d7f..343d8cf 100644
--- a/test/expr/cast/cf.swift
+++ b/test/expr/cast/cf.swift
@@ -80,3 +80,25 @@
acceptNSString(x)
acceptCFString(y)
}
+
+func testBridgedCFDowncast(array: [Any], dictionary: [AnyHashable : Any], set: Set<AnyHashable>) {
+ let cfArray = array as CFArray
+ let cfDictionary = dictionary as CFDictionary
+ let cfSet = set as CFSet
+
+ _ = array as? CFArray // expected-warning {{conditional cast from '[Any]' to 'CFArray' always succeeds}}
+ _ = dictionary as? CFDictionary // expected-warning {{conditional cast from '[AnyHashable : Any]' to 'CFDictionary' always succeeds}}
+ _ = set as? CFSet // expected-warning {{conditional cast from 'Set<AnyHashable>' to 'CFSet' always succeeds}}
+
+ _ = array as! CFArray // expected-warning {{forced cast from '[Any]' to 'CFArray' always succeeds}}
+ _ = dictionary as! CFDictionary // expected-warning {{forced cast from '[AnyHashable : Any]' to 'CFDictionary' always succeeds}}
+ _ = set as! CFSet // expected-warning {{forced cast from 'Set<AnyHashable>' to 'CFSet' always succeeds}}
+
+ _ = cfArray as! [Any]
+ _ = cfDictionary as! [AnyHashable : Any]
+ _ = cfSet as! Set<AnyHashable>
+
+ _ = cfArray as? [Any]
+ _ = cfDictionary as? [AnyHashable : Any]
+ _ = cfSet as? Set<AnyHashable>
+}
diff --git a/validation-test/Sema/rdar32204609.swift b/validation-test/Sema/rdar32204609.swift
new file mode 100644
index 0000000..5e14f85
--- /dev/null
+++ b/validation-test/Sema/rdar32204609.swift
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %target-build-swift %s -o %t/a.out
+// RUN: %target-run %t/a.out
+
+// REQUIRES: executable_test
+
+let x: Int! = nil
+let y: Int! = 1
+
+print(x == y)
diff --git a/validation-test/compiler_crashers/28693-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift b/validation-test/compiler_crashers_fixed/28693-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift
similarity index 86%
rename from validation-test/compiler_crashers/28693-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift
rename to validation-test/compiler_crashers_fixed/28693-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift
index d626bb2..03e9930 100644
--- a/validation-test/compiler_crashers/28693-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift
+++ b/validation-test/compiler_crashers_fixed/28693-swift-genericenvironment-queryinterfacetypesubstitutions-operator-swift-substitu.swift
@@ -5,5 +5,5 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
-// RUN: not --crash %target-swift-frontend %s -emit-ir
+// RUN: not %target-swift-frontend %s -emit-ir
protocol b:Self