Skip to content

Commit 76c264e

Browse files
authored
Merge pull request #15412 from hamishknight/redeclaration-fixes
[Sema] Fix several redeclaration checking bugs
2 parents 5c92ecd + a506f60 commit 76c264e

15 files changed

+384
-80
lines changed

include/swift/AST/Decl.h

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,22 +193,56 @@ struct OverloadSignature {
193193
DeclName Name;
194194

195195
/// The kind of unary operator.
196-
UnaryOperatorKind UnaryOperator = UnaryOperatorKind::None;
196+
UnaryOperatorKind UnaryOperator;
197197

198198
/// Whether this is an instance member.
199-
bool IsInstanceMember = false;
199+
unsigned IsInstanceMember : 1;
200200

201-
/// Whether this is a property.
202-
bool IsProperty = false;
201+
/// Whether this is a variable.
202+
unsigned IsVariable : 1;
203+
204+
/// Whether this is a function.
205+
unsigned IsFunction : 1;
203206

204207
/// Whether this signature is part of a protocol extension.
205-
bool InProtocolExtension = false;
208+
unsigned InProtocolExtension : 1;
209+
210+
/// Whether this signature is of a member defined in an extension of a generic
211+
/// type.
212+
unsigned InExtensionOfGenericType : 1;
213+
214+
OverloadSignature()
215+
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
216+
IsVariable(false), IsFunction(false), InProtocolExtension(false),
217+
InExtensionOfGenericType(false) {}
206218
};
207219

208220
/// Determine whether two overload signatures conflict.
221+
///
222+
/// \param sig1 The overload signature of the first declaration.
223+
/// \param sig2 The overload signature of the second declaration.
224+
/// \param skipProtocolExtensionCheck If \c true, members of protocol extensions
225+
/// will be allowed to conflict with members of protocol declarations.
209226
bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2,
210227
bool skipProtocolExtensionCheck = false);
211228

229+
/// Determine whether two overload signatures and overload types conflict.
230+
///
231+
/// \param ctx The AST context.
232+
/// \param sig1 The overload signature of the first declaration.
233+
/// \param sig1Type The overload type of the first declaration.
234+
/// \param sig2 The overload signature of the second declaration.
235+
/// \param sig2Type The overload type of the second declaration.
236+
/// \param wouldConflictInSwift5 If non-null, the referenced boolean will be set
237+
/// to \c true iff the function returns \c false for this version of
238+
/// Swift, but the given overloads will conflict in Swift 5 mode.
239+
/// \param skipProtocolExtensionCheck If \c true, members of protocol extensions
240+
/// will be allowed to conflict with members of protocol declarations.
241+
bool conflicting(ASTContext &ctx,
242+
const OverloadSignature& sig1, CanType sig1Type,
243+
const OverloadSignature& sig2, CanType sig2Type,
244+
bool *wouldConflictInSwift5 = nullptr,
245+
bool skipProtocolExtensionCheck = false);
212246

