Skip to content

Commit 4b46043

Browse files
authored
Merge pull request #29304 from LucianoPAlmeida/port-object-literal-diagnostics
[Diagnostics] Port diagnostics from FailureDiagnosis::visitObjectLiteralExpr
2 parents e9df206 + e598f61 commit 4b46043

10 files changed

+113
-76
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,12 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
10751075
cs, TypeVar->getImpl().getLocator());
10761076
if (cs.recordFix(fix))
10771077
return true;
1078+
} else if (auto *OLE = dyn_cast_or_null<ObjectLiteralExpr>(
1079+
srcLocator->getAnchor())) {
1080+
auto *fix = SpecifyObjectLiteralTypeImport::create(
1081+
cs, TypeVar->getImpl().getLocator());
1082+
if (cs.recordFix(fix))
1083+
return true;
10781084
}
10791085
}
10801086
}

lib/Sema/CSDiag.cpp

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
239239
bool visitTryExpr(TryExpr *E);
240240

241241
bool visitUnresolvedDotExpr(UnresolvedDotExpr *UDE);
242-
bool visitObjectLiteralExpr(ObjectLiteralExpr *E);
243242

244243
bool visitApplyExpr(ApplyExpr *AE);
245244
bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E);
@@ -1722,74 +1721,6 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
17221721
return false;
17231722
}
17241723

1725-
/// When an object literal fails to typecheck because its protocol's
1726-
/// corresponding default type has not been set in the global namespace (e.g.
1727-
/// _ColorLiteralType), suggest that the user import the appropriate module for
1728-
/// the target.
1729-
bool FailureDiagnosis::visitObjectLiteralExpr(ObjectLiteralExpr *E) {
1730-
// Type check the argument first.
1731-
auto protocol = TypeChecker::getLiteralProtocol(CS.getASTContext(), E);
1732-
if (!protocol)
1733-
return false;
1734-
auto constrName =
1735-
TypeChecker::getObjectLiteralConstructorName(CS.getASTContext(), E);
1736-
assert(constrName);
1737-
auto *constr = dyn_cast_or_null<ConstructorDecl>(
1738-
protocol->getSingleRequirement(constrName));
1739-
if (!constr)
1740-
return false;
1741-
auto paramType = TypeChecker::getObjectLiteralParameterType(E, constr);
1742-
if (!typeCheckChildIndependently(
1743-
E->getArg(), paramType, CTP_CallArgument))
1744-
return true;
1745-
1746-
// Conditions for showing this diagnostic:
1747-
// * The object literal protocol's default type is unimplemented
1748-
if (TypeChecker::getDefaultType(protocol, CS.DC))
1749-
return false;
1750-
// * The object literal has no contextual type
1751-
if (CS.getContextualType())
1752-
return false;
1753-
1754-
// Figure out what import to suggest.
1755-
auto &Ctx = CS.getASTContext();
1756-
const auto &target = Ctx.LangOpts.Target;
1757-
StringRef importModule;
1758-
StringRef importDefaultTypeName;
1759-
if (protocol == Ctx.getProtocol(KnownProtocolKind::ExpressibleByColorLiteral)) {
1760-
if (target.isMacOSX()) {
1761-
importModule = "AppKit";
1762-
importDefaultTypeName = "NSColor";
1763-
} else if (target.isiOS() || target.isTvOS()) {
1764-
importModule = "UIKit";
1765-
importDefaultTypeName = "UIColor";
1766-
}
1767-
} else if (protocol == Ctx.getProtocol(
1768-
KnownProtocolKind::ExpressibleByImageLiteral)) {
1769-
if (target.isMacOSX()) {
1770-
importModule = "AppKit";
1771-
importDefaultTypeName = "NSImage";
1772-
} else if (target.isiOS() || target.isTvOS()) {
1773-
importModule = "UIKit";
1774-
importDefaultTypeName = "UIImage";
1775-
}
1776-
} else if (protocol == Ctx.getProtocol(
1777-
KnownProtocolKind::ExpressibleByFileReferenceLiteral)) {
1778-
importModule = "Foundation";
1779-
importDefaultTypeName = "URL";
1780-
}
1781-
1782-
// Emit the diagnostic.
1783-
const auto plainName = E->getLiteralKindPlainName();
1784-
Ctx.Diags.diagnose(E->getLoc(), diag::object_literal_default_type_missing,
1785-
plainName);
1786-
if (!importModule.empty()) {
1787-
Ctx.Diags.diagnose(E->getLoc(), diag::object_literal_resolve_import,
1788-
importModule, importDefaultTypeName, plainName);
1789-
}
1790-
return true;
1791-
}
1792-
17931724
bool FailureDiagnosis::diagnoseMemberFailures(
17941725
Expr *E, Expr *baseExpr, ConstraintKind lookupKind, DeclNameRef memberName,
17951726
FunctionRefKind funcRefKind, ConstraintLocator *locator,

lib/Sema/CSDiagnostics.cpp

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3882,7 +3882,7 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {
38823882

38833883
auto *anchor = getRawAnchor();
38843884
if (!(isa<CallExpr>(anchor) || isa<SubscriptExpr>(anchor) ||
3885-
isa<UnresolvedMemberExpr>(anchor)))
3885+
isa<UnresolvedMemberExpr>(anchor) || isa<ObjectLiteralExpr>(anchor)))
38863886
return false;
38873887

