Skip to content

Commit f1ca2d7

Browse files
committed
Enable SE-0328 "Structural opaque result types" by default.
Remove the error that prevented the use of multiple opaque result types, which was the remaining blocker for SE-0328's structural opaque result types. Add some type checking tests for this feature, and customize the diagnostics so they describe *which* opaque result type failed to match when indeed there is a failure.
1 parent 482421f commit f1ca2d7

File tree

6 files changed

+81
-36
lines changed

6 files changed

+81
-36
lines changed

Diff for: include/swift/AST/Decl.h

+9-9
Original file line numberDiff line numberDiff line change
@@ -2746,15 +2746,6 @@ class OpaqueTypeDecl final :
27462746
return getNumOpaqueReturnTypeReprs();
27472747
}
27482748

2749-
/// Retrieve the buffer containing the opaque return type
2750-
/// representations that correspond to the opaque generic parameters.
2751-
ArrayRef<OpaqueReturnTypeRepr *> getOpaqueReturnTypeReprs() const {
2752-
return {
2753-
getTrailingObjects<OpaqueReturnTypeRepr *>(),
2754-
getNumOpaqueReturnTypeReprs()
2755-
};
2756-
}
2757-
27582749
public:
27592750
static OpaqueTypeDecl *get(
27602751
ValueDecl *NamingDecl, GenericParamList *GenericParams,
@@ -2793,6 +2784,15 @@ class OpaqueTypeDecl final :
27932784
return OpaqueInterfaceGenericSignature.getInnermostGenericParams();
27942785
}
27952786

2787+
/// Retrieve the buffer containing the opaque return type
2788+
/// representations that correspond to the opaque generic parameters.
2789+
ArrayRef<OpaqueReturnTypeRepr *> getOpaqueReturnTypeReprs() const {
2790+
return {
2791+
getTrailingObjects<OpaqueReturnTypeRepr *>(),
2792+
getNumOpaqueReturnTypeReprs()
2793+
};
2794+
}
2795+
27962796
/// The underlying interface type describing the whole opaque type.
27972797
///
27982798
/// FIXME: Structured opaque types will generalize this to an

Diff for: include/swift/AST/DiagnosticsSema.def

+2-5
Original file line numberDiff line numberDiff line change
@@ -1876,9 +1876,6 @@ ERROR(opaque_type_invalid_constraint,none,
18761876
"and/or a base class", ())
18771877
NOTE(opaque_of_optional_rewrite,none,
18781878
"did you mean to write an optional of an 'opaque' type?", ())
1879-
ERROR(more_than_one_opaque_type,none,
1880-
"%0 contains multiple 'opaque' types, but only one 'opaque' type is "
1881-
"supported", (TypeRepr*))
18821879
ERROR(inferred_opaque_type,none,
18831880
"property definition has inferred type %0, involving the 'some' "
18841881
"return type of another declaration", (Type))
@@ -4135,8 +4132,8 @@ ERROR(opaque_type_no_underlying_type_candidates,none,
41354132
"function declares an opaque return type, but has no return statements "
41364133
"in its body from which to infer an underlying type", ())
41374134
ERROR(opaque_type_mismatched_underlying_type_candidates,none,
4138-
"function declares an opaque return type, but the return statements "
4139-
"in its body do not have matching underlying types", ())
4135+
"function declares an opaque return type %0, but the return statements "
4136+
"in its body do not have matching underlying types", (TypeRepr *))
41404137
NOTE(opaque_type_underlying_type_candidate_here,none,
41414138
"return statement has underlying type %0", (Type))
41424139
ERROR(opaque_type_self_referential_underlying_type,none,

Diff for: lib/Sema/MiscDiagnostics.cpp

+30-5
Original file line numberDiff line numberDiff line change
@@ -2651,12 +2651,36 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26512651
return canonicalUnderlyingSubs != otherCandidate.second.getCanonical();
26522652
});
26532653
if (mismatch) {
2654+
unsigned mismatchIndex = OpaqueDecl->getOpaqueGenericParams().size();
2655+
for (auto genericParam : OpaqueDecl->getOpaqueGenericParams()) {
2656+
unsigned index = genericParam->getIndex();
2657+
Type underlyingType = Candidates[0].second.getReplacementTypes()[index];
2658+
bool found = false;
2659+
for (const auto &candidate : Candidates) {
2660+
Type otherType = candidate.second.getReplacementTypes()[index];
2661+
if (!underlyingType->isEqual(otherType)) {
2662+
mismatchIndex = index;
2663+
found = true;
2664+
break;
2665+
}
2666+
}
2667+
2668+
if (found)
2669+
break;
2670+
}
2671+
assert(mismatchIndex < OpaqueDecl->getOpaqueGenericParams().size());
2672+
TypeRepr *opaqueRepr =
2673+
OpaqueDecl->getOpaqueReturnTypeReprs()[mismatchIndex];
26542674
Implementation->diagnose(
2655-
diag::opaque_type_mismatched_underlying_type_candidates);
2675+
diag::opaque_type_mismatched_underlying_type_candidates,
2676+
opaqueRepr)
2677+
.highlight(opaqueRepr->getSourceRange());
2678+
26562679
for (auto candidate : Candidates) {
2657-
Ctx.Diags.diagnose(candidate.first->getLoc(),
2658-
diag::opaque_type_underlying_type_candidate_here,
2659-
candidate.second.getReplacementTypes()[0]);
2680+
Ctx.Diags.diagnose(
2681+
candidate.first->getLoc(),
2682+
diag::opaque_type_underlying_type_candidate_here,
2683+
candidate.second.getReplacementTypes()[mismatchIndex]);
26602684
}
26612685
return;
26622686
}
@@ -2672,9 +2696,10 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
26722696
});
26732697

