Skip to content

[Diagnostics] Port diagnostics from FailureDiagnosis::visitObjectLiteralExpr #29304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,12 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
cs, TypeVar->getImpl().getLocator());
if (cs.recordFix(fix))
return true;
} else if (auto *OLE = dyn_cast_or_null<ObjectLiteralExpr>(
srcLocator->getAnchor())) {
auto *fix = SpecifyObjectLiteralTypeImport::create(
cs, TypeVar->getImpl().getLocator());
if (cs.recordFix(fix))
return true;
}
}
}
Expand Down
69 changes: 0 additions & 69 deletions lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
bool visitTryExpr(TryExpr *E);

bool visitUnresolvedDotExpr(UnresolvedDotExpr *UDE);
bool visitObjectLiteralExpr(ObjectLiteralExpr *E);

bool visitApplyExpr(ApplyExpr *AE);
bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E);
Expand Down Expand Up @@ -1722,74 +1721,6 @@ visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E) {
return false;
}

/// When an object literal fails to typecheck because its protocol's
/// corresponding default type has not been set in the global namespace (e.g.
/// _ColorLiteralType), suggest that the user import the appropriate module for
/// the target.
bool FailureDiagnosis::visitObjectLiteralExpr(ObjectLiteralExpr *E) {
// Type check the argument first.
auto protocol = TypeChecker::getLiteralProtocol(CS.getASTContext(), E);
if (!protocol)
return false;
auto constrName =
TypeChecker::getObjectLiteralConstructorName(CS.getASTContext(), E);
assert(constrName);
auto *constr = dyn_cast_or_null<ConstructorDecl>(
protocol->getSingleRequirement(constrName));
if (!constr)
return false;
auto paramType = TypeChecker::getObjectLiteralParameterType(E, constr);
if (!typeCheckChildIndependently(
E->getArg(), paramType, CTP_CallArgument))
return true;

// Conditions for showing this diagnostic:
// * The object literal protocol's default type is unimplemented
if (TypeChecker::getDefaultType(protocol, CS.DC))
return false;
// * The object literal has no contextual type
if (CS.getContextualType())
return false;

// Figure out what import to suggest.
auto &Ctx = CS.getASTContext();
const auto &target = Ctx.LangOpts.Target;
StringRef importModule;
StringRef importDefaultTypeName;
if (protocol == Ctx.getProtocol(KnownProtocolKind::ExpressibleByColorLiteral)) {
if (target.isMacOSX()) {
importModule = "AppKit";
importDefaultTypeName = "NSColor";
} else if (target.isiOS() || target.isTvOS()) {
importModule = "UIKit";
importDefaultTypeName = "UIColor";
}
} else if (protocol == Ctx.getProtocol(
KnownProtocolKind::ExpressibleByImageLiteral)) {
if (target.isMacOSX()) {
importModule = "AppKit";
importDefaultTypeName = "NSImage";
} else if (target.isiOS() || target.isTvOS()) {
importModule = "UIKit";
importDefaultTypeName = "UIImage";
}
} else if (protocol == Ctx.getProtocol(
KnownProtocolKind::ExpressibleByFileReferenceLiteral)) {
importModule = "Foundation";
importDefaultTypeName = "URL";
}

// Emit the diagnostic.
const auto plainName = E->getLiteralKindPlainName();
Ctx.Diags.diagnose(E->getLoc(), diag::object_literal_default_type_missing,
plainName);
if (!importModule.empty()) {
Ctx.Diags.diagnose(E->getLoc(), diag::object_literal_resolve_import,
importModule, importDefaultTypeName, plainName);
}
return true;
}

bool FailureDiagnosis::diagnoseMemberFailures(
Expr *E, Expr *baseExpr, ConstraintKind lookupKind, DeclNameRef memberName,
FunctionRefKind funcRefKind, ConstraintLocator *locator,
Expand Down
57 changes: 56 additions & 1 deletion lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3882,7 +3882,7 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const {

auto *anchor = getRawAnchor();
if (!(isa<CallExpr>(anchor) || isa<SubscriptExpr>(anchor) ||
isa<UnresolvedMemberExpr>(anchor)))
isa<UnresolvedMemberExpr>(anchor) || isa<ObjectLiteralExpr>(anchor)))
return false;

if (SynthesizedArgs.size() != 1)
Expand Down Expand Up @@ -4219,6 +4219,9 @@ MissingArgumentsFailure::getCallInfo(Expr *anchor) const {
} else if (auto *SE = dyn_cast<SubscriptExpr>(anchor)) {
return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(),
SE->hasTrailingClosure());
} else if (auto *OLE = dyn_cast<ObjectLiteralExpr>(anchor)) {
return std::make_tuple(OLE, OLE->getArg(), OLE->getNumArguments(),
OLE->hasTrailingClosure());
}

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

return true;
}

static std::pair<StringRef, StringRef>
getImportModuleAndDefaultType(const ASTContext &ctx, ObjectLiteralExpr *expr) {
const auto &target = ctx.LangOpts.Target;

switch (expr->getLiteralKind()) {
case ObjectLiteralExpr::colorLiteral: {
if (target.isMacOSX()) {
return std::make_pair("AppKit", "NSColor");
} else if (target.isiOS() || target.isTvOS()) {
return std::make_pair("UIKit", "UIColor");
}
break;
}

case ObjectLiteralExpr::imageLiteral: {
if (target.isMacOSX()) {
return std::make_pair("AppKit", "NSImage");
} else if (target.isiOS() || target.isTvOS()) {
return std::make_pair("UIKit", "UIImage");
}
break;
}

case ObjectLiteralExpr::fileLiteral: {
return std::make_pair("Foundation", "URL");
}
}

return std::make_pair("", "");
}

