Skip to content

Commit 68e09d6

Browse files
[CSFix] Creating object literal module import fix
1 parent 203a2b6 commit 68e09d6

File tree

5 files changed

+120
-2
lines changed

5 files changed

+120
-2
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6038,3 +6038,53 @@ bool UnableToInferClosureReturnType::diagnoseAsError() {
60386038

60396039
return true;
60406040
}
6041+
6042+
static std::tuple<StringRef, StringRef>
6043+
getImportModuleAndDefaultType(const ASTContext &ctx, ProtocolDecl *protocol) {
6044+
const auto &target = ctx.LangOpts.Target;
6045+
if (protocol ==
6046+
ctx.getProtocol(KnownProtocolKind::ExpressibleByColorLiteral)) {
6047+
if (target.isMacOSX()) {
6048+
return std::make_tuple("AppKit", "NSColor");
6049+
} else if (target.isiOS() || target.isTvOS()) {
6050+
return std::make_tuple("UIKit", "UIColor");
6051+
}
6052+
} else if (protocol ==
6053+
ctx.getProtocol(KnownProtocolKind::ExpressibleByImageLiteral)) {
6054+
if (target.isMacOSX()) {
6055+
return std::make_tuple("AppKit", "NSImage");
6056+
} else if (target.isiOS() || target.isTvOS()) {
6057+
return std::make_tuple("UIKit", "UIImage");
6058+
}
6059+
} else if (protocol ==
6060+
ctx.getProtocol(
6061+
KnownProtocolKind::ExpressibleByFileReferenceLiteral)) {
6062+
return std::make_tuple("Foundation", "URL");
6063+
}
6064+
return std::make_tuple("", "");
6065+
}
6066+
6067+
bool UnableToInferProtocolLiteralType::diagnoseAsError() {
6068+
auto *locator = getLocator();
6069+
auto &cs = getConstraintSystem();
6070+
auto *expr = cast<ObjectLiteralExpr>(locator->getAnchor());
6071+
6072+
auto &ctx = cs.getASTContext();
6073+
auto protocol = TypeChecker::getLiteralProtocol(ctx, expr);
6074+
assert(protocol);
6075+
auto plainName = expr->getLiteralKindPlainName();
6076+
6077+
StringRef importModule;
6078+
StringRef importDefaultTypeName;
6079+
std::tie(importModule, importDefaultTypeName) =
6080+
getImportModuleAndDefaultType(ctx, protocol);
6081+
6082+
emitDiagnostic(expr->getLoc(), diag::object_literal_default_type_missing,
6083+
plainName);
6084+
if (!importModule.empty()) {
6085+
emitDiagnostic(expr->getLoc(), diag::object_literal_resolve_import,
6086+
importModule, importDefaultTypeName, plainName);
6087+
}
6088+
6089+
return true;
6090+
}

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: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,3 +1168,28 @@ 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::attempt(ConstraintSystem &cs,
1180+
ConstraintLocator *locator) {
1181+
// FIXME: ArgumentMismatchFailure is currently used from CSDiag, meaning
1182+
// we could endup emiting this diagnostic duplicated.
1183+
if (cs.Options.contains(ConstraintSystemFlags::SubExpressionDiagnostics))
1184+
return nullptr;
1185+
1186+
auto *anchor = locator->getAnchor();
1187+
if (!isa<ObjectLiteralExpr>(anchor))
1188+
return nullptr;
1189+
1190+
// * The object literal has no contextual type
1191+
if (cs.getContextualType())
1192+
return nullptr;
1193+
1194+
return new (cs.getAllocator()) SpecifyObjectLiteralTypeImport(cs, locator);
1195+
}

lib/Sema/CSFix.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ 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 it's
240+
/// protocol type was not imported.
241+
SpecifyObjectLiteralTypeImport,
242+
238243
};
239244

240245
class ConstraintFix {
@@ -1633,6 +1638,22 @@ class SpecifyClosureReturnType final : public ConstraintFix {
16331638
ConstraintLocator *locator);
16341639
};
16351640

1641+
class SpecifyObjectLiteralTypeImport final : public ConstraintFix {
1642+
SpecifyObjectLiteralTypeImport(ConstraintSystem &cs, ConstraintLocator *locator)
1643+
: ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {}
1644+
1645+
public:
1646+
std::string getName() const {
1647+
return "specify object literal protocol type import";
1648+
}
1649+
1650+
bool diagnose(bool asNote = false) const;
1651+
1652+
static SpecifyObjectLiteralTypeImport *attempt(ConstraintSystem &cs,
1653+
ConstraintLocator *locator);
1654+
1655+
};
1656+
16361657
} // end namespace constraints
16371658
} // end namespace swift
16381659

lib/Sema/CSSimplify.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,18 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
10271027
argsWithLabels, params, paramInfo, argInfo->HasTrailingClosure,
10281028
cs.shouldAttemptFixes(), listener, parameterBindings))
10291029
return cs.getTypeMatchFailure(locator);
1030-
1030+
1031+
if (!callee) {
1032+
// If we couldn't find a callee, diagnose and maybe suggest
1033+
// import a module.
1034+
if (cs.shouldAttemptFixes()) {
1035+
if (auto *fix = SpecifyObjectLiteralTypeImport::attempt(cs, loc)) {
1036+
if (cs.recordFix(fix))
1037+
return cs.getTypeMatchFailure(locator);
1038+
}
1039+
}
1040+
}
1041+
10311042
auto extraArguments = listener.getExtraneousArguments();
10321043
if (!extraArguments.empty()) {
10331044
if (RemoveExtraneousArguments::isMinMaxNameShadowing(cs, locator))
@@ -1047,6 +1058,7 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
10471058
return cs.getTypeMatchFailure(locator);
10481059
}
10491060
}
1061+
10501062
}
10511063

10521064
// If this application is part of an operator, then we allow an implicit
@@ -8739,7 +8751,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
87398751
case FixKind::UseValueTypeOfRawRepresentative:
87408752
case FixKind::ExplicitlyConstructRawRepresentable:
87418753
case FixKind::SpecifyBaseTypeForContextualMember:
8742-
case FixKind::CoerceToCheckedCast: {
8754+
case FixKind::CoerceToCheckedCast:
8755+
case FixKind::SpecifyObjectLiteralTypeImport: {
87438756
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
87448757
}
87458758

0 commit comments

Comments
 (0)