Skip to content

Commit 671eed7

Browse files
authored
Merge pull request #992 from swiftwasm/release/5.3
[pull] swiftwasm-release/5.3 from release/5.3
2 parents 7b90e77 + 0f3aacd commit 671eed7

17 files changed

+340
-42
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,13 @@ ERROR(spi_attribute_on_non_public,none,
17051705
"cannot be declared '@_spi' because only public and open "
17061706
"declarations can be '@_spi'",
17071707
(AccessLevel, DescriptiveDeclKind))
1708+
ERROR(spi_attribute_on_protocol_requirement,none,
1709+
"protocol requirement %0 cannot be declared '@_spi' without "
1710+
"a default implementation in a protocol extension",
1711+
(DeclName))
1712+
ERROR(spi_attribute_on_frozen_stored_properties,none,
1713+
"stored property %0 cannot be declared '@_spi' in a '@frozen' struct",
1714+
(DeclName))
17081715

17091716
// Opaque return types
17101717
ERROR(opaque_type_invalid_constraint,none,
@@ -4239,8 +4246,8 @@ ERROR(objc_invalid_on_subscript,none,
42394246
ERROR(objc_invalid_on_static_subscript,none,
42404247
"%0 cannot be %" OBJC_ATTR_SELECT "1", (DescriptiveDeclKind, unsigned))
42414248
ERROR(objc_invalid_with_generic_params,none,
4242-
"method cannot be %" OBJC_ATTR_SELECT "0 because it has generic "
4243-
"parameters", (unsigned))
4249+
"%0 cannot be %" OBJC_ATTR_SELECT "1 because it has generic parameters",
4250+
(DescriptiveDeclKind, unsigned))
42444251
ERROR(objc_convention_invalid,none,
42454252
"%0 is not representable in Objective-C, so it cannot be used"
42464253
" with '@convention(%1)'", (Type, StringRef))

lib/IDE/CompletionInstance.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,10 @@ bool CompletionInstance::performCachedOperationIfPossible(
315315
auto tmpBufferID = tmpSM.addMemBufferCopy(completionBuffer);
316316
tmpSM.setCodeCompletionPoint(tmpBufferID, Offset);
317317

318-
LangOptions langOpts;
318+
LangOptions langOpts = CI.getASTContext().LangOpts;
319319
langOpts.DisableParserLookup = true;
320-
TypeCheckerOptions typeckOpts;
321-
SearchPathOptions searchPathOpts;
320+
TypeCheckerOptions typeckOpts = CI.getASTContext().TypeCheckerOpts;
321+
SearchPathOptions searchPathOpts = CI.getASTContext().SearchPathOpts;
322322
DiagnosticEngine tmpDiags(tmpSM);
323323
std::unique_ptr<ASTContext> tmpCtx(
324324
ASTContext::get(langOpts, typeckOpts, searchPathOpts, tmpSM, tmpDiags));
@@ -327,15 +327,22 @@ bool CompletionInstance::performCachedOperationIfPossible(
327327
registerTypeCheckerRequestFunctions(tmpCtx->evaluator);
328328
registerSILGenRequestFunctions(tmpCtx->evaluator);
329329
ModuleDecl *tmpM = ModuleDecl::create(Identifier(), *tmpCtx);
330-
SourceFile *tmpSF =
331-
new (*tmpCtx) SourceFile(*tmpM, oldSF->Kind, tmpBufferID,
332-
SourceFile::ImplicitModuleImportKind::None);
330+
SourceFile *tmpSF = new (*tmpCtx)
331+
SourceFile(*tmpM, oldSF->Kind, tmpBufferID,
332+
SourceFile::ImplicitModuleImportKind::None,
333+
/*KeepParsedTokens=*/false, /*BuildSyntaxTree=*/false,
334+
oldSF->getParsingOptions());
333335
tmpSF->enableInterfaceHash();
334336
// Ensure all non-function-body tokens are hashed into the interface hash
335337
tmpCtx->LangOpts.EnableTypeFingerprints = false;
336338

337-
// Couldn't find any completion token?
339+
// FIXME: Since we don't setup module loaders on the temporary AST context,
340+
// 'canImport()' conditional compilation directive always fails. That causes
341+
// interface hash change and prevents fast-completion.
342+
343+
// Parse and get the completion context.
338344
auto *newState = tmpSF->getDelayedParserState();
345+
// Couldn't find any completion token?
339346
if (!newState->hasCodeCompletionDelayedDeclState())
340347
return false;
341348

lib/Parse/ParseIfConfig.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,10 @@ ParserResult<IfConfigDecl> Parser::parseIfConfig(
676676
SmallVector<ASTNode, 16> Elements;
677677
llvm::SaveAndRestore<bool> S(InInactiveClauseEnvironment,
678678
InInactiveClauseEnvironment || !isActive);
679+
// Disable updating the interface hash inside inactive blocks.
680+
llvm::SaveAndRestore<NullablePtr<llvm::MD5>> T(
681+
CurrentTokenHash, isActive ? CurrentTokenHash : nullptr);
682+
679683
if (isActive || !isVersionCondition) {
680684
parseElements(Elements, isActive);
681685
} else if (SyntaxContext->isEnabled()) {

lib/Sema/ConstraintSystem.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,19 @@ getDynamicResultSignature(ValueDecl *decl) {
216216
}
217217

218218
if (auto asd = dyn_cast<AbstractStorageDecl>(decl)) {
219+
auto ty = asd->getInterfaceType();
220+
221+
// Strip off a generic signature if we have one. This matches the logic
222+
// for methods, and ensures that we don't take a protocol's generic
223+
// signature into account for a subscript requirement.
224+
if (auto *genericFn = ty->getAs<GenericFunctionType>()) {
225+
ty = FunctionType::get(genericFn->getParams(), genericFn->getResult(),
226+
genericFn->getExtInfo());
227+
}
228+
219229
// Handle properties and subscripts, anchored by the getter's selector.
220230
return std::make_tuple(asd->isStatic(), asd->getObjCGetterSelector(),
221-
asd->getInterfaceType()->getCanonicalType());
231+
ty->getCanonicalType());
222232
}
223233

224234
llvm_unreachable("Not a valid @objc member");

lib/Sema/MiscDiagnostics.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
137137
if (auto *SE = dyn_cast<SubscriptExpr>(E))
138138
CallArgs.insert(SE->getIndex());
139139

140+
if (auto *DSE = dyn_cast<DynamicSubscriptExpr>(E))
141+
CallArgs.insert(DSE->getIndex());
142+
140143
if (auto *KPE = dyn_cast<KeyPathExpr>(E)) {
141144
for (auto Comp : KPE->getComponents()) {
142145
if (auto *Arg = Comp.getIndexExpr())

lib/Sema/TypeCheckAccess.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,11 +1483,14 @@ class UsableFromInlineChecker : public AccessControlCheckerBase,
14831483
}
14841484
};
14851485

1486+
// Diagnose public APIs exposing types that are either imported as
1487+
// implementation-only or declared as SPI.
14861488
class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
14871489
class Diagnoser;
14881490

14891491
void checkTypeImpl(
14901492
Type type, const TypeRepr *typeRepr, const SourceFile &SF,
1493+
const Decl *context,
14911494
const Diagnoser &diagnoser) {
14921495
// Don't bother checking errors.
14931496
if (type && type->hasError())
@@ -1500,14 +1503,15 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
15001503
if (typeRepr) {
15011504
const_cast<TypeRepr *>(typeRepr)->walk(TypeReprIdentFinder(
15021505
[&](const ComponentIdentTypeRepr *component) {
1503-
ModuleDecl *M = component->getBoundDecl()->getModuleContext();
1504-
if (!SF.isImportedImplementationOnly(M) &&
1505-
!SF.isImportedAsSPI(component->getBoundDecl()))
1506-
return true;
1507-
1508-
diagnoser.diagnoseType(component->getBoundDecl(), component,
1509-
SF.isImportedImplementationOnly(M));
1510-
foundAnyIssues = true;
1506+
TypeDecl *typeDecl = component->getBoundDecl();
1507+
ModuleDecl *M = typeDecl->getModuleContext();
1508+
bool isImplementationOnly = SF.isImportedImplementationOnly(M);
1509+
if (isImplementationOnly ||
1510+
(SF.isImportedAsSPI(typeDecl) && !context->isSPI())) {
1511+
diagnoser.diagnoseType(typeDecl, component, isImplementationOnly);
1512+
foundAnyIssues = true;
1513+
}
1514+
15111515
// We still continue even in the diagnostic case to report multiple
15121516
// violations.
15131517
return true;
@@ -1525,19 +1529,19 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
15251529

15261530
class ProblematicTypeFinder : public TypeDeclFinder {
15271531
const SourceFile &SF;
1532+
const Decl *context;
15281533
const Diagnoser &diagnoser;
15291534
public:
1530-
ProblematicTypeFinder(const SourceFile &SF, const Diagnoser &diagnoser)
1531-
: SF(SF), diagnoser(diagnoser) {}
1535+
ProblematicTypeFinder(const SourceFile &SF, const Decl *context, const Diagnoser &diagnoser)
1536+
: SF(SF), context(context), diagnoser(diagnoser) {}
15321537

15331538
void visitTypeDecl(const TypeDecl *typeDecl) {
15341539
ModuleDecl *M = typeDecl->getModuleContext();
1535-
if (!SF.isImportedImplementationOnly(M) &&
1536-
!SF.isImportedAsSPI(typeDecl))
1537-
return;
1538-
1539-
diagnoser.diagnoseType(typeDecl, /*typeRepr*/nullptr,
1540-
SF.isImportedImplementationOnly(M));
1540+
bool isImplementationOnly = SF.isImportedImplementationOnly(M);
1541+
if (isImplementationOnly ||
1542+
(SF.isImportedAsSPI(typeDecl) && !context->isSPI()))
1543+
diagnoser.diagnoseType(typeDecl, /*typeRepr*/nullptr,
1544+
isImplementationOnly);
15411545
}
15421546

15431547
void visitSubstitutionMap(SubstitutionMap subs) {
@@ -1597,15 +1601,15 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
15971601
}
15981602
};
15991603

1600-
type.walk(ProblematicTypeFinder(SF, diagnoser));
1604+
type.walk(ProblematicTypeFinder(SF, context, diagnoser));
16011605
}
16021606

16031607
void checkType(
16041608
Type type, const TypeRepr *typeRepr, const Decl *context,
16051609
const Diagnoser &diagnoser) {
16061610
auto *SF = context->getDeclContext()->getParentSourceFile();
16071611
assert(SF && "checking a non-source declaration?");
1608-
return checkTypeImpl(type, typeRepr, *SF, diagnoser);
1612+
return checkTypeImpl(type, typeRepr, *SF, context, diagnoser);
16091613
}
16101614

16111615
void checkType(
@@ -1702,7 +1706,7 @@ class ExportabilityChecker : public DeclVisitor<ExportabilityChecker> {
17021706
AccessScope accessScope =
17031707
VD->getFormalAccessScope(nullptr,
17041708
/*treatUsableFromInlineAsPublic*/true);
1705-
if (accessScope.isPublic() && !accessScope.isSPI())
1709+
if (accessScope.isPublic())
17061710
return false;
17071711

17081712
// Is this a stored property in a non-resilient struct or class?

lib/Sema/TypeCheckAttr.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,13 +862,60 @@ void AttributeChecker::visitSetterAccessAttr(
862862

863863
void AttributeChecker::visitSPIAccessControlAttr(SPIAccessControlAttr *attr) {
864864
if (auto VD = dyn_cast<ValueDecl>(D)) {
865+
// VD must be public or open to use an @_spi attribute.
865866
auto declAccess = VD->getFormalAccess();
866867
if (declAccess < AccessLevel::Public) {
867868
diagnoseAndRemoveAttr(attr,
868869
diag::spi_attribute_on_non_public,
869870
declAccess,
870871
D->getDescriptiveKind());
871872
}
873+
874+
// If VD is a public protocol requirement it can be SPI only if there's
875+
// a default implementation.
876+
if (auto protocol = dyn_cast<ProtocolDecl>(D->getDeclContext())) {
877+
auto implementations = TypeChecker::lookupMember(
878+
D->getDeclContext(),
879+
protocol->getDeclaredType(),
880+
VD->createNameRef(),
881+
NameLookupFlags::ProtocolMembers);
882+
bool hasDefaultImplementation = llvm::any_of(implementations,
883+
[&](const LookupResultEntry &entry) {
884+
auto entryDecl = entry.getValueDecl();
885+
auto DC = entryDecl->getDeclContext();
886+
auto extension = dyn_cast<ExtensionDecl>(DC);
887+
888+
// The implementation must be defined in the same module in
889+
// an unconstrained extension.
890+
if (!extension ||
891+
extension->getParentModule() != protocol->getParentModule() ||
892+
extension->isConstrainedExtension())
893+
return false;
894+
895+
// For computed properties and subscripts, check that the default
896+
// implementation defines `set` if the protocol declares it.
897+
if (auto protoStorage = dyn_cast<AbstractStorageDecl>(VD))
898+
if (auto entryStorage = dyn_cast<AbstractStorageDecl>(entryDecl))
899+
if (protoStorage->getAccessor(AccessorKind::Set) &&
900+
!entryStorage->getAccessor(AccessorKind::Set))
901+
return false;
902+
903+
return true;
904+
});
905+
906+
if (!hasDefaultImplementation)
907+
diagnoseAndRemoveAttr(attr,
908+
diag::spi_attribute_on_protocol_requirement,
909+
VD->getName());
910+
}
911+
912+
// Forbid stored properties marked SPI in frozen types.
913+
if (auto property = dyn_cast<AbstractStorageDecl>(VD))
914+
if (auto DC = dyn_cast<NominalTypeDecl>(D->getDeclContext()))
915+
if (property->hasStorage() && !DC->isFormallyResilient())
916+
diagnoseAndRemoveAttr(attr,
917+
diag::spi_attribute_on_frozen_stored_properties,
918+
VD->getName());
872919
}
873920
}
874921

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,17 @@ static bool isParamListRepresentableInObjC(const AbstractFunctionDecl *AFD,
304304

305305
/// Check whether the given declaration contains its own generic parameters,
306306
/// and therefore is not representable in Objective-C.
307-
static bool checkObjCWithGenericParams(const AbstractFunctionDecl *AFD,
308-
ObjCReason Reason) {
309-
bool Diagnose = shouldDiagnoseObjCReason(Reason, AFD->getASTContext());
307+
static bool checkObjCWithGenericParams(const ValueDecl *VD, ObjCReason Reason) {
308+
bool Diagnose = shouldDiagnoseObjCReason(Reason, VD->getASTContext());
310309

311-
if (AFD->getGenericParams()) {
310+
auto *GC = VD->getAsGenericContext();
311+
assert(GC);
312+
if (GC->getGenericParams()) {
312313
// Diagnose this problem, if asked to.
313314
if (Diagnose) {
314-
AFD->diagnose(diag::objc_invalid_with_generic_params,
315-
getObjCDiagnosticAttrKind(Reason));
316-
describeObjCReason(AFD, Reason);
315+
VD->diagnose(diag::objc_invalid_with_generic_params,
316+
VD->getDescriptiveKind(), getObjCDiagnosticAttrKind(Reason));
317+
describeObjCReason(VD, Reason);
317318
}
318319

319320
return true;
@@ -855,6 +856,8 @@ bool swift::isRepresentableInObjC(const SubscriptDecl *SD, ObjCReason Reason) {
855856

856857
if (checkObjCInForeignClassContext(SD, Reason))
857858
return false;
859+
if (checkObjCWithGenericParams(SD, Reason))
860+
return false;
858861

859862
// ObjC doesn't support class subscripts.
860863
if (!SD->isInstanceMember()) {

stdlib/public/core/Dictionary.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ extension Dictionary {
879879
/// - key: The key the look up in the dictionary.
880880
/// - defaultValue: The default value to use if `key` doesn't exist in the
881881
/// dictionary.
882-
/// - Returns: The value associated with `key` in the dictionary`; otherwise,
882+
/// - Returns: The value associated with `key` in the dictionary; otherwise,
883883
/// `defaultValue`.
884884
@inlinable
885885
public subscript(

stdlib/toolchain/Compatibility51/Concurrent.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <iterator>
2121
#include <algorithm>
2222
#include <atomic>
23+
#include <cassert>
2324
#include <functional>
2425
#include <pthread.h>
2526
#include <stdint.h>

test/Constraints/dynamic_lookup.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,11 @@ func dynamicInitCrash(ao: AnyObject.Type) {
354354
func unambiguousMethodParam(_ x: Int)
355355

356356
subscript(ambiguousSubscript _: Int) -> String { get } // expected-note {{found this candidate}}
357-
subscript(unambiguousSubscript _: String) -> Int { get } // expected-note {{found this candidate}}
357+
subscript(unambiguousSubscript _: String) -> Int { get }
358+
359+
subscript(differentSelectors _: Int) -> Int { // expected-note {{found this candidate}}
360+
@objc(differentSelector1:) get
361+
}
358362
}
359363

360364
class C1 {
@@ -368,7 +372,15 @@ class C1 {
368372
@objc func unambiguousMethodParam(_ x: Int) {}
369373

370374
@objc subscript(ambiguousSubscript _: Int) -> Int { return 0 } // expected-note {{found this candidate}}
371-
@objc subscript(unambiguousSubscript _: String) -> Int { return 0 } // expected-note {{found this candidate}}
375+
@objc subscript(unambiguousSubscript _: String) -> Int { return 0 }
376+
377+
@objc subscript(differentSelectors _: Int) -> Int { // expected-note {{found this candidate}}
378+
@objc(differentSelector2:) get { return 0 }
379+
}
380+
}
381+
382+
class C2 {
383+
@objc subscript(singleCandidate _: Int) -> Int { return 0 }
372384
}
373385

374386
func testAnyObjectAmbiguity(_ x: AnyObject) {
@@ -384,10 +396,19 @@ func testAnyObjectAmbiguity(_ x: AnyObject) {
384396
_ = x.ambiguousMethodParam // expected-error {{ambiguous use of 'ambiguousMethodParam'}}
385397
_ = x.unambiguousMethodParam
386398

399+
// SR-12799: Don't emit a "single-element" tuple error.
400+
_ = x[singleCandidate: 0]
401+
387402
_ = x[ambiguousSubscript: 0] // expected-error {{ambiguous use of 'subscript(ambiguousSubscript:)'}}
403+
_ = x[ambiguousSubscript: 0] as Int
404+
_ = x[ambiguousSubscript: 0] as String
405+
406+
// SR-8611: Make sure we can coalesce subscripts with the same types and
407+
// selectors through AnyObject lookup.
408+
_ = x[unambiguousSubscript: ""]
388409

389-
// FIX-ME(SR-8611): This is currently ambiguous but shouldn't be.
390-
_ = x[unambiguousSubscript: ""] // expected-error {{ambiguous use of 'subscript(unambiguousSubscript:)'}}
410+
// But not if they have different selectors.
411+
_ = x[differentSelectors: 0] // expected-error {{ambiguous use of 'subscript(differentSelectors:)}}
391412
}
392413

393414
// SR-11648

0 commit comments

Comments
 (0)