Skip to content

Commit b11d544

Browse files
authored
Merge pull request #13643 from DougGregor/redecl-fewer-validations
[Type checker] Make redeclaration checking validate fewer declarations.
2 parents de28975 + 8b58b0d commit b11d544

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.
@@ -2251,9 +2248,13 @@ class ValueDecl : public Decl {
22512248
/// Retrieve the declaration that this declaration overrides, if any.
22522249
ValueDecl *getOverriddenDecl() const;
22532250

2254-
/// Compute the overload signature for this declaration.
2251+
/// Compute the untyped overload signature for this declaration.
22552252
OverloadSignature getOverloadSignature() const;
22562253

2254+
/// Retrieve the type used to describe this entity for the purposes of
2255+
/// overload resolution.
2256+
CanType getOverloadSignatureType() const;
2257+
22572258
/// Returns true if the decl requires Objective-C interop.
22582259
///
22592260
/// 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)