bool UnableToInferProtocolLiteralType::diagnoseAsError() {
auto &cs = getConstraintSystem();
auto &ctx = cs.getASTContext();
auto *expr = cast<ObjectLiteralExpr>(getLocator()->getAnchor());

StringRef importModule;
StringRef importDefaultTypeName;
std::tie(importModule, importDefaultTypeName) =
getImportModuleAndDefaultType(ctx, expr);

auto plainName = expr->getLiteralKindPlainName();
emitDiagnostic(expr->getLoc(), diag::object_literal_default_type_missing,
plainName);
if (!importModule.empty()) {
emitDiagnostic(expr->getLoc(), diag::object_literal_resolve_import,
importModule, importDefaultTypeName, plainName);
}

return true;
}
9 changes: 9 additions & 0 deletions lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -1926,6 +1926,15 @@ class UnableToInferClosureReturnType final : public FailureDiagnostic {
bool diagnoseAsError();
};

class UnableToInferProtocolLiteralType final : public FailureDiagnostic {
public:
UnableToInferProtocolLiteralType(ConstraintSystem &cs,
ConstraintLocator *locator)
: FailureDiagnostic(cs, locator) {}

bool diagnoseAsError();
};

} // end namespace constraints
} // end namespace swift

Expand Down
12 changes: 12 additions & 0 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,3 +1168,15 @@ SpecifyClosureReturnType::create(ConstraintSystem &cs,
ConstraintLocator *locator) {
return new (cs.getAllocator()) SpecifyClosureReturnType(cs, locator);
}

bool SpecifyObjectLiteralTypeImport::diagnose(bool asNote) const {
auto &cs = getConstraintSystem();
UnableToInferProtocolLiteralType failure(cs, getLocator());
return failure.diagnose(asNote);
}

SpecifyObjectLiteralTypeImport *
SpecifyObjectLiteralTypeImport::create(ConstraintSystem &cs,
ConstraintLocator *locator) {
return new (cs.getAllocator()) SpecifyObjectLiteralTypeImport(cs, locator);
}
22 changes: 22 additions & 0 deletions lib/Sema/CSFix.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ enum class FixKind : uint8_t {
/// Closure return type has to be explicitly specified because it can't be
/// inferred in current context e.g. because it's a multi-statement closure.
SpecifyClosureReturnType,

/// Object literal type coudn't be infered because the module where
/// the default type that implements the associated literal protocol
/// is declared was not imported.
SpecifyObjectLiteralTypeImport,

};

class ConstraintFix {
Expand Down Expand Up @@ -1633,6 +1639,22 @@ class SpecifyClosureReturnType final : public ConstraintFix {
ConstraintLocator *locator);
};

class SpecifyObjectLiteralTypeImport final : public ConstraintFix {
SpecifyObjectLiteralTypeImport(ConstraintSystem &cs, ConstraintLocator *locator)
: ConstraintFix(cs, FixKind::SpecifyObjectLiteralTypeImport, locator) {}

public:
std::string getName() const {
return "import required module to gain access to a default literal type";
}

bool diagnose(bool asNote = false) const;

static SpecifyObjectLiteralTypeImport *create(ConstraintSystem &cs,
ConstraintLocator *locator);

};

} // end namespace constraints
} // end namespace swift

Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,8 @@ namespace {

auto tv = CS.createTypeVariable(exprLoc,
TVO_PrefersSubtypeBinding |
TVO_CanBindToNoEscape);
TVO_CanBindToNoEscape |
TVO_CanBindToHole);

CS.addConstraint(ConstraintKind::LiteralConformsTo, tv,
protocol->getDeclaredType(),
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8739,7 +8739,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
case FixKind::UseValueTypeOfRawRepresentative:
case FixKind::ExplicitlyConstructRawRepresentable:
case FixKind::SpecifyBaseTypeForContextualMember:
case FixKind::CoerceToCheckedCast: {
case FixKind::CoerceToCheckedCast:
case FixKind::SpecifyObjectLiteralTypeImport: {
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
}

Expand Down
2 changes: 1 addition & 1 deletion test/Sema/object_literals_ios.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct S: _ExpressibleByColorLiteral {

let y: S = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
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}}
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)'}}
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}}

struct I: _ExpressibleByImageLiteral {
init(imageLiteralResourceName: String) {}
Expand Down
6 changes: 3 additions & 3 deletions test/Sema/object_literals_osx.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ struct S: _ExpressibleByColorLiteral {

let y: S = #colorLiteral(red: 1, green: 0, blue: 0, alpha: 1)
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}}
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)'}}
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}}

struct I: _ExpressibleByImageLiteral {
init(imageLiteralResourceName: String) {}
Expand All @@ -23,7 +23,7 @@ struct Path: _ExpressibleByFileReferenceLiteral {
let p1: Path = #fileLiteral(resourceName: "what.txt")
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}}

let text = #fileLiteral(resourceName: "TextFile.txt").relativeString! // expected-error{{type of expression is ambiguous without more context}}
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}}

// rdar://problem/49861813
#fileLiteral() // expected-error {{cannot convert value of type '()' to expected argument type '(resourceName: String)'}}
#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}}