Skip to content

Commit 7e5373a

Browse files
authored
Merge pull request #2629 from swiftwasm/main
[pull] swiftwasm from main
2 parents d048ef0 + b6f9677 commit 7e5373a

File tree

20 files changed

+189
-22
lines changed

20 files changed

+189
-22
lines changed

.clang-format

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
BasedOnStyle: LLVM
2-
AlwaysBreakTemplateDeclarations: Yes
2+
AlwaysBreakTemplateDeclarations: Yes

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,10 @@ ERROR(reserved_member_name,none,
783783
"type member must not be named %0, since it would conflict with the"
784784
" 'foo.%1' expression", (DeclName, StringRef))
785785

786+
NOTE(invalid_redecl_by_optionality_note,none,
787+
"%select{implicitly unwrapped |}0optional parameter is of "
788+
"same type as %select{implicitly unwrapped |}1optional parameter",
789+
(bool, bool))
786790
ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
787791
ERROR(invalid_redecl_init,none,
788792
"invalid redeclaration of synthesized %select{|memberwise }1%0",

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,66 @@ CheckRedeclarationRequest::evaluate(Evaluator &eval, ValueDecl *current) const {
646646
continue;
647647
}
648648

649+
// Signatures are the same, but interface types are not. We must
650+
// have a type that we've massaged as part of signature
651+
// interface type generation.
652+
if (current->getInterfaceType()->isEqual(other->getInterfaceType())) {
653+
if (currentDC->isTypeContext() == other->getDeclContext()->isTypeContext()) {
654+
auto currFnTy = current->getInterfaceType()->getAs<AnyFunctionType>();
655+
auto otherFnTy = other->getInterfaceType()->getAs<AnyFunctionType>();
656+
if (currFnTy && otherFnTy && currentDC->isTypeContext()) {
657+
currFnTy = currFnTy->getResult()->getAs<AnyFunctionType>();
658+
otherFnTy = otherFnTy->getResult()->getAs<AnyFunctionType>();
659+
}
660+
661+
if (currFnTy && otherFnTy) {
662+
ArrayRef<AnyFunctionType::Param> currParams = currFnTy->getParams();
663+
ArrayRef<AnyFunctionType::Param> otherParams = otherFnTy->getParams();
664+
665+
if (currParams.size() == otherParams.size()) {
666+
auto diagnosed = false;
667+
for (unsigned i : indices(currParams)) {
668+
669+
bool currIsIUO = false;
670+
bool otherIsIUO = false;
671+
bool optionalRedecl = false;
672+
673+
if (currParams[i].getPlainType()->getOptionalObjectType()) {
674+
optionalRedecl = true;
675+
if (swift::getParameterAt(current, i)->isImplicitlyUnwrappedOptional())
676+
currIsIUO = true;
677+
}
678+
679+
if (otherParams[i].getPlainType()->getOptionalObjectType()) {
680+
if (swift::getParameterAt(other, i)->isImplicitlyUnwrappedOptional())
681+
otherIsIUO = true;
682+
}
683+
else {
684+
optionalRedecl = false;
685+
}
686+
687+
if (optionalRedecl && currIsIUO != otherIsIUO) {
688+
ctx.Diags.diagnoseWithNotes(
689+
current->diagnose(diag::invalid_redecl,
690+
current->getName()), [&]() {
691+
other->diagnose(diag::invalid_redecl_prev, other->getName());
692+
});
693+
current->diagnose(diag::invalid_redecl_by_optionality_note,
694+
otherIsIUO, currIsIUO);
695+
696+
current->setInvalid();
697+
diagnosed = true;
698+
break;
699+
}
700+
}
701+
702+
if (diagnosed)
703+
break;
704+
}
705+
}
706+
}
707+
}
708+
649709
// If the conflicting declarations have non-overlapping availability and,
650710
// we allow the redeclaration to proceed if...
651711
//

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -731,26 +731,49 @@ tryCastToAnyHashable(
731731
// TODO: Implement a fast path for NSString->AnyHashable casts.
732732
// These are incredibly common because an NSDictionary with
733733
// NSString keys is bridged by default to [AnyHashable:Any].
734-
// Until this is implemented, fall through to the default case
735-
SWIFT_FALLTHROUGH;
734+
// Until this is implemented, fall through to the general case
735+
break;
736736
#else
737-
// If no Obj-C interop, just fall through to the default case.
738-
SWIFT_FALLTHROUGH;
737+
// If no Obj-C interop, just fall through to the general case.
738+
break;
739739
#endif
740740
}
741-
default: {
742-
auto hashableConformance = reinterpret_cast<const HashableWitnessTable *>(
743-
swift_conformsToProtocol(srcType, &HashableProtocolDescriptor));
744-
if (hashableConformance) {
745-
_swift_convertToAnyHashableIndirect(srcValue, destLocation,
746-
srcType, hashableConformance);
747-
return DynamicCastResult::SuccessViaCopy;
748-
} else {
749-
return DynamicCastResult::Failure;
741+
case MetadataKind::Optional: {
742+
// Until SR-9047 fixes the interactions between AnyHashable and Optional, we
743+
// avoid directly injecting Optionals. In particular, this allows
744+
// casts from [String?:String] to [AnyHashable:Any] to work the way people
745+
// expect. Otherwise, without SR-9047, the resulting dictionary can only be
746+
// indexed with an explicit Optional<String>, not a plain String.
747+
// After SR-9047, we can consider dropping this special case entirely.
748+
749+
// !!!! This breaks compatibility with compiler-optimized casts
750+
// (which just inject) and violates the Casting Spec. It just preserves
751+
// the behavior of the older casting code until we can clean things up.
752+
auto srcInnerType = cast<EnumMetadata>(srcType)->getGenericArgs()[0];
753+
unsigned sourceEnumCase = srcInnerType->vw_getEnumTagSinglePayload(
754+
srcValue, /*emptyCases=*/1);
755+
auto nonNil = (sourceEnumCase == 0);
756+
if (nonNil) {
757+
return DynamicCastResult::Failure; // Our caller will unwrap the optional and try again
750758
}
759+
// Else Optional is nil -- the general case below will inject it
760+
break;
751761
}
762+
default:
763+
break;
764+
}
765+
766+
767+
// General case: If it conforms to Hashable, we cast it
768+
auto hashableConformance = reinterpret_cast<const HashableWitnessTable *>(
769+
swift_conformsToProtocol(srcType, &HashableProtocolDescriptor));
770+
if (hashableConformance) {
771+
_swift_convertToAnyHashableIndirect(srcValue, destLocation,
772+
srcType, hashableConformance);
773+
return DynamicCastResult::SuccessViaCopy;
774+
} else {
775+
return DynamicCastResult::Failure;
752776
}
753-
return DynamicCastResult::Failure;
754777
}
755778

756779
static DynamicCastResult

stdlib/tools/swift-reflection-test/swift-reflection-test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ makeLocalSection(const void *Buffer,
310310
}
311311

312312
swift_reflection_section_t LS = {(void *)Buffer,
313-
(void *)(Buffer + Section.Size)};
313+
(void *)((uint8_t *)Buffer + Section.Size)};
314314
return LS;
315315
}
316316