38883888
if (SynthesizedArgs.size() != 1)
@@ -4219,6 +4219,9 @@ MissingArgumentsFailure::getCallInfo(Expr *anchor) const {
42194219
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
42204220
return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(),
42214221
SE->hasTrailingClosure());
4222+
} else if (auto *OLE = dyn_cast<ObjectLiteralExpr>(anchor)) {
4223+
return std::make_tuple(OLE, OLE->getArg(), OLE->getNumArguments(),
4224+
OLE->hasTrailingClosure());
42224225
}
42234226

42244227
return std::make_tuple(nullptr, nullptr, 0, false);
@@ -6038,3 +6041,55 @@ bool UnableToInferClosureReturnType::diagnoseAsError() {
60386041

60396042
return true;
60406043
}
6044+
6045+
static std::pair<StringRef, StringRef>
6046+
getImportModuleAndDefaultType(const ASTContext &ctx, ObjectLiteralExpr *expr) {
6047+
const auto &target = ctx.LangOpts.Target;
6048+
6049+
switch (expr->getLiteralKind()) {
6050+
case ObjectLiteralExpr::colorLiteral: {
6051+
if (target.isMacOSX()) {
6052+
return std::make_pair("AppKit", "NSColor");
6053+
} else if (target.isiOS() || target.isTvOS()) {
6054+
return std::make_pair("UIKit", "UIColor");
6055+
}
6056+
break;
6057+
}
6058+
6059+
case ObjectLiteralExpr::imageLiteral: {
6060+
if (target.isMacOSX()) {
6061+
return std::make_pair("AppKit", "NSImage");
6062+
} else if (target.isiOS() || target.isTvOS()) {
6063+
return std::make_pair("UIKit", "UIImage");
6064+
}
6065+
break;
6066+
}
6067+
6068+
case ObjectLiteralExpr::fileLiteral: {
6069+
return std::make_pair("Foundation", "URL");
6070+
}
6071+
}
6072+
6073+
return std::make_pair("", "");
6074+
}
6075+
6076+
bool UnableToInferProtocolLiteralType::diagnoseAsError() {
6077+
auto &cs = getConstraintSystem();
6078+
auto &ctx = cs.getASTContext();
6079+
auto *expr = cast<ObjectLiteralExpr>(getLocator()->getAnchor());
6080+
6081+
StringRef importModule;
6082+
StringRef importDefaultTypeName;
6083+
std::tie(importModule, importDefaultTypeName) =
6084+
getImportModuleAndDefaultType(ctx, expr);
6085+
6086+
auto plainName = expr->getLiteralKindPlainName();
6087+
emitDiagnostic(expr->getLoc(), diag::object_literal_default_type_missing,
6088+
plainName);
6089+
if (!importModule.empty()) {
6090+
emitDiagnostic(expr->getLoc(), diag::object_literal_resolve_import,
6091+
importModule, importDefaultTypeName, plainName);
6092+
}
6093+
6094+
return true;
6095+
}

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,15 @@ class UnableToInferClosureReturnType final : public FailureDiagnostic {
19261926
bool diagnoseAsError();
19271927
};
19281928

1929+
class UnableToInferProtocolLiteralType final : public FailureDiagnostic {
1930+
public:
1931+
UnableToInferProtocolLiteralType(ConstraintSystem &cs,
1932+
ConstraintLocator *locator)
1933+
: FailureDiagnostic(cs, locator) {}
1934+
1935+
bool diagnoseAsError();
1936+
};
1937+
19291938
} // end namespace constraints
19301939
} // end namespace swift
19311940

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,3 +1168,15 @@ SpecifyClosureReturnType::create(ConstraintSystem &cs,
11681168
ConstraintLocator *locator) {
11691169
return new (cs.getAllocator()) SpecifyClosureReturnType(cs, locator);
11701170
}
1171+
1172+
bool SpecifyObjectLiteralTypeImport::diagnose(bool asNote) const {
1173+
auto &cs = getConstraintSystem();
1174+
UnableToInferProtocolLiteralType failure(cs, getLocator());
1175+
return failure.diagnose(asNote);
1176+
}
1177+
1178+
SpecifyObjectLiteralTypeImport *
1179+
SpecifyObjectLiteralTypeImport::create(ConstraintSystem &cs,
1180+
ConstraintLocator *locator) {
1181+
return new (cs.getAllocator()) SpecifyObjectLiteralTypeImport(cs, locator);
1182+
}

lib/Sema/CSFix.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,12 @@ enum class FixKind : uint8_t {
235235
/// Closure return type has to be explicitly specified because it can't be
236236
/// inferred in current context e.g. because it's a multi-statement closure.
237237
SpecifyClosureReturnType,
238+
239+
/// Object literal type coudn't be infered because the module where
240+
/// the default type that implements the associated literal protocol
241+
/// is declared was not imported.
242+
SpecifyObjectLiteralTypeImport,
243+
238244
};
239245