213247
/// Decl - Base class for all declarations in Swift.
214248
class alignas(1 << DeclAlignInBits) Decl {

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,10 @@ ERROR(reserved_member_name,none,
610610
" 'foo.%1' expression", (DeclName, StringRef))
611611

612612
ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
613+
WARNING(invalid_redecl_swift5_warning,none,
614+
"redeclaration of %0 is deprecated and will be illegal in Swift 5",
615+
(DeclName))
616+
613617
NOTE(invalid_redecl_prev,none,
614618
"%0 previously declared here", (DeclName))
615619

include/swift/AST/Types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,11 @@ class alignas(1 << TypeAlignInBits) TypeBase {
563563
/// underlying type.
564564
Type eraseDynamicSelfType();
565565

566+
/// Given a declaration context, returns a function type with the 'self'
567+
/// type curried as the input if the declaration context describes a type.
568+
/// Otherwise, returns the type itself.
569+
Type addCurriedSelfType(const DeclContext *dc);
570+
566571
/// Map a contextual type to an interface type.
567572
Type mapTypeOutOfContext();
568573

lib/AST/Decl.cpp

Lines changed: 68 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,13 +1699,51 @@ bool swift::conflicting(const OverloadSignature& sig1,
16991699
// If one is a compound name and the other is not, they do not conflict
17001700
// if one is a property and the other is a non-nullary function.
17011701
if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) {
1702-
return !((sig1.IsProperty && !sig2.Name.getArgumentNames().empty()) ||
1703-
(sig2.IsProperty && !sig1.Name.getArgumentNames().empty()));
1702+
return !((sig1.IsVariable && !sig2.Name.getArgumentNames().empty()) ||
1703+
(sig2.IsVariable && !sig1.Name.getArgumentNames().empty()));
17041704
}
17051705

17061706
return sig1.Name == sig2.Name;
17071707
}
17081708

1709+
bool swift::conflicting(ASTContext &ctx,
1710+
const OverloadSignature& sig1, CanType sig1Type,
1711+
const OverloadSignature& sig2, CanType sig2Type,
1712+
bool *wouldConflictInSwift5,
1713+
bool skipProtocolExtensionCheck) {
1714+
// If the signatures don't conflict to begin with, we're done.
1715+
if (!conflicting(sig1, sig2, skipProtocolExtensionCheck))
1716+
return false;
1717+
1718+
// Functions always conflict with non-functions with the same signature.
1719+
// In practice, this only applies for zero argument functions.
1720+
if (sig1.IsFunction != sig2.IsFunction)
1721+
return true;
1722+
1723+
// Variables always conflict with non-variables with the same signature.
1724+
// (e.g variables with zero argument functions, variables with type
1725+
// declarations)
1726+
if (sig1.IsVariable != sig2.IsVariable) {
1727+
// Prior to Swift 5, we permitted redeclarations of variables as different
1728+
// declarations if the variable was declared in an extension of a generic
1729+
// type. Make sure we maintain this behaviour in versions < 5.
1730+
if (!ctx.isSwiftVersionAtLeast(5)) {
1731+
if ((sig1.IsVariable && sig1.InExtensionOfGenericType) ||
1732+
(sig2.IsVariable && sig2.InExtensionOfGenericType)) {
1733+
if (wouldConflictInSwift5)
1734+
*wouldConflictInSwift5 = true;
1735+
1736+
return false;
1737+
}
1738+
}
1739+
1740+
return true;
1741+
}
1742+
1743+
// Otherwise, the declarations conflict if the overload types are the same.
1744+
return sig1Type == sig2Type;
1745+
}
1746+
17091747
static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
17101748
bool topLevelFunction,
17111749
bool isMethod,
@@ -1815,9 +1853,10 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
18151853

18161854
signature.Name = getFullName();
18171855
signature.InProtocolExtension
1818-
= getDeclContext()->getAsProtocolExtensionContext();
1856+
= static_cast<bool>(getDeclContext()->getAsProtocolExtensionContext());
18191857
signature.IsInstanceMember = isInstanceMember();
1820-
signature.IsProperty = isa<VarDecl>(this);
1858+
signature.IsVariable = isa<VarDecl>(this);
1859+
signature.IsFunction = isa<AbstractFunctionDecl>(this);
18211860

18221861
// Unary operators also include prefix/postfix.
18231862
if (auto func = dyn_cast<FuncDecl>(this)) {
@@ -1826,11 +1865,15 @@ OverloadSignature ValueDecl::getOverloadSignature() const {
18261865
}
18271866
}
18281867

1868+
if (auto *extension = dyn_cast<ExtensionDecl>(getDeclContext()))
1869+
if (extension->getGenericSignature())
1870+
signature.InExtensionOfGenericType = true;
1871+
18291872
return signature;
18301873
}
18311874