test/Casting/Casts.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,4 +881,47 @@ CastsTests.test("NSDictionary -> Dictionary casting [SR-12025]") {
881881
}
882882
#endif
883883

884+
// Casting optionals to AnyHashable is a little peculiar
885+
// TODO: It would be nice if AnyHashable(Optional("Foo")) == AnyHashable("Foo")
886+
// (including as dictionary keys). That would make this a lot less confusing.
887+
CastsTests.test("Optional cast to AnyHashable") {
888+
let d: [String?: String] = ["FooKey": "FooValue", nil: "NilValue"]
889+
// In Swift 5.3, this cast DOES unwrap the non-nil key
890+
// We've deliberately tried to preserve that behavior in Swift 5.4
891+
let d2 = d as [AnyHashable: String]
892+
893+
// After SR-9047, all four of the following should work:
894+
let d3 = d2["FooKey" as String? as AnyHashable]
895+
expectNil(d3)
896+
let d4 = d2["FooKey" as String?]
897+
expectNil(d4)
898+
let d5 = d2["FooKey"]
899+
expectNotNil(d5)
900+
let d6 = d2["FooKey" as AnyHashable]
901+
expectNotNil(d6)
902+
903+
// The nil key should be preserved and still function
904+
let d7 = d2[String?.none as AnyHashable]
905+
expectNotNil(d7)
906+
907+
// Direct casts via the runtime unwrap the optional
908+
let a: String = "Foo"
909+
let ah: AnyHashable = a
910+
let b: String? = a
911+
let bh = runtimeCast(b, to: AnyHashable.self)
912+
expectEqual(bh, ah)
913+
914+
// Direct casts that don't go through the runtime don't unwrap the optional
915+
// This is inconsistent with the runtime cast behavior above. We should
916+
// probably change the runtime behavior above to work the same as this,
917+
// but that should wait until SR-9047 lands.
918+
let x: String = "Baz"
919+
let xh = x as AnyHashable
920+
let y: String? = x
921+
let yh = y as AnyHashable // Doesn't unwrap the optional
922+
// xh is AnyHashable("Baz")
923+
// yh is AnyHashable(Optional("Baz"))
924+
expectNotEqual(xh, yh)
925+
}
926+
884927
runAllTests()

test/IDE/complete_async_context.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency
22

3+
// REQUIRES: concurrency
4+
35
func funcThrows() throws {
46
fatalError()
57
}

test/IDE/complete_asyncannotation.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency
22

3+
// REQUIRES: concurrency
4+
35
func globalFuncAsync() async {}
46
func globalFuncAsyncThrows() async throws {}
57
func globalFuncAsyncRethrows(_ x: () async throws -> ()) async rethrows {}

test/IDE/complete_concurrency_keyword.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency
22

3+
// REQUIRES: concurrency
4+
35
// CHECK_DECL: NOT
46

57
#^GLOBAL^#

test/IDE/complete_concurrency_specifier.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency
22

3+
// REQUIRES: concurrency
4+
35
// SPECIFIER: Begin completions
46
// SPECIFIER-DAG: Keyword/None: async; name=async
57
// SPECIFIER-DAG: Keyword[throws]/None: throws; name=throws

0 commit comments

Comments
 (0)