Skip to content

Commit be39c05

Browse files
authored
Merge pull request #71026 from xedin/rdar-111120803
[CSSimplify] Increase impact of requirement failures in special result builder methods
2 parents ac58db8 + b3152d8 commit be39c05

File tree

4 files changed

+211
-17
lines changed

4 files changed

+211
-17
lines changed

include/swift/Sema/ConstraintSystem.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6448,6 +6448,9 @@ bool containsPackExpansionType(TupleType *tuple);
64486448
/// \returns null if \c type is not a single unlabeled pack expansion tuple.
64496449
Type getPatternTypeOfSingleUnlabeledPackExpansionTuple(Type type);
64506450

6451+
/// Check whether this is a reference to one of the special result builder
6452+
/// methods prefixed with `build*` i.e. `buildBlock`, `buildExpression` etc.
6453+
bool isResultBuilderMethodReference(ASTContext &, UnresolvedDotExpr *);
64516454
} // end namespace constraints
64526455

64536456
template<typename ...Args>

lib/Sema/CSSimplify.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2755,7 +2755,12 @@ assessRequirementFailureImpact(ConstraintSystem &cs, Type requirementType,
27552755
if (!cs.findSelectedOverloadFor(calleeLoc))
27562756
return 10;
27572757
}
2758-
2758+
2759+
if (auto *UDE = getAsExpr<UnresolvedDotExpr>(anchor)) {
2760+
if (isResultBuilderMethodReference(cs.getASTContext(), UDE))
2761+
return 12;
2762+
}
2763+
27592764
auto resolvedTy = cs.simplifyType(requirementType);
27602765

27612766
// Increase the impact of a conformance fix for generic parameters on

