| //===--- CSSimplify.cpp - Constraint Simplification -----------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements simplifications of constraints within the constraint |
| // system. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "ConstraintSystem.h" |
| #include "swift/Basic/StringExtras.h" |
| #include "swift/ClangImporter/ClangModule.h" |
| |
| using namespace swift; |
| using namespace constraints; |
| |
| MatchCallArgumentListener::~MatchCallArgumentListener() { } |
| |
| void MatchCallArgumentListener::extraArgument(unsigned argIdx) { } |
| |
| void MatchCallArgumentListener::missingArgument(unsigned paramIdx) { } |
| |
| void MatchCallArgumentListener::outOfOrderArgument(unsigned argIdx, |
| unsigned prevArgIdx) { |
| } |
| |
| bool MatchCallArgumentListener::relabelArguments(ArrayRef<Identifier> newNames){ |
| return true; |
| } |
| |
| /// Produce a score (smaller is better) comparing a parameter name and |
| /// potentially-typo'd argument name. |
| /// |
| /// \param paramName The name of the parameter. |
| /// \param argName The name of the argument. |
| /// \param maxScore The maximum score permitted by this comparison, or |
| /// 0 if there is no limit. |
| /// |
| /// \returns the score, if it is good enough to even consider this a match. |
| /// Otherwise, an empty optional. |
| /// |
| static Optional<unsigned> scoreParamAndArgNameTypo(StringRef paramName, |
| StringRef argName, |
| unsigned maxScore) { |
| using namespace camel_case; |
| |
| // Compute the edit distance. |
| unsigned dist = argName.edit_distance(paramName, /*AllowReplacements=*/true, |
| /*MaxEditDistance=*/maxScore); |
| |
| // If the edit distance would be too long, we're done. |
| if (maxScore != 0 && dist > maxScore) |
| return None; |
| |
| // The distance can be zero due to the "with" transformation above. |
| if (dist == 0) |
| return 1; |
| |
| // Only allow about one typo for every two properly-typed characters, which |
| // prevents completely-wacky suggestions in many cases. |
| if (dist > (argName.size() + 1) / 3) |
| return None; |
| |
| return dist; |
| } |
| |
| SmallVector<CallArgParam, 4> constraints::decomposeArgParamType(Type type) { |
| SmallVector<CallArgParam, 4> result; |
| switch (type->getKind()) { |
| case TypeKind::Tuple: |
| for (const auto &elt : cast<TupleType>(type.getPointer())->getElements()) { |
| CallArgParam argParam; |
| argParam.Ty = elt.isVararg() ? elt.getVarargBaseTy() : elt.getType(); |
| argParam.Label = elt.getName(); |
| argParam.HasDefaultArgument |
| = elt.getDefaultArgKind() != DefaultArgumentKind::None; |
| argParam.Variadic = elt.isVararg(); |
| result.push_back(argParam); |
| } |
| break; |
| |
| case TypeKind::Paren: { |
| CallArgParam argParam; |
| argParam.Ty = cast<ParenType>(type.getPointer())->getUnderlyingType(); |
| result.push_back(argParam); |
| break; |
| } |
| |
| default: { |
| CallArgParam argParam; |
| argParam.Ty = type; |
| result.push_back(argParam); |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| /// Turn a param list into a symbolic and printable representation that does not |
| /// include the types, something like (_:, b:, c:) |
| std::string constraints::getParamListAsString(ArrayRef<CallArgParam> params){ |
| std::string result = "("; |
| |
| bool isFirst = true; |
| for (auto ¶m : params) { |
| if (isFirst) |
| isFirst = false; |
| else |
| result += ", "; |
| |
| if (param.hasLabel()) |
| result += param.Label.str(); |
| else |
| result += "_"; |
| result += ":"; |
| } |
| |
| |
| result += ')'; |
| return result; |
| } |
| |
| |
| |
| bool constraints:: |
| matchCallArguments(ArrayRef<CallArgParam> args, |
| ArrayRef<CallArgParam> params, |
| bool hasTrailingClosure, |
| bool allowFixes, |
| MatchCallArgumentListener &listener, |
| SmallVectorImpl<ParamBinding> ¶meterBindings) { |
| // Keep track of the parameter we're matching and what argument indices |
| // got bound to each parameter. |
| unsigned paramIdx, numParams = params.size(); |
| parameterBindings.clear(); |
| parameterBindings.resize(numParams); |
| |
| // Keep track of which arguments we have claimed from the argument tuple. |
| unsigned nextArgIdx = 0, numArgs = args.size(); |
| SmallVector<bool, 4> claimedArgs(numArgs, false); |
| SmallVector<Identifier, 4> actualArgNames; |
| unsigned numClaimedArgs = 0; |
| |
| // Indicates whether any of the arguments are potentially out-of-order, |
| // requiring further checking at the end. |
| bool potentiallyOutOfOrder = false; |
| |
| // Local function that claims the argument at \c argNumber, returning the |
| // index of the claimed argument. This is primarily a helper for |
| // \c claimNextNamed. |
| auto claim = [&](Identifier expectedName, unsigned argNumber, |
| bool ignoreNameClash = false) -> unsigned { |
| // Make sure we can claim this argument. |
| assert(argNumber != numArgs && "Must have a valid index to claim"); |
| assert(!claimedArgs[argNumber] && "Argument already claimed"); |
| |
| if (!actualArgNames.empty()) { |
| // We're recording argument names; record this one. |
| actualArgNames[argNumber] = expectedName; |
| } else if (args[argNumber].Label != expectedName && !ignoreNameClash) { |
| // We have an argument name mismatch. Start recording argument names. |
| actualArgNames.resize(numArgs); |
| |
| // Figure out previous argument names from the parameter bindings. |
| for (unsigned i = 0; i != numParams; ++i) { |
| const auto ¶m = params[i]; |
| bool firstArg = true; |
| |
| for (auto argIdx : parameterBindings[i]) { |
| actualArgNames[argIdx] = firstArg ? param.Label : Identifier(); |
| firstArg = false; |
| } |
| } |
| |
| // Record this argument name. |
| actualArgNames[argNumber] = expectedName; |
| } |
| |
| claimedArgs[argNumber] = true; |
| ++numClaimedArgs; |
| return argNumber; |
| }; |
| |
| // Local function that skips over any claimed arguments. |
| auto skipClaimedArgs = [&]() { |
| while (nextArgIdx != numArgs && claimedArgs[nextArgIdx]) |
| ++nextArgIdx; |
| }; |
| |
| // Local function that retrieves the next unclaimed argument with the given |
| // name (which may be empty). This routine claims the argument. |
| auto claimNextNamed |
| = [&](Identifier name, bool ignoreNameMismatch) -> Optional<unsigned> { |
| // Skip over any claimed arguments. |
| skipClaimedArgs(); |
| |
| // If we've claimed all of the arguments, there's nothing more to do. |
| if (numClaimedArgs == numArgs) |
| return None; |
| |
| // When the expected name is empty, we claim the next argument if it has |
| // no name. |
| if (name.empty()) { |
| // Nothing to claim. |
| if (nextArgIdx == numArgs || |
| claimedArgs[nextArgIdx] || |
| (args[nextArgIdx].hasLabel() && !ignoreNameMismatch)) |
| return None; |
| |
| return claim(name, nextArgIdx); |
| } |
| |
| // If the name matches, claim this argument. |
| if (nextArgIdx != numArgs && |
| (ignoreNameMismatch || args[nextArgIdx].Label == name)) { |
| return claim(name, nextArgIdx); |
| } |
| |
| // The name didn't match. Go hunting for an unclaimed argument whose name |
| // does match. |
| Optional<unsigned> claimedWithSameName; |
| for (unsigned i = nextArgIdx; i != numArgs; ++i) { |
| // Skip arguments where the name doesn't match. |
| if (args[i].Label != name) |
| continue; |
| |
| // Skip claimed arguments. |
| if (claimedArgs[i]) { |
| // Note that we have already claimed an argument with the same name. |
| if (!claimedWithSameName) |
| claimedWithSameName = i; |
| continue; |
| } |
| |
| // We found a match. If the match wasn't the next one, we have |
| // potentially out of order arguments. |
| if (i != nextArgIdx) |
| potentiallyOutOfOrder = true; |
| |
| // Claim it. |
| return claim(name, i); |
| } |
| |
| // If we're not supposed to attempt any fixes, we're done. |
| if (!allowFixes) |
| return None; |
| |
| // Several things could have gone wrong here, and we'll check for each |
| // of them at some point: |
| // - The keyword argument might be redundant, in which case we can point |
| // out the issue. |
| // - The argument might be unnamed, in which case we try to fix the |
| // problem by adding the name. |
| // - The keyword argument might be a typo for an actual argument name, in |
| // which case we should find the closest match to correct to. |
| |
| // Redundant keyword arguments. |
| if (claimedWithSameName) { |
| // FIXME: We can provide better diagnostics here. |
| return None; |
| } |
| |
| // Missing a keyword argument name. |
| if (nextArgIdx != numArgs && !args[nextArgIdx].hasLabel()) { |
| // Claim the next argument. |
| return claim(name, nextArgIdx); |
| } |
| |
| // Typo correction is handled in a later pass. |
| return None; |
| }; |
| |
| // Local function that attempts to bind the given parameter to arguments in |
| // the list. |
| bool haveUnfulfilledParams = false; |
| auto bindNextParameter = [&](bool ignoreNameMismatch) { |
| const auto ¶m = params[paramIdx]; |
| |
| // Handle variadic parameters. |
| if (param.Variadic) { |
| // Claim the next argument with the name of this parameter. |
| auto claimed = claimNextNamed(param.Label, ignoreNameMismatch); |
| |
| // If there was no such argument, leave the argument unf |
| if (!claimed) { |
| haveUnfulfilledParams = true; |
| return; |
| } |
| |
| // Record the first argument for the variadic. |
| parameterBindings[paramIdx].push_back(*claimed); |
| |
| // Claim any additional unnamed arguments. |
| while ((claimed = claimNextNamed(Identifier(), false))) { |
| parameterBindings[paramIdx].push_back(*claimed); |
| } |
| |
| skipClaimedArgs(); |
| return; |
| } |
| |
| // Try to claim an argument for this parameter. |
| if (auto claimed = claimNextNamed(param.Label, ignoreNameMismatch)) { |
| parameterBindings[paramIdx].push_back(*claimed); |
| skipClaimedArgs(); |
| return; |
| } |
| |
| // There was no argument to claim. Leave the argument unfulfilled. |
| haveUnfulfilledParams = true; |
| }; |
| |
| // If we have a trailing closure, it maps to the last parameter. |
| if (hasTrailingClosure && numParams > 0) { |
| claimedArgs[numArgs-1] = true; |
| ++numClaimedArgs; |
| parameterBindings[numParams-1].push_back(numArgs-1); |
| } |
| |
| // Mark through the parameters, binding them to their arguments. |
| for (paramIdx = 0; paramIdx != numParams; ++paramIdx) { |
| if (parameterBindings[paramIdx].empty()) |
| bindNextParameter(false); |
| } |
| |
| // If we have any unclaimed arguments, complain about those. |
| if (numClaimedArgs != numArgs) { |
| |
| // Find all of the named, unclaimed arguments. |
| llvm::SmallVector<unsigned, 4> unclaimedNamedArgs; |
| for (nextArgIdx = 0; skipClaimedArgs(), nextArgIdx != numArgs; |
| ++nextArgIdx) { |
| if (args[nextArgIdx].hasLabel()) |
| unclaimedNamedArgs.push_back(nextArgIdx); |
| } |
| |
| if (!unclaimedNamedArgs.empty()) { |
| // Find all of the named, unfulfilled parameters. |
| llvm::SmallVector<unsigned, 4> unfulfilledNamedParams; |
| bool hasUnfulfilledUnnamedParams = false; |
| for (paramIdx = 0; paramIdx != numParams; ++paramIdx ) { |
| if (parameterBindings[paramIdx].empty()) { |
| if (params[paramIdx].hasLabel()) |
| unfulfilledNamedParams.push_back(paramIdx); |
| else |
| hasUnfulfilledUnnamedParams = true; |
| } |
| } |
| |
| if (!unfulfilledNamedParams.empty()) { |
| // Use typo correction to find the best matches. |
| // FIXME: There is undoubtedly a good dynamic-programming algorithm |
| // to find the best assignment here. |
| for (auto argIdx : unclaimedNamedArgs) { |
| auto argName = args[argIdx].Label; |
| |
| // Find the closest matching unfulfilled named parameter. |
| unsigned bestScore = 0; |
| unsigned best = 0; |
| for (unsigned i = 0, n = unfulfilledNamedParams.size(); i != n; ++i) { |
| unsigned param = unfulfilledNamedParams[i]; |
| auto paramName = params[param].Label; |
| |
| if (auto score = scoreParamAndArgNameTypo(paramName.str(), |
| argName.str(), |
| bestScore)) { |
| if (*score < bestScore || bestScore == 0) { |
| bestScore = *score; |
| best = i; |
| } |
| } |
| } |
| |
| // If we found a parameter to fulfill, do it. |
| if (bestScore > 0) { |
| // Bind this parameter to the argument. |
| nextArgIdx = argIdx; |
| paramIdx = unfulfilledNamedParams[best]; |
| bindNextParameter(true); |
| |
| // Erase this parameter from the list of unfulfilled named |
| // parameters, so we don't try to fulfill it again. |
| unfulfilledNamedParams.erase(unfulfilledNamedParams.begin() + best); |
| if (unfulfilledNamedParams.empty()) |
| break; |
| } |
| } |
| |
| // Update haveUnfulfilledParams, because we may have fulfilled some |
| // parameters above. |
| haveUnfulfilledParams = hasUnfulfilledUnnamedParams || |
| !unfulfilledNamedParams.empty(); |
| } |
| } |
| |
| // Find all of the unfulfilled parameters, and match them up |
| // semi-positionally. |
| if (numClaimedArgs != numArgs) { |
| // Restart at the first argument/parameter. |
| nextArgIdx = 0; |
| skipClaimedArgs(); |
| haveUnfulfilledParams = false; |
| for (paramIdx = 0; paramIdx != numParams; ++paramIdx) { |
| // Skip fulfilled parameters. |
| if (!parameterBindings[paramIdx].empty()) |
| continue; |
| |
| bindNextParameter(true); |
| } |
| } |
| |
| // If we still haven't claimed all of the arguments, fail. |
| if (numClaimedArgs != numArgs) { |
| nextArgIdx = 0; |
| skipClaimedArgs(); |
| listener.extraArgument(nextArgIdx); |
| return true; |
| } |
| |
| // FIXME: If we had the actual parameters and knew the body names, those |
| // matches would be best. |
| potentiallyOutOfOrder = true; |
| } |
| |
| // If we have any unfulfilled parameters, check them now. |
| if (haveUnfulfilledParams) { |
| for (paramIdx = 0; paramIdx != numParams; ++paramIdx) { |
| // If we have a binding for this parameter, we're done. |
| if (!parameterBindings[paramIdx].empty()) |
| continue; |
| |
| const auto ¶m = params[paramIdx]; |
| |
| // Variadic parameters can be unfulfilled. |
| if (param.Variadic) |
| continue; |
| |
| // Parameters with defaults can be unfulfilled. |
| if (param.HasDefaultArgument) |
| continue; |
| |
| listener.missingArgument(paramIdx); |
| return true; |
| } |
| } |
| |
| // If any arguments were provided out-of-order, check whether we have |
| // violated any of the reordering rules. |
| if (potentiallyOutOfOrder) { |
| // Build a mapping from arguments to parameters. |
| SmallVector<unsigned, 4> argumentBindings(numArgs); |
| for(paramIdx = 0; paramIdx != numParams; ++paramIdx) { |
| for (auto argIdx : parameterBindings[paramIdx]) |
| argumentBindings[argIdx] = paramIdx; |
| } |
| |
| // Walk through the arguments, determining if any were bound to parameters |
| // out-of-order where it is not permitted. |
| unsigned prevParamIdx = argumentBindings[0]; |
| for (unsigned argIdx = 1; argIdx != numArgs; ++argIdx) { |
| unsigned paramIdx = argumentBindings[argIdx]; |
| |
| // If this argument binds to the same parameter as the previous one or to |
| // a later parameter, just update the parameter index. |
| if (paramIdx >= prevParamIdx) { |
| prevParamIdx = paramIdx; |
| continue; |
| } |
| |
| // The argument binds to a parameter that comes earlier than the |
| // previous argument. This is fine so long as this parameter and all of |
| // those parameters up to (and including) the previously-bound parameter |
| // are either variadic or have a default argument. |
| for (unsigned i = paramIdx; i != prevParamIdx + 1; ++i) { |
| const auto ¶m = params[i]; |
| if (param.Variadic || param.HasDefaultArgument) |
| continue; |
| |
| unsigned prevArgIdx = parameterBindings[prevParamIdx].front(); |
| listener.outOfOrderArgument(argIdx, prevArgIdx); |
| return true; |
| } |
| } |
| } |
| |
| // If no arguments were renamed, the call arguments match up with the |
| // parameters. |
| if (actualArgNames.empty()) |
| return false; |
| |
| // The arguments were relabeled; notify the listener. |
| return listener.relabelArguments(actualArgNames); |
| } |
| |
| // Match the argument of a call to the parameter. |
| static ConstraintSystem::SolutionKind |
| matchCallArguments(ConstraintSystem &cs, TypeMatchKind kind, |
| Type argType, Type paramType, |
| ConstraintLocatorBuilder locator) { |
| /// Listener used to produce failures if they should be produced. |
| class Listener : public MatchCallArgumentListener { |
| ConstraintSystem &CS; |
| Type ArgType; |
| Type ParamType; |
| ConstraintLocatorBuilder &Locator; |
| |
| public: |
| Listener(ConstraintSystem &cs, Type argType, Type paramType, |
| ConstraintLocatorBuilder &locator) |
| : CS(cs), ArgType(argType), ParamType(paramType), Locator(locator) { } |
| |
| bool relabelArguments(ArrayRef<Identifier> newNames) override { |
| if (!CS.shouldAttemptFixes()) { |
| // FIXME: record why this failed. We have renaming. |
| return true; |
| } |
| |
| // Add a fix for the name. This is only responsible for recording the fix. |
| auto result = CS.simplifyFixConstraint( |
| Fix::getRelabelTuple(CS, FixKind::RelabelCallTuple, |
| newNames), |
| ArgType, ParamType, |
| TypeMatchKind::ArgumentTupleConversion, |
| ConstraintSystem::TMF_None, |
| Locator); |
| return result != ConstraintSystem::SolutionKind::Solved; |
| } |
| }; |
| |
| // In the empty existential parameter case, we don't need to decompose the |
| // arguments. |
| if (paramType->isEmptyExistentialComposition()) { |
| if (argType->is<InOutType>()) { |
| return ConstraintSystem::SolutionKind::Error; |
| } |
| return ConstraintSystem::SolutionKind::Solved; |
| } |
| |
| // Extract the arguments. |
| auto args = decomposeArgParamType(argType); |
| |
| // Extract the parameters. |
| auto params = decomposeArgParamType(paramType); |
| |
| // Match up the call arguments to the parameters. |
| Listener listener(cs, argType, paramType, locator); |
| SmallVector<ParamBinding, 4> parameterBindings; |
| if (constraints::matchCallArguments(args, params, |
| hasTrailingClosure(locator), |
| cs.shouldAttemptFixes(), listener, |
| parameterBindings)) |
| return ConstraintSystem::SolutionKind::Error; |
| |
| // Check the argument types for each of the parameters. |
| unsigned subflags = ConstraintSystem::TMF_GenerateConstraints; |
| TypeMatchKind subKind; |
| switch (kind) { |
| case TypeMatchKind::ArgumentTupleConversion: |
| subKind = TypeMatchKind::ArgumentConversion; |
| break; |
| |
| case TypeMatchKind::OperatorArgumentTupleConversion: |
| subKind = TypeMatchKind::OperatorArgumentConversion; |
| break; |
| |
| case TypeMatchKind::Conversion: |
| case TypeMatchKind::ExplicitConversion: |
| case TypeMatchKind::OperatorArgumentConversion: |
| case TypeMatchKind::ArgumentConversion: |
| case TypeMatchKind::BindType: |
| case TypeMatchKind::BindParamType: |
| case TypeMatchKind::BindToPointerType: |
| case TypeMatchKind::SameType: |
| case TypeMatchKind::ConformsTo: |
| case TypeMatchKind::Subtype: |
| llvm_unreachable("Not a call argument constraint"); |
| } |
| |
| auto haveOneNonUserConversion = |
| (subKind != TypeMatchKind::OperatorArgumentConversion); |
| |
| auto haveNilArgument = false; |
| auto nilLiteralProto = cs.TC.getProtocol(SourceLoc(), |
| KnownProtocolKind:: |
| NilLiteralConvertible); |
| |
| auto isNilLiteral = [&](Type t) -> bool { |
| if (auto tyvar = t->getAs<TypeVariableType>()) { |
| return tyvar->getImpl().literalConformanceProto == nilLiteralProto; |
| } |
| return false; |
| }; |
| |
| // If we're applying an operator function to a nil literal operand, we |
| // disallow value-to-optional conversions from taking place so as not to |
| // select an overly permissive overload. |
| auto allowOptionalConversion = [&](Type t) -> bool { |
| |
| if (t->isLValueType()) |
| t = t->getLValueOrInOutObjectType(); |
| |
| if (!t->getAnyOptionalObjectType().isNull()) |
| return true; |
| |
| if (isNilLiteral(t)) |
| return true; |
| |
| if (auto nt = t->getNominalOrBoundGenericNominal()) { |
| return nt->getName() == cs.TC.Context.Id_OptionalNilComparisonType; |
| } |
| |
| return false; |
| }; |
| |
| // Pre-scan operator arguments for nil literals. |
| if (subKind == TypeMatchKind::OperatorArgumentConversion) { |
| for (auto arg : args) { |
| if (isNilLiteral(arg.Ty)) { |
| haveNilArgument = true; |
| break; |
| } |
| } |
| } |
| |
| for (unsigned paramIdx = 0, numParams = parameterBindings.size(); |
| paramIdx != numParams; ++paramIdx){ |
| // Skip unfulfilled parameters. There's nothing to do for them. |
| if (parameterBindings[paramIdx].empty()) |
| continue; |
| |
| // Determine the parameter type. |
| const auto ¶m = params[paramIdx]; |
| auto paramTy = param.Ty; |
| |
| // Compare each of the bound arguments for this parameter. |
| for (auto argIdx : parameterBindings[paramIdx]) { |
| auto loc = locator.withPathElement(LocatorPathElt:: |
| getApplyArgToParam(argIdx, |
| paramIdx)); |
| auto argTy = args[argIdx].Ty; |
| |
| if (haveNilArgument && !allowOptionalConversion(argTy)) { |
| subflags |= ConstraintSystem::TMF_ApplyingOperatorWithNil; |
| } |
| |
| if (!haveOneNonUserConversion) { |
| subflags |= ConstraintSystem::TMF_ApplyingOperatorParameter; |
| } |
| |
| switch (cs.matchTypes(argTy,paramTy, |
| subKind, subflags, |
| loc)) { |
| case ConstraintSystem::SolutionKind::Error: |
| return ConstraintSystem::SolutionKind::Error; |
| |
| case ConstraintSystem::SolutionKind::Solved: |
| case ConstraintSystem::SolutionKind::Unsolved: |
| break; |
| } |
| } |
| } |
| |
| return ConstraintSystem::SolutionKind::Solved; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2, |
| TypeMatchKind kind, unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| unsigned subFlags = flags | TMF_GenerateConstraints; |
| |
| // Equality and subtyping have fairly strict requirements on tuple matching, |
| // requiring element names to either match up or be disjoint. |
| if (kind < TypeMatchKind::Conversion) { |
| if (tuple1->getNumElements() != tuple2->getNumElements()) |
| return SolutionKind::Error; |
| |
| for (unsigned i = 0, n = tuple1->getNumElements(); i != n; ++i) { |
| const auto &elt1 = tuple1->getElement(i); |
| const auto &elt2 = tuple2->getElement(i); |
| |
| // If the names don't match, we may have a conflict. |
| if (elt1.getName() != elt2.getName()) { |
| // Same-type requirements require exact name matches. |
| if (kind == TypeMatchKind::SameType) |
| return SolutionKind::Error; |
| |
| // For subtyping constraints, just make sure that this name isn't |
| // used at some other position. |
| if (elt2.hasName() && tuple1->getNamedElementId(elt2.getName()) != -1) |
| return SolutionKind::Error; |
| } |
| |
| // Variadic bit must match. |
| if (elt1.isVararg() != elt2.isVararg()) |
| return SolutionKind::Error; |
| |
| // Compare the element types. |
| switch (matchTypes(elt1.getType(), elt2.getType(), kind, subFlags, |
| locator.withPathElement( |
| LocatorPathElt::getTupleElement(i)))) { |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| |
| case SolutionKind::Solved: |
| case SolutionKind::Unsolved: |
| break; |
| } |
| } |
| return SolutionKind::Solved; |
| } |
| |
| assert(kind >= TypeMatchKind::Conversion); |
| TypeMatchKind subKind; |
| switch (kind) { |
| case TypeMatchKind::ArgumentTupleConversion: |
| subKind = TypeMatchKind::ArgumentConversion; |
| break; |
| |
| case TypeMatchKind::OperatorArgumentTupleConversion: |
| subKind = TypeMatchKind::OperatorArgumentConversion; |
| break; |
| |
| case TypeMatchKind::OperatorArgumentConversion: |
| case TypeMatchKind::ArgumentConversion: |
| case TypeMatchKind::ExplicitConversion: |
| case TypeMatchKind::Conversion: |
| subKind = TypeMatchKind::Conversion; |
| break; |
| |
| case TypeMatchKind::BindType: |
| case TypeMatchKind::BindParamType: |
| case TypeMatchKind::BindToPointerType: |
| case TypeMatchKind::SameType: |
| case TypeMatchKind::Subtype: |
| case TypeMatchKind::ConformsTo: |
| llvm_unreachable("Not a conversion"); |
| } |
| |
| // Compute the element shuffles for conversions. |
| SmallVector<int, 16> sources; |
| SmallVector<unsigned, 4> variadicArguments; |
| if (computeTupleShuffle(tuple1, tuple2, sources, variadicArguments)) |
| return SolutionKind::Error; |
| |
| // Check each of the elements. |
| bool hasVariadic = false; |
| unsigned variadicIdx = sources.size(); |
| for (unsigned idx2 = 0, n = sources.size(); idx2 != n; ++idx2) { |
| // Default-initialization always allowed for conversions. |
| if (sources[idx2] == TupleShuffleExpr::DefaultInitialize) { |
| continue; |
| } |
| |
| // Variadic arguments handled below. |
| if (sources[idx2] == TupleShuffleExpr::Variadic) { |
| assert(!hasVariadic && "Multiple variadic parameters"); |
| hasVariadic = true; |
| variadicIdx = idx2; |
| continue; |
| } |
| |
| assert(sources[idx2] >= 0); |
| unsigned idx1 = sources[idx2]; |
| |
| // Match up the types. |
| const auto &elt1 = tuple1->getElement(idx1); |
| const auto &elt2 = tuple2->getElement(idx2); |
| switch (matchTypes(elt1.getType(), elt2.getType(), subKind, subFlags, |
| locator.withPathElement( |
| LocatorPathElt::getTupleElement(idx1)))) { |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| |
| case SolutionKind::Solved: |
| case SolutionKind::Unsolved: |
| break; |
| } |
| |
| } |
| |
| // If we have variadic arguments to check, do so now. |
| if (hasVariadic) { |
| const auto &elt2 = tuple2->getElements()[variadicIdx]; |
| auto eltType2 = elt2.getVarargBaseTy(); |
| |
| for (unsigned idx1 : variadicArguments) { |
| switch (matchTypes(tuple1->getElementType(idx1), eltType2, subKind, |
| subFlags, |
| locator.withPathElement( |
| LocatorPathElt::getTupleElement(idx1)))) { |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| |
| case SolutionKind::Solved: |
| case SolutionKind::Unsolved: |
| break; |
| } |
| } |
| } |
| |
| return SolutionKind::Solved; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchScalarToTupleTypes(Type type1, TupleType *tuple2, |
| TypeMatchKind kind, unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| int scalarFieldIdx = tuple2->getElementForScalarInit(); |
| assert(scalarFieldIdx >= 0 && "Invalid tuple for scalar-to-tuple"); |
| const auto &elt = tuple2->getElement(scalarFieldIdx); |
| auto scalarFieldTy = elt.isVararg()? elt.getVarargBaseTy() : elt.getType(); |
| return matchTypes(type1, scalarFieldTy, kind, flags, |
| locator.withPathElement(ConstraintLocator::ScalarToTuple)); |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchTupleToScalarTypes(TupleType *tuple1, Type type2, |
| TypeMatchKind kind, unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| assert(tuple1->getNumElements() == 1 && "Wrong number of elements"); |
| assert(!tuple1->getElement(0).isVararg() && "Should not be variadic"); |
| |
| return matchTypes(tuple1->getElementType(0), |
| type2, kind, flags, |
| locator.withPathElement( |
| LocatorPathElt::getTupleElement(0))); |
| } |
| |
| // Returns 'false' (i.e. no error) if it is legal to match functions with the |
| // corresponding function type representations and the given match kind. |
| static bool matchFunctionRepresentations(FunctionTypeRepresentation rep1, |
| FunctionTypeRepresentation rep2, |
| TypeMatchKind kind) { |
| switch (kind) { |
| case TypeMatchKind::BindType: |
| case TypeMatchKind::BindParamType: |
| case TypeMatchKind::BindToPointerType: |
| case TypeMatchKind::SameType: |
| return rep1 != rep2; |
| |
| case TypeMatchKind::ConformsTo: |
| llvm_unreachable("Not sure if we can end up here"); |
| |
| case TypeMatchKind::Subtype: |
| case TypeMatchKind::Conversion: |
| case TypeMatchKind::ExplicitConversion: |
| case TypeMatchKind::ArgumentConversion: |
| case TypeMatchKind::ArgumentTupleConversion: |
| case TypeMatchKind::OperatorArgumentTupleConversion: |
| case TypeMatchKind::OperatorArgumentConversion: |
| return false; |
| } |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2, |
| TypeMatchKind kind, unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| // An @autoclosure function type can be a subtype of a |
| // non-@autoclosure function type. |
| if (func1->isAutoClosure() != func2->isAutoClosure() && |
| (func2->isAutoClosure() || kind < TypeMatchKind::Subtype)) |
| return SolutionKind::Error; |
| |
| // A non-throwing function can be a subtype of a throwing function. |
| if (func1->throws() != func2->throws()) { |
| // Cannot drop 'throws'. |
| if (func1->throws() || (func2->throws() && kind < TypeMatchKind::Subtype)) |
| return SolutionKind::Error; |
| } |
| |
| // A @noreturn function type can be a subtype of a non-@noreturn function |
| // type. |
| if (func1->isNoReturn() != func2->isNoReturn() && |
| (func2->isNoReturn() || kind < TypeMatchKind::SameType)) |
| return SolutionKind::Error; |
| |
| // A non-@noescape function type can be a subtype of a @noescape function |
| // type. |
| if (func1->isNoEscape() != func2->isNoEscape() && |
| (func1->isNoEscape() || kind < TypeMatchKind::Subtype)) |
| return SolutionKind::Error; |
| |
| if (matchFunctionRepresentations(func1->getExtInfo().getRepresentation(), |
| func2->getExtInfo().getRepresentation(), |
| kind)) { |
| return SolutionKind::Error; |
| } |
| |
| // Determine how we match up the input/result types. |
| TypeMatchKind subKind; |
| switch (kind) { |
| case TypeMatchKind::BindType: |
| case TypeMatchKind::BindParamType: |
| case TypeMatchKind::BindToPointerType: |
| case TypeMatchKind::SameType: |
| subKind = kind; |
| break; |
| |
| case TypeMatchKind::ConformsTo: |
| llvm_unreachable("Not sure if we can end up here"); |
| |
| case TypeMatchKind::Subtype: |
| case TypeMatchKind::Conversion: |
| case TypeMatchKind::ExplicitConversion: |
| case TypeMatchKind::ArgumentConversion: |
| case TypeMatchKind::ArgumentTupleConversion: |
| case TypeMatchKind::OperatorArgumentTupleConversion: |
| case TypeMatchKind::OperatorArgumentConversion: |
| subKind = TypeMatchKind::Subtype; |
| break; |
| } |
| |
| unsigned subFlags = flags | TMF_GenerateConstraints; |
| |
| // Input types can be contravariant (or equal). |
| SolutionKind result = matchTypes(func2->getInput(), func1->getInput(), |
| subKind, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::FunctionArgument)); |
| if (result == SolutionKind::Error) |
| return SolutionKind::Error; |
| |
| // Result type can be covariant (or equal). |
| switch (matchTypes(func1->getResult(), func2->getResult(), subKind, |
| subFlags, |
| locator.withPathElement( |
| ConstraintLocator::FunctionResult))) { |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| |
| case SolutionKind::Solved: |
| result = SolutionKind::Solved; |
| break; |
| |
| case SolutionKind::Unsolved: |
| result = SolutionKind::Unsolved; |
| break; |
| } |
| |
| return result; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchSuperclassTypes(Type type1, Type type2, |
| TypeMatchKind kind, unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| auto classDecl2 = type2->getClassOrBoundGenericClass(); |
| bool done = false; |
| for (auto super1 = TC.getSuperClassOf(type1); |
| !done && super1; |
| super1 = TC.getSuperClassOf(super1)) { |
| if (super1->getClassOrBoundGenericClass() != classDecl2) |
| continue; |
| |
| return matchTypes(super1, type2, TypeMatchKind::SameType, |
| TMF_GenerateConstraints, locator); |
| } |
| |
| return SolutionKind::Error; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2, |
| ConstraintLocatorBuilder locator) { |
| // Handle nominal types that are not directly generic. |
| if (auto nominal1 = type1->getAs<NominalType>()) { |
| auto nominal2 = type2->castTo<NominalType>(); |
| |
| assert((bool)nominal1->getParent() == (bool)nominal2->getParent() && |
| "Mismatched parents of nominal types"); |
| |
| if (!nominal1->getParent()) |
| return SolutionKind::Solved; |
| |
| // Match up the parents, exactly. |
| return matchTypes(nominal1->getParent(), nominal2->getParent(), |
| TypeMatchKind::SameType, TMF_GenerateConstraints, |
| locator.withPathElement(ConstraintLocator::ParentType)); |
| } |
| |
| auto bound1 = type1->castTo<BoundGenericType>(); |
| auto bound2 = type2->castTo<BoundGenericType>(); |
| |
| // Match up the parents, exactly, if there are parents. |
| assert((bool)bound1->getParent() == (bool)bound2->getParent() && |
| "Mismatched parents of bound generics"); |
| if (bound1->getParent()) { |
| switch (matchTypes(bound1->getParent(), bound2->getParent(), |
| TypeMatchKind::SameType, TMF_GenerateConstraints, |
| locator.withPathElement(ConstraintLocator::ParentType))){ |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| |
| case SolutionKind::Solved: |
| case SolutionKind::Unsolved: |
| break; |
| } |
| } |
| |
| // Match up the generic arguments, exactly. |
| auto args1 = bound1->getGenericArgs(); |
| auto args2 = bound2->getGenericArgs(); |
| if (args1.size() != args2.size()) { |
| return SolutionKind::Error; |
| } |
| for (unsigned i = 0, n = args1.size(); i != n; ++i) { |
| switch (matchTypes(args1[i], args2[i], TypeMatchKind::SameType, |
| TMF_GenerateConstraints, |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(i)))) { |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| |
| case SolutionKind::Solved: |
| case SolutionKind::Unsolved: |
| break; |
| } |
| } |
| |
| return SolutionKind::Solved; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchExistentialTypes(Type type1, Type type2, |
| ConstraintKind kind, unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| if (type1->is<InOutType>()) { |
| return SolutionKind::Error; |
| } |
| |
| SmallVector<ProtocolDecl *, 4> protocols; |
| type2->getAnyExistentialTypeProtocols(protocols); |
| |
| for (auto proto : protocols) { |
| switch (simplifyConformsToConstraint(type1, proto, kind, locator, flags)) { |
| case SolutionKind::Solved: |
| break; |
| |
| case SolutionKind::Unsolved: |
| // Add the constraint. |
| addConstraint(kind, type1, proto->getDeclaredType(), |
| getConstraintLocator(locator)); |
| break; |
| |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| } |
| } |
| |
| return SolutionKind::Solved; |
| } |
| |
| /// \brief Map a type-matching kind to a constraint kind. |
| static ConstraintKind getConstraintKind(TypeMatchKind kind) { |
| switch (kind) { |
| case TypeMatchKind::BindType: |
| case TypeMatchKind::BindToPointerType: |
| return ConstraintKind::Bind; |
| |
| case TypeMatchKind::BindParamType: |
| return ConstraintKind::BindParam; |
| |
| case TypeMatchKind::SameType: |
| return ConstraintKind::Equal; |
| |
| case TypeMatchKind::ConformsTo: |
| return ConstraintKind::ConformsTo; |
| |
| case TypeMatchKind::Subtype: |
| return ConstraintKind::Subtype; |
| |
| case TypeMatchKind::Conversion: |
| return ConstraintKind::Conversion; |
| |
| case TypeMatchKind::ExplicitConversion: |
| return ConstraintKind::ExplicitConversion; |
| |
| case TypeMatchKind::ArgumentConversion: |
| return ConstraintKind::ArgumentConversion; |
| |
| case TypeMatchKind::ArgumentTupleConversion: |
| return ConstraintKind::ArgumentTupleConversion; |
| |
| case TypeMatchKind::OperatorArgumentTupleConversion: |
| return ConstraintKind::OperatorArgumentTupleConversion; |
| |
| case TypeMatchKind::OperatorArgumentConversion: |
| return ConstraintKind::OperatorArgumentConversion; |
| } |
| |
| llvm_unreachable("unhandled type matching kind"); |
| } |
| |
| static bool isStringCompatiblePointerBaseType(TypeChecker &TC, |
| DeclContext *DC, |
| Type baseType) { |
| // Allow strings to be passed to pointer-to-byte or pointer-to-void types. |
| if (baseType->isEqual(TC.getInt8Type(DC))) |
| return true; |
| if (baseType->isEqual(TC.getUInt8Type(DC))) |
| return true; |
| if (baseType->isEqual(TC.Context.TheEmptyTupleType)) |
| return true; |
| |
| return false; |
| } |
| |
| /// Determine whether the given type is a value type to which we can bridge a |
| /// value of its corresponding class type, such as 'String' bridging from |
| /// NSString. |
| static bool allowsBridgingFromObjC(TypeChecker &tc, DeclContext *dc, |
| Type type) { |
| auto objcType = tc.getBridgedToObjC(dc, type); |
| if (!objcType) |
| return false; |
| |
| auto objcClass = objcType->getClassOrBoundGenericClass(); |
| if (!objcClass) |
| return false; |
| |
| return true; |
| } |
| |
| /// Check whether the given value type is one of a few specific |
| /// bridged types. |
| static bool isArrayDictionarySetOrString(const ASTContext &ctx, Type type) { |
| if (auto structDecl = type->getStructOrBoundGenericStruct()) { |
| return (structDecl == ctx.getStringDecl() || |
| structDecl == ctx.getArrayDecl() || |
| structDecl == ctx.getDictionaryDecl() || |
| structDecl == ctx.getSetDecl()); |
| } |
| |
| return false; |
| } |
| |
| /// Given that 'tupleTy' is the argument type of a function that's being |
| /// invoked with a single unlabeled argument, return the type of the parameter |
| /// that matches that argument, or the null type if such a match is impossible. |
| static Type getTupleElementTypeForSingleArgument(TupleType *tupleTy) { |
| Type result; |
| for (auto ¶m : tupleTy->getElements()) { |
| bool mustClaimArg = !param.isVararg() && |
| param.getDefaultArgKind() == DefaultArgumentKind::None; |
| bool canClaimArg = !param.hasName(); |
| if (!result && canClaimArg) { |
| result = param.isVararg() ? param.getVarargBaseTy() : param.getType(); |
| } else if (mustClaimArg) { |
| return Type(); |
| } |
| } |
| return result; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind, |
| unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| // If we have type variables that have been bound to fixed types, look through |
| // to the fixed type. |
| TypeVariableType *typeVar1; |
| bool isArgumentTupleConversion |
| = kind == TypeMatchKind::ArgumentTupleConversion || |
| kind == TypeMatchKind::OperatorArgumentTupleConversion; |
| type1 = getFixedTypeRecursive(type1, typeVar1, |
| kind == TypeMatchKind::SameType, |
| isArgumentTupleConversion); |
| auto desugar1 = type1->getDesugaredType(); |
| |
| TypeVariableType *typeVar2; |
| type2 = getFixedTypeRecursive(type2, typeVar2, |
| kind == TypeMatchKind::SameType, |
| isArgumentTupleConversion); |
| auto desugar2 = type2->getDesugaredType(); |
| |
| // If the types are obviously equivalent, we're done. |
| if (kind != TypeMatchKind::ConformsTo && desugar1->isEqual(desugar2)) |
| return SolutionKind::Solved; |
| |
| // If either (or both) types are type variables, unify the type variables. |
| if (typeVar1 || typeVar2) { |
| switch (kind) { |
| case TypeMatchKind::BindType: |
| case TypeMatchKind::BindToPointerType: |
| case TypeMatchKind::SameType: { |
| if (typeVar1 && typeVar2) { |
| auto rep1 = getRepresentative(typeVar1); |
| auto rep2 = getRepresentative(typeVar2); |
| if (rep1 == rep2) { |
| // We already merged these two types, so this constraint is |
| // trivially solved. |
| return SolutionKind::Solved; |
| } |
| |
| // If exactly one of the type variables can bind to an lvalue, we |
| // can't merge these two type variables. |
| if (rep1->getImpl().canBindToLValue() |
| != rep2->getImpl().canBindToLValue()) { |
| if (flags & TMF_GenerateConstraints) { |
| if (kind == TypeMatchKind::BindToPointerType) { |
| increaseScore(ScoreKind::SK_ScalarPointerConversion); |
| } |
| |
| // Add a new constraint between these types. We consider the current |
| // type-matching problem to the "solved" by this addition, because |
| // this new constraint will be solved at a later point. |
| // Obviously, this must not happen at the top level, or the |
| // algorithm would not terminate. |
| addConstraint(getConstraintKind(kind), rep1, rep2, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| // Merge the equivalence classes corresponding to these two variables. |
| mergeEquivalenceClasses(rep1, rep2); |
| return SolutionKind::Solved; |
| } |
| |
| // Provide a fixed type for the type variable. |
| bool wantRvalue = kind == TypeMatchKind::SameType; |
| if (typeVar1) { |
| // If we want an rvalue, get the rvalue. |
| if (wantRvalue) |
| type2 = type2->getRValueType(); |
| |
| // If the left-hand type variable cannot bind to an lvalue, |
| // but we still have an lvalue, fail. |
| if (!typeVar1->getImpl().canBindToLValue()) { |
| if (type2->isLValueType()) { |
| if (shouldRecordFailures()) { |
| recordFailure(getConstraintLocator(locator), |
| Failure::IsForbiddenLValue, type1, type2); |
| } |
| return SolutionKind::Error; |
| } |
| |
| // Okay. Bind below. |
| } |
| |
| // Check whether the type variable must be bound to a materializable |
| // type. |
| if (typeVar1->getImpl().mustBeMaterializable()) { |
| if (!type2->isMaterializable()) { |
| if (shouldRecordFailures()) { |
| // TODO: customize error message for closure vs. generic param |
| recordFailure(getConstraintLocator(locator), |
| Failure::IsNotMaterializable, type2); |
| } |
| return SolutionKind::Error; |
| } else { |
| setMustBeMaterializableRecursive(type2); |
| } |
| } |
| |
| // A constraint that binds any pointer to a void pointer is |
| // ineffective, since any pointer can be converted to a void pointer. |
| if (kind == TypeMatchKind::BindToPointerType && desugar2->isVoid() && |
| (flags & TMF_GenerateConstraints)) { |
| // Bind type1 to Void only as a last resort. |
| addConstraint(ConstraintKind::Defaultable, typeVar1, type2, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| assignFixedType(typeVar1, type2); |
| |
| // For symmetry with overload resolution, penalize conversions to empty |
| // existentials. |
| if (type2->isEmptyExistentialComposition()) |
| increaseScore(ScoreKind::SK_EmptyExistentialConversion); |
| |
| return SolutionKind::Solved; |
| } |
| |
| // If we want an rvalue, get the rvalue. |
| if (wantRvalue) |
| type1 = type1->getRValueType(); |
| |
| if (!typeVar2->getImpl().canBindToLValue()) { |
| if (type1->isLValueType()) { |
| if (shouldRecordFailures()) { |
| recordFailure(getConstraintLocator(locator), |
| Failure::IsForbiddenLValue, type1, type2); |
| } |
| return SolutionKind::Error; |
| } |
| |
| // Okay. Bind below. |
| } |
| |
| assignFixedType(typeVar2, type1); |
| return SolutionKind::Solved; |
| } |
| |
| case TypeMatchKind::BindParamType: { |
| if (typeVar2 && !typeVar1) { |
| if (auto *iot = dyn_cast<InOutType>(desugar1)) { |
| assignFixedType(typeVar2, LValueType::get(iot->getObjectType())); |
| } else { |
| assignFixedType(typeVar2, type1); |
| } |
| return SolutionKind::Solved; |
| } else if (typeVar1 && !typeVar2) { |
| if (auto *lvt = dyn_cast<LValueType>(desugar2)) { |
| assignFixedType(typeVar1, InOutType::get(lvt->getObjectType())); |
| } else { |
| assignFixedType(typeVar1, type2); |
| } |
| return SolutionKind::Solved; |
| } |
| return SolutionKind::Unsolved; |
| } |
| |
| // We need to be careful about mapping 'raw' argument type variables to |
| // parameter tuples containing default args, or varargs in the first |
| // position. If we naively bind the type variable to the parameter tuple, |
| // we'll later end up looking to whatever expression created the type |
| // variable to find the declarations for default arguments. This can |
| // obviously be problematic if the expression in question is not an |
| // application. (For example, We don't want to introspect an 'if' expression |
| // to see if it has default arguments.) Instead, we should bind the type |
| // variable to the first element type of the tuple. |
| case TypeMatchKind::ArgumentTupleConversion: |
| if (typeVar1 && |
| !typeVar1->getImpl().literalConformanceProto && |
| (flags & TMF_GenerateConstraints) && |
| dyn_cast<ParenType>(type1.getPointer())) { |
| |
| if (auto tupleTy = type2->getAs<TupleType>()) { |
| if (auto tupleEltTy = getTupleElementTypeForSingleArgument(tupleTy)) { |
| addConstraint(getConstraintKind(kind), |
| typeVar1, |
| tupleEltTy, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| } |
| |
| } |
| SWIFT_FALLTHROUGH; |
| |
| case TypeMatchKind::ConformsTo: |
| case TypeMatchKind::Subtype: |
| case TypeMatchKind::Conversion: |
| case TypeMatchKind::ExplicitConversion: |
| case TypeMatchKind::ArgumentConversion: |
| case TypeMatchKind::OperatorArgumentTupleConversion: |
| case TypeMatchKind::OperatorArgumentConversion: |
| if (flags & TMF_GenerateConstraints) { |
| // Add a new constraint between these types. We consider the current |
| // type-matching problem to the "solved" by this addition, because |
| // this new constraint will be solved at a later point. |
| // Obviously, this must not happen at the top level, or the algorithm |
| // would not terminate. |
| addConstraint(getConstraintKind(kind), type1, type2, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| // We couldn't solve this constraint. If only one of the types is a type |
| // variable, perhaps we can do something with it below. |
| if (typeVar1 && typeVar2) |
| return typeVar1 == typeVar2 ? SolutionKind::Solved |
| : SolutionKind::Unsolved; |
| |
| break; |
| } |
| } |
| |
| llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes; |
| bool concrete = !typeVar1 && !typeVar2; |
| |
| // If this is an argument conversion, handle it directly. The rules are |
| // different from normal conversions. |
| if (kind == TypeMatchKind::ArgumentTupleConversion || |
| kind == TypeMatchKind::OperatorArgumentTupleConversion) { |
| if (concrete) { |
| return ::matchCallArguments(*this, kind, type1, type2, locator); |
| } |
| |
| if (flags & TMF_GenerateConstraints) { |
| // Add a new constraint between these types. We consider the current |
| // type-matching problem to the "solved" by this addition, because |
| // this new constraint will be solved at a later point. |
| // Obviously, this must not happen at the top level, or the algorithm |
| // would not terminate. |
| addConstraint(getConstraintKind(kind), type1, type2, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| // Decompose parallel structure. |
| unsigned subFlags = (flags | TMF_GenerateConstraints) & ~TMF_ApplyingFix; |
| if (desugar1->getKind() == desugar2->getKind()) { |
| switch (desugar1->getKind()) { |
| #define SUGARED_TYPE(id, parent) case TypeKind::id: |
| #define TYPE(id, parent) |
| #include "swift/AST/TypeNodes.def" |
| llvm_unreachable("Type has not been desugared completely"); |
| |
| #define ARTIFICIAL_TYPE(id, parent) case TypeKind::id: |
| #define TYPE(id, parent) |
| #include "swift/AST/TypeNodes.def" |
| llvm_unreachable("artificial type in constraint"); |
| |
| #define BUILTIN_TYPE(id, parent) case TypeKind::id: |
| #define TYPE(id, parent) |
| #include "swift/AST/TypeNodes.def" |
| case TypeKind::Module: |
| if (desugar1 == desugar2) { |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Error; |
| |
| case TypeKind::Error: |
| case TypeKind::Unresolved: |
| return SolutionKind::Error; |
| |
| case TypeKind::GenericTypeParam: |
| case TypeKind::DependentMember: |
| llvm_unreachable("unmapped dependent type in type checker"); |
| |
| case TypeKind::TypeVariable: |
| case TypeKind::Archetype: |
| // Nothing to do here; handle type variables and archetypes below. |
| break; |
| |
| case TypeKind::Tuple: { |
| // Try the tuple-to-tuple conversion. |
| conversionsOrFixes.push_back(ConversionRestrictionKind::TupleToTuple); |
| break; |
| } |
| |
| case TypeKind::Enum: |
| case TypeKind::Struct: |
| case TypeKind::Class: { |
| auto nominal1 = cast<NominalType>(desugar1); |
| auto nominal2 = cast<NominalType>(desugar2); |
| if (nominal1->getDecl() == nominal2->getDecl()) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality); |
| } |
| |
| // Check for CF <-> ObjectiveC bridging. |
| if (desugar1->getKind() == TypeKind::Class && |
| kind >= TypeMatchKind::Subtype) { |
| auto class1 = cast<ClassDecl>(nominal1->getDecl()); |
| auto class2 = cast<ClassDecl>(nominal2->getDecl()); |
| |
| // CF -> Objective-C via toll-free bridging. |
| if (class1->isForeign() && !class2->isForeign() && |
| class1->getAttrs().hasAttribute<ObjCBridgedAttr>()) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::CFTollFreeBridgeToObjC); |
| } |
| |
| // Objective-C -> CF via toll-free bridging. |
| if (class2->isForeign() && !class1->isForeign() && |
| class2->getAttrs().hasAttribute<ObjCBridgedAttr>()) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ObjCTollFreeBridgeToCF); |
| } |
| } |
| |
| break; |
| } |
| |
| case TypeKind::DynamicSelf: |
| // FIXME: Deep equality? What is the rule between two DynamicSelfs? |
| break; |
| |
| case TypeKind::Protocol: |
| // Nothing to do here; try existential and user-defined conversions below. |
| break; |
| |
| case TypeKind::Metatype: |
| case TypeKind::ExistentialMetatype: { |
| auto meta1 = cast<AnyMetatypeType>(desugar1); |
| auto meta2 = cast<AnyMetatypeType>(desugar2); |
| |
| TypeMatchKind subKind = TypeMatchKind::SameType; |
| // A.Type < B.Type if A < B and both A and B are classes. |
| if (isa<MetatypeType>(desugar1) && |
| kind != TypeMatchKind::SameType && |
| meta1->getInstanceType()->mayHaveSuperclass() && |
| meta2->getInstanceType()->getClassOrBoundGenericClass()) |
| subKind = std::min(kind, TypeMatchKind::Subtype); |
| // P.Type < Q.Type if P < Q, both P and Q are protocols, and P.Type |
| // and Q.Type are both existential metatypes. |
| else if (isa<ExistentialMetatypeType>(meta1) |
| && isa<ExistentialMetatypeType>(meta2)) |
| subKind = std::min(kind, TypeMatchKind::Subtype); |
| |
| return matchTypes(meta1->getInstanceType(), meta2->getInstanceType(), |
| subKind, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::InstanceType)); |
| } |
| |
| case TypeKind::Function: |
| return matchFunctionTypes(cast<FunctionType>(desugar1), |
| cast<FunctionType>(desugar2), |
| kind, flags, locator); |
| |
| case TypeKind::PolymorphicFunction: |
| case TypeKind::GenericFunction: |
| llvm_unreachable("Polymorphic function type should have been opened"); |
| |
| case TypeKind::ProtocolComposition: |
| // Existential types handled below. |
| break; |
| |
| case TypeKind::LValue: |
| if (kind == TypeMatchKind::BindParamType) { |
| recordFailure(getConstraintLocator(locator), |
| Failure::IsForbiddenLValue, type1, type2); |
| return SolutionKind::Error; |
| } |
| return matchTypes(cast<LValueType>(desugar1)->getObjectType(), |
| cast<LValueType>(desugar2)->getObjectType(), |
| TypeMatchKind::SameType, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::ArrayElementType)); |
| |
| case TypeKind::InOut: |
| // If the RHS is an inout type, the LHS must be an @lvalue type. |
| if (kind == TypeMatchKind::BindParamType || |
| kind >= TypeMatchKind::OperatorArgumentConversion) { |
| if (shouldRecordFailures()) |
| recordFailure(getConstraintLocator(locator), |
| Failure::IsForbiddenLValue, type1, type2); |
| return SolutionKind::Error; |
| } |
| return matchTypes(cast<InOutType>(desugar1)->getObjectType(), |
| cast<InOutType>(desugar2)->getObjectType(), |
| TypeMatchKind::SameType, subFlags, |
| locator.withPathElement(ConstraintLocator::ArrayElementType)); |
| |
| case TypeKind::UnboundGeneric: |
| llvm_unreachable("Unbound generic type should have been opened"); |
| |
| case TypeKind::BoundGenericClass: |
| case TypeKind::BoundGenericEnum: |
| case TypeKind::BoundGenericStruct: { |
| auto bound1 = cast<BoundGenericType>(desugar1); |
| auto bound2 = cast<BoundGenericType>(desugar2); |
| |
| if (bound1->getDecl() == bound2->getDecl()) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality); |
| } |
| break; |
| } |
| } |
| } |
| |
| if (concrete && kind >= TypeMatchKind::Subtype) { |
| auto tuple1 = type1->getAs<TupleType>(); |
| auto tuple2 = type2->getAs<TupleType>(); |
| |
| // Detect when the source and destination are both permit scalar |
| // conversions, but the source has a name and the destination does not have |
| // the same name. |
| bool tuplesWithMismatchedNames = false; |
| if (tuple1 && tuple2) { |
| int scalar1 = tuple1->getElementForScalarInit(); |
| int scalar2 = tuple2->getElementForScalarInit(); |
| if (scalar1 >= 0 && scalar2 >= 0) { |
| auto name1 = tuple1->getElement(scalar1).getName(); |
| auto name2 = tuple2->getElement(scalar2).getName(); |
| tuplesWithMismatchedNames = !name1.empty() && name1 != name2; |
| } |
| } |
| |
| if (tuple2 && !tuplesWithMismatchedNames) { |
| // A scalar type is a trivial subtype of a one-element, non-variadic tuple |
| // containing a single element if the scalar type is a subtype of |
| // the type of that tuple's element. |
| // |
| // A scalar type can be converted to an argument tuple so long as |
| // there is at most one non-defaulted element. |
| // For non-argument tuples, we can do the same conversion but not |
| // to a tuple with varargs. |
| if ((tuple2->getNumElements() == 1 && |
| !tuple2->getElement(0).isVararg()) || |
| (kind >= TypeMatchKind::Conversion && |
| tuple2->getElementForScalarInit() >= 0 && |
| (isArgumentTupleConversion || |
| !tuple2->getVarArgsBaseType()))) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ScalarToTuple); |
| |
| // FIXME: Prohibits some user-defined conversions for tuples. |
| goto commit_to_conversions; |
| } |
| } |
| |
| if (tuple1 && !tuplesWithMismatchedNames) { |
| // A single-element tuple can be a trivial subtype of a scalar. |
| if (tuple1->getNumElements() == 1 && |
| !tuple1->getElement(0).isVararg()) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::TupleToScalar); |
| } |
| } |
| |
| // Subclass-to-superclass conversion. |
| if (type1->mayHaveSuperclass() && type2->mayHaveSuperclass() && |
| type2->getClassOrBoundGenericClass() && |
| type1->getClassOrBoundGenericClass() |
| != type2->getClassOrBoundGenericClass()) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::Superclass); |
| } |
| |
| // Metatype to object conversion. |
| // |
| // Class and protocol metatypes are interoperable with certain Objective-C |
| // runtime classes, but only when ObjC interop is enabled. |
| |
| if (TC.getLangOpts().EnableObjCInterop) { |
| // These conversions are between concrete types that don't need further |
| // resolution, so we can consider them immediately solved. |
| auto addSolvedRestrictedConstraint |
| = [&](ConversionRestrictionKind restriction) -> SolutionKind { |
| auto constraint = Constraint::createRestricted(*this, |
| ConstraintKind::Subtype, |
| restriction, |
| type1, type2, |
| getConstraintLocator(locator)); |
| addConstraint(constraint); |
| return SolutionKind::Solved; |
| }; |
| |
| if (auto meta1 = type1->getAs<MetatypeType>()) { |
| if (meta1->getInstanceType()->mayHaveSuperclass() |
| && type2->isAnyObject()) { |
| increaseScore(ScoreKind::SK_UserConversion); |
| return addSolvedRestrictedConstraint( |
| ConversionRestrictionKind::ClassMetatypeToAnyObject); |
| } |
| // Single @objc protocol value metatypes can be converted to the ObjC |
| // Protocol class type. |
| auto isProtocolClassType = [&](Type t) -> bool { |
| if (auto classDecl = t->getClassOrBoundGenericClass()) |
| if (classDecl->getName() == getASTContext().Id_Protocol |
| && classDecl->getModuleContext()->getName() |
| == getASTContext().Id_ObjectiveC) |
| return true; |
| return false; |
| }; |
| |
| if (auto protoTy = meta1->getInstanceType()->getAs<ProtocolType>()) { |
| if (protoTy->getDecl()->isObjC() |
| && isProtocolClassType(type2)) { |
| increaseScore(ScoreKind::SK_UserConversion); |
| return addSolvedRestrictedConstraint( |
| ConversionRestrictionKind::ProtocolMetatypeToProtocolClass); |
| } |
| } |
| } |
| if (auto meta1 = type1->getAs<ExistentialMetatypeType>()) { |
| // Class-constrained existential metatypes can be converted to AnyObject. |
| if (meta1->getInstanceType()->isClassExistentialType() |
| && type2->isAnyObject()) { |
| increaseScore(ScoreKind::SK_UserConversion); |
| return addSolvedRestrictedConstraint( |
| ConversionRestrictionKind::ExistentialMetatypeToAnyObject); |
| } |
| } |
| } |
| |
| // Implicit collection conversions. |
| if (kind >= TypeMatchKind::Conversion) { |
| if (isArrayType(desugar1) && isArrayType(desugar2)) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast); |
| } else if (isDictionaryType(desugar1) && isDictionaryType(desugar2)) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::DictionaryUpcast); |
| } else if (isSetType(desugar1) && isSetType(desugar2)) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::SetUpcast); |
| } |
| } |
| } |
| |
| if (kind == TypeMatchKind::BindToPointerType) { |
| if (desugar2->isEqual(getASTContext().TheEmptyTupleType)) |
| return SolutionKind::Solved; |
| } |
| |
| if (concrete && kind >= TypeMatchKind::Conversion) { |
| // An lvalue of type T1 can be converted to a value of type T2 so long as |
| // T1 is convertible to T2 (by loading the value). |
| if (type1->is<LValueType>()) |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::LValueToRValue); |
| |
| // An expression can be converted to an auto-closure function type, creating |
| // an implicit closure. |
| if (auto function2 = type2->getAs<FunctionType>()) { |
| if (function2->isAutoClosure()) |
| return matchTypes(type1, function2->getResult(), kind, subFlags, |
| locator.withPathElement(ConstraintLocator::Load)); |
| } |
| |
| // Bridging from a value type to an Objective-C class type. |
| // FIXME: Banned for operator parameters, like user conversions are. |
| |
| // NOTE: The plan for <rdar://problem/18311362> was to make such bridging |
| // conversions illegal except when explicitly converting with the 'as' |
| // operator. But using a String to subscript an [NSObject : AnyObject] is |
| // sufficiently common due to bridging that disallowing such conversions is |
| // not yet feasible, and a more targeted fix in the type checker is hard to |
| // justify. |
| |
| if (type1->isPotentiallyBridgedValueType() && |
| type1->getAnyNominal() |
| != TC.Context.getImplicitlyUnwrappedOptionalDecl() && |
| !(flags & TMF_ApplyingOperatorParameter)) { |
| |
| auto isBridgeableTargetType = type2->isBridgeableObjectType(); |
| |
| // Allow bridged conversions to CVarArgType through NSObject. |
| if (!isBridgeableTargetType && type2->isExistentialType()) { |
| if (auto nominalType = type2->getAs<NominalType>()) |
| isBridgeableTargetType = nominalType->getDecl()->getName() == |
| TC.Context.Id_CVarArgType; |
| } |
| |
| if (isBridgeableTargetType && TC.getBridgedToObjC(DC, type1)) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::BridgeToObjC); |
| } |
| } |
| |
| if (kind == TypeMatchKind::ExplicitConversion) { |
| // Bridging from an Objective-C class type to a value type. |
| // Note that specifically require a class or class-constrained archetype |
| // here, because archetypes cannot be bridged. |
| if (type1->mayHaveSuperclass() && type2->isPotentiallyBridgedValueType() && |
| type2->getAnyNominal() |
| != TC.Context.getImplicitlyUnwrappedOptionalDecl() && |
| allowsBridgingFromObjC(TC, DC, type2)) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::BridgeFromObjC); |
| } |
| |
| // Bridging from an ErrorType to an Objective-C NSError. |
| if (auto errorType = TC.Context.getProtocol(KnownProtocolKind::ErrorType)) { |
| if (TC.containsProtocol(type1, errorType, DC, |
| ConformanceCheckFlags::InExpression)) |
| if (auto NSErrorTy = TC.getNSErrorType(DC)) |
| if (type2->isEqual(NSErrorTy)) |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::BridgeToNSError); |
| } |
| } |
| |
| // Pointer arguments can be converted from pointer-compatible types. |
| if (kind >= TypeMatchKind::ArgumentConversion) { |
| if (auto bgt2 = type2->getAs<BoundGenericType>()) { |
| if (bgt2->getDecl() == getASTContext().getUnsafeMutablePointerDecl() |
| || bgt2->getDecl() == getASTContext().getUnsafePointerDecl()) { |
| // UnsafeMutablePointer can be converted from an inout reference to a |
| // scalar or array. |
| if (auto inoutType1 = dyn_cast<InOutType>(desugar1)) { |
| auto inoutBaseType = inoutType1->getInOutObjectType(); |
| |
| auto isWrappedArray = isArrayType(inoutBaseType); |
| |
| if (auto baseTyVar1 = dyn_cast<TypeVariableType>(inoutBaseType. |
| getPointer())) { |
| TypeVariableType *tv1; |
| auto bt1 = getFixedTypeRecursive(baseTyVar1, tv1, |
| kind == TypeMatchKind::SameType, |
| isArgumentTupleConversion); |
| |
| isWrappedArray = isArrayType(bt1); |
| } |
| |
| if (isWrappedArray) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ArrayToPointer); |
| } |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::InoutToPointer); |
| } |
| |
| if (!(flags & TMF_ApplyingOperatorParameter) && |
| // Operators cannot use these implicit conversions. |
| (kind == TypeMatchKind::ArgumentConversion || |
| kind == TypeMatchKind::ArgumentTupleConversion)) { |
| auto bgt1 = type1->getAs<BoundGenericType>(); |
| |
| // We can potentially convert from an UnsafeMutablePointer |
| // of a different type, if we're a void pointer. |
| if (bgt1 && bgt1->getDecl() |
| == getASTContext().getUnsafeMutablePointerDecl()) { |
| // Favor an UnsafeMutablePointer-to-UnsafeMutablePointer |
| // conversion. |
| if (bgt1->getDecl() != bgt2->getDecl()) |
| increaseScore(ScoreKind::SK_ScalarPointerConversion); |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::PointerToPointer); |
| } |
| |
| // UnsafePointer can also be converted from an array |
| // or string value, or a UnsafePointer or |
| // AutoreleasingUnsafeMutablePointer. |
| if (bgt2->getDecl() == getASTContext().getUnsafePointerDecl()){ |
| if (isArrayType(type1)) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ArrayToPointer); |
| } |
| |
| // The pointer can be converted from a string, if the element type |
| // is compatible. |
| if (type1->isEqual(TC.getStringType(DC))) { |
| TypeVariableType *tv = nullptr; |
| auto baseTy = getFixedTypeRecursive(bgt2->getGenericArgs()[0], |
| tv, false, false); |
| |
| if (tv || isStringCompatiblePointerBaseType(TC, DC, baseTy)) |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::StringToPointer); |
| } |
| |
| if (bgt1 && bgt1->getDecl() |
| == getASTContext().getUnsafePointerDecl()) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::PointerToPointer); |
| } |
| if (bgt1 && bgt1->getDecl() == getASTContext() |
| .getAutoreleasingUnsafeMutablePointerDecl()) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::PointerToPointer); |
| } |
| } |
| } |
| } else if ( |
| bgt2->getDecl() == getASTContext() |
| .getAutoreleasingUnsafeMutablePointerDecl()) { |
| // AutoUnsafeMutablePointer can be converted from an inout |
| // reference to a scalar. |
| if (type1->is<InOutType>()) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::InoutToPointer); |
| } |
| } |
| } |
| } |
| } |
| |
| if (concrete && kind >= TypeMatchKind::OperatorArgumentConversion) { |
| // If the RHS is an inout type, the LHS must be an @lvalue type. |
| if (auto *iot = type2->getAs<InOutType>()) { |
| return matchTypes(type1, LValueType::get(iot->getObjectType()), |
| kind, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::ArrayElementType)); |
| } |
| } |
| |
| // Conformance of a metatype to an existential metatype is actually |
| // equivalent to a conformance relationship on the instance types. |
| // This applies to nested metatype levels, so if A : P then |
| // A.Type : P.Type. |
| if (concrete && kind >= TypeMatchKind::ConformsTo) { |
| if (auto meta1 = type1->getAs<MetatypeType>()) { |
| if (auto meta2 = type2->getAs<ExistentialMetatypeType>()) { |
| return matchTypes(meta1->getInstanceType(), |
| meta2->getInstanceType(), |
| TypeMatchKind::ConformsTo, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::InstanceType)); |
| } |
| } |
| } |
| |
| // Instance type check for the above. We are going to check conformance once |
| // we hit commit_to_conversions below, but we have to add a token restriction |
| // to ensure we wrap the metatype value in a metatype erasure. |
| if (concrete && type2->isExistentialType()) { |
| |
| // If we're binding to an empty existential, we need to make sure that the |
| // conversion is valid. |
| if (kind == TypeMatchKind::BindType && |
| type2->isEmptyExistentialComposition()) { |
| |
| conversionsOrFixes.push_back(ConversionRestrictionKind::Existential); |
| addConstraint(ConstraintKind::SelfObjectOfProtocol, |
| type1, type2, getConstraintLocator(locator)); |
| |
| return SolutionKind::Solved; |
| } |
| |
| if (kind == TypeMatchKind::ConformsTo) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind:: |
| MetatypeToExistentialMetatype); |
| } else if (kind >= TypeMatchKind::Subtype) { |
| conversionsOrFixes.push_back(ConversionRestrictionKind::Existential); |
| } |
| } |
| |
| // A value of type T can be converted to type U? if T is convertible to U. |
| // A value of type T? can be converted to type U? if T is convertible to U. |
| // The above conversions also apply to implicitly unwrapped optional types, |
| // except that there is no implicit conversion from T? to T!. |
| { |
| BoundGenericType *boundGenericType2; |
| |
| if (concrete && kind >= TypeMatchKind::Subtype && |
| (boundGenericType2 = type2->getAs<BoundGenericType>())) { |
| auto decl2 = boundGenericType2->getDecl(); |
| if (auto optionalKind2 = decl2->classifyAsOptionalType()) { |
| assert(boundGenericType2->getGenericArgs().size() == 1); |
| |
| BoundGenericType *boundGenericType1 = type1->getAs<BoundGenericType>(); |
| if (boundGenericType1) { |
| auto decl1 = boundGenericType1->getDecl(); |
| if (decl1 == decl2) { |
| assert(boundGenericType1->getGenericArgs().size() == 1); |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::OptionalToOptional); |
| } else if (optionalKind2 == OTK_Optional && |
| decl1 == TC.Context.getImplicitlyUnwrappedOptionalDecl()) { |
| assert(boundGenericType1->getGenericArgs().size() == 1); |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ImplicitlyUnwrappedOptionalToOptional); |
| } else if (optionalKind2 == OTK_ImplicitlyUnwrappedOptional && |
| kind >= TypeMatchKind::Conversion && |
| decl1 == TC.Context.getOptionalDecl()) { |
| assert(boundGenericType1->getGenericArgs().size() == 1); |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::OptionalToImplicitlyUnwrappedOptional); |
| } |
| } |
| |
| // Do not attempt a value-to-optional conversion when resolving the |
| // applicable overloads for an operator application with nil operands. |
| if (!(subFlags & TMF_ApplyingOperatorWithNil)) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ValueToOptional); |
| } |
| } |
| } |
| } |
| |
| // A value of type T! can be (unsafely) forced to U if T |
| // is convertible to U. |
| { |
| Type objectType1; |
| if (concrete && kind >= TypeMatchKind::Conversion && |
| (objectType1 = lookThroughImplicitlyUnwrappedOptionalType(type1))) { |
| conversionsOrFixes.push_back( |
| ConversionRestrictionKind::ForceUnchecked); |
| } |
| } |
| |
| // If the types disagree, but we're comparing a non-void, single-expression |
| // closure result type to a void function result type, allow the conversion. |
| { |
| if (concrete && kind >= TypeMatchKind::Subtype && type2->isVoid()) { |
| SmallVector<LocatorPathElt, 2> parts; |
| locator.getLocatorParts(parts); |
| |
| while (!parts.empty()) { |
| if (parts.back().getKind() == ConstraintLocator::ClosureResult) { |
| increaseScore(SK_FunctionConversion); |
| return SolutionKind::Solved; |
| } |
| parts.pop_back(); |
| } |
| } |
| } |
| |
| if (concrete && kind == TypeMatchKind::BindParamType) { |
| if (auto *iot = dyn_cast<InOutType>(desugar1)) { |
| if (auto *lvt = dyn_cast<LValueType>(desugar2)) { |
| return matchTypes(iot->getObjectType(), lvt->getObjectType(), |
| TypeMatchKind::BindType, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::ArrayElementType)); |
| } |
| } |
| } |
| |
| commit_to_conversions: |
| // When we hit this point, we're committed to the set of potential |
| // conversions recorded thus far. |
| // |
| // |
| // FIXME: One should only jump to this label in the case where we want to |
| // cut off other potential conversions because we know none of them apply. |
| // Gradually, those gotos should go away as we can handle more kinds of |
| // conversions via disjunction constraints. |
| |
| // If we should attempt fixes, add those to the list. They'll only be visited |
| // if there are no other possible solutions. |
| if (shouldAttemptFixes() && !typeVar1 && !typeVar2 && |
| !(flags & TMF_ApplyingFix) && kind >= TypeMatchKind::Conversion) { |
| Type objectType1 = type1->getRValueObjectType(); |
| |
| // If we have an optional type, try to force-unwrap it. |
| // FIXME: Should we also try '?'? |
| if (objectType1->getOptionalObjectType()) { |
| conversionsOrFixes.push_back(FixKind::ForceOptional); |
| } |
| |
| // If we have a value of type AnyObject that we're trying to convert to |
| // a class, force a downcast. |
| // FIXME: Also allow types bridged through Objective-C classes. |
| if (objectType1->isAnyObject() && |
| type2->getClassOrBoundGenericClass()) { |
| conversionsOrFixes.push_back(Fix::getForcedDowncast(*this, type2)); |
| } |
| |
| // Look through IUO's. |
| auto type1WithoutIUO = objectType1; |
| if (auto elt = type1WithoutIUO->getImplicitlyUnwrappedOptionalObjectType()) |
| type1WithoutIUO = elt; |
| |
| // If we could perform a bridging cast, try it. |
| if (isArrayDictionarySetOrString(TC.Context, type2) && |
| TC.getDynamicBridgedThroughObjCClass(DC, type1WithoutIUO, type2)){ |
| conversionsOrFixes.push_back(Fix::getForcedDowncast(*this, type2)); |
| } |
| |
| // If we're converting an lvalue to an inout type, add the missing '&'. |
| if (type2->getRValueType()->is<InOutType>() && type1->is<LValueType>()) { |
| conversionsOrFixes.push_back(FixKind::AddressOf); |
| } |
| } |
| |
| if (conversionsOrFixes.empty()) { |
| // If one of the types is a type variable, we leave this unsolved. |
| if (typeVar1 || typeVar2) |
| return SolutionKind::Unsolved; |
| |
| return SolutionKind::Error; |
| } |
| |
| // Where there is more than one potential conversion, create a disjunction |
| // so that we'll explore all of the options. |
| if (conversionsOrFixes.size() > 1) { |
| auto fixedLocator = getConstraintLocator(locator); |
| SmallVector<Constraint *, 2> constraints; |
| for (auto potential : conversionsOrFixes) { |
| auto constraintKind = getConstraintKind(kind); |
| |
| if (auto restriction = potential.getRestriction()) { |
| // Determine the constraint kind. For a deep equality constraint, only |
| // perform equality. |
| if (*restriction == ConversionRestrictionKind::DeepEquality) |
| constraintKind = ConstraintKind::Equal; |
| |
| constraints.push_back( |
| Constraint::createRestricted(*this, constraintKind, *restriction, |
| type1, type2, fixedLocator)); |
| continue; |
| } |
| |
| // If the first thing we found is a fix, add a "don't fix" marker. |
| if (conversionsOrFixes.empty()) { |
| constraints.push_back( |
| Constraint::createFixed(*this, constraintKind, FixKind::None, |
| type1, type2, fixedLocator)); |
| } |
| |
| auto fix = *potential.getFix(); |
| constraints.push_back( |
| Constraint::createFixed(*this, constraintKind, fix, type1, type2, |
| fixedLocator)); |
| } |
| addConstraint(Constraint::createDisjunction(*this, constraints, |
| fixedLocator)); |
| return SolutionKind::Solved; |
| } |
| |
| // For a single potential conversion, directly recurse, so that we |
| // don't allocate a new constraint or constraint locator. |
| |
| // Handle restrictions. |
| if (auto restriction = conversionsOrFixes[0].getRestriction()) { |
| ConstraintRestrictions.push_back( |
| std::make_tuple(type1, type2, *restriction)); |
| |
| if (flags & TMF_UnwrappingOptional) { |
| subFlags |= TMF_UnwrappingOptional; |
| } |
| |
| return simplifyRestrictedConstraint(*restriction, type1, type2, |
| kind, subFlags, locator); |
| } |
| |
| // Handle fixes. |
| auto fix = *conversionsOrFixes[0].getFix(); |
| return simplifyFixConstraint(fix, type1, type2, kind, subFlags, locator); |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyConstructionConstraint(Type valueType, |
| FunctionType *fnType, |
| unsigned flags, |
| ConstraintLocator *locator) { |
| // Desugar the value type. |
| auto desugarValueType = valueType->getDesugaredType(); |
| |
| // If we have a type variable that has been bound to a fixed type, |
| // look through to that fixed type. |
| auto desugarValueTypeVar = dyn_cast<TypeVariableType>(desugarValueType); |
| if (desugarValueTypeVar) { |
| if (auto fixed = getFixedType(desugarValueTypeVar)) { |
| valueType = fixed; |
| desugarValueType = fixed->getDesugaredType(); |
| desugarValueTypeVar = nullptr; |
| } |
| } |
| |
| Type argType = fnType->getInput(); |
| Type resultType = fnType->getResult(); |
| |
| switch (desugarValueType->getKind()) { |
| #define SUGARED_TYPE(id, parent) case TypeKind::id: |
| #define TYPE(id, parent) |
| #include "swift/AST/TypeNodes.def" |
| llvm_unreachable("Type has not been desugared completely"); |
| |
| #define ARTIFICIAL_TYPE(id, parent) case TypeKind::id: |
| #define TYPE(id, parent) |
| #include "swift/AST/TypeNodes.def" |
| llvm_unreachable("artificial type in constraint"); |
| |
| case TypeKind::Unresolved: |
| case TypeKind::Error: |
| return SolutionKind::Error; |
| |
| case TypeKind::GenericFunction: |
| case TypeKind::GenericTypeParam: |
| case TypeKind::DependentMember: |
| llvm_unreachable("unmapped dependent type"); |
| |
| case TypeKind::TypeVariable: |
| return SolutionKind::Unsolved; |
| |
| case TypeKind::Tuple: { |
| // Tuple construction is simply tuple conversion. |
| if (matchTypes(resultType, desugarValueType, |
| TypeMatchKind::BindType, |
| flags, |
| ConstraintLocatorBuilder(locator) |
| .withPathElement(ConstraintLocator::ApplyFunction)) |
| == SolutionKind::Error) |
| return SolutionKind::Error; |
| |
| return matchTypes(argType, valueType, TypeMatchKind::Conversion, |
| flags|TMF_GenerateConstraints, locator); |
| } |
| |
| case TypeKind::Enum: |
| case TypeKind::Struct: |
| case TypeKind::Class: |
| case TypeKind::BoundGenericClass: |
| case TypeKind::BoundGenericEnum: |
| case TypeKind::BoundGenericStruct: |
| case TypeKind::Archetype: |
| case TypeKind::DynamicSelf: |
| case TypeKind::ProtocolComposition: |
| case TypeKind::Protocol: |
| // Break out to handle the actual construction below. |
| break; |
| |
| case TypeKind::PolymorphicFunction: |
| llvm_unreachable("Polymorphic function type should have been opened"); |
| |
| case TypeKind::UnboundGeneric: |
| llvm_unreachable("Unbound generic type should have been opened"); |
| |
| #define BUILTIN_TYPE(id, parent) case TypeKind::id: |
| #define TYPE(id, parent) |
| #include "swift/AST/TypeNodes.def" |
| case TypeKind::ExistentialMetatype: |
| case TypeKind::Metatype: |
| case TypeKind::Function: |
| case TypeKind::LValue: |
| case TypeKind::InOut: |
| case TypeKind::Module: |
| return SolutionKind::Error; |
| } |
| |
| NameLookupOptions lookupOptions = defaultConstructorLookupOptions; |
| if (isa<AbstractFunctionDecl>(DC)) |
| lookupOptions |= NameLookupFlags::KnownPrivate; |
| auto ctors = TC.lookupConstructors(DC, valueType, lookupOptions); |
| if (!ctors) { |
| // If we are supposed to record failures, do so. |
| if (shouldRecordFailures()) { |
| recordFailure(locator, Failure::NoPublicInitializers, valueType); |
| } |
| |
| return SolutionKind::Error; |
| } |
| |
| auto &context = getASTContext(); |
| auto name = context.Id_init; |
| auto applyLocator = getConstraintLocator(locator, |
| ConstraintLocator::ApplyArgument); |
| auto fnLocator = getConstraintLocator(locator, |
| ConstraintLocator::ApplyFunction); |
| auto tv = createTypeVariable(applyLocator, |
| TVO_CanBindToLValue|TVO_PrefersSubtypeBinding); |
| |
| // The constructor will have function type T -> T2, for a fresh type |
| // variable T. T2 is the result type provided via the construction |
| // constraint itself. |
| addValueMemberConstraint(MetatypeType::get(valueType, TC.Context), name, |
| FunctionType::get(tv, resultType), |
| getConstraintLocator( |
| fnLocator, |
| ConstraintLocator::ConstructorMember)); |
| |
| // The first type must be convertible to the constructor's argument type. |
| addConstraint(ConstraintKind::ArgumentTupleConversion, argType, tv, |
| applyLocator); |
| |
| return SolutionKind::Solved; |
| } |
| |
| ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( |
| Type type, |
| Type protocol, |
| ConstraintKind kind, |
| ConstraintLocatorBuilder locator, |
| unsigned flags) { |
| if (auto proto = protocol->getAs<ProtocolType>()) { |
| return simplifyConformsToConstraint(type, proto->getDecl(), kind, |
| locator, flags); |
| } |
| |
| return matchExistentialTypes(type, protocol, kind, flags, locator); |
| } |
| |
| ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint( |
| Type type, |
| ProtocolDecl *protocol, |
| ConstraintKind kind, |
| ConstraintLocatorBuilder locator, |
| unsigned flags) { |
| // Dig out the fixed type to which this type refers. |
| TypeVariableType *typeVar; |
| type = getFixedTypeRecursive(type, typeVar, /*wantRValue=*/true); |
| |
| // If we hit a type variable without a fixed type, we can't |
| // solve this yet. |
| if (typeVar) |
| return SolutionKind::Unsolved; |
| |
| // For purposes of argument type matching, existential types don't need to |
| // conform -- they only need to contain the protocol, so check that |
| // separately. |
| switch (kind) { |
| case ConstraintKind::SelfObjectOfProtocol: |
| if (TC.containsProtocol(type, protocol, DC, |
| ConformanceCheckFlags::InExpression)) |
| return SolutionKind::Solved; |
| break; |
| case ConstraintKind::ConformsTo: |
| // Check whether this type conforms to the protocol. |
| if (TC.conformsToProtocol(type, protocol, DC, |
| ConformanceCheckFlags::InExpression)) |
| return SolutionKind::Solved; |
| break; |
| default: |
| llvm_unreachable("bad constraint kind"); |
| } |
| |
| if (!shouldAttemptFixes()) |
| return SolutionKind::Error; |
| |
| // See if there's anything we can do to fix the conformance: |
| OptionalTypeKind optionalKind; |
| if (auto optionalObjectType = type->getAnyOptionalObjectType(optionalKind)) { |
| if (protocol->isSpecificProtocol(KnownProtocolKind::BooleanType)) { |
| // Optionals don't conform to BooleanType; suggest '!= nil'. |
| if (recordFix(FixKind::OptionalToBoolean, getConstraintLocator(locator))) |
| return SolutionKind::Error; |
| return SolutionKind::Solved; |
| } else if (optionalKind == OTK_Optional) { |
| // The underlying type of an optional may conform to the protocol if the |
| // optional doesn't; suggest forcing if that's the case. |
| auto result = simplifyConformsToConstraint( |
| optionalObjectType, protocol, kind, |
| locator.withPathElement(LocatorPathElt::getGenericArgument(0)), flags); |
| if (result == SolutionKind::Solved) { |
| if (recordFix(FixKind::ForceOptional, getConstraintLocator(locator))) { |
| return SolutionKind::Error; |
| } |
| } |
| return result; |
| } |
| } |
| |
| // There's nothing more we can do; fail. |
| return SolutionKind::Error; |
| } |
| |
| /// Determine the kind of checked cast to perform from the given type to |
| /// the given type. |
| /// |
| /// This routine does not attempt to check whether the cast can actually |
| /// succeed; that's the caller's responsibility. |
| static CheckedCastKind getCheckedCastKind(ConstraintSystem *cs, |
| Type fromType, |
| Type toType) { |
| // Array downcasts are handled specially. |
| if (cs->isArrayType(fromType) && cs->isArrayType(toType)) { |
| return CheckedCastKind::ArrayDowncast; |
| } |
| |
| // Dictionary downcasts are handled specially. |
| if (cs->isDictionaryType(fromType) && cs->isDictionaryType(toType)) { |
| return CheckedCastKind::DictionaryDowncast; |
| } |
| |
| // Set downcasts are handled specially. |
| if (cs->isSetType(fromType) && cs->isSetType(toType)) { |
| return CheckedCastKind::SetDowncast; |
| } |
| |
| // If we can bridge through an Objective-C class, do so. |
| auto &tc = cs->getTypeChecker(); |
| if (tc.getDynamicBridgedThroughObjCClass(cs->DC, fromType, toType)) { |
| return CheckedCastKind::BridgeFromObjectiveC; |
| } |
| |
| return CheckedCastKind::ValueCast; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyCheckedCastConstraint( |
| Type fromType, Type toType, |
| ConstraintLocatorBuilder locator) { |
| do { |
| // Dig out the fixed type to which this type refers. |
| TypeVariableType *typeVar1; |
| fromType = getFixedTypeRecursive(fromType, typeVar1, /*wantRValue=*/true); |
| |
| // If we hit a type variable without a fixed type, we can't |
| // solve this yet. |
| if (typeVar1) |
| return SolutionKind::Unsolved; |
| |
| // Dig out the fixed type to which this type refers. |
| TypeVariableType *typeVar2; |
| toType = getFixedTypeRecursive(toType, typeVar2, /*wantRValue=*/true); |
| |
| // If we hit a type variable without a fixed type, we can't |
| // solve this yet. |
| if (typeVar2) |
| return SolutionKind::Unsolved; |
| |
| Type origFromType = fromType; |
| Type origToType = toType; |
| |
| // Peel off optionals metatypes from the types, because we might cast through |
| // them. |
| toType = toType->lookThroughAllAnyOptionalTypes(); |
| fromType = fromType->lookThroughAllAnyOptionalTypes(); |
| |
| // Peel off metatypes, since if we can cast two types, we can cast their |
| // metatypes. |
| while (auto toMetatype = toType->getAs<MetatypeType>()) { |
| auto fromMetatype = fromType->getAs<MetatypeType>(); |
| if (!fromMetatype) |
| break; |
| toType = toMetatype->getInstanceType(); |
| fromType = fromMetatype->getInstanceType(); |
| } |
| |
| // Peel off a potential layer of existential<->concrete metatype conversion. |
| if (auto toMetatype = toType->getAs<AnyMetatypeType>()) { |
| if (auto fromMetatype = fromType->getAs<MetatypeType>()) { |
| toType = toMetatype->getInstanceType(); |
| fromType = fromMetatype->getInstanceType(); |
| } |
| } |
| |
| // If nothing changed, we're done. |
| if (fromType.getPointer() == origFromType.getPointer() && |
| toType.getPointer() == origToType.getPointer()) |
| break; |
| } while (true); |
| |
| auto kind = getCheckedCastKind(this, fromType, toType); |
| switch (kind) { |
| case CheckedCastKind::ArrayDowncast: { |
| auto fromBaseType = getBaseTypeForArrayType(fromType.getPointer()); |
| auto toBaseType = getBaseTypeForArrayType(toType.getPointer()); |
| |
| // FIXME: Deal with from/to base types that haven't been solved |
| // down to type variables yet. |
| |
| // Check whether we need to bridge through an Objective-C class. |
| if (auto classType = TC.getDynamicBridgedThroughObjCClass(DC, |
| fromBaseType, |
| toBaseType)) { |
| // The class we're bridging through must be a subtype of the type we're |
| // coming from. |
| addConstraint(ConstraintKind::Subtype, classType, fromBaseType, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| addConstraint(ConstraintKind::Subtype, toBaseType, fromBaseType, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| case CheckedCastKind::DictionaryDowncast: |
| case CheckedCastKind::DictionaryDowncastBridged: { |
| Type fromKeyType, fromValueType; |
| std::tie(fromKeyType, fromValueType) = *isDictionaryType(fromType); |
| |
| Type toKeyType, toValueType; |
| std::tie(toKeyType, toValueType) = *isDictionaryType(toType); |
| |
| // FIXME: Deal with from/to base types that haven't been solved |
| // down to type variables yet. |
| |
| // Check whether we need to bridge the key through an Objective-C class. |
| if (auto bridgedKey = TC.getDynamicBridgedThroughObjCClass(DC, |
| fromKeyType, |
| toKeyType)) { |
| toKeyType = bridgedKey; |
| } |
| |
| // Perform subtype check on the possibly-bridged-through key type. |
| unsigned subFlags = TMF_GenerateConstraints; |
| auto result = matchTypes(toKeyType, fromKeyType, TypeMatchKind::Subtype, |
| subFlags, locator); |
| if (result == SolutionKind::Error) |
| return result; |
| |
| // Check whether we need to bridge the value through an Objective-C class. |
| if (auto bridgedValue = TC.getDynamicBridgedThroughObjCClass(DC, |
| fromValueType, |
| toValueType)) { |
| toValueType = bridgedValue; |
| } |
| |
| // Perform subtype check on the possibly-bridged-through value type. |
| switch (matchTypes(toValueType, fromValueType, TypeMatchKind::Subtype, |
| subFlags, locator)) { |
| case SolutionKind::Solved: |
| return result; |
| |
| case SolutionKind::Unsolved: |
| return SolutionKind::Unsolved; |
| |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| } |
| } |
| |
| case CheckedCastKind::SetDowncast: |
| case CheckedCastKind::SetDowncastBridged: { |
| auto fromBaseType = getBaseTypeForSetType(fromType.getPointer()); |
| auto toBaseType = getBaseTypeForSetType(toType.getPointer()); |
| // FIXME: Deal with from/to base types that haven't been solved |
| // down to type variables yet. |
| |
| // Check whether we need to bridge through an Objective-C class. |
| if (auto classType = TC.getDynamicBridgedThroughObjCClass(DC, |
| fromBaseType, |
| toBaseType)) { |
| // The class we're bridging through must be a subtype of the type we're |
| // coming from. |
| addConstraint(ConstraintKind::Subtype, classType, fromBaseType, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| addConstraint(ConstraintKind::Subtype, toBaseType, fromBaseType, |
| getConstraintLocator(locator)); |
| return SolutionKind::Solved; |
| } |
| |
| case CheckedCastKind::ValueCast: { |
| // If casting among classes, and there are open |
| // type variables remaining, introduce a subtype constraint to help resolve |
| // them. |
| if (fromType->getClassOrBoundGenericClass() |
| && toType->getClassOrBoundGenericClass() |
| && (fromType->hasTypeVariable() || toType->hasTypeVariable())) { |
| addConstraint(ConstraintKind::Subtype, toType, fromType, |
| getConstraintLocator(locator)); |
| } |
| |
| return SolutionKind::Solved; |
| } |
| |
| case CheckedCastKind::BridgeFromObjectiveC: { |
| // This existential-to-concrete cast might bridge through an Objective-C |
| // class type. |
| Type objCClass = TC.getDynamicBridgedThroughObjCClass(DC, |
| fromType, |
| toType); |
| assert(objCClass && "Type must be bridged"); |
| (void)objCClass; |
| // Otherwise no constraint is necessary; as long as both objCClass and |
| // fromType are Objective-C types, they can't have any open type variables, |
| // and conversion between unrelated classes will be diagnosed in |
| // typeCheckCheckedCast. |
| return SolutionKind::Solved; |
| } |
| |
| case CheckedCastKind::Coercion: |
| case CheckedCastKind::Unresolved: |
| llvm_unreachable("Not a valid result"); |
| } |
| } |
| |
| /// Determine whether the given type is the Self type of the protocol. |
| static bool isProtocolSelf(Type type) { |
| if (auto genericParam = type->getAs<GenericTypeParamType>()) |
| return genericParam->getDepth() == 0; |
| |
| return false; |
| } |
| |
| /// Determine whether the given type contains a reference to the 'Self' type |
| /// of a protocol. |
| static bool containsProtocolSelf(Type type) { |
| // If the type is not dependent, it doesn't refer to 'Self'. |
| if (!type->hasTypeParameter()) |
| return false; |
| |
| return type.findIf([](Type type) -> bool { |
| return isProtocolSelf(type); |
| }); |
| } |
| |
| /// Determine whether the given protocol member's signature prevents |
| /// it from being used in an existential reference. |
| static bool isUnavailableInExistential(TypeChecker &tc, ValueDecl *decl) { |
| Type type = decl->getInterfaceType(); |
| if (!type) // FIXME: deal with broken recursion |
| return true; |
| |
| // For a function or constructor, skip the implicit 'this'. |
| if (auto afd = dyn_cast<AbstractFunctionDecl>(decl)) { |
| type = type->castTo<AnyFunctionType>()->getResult(); |
| |
| // Allow functions to return Self, but not have Self anywhere in |
| // their argument types. |
| for (unsigned i = 1, n = afd->getNumParameterLists(); i != n; ++i) { |
| // Check whether the input type contains Self anywhere. |
| auto fnType = type->castTo<AnyFunctionType>(); |
| if (containsProtocolSelf(fnType->getInput())) |
| return true; |
| |
| type = fnType->getResult(); |
| } |
| |
| // Look through one level of optional on the result type. |
| if (auto valueType = type->getAnyOptionalObjectType()) |
| type = valueType; |
| |
| if (isProtocolSelf(type) || type->is<DynamicSelfType>()) |
| return false; |
| |
| return containsProtocolSelf(type); |
| } |
| |
| return containsProtocolSelf(type); |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyOptionalObjectConstraint(const Constraint &constraint) |
| { |
| // Resolve the optional type. |
| Type optLValueTy = simplifyType(constraint.getFirstType()); |
| Type optTy = optLValueTy->getRValueType(); |
| |
| if (optTy->is<TypeVariableType>()) { |
| return SolutionKind::Unsolved; |
| } |
| |
| // If the base type is not optional, the constraint fails. |
| Type objectTy = optTy->getAnyOptionalObjectType(); |
| if (!objectTy) |
| return SolutionKind::Error; |
| |
| // The object type is an lvalue if the optional was. |
| if (optLValueTy->is<LValueType>()) |
| objectTy = LValueType::get(objectTy); |
| |
| // Equate it to the other type in the constraint. |
| addConstraint(ConstraintKind::Bind, objectTy, constraint.getSecondType(), |
| constraint.getLocator()); |
| |
| return SolutionKind::Solved; |
| } |
| |
| /// If the given type conforms to the RawRepresentable protocol, |
| /// return its underlying raw type. |
| static Type getRawRepresentableValueType(TypeChecker &tc, DeclContext *dc, |
| Type type) { |
| auto proto = tc.Context.getProtocol(KnownProtocolKind::RawRepresentable); |
| if (!proto) |
| return nullptr; |
| |
| if (type->hasTypeVariable()) |
| return nullptr; |
| |
| ProtocolConformance *conformance = nullptr; |
| if (!tc.conformsToProtocol(type, proto, dc, |
| ConformanceCheckFlags::InExpression, &conformance)) |
| return nullptr; |
| |
| return tc.getWitnessType(type, proto, conformance, tc.Context.Id_RawValue, |
| diag::broken_raw_representable_requirement); |
| } |
| |
| /// Retrieve the argument labels that are provided for a member |
| /// reference at the given locator. |
| static Optional<ArrayRef<Identifier>> |
| getArgumentLabels(ConstraintSystem &cs, ConstraintLocatorBuilder locator) { |
| SmallVector<LocatorPathElt, 2> parts; |
| Expr *anchor = locator.getLocatorParts(parts); |
| if (!anchor) |
| return None; |
| |
| while (!parts.empty()) { |
| if (parts.back().getKind() == ConstraintLocator::Member || |
| parts.back().getKind() == ConstraintLocator::SubscriptMember) { |
| parts.pop_back(); |
| continue; |
| } |
| |
| if (parts.back().getKind() == ConstraintLocator::ApplyFunction) { |
| if (auto applyExpr = dyn_cast<ApplyExpr>(anchor)) { |
| anchor = applyExpr->getFn()->getSemanticsProvidingExpr(); |
| } |
| parts.pop_back(); |
| continue; |
| } |
| |
| if (parts.back().getKind() == ConstraintLocator::ConstructorMember) { |
| // FIXME: Workaround for strange anchor on ConstructorMember locators. |
| |
| if (auto optionalWrapper = dyn_cast<BindOptionalExpr>(anchor)) |
| anchor = optionalWrapper->getSubExpr(); |
| else if (auto forceWrapper = dyn_cast<ForceValueExpr>(anchor)) |
| anchor = forceWrapper->getSubExpr(); |
| |
| parts.pop_back(); |
| continue; |
| } |
| |
| break; |
| } |
| |
| if (!parts.empty()) |
| return None; |
| |
| auto known = cs.ArgumentLabels.find(cs.getConstraintLocator(anchor)); |
| if (known == cs.ArgumentLabels.end()) |
| return None; |
| |
| return known->second; |
| } |
| |
| /// Given a ValueMember, UnresolvedValueMember, or TypeMember constraint, |
| /// perform a lookup into the specified base type to find a candidate list. |
| /// The list returned includes the viable candidates as well as the unviable |
| /// ones (along with reasons why they aren't viable). |
| MemberLookupResult ConstraintSystem:: |
| performMemberLookup(ConstraintKind constraintKind, |
| DeclName memberName, Type baseTy, |
| ConstraintLocator *memberLocator) { |
| Type baseObjTy = baseTy->getRValueType(); |
| |
| // Dig out the instance type and figure out what members of the instance type |
| // we are going to see. |
| bool isMetatype = false; |
| bool hasInstanceMembers = false; |
| bool hasInstanceMethods = false; |
| bool hasStaticMembers = false; |
| Type instanceTy = baseObjTy; |
| if (baseObjTy->is<ModuleType>()) { |
| hasStaticMembers = true; |
| } else if (auto baseObjMeta = baseObjTy->getAs<AnyMetatypeType>()) { |
| instanceTy = baseObjMeta->getInstanceType(); |
| isMetatype = true; |
| if (baseObjMeta->is<ExistentialMetatypeType>()) { |
| // An instance of an existential metatype is a concrete type conforming |
| // to the existential, say Self. Instance members of the concrete type |
| // have type Self -> T -> U, but we don't know what Self is at compile |
| // time so we cannot refer to them. Static methods are fine, on the other |
| // hand -- we already know that they do not have Self or associated type |
| // requirements, since otherwise we would not be able to refer to the |
| // existential metatype in the first place. |
| hasStaticMembers = true; |
| } else if (instanceTy->isExistentialType()) { |
| // A protocol metatype has instance methods with type P -> T -> U, but |
| // not instance properties or static members -- the metatype value itself |
| // doesn't give us a witness so there's no static method to bind. |
| hasInstanceMethods = true; |
| } else { |
| // Metatypes of nominal types and archetypes have instance methods and |
| // static members, but not instance properties. |
| // FIXME: partial application of properties |
| hasInstanceMethods = true; |
| hasStaticMembers = true; |
| } |
| } else { |
| // Otherwise, we can access all instance members. |
| hasInstanceMembers = true; |
| hasInstanceMethods = true; |
| } |
| |
| bool isExistential = instanceTy->isExistentialType(); |
| |
| if (instanceTy->is<TypeVariableType>() || |
| instanceTy->is<UnresolvedType>()) { |
| MemberLookupResult result; |
| result.OverallResult = MemberLookupResult::Unsolved; |
| return result; |
| } |
| |
| |
| // Okay, start building up the result list. |
| MemberLookupResult result; |
| result.OverallResult = MemberLookupResult::HasResults; |
| |
| // If the base type is a tuple type, look for the named or indexed member |
| // of the tuple. |
| if (auto baseTuple = baseObjTy->getAs<TupleType>()) { |
| // Tuples don't have compound-name members. |
| if (!memberName.isSimpleName()) |
| return result; // No result. |
| |
| StringRef nameStr = memberName.getBaseName().str(); |
| int fieldIdx = -1; |
| // Resolve a number reference into the tuple type. |
| unsigned Value = 0; |
| if (!nameStr.getAsInteger(10, Value) && |
| Value < baseTuple->getNumElements()) { |
| fieldIdx = Value; |
| } else { |
| fieldIdx = baseTuple->getNamedElementId(memberName.getBaseName()); |
| } |
| |
| if (fieldIdx == -1) |
| return result; // No result. |
| |
| // Add an overload set that selects this field. |
| result.ViableCandidates.push_back(OverloadChoice(baseTy, fieldIdx)); |
| return result; |
| } |
| |
| |
| // If we have a simple name, determine whether there are argument |
| // labels we can use to restrict the set of lookup results. |
| Optional<ArrayRef<Identifier>> argumentLabels; |
| if (memberName.isSimpleName()) { |
| argumentLabels = getArgumentLabels(*this, |
| ConstraintLocatorBuilder(memberLocator)); |
| |
| // If we're referencing AnyObject and we have argument labels, put |
| // the argument labels into the name: we don't want to look for |
| // anything else, because the cost of the general search is so |
| // high. |
| if (baseObjTy->isAnyObject() && argumentLabels) { |
| memberName = DeclName(TC.Context, memberName.getBaseName(), |
| *argumentLabels); |
| argumentLabels.reset(); |
| } |
| } |
| |
| /// Determine whether the given declaration has compatible argument |
| /// labels. |
| auto hasCompatibleArgumentLabels = [&](ValueDecl *decl) -> bool { |
| if (!argumentLabels) |
| return true; |
| |
| auto name = decl->getFullName(); |
| if (name.isSimpleName()) |
| return true; |
| |
| for (auto argLabel : *argumentLabels) { |
| if (argLabel.empty()) |
| continue; |
| |
| if (std::find(name.getArgumentNames().begin(), |
| name.getArgumentNames().end(), |
| argLabel) == name.getArgumentNames().end()) { |
| return false; |
| } |
| } |
| |
| return true; |
| }; |
| |
| |
| // Handle initializers, they have their own approach to name lookup. |
| if (memberName.isSimpleName(TC.Context.Id_init)) { |
| NameLookupOptions lookupOptions = defaultConstructorLookupOptions; |
| if (isa<AbstractFunctionDecl>(DC)) |
| lookupOptions |= NameLookupFlags::KnownPrivate; |
| LookupResult ctors = TC.lookupConstructors(DC, baseObjTy, lookupOptions); |
| if (!ctors) |
| return result; // No result. |
| |
| // The constructors are only found on the metatype. |
| if (!isMetatype) |
| return result; |
| |
| TypeBase *favoredType = nullptr; |
| if (auto anchor = memberLocator->getAnchor()) { |
| if (auto applyExpr = dyn_cast<ApplyExpr>(anchor)) { |
| auto argExpr = applyExpr->getArg(); |
| favoredType = getFavoredType(argExpr); |
| |
| if (!favoredType) { |
| optimizeConstraints(argExpr); |
| favoredType = getFavoredType(argExpr); |
| } |
| } |
| } |
| |
| // Introduce a new overload set. |
| retry_ctors_after_fail: |
| bool labelMismatch = false; |
| for (auto constructor : ctors) { |
| // If the constructor is invalid, we fail entirely to avoid error cascade. |
| TC.validateDecl(constructor, true); |
| if (constructor->isInvalid()) |
| return result.markErrorAlreadyDiagnosed(); |
| |
| // If the argument labels for this result are incompatible with |
| // the call site, skip it. |
| if (!hasCompatibleArgumentLabels(constructor)) { |
| labelMismatch = true; |
| result.addUnviable(constructor, MemberLookupResult::UR_LabelMismatch); |
| continue; |
| } |
| |
| // If our base is an existential type, we can't make use of any |
| // constructor whose signature involves associated types. |
| if (isExistential && |
| isUnavailableInExistential(getTypeChecker(), constructor)) { |
| result.addUnviable(constructor, |
| MemberLookupResult::UR_UnavailableInExistential); |
| continue; |
| } |
| |
| // If the invocation's argument expression has a favored constraint, |
| // use that information to determine whether a specific overload for |
| // the initializer should be favored. |
| if (favoredType && result.FavoredChoice == ~0U) { |
| // Only try and favor monomorphic initializers. |
| if (auto fnTypeWithSelf = |
| constructor->getType()->getAs<FunctionType>()) { |
| |
| if (auto fnType = |
| fnTypeWithSelf->getResult()->getAs<FunctionType>()) { |
| |
| auto argType = fnType->getInput(); |
| |
| if (auto parenType = |
| dyn_cast<ParenType>(argType.getPointer())) { |
| argType = parenType->getUnderlyingType(); |
| } |
| |
| if (argType->isEqual(favoredType)) |
| result.FavoredChoice = result.ViableCandidates.size(); |
| } |
| } |
| } |
| |
| result.addViable(OverloadChoice(baseTy, constructor, |
| /*isSpecialized=*/false, *this)); |
| } |
| |
| |
| // If we rejected some possibilities due to an argument-label |
| // mismatch and ended up with nothing, try again ignoring the |
| // labels. This allows us to perform typo correction on the labels. |
| if (result.ViableCandidates.empty() && labelMismatch && |
| shouldAttemptFixes()) { |
| argumentLabels.reset(); |
| goto retry_ctors_after_fail; |
| } |
| |
| // FIXME: Should we look for constructors in bridged types? |
| return result; |
| } |
| |
| // If we want member types only, use member type lookup. |
| if (constraintKind == ConstraintKind::TypeMember) { |
| // Types don't have compound names. |
| // FIXME: Customize diagnostic to mention types and compound names. |
| if (!memberName.isSimpleName()) |
| return result; // No result. |
| |
| NameLookupOptions lookupOptions = defaultMemberTypeLookupOptions; |
| if (isa<AbstractFunctionDecl>(DC)) |
| lookupOptions |= NameLookupFlags::KnownPrivate; |
| auto lookup = TC.lookupMemberType(DC, baseObjTy, memberName.getBaseName(), |
| lookupOptions); |
| // Form the overload set. |
| for (auto candidate : lookup) { |
| // If the result is invalid, don't cascade errors. |
| TC.validateDecl(candidate.first, true); |
| if (candidate.first->isInvalid()) |
| return result.markErrorAlreadyDiagnosed(); |
| |
| result.addViable(OverloadChoice(baseTy, candidate.first, |
| /*isSpecialized=*/false)); |
| } |
| |
| return result; |
| } |
| |
| |
| // Look for members within the base. |
| LookupResult &lookup = lookupMember(baseObjTy, memberName); |
| |
| // The set of directly accessible types, which is only used when |
| // we're performing dynamic lookup into an existential type. |
| bool isDynamicLookup = instanceTy->isAnyObject(); |
| |
| // If the instance type is String bridged to NSString, compute |
| // the type we'll look in for bridging. |
| Type bridgedClass; |
| Type bridgedType; |
| if (instanceTy->getAnyNominal() == TC.Context.getStringDecl()) { |
| if (Type classType = TC.getBridgedToObjC(DC, instanceTy)) { |
| bridgedClass = classType; |
| bridgedType = isMetatype ? MetatypeType::get(classType) : classType; |
| } |
| } |
| bool labelMismatch = false; |
| |
| // Local function that adds the given declaration if it is a |
| // reasonable choice. |
| auto addChoice = [&](ValueDecl *cand, bool isBridged, |
| bool isUnwrappedOptional) { |
| // If the result is invalid, skip it. |
| TC.validateDecl(cand, true); |
| if (cand->isInvalid()) { |
| result.markErrorAlreadyDiagnosed(); |
| return; |
| } |
| |
| // If the argument labels for this result are incompatible with |
| // the call site, skip it. |
| if (!hasCompatibleArgumentLabels(cand)) { |
| labelMismatch = true; |
| result.addUnviable(cand, MemberLookupResult::UR_LabelMismatch); |
| return; |
| } |
| |
| |
| // If our base is an existential type, we can't make use of any |
| // member whose signature involves associated types. |
| if (isExistential && isUnavailableInExistential(getTypeChecker(), cand)) { |
| result.addUnviable(cand, MemberLookupResult::UR_UnavailableInExistential); |
| return; |
| } |
| |
| // See if we have an instance method, instance member or static method, |
| // and check if it can be accessed on our base type. |
| if (cand->isInstanceMember()) { |
| if ((isa<FuncDecl>(cand) && !hasInstanceMethods) || |
| (!isa<FuncDecl>(cand) && !hasInstanceMembers)) { |
| result.addUnviable(cand, MemberLookupResult::UR_InstanceMemberOnType); |
| return; |
| } |
| |
| } else { |
| if (!hasStaticMembers) { |
| result.addUnviable(cand, MemberLookupResult::UR_TypeMemberOnInstance); |
| return; |
| } |
| } |
| |
| // If we have an rvalue base, make sure that the result isn't 'mutating' |
| // (only valid on lvalues). |
| if (!isMetatype && |
| !baseTy->is<LValueType>() && cand->isInstanceMember()) { |
| if (auto *FD = dyn_cast<FuncDecl>(cand)) |
| if (FD->isMutating()) { |
| result.addUnviable(cand, |
| MemberLookupResult::UR_MutatingMemberOnRValue); |
| return; |
| } |
| |
| // Subscripts and computed properties are ok on rvalues so long |
| // as the getter is nonmutating. |
| if (auto storage = dyn_cast<AbstractStorageDecl>(cand)) { |
| if (storage->isGetterMutating()) { |
| result.addUnviable(cand, |
| MemberLookupResult::UR_MutatingGetterOnRValue); |
| return; |
| } |
| } |
| } |
| |
| // If the result's type contains delayed members, we need to force them now. |
| if (auto NT = dyn_cast<NominalType>(cand->getType().getPointer())) { |
| if (auto *NTD = dyn_cast<NominalTypeDecl>(NT->getDecl())) { |
| TC.forceExternalDeclMembers(NTD); |
| } |
| } |
| |
| // If we're looking into an existential type, check whether this |
| // result was found via dynamic lookup. |
| if (isDynamicLookup) { |
| assert(cand->getDeclContext()->isTypeContext() && "Dynamic lookup bug"); |
| |
| // We found this declaration via dynamic lookup, record it as such. |
| result.addViable(OverloadChoice::getDeclViaDynamic(baseTy, cand)); |
| return; |
| } |
| |
| // If we have a bridged type, we found this declaration via bridging. |
| if (isBridged) { |
| result.addViable(OverloadChoice::getDeclViaBridge(bridgedType, cand)); |
| return; |
| } |
| |
| // If we got the choice by unwrapping an optional type, unwrap the base |
| // type. |
| Type ovlBaseTy = baseTy; |
| if (isUnwrappedOptional) { |
| ovlBaseTy = MetatypeType::get(baseTy->castTo<MetatypeType>() |
| ->getInstanceType() |
| ->getAnyOptionalObjectType()); |
| result.addViable(OverloadChoice::getDeclViaUnwrappedOptional(ovlBaseTy, |
| cand)); |
| } else { |
| result.addViable(OverloadChoice(ovlBaseTy, cand, |
| /*isSpecialized=*/false, *this)); |
| } |
| }; |
| |
| // Add all results from this lookup. |
| retry_after_fail: |
| labelMismatch = false; |
| for (auto result : lookup) |
| addChoice(result, /*isBridged=*/false, /*isUnwrappedOptional=*/false); |
| |
| // If the instance type is a bridged to an Objective-C type, perform |
| // a lookup into that Objective-C type. |
| if (bridgedType) { |
| LookupResult &bridgedLookup = lookupMember(bridgedClass, memberName); |
| Module *foundationModule = nullptr; |
| for (auto result : bridgedLookup) { |
| // Ignore results from the Objective-C "Foundation" |
| // module. Those core APIs are explicitly provided by the |
| // Foundation module overlay. |
| auto module = result->getModuleContext(); |
| if (foundationModule) { |
| if (module == foundationModule) |
| continue; |
| } else if (ClangModuleUnit::hasClangModule(module) && |
| module->getName().str() == "Foundation") { |
| // Cache the foundation module name so we don't need to look |
| // for it again. |
| foundationModule = module; |
| continue; |
| } |
| |
| addChoice(result, /*isBridged=*/true, /*isUnwrappedOptional=*/false); |
| } |
| } |
| |
| // If we're looking into a metatype for an unresolved member lookup, look |
| // through optional types. |
| // |
| // FIXME: The short-circuit here is lame. |
| if (result.ViableCandidates.empty() && isMetatype && |
| constraintKind == ConstraintKind::UnresolvedValueMember) { |
| if (auto objectType = instanceTy->getAnyOptionalObjectType()) { |
| LookupResult &optionalLookup = lookupMember(MetatypeType::get(objectType), |
| memberName); |
| for (auto result : optionalLookup) |
| addChoice(result, /*bridged*/false, /*isUnwrappedOptional=*/true); |
| } |
| } |
| |
| // If we rejected some possibilities due to an argument-label |
| // mismatch and ended up with nothing, try again ignoring the |
| // labels. This allows us to perform typo correction on the labels. |
| if (result.ViableCandidates.empty() && labelMismatch && shouldAttemptFixes()){ |
| argumentLabels.reset(); |
| goto retry_after_fail; |
| } |
| |
| return result; |
| } |
| |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyMemberConstraint(const Constraint &constraint) { |
| // Resolve the base type, if we can. If we can't resolve the base type, |
| // then we can't solve this constraint. |
| Type baseTy = simplifyType(constraint.getFirstType()); |
| Type baseObjTy = baseTy->getRValueType(); |
| |
| // Try to look through ImplicitlyUnwrappedOptional<T>; the result is |
| // always an l-value if the input was. |
| if (auto objTy = lookThroughImplicitlyUnwrappedOptionalType(baseObjTy)) { |
| increaseScore(SK_ForceUnchecked); |
| |
| baseObjTy = objTy; |
| if (baseTy->is<LValueType>()) |
| baseTy = LValueType::get(objTy); |
| else |
| baseTy = objTy; |
| } |
| |
| MemberLookupResult result = |
| performMemberLookup(constraint.getKind(), constraint.getMember(), |
| baseTy, constraint.getLocator()); |
| |
| DeclName name = constraint.getMember(); |
| Type memberTy = constraint.getSecondType(); |
| |
| switch (result.OverallResult) { |
| case MemberLookupResult::Unsolved: |
| return SolutionKind::Unsolved; |
| case MemberLookupResult::ErrorAlreadyDiagnosed: |
| return SolutionKind::Error; |
| case MemberLookupResult::HasResults: |
| // Keep going! |
| break; |
| } |
| |
| // If we found viable candidates, then we're done! |
| if (!result.ViableCandidates.empty()) { |
| addOverloadSet(memberTy, result.ViableCandidates, constraint.getLocator(), |
| result.getFavoredChoice()); |
| |
| return SolutionKind::Solved; |
| } |
| |
| |
| // If we found some unviable results, then fail, but without recovery. |
| if (!result.UnviableCandidates.empty()) |
| return SolutionKind::Error; |
| |
| |
| // If the lookup found no hits at all (either viable or unviable), diagnose it |
| // as such and try to recover in various ways. |
| |
| if (constraint.getKind() == ConstraintKind::TypeMember) { |
| // If the base type was an optional, try to look through it. |
| if (shouldAttemptFixes() && baseObjTy->getOptionalObjectType()) { |
| // Note the fix. |
| if (recordFix(FixKind::ForceOptional, constraint.getLocator())) |
| return SolutionKind::Error; |
| |
| // Look through one level of optional. |
| addConstraint(Constraint::create(*this, ConstraintKind::TypeMember, |
| baseObjTy->getOptionalObjectType(), |
| constraint.getSecondType(), |
| constraint.getMember(), |
| constraint.getLocator())); |
| return SolutionKind::Solved; |
| } |
| return SolutionKind::Error; |
| } |
| |
| |
| auto instanceTy = baseObjTy; |
| if (auto MTT = instanceTy->getAs<MetatypeType>()) |
| instanceTy = MTT->getInstanceType(); |
| |
| // Value member lookup has some hacks too. |
| Type rawValueType; |
| if (shouldAttemptFixes() && name == TC.Context.Id_fromRaw && |
| (rawValueType = getRawRepresentableValueType(TC, DC, instanceTy))) { |
| // Replace a reference to ".fromRaw" with a reference to init(rawValue:). |
| // FIXME: This is temporary. |
| |
| // Record this fix. |
| if (recordFix(FixKind::FromRawToInit, constraint.getLocator())) |
| return SolutionKind::Error; |
| |
| // Form the type that "fromRaw" would have had and bind the |
| // member type to it. |
| Type fromRawType = FunctionType::get(ParenType::get(TC.Context, |
| rawValueType), |
| OptionalType::get(instanceTy)); |
| addConstraint(ConstraintKind::Bind, memberTy, fromRawType, |
| constraint.getLocator()); |
| |
| return SolutionKind::Solved; |
| } |
| |
| if (shouldAttemptFixes() && name == TC.Context.Id_toRaw && |
| (rawValueType = getRawRepresentableValueType(TC, DC, instanceTy))) { |
| // Replace a call to "toRaw" with a reference to rawValue. |
| // FIXME: This is temporary. |
| |
| // Record this fix. |
| if (recordFix(FixKind::ToRawToRawValue, constraint.getLocator())) |
| return SolutionKind::Error; |
| |
| // Form the type that "toRaw" would have had and bind the member |
| // type to it. |
| Type toRawType = FunctionType::get(TupleType::getEmpty(TC.Context), |
| rawValueType); |
| addConstraint(ConstraintKind::Bind, memberTy, toRawType, |
| constraint.getLocator()); |
| |
| return SolutionKind::Solved; |
| } |
| |
| if (shouldAttemptFixes() && name.isSimpleName("allZeros") && |
| (rawValueType = getRawRepresentableValueType(TC, DC, instanceTy))) { |
| // Replace a reference to "X.allZeros" with a reference to X(). |
| // FIXME: This is temporary. |
| |
| // Record this fix. |
| if (recordFix(FixKind::AllZerosToInit, constraint.getLocator())) |
| return SolutionKind::Error; |
| |
| // Form the type that "allZeros" would have had and bind the |
| // member type to it. |
| addConstraint(ConstraintKind::Bind, memberTy, rawValueType, |
| constraint.getLocator()); |
| return SolutionKind::Solved; |
| } |
| |
| if (shouldAttemptFixes() && baseObjTy->getOptionalObjectType()) { |
| // If the base type was an optional, look through it. |
| |
| // Note the fix. |
| if (recordFix(FixKind::ForceOptional, constraint.getLocator())) |
| return SolutionKind::Error; |
| |
| // Look through one level of optional. |
| addValueMemberConstraint(baseObjTy->getOptionalObjectType(), |
| constraint.getMember(), |
| constraint.getSecondType(), |
| constraint.getLocator()); |
| return SolutionKind::Solved; |
| } |
| return SolutionKind::Error; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyArchetypeConstraint(const Constraint &constraint) { |
| // Resolve the base type, if we can. If we can't resolve the base type, |
| // then we can't solve this constraint. |
| Type baseTy = constraint.getFirstType()->getRValueType(); |
| if (auto tv = dyn_cast<TypeVariableType>(baseTy.getPointer())) { |
| auto fixed = getFixedType(tv); |
| if (!fixed) |
| return SolutionKind::Unsolved; |
| |
| // Continue with the fixed type. |
| baseTy = fixed->getRValueType(); |
| } |
| |
| if (baseTy->is<ArchetypeType>()) |
| return SolutionKind::Solved; |
| |
| return SolutionKind::Error; |
| } |
| |
| /// Simplify the given type for use in a type property constraint. |
| static Type simplifyForTypePropertyConstraint(ConstraintSystem &cs, Type type) { |
| if (auto tv = type->getAs<TypeVariableType>()) { |
| auto fixed = cs.getFixedType(tv); |
| if (!fixed) |
| return Type(); |
| |
| // Continue with the fixed type. |
| type = fixed; |
| |
| // Look through parentheses. |
| while (auto paren = dyn_cast<ParenType>(type.getPointer())) |
| type = paren->getUnderlyingType(); |
| } |
| |
| return type; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyClassConstraint(const Constraint &constraint){ |
| auto baseTy = simplifyForTypePropertyConstraint(*this, |
| constraint.getFirstType()); |
| if (!baseTy) |
| return SolutionKind::Unsolved; |
| |
| if (baseTy->getClassOrBoundGenericClass()) |
| return SolutionKind::Solved; |
| |
| if (auto archetype = baseTy->getAs<ArchetypeType>()) { |
| if (archetype->requiresClass()) |
| return SolutionKind::Solved; |
| } |
| return SolutionKind::Error; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyBridgedToObjectiveCConstraint( |
| const Constraint &constraint) |
| { |
| auto baseTy = simplifyForTypePropertyConstraint(*this, |
| constraint.getFirstType()); |
| if (!baseTy) |
| return SolutionKind::Unsolved; |
| |
| if (TC.getBridgedToObjC(DC, baseTy)) { |
| increaseScore(SK_UserConversion); |
| return SolutionKind::Solved; |
| } |
| |
| // Record this failure. |
| recordFailure(constraint.getLocator(), |
| Failure::IsNotBridgedToObjectiveC, |
| baseTy); |
| return SolutionKind::Error; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyDefaultableConstraint(const Constraint &constraint) { |
| // Leave the constraint around if the first variable is still opaque. |
| auto baseTy = simplifyForTypePropertyConstraint(*this, |
| constraint.getFirstType()); |
| if (!baseTy) |
| return SolutionKind::Unsolved; |
| |
| // Otherwise, any type is fine. |
| return SolutionKind::Solved; |
| } |
| |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyDynamicTypeOfConstraint(const Constraint &constraint) { |
| // Solve forward. |
| TypeVariableType *typeVar2; |
| Type type2 = getFixedTypeRecursive(constraint.getSecondType(), typeVar2, |
| /*wantRValue=*/ true); |
| if (!typeVar2) { |
| Type dynamicType2; |
| if (type2->isAnyExistentialType()) { |
| dynamicType2 = ExistentialMetatypeType::get(type2); |
| } else { |
| dynamicType2 = MetatypeType::get(type2); |
| } |
| return matchTypes(constraint.getFirstType(), dynamicType2, |
| TypeMatchKind::BindType, TMF_GenerateConstraints, |
| constraint.getLocator()); |
| } |
| |
| // Okay, can't solve forward. See what we can do backwards. |
| TypeVariableType *typeVar1; |
| Type type1 = getFixedTypeRecursive(constraint.getFirstType(), typeVar1, true); |
| |
| // If we have an existential metatype, that's good enough to solve |
| // the constraint. |
| if (auto metatype1 = type1->getAs<ExistentialMetatypeType>()) |
| return matchTypes(metatype1->getInstanceType(), type2, |
| TypeMatchKind::BindType, |
| TMF_GenerateConstraints, constraint.getLocator()); |
| |
| // If we have a normal metatype, we can't solve backwards unless we |
| // know what kind of object it is. |
| if (auto metatype1 = type1->getAs<MetatypeType>()) { |
| TypeVariableType *instanceTypeVar1; |
| Type instanceType1 = getFixedTypeRecursive(metatype1->getInstanceType(), |
| instanceTypeVar1, true); |
| if (!instanceTypeVar1) { |
| return matchTypes(instanceType1, type2, |
| TypeMatchKind::BindType, |
| TMF_GenerateConstraints, constraint.getLocator()); |
| } |
| |
| // If it's definitely not either kind of metatype, then we can |
| // report failure right away. |
| } else if (!typeVar1) { |
| return SolutionKind::Error; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyApplicableFnConstraint(const Constraint &constraint) { |
| |
| // By construction, the left hand side is a type that looks like the |
| // following: $T1 -> $T2. |
| Type type1 = constraint.getFirstType(); |
| assert(type1->is<FunctionType>()); |
| |
| // Drill down to the concrete type on the right hand side. |
| TypeVariableType *typeVar2; |
| Type type2 = getFixedTypeRecursive(constraint.getSecondType(), typeVar2, |
| /*wantRValue=*/true); |
| auto desugar2 = type2->getDesugaredType(); |
| |
| // Try to look through ImplicitlyUnwrappedOptional<T>: the result is always an |
| // r-value. |
| if (auto objTy = lookThroughImplicitlyUnwrappedOptionalType(desugar2)) { |
| type2 = objTy; |
| desugar2 = type2->getDesugaredType(); |
| } |
| |
| // Force the right-hand side to be an rvalue. |
| unsigned flags = TMF_GenerateConstraints; |
| |
| // If the types are obviously equivalent, we're done. |
| if (type1.getPointer() == desugar2) |
| return SolutionKind::Solved; |
| |
| // If right-hand side is a type variable, the constraint is unsolved. |
| if (typeVar2) |
| return SolutionKind::Unsolved; |
| |
| // Strip the 'ApplyFunction' off the locator. |
| // FIXME: Perhaps ApplyFunction can go away entirely? |
| ConstraintLocatorBuilder locator = constraint.getLocator(); |
| SmallVector<LocatorPathElt, 2> parts; |
| Expr *anchor = locator.getLocatorParts(parts); |
| assert(!parts.empty() && "Nonsensical applicable-function locator"); |
| assert(parts.back().getKind() == ConstraintLocator::ApplyFunction); |
| assert(parts.back().getNewSummaryFlags() == 0); |
| parts.pop_back(); |
| ConstraintLocatorBuilder outerLocator = |
| getConstraintLocator(anchor, parts, locator.getSummaryFlags()); |
| |
| retry: |
| // For a function, bind the output and convert the argument to the input. |
| auto func1 = type1->castTo<FunctionType>(); |
| if (desugar2->getKind() == TypeKind::Function) { |
| auto func2 = cast<FunctionType>(desugar2); |
| |
| // If this application is part of an operator, then we allow an implicit |
| // lvalue to be compatible with inout arguments. This is used by |
| // assignment operators. |
| TypeMatchKind ArgConv = TypeMatchKind::ArgumentTupleConversion; |
| if (isa<PrefixUnaryExpr>(anchor) || isa<PostfixUnaryExpr>(anchor) || |
| isa<BinaryExpr>(anchor)) |
| ArgConv = TypeMatchKind::OperatorArgumentTupleConversion; |
| |
| // The argument type must be convertible to the input type. |
| if (matchTypes(func1->getInput(), func2->getInput(), |
| ArgConv, flags, |
| outerLocator.withPathElement( |
| ConstraintLocator::ApplyArgument)) |
| == SolutionKind::Error) |
| return SolutionKind::Error; |
| |
| // The result types are equivalent. |
| if (matchTypes(func1->getResult(), func2->getResult(), |
| TypeMatchKind::BindType, |
| flags, |
| locator.withPathElement(ConstraintLocator::FunctionResult)) |
| == SolutionKind::Error) |
| return SolutionKind::Error; |
| |
| // If our type constraints is for a FunctionType, move over the @noescape |
| // flag. |
| if (func1->isNoEscape() && !func2->isNoEscape()) { |
| auto &extraExtInfo = extraFunctionAttrs[func2]; |
| extraExtInfo = extraExtInfo.withNoEscape(); |
| } |
| return SolutionKind::Solved; |
| } |
| |
| // For a metatype, perform a construction. |
| if (auto meta2 = dyn_cast<AnyMetatypeType>(desugar2)) { |
| // Construct the instance from the input arguments. |
| return simplifyConstructionConstraint(meta2->getInstanceType(), func1, |
| flags, |
| getConstraintLocator(outerLocator)); |
| } |
| |
| if (!shouldAttemptFixes()) |
| return SolutionKind::Error; |
| |
| // If we're coming from an optional type, unwrap the optional and try again. |
| if (auto objectType2 = desugar2->getOptionalObjectType()) { |
| if (recordFix(FixKind::ForceOptional, getConstraintLocator(locator))) |
| return SolutionKind::Error; |
| |
| type2 = objectType2; |
| desugar2 = type2->getDesugaredType(); |
| goto retry; |
| } |
| |
| // If this is a '()' call, drop the call. |
| if (func1->getInput()->isEqual(TupleType::getEmpty(getASTContext()))) { |
| // We don't bother with a 'None' case, because at this point we won't get |
| // a better diagnostic from that case. |
| if (recordFix(FixKind::RemoveNullaryCall, getConstraintLocator(locator))) |
| return SolutionKind::Error; |
| |
| return matchTypes(func1->getResult(), type2, |
| TypeMatchKind::BindType, |
| flags | TMF_ApplyingFix | TMF_GenerateConstraints, |
| locator.withPathElement( |
| ConstraintLocator::FunctionResult)); |
| } |
| |
| return SolutionKind::Error; |
| } |
| |
| /// \brief Retrieve the type-matching kind corresponding to the given |
| /// constraint kind. |
| static TypeMatchKind getTypeMatchKind(ConstraintKind kind) { |
| switch (kind) { |
| case ConstraintKind::Bind: return TypeMatchKind::BindType; |
| case ConstraintKind::Equal: return TypeMatchKind::SameType; |
| case ConstraintKind::BindParam: return TypeMatchKind::BindParamType; |
| case ConstraintKind::Subtype: return TypeMatchKind::Subtype; |
| case ConstraintKind::Conversion: return TypeMatchKind::Conversion; |
| case ConstraintKind::ExplicitConversion: |
| return TypeMatchKind::ExplicitConversion; |
| case ConstraintKind::ArgumentConversion: |
| return TypeMatchKind::ArgumentConversion; |
| case ConstraintKind::ArgumentTupleConversion: |
| return TypeMatchKind::ArgumentTupleConversion; |
| case ConstraintKind::OperatorArgumentTupleConversion: |
| return TypeMatchKind::OperatorArgumentTupleConversion; |
| case ConstraintKind::OperatorArgumentConversion: |
| return TypeMatchKind::OperatorArgumentConversion; |
| |
| case ConstraintKind::ApplicableFunction: |
| llvm_unreachable("ApplicableFunction constraints don't involve " |
| "type matches"); |
| |
| case ConstraintKind::DynamicTypeOf: |
| llvm_unreachable("DynamicTypeOf constraints don't involve type matches"); |
| |
| case ConstraintKind::BindOverload: |
| llvm_unreachable("Overload binding constraints don't involve type matches"); |
| |
| case ConstraintKind::ConformsTo: |
| case ConstraintKind::SelfObjectOfProtocol: |
| llvm_unreachable("Conformance constraints don't involve type matches"); |
| |
| case ConstraintKind::CheckedCast: |
| llvm_unreachable("Checked cast constraints don't involve type matches"); |
| |
| case ConstraintKind::ValueMember: |
| case ConstraintKind::UnresolvedValueMember: |
| case ConstraintKind::TypeMember: |
| llvm_unreachable("Member constraints don't involve type matches"); |
| |
| case ConstraintKind::OptionalObject: |
| llvm_unreachable("optional object constraints don't involve type matches"); |
| |
| case ConstraintKind::Archetype: |
| case ConstraintKind::Class: |
| case ConstraintKind::BridgedToObjectiveC: |
| case ConstraintKind::Defaultable: |
| llvm_unreachable("Type properties don't involve type matches"); |
| |
| case ConstraintKind::Disjunction: |
| llvm_unreachable("Con/disjunction constraints don't involve type matches"); |
| } |
| } |
| |
| Type ConstraintSystem::getBaseTypeForArrayType(TypeBase *type) { |
| type = type->lookThroughAllAnyOptionalTypes().getPointer(); |
| |
| if (auto bound = type->getAs<BoundGenericStructType>()) { |
| if (bound->getDecl() == getASTContext().getArrayDecl()) { |
| return bound->getGenericArgs()[0]; |
| } |
| } |
| |
| type->dump(); |
| llvm_unreachable("attempted to extract a base type from a non-array type"); |
| } |
| |
| Type ConstraintSystem::getBaseTypeForSetType(TypeBase *type) { |
| type = type->lookThroughAllAnyOptionalTypes().getPointer(); |
| |
| if (auto bound = type->getAs<BoundGenericStructType>()) { |
| if (bound->getDecl() == getASTContext().getSetDecl()) { |
| return bound->getGenericArgs()[0]; |
| } |
| } |
| |
| type->dump(); |
| llvm_unreachable("attempted to extract a base type from a non-set type"); |
| } |
| |
| static Type getBaseTypeForPointer(ConstraintSystem &cs, TypeBase *type) { |
| auto bgt = type->castTo<BoundGenericType>(); |
| assert((bgt->getDecl() == cs.getASTContext().getUnsafeMutablePointerDecl() |
| || bgt->getDecl() == cs.getASTContext().getUnsafePointerDecl() |
| || bgt->getDecl() |
| == cs.getASTContext().getAutoreleasingUnsafeMutablePointerDecl()) |
| && "conversion is not to a pointer type"); |
| return bgt->getGenericArgs()[0]; |
| } |
| |
| /// Given that we have a conversion constraint between two types, and |
| /// that the given constraint-reduction rule applies between them at |
| /// the top level, apply it and generate any necessary recursive |
| /// constraints. |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restriction, |
| Type type1, Type type2, |
| TypeMatchKind matchKind, |
| unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| // Add to the score based on context. |
| auto addContextualScore = [&] { |
| // Okay, we need to perform one or more conversions. If this |
| // conversion will cause a function conversion, score it as worse. |
| // This induces conversions to occur within closures instead of |
| // outside of them wherever possible. |
| if (locator.isFunctionConversion()) { |
| increaseScore(SK_FunctionConversion); |
| } |
| }; |
| |
| // We'll apply user conversions for operator arguments at the application |
| // site. |
| if (matchKind == TypeMatchKind::OperatorArgumentConversion) { |
| flags |= TMF_ApplyingOperatorParameter; |
| } |
| |
| unsigned subFlags = flags | TMF_GenerateConstraints; |
| |
| switch (restriction) { |
| // for $< in { <, <c, <oc }: |
| // T_i $< U_i ===> (T_i...) $< (U_i...) |
| case ConversionRestrictionKind::TupleToTuple: |
| return matchTupleTypes(type1->castTo<TupleType>(), |
| type2->castTo<TupleType>(), |
| matchKind, subFlags, locator); |
| |
| // T <c U ===> T <c (U) |
| case ConversionRestrictionKind::ScalarToTuple: |
| return matchScalarToTupleTypes(type1, |
| type2->castTo<TupleType>(), |
| matchKind, subFlags, locator); |
| |
| // for $< in { <, <c, <oc }: |
| // T $< U ===> (T) $< U |
| case ConversionRestrictionKind::TupleToScalar: |
| return matchTupleToScalarTypes(type1->castTo<TupleType>(), |
| type2, |
| matchKind, subFlags, locator); |
| |
| case ConversionRestrictionKind::DeepEquality: |
| return matchDeepEqualityTypes(type1, type2, locator); |
| |
| case ConversionRestrictionKind::Superclass: |
| addContextualScore(); |
| return matchSuperclassTypes(type1, type2, matchKind, subFlags, locator); |
| |
| case ConversionRestrictionKind::LValueToRValue: |
| return matchTypes(type1->getRValueType(), type2, |
| matchKind, subFlags, locator); |
| |
| // for $< in { <, <c, <oc }: |
| // T $< U, U : P_i ===> T $< protocol<P_i...> |
| case ConversionRestrictionKind::Existential: |
| addContextualScore(); |
| return matchExistentialTypes(type1, type2, |
| ConstraintKind::SelfObjectOfProtocol, |
| subFlags, locator); |
| |
| // for $< in { <, <c, <oc }: |
| // for T protocol, |
| // T : S ===> T.Protocol $< S.Type |
| // else, |
| // T : S ===> T.Type $< S.Type |
| case ConversionRestrictionKind::MetatypeToExistentialMetatype: |
| addContextualScore(); |
| return matchExistentialTypes(type1, type2, |
| ConstraintKind::ConformsTo, |
| subFlags, locator); |
| |
| // for $< in { <, <c, <oc }: |
| // T $< U ===> T $< U? |
| case ConversionRestrictionKind::ValueToOptional: { |
| addContextualScore(); |
| increaseScore(SK_ValueToOptional); |
| |
| assert(matchKind >= TypeMatchKind::Subtype); |
| auto generic2 = type2->castTo<BoundGenericType>(); |
| assert(generic2->getDecl()->classifyAsOptionalType()); |
| return matchTypes(type1, generic2->getGenericArgs()[0], |
| matchKind, (subFlags | TMF_UnwrappingOptional), locator); |
| } |
| |
| // for $< in { <, <c, <oc }: |
| // T $< U ===> T? $< U? |
| // T $< U ===> T! $< U! |
| // T $< U ===> T! $< U? |
| // also: |
| // T <c U ===> T? <c U! |
| case ConversionRestrictionKind::OptionalToImplicitlyUnwrappedOptional: |
| case ConversionRestrictionKind::ImplicitlyUnwrappedOptionalToOptional: |
| case ConversionRestrictionKind::OptionalToOptional: { |
| addContextualScore(); |
| assert(matchKind >= TypeMatchKind::Subtype); |
| auto generic1 = type1->castTo<BoundGenericType>(); |
| auto generic2 = type2->castTo<BoundGenericType>(); |
| assert(generic1->getDecl()->classifyAsOptionalType()); |
| assert(generic2->getDecl()->classifyAsOptionalType()); |
| return matchTypes(generic1->getGenericArgs()[0], |
| generic2->getGenericArgs()[0], |
| matchKind, subFlags, |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(0))); |
| } |
| |
| // T <c U ===> T! <c U |
| // |
| // We don't want to allow this after user-defined conversions: |
| // - it gets really complex for users to understand why there's |
| // a dereference in their code |
| // - it would allow nil to be coercible to a non-optional type |
| // Fortunately, user-defined conversions only allow subtype |
| // conversions on their results. |
| case ConversionRestrictionKind::ForceUnchecked: { |
| addContextualScore(); |
| assert(matchKind >= TypeMatchKind::Conversion); |
| auto boundGenericType1 = type1->castTo<BoundGenericType>(); |
| assert(boundGenericType1->getDecl()->classifyAsOptionalType() |
| == OTK_ImplicitlyUnwrappedOptional); |
| assert(boundGenericType1->getGenericArgs().size() == 1); |
| Type valueType1 = boundGenericType1->getGenericArgs()[0]; |
| increaseScore(SK_ForceUnchecked); |
| return matchTypes(valueType1, type2, |
| matchKind, subFlags, |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(0))); |
| } |
| |
| case ConversionRestrictionKind::ClassMetatypeToAnyObject: |
| case ConversionRestrictionKind::ExistentialMetatypeToAnyObject: |
| case ConversionRestrictionKind::ProtocolMetatypeToProtocolClass: { |
| // Nothing more to solve. |
| addContextualScore(); |
| return SolutionKind::Solved; |
| } |
| |
| // T <p U ===> T[] <a UnsafeMutablePointer<U> |
| case ConversionRestrictionKind::ArrayToPointer: { |
| addContextualScore(); |
| auto obj1 = type1; |
| // Unwrap an inout type. |
| if (auto inout1 = obj1->getAs<InOutType>()) { |
| obj1 = inout1->getObjectType(); |
| } |
| |
| TypeVariableType *tv1; |
| obj1 = getFixedTypeRecursive(obj1, tv1, false, false); |
| |
| auto t1 = obj1->getDesugaredType(); |
| auto t2 = type2->getDesugaredType(); |
| |
| auto baseType1 = getBaseTypeForArrayType(t1); |
| auto baseType2 = getBaseTypeForPointer(*this, t2); |
| |
| return matchTypes(baseType1, baseType2, |
| TypeMatchKind::BindToPointerType, |
| subFlags, locator); |
| } |
| |
| // String ===> UnsafePointer<[U]Int8> |
| case ConversionRestrictionKind::StringToPointer: { |
| addContextualScore(); |
| |
| auto baseType2 = getBaseTypeForPointer(*this, type2->getDesugaredType()); |
| |
| // The pointer element type must be void or a byte-sized type. |
| // TODO: Handle different encodings based on pointer element type, such as |
| // UTF16 for [U]Int16 or UTF32 for [U]Int32. For now we only interop with |
| // Int8 pointers using UTF8 encoding. |
| TypeVariableType *btv2 = nullptr; |
| baseType2 = getFixedTypeRecursive(baseType2, btv2, false, false); |
| // If we haven't resolved the element type, generate constraints. |
| if (btv2) { |
| if (flags & TMF_GenerateConstraints) { |
| auto int8Con = Constraint::create(*this, ConstraintKind::Bind, |
| btv2, TC.getInt8Type(DC), |
| DeclName(), |
| getConstraintLocator(locator)); |
| auto uint8Con = Constraint::create(*this, ConstraintKind::Bind, |
| btv2, TC.getUInt8Type(DC), |
| DeclName(), |
| getConstraintLocator(locator)); |
| auto voidCon = Constraint::create(*this, ConstraintKind::Bind, |
| btv2, TC.Context.TheEmptyTupleType, |
| DeclName(), |
| getConstraintLocator(locator)); |
| |
| Constraint *disjunctionChoices[] = {int8Con, uint8Con, voidCon}; |
| auto disjunction = Constraint::createDisjunction(*this, |
| disjunctionChoices, |
| getConstraintLocator(locator)); |
| |
| addConstraint(disjunction); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| if (!isStringCompatiblePointerBaseType(TC, DC, baseType2)) { |
| return SolutionKind::Unsolved; |
| } |
| return SolutionKind::Solved; |
| } |
| |
| // T <p U ===> inout T <a UnsafeMutablePointer<U> |
| case ConversionRestrictionKind::InoutToPointer: { |
| addContextualScore(); |
| |
| auto t2 = type2->getDesugaredType(); |
| |
| auto baseType1 = type1->getInOutObjectType(); |
| auto baseType2 = getBaseTypeForPointer(*this, t2); |
| |
| // Set up the disjunction for the array or scalar cases. |
| |
| return matchTypes(baseType1, baseType2, |
| TypeMatchKind::BindToPointerType, |
| subFlags, locator); |
| } |
| |
| // T <p U ===> UnsafeMutablePointer<T> <a UnsafeMutablePointer<U> |
| case ConversionRestrictionKind::PointerToPointer: { |
| auto t1 = type1->getDesugaredType(); |
| auto t2 = type2->getDesugaredType(); |
| |
| Type baseType1 = getBaseTypeForPointer(*this, t1); |
| Type baseType2 = getBaseTypeForPointer(*this, t2); |
| |
| return matchTypes(baseType1, baseType2, |
| TypeMatchKind::BindToPointerType, |
| subFlags, locator); |
| } |
| |
| // T < U or T is bridged to V where V < U ===> Array<T> <c Array<U> |
| case ConversionRestrictionKind::ArrayUpcast: { |
| auto t1 = type1->getDesugaredType(); |
| auto t2 = type2->getDesugaredType(); |
| |
| Type baseType1 = getBaseTypeForArrayType(t1); |
| Type baseType2 = getBaseTypeForArrayType(t2); |
| |
| // Look through type variables in the first element type; we need to know |
| // it's structure before we can decide whether this can be an array upcast. |
| TypeVariableType *baseTypeVar1; |
| baseType1 = getFixedTypeRecursive(baseType1, baseTypeVar1, false, false); |
| if (baseTypeVar1) { |
| if (flags & TMF_GenerateConstraints) { |
| addConstraint( |
| Constraint::createRestricted(*this, getConstraintKind(matchKind), |
| restriction, type1, type2, |
| getConstraintLocator(locator))); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| bool isSimpleUpcast = baseType1->isBridgeableObjectType(); |
| if (isSimpleUpcast) { |
| increaseScore(SK_CollectionUpcastConversion); |
| } else { |
| // Check whether this is a bridging upcast. |
| Type bridgedType1 = TC.getBridgedToObjC(DC, baseType1); |
| if (!bridgedType1) { |
| // FIXME: Record error. |
| return SolutionKind::Error; |
| } |
| |
| // Replace the base type so we perform the appropriate subtype check. |
| baseType1 = bridgedType1; |
| increaseScore(SK_CollectionBridgedConversion); |
| } |
| |
| addContextualScore(); |
| assert(matchKind >= TypeMatchKind::Conversion); |
| |
| return matchTypes(baseType1, |
| baseType2, |
| TypeMatchKind::Subtype, |
| subFlags, |
| locator); |
| } |
| |
| // K1 < K2 && V1 < V2 || K1 bridges to K2 && V1 bridges to V2 ===> |
| // Dictionary<K1, V1> <c Dictionary<K2, V2> |
| case ConversionRestrictionKind::DictionaryUpcast: { |
| auto t1 = type1->getDesugaredType(); |
| Type key1, value1; |
| std::tie(key1, value1) = *isDictionaryType(t1); |
| |
| auto t2 = type2->getDesugaredType(); |
| Type key2, value2; |
| std::tie(key2, value2) = *isDictionaryType(t2); |
| |
| // Look through type variables in the first key and value type; we |
| // need to know their structure before we can decide whether this |
| // can be an upcast. |
| TypeVariableType *keyTypeVar1 = nullptr; |
| TypeVariableType *valueTypeVar1 = nullptr; |
| key1 = getFixedTypeRecursive(key1, keyTypeVar1, false, false); |
| if (!keyTypeVar1) { |
| value1 = getFixedTypeRecursive(value1, valueTypeVar1, false, false); |
| } |
| |
| if (keyTypeVar1 || valueTypeVar1) { |
| if (flags & TMF_GenerateConstraints) { |
| addConstraint( |
| Constraint::createRestricted(*this, getConstraintKind(matchKind), |
| restriction, type1, type2, |
| getConstraintLocator(locator))); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| // If both the first key and value types are bridgeable object |
| // types, this can only be an upcast. |
| bool isUpcast = key1->isBridgeableObjectType() && |
| value1->isBridgeableObjectType(); |
| |
| if (isUpcast) { |
| increaseScore(SK_CollectionUpcastConversion); |
| } else { |
| // This might be a bridged upcast. |
| Type bridgedKey1 = TC.getBridgedToObjC(DC, key1); |
| Type bridgedValue1; |
| if (bridgedKey1) { |
| bridgedValue1 = TC.getBridgedToObjC(DC, value1); |
| } |
| |
| // Both the key and value types need to be bridged. |
| if (!bridgedKey1 || !bridgedValue1) { |
| // FIXME: Record failure. |
| return SolutionKind::Error; |
| } |
| |
| // Look through the destination key and value types. We need |
| // their structure to determine whether we'll be bridging or |
| // upcasting the key and value. |
| TypeVariableType *keyTypeVar2 = nullptr; |
| TypeVariableType *valueTypeVar2 = nullptr; |
| key2 = getFixedTypeRecursive(key2, keyTypeVar2, false, false); |
| if (!keyTypeVar2) { |
| value2 = getFixedTypeRecursive(value2, valueTypeVar2, false, false); |
| } |
| |
| // If either the destination key or value type is a type |
| // variable, we can't simplify this now. |
| if (keyTypeVar2 || valueTypeVar2) { |
| if (flags & TMF_GenerateConstraints) { |
| addConstraint( |
| Constraint::createRestricted(*this, getConstraintKind(matchKind), |
| restriction, type1, type2, |
| getConstraintLocator(locator))); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| // This can be a bridging upcast. |
| if (key2->isBridgeableObjectType()) |
| key1 = bridgedKey1; |
| if (value2->isBridgeableObjectType()) |
| value1 = bridgedValue1; |
| increaseScore(SK_CollectionBridgedConversion); |
| } |
| |
| addContextualScore(); |
| assert(matchKind >= TypeMatchKind::Conversion); |
| |
| // The source key and value types must be subtypes of the destination |
| // key and value types, respectively. |
| auto result = matchTypes(key1, key2, TypeMatchKind::Subtype, subFlags, |
| locator); |
| if (result == SolutionKind::Error) |
| return result; |
| |
| switch (matchTypes(value1, value2, TypeMatchKind::Subtype, subFlags, |
| locator)) { |
| case SolutionKind::Solved: |
| return result; |
| |
| case SolutionKind::Unsolved: |
| return SolutionKind::Unsolved; |
| |
| case SolutionKind::Error: |
| return SolutionKind::Error; |
| } |
| } |
| |
| // T1 < T2 || T1 bridges to T2 ===> Set<T1> <c Set<T2> |
| case ConversionRestrictionKind::SetUpcast: { |
| auto t1 = type1->getDesugaredType(); |
| Type baseType1 = getBaseTypeForSetType(t1); |
| |
| auto t2 = type2->getDesugaredType(); |
| Type baseType2 = getBaseTypeForSetType(t2); |
| |
| // Look through type variables in the first base type; we need to know |
| // their structure before we can decide whether this can be an upcast. |
| TypeVariableType *baseTypeVar1 = nullptr; |
| baseType1 = getFixedTypeRecursive(baseType1, baseTypeVar1, false, false); |
| |
| if (baseTypeVar1) { |
| if (flags & TMF_GenerateConstraints) { |
| addConstraint( |
| Constraint::createRestricted(*this, getConstraintKind(matchKind), |
| restriction, type1, type2, |
| getConstraintLocator(locator))); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| // If the first base type is a bridgeable object type, this can only be an |
| // upcast. |
| bool isUpcast = baseType1->isBridgeableObjectType(); |
| |
| if (isUpcast) { |
| increaseScore(SK_CollectionUpcastConversion); |
| } else { |
| // This might be a bridged upcast. |
| Type bridgedBaseType1 = TC.getBridgedToObjC(DC, baseType1); |
| if (!bridgedBaseType1) { |
| // FIXME: Record failure. |
| return SolutionKind::Error; |
| } |
| |
| // Look through the destination base type. We need its structure to |
| // determine whether we'll be bridging or upcasting the base type. |
| TypeVariableType *baseTypeVar2 = nullptr; |
| baseType2 = getFixedTypeRecursive(baseType2, baseTypeVar2, false, false); |
| |
| // If the destination base type is a type variable, we can't simplify |
| // this now. |
| if (baseTypeVar2) { |
| if (flags & TMF_GenerateConstraints) { |
| addConstraint( |
| Constraint::createRestricted(*this, getConstraintKind(matchKind), |
| restriction, type1, type2, |
| getConstraintLocator(locator))); |
| return SolutionKind::Solved; |
| } |
| |
| return SolutionKind::Unsolved; |
| } |
| |
| // This can be a bridging upcast. |
| if (baseType2->isBridgeableObjectType()) |
| baseType1 = bridgedBaseType1; |
| increaseScore(SK_CollectionBridgedConversion); |
| } |
| |
| addContextualScore(); |
| assert(matchKind >= TypeMatchKind::Conversion); |
| |
| // The source base type must be a subtype of the destination base type. |
| return matchTypes(baseType1, baseType2, TypeMatchKind::Subtype, subFlags, |
| locator); |
| } |
| |
| // T bridges to C and C < U ===> T <c U |
| case ConversionRestrictionKind::BridgeToObjC: { |
| auto objcClass = TC.getBridgedToObjC(DC, type1); |
| assert(objcClass && "type is not bridged to Objective-C?"); |
| addContextualScore(); |
| increaseScore(SK_UserConversion); // FIXME: Use separate score kind? |
| if (worseThanBestSolution()) { |
| return SolutionKind::Error; |
| } |
| |
| // If the bridged value type is generic, the generic arguments |
| // must be bridged to Objective-C for bridging to succeed. |
| if (auto bgt1 = type1->getAs<BoundGenericType>()) { |
| unsigned argIdx = 0; |
| for (auto arg: bgt1->getGenericArgs()) { |
| addConstraint( |
| Constraint::create(*this, |
| ConstraintKind::BridgedToObjectiveC, |
| arg, Type(), DeclName(), |
| getConstraintLocator( |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument( |
| argIdx++))))); |
| } |
| } |
| |
| return matchTypes(objcClass, type2, TypeMatchKind::Subtype, subFlags, |
| locator); |
| } |
| |
| // U bridges to C and T < C ===> T <c U |
| case ConversionRestrictionKind::BridgeFromObjC: { |
| auto objcClass = TC.getBridgedToObjC(DC, type2); |
| assert(objcClass && "type is not bridged to Objective-C?"); |
| addContextualScore(); |
| increaseScore(SK_UserConversion); // FIXME: Use separate score kind? |
| if (worseThanBestSolution()) { |
| return SolutionKind::Error; |
| } |
| |
| // If the bridged value type is generic, the generic arguments |
| // must match the |
| // FIXME: This should be an associated type of the protocol. |
| if (auto bgt1 = type2->getAs<BoundGenericType>()) { |
| if (bgt1->getDecl() == TC.Context.getArrayDecl()) { |
| // [AnyObject] |
| addConstraint(ConstraintKind::Bind, bgt1->getGenericArgs()[0], |
| TC.Context.getProtocol(KnownProtocolKind::AnyObject) |
| ->getDeclaredType(), |
| getConstraintLocator( |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(0)))); |
| } else if (bgt1->getDecl() == TC.Context.getDictionaryDecl()) { |
| // [NSObject : AnyObject] |
| auto NSObjectType = TC.getNSObjectType(DC); |
| if (!NSObjectType) { |
| // Not a bridging case. Should we detect this earlier? |
| return SolutionKind::Error; |
| } |
| |
| addConstraint(ConstraintKind::Bind, bgt1->getGenericArgs()[0], |
| NSObjectType, |
| getConstraintLocator( |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(0)))); |
| |
| addConstraint(ConstraintKind::Bind, bgt1->getGenericArgs()[1], |
| TC.Context.getProtocol(KnownProtocolKind::AnyObject) |
| ->getDeclaredType(), |
| getConstraintLocator( |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(1)))); |
| } else if (bgt1->getDecl() == TC.Context.getSetDecl()) { |
| auto NSObjectType = TC.getNSObjectType(DC); |
| if (!NSObjectType) { |
| // Not a bridging case. Should we detect this earlier? |
| return SolutionKind::Error; |
| } |
| addConstraint(ConstraintKind::Bind, bgt1->getGenericArgs()[0], |
| NSObjectType, |
| getConstraintLocator( |
| locator.withPathElement( |
| LocatorPathElt::getGenericArgument(0)))); |
| } else { |
| llvm_unreachable("unhandled generic bridged type"); |
| } |
| } |
| |
| return matchTypes(type1, objcClass, TypeMatchKind::Subtype, subFlags, |
| locator); |
| } |
| |
| case ConversionRestrictionKind::BridgeToNSError: { |
| increaseScore(SK_UserConversion); // FIXME: Use separate score kind? |
| |
| // The input type must be an ErrorType subtype. |
| auto errorType = TC.Context.getProtocol(KnownProtocolKind::ErrorType) |
| ->getDeclaredType(); |
| return matchTypes(type1, errorType, TypeMatchKind::Subtype, subFlags, |
| locator); |
| } |
| |
| // T' < U and T a toll-free-bridged to T' ===> T' <c U |
| case ConversionRestrictionKind::CFTollFreeBridgeToObjC: { |
| increaseScore(SK_UserConversion); // FIXME: Use separate score kind? |
| if (worseThanBestSolution()) { |
| return SolutionKind::Error; |
| } |
| |
| auto nativeClass = type1->getClassOrBoundGenericClass(); |
| auto bridgedObjCClass |
| = nativeClass->getAttrs().getAttribute<ObjCBridgedAttr>()->getObjCClass(); |
| |
| return matchTypes(bridgedObjCClass->getDeclaredInterfaceType(), |
| type2, TypeMatchKind::Subtype, subFlags, locator); |
| } |
| |
| // T < U' and U a toll-free-bridged to U' ===> T <c U |
| case ConversionRestrictionKind::ObjCTollFreeBridgeToCF: { |
| increaseScore(SK_UserConversion); // FIXME: Use separate score kind? |
| if (worseThanBestSolution()) { |
| return SolutionKind::Error; |
| } |
| |
| auto nativeClass = type2->getClassOrBoundGenericClass(); |
| auto bridgedObjCClass |
| = nativeClass->getAttrs().getAttribute<ObjCBridgedAttr>()->getObjCClass(); |
| |
| return matchTypes(type1, |
| bridgedObjCClass->getDeclaredInterfaceType(), |
| TypeMatchKind::Subtype, subFlags, locator); |
| } |
| } |
| |
| llvm_unreachable("bad conversion restriction"); |
| } |
| |
| bool ConstraintSystem::recordFix(Fix fix, ConstraintLocatorBuilder locator) { |
| auto &ctx = getASTContext(); |
| if (ctx.LangOpts.DebugConstraintSolver) { |
| auto &log = ctx.TypeCheckerDebug->getStream(); |
| log.indent(solverState? solverState->depth * 2 + 2 : 0) |
| << "(attempting fix "; |
| fix.print(log, this); |
| log << " @"; |
| getConstraintLocator(locator)->dump(&ctx.SourceMgr, log); |
| log << ")\n"; |
| } |
| |
| // Record the fix. |
| if (fix.getKind() != FixKind::None) { |
| // Increase the score. If this would make the current solution worse than |
| // the best solution we've seen already, stop now. |
| increaseScore(SK_Fix); |
| if (worseThanBestSolution()) |
| return true; |
| |
| Fixes.push_back({fix, getConstraintLocator(locator)}); |
| } |
| return false; |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyFixConstraint(Fix fix, |
| Type type1, Type type2, |
| TypeMatchKind matchKind, |
| unsigned flags, |
| ConstraintLocatorBuilder locator) { |
| if (recordFix(fix, locator)) { |
| return SolutionKind::Error; |
| } |
| |
| // Try with the fix. |
| unsigned subFlags = flags | TMF_ApplyingFix | TMF_GenerateConstraints; |
| switch (fix.getKind()) { |
| case FixKind::None: |
| return matchTypes(type1, type2, matchKind, subFlags, locator); |
| |
| case FixKind::RemoveNullaryCall: |
| llvm_unreachable("Always applied directly"); |
| |
| case FixKind::ForceOptional: |
| // Assume that '!' was applied to the first type. |
| return matchTypes(type1->getRValueObjectType()->getOptionalObjectType(), |
| type2, matchKind, subFlags, locator); |
| |
| case FixKind::ForceDowncast: |
| // These work whenever they are suggested. |
| return SolutionKind::Solved; |
| |
| case FixKind::AddressOf: |
| // Assume that '&' was applied to the first type, turning an lvalue into |
| // an inout. |
| return matchTypes(InOutType::get(type1->getRValueType()), type2, |
| matchKind, subFlags, locator); |
| |
| case FixKind::TupleToScalar: |
| return matchTypes(type1->castTo<TupleType>()->getElementType(0), |
| type2, matchKind, subFlags, |
| locator.withPathElement( |
| LocatorPathElt::getTupleElement(0))); |
| |
| case FixKind::ScalarToTuple: { |
| auto tuple2 = type2->castTo<TupleType>(); |
| int scalarFieldIdx = tuple2->getElementForScalarInit(); |
| assert(scalarFieldIdx >= 0 && "Invalid tuple for scalar-to-tuple"); |
| const auto &elt = tuple2->getElement(scalarFieldIdx); |
| auto scalarFieldTy = elt.isVararg()? elt.getVarargBaseTy() : elt.getType(); |
| return matchTypes(type1, scalarFieldTy, matchKind, subFlags, |
| locator.withPathElement( |
| ConstraintLocator::ScalarToTuple)); |
| } |
| |
| case FixKind::RelabelCallTuple: |
| case FixKind::OptionalToBoolean: |
| // The actual semantics are handled elsewhere. |
| return SolutionKind::Solved; |
| |
| case FixKind::FromRawToInit: |
| case FixKind::ToRawToRawValue: |
| case FixKind::CoerceToCheckedCast: |
| case FixKind::AllZerosToInit: |
| llvm_unreachable("handled elsewhere"); |
| } |
| } |
| |
| ConstraintSystem::SolutionKind |
| ConstraintSystem::simplifyConstraint(const Constraint &constraint) { |
| switch (constraint.getKind()) { |
| case ConstraintKind::Bind: |
| case ConstraintKind::Equal: |
| case ConstraintKind::BindParam: |
| case ConstraintKind::Subtype: |
| case ConstraintKind::Conversion: |
| case ConstraintKind::ExplicitConversion: |
| case ConstraintKind::ArgumentConversion: |
| case ConstraintKind::ArgumentTupleConversion: |
| case ConstraintKind::OperatorArgumentTupleConversion: |
| case ConstraintKind::OperatorArgumentConversion: { |
| // For relational constraints, match up the types. |
| auto matchKind = getTypeMatchKind(constraint.getKind()); |
| |
| // If there is a fix associated with this constraint, apply it before |
| // we continue. |
| if (auto fix = constraint.getFix()) { |
| return simplifyFixConstraint(*fix, constraint.getFirstType(), |
| constraint.getSecondType(), matchKind, |
| TMF_GenerateConstraints, |
| constraint.getLocator()); |
| } |
| |
| |
| // If there is a restriction on this constraint, apply it directly rather |
| // than going through the general \c matchTypes() machinery. |
| if (auto restriction = constraint.getRestriction()) { |
| SolutionKind result = simplifyRestrictedConstraint(*restriction, |
| constraint.getFirstType(), |
| constraint.getSecondType(), |
| matchKind, |
| 0, |
| constraint.getLocator()); |
| |
| // If we actually solved something, record what we did. |
| switch(result) { |
| case SolutionKind::Error: |
| case SolutionKind::Unsolved: |
| break; |
| |
| case SolutionKind::Solved: |
| ConstraintRestrictions.push_back( |
| std::make_tuple(constraint.getFirstType(), |
| constraint.getSecondType(), *restriction)); |
| break; |
| } |
| |
| return result; |
| } |
| |
| return matchTypes(constraint.getFirstType(), constraint.getSecondType(), |
| matchKind, |
| TMF_None, constraint.getLocator()); |
| } |
| |
| case ConstraintKind::ApplicableFunction: |
| return simplifyApplicableFnConstraint(constraint); |
| |
| case ConstraintKind::DynamicTypeOf: |
| return simplifyDynamicTypeOfConstraint(constraint); |
| |
| case ConstraintKind::BindOverload: |
| resolveOverload(constraint.getLocator(), constraint.getFirstType(), |
| constraint.getOverloadChoice()); |
| return SolutionKind::Solved; |
| |
| case ConstraintKind::ConformsTo: |
| case ConstraintKind::SelfObjectOfProtocol: |
| return simplifyConformsToConstraint( |
| constraint.getFirstType(), |
| constraint.getSecondType(), |
| constraint.getKind(), |
| constraint.getLocator(), |
| TMF_None); |
| |
| case ConstraintKind::CheckedCast: { |
| auto result = simplifyCheckedCastConstraint(constraint.getFirstType(), |
| constraint.getSecondType(), |
| constraint.getLocator()); |
| // NOTE: simplifyCheckedCastConstraint() may return Unsolved, e.g. if the |
| // subexpression's type is unresolved. Don't record the fix until we |
| // successfully simplify the constraint. |
| if (result == SolutionKind::Solved) { |
| if (auto fix = constraint.getFix()) { |
| if (recordFix(*fix, constraint.getLocator())) { |
| return SolutionKind::Error; |
| } |
| } |
| } |
| return result; |
| } |
| |
| case ConstraintKind::OptionalObject: |
| return simplifyOptionalObjectConstraint(constraint); |
| |
| case ConstraintKind::ValueMember: |
| case ConstraintKind::UnresolvedValueMember: |
| case ConstraintKind::TypeMember: |
| return simplifyMemberConstraint(constraint); |
| |
| case ConstraintKind::Archetype: |
| return simplifyArchetypeConstraint(constraint); |
| |
| case ConstraintKind::BridgedToObjectiveC: |
| return simplifyBridgedToObjectiveCConstraint(constraint); |
| |
| case ConstraintKind::Class: |
| return simplifyClassConstraint(constraint); |
| |
| case ConstraintKind::Defaultable: |
| return simplifyDefaultableConstraint(constraint); |
| |
| case ConstraintKind::Disjunction: |
| // Disjunction constraints are never solved here. |
| return SolutionKind::Unsolved; |
| } |
| } |