diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index a3a15f49035ca..f7a4ac736135f 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -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( + srcLocator->getAnchor())) { + auto *fix = SpecifyObjectLiteralTypeImport::create( + cs, TypeVar->getImpl().getLocator()); + if (cs.recordFix(fix)) + return true; } } } diff --git a/lib/Sema/CSDiag.cpp b/lib/Sema/CSDiag.cpp index acb50536c105d..96ee39f27578a 100644 --- a/lib/Sema/CSDiag.cpp +++ b/lib/Sema/CSDiag.cpp @@ -239,7 +239,6 @@ class FailureDiagnosis :public ASTVisitor{ bool visitTryExpr(TryExpr *E); bool visitUnresolvedDotExpr(UnresolvedDotExpr *UDE); - bool visitObjectLiteralExpr(ObjectLiteralExpr *E); bool visitApplyExpr(ApplyExpr *AE); bool visitRebindSelfInConstructorExpr(RebindSelfInConstructorExpr *E); @@ -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( - 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, diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index dbe3a5b7dc0f4..f1b0e5d3eef03 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -3882,7 +3882,7 @@ bool MissingArgumentsFailure::diagnoseSingleMissingArgument() const { auto *anchor = getRawAnchor(); if (!(isa(anchor) || isa(anchor) || - isa(anchor))) + isa(anchor) || isa(anchor))) return false; if (SynthesizedArgs.size() != 1) @@ -4219,6 +4219,9 @@ MissingArgumentsFailure::getCallInfo(Expr *anchor) const { } else if (auto *SE = dyn_cast(anchor)) { return std::make_tuple(SE, SE->getIndex(), SE->getNumArguments(), SE->hasTrailingClosure()); + } else if (auto *OLE = dyn_cast(anchor)) { + return std::make_tuple(OLE, OLE->getArg(), OLE->getNumArguments(), + OLE->hasTrailingClosure()); } return std::make_tuple(nullptr, nullptr, 0, false); @@ -6038,3 +6041,55 @@ bool UnableToInferClosureReturnType::diagnoseAsError() { return true; } + +static std::pair +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(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; +} diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index a94be81e1c36a..cbe28453808e1 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -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 diff --git a/lib/Sema/CSFix.cpp b/lib/Sema/CSFix.cpp index 21abf55ddd143..e15edfc72284e 100644 --- a/lib/Sema/CSFix.cpp +++ b/lib/Sema/CSFix.cpp @@ -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); +} diff --git a/lib/Sema/CSFix.h b/lib/Sema/CSFix.h index d8550f6ef09a9..05959c8ddbaf4 100644 --- a/lib/Sema/CSFix.h +++ b/lib/Sema/CSFix.h @@ -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 { @@ -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 diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 259ced6a8037d..7078c4cc45af1 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -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(), diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index aa4b80319b932..6f5a94ca3c851 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -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; } diff --git a/test/Sema/object_literals_ios.swift b/test/Sema/object_literals_ios.swift index 7585a96d0122b..225d7a165df0f 100644 --- a/test/Sema/object_literals_ios.swift +++ b/test/Sema/object_literals_ios.swift @@ -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) {} diff --git a/test/Sema/object_literals_osx.swift b/test/Sema/object_literals_osx.swift index 965dd8e1ca597..b49c28989f9bd 100644 --- a/test/Sema/object_literals_osx.swift +++ b/test/Sema/object_literals_osx.swift @@ -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) {} @@ -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}}