Skip to content

Commit 8b58b0d

Browse files
committed
[Type checker] Make redeclaration checking validate fewer declarations.
Redeclaration checking was validating all declarations with the same base name as the given declaration (and in the same general nominal type), even when it was trivial to determine that the declarations could not be conflicting. Separate out the easy structural checks (based on kind, full name, instance vs. non-instance member, etc.) and perform those first, before validation. Fixes SR-6558, a case where redeclaration checking caused some unnecessary recursion in the type checker.
1 parent fc253e8 commit 8b58b0d

File tree

8 files changed

+110
-108
lines changed

8 files changed

+110
-108
lines changed

include/swift/AST/Decl.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,6 @@ struct OverloadSignature {
213213
/// The full name of the declaration.
214214
DeclName Name;
215215

216-
/// The interface type of the declaration, when relevant to the
217-
/// overload signature.
218-
CanType InterfaceType;
219-
220216
/// The kind of unary operator.
221217
UnaryOperatorKind UnaryOperator = UnaryOperatorKind::None;
222218

@@ -231,7 +227,8 @@ struct OverloadSignature {
231227
};
232228

233229
/// Determine whether two overload signatures conflict.
234-
bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2);
230+
bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2,
231+
bool skipProtocolExtensionCheck = false);
235232

236233

237234
/// Decl - Base class for all declarations in Swift.
@@ -2276,9 +2273,13 @@ class ValueDecl : public Decl {
22762273
/// Retrieve the declaration that this declaration overrides, if any.
22772274
ValueDecl *getOverriddenDecl() const;
22782275

2279-
/// Compute the overload signature for this declaration.
2276+
/// Compute the untyped overload signature for this declaration.
22802277
OverloadSignature getOverloadSignature() const;
22812278

2279+
/// Retrieve the type used to describe this entity for the purposes of
2280+
/// overload resolution.
2281+
CanType getOverloadSignatureType() const;
2282+
22822283
/// Returns true if the decl requires Objective-C interop.
22832284
///
22842285
/// This can be true even if there is no 'objc' attribute on the declaration.

lib/AST/Decl.cpp

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,27 +1654,34 @@ ValueDecl *ValueDecl::getOverriddenDecl() const {
16541654
}
16551655

16561656
bool swift::conflicting(const OverloadSignature& sig1,
1657-
const OverloadSignature& sig2) {
1657+
const OverloadSignature& sig2,
1658+
bool skipProtocolExtensionCheck) {
16581659
// A member of a protocol extension never conflicts with a member of a
16591660
// protocol.
1660-
if (sig1.InProtocolExtension != sig2.InProtocolExtension)
1661+
if (!skipProtocolExtensionCheck &&
1662+
sig1.InProtocolExtension != sig2.InProtocolExtension)
16611663
return false;
16621664

16631665
// If the base names are different, they can't conflict.
16641666
if (sig1.Name.getBaseName() != sig2.Name.getBaseName())
16651667
return false;
1666-
1668+
1669+
// If one is an operator and the other is not, they can't conflict.
1670+
if (sig1.UnaryOperator != sig2.UnaryOperator)
1671+
return false;
1672+
1673+
// If one is an instance and the other is not, they can't conflict.
1674+
if (sig1.IsInstanceMember != sig2.IsInstanceMember)
1675+
return false;
1676+
16671677
// If one is a compound name and the other is not, they do not conflict
16681678
// if one is a property and the other is a non-nullary function.
16691679
if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) {
16701680
return !((sig1.IsProperty && sig2.Name.getArgumentNames().size() > 0) ||
16711681
(sig2.IsProperty && sig1.Name.getArgumentNames().size() > 0));
16721682
}
16731683

1674-
return sig1.Name == sig2.Name &&
1675-
sig1.InterfaceType == sig2.InterfaceType &&
1676-
sig1.UnaryOperator == sig2.UnaryOperator &&
1677-
sig1.IsInstanceMember == sig2.IsInstanceMember;
1684+
return sig1.Name == sig2.Name;
16781685
}
16791686

16801687
static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
@@ -1791,63 +1798,68 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
17911798
signature.Name = getFullName();
17921799
signature.InProtocolExtension
17931800
= getDeclContext()->getAsProtocolExtensionContext();
1801+
signature.IsInstanceMember = isInstanceMember();
1802+
signature.IsProperty = isa<VarDecl>(this);
17941803

