Skip to content

Commit 1e4ac49

Browse files
Merge pull request #4400 from swiftwasm/main
[pull] swiftwasm from main
2 parents b36d317 + 16d204b commit 1e4ac49

File tree

55 files changed

+1418
-275
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1418
-275
lines changed

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,36 @@ _**Note:** This is in reverse chronological order, so newer entries are added to
55

66
## Swift 5.7
77

8+
* [SE-0326][]:
9+
10+
It's now possible to infer parameter and result types from the body of a multi-statement
11+
closure. The distinction between single- and multi-statement closures has been removed.
12+
13+
Use of closures becomes less cumbersome by removing the need to constantly specify explicit
14+
closure types which sometimes could be pretty large e.g. when there are multiple parameters
15+
or a complex tuple result type.
16+
17+
For example:
18+
19+
```swift
20+
func map<T>(fn: (Int) -> T) -> T {
21+
return fn(42)
22+
}
23+
24+
func computeResult<U: BinaryInteger>(_: U) -> U { /* processing */ }
25+
26+
let _ = map {
27+
if let $0 < 0 {
28+
// do some processing
29+
}
30+
31+
return computeResult($0)
32+
}
33+
```
34+
35+
The result type of `map` can now be inferred from the body of the trailing closure
36+
passed as an argument.
37+
838
* [SE-0345][]:
939

1040
It is now possible to unwrap optional variables with a shorthand syntax that
@@ -9119,6 +9149,7 @@ Swift 1.0
91199149
[SE-0343]: <https://github.com/apple/swift-evolution/blob/main/proposals/0343-top-level-concurrency.md>
91209150
[SE-0340]: <https://github.com/apple/swift-evolution/blob/main/proposals/0340-swift-noasync.md>
91219151
[SE-0345]: <https://github.com/apple/swift-evolution/blob/main/proposals/0345-if-let-shorthand.md>
9152+
[SE-0326]: <https://github.com/apple/swift-evolution/blob/main/proposals/0326-extending-multi-statement-closure-inference.md>
91229153

91239154
[SR-75]: <https://bugs.swift.org/browse/SR-75>
91249155
[SR-106]: <https://bugs.swift.org/browse/SR-106>

include/swift/Sema/ConstraintSystem.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5694,7 +5694,6 @@ Expr *getArgumentLabelTargetExpr(Expr *fn);
56945694
/// variable and anything that depends on it to their non-dependent bounds.
56955695
Type typeEraseOpenedExistentialReference(Type type, Type existentialBaseType,
56965696
TypeVariableType *openedTypeVar,
5697-
const DeclContext *useDC,
56985697
TypePosition outermostPosition);
56995698

57005699
/// Returns true if a reference to a member on a given base type will apply

lib/AST/RequirementMachine/Debug.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ enum class DebugFlags : unsigned {
7272

7373
/// Print a trace of requirement machines constructed and how long each took.
7474
Timers = (1<<16),
75+
76+
/// Print conflicting rules.
77+
ConflictingRules = (1<<17),
7578
};
7679

7780
using DebugOptions = OptionSet<DebugFlags>;

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -167,30 +167,6 @@ void RewriteSystem::propagateRedundantRequirementIDs() {
167167
}
168168
}
169169