lib/Sema/ConstraintSystem.cpp

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5494,21 +5494,6 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
54945494
// Aggregate all requirement fixes that belong to the same callee
54955495
// and attempt to diagnose possible ambiguities.
54965496
{
5497-
auto isResultBuilderMethodRef = [&](ASTNode node) {
5498-
auto *UDE = getAsExpr<UnresolvedDotExpr>(node);
5499-
if (!(UDE && UDE->isImplicit()))
5500-
return false;
5501-
5502-
auto &ctx = getASTContext();
5503-
SmallVector<Identifier, 4> builderMethods(
5504-
{ctx.Id_buildBlock, ctx.Id_buildExpression, ctx.Id_buildPartialBlock,
5505-
ctx.Id_buildFinalResult});
5506-
5507-
return llvm::any_of(builderMethods, [&](const Identifier &methodId) {
5508-
return UDE->getName().compare(DeclNameRef(methodId)) == 0;
5509-
});
5510-
};
5511-
55125497
// Aggregates fixes fixes attached to `buildExpression` and `buildBlock`
55135498
// methods at the particular source location.
55145499
llvm::MapVector<SourceLoc, SmallVector<FixInContext, 4>>
@@ -5524,7 +5509,8 @@ bool ConstraintSystem::diagnoseAmbiguityWithFixes(
55245509

55255510
auto *calleeLoc = entry.first->getCalleeLocator(fix->getLocator());
55265511

5527-
if (isResultBuilderMethodRef(calleeLoc->getAnchor())) {
5512+
auto *UDE = getAsExpr<UnresolvedDotExpr>(calleeLoc->getAnchor());
5513+
if (UDE && isResultBuilderMethodReference(getASTContext(), UDE)) {
55285514
auto *anchor = castToExpr<Expr>(calleeLoc->getAnchor());
55295515
builderMethodRequirementFixes[anchor->getLoc()].push_back(entry);
55305516
} else {
@@ -7969,3 +7955,17 @@ void constraints::dumpAnchor(ASTNode anchor, SourceManager *SM,
79697955
}
79707956
// TODO(diagnostics): Implement the rest of the cases.
79717957
}
7958+
7959+
bool constraints::isResultBuilderMethodReference(ASTContext &ctx,
7960+
UnresolvedDotExpr *UDE) {
7961+
if (!(UDE && UDE->isImplicit()))
7962+
return false;
7963+
7964+
SmallVector<Identifier, 5> builderMethods(
7965+
{ctx.Id_buildBlock, ctx.Id_buildExpression, ctx.Id_buildPartialBlock,
7966+
ctx.Id_buildFinalResult, ctx.Id_buildIf});
7967+
7968+
return llvm::any_of(builderMethods, [&](const Identifier &methodId) {
7969+
return UDE->getName().compare(DeclNameRef(methodId)) == 0;
7970+
});
7971+
}
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
// RUN: %target-typecheck-verify-swift -target %target-cpu-apple-macosx10.15 -swift-version 5
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: OS=macosx
5+
6+
import SwiftUI
7+
8+
extension [UInt8] {
9+
var toASCII : String? { nil }
10+
}
11+
12+
// rdar://111120803
13+
do {
14+
struct MissingOptionalUnwrap : View {
15+
var data: [UInt8]
16+
17+
var body: some View {
18+
Group {
19+
Text("")
20+
Text(data.toASCII)
21+
// expected-error@-1 {{value of optional type 'String?' must be unwrapped to a value of type 'String'}}
22+
// expected-note@-2 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
23+
// expected-note@-3 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}
24+
}
25+
}
26+
}
27+
}
28+
29+
// rdar://112928810
30+
do {
31+
struct DismissAction {
32+
func callAsFunction() {
33+
}
34+
}
35+
36+
struct TestConcurrencyMismatch : View {
37+
private var dismiss : DismissAction
38+
39+
var body: some View {
40+
List {
41+
}
42+
.toolbar {
43+
ToolbarItem(placement: .cancellationAction) {
44+
Button("Dismiss") {
45+
dismiss()
46+
}
47+
}
48+
ToolbarItem(placement: .primaryAction) {
49+
Button("Done") {
50+
MainActor.run {
51+
// expected-error@-1 {{cannot pass function of type '@Sendable () async -> ()' to parameter expecting synchronous function type}}
52+
await dismiss()
53+
// expected-note@-1 {{'async' inferred from asynchronous operation used here}}
54+
}
55+
}
56+
}
57+
}
58+
}
59+
}
60+
}
61+
62+
// rdar://115784749
63+
do {
64+
struct InvalidArgumentPlacement : View {
65+
var body: some View {
66+
let base = RoundedRectangle(cornerRadius: 12)
67+
Group {
68+
base.strokeBorder(lineWidth: 2, LinearGradient(gradient: Gradient(colors: [.red, .blue]), startPoint: .top, endPoint: .bottom))
69+
// expected-error@-1 {{unnamed argument #2 must precede argument 'lineWidth'}}
70+
Text("test")
71+
.font(.system(size: 200))
72+
.minimumScaleFactor(0.01)
73+
.aspectRatio(1, contentMode: .fit)
74+
}
75+
}
76+
}
77+
}
78+
79+
// rdar://118326796
80+
do {
81+
class Model: ObservableObject {
82+
}
83+
84+
struct InvalidRef: View {
85+
@State private var isLoading = true
86+
87+
var body: some View {
88+
Group {
89+
if isLoading{
90+
EmptyView().onAppear {
91+
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
92+
isLoading = false
93+
}
94+
}
95+
} else {
96+
NavigationView {
97+
}
98+
.environmentObject(Model)
99+
// expected-error@-1 {{type 'Model.Type' cannot conform to 'ObservableObject'}}
100+
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
101+
// expected-note@-3 {{required by instance method 'environmentObject' where 'T' = 'Model.Type'}}
102+
}
103+
}
104+
}
105+
}
106+
}
107+
108+
// rdar://106804509
109+
do {
110+
struct Entry: Identifiable {
111+
var id: String { name }
112+
let name: String
113+
let type: String = "string"
114+
}
115+
116+
struct MissingLabelTest: View {
117+
var entry: [Entry] = []
118+
119+
var body: some View {
120+
VStack(alignment: .leading) {
121+
ForEach(entry) { entry in
122+
HStack {
123+
Text(entry.name)
124+
Text("(\(entry.type))").foregroundColor(.secondary)
125+
}
126+
ViewWithTitle("title")
127+
// expected-error@-1 {{missing argument label 'title:' in call}}
128+
}
129+
}
130+
}
131+
}
132+
133+
struct ViewWithTitle: View {
134+
let title: String
135+
136+
var body: some View {
137+
Text(title)
138+
}
139+
}
140+
}
141+
142+
// rdar://119008852
143+
do {
144+
struct LazyPageView: View {
145+
@State var currentOffset = 0
146+
@State private var tabViewSelection = 0
147+
let minIndex: Int?
148+
let maxIndex: Int?
149+
let contentGen: (Int) -> any View
150+
151+
var body: some View {
152+
TabView(selection: $tabViewSelection) {
153+
Group {
154+
if minIndex == nil || currentOffset - 1 >= minIndex! {
155+
// expected-error@-1 {{type 'any View' cannot conform to 'View'}}
156+
// expected-note@-2 {{only concrete types such as structs, enums and classes can conform to protocols}}
157+
// expected-note@-3 {{required by static method 'buildIf' where 'Content' = 'any View'}}
158+
contentGen(currentOffset - 1)
159+
}
160+
}
161+
contentGen(currentOffset)
162+
}
163+
}
164+
}
165+
}
166+
167+
// rdar://118374670
168+
do {
169+
struct MissingWrapperInnerView: View {
170+
@State var cond = false
171+
172+
var body: some View {
173+
Group {
174+
Group {
175+
EmptyView()
176+
}
177+
.disabled(true)
178+
Toggle(isOn: cond) {
179+
// expected-error@-1 {{cannot convert value 'cond' of type 'Bool' to expected type 'Binding<Bool>', use wrapper instead}} {{22-22=$}}
180+
Text("")
181+
}
182+
}
183+
.disabled(true)
184+
}
185+
}
186+
}

0 commit comments

Comments
 (0)