1795-
// Functions, initializers, and de-initializers include their
1796-
// interface types in their signatures as well as whether they are
1797-
// instance members.
1798-
if (auto afd = dyn_cast<AbstractFunctionDecl>(this)) {
1799-
signature.InterfaceType =
1800-
mapSignatureFunctionType(
1801-
getASTContext(), getInterfaceType(),
1802-
/*topLevelFunction=*/true,
1803-
/*isMethod=*/afd->getImplicitSelfDecl() != nullptr,
1804-
/*isInitializer=*/isa<ConstructorDecl>(afd),
1805-
afd->getNumParameterLists())->getCanonicalType();
1806-
1807-
signature.IsInstanceMember = isInstanceMember();
1808-
// Unary operators also include prefix/postfix.
1809-
if (auto func = dyn_cast<FuncDecl>(this)) {
1810-
if (func->isUnaryOperator()) {
1811-
signature.UnaryOperator = func->getAttrs().getUnaryOperatorKind();
1812-
}
1804+
if (auto func = dyn_cast<FuncDecl>(this)) {
1805+
if (func->isUnaryOperator()) {
1806+
signature.UnaryOperator = func->getAttrs().getUnaryOperatorKind();
18131807
}
1814-
} else if (isa<SubscriptDecl>(this)) {
1815-
signature.InterfaceType = getInterfaceType()->getCanonicalType();
1808+
}
18161809

1817-
// If the subscript occurs within a generic extension context,
1818-
// consider the generic signature of the extension.
1819-
if (auto ext = dyn_cast<ExtensionDecl>(getDeclContext())) {
1820-
if (auto genericSig = ext->getGenericSignature()) {
1821-
if (auto funcTy = signature.InterfaceType->getAs<AnyFunctionType>()) {
1822-
signature.InterfaceType
1823-
= GenericFunctionType::get(genericSig,
1824-
funcTy->getParams(),
1825-
funcTy->getResult(),
1826-
funcTy->getExtInfo())
1827-
->getCanonicalType();
1828-
}
1829-
}
1830-
}
1831-
} else if (isa<VarDecl>(this)) {
1832-
signature.IsProperty = true;
1833-
signature.IsInstanceMember = isInstanceMember();
1810+
return signature;
1811+
}
18341812

1835-
// If the property occurs within a generic extension context,
1813+
CanType ValueDecl::getOverloadSignatureType() const {
1814+
if (auto afd = dyn_cast<AbstractFunctionDecl>(this)) {
1815+
return mapSignatureFunctionType(
1816+
getASTContext(), getInterfaceType(),
1817+
/*topLevelFunction=*/true,
1818+
/*isMethod=*/afd->getImplicitSelfDecl() != nullptr,
1819+
/*isInitializer=*/isa<ConstructorDecl>(afd),
1820+
afd->getNumParameterLists())->getCanonicalType();
1821+
}
1822+
1823+
if (isa<SubscriptDecl>(this)) {
1824+
CanType interfaceType = getInterfaceType()->getCanonicalType();
1825+
1826+
// If the subscript declaration occurs within a generic extension context,
18361827
// consider the generic signature of the extension.
1837-
if (auto ext = dyn_cast<ExtensionDecl>(getDeclContext())) {
1838-
if (auto genericSig = ext->getGenericSignature()) {
1839-
ASTContext &ctx = getASTContext();
1840-
signature.InterfaceType
1841-
= GenericFunctionType::get(genericSig,
1842-
TupleType::getEmpty(ctx),
1843-
TupleType::getEmpty(ctx),
1844-
AnyFunctionType::ExtInfo())
1828+
auto ext = dyn_cast<ExtensionDecl>(getDeclContext());
1829+
if (!ext) return interfaceType;
1830+
1831+
auto genericSig = ext->getGenericSignature();
1832+
if (!genericSig) return interfaceType;
1833+
1834+
if (auto funcTy = interfaceType->getAs<AnyFunctionType>()) {
1835+
return GenericFunctionType::get(genericSig,
1836+
funcTy->getParams(),
1837+
funcTy->getResult(),
1838+
funcTy->getExtInfo())
18451839
->getCanonicalType();
1846-
}
18471840
}
1841+
1842+
return interfaceType;
18481843
}
18491844

1850-
return signature;
1845+
if (isa<VarDecl>(this)) {
1846+
// If the variable declaration occurs within a generic extension context,
1847+
// consider the generic signature of the extension.
1848+
auto ext = dyn_cast<ExtensionDecl>(getDeclContext());
1849+
if (!ext) return CanType();
1850+
1851+
auto genericSig = ext->getGenericSignature();
1852+
if (!genericSig) return CanType();
1853+
1854+
ASTContext &ctx = getASTContext();
1855+
return GenericFunctionType::get(genericSig,
1856+
TupleType::getEmpty(ctx),
1857+
TupleType::getEmpty(ctx),
1858+
AnyFunctionType::ExtInfo())
1859+
->getCanonicalType();
1860+
}
1861+
1862+
return CanType();
18511863
}
18521864

18531865
void ValueDecl::setIsObjC(bool Value) {

lib/AST/LookupVisibleDecls.cpp

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -668,35 +668,6 @@ template <> struct DenseMapInfo<FoundDeclTy> {
668668

669669
namespace {
670670

671-
/// Similar to swift::conflicting, but lenient about protocol extensions which
672-
/// don't affect code completion's concept of overloading.
673-
static bool relaxedConflicting(const OverloadSignature &sig1,
674-
const OverloadSignature &sig2) {
675-
676-
// If the base names are different, they can't conflict.
677-
if (sig1.Name.getBaseName() != sig2.Name.getBaseName())
678-
return false;
679-
680-
// If one is a compound name and the other is not, they do not conflict
681-
// if one is a property and the other is a non-nullary function.
682-
if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) {
683-
return !((sig1.IsProperty && sig2.Name.getArgumentNames().size() > 0) ||
684-
(sig2.IsProperty && sig1.Name.getArgumentNames().size() > 0));
685-
}
686-
687-
// Allow null property types to match non-null ones, which only happens when
688-
// one property is from a generic extension and the other is not.
689-
if (sig1.InterfaceType != sig2.InterfaceType) {
690-
if (!sig1.IsProperty || !sig2.IsProperty)
691-
return false;
692-
if (sig1.InterfaceType && sig2.InterfaceType)
693-
return false;
694-
}
695-
696-
return sig1.Name == sig2.Name && sig1.UnaryOperator == sig2.UnaryOperator &&
697-
sig1.IsInstanceMember == sig2.IsInstanceMember;
698-
}
699-
700671
/// Hack to guess at whether substituting into the type of a declaration will
701672
/// be okay.
702673
/// FIXME: This is awful. We should either have Type::subst() work for
@@ -803,11 +774,12 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
803774
}
804775

805776
auto FoundSignature = VD->getOverloadSignature();
806-
if (FoundSignature.InterfaceType && shouldSubst &&
807-
shouldSubstIntoDeclType(FoundSignature.InterfaceType)) {
777+
auto FoundSignatureType = VD->getOverloadSignatureType();
778+
if (FoundSignatureType && shouldSubst &&
779+
shouldSubstIntoDeclType(FoundSignatureType)) {
808780
auto subs = BaseTy->getMemberSubstitutionMap(M, VD);
809-
if (auto CT = FoundSignature.InterfaceType.subst(subs))
810-
FoundSignature.InterfaceType = CT->getCanonicalType();
781+
if (auto CT = FoundSignatureType.subst(subs))
782+
FoundSignatureType = CT->getCanonicalType();
811783
}
812784

813785
for (auto I = PossiblyConflicting.begin(), E = PossiblyConflicting.end();
@@ -820,14 +792,18 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
820792
}
821793

822794
auto OtherSignature = OtherVD->getOverloadSignature();
823-
if (OtherSignature.InterfaceType && shouldSubst &&
824-
shouldSubstIntoDeclType(OtherSignature.InterfaceType)) {
795+
auto OtherSignatureType = OtherVD->getOverloadSignatureType();
796+
if (OtherSignatureType && shouldSubst &&
797+
shouldSubstIntoDeclType(OtherSignatureType)) {
825798
auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD);
826-
if (auto CT = OtherSignature.InterfaceType.subst(subs))
827-
OtherSignature.InterfaceType = CT->getCanonicalType();
799+
if (auto CT = OtherSignatureType.subst(subs))
800+
OtherSignatureType = CT->getCanonicalType();
828801
}
829802

830-
if (relaxedConflicting(FoundSignature, OtherSignature)) {
803+
if (conflicting(FoundSignature, OtherSignature, true) &&
804+
(FoundSignatureType == OtherSignatureType ||
805+
FoundSignature.Name.isCompoundName() !=
806+
OtherSignature.Name.isCompoundName())) {
831807
if (VD->getFormalAccess() > OtherVD->getFormalAccess()) {
832808
PossiblyConflicting.erase(I);
833809
PossiblyConflicting.insert(VD);

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ bool swift::removeShadowedDecls(SmallVectorImpl<ValueDecl*> &decls,
193193
// constrained extensions, so use the overload signature's
194194
// type. This is layering a partial fix upon a total hack.
195195
if (auto asd = dyn_cast<AbstractStorageDecl>(decl))
196-
signature = asd->getOverloadSignature().InterfaceType;
196+
signature = asd->getOverloadSignatureType();
197197

198198
// If we've seen a declaration with this signature before, note it.
199199
auto &knownDecls =

lib/Sema/TypeCheckDecl.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
899899
// Compare this signature against the signature of other
900900
// declarations with the same name.
901901
OverloadSignature currentSig = current->getOverloadSignature();
902+
CanType currentSigType = current->getOverloadSignatureType();
902903
ModuleDecl *currentModule = current->getModuleContext();
903904
for (auto other : otherDefinitions) {
904905
// Skip invalid declarations and ourselves.
@@ -914,6 +915,12 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
914915
if (currentDC->isTypeContext() != other->getDeclContext()->isTypeContext())
915916
continue;
916917

918+
// Check whether the overload signatures conflict (ignoring the type for
919+
// now).
920+
auto otherSig = other->getOverloadSignature();
921+
if (!conflicting(currentSig, otherSig))
922+
continue;
923+
917924
// Validate the declaration.
918925
tc.validateDecl(other);
919926
if (other->isInvalid() || !other->hasInterfaceType())
@@ -946,8 +953,12 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
946953
break;
947954
}
948955

956+
// Get the overload signature type.
957+
CanType otherSigType = other->getOverloadSignatureType();
958+
949959
// If there is another conflict, complain.
950-
if (conflicting(currentSig, other->getOverloadSignature())) {
960+
if (currentSigType == otherSigType ||
961+
currentSig.Name.isCompoundName() != otherSig.Name.isCompoundName()) {
951962
// If the two declarations occur in the same source file, make sure
952963
// we get the diagnostic ordering to be sensible.
953964
if (auto otherFile = other->getDeclContext()->getParentSourceFile()) {

test/IDE/complete_value_expr.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,24 +1650,26 @@ struct dedupS : dedupP {
16501650
16511651
func testDeDuped(_ x: dedupS) {
16521652
x#^PROTOCOL_EXT_DEDUP_1^#
1653-
// FIXME: Should produce 3 items
1654-
// PROTOCOL_EXT_DEDUP_1: Begin completions, 5 items
1653+
// FIXME: Should produce 3 items (?)
1654+
// PROTOCOL_EXT_DEDUP_1: Begin completions, 6 items
16551655
// PROTOCOL_EXT_DEDUP_1: Decl[InstanceMethod]/CurrNominal: .foo()[#Int#]; name=foo()
16561656
// PROTOCOL_EXT_DEDUP_1: Decl[InstanceVar]/CurrNominal: .bar[#Int#]; name=bar
16571657
// PROTOCOL_EXT_DEDUP_1: Decl[Subscript]/CurrNominal: [{#Int#}][#Int#]; name=[Int]
16581658
// PROTOCOL_EXT_DEDUP_1: End completions
16591659
}
16601660
func testDeDuped2(_ x: dedupP) {
16611661
x#^PROTOCOL_EXT_DEDUP_2^#
1662-
// PROTOCOL_EXT_DEDUP_2: Begin completions, 3 items
1662+
// FIXME: Should produce 3 items (?)
1663+
// PROTOCOL_EXT_DEDUP_2: Begin completions, 4 items
16631664
// PROTOCOL_EXT_DEDUP_2: Decl[InstanceMethod]/CurrNominal: .foo()[#dedupP.T#]; name=foo()
16641665
// PROTOCOL_EXT_DEDUP_2: Decl[InstanceVar]/CurrNominal: .bar[#dedupP.T#]; name=bar
16651666
// PROTOCOL_EXT_DEDUP_2: Decl[Subscript]/CurrNominal: [{#Self.T#}][#Self.T#]; name=[Self.T]
16661667
// PROTOCOL_EXT_DEDUP_2: End completions
16671668
}
16681669
func testDeDuped3<T : dedupP where T.T == Int>(_ x: T) {
1670+
// FIXME: Should produce 3 items (?)
16691671
x#^PROTOCOL_EXT_DEDUP_3^#
1670-
// PROTOCOL_EXT_DEDUP_3: Begin completions, 3 items
1672+
// PROTOCOL_EXT_DEDUP_3: Begin completions, 4 items
16711673
// PROTOCOL_EXT_DEDUP_3: Decl[InstanceMethod]/Super: .foo()[#Int#]; name=foo()
16721674
// PROTOCOL_EXT_DEDUP_3: Decl[InstanceVar]/Super: .bar[#Int#]; name=bar
16731675
// PROTOCOL_EXT_DEDUP_3: Decl[Subscript]/Super: [{#Self.T#}][#Self.T#]; name=[Self.T]

validation-test/compiler_crashers_2_fixed/0126-sr5905.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not %target-swift-frontend %s -typecheck
1+
// RUN: %target-swift-frontend %s -emit-ir -o /dev/null
22
protocol VectorIndex {
33
associatedtype Vector8 : Vector where Vector8.Index == Self, Vector8.Element == UInt8
44
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// See https://swift.org/LICENSE.txt for license information
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// REQUIRES: asserts
9-
// RUN: not --crash %target-swift-frontend %s -emit-ir
8+
9+
// RUN: not %target-swift-frontend %s -emit-ir
1010
class a:P{class a{}{}func a:a{}func a{}}@objc protocol P{{}func a

0 commit comments

Comments
 (0)