170-
/// Process pairs of conflicting rules, marking the more specific rule as
171-
/// conflicting, which instructs minimization to drop this rule.
172-
void RewriteSystem::processConflicts() {
173-
for (auto pair : ConflictingRules) {
174-
auto *existingRule = &getRule(pair.first);
175-
auto *newRule = &getRule(pair.second);
176-
177-
// The identity conformance rule ([P].[P] => [P]) will conflict with
178-
// a concrete type requirement in an invalid protocol declaration
179-
// where 'Self' is constrained to a type that does not conform to
180-
// the protocol. This rule is permanent, so don't mark it as
181-
// conflicting in this case.
182-
183-
if (!existingRule->isIdentityConformanceRule() &&
184-
existingRule->getRHS().size() >= newRule->getRHS().size())
185-
existingRule->markConflicting();
186-
if (!newRule->isIdentityConformanceRule() &&
187-
newRule->getRHS().size() >= existingRule->getRHS().size())
188-
newRule->markConflicting();
189-
190-
// FIXME: Diagnose the conflict later.
191-
}
192-
}
193-
194170
/// Find a rule to delete by looking through all loops for rewrite rules appearing
195171
/// once in empty context. Returns a pair consisting of a loop ID and a rule ID,
196172
/// otherwise returns None.
@@ -477,7 +453,6 @@ void RewriteSystem::minimizeRewriteSystem() {
477453
Minimized = 1;
478454

479455
propagateExplicitBits();
480-
processConflicts();
481456

482457
if (Context.getASTContext().LangOpts.EnableRequirementMachineLoopNormalization) {
483458
for (auto &loop : Loops) {

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,37 @@ static void recordRelation(Term key,
119119
(void) system.addRule(lhs, rhs, &path);
120120
}
121121

122+
/// Given two property rules that conflict because no concrete type
123+
/// can satisfy both, mark one or both rules conflicting.
124+
///
125+
/// The right hand side of one rule must be a suffix of the other
126+
/// (in which case the longer of the two rules is conflicting) or
127+
/// the right hand sides are equal (in which case both will be
128+
/// conflicting).
122129
void RewriteSystem::recordConflict(unsigned existingRuleID,
123130
unsigned newRuleID) {
124131
ConflictingRules.emplace_back(existingRuleID, newRuleID);
132+
133+
auto &existingRule = getRule(existingRuleID);
134+
auto &newRule = getRule(newRuleID);
135+
136+
if (Debug.contains(DebugFlags::ConflictingRules)) {
137+
llvm::dbgs() << "Conflicting rules:\n";
138+
llvm::dbgs() << "- " << existingRule << "\n";
139+
llvm::dbgs() << "- " << newRule << "\n";
140+
}
141+
142+
// The identity conformance rule ([P].[P] => [P]) will conflict with
143+
// a concrete type requirement in an invalid protocol declaration
144+
// where 'Self' is constrained to a type that does not conform to
145+
// the protocol. This rule is permanent, so don't mark it as
146+
// conflicting in this case.
147+
if (!existingRule.isIdentityConformanceRule() &&
148+
existingRule.getRHS().size() >= newRule.getRHS().size())
149+
existingRule.markConflicting();
150+
if (!newRule.isIdentityConformanceRule() &&
151+
newRule.getRHS().size() >= existingRule.getRHS().size())
152+
newRule.markConflicting();
125153
}
126154

127155
void PropertyMap::addConformanceProperty(
@@ -350,8 +378,10 @@ void PropertyMap::addSuperclassProperty(
350378
}
351379

352380
auto &req = props->Superclasses[props->SuperclassDecl];
353-
for (const auto &pair : req.SuperclassRules)
354-
System.recordConflict(pair.second, ruleID);
381+
for (const auto &pair : req.SuperclassRules) {
382+
if (checkRulePairOnce(pair.second, ruleID))
383+
System.recordConflict(pair.second, ruleID);
384+
}
355385
}
356386
}
357387

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -654,20 +654,35 @@ void swift::rewriting::realizeInheritedRequirements(
654654
}
655655
}
656656

657+
static bool shouldSuggestConcreteTypeFixit(
658+
Type type, AllowConcreteTypePolicy concreteTypePolicy) {
659+
switch (concreteTypePolicy) {
660+
case AllowConcreteTypePolicy::All:
661+
return true;
662+
663+
case AllowConcreteTypePolicy::AssocTypes:
664+
return type->is<DependentMemberType>();
665+
666+
case AllowConcreteTypePolicy::NestedAssocTypes:
667+
if (auto *memberType = type->getAs<DependentMemberType>())
668+
return memberType->getBase()->is<DependentMemberType>();
669+
670+
return false;
671+
}
672+
}
673+
657674
/// Emit diagnostics for the given \c RequirementErrors.
658675
///
659676
/// \param ctx The AST context in which to emit diagnostics.
660677
/// \param errors The set of requirement diagnostics to be emitted.
661-
/// \param allowConcreteGenericParams Whether concrete type parameters
662-
/// are permitted in the generic signature. If true, diagnostics will
663-
/// offer fix-its to turn invalid type requirements, e.g. T: Int, into
664-
/// same-type requirements.
678+
/// \param concreteTypePolicy Whether fix-its should be offered to turn
679+
/// invalid type requirements, e.g. T: Int, into same-type requirements.
665680
///
666681
/// \returns true if any errors were emitted, and false otherwise (including
667682
/// when only warnings were emitted).
668683
bool swift::rewriting::diagnoseRequirementErrors(
669684
ASTContext &ctx, ArrayRef<RequirementError> errors,
670-
bool allowConcreteGenericParams) {
685+
AllowConcreteTypePolicy concreteTypePolicy) {
671686
bool diagnosedError = false;
672687

673688
for (auto error : errors) {
@@ -697,7 +712,7 @@ bool swift::rewriting::diagnoseRequirementErrors(
697712
return subjectTypeName;
698713
};
699714

700-
if (allowConcreteGenericParams) {
715+
if (shouldSuggestConcreteTypeFixit(subjectType, concreteTypePolicy)) {
701716
auto options = PrintOptions::forDiagnosticArguments();
702717
auto subjectTypeName = subjectType.getString(options);
703718
auto subjectTypeNameWithoutSelf = getNameWithoutSelf(subjectTypeName);
@@ -725,16 +740,25 @@ bool swift::rewriting::diagnoseRequirementErrors(
725740
auto requirement = error.requirement;
726741
auto conflict = error.conflictingRequirement;
727742

743+
if (requirement.getFirstType()->hasError() ||
744+
(requirement.getKind() != RequirementKind::Layout &&
745+
requirement.getSecondType()->hasError())) {
746+
// Don't emit a cascading error.
747+
break;
748+
}
749+
728750
if (!conflict) {
729-
if (requirement.getFirstType()->hasError() ||
730-
requirement.getSecondType()->hasError()) {
731-
// Don't emit a cascading error.
732-
break;
733-
}
734751
ctx.Diags.diagnose(loc, diag::requires_same_concrete_type,
735752
requirement.getFirstType(),
736753
requirement.getSecondType());
737754
} else {
755+
if (conflict->getFirstType()->hasError() ||
756+
(conflict->getKind() != RequirementKind::Layout &&
757+
conflict->getSecondType()->hasError())) {
758+
// Don't emit a cascading error.
759+
break;
760+
}
761+
738762
auto options = PrintOptions::forDiagnosticArguments();
739763
std::string requirements;
740764
llvm::raw_string_ostream OS(requirements);
@@ -754,6 +778,13 @@ bool swift::rewriting::diagnoseRequirementErrors(
754778

755779
case RequirementError::Kind::RedundantRequirement: {
756780
auto requirement = error.requirement;
781+
if (requirement.getFirstType()->hasError() ||
782+
(requirement.getKind() != RequirementKind::Layout &&
783+
requirement.getSecondType()->hasError())) {
784+
// Don't emit a cascading error.
785+
break;
786+
}
787+
757788
switch (requirement.getKind()) {
758789
case RequirementKind::SameType:
759790
ctx.Diags.diagnose(loc, diag::redundant_same_type_to_concrete,
@@ -886,7 +917,8 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
886917

887918
if (ctx.LangOpts.RequirementMachineProtocolSignatures ==
888919
RequirementMachineMode::Enabled) {
889-
diagnoseRequirementErrors(ctx, errors, /*allowConcreteGenericParams=*/false);
920+
diagnoseRequirementErrors(ctx, errors,
921+
AllowConcreteTypePolicy::NestedAssocTypes);
890922
}
891923

892924
return ctx.AllocateCopy(result);
@@ -1159,7 +1191,8 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
11591191

11601192
if (ctx.LangOpts.RequirementMachineProtocolSignatures ==
11611193
RequirementMachineMode::Enabled) {
1162-
diagnoseRequirementErrors(ctx, errors, /*allowConcreteGenericParams=*/false);
1194+
diagnoseRequirementErrors(ctx, errors,
1195+
AllowConcreteTypePolicy::NestedAssocTypes);
11631196
}
11641197

11651198
return ctx.AllocateCopy(result);

lib/AST/RequirementMachine/RequirementLowering.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,24 @@ void realizeInheritedRequirements(TypeDecl *decl, Type type,
5555
SmallVectorImpl<StructuralRequirement> &result,
5656
SmallVectorImpl<RequirementError> &errors);
5757

58+
/// Policy for the fixit that transforms 'T : S' where 'S' is not a protocol
59+
/// or a class into 'T == S'.
60+
enum AllowConcreteTypePolicy {
61+
/// Any type parameter can be concrete.
62+
All,
63+
64+
/// Only associated types can be concrete.
65+
AssocTypes,
66+
67+
/// Only nested associated types can be concrete. This is for protocols,
68+
/// where we don't want to suggest making an associated type member of
69+
/// 'Self' concrete.
70+
NestedAssocTypes
71+
};
72+
5873
bool diagnoseRequirementErrors(ASTContext &ctx,
5974
ArrayRef<RequirementError> errors,
60-
bool allowConcreteGenericParams);
75+
AllowConcreteTypePolicy concreteTypePolicy);
6176

6277
// Defined in ConcreteContraction.cpp.
6378
bool performConcreteContraction(

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ RequirementSignatureRequestRQM::evaluate(Evaluator &evaluator,
412412
SmallVector<RequirementError, 4> errors;
413413
machine->computeRequirementDiagnostics(errors, proto->getLoc());
414414
diagnoseRequirementErrors(ctx, errors,
415-
/*allowConcreteGenericParams=*/false);
415+
AllowConcreteTypePolicy::NestedAssocTypes);
416416
}
417417

418418
if (!machine->getErrors()) {
@@ -844,7 +844,10 @@ InferredGenericSignatureRequestRQM::evaluate(
844844
ctx.LangOpts.RequirementMachineInferredSignatures ==
845845
RequirementMachineMode::Enabled) {
846846
machine->computeRequirementDiagnostics(errors, loc);
847-
diagnoseRequirementErrors(ctx, errors, allowConcreteGenericParams);
847+
diagnoseRequirementErrors(ctx, errors,
848+
allowConcreteGenericParams
849+
? AllowConcreteTypePolicy::All
850+
: AllowConcreteTypePolicy::AssocTypes);
848851
}
849852

850853
// FIXME: Handle allowConcreteGenericParams

lib/AST/RequirementMachine/RewriteContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ static DebugOptions parseDebugFlags(StringRef debugFlags) {
177177
.Case("concrete-contraction", DebugFlags::ConcreteContraction)
178178
.Case("propagate-requirement-ids", DebugFlags::PropagateRequirementIDs)
179179
.Case("timers", DebugFlags::Timers)
180+
.Case("conflicting-rules", DebugFlags::ConflictingRules)
180181
.Default(None);
181182
if (!flag) {
182183
llvm::errs() << "Unknown debug flag in -debug-requirement-machine "

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,41 @@ void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const {
608608
#undef ASSERT_RULE
609609
}
610610

611+
/// Determine whether this is a redundantly inheritable Objective-C protocol.
612+
///
613+
/// A redundantly-inheritable Objective-C protocol is one where we will
614+
/// silently accept a directly-stated redundant conformance to this protocol,
615+
/// and emit this protocol in the list of "inherited" protocols. There are
616+
/// two cases where we allow this:
617+
///
618+
// 1) For a protocol defined in Objective-C, so that we will match Clang's
619+
/// behavior, and
620+
/// 2) For an @objc protocol defined in Swift that directly inherits from
621+
/// JavaScriptCore's JSExport, which depends on this behavior.
622+
static bool isRedundantlyInheritableObjCProtocol(const ProtocolDecl *inheritingProto,
623+
const ProtocolDecl *proto) {
624+
if (!proto->isObjC()) return false;
625+
626+
// Check the two conditions in which we will suppress the diagnostic and
627+
// emit the redundant inheritance.
628+
if (!inheritingProto->hasClangNode() && !proto->getName().is("JSExport"))
629+
return false;
630+
631+
// If the inheriting protocol already has @_restatedObjCConformance with
632+
// this protocol, we're done.
633+
for (auto *attr : inheritingProto->getAttrs()
634+
.getAttributes<RestatedObjCConformanceAttr>()) {
635+
if (attr->Proto == proto) return true;
636+
}
637+
638+
// Otherwise, add @_restatedObjCConformance.
639+
auto &ctx = proto->getASTContext();
640+
const_cast<ProtocolDecl *>(inheritingProto)
641+
->getAttrs().add(new (ctx) RestatedObjCConformanceAttr(
642+
const_cast<ProtocolDecl *>(proto)));
643+
return true;
644+
}
645+
611646
/// Computes the set of explicit redundant requirements to
612647
/// emit warnings for in the source code.
613648
void RewriteSystem::computeRedundantRequirementDiagnostics(
@@ -689,8 +724,18 @@ void RewriteSystem::computeRedundantRequirementDiagnostics(
689724
auto isRedundantRule = [&](unsigned ruleID) {
690725
const auto &rule = getRules()[ruleID];
691726

692-
return (rule.isRedundant() &&
693-
nonExplicitNonRedundantRules.count(ruleID) == 0);
727+
if (!rule.isRedundant())
728+
return false;
729+
730+
if (nonExplicitNonRedundantRules.count(ruleID) > 0)
731+
return false;
732+
733+
if (rule.isProtocolRefinementRule(Context) &&
734+
isRedundantlyInheritableObjCProtocol(rule.getLHS()[0].getProtocol(),
735+
rule.getLHS()[1].getProtocol()))
736+
return false;
737+
738+
return true;
694739
};
695740

696741
// Finally walk through the written requirements, diagnosing any that are

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,6 @@ class RewriteSystem final {
361361

362362
void propagateRedundantRequirementIDs();
363363

364-
void processConflicts();
365-
366364
using EliminationPredicate = llvm::function_ref<bool(unsigned loopID,
367365
unsigned ruleID)>;
368366

0 commit comments

Comments
 (0)