240246
class ConstraintFix {
@@ -1633,6 +1639,22 @@ class SpecifyClosureReturnType final : public ConstraintFix {
16331639
ConstraintLocator *locator);
16341640
};
16351641

1642+
class SpecifyObjectLiteralTypeImport final : public ConstraintFix {
1643+
SpecifyObjectLiteralTypeImport(ConstraintSystem &cs, ConstraintLocator *locator)
1644+
: ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {}
1645+
1646+
public:
1647+
std::string getName() const {
1648+
return "import required module to gain access to a default literal type";
1649+
}
1650+
1651+
bool diagnose(bool asNote = false) const;
1652+
1653+
static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs,
1654+
ConstraintLocator *locator);
1655+
1656+
};
1657+
16361658
} // end namespace constraints
16371659
} // end namespace swift
16381660

lib/Sema/CSGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,8 @@ namespace {
12771277

12781278
auto tv = CS.createTypeVariable(exprLoc,
12791279
TVO_PrefersSubtypeBinding |
1280-
TVO_CanBindToNoEscape);
1280+
TVO_CanBindToNoEscape |
1281+
TVO_CanBindToHole);
12811282

12821283
CS.addConstraint(ConstraintKind::LiteralConformsTo, tv,
12831284
protocol->getDeclaredType(),

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8739,7 +8739,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
87398739
case FixKind::UseValueTypeOfRawRepresentative:
87408740
case FixKind::ExplicitlyConstructRawRepresentable:
87418741
case FixKind::SpecifyBaseTypeForContextualMember:
8742-
case FixKind::CoerceToCheckedCast: {
8742+
case FixKind::CoerceToCheckedCast:
8743+
case FixKind::SpecifyObjectLiteralTypeImport: {
87438744
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
87448745
}
87458746

test/Sema/object_literals_ios.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct S: _ExpressibleByColorLiteral {
77

88
let y: S = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
99
let y2 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1) // expected-error{{could not infer type of color literal}} expected-note{{import UIKit to use 'UIColor' as the default color literal type}}
10-
let y3 = #colorLiteral(red: 1, bleen: 0, grue: 0, alpha: 1) // expected-error{{cannot convert value of type '(red: Int, bleen: Int, grue: Int, alpha: Int)' to expected argument type '(red: Float, green: Float, blue: Float, alpha: Float)'}}
10+
let y3 = #colorLiteral(red: 1, bleen: 0, grue: 0, alpha: 1) // expected-error{{incorrect argument labels in call (have 'red:bleen:grue:alpha:', expected 'red:green:blue:alpha:')}} expected-error{{could not infer type of color literal}} expected-note{{import AppKit to use 'NSColor' as the default color literal type}}
1111

1212
struct I: _ExpressibleByImageLiteral {
1313
init(imageLiteralResourceName: String) {}

test/Sema/object_literals_osx.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ struct S: _ExpressibleByColorLiteral {
77

88
let y: S = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
99
let y2 = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1) // expected-error{{could not infer type of color literal}} expected-note{{import AppKit to use 'NSColor' as the default color literal type}}
10-
let y3 = #colorLiteral(red: 1, bleen: 0, grue: 0, alpha: 1) // expected-error{{cannot convert value of type '(red: Int, bleen: Int, grue: Int, alpha: Int)' to expected argument type '(red: Float, green: Float, blue: Float, alpha: Float)'}}
10+
let y3 = #colorLiteral(red: 1, bleen: 0, grue: 0, alpha: 1) // expected-error{{incorrect argument labels in call (have 'red:bleen:grue:alpha:', expected 'red:green:blue:alpha:')}} expected-error{{could not infer type of color literal}} expected-note{{import AppKit to use 'NSColor' as the default color literal type}}
1111

1212
struct I: _ExpressibleByImageLiteral {
1313
init(imageLiteralResourceName: String) {}
@@ -23,7 +23,7 @@ struct Path: _ExpressibleByFileReferenceLiteral {
2323
let p1: Path = #fileLiteral(resourceName: "what.txt")
2424
let p2 = #fileLiteral(resourceName: "what.txt") // expected-error{{could not infer type of file reference literal}} expected-note{{import Foundation to use 'URL' as the default file reference literal type}}
2525

26-
let text = #fileLiteral(resourceName: "TextFile.txt").relativeString! // expected-error{{type of expression is ambiguous without more context}}
26+
let text = #fileLiteral(resourceName: "TextFile.txt").relativeString! // expected-error{{could not infer type of file reference literal}} expected-note{{import Foundation to use 'URL' as the default file reference literal type}}
2727

2828
// rdar://problem/49861813
29-
#fileLiteral() // expected-error {{cannot convert value of type '()' to expected argument type '(resourceName: String)'}}
29+
#fileLiteral() // expected-error{{missing argument for parameter 'resourceName' in call}} expected-error{{could not infer type of file reference literal}} expected-note{{import Foundation to use 'URL' as the default file reference literal type}}

0 commit comments

Comments
 (0)