18321875
CanType ValueDecl::getOverloadSignatureType() const {
1833-
if (auto afd = dyn_cast<AbstractFunctionDecl>(this)) {
1876+
if (auto *afd = dyn_cast<AbstractFunctionDecl>(this)) {
18341877
return mapSignatureFunctionType(
18351878
getASTContext(), getInterfaceType(),
18361879
/*topLevelFunction=*/true,
@@ -1839,42 +1882,30 @@ CanType ValueDecl::getOverloadSignatureType() const {
18391882
afd->getNumParameterLists())->getCanonicalType();
18401883
}
18411884

1842-
if (isa<SubscriptDecl>(this)) {
1843-
CanType interfaceType = getInterfaceType()->getCanonicalType();
1844-
1845-
// If the subscript declaration occurs within a generic extension context,
1846-
// consider the generic signature of the extension.
1847-
auto ext = dyn_cast<ExtensionDecl>(getDeclContext());
1848-
if (!ext) return interfaceType;
1849-
1850-
auto genericSig = ext->getGenericSignature();
1851-
if (!genericSig) return interfaceType;
1852-
1853-
if (auto funcTy = interfaceType->getAs<AnyFunctionType>()) {
1854-
return GenericFunctionType::get(genericSig,
1855-
funcTy->getParams(),
1856-
funcTy->getResult(),
1857-
funcTy->getExtInfo())
1858-
->getCanonicalType();
1885+
if (auto *asd = dyn_cast<AbstractStorageDecl>(this)) {
1886+
// First, get the default overload signature type for the decl. For vars,
1887+
// this is the empty tuple type, as variables cannot be overloaded directly
1888+
// by type. For subscripts, it's their interface type.
1889+
CanType defaultSignatureType;
1890+
if (isa<VarDecl>(this)) {
1891+
defaultSignatureType = TupleType::getEmpty(getASTContext());
1892+
} else {
1893+
defaultSignatureType = getInterfaceType()->getCanonicalType();
18591894
}
1860-
return interfaceType;
1861-
} else if (isa<VarDecl>(this)) {
1862-
// If the variable declaration occurs within a generic extension context,
1863-
// consider the generic signature of the extension.
1864-
auto ext = dyn_cast<ExtensionDecl>(getDeclContext());
1865-
if (!ext) return CanType();
18661895

1867-
auto genericSig = ext->getGenericSignature();
1868-
if (!genericSig) return CanType();
1869-
1870-
ASTContext &ctx = getASTContext();
1871-
return GenericFunctionType::get(genericSig,
1872-
TupleType::getEmpty(ctx),
1873-
TupleType::getEmpty(ctx),
1874-
AnyFunctionType::ExtInfo())
1875-
->getCanonicalType();
1896+
// We want to curry the default signature type with the 'self' type of the
1897+
// given context (if any) in order to ensure the overload signature type
1898+
// is unique across different contexts, such as between a protocol extension
1899+
// and struct decl.
1900+
return defaultSignatureType->addCurriedSelfType(getDeclContext())
1901+
->getCanonicalType();
18761902
}
18771903

1904+
// Note: If you add more cases to this function, you should update the
1905+
// implementation of the swift::conflicting overload that deals with
1906+
// overload types, in order to account for cases where the overload types
1907+
// don't match, but the decls differ and therefore always conflict.
1908+
18781909
return CanType();
18791910
}
18801911

lib/AST/LookupVisibleDecls.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -805,10 +805,10 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
805805
OtherSignatureType = CT->getCanonicalType();
806806
}
807807

808-
if (conflicting(FoundSignature, OtherSignature, true) &&
809-
(FoundSignatureType == OtherSignatureType ||
810-
FoundSignature.Name.isCompoundName() !=
811-
OtherSignature.Name.isCompoundName())) {
808+
if (conflicting(M->getASTContext(), FoundSignature, FoundSignatureType,
809+
OtherSignature, OtherSignatureType,
810+
/*wouldConflictInSwift5*/nullptr,
811+
/*skipProtocolExtensionCheck*/true)) {
812812
if (VD->getFormalAccess() > OtherVD->getFormalAccess()) {
813813
PossiblyConflicting.erase(I);
814814
PossiblyConflicting.insert(VD);

lib/AST/Type.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,27 @@ Type TypeBase::eraseDynamicSelfType() {
402402
});
403403
}
404404

405+
Type TypeBase::addCurriedSelfType(const DeclContext *dc) {
406+
if (!dc->isTypeContext())
407+
return this;
408+
409+
auto *type = this;
410+
411+
GenericSignature *sig = dc->getGenericSignatureOfContext();
412+
if (auto *genericFn = type->getAs<GenericFunctionType>()) {
413+
sig = genericFn->getGenericSignature();
414+
type = FunctionType::get(genericFn->getInput(),
415+
genericFn->getResult(),
416+
genericFn->getExtInfo());
417+
}
418+
419+
auto selfTy = dc->getDeclaredInterfaceType();
420+
if (sig)
421+
return GenericFunctionType::get(sig, selfTy, type,
422+
AnyFunctionType::ExtInfo());
423+
return FunctionType::get(selfTy, type);
424+
}
425+
405426
void
406427
TypeBase::getTypeVariables(SmallVectorImpl<TypeVariableType *> &typeVariables) {
407428
// If we know we don't have any type variables, we're done.

lib/Sema/CSRanking.cpp

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -254,27 +254,6 @@ computeSelfTypeRelationship(TypeChecker &tc, DeclContext *dc, ValueDecl *decl1,
254254
return {SelfTypeRelationship::ConformsTo, conformance};
255255
}
256256

257-
// Given a type and a declaration context, return a type with a curried
258-
// 'self' type as input if the declaration context describes a type.
259-
static Type addCurriedSelfType(ASTContext &ctx, Type type, DeclContext *dc) {
260-
if (!dc->isTypeContext())
261-
return type;
262-
263-
GenericSignature *sig = dc->getGenericSignatureOfContext();
264-
if (auto *genericFn = type->getAs<GenericFunctionType>()) {
265-
sig = genericFn->getGenericSignature();
266-
type = FunctionType::get(genericFn->getInput(),
267-
genericFn->getResult(),
268-
genericFn->getExtInfo());
269-
}
270-
271-
auto selfTy = dc->getDeclaredInterfaceType();
272-
if (sig)
273-
return GenericFunctionType::get(sig, selfTy, type,
274-
AnyFunctionType::ExtInfo());
275-
return FunctionType::get(selfTy, type);
276-
}
277-
278257
/// \brief Given two generic function declarations, signal if the first is more
279258
/// "constrained" than the second by comparing the number of constraints
280259
/// applied to each type parameter.
@@ -480,8 +459,8 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
480459
}
481460
} else {
482461
// Add a curried 'self' type.
483-
type1 = addCurriedSelfType(tc.Context, type1, outerDC1);
484-
type2 = addCurriedSelfType(tc.Context, type2, outerDC2);
462+
type1 = type1->addCurriedSelfType(outerDC1);
463+
type2 = type2->addCurriedSelfType(outerDC2);
485464

486465
// For a subscript declaration, only look at the input type (i.e., the
487466
// indices).

lib/Sema/TypeCheckDecl.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -959,9 +959,12 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
959959
// Get the overload signature type.
960960
CanType otherSigType = other->getOverloadSignatureType();
961961

962+
bool wouldBeSwift5Redeclaration = false;
963+
auto isRedeclaration = conflicting(tc.Context, currentSig, currentSigType,
964+
otherSig, otherSigType,
965+
&wouldBeSwift5Redeclaration);
962966
// If there is another conflict, complain.
963-
if (currentSigType == otherSigType ||
964-
currentSig.Name.isCompoundName() != otherSig.Name.isCompoundName()) {
967+
if (isRedeclaration || wouldBeSwift5Redeclaration) {
965968
// If the two declarations occur in the same source file, make sure
966969
// we get the diagnostic ordering to be sensible.
967970
if (auto otherFile = other->getDeclContext()->getParentSourceFile()) {
@@ -1060,9 +1063,23 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
10601063
continue;
10611064
}
10621065

1063-
tc.diagnose(current, diag::invalid_redecl, current->getFullName());
1064-
tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName());
1065-
markInvalid();
1066+
// If this isn't a redeclaration in the current version of Swift, but
1067+
// would be in Swift 5 mode, emit a warning instead of an error.
1068+
if (wouldBeSwift5Redeclaration) {
1069+
tc.diagnose(current, diag::invalid_redecl_swift5_warning,
1070+
current->getFullName());
1071+
tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName());
1072+
} else {
1073+
tc.diagnose(current, diag::invalid_redecl, current->getFullName());
1074+
tc.diagnose(other, diag::invalid_redecl_prev, other->getFullName());
1075+
markInvalid();
1076+
}
1077+
1078+
// Make sure we don't do this checking again for the same decl. We also
1079+
// set this at the beginning of the function, but we might have swapped
1080+
// the decls for diagnostics; so ensure we also set this for the actual
1081+
// decl we diagnosed on.
1082+
current->setCheckedRedeclaration(true);
10661083
break;
10671084
}
10681085
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var fooObject: FooStruct = FooStruct()
2+
var genericFooObject: GenericFooStruct = GenericFooStruct<Void>()
23

34
private func privateFunc_ERROR() {}
45

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
protocol FooProt {
2-
var instanceVar: Int { get }
2+
var instanceVar: Int { get }
33
}
44

55
struct FooStruct : FooProt {
@@ -8,3 +8,10 @@ struct FooStruct : FooProt {
88

99
private func privateFunc_ERROR() {}
1010
}
11+
12+
struct GenericFooStruct<T> : FooProt {
13+
var instanceVar: Int = 17
14+
func instanceFunc0() {}
15+
16+
private func privateFunc_ERROR() {}
17+
}

0 commit comments

Comments
 (0)