Skip to content

Commit 913a1f5

Browse files
authored
Merge pull request #24383 from xedin/rdar-49582531
[Diagnostics] Improve missing conformance diagnostics for opaque return
2 parents c138770 + caad4a8 commit 913a1f5

File tree

4 files changed

+112
-11
lines changed

4 files changed

+112
-11
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ NOTE(implicit_member_declared_here,none,
4747
"%1 '%0' is implicitly declared", (StringRef, StringRef))
4848
NOTE(extended_type_declared_here,none,
4949
"extended type declared here", ())
50+
NOTE(opaque_return_type_declared_here,none,
51+
"opaque return type declared here", ())
5052

5153
//------------------------------------------------------------------------------
5254
// MARK: Constraint solver diagnostics
@@ -1583,6 +1585,9 @@ ERROR(type_does_not_conform_in_decl_ref,none,
15831585
ERROR(type_does_not_conform_decl_owner,none,
15841586
"%0 %1 requires that %2 conform to %3",
15851587
(DescriptiveDeclKind, DeclName, Type, Type))
1588+
ERROR(type_does_not_conform_in_opaque_return,none,
1589+
"return type of %0 %1 requires that %2 conform to %3",
1590+
(DescriptiveDeclKind, DeclName, Type, Type))
15861591
ERROR(types_not_equal_decl,none,
15871592
"%0 %1 requires the types %2 and %3 be equivalent",
15881593
(DescriptiveDeclKind, DeclName, Type, Type))

lib/Sema/CSDiagnostics.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,25 @@ ValueDecl *RequirementFailure::getDeclRef() const {
155155
auto *anchor = getRawAnchor();
156156
auto *locator = cs.getConstraintLocator(anchor);
157157

158-
if (isFromContextualType()) {
159-
auto type = cs.getContextualType();
158+
// Get a declaration associated with given type (if any).
159+
// This is used to retrieve affected declaration when
160+
// failure is in any way contextual, and declaration can't
161+
// be fetched directly from constraint system.
162+
auto getAffectedDeclFromType = [](Type type) -> ValueDecl * {
160163
assert(type);
161-
auto *alias = dyn_cast<TypeAliasType>(type.getPointer());
162-
return alias ? alias->getDecl() : type->getAnyGeneric();
163-
}
164+
// If problem is related to a typealias, let's point this
165+
// diagnostic directly to its declaration without desugaring.
166+
if (auto *alias = dyn_cast<TypeAliasType>(type.getPointer()))
167+
return alias->getDecl();
168+
169+
if (auto *opaque = type->getAs<OpaqueTypeArchetypeType>())
170+
return opaque->getDecl();
171+
172+
return type->getAnyGeneric();
173+
};
174+
175+
if (isFromContextualType())
176+
return getAffectedDeclFromType(cs.getContextualType());
164177

165178
if (auto *AE = dyn_cast<CallExpr>(anchor)) {
166179
// NOTE: In valid code, the function can only be a TypeExpr
@@ -196,11 +209,7 @@ ValueDecl *RequirementFailure::getDeclRef() const {
196209
if (overload)
197210
return overload->choice.getDecl();
198211

199-
auto ownerType = getOwnerType();
200-
if (auto *NA = dyn_cast<TypeAliasType>(ownerType.getPointer()))
201-
return NA->getDecl();
202-
203-
return ownerType->getAnyGeneric();
212+
return getAffectedDeclFromType(getOwnerType());
204213
}
205214

206215
GenericSignature *RequirementFailure::getSignature(ConstraintLocator *locator) {
@@ -263,6 +272,28 @@ bool RequirementFailure::diagnoseAsError() {
263272
auto lhs = resolveType(getLHS());
264273
auto rhs = resolveType(getRHS());
265274

275+
if (auto *OTD = dyn_cast<OpaqueTypeDecl>(AffectedDecl)) {
276+
auto *namingDecl = OTD->getNamingDecl();
277+
emitDiagnostic(
278+
anchor->getLoc(), diag::type_does_not_conform_in_opaque_return,
279+
namingDecl->getDescriptiveKind(), namingDecl->getFullName(), lhs, rhs);
280+
281+
TypeLoc returnLoc;
282+
if (auto *VD = dyn_cast<VarDecl>(namingDecl)) {
283+
returnLoc = VD->getTypeLoc();
284+
} else if (auto *FD = dyn_cast<FuncDecl>(namingDecl)) {
285+
returnLoc = FD->getBodyResultTypeLoc();
286+
} else if (auto *SD = dyn_cast<SubscriptDecl>(namingDecl)) {
287+
returnLoc = SD->getElementTypeLoc();
288+
}
289+
290+
if (returnLoc.hasLocation()) {
291+
emitDiagnostic(returnLoc.getLoc(), diag::opaque_return_type_declared_here)
292+
.highlight(returnLoc.getSourceRange());
293+
}
294+
return true;
295+
}
296+
266297
if (genericCtx != reqDC && (genericCtx->isChildContextOf(reqDC) ||
267298
isStaticOrInstanceMember(AffectedDecl))) {
268299
auto *NTD = reqDC->getSelfNominalTypeDecl();

lib/Sema/MiscDiagnostics.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2218,6 +2218,9 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
22182218
AbstractFunctionDecl *Implementation;
22192219
OpaqueTypeDecl *OpaqueDecl;
22202220
SmallVector<std::pair<Expr*, Type>, 4> Candidates;
2221+
2222+
bool HasInvalidReturn = false;
2223+
22212224
public:
22222225
OpaqueUnderlyingTypeChecker(TypeChecker &TC,
22232226
AbstractFunctionDecl *Implementation,
@@ -2231,7 +2234,13 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
22312234

22322235
void check() {
22332236
Implementation->getBody()->walk(*this);
2234-
2237+
2238+
// If given function has any invalid returns in the body
2239+
// let's not try to validate the types, since it wouldn't
2240+
// be accurate.
2241+
if (HasInvalidReturn)
2242+
return;
2243+
22352244
// If there are no candidates, then the body has no return statements, and
22362245
// we have nothing to infer the underlying type from.
22372246
if (Candidates.empty()) {
@@ -2310,6 +2319,20 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
23102319
}
23112320
return std::make_pair(false, E);
23122321
}
2322+
2323+
std::pair<bool, Stmt *> walkToStmtPre(Stmt *S) override {
2324+
if (auto *RS = dyn_cast<ReturnStmt>(S)) {
2325+
if (RS->hasResult()) {
2326+
auto resultTy = RS->getResult()->getType();
2327+
// If expression associated with return statement doesn't have
2328+
// a type or type has an error, checking opaque types is going
2329+
// to produce incorrect diagnostics.
2330+
HasInvalidReturn |= resultTy.isNull() || resultTy->hasError();
2331+
}
2332+
}
2333+
2334+
return {true, S};
2335+
}
23132336
};
23142337

23152338
} // end anonymous namespace

test/type/opaque.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,45 @@ struct RedeclarationTest {
314314
subscript(redeclared _: Int) -> some Q { return 0 }
315315
subscript(redeclared _: Int) -> P { return 0 }
316316
}
317+
318+
func diagnose_requirement_failures() {
319+
struct S {
320+
var foo: some P { return S() } // expected-note {{declared here}}
321+
// expected-error@-1 {{return type of property 'foo' requires that 'S' conform to 'P'}}
322+
323+
subscript(_: Int) -> some P { // expected-note {{declared here}}
324+
return S()
325+
// expected-error@-1 {{return type of subscript 'subscript(_:)' requires that 'S' conform to 'P'}}
326+
}
327+
328+
func bar() -> some P { // expected-note {{declared here}}
329+
return S()
330+
// expected-error@-1 {{return type of instance method 'bar()' requires that 'S' conform to 'P'}}
331+
}
332+
333+
static func baz(x: String) -> some P { // expected-note {{declared here}}
334+
return S()
335+
// expected-error@-1 {{return type of static method 'baz(x:)' requires that 'S' conform to 'P'}}
336+
}
337+
}
338+
339+
func fn() -> some P { // expected-note {{declared here}}
340+
return S()
341+
// expected-error@-1 {{return type of local function 'fn()' requires that 'S' conform to 'P'}}
342+
}
343+
}
344+
345+
func global_function_with_requirement_failure() -> some P { // expected-note {{declared here}}
346+
return 42 as Double
347+
// expected-error@-1 {{return type of global function 'global_function_with_requirement_failure()' requires that 'Double' conform to 'P'}}
348+
}
349+
350+
func recursive_func_is_invalid_opaque() {
351+
func rec(x: Int) -> some P {
352+
// expected-error@-1 {{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}}
353+
if x == 0 {
354+
return rec(x: 0)
355+
}
356+
return rec(x: x - 1)
357+
}
358+
}

0 commit comments

Comments
 (0)