//===--- CSFix.cpp - Constraint Fixes -------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements the \c ConstraintFix class and its related types, // which is used by constraint solver to attempt to fix constraints to be // able to produce a solution which is easily diagnosable. // //===----------------------------------------------------------------------===// #include "CSFix.h" #include "CSDiagnostics.h" #include "ConstraintLocator.h" #include "ConstraintSystem.h" #include "OverloadChoice.h" #include "swift/AST/Expr.h" #include "swift/AST/Type.h" #include "swift/AST/Types.h" #include "swift/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include using namespace swift; using namespace constraints; ConstraintFix::~ConstraintFix() {} Expr *ConstraintFix::getAnchor() const { return getLocator()->getAnchor(); } void ConstraintFix::print(llvm::raw_ostream &Out) const { Out << "[fix: "; Out << getName(); Out << ']'; Out << " @ "; getLocator()->dump(&CS.getASTContext().SourceMgr, Out); } void ConstraintFix::dump() const {print(llvm::errs()); } std::string ForceDowncast::getName() const { llvm::SmallString<16> name; name += "force downcast ("; name += getFromType()->getString(); name += " as! "; name += getToType()->getString(); name += ")"; return name.c_str(); } bool ForceDowncast::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); MissingExplicitConversionFailure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } ForceDowncast *ForceDowncast::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) ForceDowncast(cs, fromType, toType, locator); } bool ForceOptional::diagnose(bool asNote) const { MissingOptionalUnwrapFailure failure(getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } ForceOptional *ForceOptional::create(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { return new (cs.getAllocator()) ForceOptional(cs, fromType, toType, locator); } bool UnwrapOptionalBase::diagnose(bool asNote) const { bool resultIsOptional = getKind() == FixKind::UnwrapOptionalBaseWithOptionalResult; MemberAccessOnOptionalBaseFailure failure( getConstraintSystem(), getLocator(), MemberName, resultIsOptional); return failure.diagnose(asNote); } UnwrapOptionalBase *UnwrapOptionalBase::create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator) { return new (cs.getAllocator()) UnwrapOptionalBase(cs, FixKind::UnwrapOptionalBase, member, locator); } UnwrapOptionalBase *UnwrapOptionalBase::createWithOptionalResult( ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator) { return new (cs.getAllocator()) UnwrapOptionalBase( cs, FixKind::UnwrapOptionalBaseWithOptionalResult, member, locator); } bool AddAddressOf::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); MissingAddressOfFailure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AddAddressOf *AddAddressOf::create(ConstraintSystem &cs, Type argTy, Type paramTy, ConstraintLocator *locator) { return new (cs.getAllocator()) AddAddressOf(cs, argTy, paramTy, locator); } bool TreatRValueAsLValue::diagnose(bool asNote) const { RValueTreatedAsLValueFailure failure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } TreatRValueAsLValue *TreatRValueAsLValue::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) TreatRValueAsLValue(cs, locator); } bool CoerceToCheckedCast::diagnose(bool asNote) const { MissingForcedDowncastFailure failure(getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } CoerceToCheckedCast *CoerceToCheckedCast::attempt(ConstraintSystem &cs, Type fromType, Type toType, ConstraintLocator *locator) { // If any of the types has a type variable, don't add the fix. if (fromType->hasTypeVariable() || toType->hasTypeVariable()) return nullptr; auto *expr = locator->getAnchor(); if (auto *assignExpr = dyn_cast(expr)) expr = assignExpr->getSrc(); auto *coerceExpr = dyn_cast(expr); if (!coerceExpr) return nullptr; auto subExpr = coerceExpr->getSubExpr(); auto castKind = TypeChecker::typeCheckCheckedCast(fromType, toType, CheckedCastContextKind::None, cs.DC, coerceExpr->getLoc(), subExpr, coerceExpr->getCastTypeLoc().getSourceRange()); // Invalid cast. if (castKind == CheckedCastKind::Unresolved) return nullptr; return new (cs.getAllocator()) CoerceToCheckedCast(cs, fromType, toType, locator); } bool MarkExplicitlyEscaping::diagnose(bool asNote) const { NoEscapeFuncToTypeConversionFailure failure(getConstraintSystem(), getLocator(), ConvertTo); return failure.diagnose(asNote); } MarkExplicitlyEscaping * MarkExplicitlyEscaping::create(ConstraintSystem &cs, ConstraintLocator *locator, Type convertingTo) { return new (cs.getAllocator()) MarkExplicitlyEscaping(cs, locator, convertingTo); } bool RelabelArguments::diagnose(bool asNote) const { LabelingFailure failure(getConstraintSystem(), getLocator(), getLabels()); return failure.diagnose(asNote); } RelabelArguments * RelabelArguments::create(ConstraintSystem &cs, llvm::ArrayRef correctLabels, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(correctLabels.size()); void *mem = cs.getAllocator().Allocate(size, alignof(RelabelArguments)); return new (mem) RelabelArguments(cs, correctLabels, locator); } bool MissingConformance::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); auto *locator = getLocator(); if (IsContextual) { auto context = cs.getContextualTypePurpose(); MissingContextualConformanceFailure failure( cs, context, NonConformingType, ProtocolType, locator); return failure.diagnose(asNote); } MissingConformanceFailure failure( cs, locator, std::make_pair(NonConformingType, ProtocolType)); return failure.diagnose(asNote); } MissingConformance * MissingConformance::forContextual(ConstraintSystem &cs, Type type, Type protocolType, ConstraintLocator *locator) { return new (cs.getAllocator()) MissingConformance( cs, /*isContextual=*/true, type, protocolType, locator); } MissingConformance * MissingConformance::forRequirement(ConstraintSystem &cs, Type type, Type protocolType, ConstraintLocator *locator) { return new (cs.getAllocator()) MissingConformance( cs, /*isContextual=*/false, type, protocolType, locator); } bool SkipSameTypeRequirement::diagnose(bool asNote) const { SameTypeRequirementFailure failure(getConstraintSystem(), LHS, RHS, getLocator()); return failure.diagnose(asNote); } SkipSameTypeRequirement * SkipSameTypeRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipSameTypeRequirement(cs, lhs, rhs, locator); } bool SkipSuperclassRequirement::diagnose(bool asNote) const { SuperclassRequirementFailure failure(getConstraintSystem(), LHS, RHS, getLocator()); return failure.diagnose(asNote); } SkipSuperclassRequirement * SkipSuperclassRequirement::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipSuperclassRequirement(cs, lhs, rhs, locator); } bool ContextualMismatch::diagnose(bool asNote) const { auto failure = ContextualFailure(getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } ContextualMismatch *ContextualMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) ContextualMismatch(cs, lhs, rhs, locator); } bool AllowTupleTypeMismatch::coalesceAndDiagnose( ArrayRef fixes, bool asNote) const { llvm::SmallVector indices; if (isElementMismatch()) indices.push_back(*Index); for (auto fix : fixes) { auto *tupleFix = fix->getAs(); if (!tupleFix || !tupleFix->isElementMismatch()) continue; indices.push_back(*tupleFix->Index); } auto &cs = getConstraintSystem(); auto *locator = getLocator(); auto purpose = cs.getContextualTypePurpose(); Type fromType; Type toType; if (getFromType()->is() && getToType()->is()) { fromType = getFromType(); toType = getToType(); } else if (auto contextualType = cs.getContextualType()) { auto *tupleExpr = simplifyLocatorToAnchor(locator); if (!tupleExpr) return false; fromType = cs.getType(tupleExpr); toType = contextualType; } else if (auto argApplyInfo = cs.getFunctionArgApplyInfo(locator)) { purpose = CTP_CallArgument; fromType = argApplyInfo->getArgType(); toType = argApplyInfo->getParamType(); } else if (auto *coerceExpr = dyn_cast(locator->getAnchor())) { purpose = CTP_CoerceOperand; fromType = cs.getType(coerceExpr->getSubExpr()); toType = cs.getType(coerceExpr); } else if (auto *assignExpr = dyn_cast(locator->getAnchor())) { purpose = CTP_AssignSource; fromType = cs.getType(assignExpr->getSrc()); toType = cs.getType(assignExpr->getDest()); } else { return false; } TupleContextualFailure failure(cs, purpose, fromType, toType, indices, locator); return failure.diagnose(asNote); } bool AllowTupleTypeMismatch::diagnose(bool asNote) const { return coalesceAndDiagnose({}, asNote); } AllowTupleTypeMismatch * AllowTupleTypeMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator, Optional index) { return new (cs.getAllocator()) AllowTupleTypeMismatch(cs, lhs, rhs, locator, index); } bool GenericArgumentsMismatch::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); GenericArgumentsMismatchFailure failure(cs, getFromType(), getToType(), getMismatches(), getLocator()); return failure.diagnose(asNote); } GenericArgumentsMismatch *GenericArgumentsMismatch::create( ConstraintSystem &cs, Type actual, Type required, llvm::ArrayRef mismatches, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(mismatches.size()); void *mem = cs.getAllocator().Allocate(size, alignof(GenericArgumentsMismatch)); return new (mem) GenericArgumentsMismatch(cs, actual, required, mismatches, locator); } bool AutoClosureForwarding::diagnose(bool asNote) const { auto failure = AutoClosureForwardingFailure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } AutoClosureForwarding *AutoClosureForwarding::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AutoClosureForwarding(cs, locator); } bool AllowAutoClosurePointerConversion::diagnose(bool asNote) const { auto failure = AutoClosurePointerConversionFailure(getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowAutoClosurePointerConversion * AllowAutoClosurePointerConversion::create(ConstraintSystem &cs, Type pointeeType, Type pointerType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowAutoClosurePointerConversion(cs, pointeeType, pointerType, locator); } bool RemoveUnwrap::diagnose(bool asNote) const { auto failure = NonOptionalUnwrapFailure(getConstraintSystem(), BaseType, getLocator()); return failure.diagnose(asNote); } RemoveUnwrap *RemoveUnwrap::create(ConstraintSystem &cs, Type baseType, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveUnwrap(cs, baseType, locator); } bool InsertExplicitCall::diagnose(bool asNote) const { auto failure = MissingCallFailure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } InsertExplicitCall *InsertExplicitCall::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) InsertExplicitCall(cs, locator); } bool UsePropertyWrapper::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); auto failure = ExtraneousPropertyWrapperUnwrapFailure( cs, Wrapped, UsingStorageWrapper, Base, Wrapper, getLocator()); return failure.diagnose(asNote); } UsePropertyWrapper *UsePropertyWrapper::create(ConstraintSystem &cs, VarDecl *wrapped, bool usingStorageWrapper, Type base, Type wrapper, ConstraintLocator *locator) { return new (cs.getAllocator()) UsePropertyWrapper( cs, wrapped, usingStorageWrapper, base, wrapper, locator); } bool UseWrappedValue::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); auto failure = MissingPropertyWrapperUnwrapFailure( cs, PropertyWrapper, usingStorageWrapper(), Base, Wrapper, getLocator()); return failure.diagnose(asNote); } UseWrappedValue *UseWrappedValue::create(ConstraintSystem &cs, VarDecl *propertyWrapper, Type base, Type wrapper, ConstraintLocator *locator) { return new (cs.getAllocator()) UseWrappedValue(cs, propertyWrapper, base, wrapper, locator); } bool UseSubscriptOperator::diagnose(bool asNote) const { auto failure = SubscriptMisuseFailure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } UseSubscriptOperator *UseSubscriptOperator::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) UseSubscriptOperator(cs, locator); } bool DefineMemberBasedOnUse::diagnose(bool asNote) const { auto failure = MissingMemberFailure(getConstraintSystem(), BaseType, Name, getLocator()); return failure.diagnose(asNote); } DefineMemberBasedOnUse * DefineMemberBasedOnUse::create(ConstraintSystem &cs, Type baseType, DeclNameRef member, ConstraintLocator *locator) { return new (cs.getAllocator()) DefineMemberBasedOnUse(cs, baseType, member, locator); } AllowMemberRefOnExistential * AllowMemberRefOnExistential::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef memberName, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowMemberRefOnExistential(cs, baseType, memberName, member, locator); } bool AllowMemberRefOnExistential::diagnose(bool asNote) const { auto failure = InvalidMemberRefOnExistential(getConstraintSystem(), getBaseType(), getMemberName(), getLocator()); return failure.diagnose(asNote); } bool AllowTypeOrInstanceMember::diagnose(bool asNote) const { auto failure = AllowTypeOrInstanceMemberFailure( getConstraintSystem(), getBaseType(), getMember(), getMemberName(), getLocator()); return failure.diagnose(asNote); } AllowTypeOrInstanceMember * AllowTypeOrInstanceMember::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef usedName, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowTypeOrInstanceMember(cs, baseType, member, usedName, locator); } bool AllowInvalidPartialApplication::diagnose(bool asNote) const { auto failure = PartialApplicationFailure(isWarning(), getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } AllowInvalidPartialApplication * AllowInvalidPartialApplication::create(bool isWarning, ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidPartialApplication(isWarning, cs, locator); } bool AllowInvalidInitRef::diagnose(bool asNote) const { switch (Kind) { case RefKind::DynamicOnMetatype: { InvalidDynamicInitOnMetatypeFailure failure( getConstraintSystem(), BaseType, Init, BaseRange, getLocator()); return failure.diagnose(asNote); } case RefKind::ProtocolMetatype: { InitOnProtocolMetatypeFailure failure(getConstraintSystem(), BaseType, Init, IsStaticallyDerived, BaseRange, getLocator()); return failure.diagnose(asNote); } case RefKind::NonConstMetatype: { ImplicitInitOnNonConstMetatypeFailure failure(getConstraintSystem(), BaseType, Init, getLocator()); return failure.diagnose(asNote); } } llvm_unreachable("covered switch"); } AllowInvalidInitRef *AllowInvalidInitRef::dynamicOnMetatype( ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, SourceRange baseRange, ConstraintLocator *locator) { return create(RefKind::DynamicOnMetatype, cs, baseTy, init, /*isStaticallyDerived=*/false, baseRange, locator); } AllowInvalidInitRef *AllowInvalidInitRef::onProtocolMetatype( ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator) { return create(RefKind::ProtocolMetatype, cs, baseTy, init, isStaticallyDerived, baseRange, locator); } AllowInvalidInitRef * AllowInvalidInitRef::onNonConstMetatype(ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, ConstraintLocator *locator) { return create(RefKind::NonConstMetatype, cs, baseTy, init, /*isStaticallyDerived=*/false, SourceRange(), locator); } AllowInvalidInitRef * AllowInvalidInitRef::create(RefKind kind, ConstraintSystem &cs, Type baseTy, ConstructorDecl *init, bool isStaticallyDerived, SourceRange baseRange, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidInitRef( cs, kind, baseTy, init, isStaticallyDerived, baseRange, locator); } bool AllowClosureParamDestructuring::diagnose(bool asNote) const { ClosureParamDestructuringFailure failure(getConstraintSystem(), ContextualType, getLocator()); return failure.diagnose(asNote); } AllowClosureParamDestructuring * AllowClosureParamDestructuring::create(ConstraintSystem &cs, FunctionType *contextualType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowClosureParamDestructuring(cs, contextualType, locator); } bool AddMissingArguments::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); MissingArgumentsFailure failure(cs, getSynthesizedArguments(), getLocator()); return failure.diagnose(asNote); } AddMissingArguments * AddMissingArguments::create(ConstraintSystem &cs, llvm::ArrayRef synthesizedArgs, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(synthesizedArgs.size()); void *mem = cs.getAllocator().Allocate(size, alignof(AddMissingArguments)); return new (mem) AddMissingArguments(cs, synthesizedArgs, locator); } bool RemoveExtraneousArguments::diagnose(bool asNote) const { ExtraneousArgumentsFailure failure(getConstraintSystem(), ContextualType, getExtraArguments(), getLocator()); return failure.diagnose(asNote); } bool RemoveExtraneousArguments::isMinMaxNameShadowing( ConstraintSystem &cs, ConstraintLocatorBuilder locator) { auto *anchor = dyn_cast_or_null(locator.getAnchor()); if (!anchor) return false; if (auto *UDE = dyn_cast(anchor->getFn())) { if (auto *baseExpr = dyn_cast(UDE->getBase())) { auto *decl = baseExpr->getDecl(); if (baseExpr->isImplicit() && decl && decl->getFullName() == cs.getASTContext().Id_self) { auto memberName = UDE->getName(); return memberName.isSimpleName("min") || memberName.isSimpleName("max"); } } } return false; } RemoveExtraneousArguments *RemoveExtraneousArguments::create( ConstraintSystem &cs, FunctionType *contextualType, llvm::ArrayRef extraArgs, ConstraintLocator *locator) { unsigned size = totalSizeToAlloc(extraArgs.size()); void *mem = cs.getAllocator().Allocate(size, alignof(RemoveExtraneousArguments)); return new (mem) RemoveExtraneousArguments(cs, contextualType, extraArgs, locator); } bool MoveOutOfOrderArgument::diagnose(bool asNote) const { OutOfOrderArgumentFailure failure(getConstraintSystem(), ArgIdx, PrevArgIdx, Bindings, getLocator()); return failure.diagnose(asNote); } MoveOutOfOrderArgument *MoveOutOfOrderArgument::create( ConstraintSystem &cs, unsigned argIdx, unsigned prevArgIdx, ArrayRef bindings, ConstraintLocator *locator) { return new (cs.getAllocator()) MoveOutOfOrderArgument(cs, argIdx, prevArgIdx, bindings, locator); } bool AllowInaccessibleMember::diagnose(bool asNote) const { InaccessibleMemberFailure failure(getConstraintSystem(), getMember(), getLocator()); return failure.diagnose(asNote); } AllowInaccessibleMember * AllowInaccessibleMember::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInaccessibleMember(cs, baseType, member, name, locator); } bool AllowAnyObjectKeyPathRoot::diagnose(bool asNote) const { AnyObjectKeyPathRootFailure failure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } AllowAnyObjectKeyPathRoot * AllowAnyObjectKeyPathRoot::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowAnyObjectKeyPathRoot(cs, locator); } bool TreatKeyPathSubscriptIndexAsHashable::diagnose(bool asNote) const { KeyPathSubscriptIndexHashableFailure failure(getConstraintSystem(), NonConformingType, getLocator()); return failure.diagnose(asNote); } TreatKeyPathSubscriptIndexAsHashable * TreatKeyPathSubscriptIndexAsHashable::create(ConstraintSystem &cs, Type type, ConstraintLocator *locator) { return new (cs.getAllocator()) TreatKeyPathSubscriptIndexAsHashable(cs, type, locator); } bool AllowInvalidRefInKeyPath::diagnose(bool asNote) const { switch (Kind) { case RefKind::StaticMember: { InvalidStaticMemberRefInKeyPath failure(getConstraintSystem(), Member, getLocator()); return failure.diagnose(asNote); } case RefKind::MutatingGetter: { InvalidMemberWithMutatingGetterInKeyPath failure( getConstraintSystem(), Member, getLocator()); return failure.diagnose(asNote); } case RefKind::Method: { InvalidMethodRefInKeyPath failure(getConstraintSystem(), Member, getLocator()); return failure.diagnose(asNote); } } llvm_unreachable("covered switch"); } AllowInvalidRefInKeyPath * AllowInvalidRefInKeyPath::forRef(ConstraintSystem &cs, ValueDecl *member, ConstraintLocator *locator) { // Referencing (instance or static) methods in key path is // not currently allowed. if (isa(member)) return AllowInvalidRefInKeyPath::create(cs, RefKind::Method, member, locator); // Referencing static members in key path is not currently allowed. if (member->isStatic()) return AllowInvalidRefInKeyPath::create(cs, RefKind::StaticMember, member, locator); if (auto *storage = dyn_cast(member)) { // Referencing members with mutating getters in key path is not // currently allowed. if (storage->isGetterMutating()) return AllowInvalidRefInKeyPath::create(cs, RefKind::MutatingGetter, member, locator); } return nullptr; } AllowInvalidRefInKeyPath * AllowInvalidRefInKeyPath::create(ConstraintSystem &cs, RefKind kind, ValueDecl *member, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidRefInKeyPath(cs, kind, member, locator); } KeyPathContextualMismatch * KeyPathContextualMismatch::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) KeyPathContextualMismatch(cs, lhs, rhs, locator); } bool RemoveAddressOf::diagnose(bool asNote) const { InvalidUseOfAddressOf failure(getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } RemoveAddressOf *RemoveAddressOf::create(ConstraintSystem &cs, Type lhs, Type rhs, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveAddressOf(cs, lhs, rhs, locator); } bool RemoveReturn::diagnose(bool asNote) const { ExtraneousReturnFailure failure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } RemoveReturn *RemoveReturn::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveReturn(cs, locator); } bool CollectionElementContextualMismatch::diagnose(bool asNote) const { CollectionElementContextualFailure failure( getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } CollectionElementContextualMismatch * CollectionElementContextualMismatch::create(ConstraintSystem &cs, Type srcType, Type dstType, ConstraintLocator *locator) { return new (cs.getAllocator()) CollectionElementContextualMismatch(cs, srcType, dstType, locator); } bool DefaultGenericArgument::coalesceAndDiagnose( ArrayRef fixes, bool asNote) const { llvm::SmallVector missingParams{Param}; for (auto *otherFix : fixes) { if (auto *fix = otherFix->getAs()) missingParams.push_back(fix->Param); } auto &cs = getConstraintSystem(); MissingGenericArgumentsFailure failure(cs, missingParams, getLocator()); return failure.diagnose(asNote); } bool DefaultGenericArgument::diagnose(bool asNote) const { return coalesceAndDiagnose({}, asNote); } DefaultGenericArgument * DefaultGenericArgument::create(ConstraintSystem &cs, GenericTypeParamType *param, ConstraintLocator *locator) { return new (cs.getAllocator()) DefaultGenericArgument(cs, param, locator); } SkipUnhandledConstructInFunctionBuilder * SkipUnhandledConstructInFunctionBuilder::create(ConstraintSystem &cs, UnhandledNode unhandled, NominalTypeDecl *builder, ConstraintLocator *locator) { return new (cs.getAllocator()) SkipUnhandledConstructInFunctionBuilder(cs, unhandled, builder, locator); } bool SkipUnhandledConstructInFunctionBuilder::diagnose(bool asNote) const { SkipUnhandledConstructInFunctionBuilderFailure failure( getConstraintSystem(), unhandled, builder, getLocator()); return failure.diagnose(asNote); } bool AllowMutatingMemberOnRValueBase::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); MutatingMemberRefOnImmutableBase failure(cs, getMember(), getLocator()); return failure.diagnose(asNote); } AllowMutatingMemberOnRValueBase * AllowMutatingMemberOnRValueBase::create(ConstraintSystem &cs, Type baseType, ValueDecl *member, DeclNameRef name, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowMutatingMemberOnRValueBase(cs, baseType, member, name, locator); } bool AllowTupleSplatForSingleParameter::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); InvalidTupleSplatWithSingleParameterFailure failure(cs, ParamType, getLocator()); return failure.diagnose(asNote); } bool AllowTupleSplatForSingleParameter::attempt( ConstraintSystem &cs, SmallVectorImpl &args, ArrayRef params, SmallVectorImpl> &bindings, ConstraintLocatorBuilder locator) { if (params.size() != 1 || args.size() <= 1) return true; const auto ¶m = params.front(); if (param.isInOut() || param.isVariadic() || param.isAutoClosure()) return true; auto paramTy = param.getOldType(); // Parameter type has to be either a tuple (with the same arity as // argument list), or a type variable. if (!(paramTy->is() && paramTy->castTo()->getNumElements() == args.size())) return true; SmallVector argElts; for (unsigned index : indices(args)) { const auto &arg = args[index]; auto label = arg.getLabel(); auto flags = arg.getParameterFlags(); // In situations where there is a single labeled parameter // we need to form a tuple which omits the label e.g. // // func foo(x: (T, T)) {} // foo(x: 0, 1) // // We'd want to suggest argument list to be `x: (0, 1)` instead // of `(x: 0, 1)` which would be incorrect. if (param.hasLabel() && label == param.getLabel()) { if (index == 0) { label = Identifier(); } else { // If label match anything other than first argument, // this can't be a tuple splat. return true; } } // Tuple can't have `inout` elements. if (flags.isInOut()) return true; argElts.push_back({arg.getPlainType(), label}); } bindings[0].clear(); bindings[0].push_back(0); auto newArgType = TupleType::get(argElts, cs.getASTContext()); args.clear(); args.push_back(AnyFunctionType::Param(newArgType, param.getLabel())); auto *fix = new (cs.getAllocator()) AllowTupleSplatForSingleParameter( cs, paramTy, cs.getConstraintLocator(locator)); return cs.recordFix(fix); } bool DropThrowsAttribute::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); ThrowingFunctionConversionFailure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } DropThrowsAttribute *DropThrowsAttribute::create(ConstraintSystem &cs, FunctionType *fromType, FunctionType *toType, ConstraintLocator *locator) { return new (cs.getAllocator()) DropThrowsAttribute(cs, fromType, toType, locator); } bool IgnoreContextualType::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); ContextualFailure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } IgnoreContextualType *IgnoreContextualType::create(ConstraintSystem &cs, Type resultTy, Type specifiedTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreContextualType(cs, resultTy, specifiedTy, locator); } bool IgnoreAssignmentDestinationType::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); auto *AE = cast(getAnchor()); // Let's check whether this is a situation of chained assignment where // one of the steps in the chain is an assignment to self e.g. // `let _ = { $0 = $0 = 42 }`. Assignment chaining results in // type mismatch between result of the previous assignment and the next. { llvm::SaveAndRestore anchor(AE); do { if (TypeChecker::diagnoseSelfAssignment(AE)) return true; } while ((AE = dyn_cast_or_null(cs.getParentExpr(AE)))); } auto CTP = isa(AE->getDest()) ? CTP_SubscriptAssignSource : CTP_AssignSource; AssignmentTypeMismatchFailure failure( cs, CTP, getFromType(), getToType(), cs.getConstraintLocator(AE->getSrc(), LocatorPathElt::ContextualType())); return failure.diagnose(asNote); } IgnoreAssignmentDestinationType * IgnoreAssignmentDestinationType::create(ConstraintSystem &cs, Type sourceTy, Type destTy, ConstraintLocator *locator) { return new (cs.getAllocator()) IgnoreAssignmentDestinationType(cs, sourceTy, destTy, locator); } bool AllowInOutConversion::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); InOutConversionFailure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowInOutConversion *AllowInOutConversion::create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInOutConversion(cs, argType, paramType, locator); } /// Check whether given `value` type is indeed a the same type as a `RawValue` /// type of a given raw representable type. static bool isValueOfRawRepresentable(ConstraintSystem &cs, Type rawRepresentableType, Type valueType) { auto rawType = isRawRepresentable(cs, rawRepresentableType); if (!rawType) return false; KnownProtocolKind protocols[] = { KnownProtocolKind::ExpressibleByStringLiteral, KnownProtocolKind::ExpressibleByIntegerLiteral}; for (auto protocol : protocols) { if (conformsToKnownProtocol(cs, valueType, protocol) && valueType->isEqual(rawType)) return true; } return false; } ExpandArrayIntoVarargs * ExpandArrayIntoVarargs::attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder builder) { auto *locator = cs.getConstraintLocator(builder); auto argLoc = locator->getLastElementAs(); if (!(argLoc && argLoc->getParameterFlags().isVariadic())) return nullptr; auto elementType = cs.isArrayType(argType); if (!elementType) return nullptr; ConstraintSystem::TypeMatchOptions options; options |= ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix; options |= ConstraintSystem::TypeMatchFlags::TMF_GenerateConstraints; auto result = cs.matchTypes(*elementType, paramType, ConstraintKind::Subtype, options, builder); if (result.isFailure()) return nullptr; return new (cs.getAllocator()) ExpandArrayIntoVarargs(cs, argType, paramType, locator); } bool ExpandArrayIntoVarargs::diagnose(bool asNote) const { ExpandArrayIntoVarargsFailure failure( getConstraintSystem(), getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } ExplicitlyConstructRawRepresentable * ExplicitlyConstructRawRepresentable::attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder locator) { auto rawRepresentableType = paramType->lookThroughAllOptionalTypes(); auto valueType = argType->lookThroughAllOptionalTypes(); if (isValueOfRawRepresentable(cs, rawRepresentableType, valueType)) return new (cs.getAllocator()) ExplicitlyConstructRawRepresentable( cs, valueType, rawRepresentableType, cs.getConstraintLocator(locator)); return nullptr; } UseValueTypeOfRawRepresentative * UseValueTypeOfRawRepresentative::attempt(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocatorBuilder locator) { auto rawRepresentableType = argType->lookThroughAllOptionalTypes(); auto valueType = paramType->lookThroughAllOptionalTypes(); if (isValueOfRawRepresentable(cs, rawRepresentableType, valueType)) return new (cs.getAllocator()) UseValueTypeOfRawRepresentative( cs, rawRepresentableType, valueType, cs.getConstraintLocator(locator)); return nullptr; } bool AllowArgumentMismatch::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); ArgumentMismatchFailure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowArgumentMismatch * AllowArgumentMismatch::create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowArgumentMismatch(cs, argType, paramType, locator); } bool RemoveInvalidCall::diagnose(bool asNote) const { ExtraneousCallFailure failure(getConstraintSystem(), getLocator()); return failure.diagnose(asNote); } RemoveInvalidCall *RemoveInvalidCall::create(ConstraintSystem &cs, ConstraintLocator *locator) { return new (cs.getAllocator()) RemoveInvalidCall(cs, locator); } bool AllowInvalidUseOfTrailingClosure::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); InvalidUseOfTrailingClosure failure(cs, getFromType(), getToType(), getLocator()); return failure.diagnose(asNote); } AllowInvalidUseOfTrailingClosure * AllowInvalidUseOfTrailingClosure::create(ConstraintSystem &cs, Type argType, Type paramType, ConstraintLocator *locator) { return new (cs.getAllocator()) AllowInvalidUseOfTrailingClosure(cs, argType, paramType, locator); } bool TreatEphemeralAsNonEphemeral::diagnose(bool asNote) const { NonEphemeralConversionFailure failure( getConstraintSystem(), getLocator(), getFromType(), getToType(), ConversionKind, isWarning()); return failure.diagnose(asNote); } TreatEphemeralAsNonEphemeral *TreatEphemeralAsNonEphemeral::create( ConstraintSystem &cs, ConstraintLocator *locator, Type srcType, Type dstType, ConversionRestrictionKind conversionKind, bool downgradeToWarning) { return new (cs.getAllocator()) TreatEphemeralAsNonEphemeral( cs, locator, srcType, dstType, conversionKind, downgradeToWarning); } std::string TreatEphemeralAsNonEphemeral::getName() const { std::string name; name += "treat ephemeral as non-ephemeral for "; name += ::getName(ConversionKind); return name; } bool SpecifyBaseTypeForContextualMember::diagnose(bool asNote) const { auto &cs = getConstraintSystem(); MissingContextualBaseInMemberRefFailure failure(cs, MemberName, getLocator()); return failure.diagnose(asNote); } SpecifyBaseTypeForContextualMember *SpecifyBaseTypeForContextualMember::create( ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator) { return new (cs.getAllocator()) SpecifyBaseTypeForContextualMember(cs, member, locator); }