26742698
if (isSelfReferencing) {
2699+
unsigned index = genericParam->getIndex();
26752700
Ctx.Diags.diagnose(Candidates.front().first->getLoc(),
26762701
diag::opaque_type_self_referential_underlying_type,
2677-
underlyingSubs.getReplacementTypes()[0]);
2702+
underlyingSubs.getReplacementTypes()[index]);
26782703
return;
26792704
}
26802705
}

Diff for: lib/Sema/TypeCheckGeneric.cpp

-7
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,6 @@ OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
215215
underlyingGenericParamType = interfaceSignature.getGenericParams()[0];
216216
} else {
217217
opaqueReprs = collectOpaqueReturnTypeReprs(repr);
218-
if (opaqueReprs.size() > 1) {
219-
ctx.Diags.diagnose(repr->getLoc(), diag::more_than_one_opaque_type, repr);
220-
return nullptr;
221-
}
222-
223-
// TODO [OPAQUE SUPPORT]: right now we only allow one structural 'some' type,
224-
// but *very* soon we will allow more than one such type.
225218
SmallVector<GenericTypeParamType *, 2> genericParamTypes;
226219
SmallVector<Requirement, 2> requirements;
227220
for (unsigned i = 0; i < opaqueReprs.size(); ++i) {

Diff for: test/type/opaque.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct Test {
7676
let zingle = {() -> some P in 1 } // expected-error{{'some' types are only implemented}}
7777

7878

79-
func twoOpaqueTypes() -> (some P, some P) { return (1, 2) } // expected-error{{'(some P, some P)' contains multiple 'opaque' types, but only one 'opaque' type is supported}}
79+
func twoOpaqueTypes() -> (some P, some P) { return (1, 2) }
8080
func asArrayElem() -> [some P] { return [1] }
8181

8282
// Invalid positions

Diff for: test/type/opaque_return_structural.swift

+39-9
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,17 @@ class C {}
1212
class D: P, Q { func paul() {}; func d() {} }
1313

1414

15-
// TODO: cases that we should support, but don't yet:
15+
func asUnwrappedOptionalBase() -> (some P)! { return 1 } // expected-warning{{using '!' is not allowed here; treating this as '?' instead}}
1616
//
17-
// WARNING: using '!' is not allowed here; treating this as '?' instead
18-
// func asUnwrappedOptionalBase() -> (some P)! { return 1 }
17+
// FIXME: We should be able to support this
18+
func asHOFRetRet() -> () -> some P { return { 1 } } // expected-error{{cannot convert value of type 'Int' to closure result type 'some P'}}
1919
//
20-
// ERROR: generic parameter 'τ_0_0' could not be inferred
21-
// func asHOFRetRet() -> () -> some P { return { 1 } }
22-
//
23-
// ERROR: function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
24-
// func asHOFRetArg() -> (some P) -> () { return { (x: Int) -> () in } }
20+
func asHOFRetArg() -> (some P) -> () { return { (x: Int) -> () in } } // expected-error{{'some' cannot appear in parameter position in result type '(some P) -> ()'}}
2521
//
2622
// ERROR: 'some' types are only implemented for the declared type of properties and subscripts and the return type of functions
2723
// let x = { () -> some P in return 1 }
2824

29-
func twoOpaqueTypes() -> (some P, some P) { return (1, 2) } // expected-error{{only one 'opaque' type is supported}}
25+
func twoOpaqueTypes() -> (some P, some P) { return (1, 2) }
3026
func asTupleElemBad() -> (P, some Q) { return (1, C()) } // expected-note{{opaque return type declared here}} expected-error{{requires that 'C' conform to 'Q'}}
3127

3228
func asTupleElem() -> (P, some Q) { return (1, 2) }
@@ -96,3 +92,37 @@ typealias Takes<T> = (T) -> Void
9692

9793
// expected-error@+1 {{'some' cannot appear in parameter position in result type 'Takes<some P>' (aka '(some P) -> ()')}}
9894
func indirectOpaqueParameter() -> Takes<some P> {}
95+
96+
struct X<T, U> { }
97+
98+
struct StructuralMethods {
99+
func f1() -> X<(some P)?, [some Q]> {
100+
return X<Int?, [String]>()
101+
}
102+
103+
func f2(cond: Bool) -> X<(some P)?, [some Q]> {
104+
if cond {
105+
return X<Int?, [String]>()
106+
} else {
107+
return X<Int?, [String]>()
108+
}
109+
}
110+
111+
// TODO: Diagnostics here should be more clear about which "some" is the
112+
// problem.
113+
func f3(cond: Bool) -> X<(some P)?, [some Q]> { // expected-error{{function declares an opaque return type 'some P', but the return statements in its body do not have matching underlying types}}
114+
if cond {
115+
return X<String?, [String]>() // expected-note{{return statement has underlying type 'String'}}
116+
} else {
117+
return X<Int?, [String]>() // expected-note{{return statement has underlying type 'Int'}}
118+
}
119+
}
120+
121+
func f4(cond: Bool) -> X<(some P)?, [some Q]> { // expected-error{{function declares an opaque return type 'some Q', but the return statements in its body do not have matching underlying types}}
122+
if cond {
123+
return X<Int?, [String]>() // expected-note{{return statement has underlying type 'String'}}
124+
} else {
125+
return X<Int?, [Int]>() // expected-note{{return statement has underlying type 'Int'}}
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)