diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 786fb1e33c9d4..0ea70a2421b27 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -3068,7 +3068,7 @@ class ConstraintSystem { return nullptr; } - TypeBase* getFavoredType(Expr *E) { + TypeBase *getFavoredType(Expr *E) { assert(E != nullptr); return this->FavoredTypes[E]; } @@ -3082,39 +3082,15 @@ class ConstraintSystem { /// /// The side tables are used through the expression type checker to avoid /// mutating nodes until we know we have successfully type-checked them. - void setType(ASTNode node, Type type) { - ASSERT(!node.isNull() && "Cannot set type information on null node"); - ASSERT(type && "Expected non-null type"); - - // Record the type. - Type &entry = NodeTypes[node]; - Type oldType = entry; - entry = type; - - if (oldType.getPointer() != type.getPointer()) { - // Record the fact that we assigned a type to this node. - if (solverState) - recordChange(SolverTrail::Change::RecordedNodeType(node, oldType)); - } - } + void setType(ASTNode node, Type type, + PreparedOverloadBuilder *preparedOverload=nullptr); /// Undo the above change. - void restoreType(ASTNode node, Type oldType) { - ASSERT(!node.isNull() && "Cannot set type information on null node"); - - if (oldType) { - auto found = NodeTypes.find(node); - ASSERT(found != NodeTypes.end()); - found->second = oldType; - } else { - bool erased = NodeTypes.erase(node); - ASSERT(erased); - } - } + void restoreType(ASTNode node, Type oldType); /// Check to see if we have a type for a node. bool hasType(ASTNode node) const { - assert(!node.isNull() && "Expected non-null node"); + ASSERT(!node.isNull() && "Expected non-null node"); return NodeTypes.count(node) > 0; } @@ -3122,55 +3098,30 @@ class ConstraintSystem { /// map is used throughout the expression type checker in order to /// avoid mutating expressions until we know we have successfully /// type-checked them. - void setType(const KeyPathExpr *KP, unsigned I, Type T) { - ASSERT(KP && "Expected non-null key path parameter!"); - ASSERT(T && "Expected non-null type!"); - - Type &entry = KeyPathComponentTypes[{KP, I}]; - Type oldType = entry; - entry = T; + void setType(const KeyPathExpr *KP, unsigned I, Type T); - if (oldType.getPointer() != T.getPointer()) { - if (solverState) { - recordChange( - SolverTrail::Change::RecordedKeyPathComponentType( - KP, I, oldType)); - } - } - } - - void restoreType(const KeyPathExpr *KP, unsigned I, Type T) { - ASSERT(KP && "Expected non-null key path parameter!"); - - if (T) { - auto found = KeyPathComponentTypes.find({KP, I}); - ASSERT(found != KeyPathComponentTypes.end()); - found->second = T; - } else { - bool erased = KeyPathComponentTypes.erase({KP, I}); - ASSERT(erased); - } - } + void restoreType(const KeyPathExpr *KP, unsigned I, Type T); bool hasType(const KeyPathExpr *KP, unsigned I) const { - assert(KP && "Expected non-null key path parameter!"); + ASSERT(KP && "Expected non-null key path parameter!"); return KeyPathComponentTypes.find(std::make_pair(KP, I)) != KeyPathComponentTypes.end(); } /// Get the type for an node. Type getType(ASTNode node) const { - assert(hasType(node) && "Expected type to have been set!"); - // FIXME: lvalue differences - // assert((!E->getType() || - // E->getType()->isEqual(ExprTypes.find(E)->second)) && - // "Mismatched types!"); - return NodeTypes.find(node)->second; + ASSERT(!node.isNull() && "Expected non-null node"); + auto found = NodeTypes.find(node); + ASSERT(found != NodeTypes.end() && "Expected type to have been set!"); + return found->second; } Type getType(const KeyPathExpr *KP, unsigned I) const { - assert(hasType(KP, I) && "Expected type to have been set!"); - return KeyPathComponentTypes.find(std::make_pair(KP, I))->second; + ASSERT(KP && "Expected non-null key path parameter!"); + auto found = KeyPathComponentTypes.find(std::make_pair(KP, I)); + ASSERT(found != KeyPathComponentTypes.end() && + "Expected type to have been set!"); + return found->second; } /// Retrieve the type of the node, if known. @@ -3182,11 +3133,6 @@ class ConstraintSystem { return known->second; } - /// Retrieve type of the given declaration to be used in - /// constraint system, this is better than calling `getType()` - /// directly because it accounts of constraint system flags. - Type getVarType(const VarDecl *var); - /// Cache the type of the expression argument and return that same /// argument. template @@ -3795,7 +3741,7 @@ class ConstraintSystem { /// Add a constraint that binds an overload set to a specific choice. void addBindOverloadConstraint(Type boundTy, OverloadChoice choice, ConstraintLocator *locator, DeclContext *useDC) { - resolveOverload(locator, boundTy, choice, useDC, + resolveOverload(choice, useDC, locator, boundTy, /*preparedOverload=*/nullptr); } @@ -4437,8 +4383,7 @@ class ConstraintSystem { FunctionType *adjustFunctionTypeForConcurrency( FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc, unsigned numApplies, bool isMainDispatchQueue, - ArrayRef replacements, ConstraintLocatorBuilder locator, - PreparedOverloadBuilder *preparedOverload); + bool openGlobalActorType, ConstraintLocatorBuilder locator); /// Retrieve the type of a reference to the given value declaration. /// @@ -4446,15 +4391,10 @@ class ConstraintSystem { /// the type by replacing each instance of an archetype with a fresh type /// variable. /// - /// \param decl The declarations whose type is being computed. - /// /// \returns a description of the type of this declaration reference. DeclReferenceType getTypeOfReference( - ValueDecl *decl, - FunctionRefInfo functionRefInfo, - ConstraintLocatorBuilder locator, - DeclContext *useDC, - PreparedOverloadBuilder *preparedOverload); + OverloadChoice choice, DeclContext *useDC, ConstraintLocatorBuilder locator, + PreparedOverloadBuilder *preparedOverload); /// Retrieve the type of a reference to the given value declaration, /// as a member with a base of the given type. @@ -4463,15 +4403,10 @@ class ConstraintSystem { /// this routine "opens up" the type by replacing each instance of a generic /// parameter with a fresh type variable. /// - /// \param isDynamicLookup Indicates that this declaration was found via - /// dynamic lookup. - /// /// \returns a description of the type of this declaration reference. DeclReferenceType getTypeOfMemberReference( - Type baseTy, ValueDecl *decl, DeclContext *useDC, bool isDynamicLookup, - FunctionRefInfo functionRefInfo, ConstraintLocator *locator, - SmallVectorImpl *replacements = nullptr, - PreparedOverloadBuilder *preparedOverload = nullptr); + OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator, + PreparedOverloadBuilder *preparedOverload); /// Retrieve a list of generic parameter types solver has "opened" (replaced /// with a type variable) at the given location. @@ -4483,7 +4418,25 @@ class ConstraintSystem { } private: - DeclReferenceType getTypeOfMemberTypeReference( + /// \returns The opened type and the thrown error type. + std::pair getTypeOfReferencePre( + OverloadChoice choice, DeclContext *useDC, ConstraintLocatorBuilder locator, + PreparedOverloadBuilder *preparedOverload); + + DeclReferenceType getTypeOfReferencePost( + OverloadChoice choice, DeclContext *useDC, ConstraintLocatorBuilder locator, + Type openedType, Type thrownErrorType); + + /// \returns the opened type and the thrown error type. + std::pair getTypeOfMemberReferencePre( + OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator, + PreparedOverloadBuilder *preparedOverload); + + DeclReferenceType getTypeOfMemberReferencePost( + OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator, + Type openedType, Type thrownErrorType); + + Type getTypeOfMemberTypeReference( Type baseObjTy, TypeDecl *typeDecl, ConstraintLocator *locator, PreparedOverloadBuilder *preparedOverload); @@ -4513,8 +4466,7 @@ class ConstraintSystem { /// determine the reference type of the member reference. Type getMemberReferenceTypeFromOpenedType( Type type, Type baseObjTy, ValueDecl *value, - ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup, - ArrayRef replacements); + ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup); /// Add the constraints needed to bind an overload's type variable. void bindOverloadType(const SelectedOverload &overload, Type boundType, @@ -4918,17 +4870,22 @@ class ConstraintSystem { SelectedOverload choice); /// Build and allocate a prepared overload in the solver arena. - PreparedOverload *prepareOverload(ConstraintLocator *locator, - OverloadChoice choice, - DeclContext *useDC); + PreparedOverload *prepareOverload(OverloadChoice choice, + DeclContext *useDC, + ConstraintLocator *locator); /// Populate the prepared overload with all type variables and constraints /// that are to be introduced into the constraint system when this choice /// is taken. - DeclReferenceType - prepareOverloadImpl(ConstraintLocator *locator, - OverloadChoice choice, + /// + /// Returns a pair consisting of the opened type, and the thrown error type. + /// + /// FIXME: As a transitional mechanism, if preparedOverload is nullptr, this + /// immediately performs all operations. + std::pair + prepareOverloadImpl(OverloadChoice choice, DeclContext *useDC, + ConstraintLocator *locator, PreparedOverloadBuilder *preparedOverload); void replayChanges( @@ -4936,8 +4893,8 @@ class ConstraintSystem { PreparedOverload *preparedOverload); /// Resolve the given overload set to the given choice. - void resolveOverload(ConstraintLocator *locator, Type boundType, - OverloadChoice choice, DeclContext *useDC, + void resolveOverload(OverloadChoice choice, DeclContext *useDC, + ConstraintLocator *locator, Type boundType, PreparedOverload *preparedOverload); /// Simplify a type, by replacing type variables with either their diff --git a/include/swift/Sema/OverloadChoice.h b/include/swift/Sema/OverloadChoice.h index b86d736368c5d..e1b4f0643b2f4 100644 --- a/include/swift/Sema/OverloadChoice.h +++ b/include/swift/Sema/OverloadChoice.h @@ -126,20 +126,19 @@ class OverloadChoice { /// FIXME: This needs three bits. Can we pack them somewhere? FunctionRefInfo TheFunctionRefInfo = FunctionRefInfo::unappliedBaseName(); -public: - OverloadChoice() : BaseAndDeclKind(nullptr, 0), DeclOrKind() {} - OverloadChoice(Type base, ValueDecl *value, FunctionRefInfo functionRefInfo) : BaseAndDeclKind(base, 0), TheFunctionRefInfo(functionRefInfo) { - assert(!base || !base->hasTypeParameter()); assert((reinterpret_cast(value) & (uintptr_t)0x03) == 0 && "Badly aligned decl"); DeclOrKind = value; } +public: + OverloadChoice() : BaseAndDeclKind(nullptr, 0), DeclOrKind() {} + OverloadChoice(Type base, OverloadChoiceKind kind) : BaseAndDeclKind(base, 0), DeclOrKind(uint32_t(kind)) { assert(base && "Must have a base type for overload choice"); @@ -162,6 +161,22 @@ class OverloadChoice { BaseAndDeclKind.getInt() == 0 && DeclOrKind.isNull(); } + /// Retrieve an overload choice for a declaration that was found via + /// unqualified lookup. + static OverloadChoice getDecl(ValueDecl *value, + FunctionRefInfo functionRefInfo) { + return OverloadChoice(Type(), value, functionRefInfo); + } + + + /// Retrieve an overload choice for a declaration that was found via + /// qualified lookup. + static OverloadChoice getDecl(Type base, ValueDecl *value, + FunctionRefInfo functionRefInfo) { + ASSERT(!base->hasTypeParameter()); + return OverloadChoice(base, value, functionRefInfo); + } + /// Retrieve an overload choice for a declaration that was found via /// dynamic lookup. static OverloadChoice getDeclViaDynamic(Type base, ValueDecl *value, diff --git a/include/swift/Sema/PreparedOverload.h b/include/swift/Sema/PreparedOverload.h index a3253fbc351c9..0d678214a6126 100644 --- a/include/swift/Sema/PreparedOverload.h +++ b/include/swift/Sema/PreparedOverload.h @@ -88,7 +88,10 @@ struct PreparedOverloadChange { AppliedPropertyWrapper, /// A fix was recorded because a property wrapper application failed. - AddedFix + AddedFix, + + /// The type of an AST node was changed. + RecordedNodeType }; /// The kind of change. @@ -132,7 +135,17 @@ struct PreparedOverloadChange { ConstraintFix *TheFix; unsigned Impact; } Fix; + + /// For ChangeKind::RecordedNodeType. + struct { + ASTNode Node; + Type TheType; + } Node; }; + + PreparedOverloadChange() + : Kind(ChangeKind::AddedTypeVariable), + TypeVar(nullptr) { } }; /// A "pre-cooked" representation of all type variables and constraints @@ -144,38 +157,29 @@ class PreparedOverload final : using Change = PreparedOverloadChange; private: + Type OpenedType; + Type ThrownErrorType; size_t Count; - DeclReferenceType DeclType; size_t numTrailingObjects(OverloadToken) const { return Count; } public: - PreparedOverload(const DeclReferenceType &declType, ArrayRef changes) - : Count(changes.size()), DeclType(declType) { + PreparedOverload(Type openedType, Type thrownErrorType, + ArrayRef changes) + : OpenedType(openedType), ThrownErrorType(thrownErrorType), + Count(changes.size()) { std::uninitialized_copy(changes.begin(), changes.end(), getTrailingObjects()); } Type getOpenedType() const { - return DeclType.openedType; - } - - Type getAdjustedOpenedType() const { - return DeclType.adjustedOpenedType; - } - - Type getReferenceType() const { - return DeclType.referenceType; - } - - Type getAdjustedReferenceType() const { - return DeclType.adjustedReferenceType; + return OpenedType; } - Type getThrownErrorTypeOnAccess() const { - return DeclType.thrownErrorTypeOnAccess; + Type getThrownErrorType() const { + return ThrownErrorType; } ArrayRef getChanges() const { @@ -247,6 +251,14 @@ struct PreparedOverloadBuilder { change.Fix.Impact = impact; Changes.push_back(change); } + + void recordedNodeType(ASTNode node, Type type) { + PreparedOverload::Change change; + change.Kind = PreparedOverload::Change::RecordedNodeType; + change.Node.Node = node; + change.Node.TheType = type; + Changes.push_back(change); + } }; } // end namespace constraints diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index 2a8b50dc1a9fc..c4e76f309168b 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -2465,9 +2465,10 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { const auto &declRef = SE->getDecl(); if (auto *subscript = dyn_cast_or_null(declRef.getDecl())) { - if (isImmutable(subscript)) - return {expr, OverloadChoice(getType(SE->getBase()), subscript, - FunctionRefInfo::doubleBaseNameApply())}; + if (isImmutable(subscript)) { + return {expr, OverloadChoice::getDecl(getType(SE->getBase()), subscript, + FunctionRefInfo::doubleBaseNameApply())}; + } } } @@ -2522,8 +2523,8 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { // If the member isn't settable, then it is the problem: return it. if (auto member = dyn_cast(MRE->getMember().getDecl())) if (isImmutable(member)) - return {expr, OverloadChoice(getType(MRE->getBase()), member, - FunctionRefInfo::singleBaseNameApply())}; + return {expr, OverloadChoice::getDecl(getType(MRE->getBase()), member, + FunctionRefInfo::singleBaseNameApply())}; // If we weren't able to resolve a member or if it is mutable, then the // problem must be with the base, recurse. @@ -2543,8 +2544,8 @@ AssignmentFailure::resolveImmutableBase(Expr *expr) const { } if (auto *DRE = dyn_cast(expr)) - return {expr, OverloadChoice(Type(), DRE->getDecl(), - FunctionRefInfo::unappliedBaseName())}; + return {expr, OverloadChoice::getDecl(DRE->getDecl(), + FunctionRefInfo::unappliedBaseName())}; // Look through x! if (auto *FVE = dyn_cast(expr)) diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 7bf1eb08330d1..56ce4b28d47e9 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1020,7 +1020,7 @@ namespace { options); SmallVector outerChoices; for (auto decl : outerAlternatives) { - outerChoices.push_back(OverloadChoice(Type(), decl, functionRefInfo)); + outerChoices.push_back(OverloadChoice::getDecl(decl, functionRefInfo)); } CS.addValueMemberConstraint( baseTy, name, tv, CurDC, functionRefInfo, outerChoices, @@ -1044,8 +1044,8 @@ namespace { auto tv = CS.createTypeVariable(memberLocator, TVO_CanBindToLValue | TVO_CanBindToNoEscape); - OverloadChoice choice = - OverloadChoice(CS.getType(base), decl, functionRefInfo); + auto choice = + OverloadChoice::getDecl(CS.getType(base), decl, functionRefInfo); auto locator = CS.getConstraintLocator(expr, ConstraintLocator::Member); CS.addBindOverloadConstraint(tv, choice, locator, CurDC); @@ -1162,7 +1162,7 @@ namespace { // a known subscript here. This might be cleaner if we split off a new // UnresolvedSubscriptExpr from SubscriptExpr. if (auto decl = declOrNull) { - OverloadChoice choice = OverloadChoice( + auto choice = OverloadChoice::getDecl( baseTy, decl, FunctionRefInfo::doubleBaseNameApply()); CS.addBindOverloadConstraint(memberTy, choice, memberLocator, CurDC); @@ -1657,8 +1657,8 @@ namespace { // resolve it. This records the overload for use later. auto tv = CS.createTypeVariable(locator, options); - OverloadChoice choice = - OverloadChoice(Type(), E->getDecl(), E->getFunctionRefInfo()); + auto choice = + OverloadChoice::getDecl(E->getDecl(), E->getFunctionRefInfo()); CS.addBindOverloadConstraint(tv, choice, locator, CurDC); return tv; } @@ -1775,8 +1775,8 @@ namespace { if (decls[i]->isInvalid()) continue; - OverloadChoice choice = - OverloadChoice(Type(), decls[i], expr->getFunctionRefInfo()); + auto choice = + OverloadChoice::getDecl(decls[i], expr->getFunctionRefInfo()); choices.push_back(choice); } @@ -2811,6 +2811,9 @@ namespace { // interface type request via `var->getType()` that would // attempt to validate `weak` attribute, and produce a // diagnostic in the middle of the solver path. + // + // FIXME: getVarType() is now gone. Is the above still + // relevant? CS.addConstraint(ConstraintKind::OneWayEqual, oneWayVarType, varType, locator); @@ -4120,7 +4123,7 @@ namespace { // logic. if (result->isInvalid()) continue; - OverloadChoice choice = OverloadChoice(Type(), result, functionRefInfo); + auto choice = OverloadChoice::getDecl(result, functionRefInfo); choices.push_back(choice); } @@ -5241,7 +5244,8 @@ ConstraintSystem::applyPropertyWrapperToParameter( locator, /*isFavored=*/false, preparedOverload); - setType(param->getPropertyWrapperWrappedValueVar(), wrappedValueType); + setType(param->getPropertyWrapperWrappedValueVar(), wrappedValueType, + preparedOverload); applyPropertyWrapper(anchor, { wrapperType, PropertyWrapperInitKind::WrappedValue }, diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index fa4ca09341de8..976138a71b4f3 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -10491,8 +10491,8 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, auto choice = instanceTy->isAnyObject() ? candidate - : OverloadChoice(instanceTy, decl, - FunctionRefInfo::singleBaseNameApply()); + : OverloadChoice::getDecl(instanceTy, decl, + FunctionRefInfo::singleBaseNameApply()); const bool invalidMethodRef = isa(decl) && !hasInstanceMethods; const bool invalidMemberRef = !isa(decl) && !hasInstanceMembers; @@ -10727,7 +10727,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName, } } - return OverloadChoice(baseTy, cand, functionRefInfo); + return OverloadChoice::getDecl(baseTy, cand, functionRefInfo); }; // Add all results from this lookup. @@ -11866,7 +11866,8 @@ ConstraintSystem::simplifyValueWitnessConstraint( if (!witness) return fail(); - auto choice = OverloadChoice(resolvedBaseType, witness.getDecl(), functionRefInfo); + auto choice = OverloadChoice::getDecl( + resolvedBaseType, witness.getDecl(), functionRefInfo); addBindOverloadConstraint(memberType, choice, getConstraintLocator(locator), useDC); return SolutionKind::Solved; @@ -14110,8 +14111,8 @@ ConstraintSystem::simplifyDynamicCallableApplicableFnConstraint( SmallVector choices; for (auto candidate : candidates) { if (candidate->isInvalid()) continue; - choices.push_back(OverloadChoice(type2, candidate, - FunctionRefInfo::singleBaseNameApply())); + choices.push_back(OverloadChoice::getDecl(type2, candidate, + FunctionRefInfo::singleBaseNameApply())); } if (choices.empty()) { @@ -16742,16 +16743,17 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) { if (!preparedOverload) { if (enablePreparedOverloads && constraint.getOverloadChoice().canBePrepared()) { - preparedOverload = prepareOverload(constraint.getLocator(), - constraint.getOverloadChoice(), - constraint.getDeclContext()); + preparedOverload = prepareOverload(constraint.getOverloadChoice(), + constraint.getDeclContext(), + constraint.getLocator()); const_cast(constraint).setPreparedOverload(preparedOverload); } } - resolveOverload(constraint.getLocator(), constraint.getFirstType(), - constraint.getOverloadChoice(), + resolveOverload(constraint.getOverloadChoice(), constraint.getDeclContext(), + constraint.getLocator(), + constraint.getFirstType(), preparedOverload); return SolutionKind::Solved; } diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 6d6452dd48af9..e6d462f004f1a 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -905,6 +905,73 @@ ConstraintLocator *ConstraintSystem::getOpenOpaqueLocator( { LocatorPathElt::OpenedOpaqueArchetype(opaqueDecl) }, 0); } +void ConstraintSystem::setType(ASTNode node, Type type, + PreparedOverloadBuilder *preparedOverload) { + ASSERT(PreparingOverload == !!preparedOverload); + + ASSERT(!node.isNull() && "Cannot set type information on null node"); + ASSERT(type && "Expected non-null type"); + + if (preparedOverload) { + preparedOverload->recordedNodeType(node, type); + return; + } + + // Record the type. + Type &entry = NodeTypes[node]; + Type oldType = entry; + entry = type; + + if (oldType.getPointer() != type.getPointer()) { + // Record the fact that we assigned a type to this node. + if (solverState) + recordChange(SolverTrail::Change::RecordedNodeType(node, oldType)); + } +} + +void ConstraintSystem::restoreType(ASTNode node, Type oldType) { + ASSERT(!node.isNull() && "Cannot set type information on null node"); + + if (oldType) { + auto found = NodeTypes.find(node); + ASSERT(found != NodeTypes.end()); + found->second = oldType; + } else { + bool erased = NodeTypes.erase(node); + ASSERT(erased); + } +} + +void ConstraintSystem::setType(const KeyPathExpr *KP, unsigned I, Type T) { + ASSERT(KP && "Expected non-null key path parameter!"); + ASSERT(T && "Expected non-null type!"); + + Type &entry = KeyPathComponentTypes[{KP, I}]; + Type oldType = entry; + entry = T; + + if (oldType.getPointer() != T.getPointer()) { + if (solverState) { + recordChange( + SolverTrail::Change::RecordedKeyPathComponentType( + KP, I, oldType)); + } + } +} + +void ConstraintSystem::restoreType(const KeyPathExpr *KP, unsigned I, Type T) { + ASSERT(KP && "Expected non-null key path parameter!"); + + if (T) { + auto found = KeyPathComponentTypes.find({KP, I}); + ASSERT(found != KeyPathComponentTypes.end()); + found->second = T; + } else { + bool erased = KeyPathComponentTypes.erase({KP, I}); + ASSERT(erased); + } +} + std::pair ConstraintSystem::openAnyExistentialType(Type type, ConstraintLocator *locator) { @@ -3441,8 +3508,10 @@ void OpenGenericTypeRequirements::operator()(GenericTypeDecl *decl, cs.recordOpenedTypes(locator, replacements, preparedOverload, /*fixmeAllowDuplicates*/ true); - for (auto [gp, typeVar] : replacements) - cs.addConstraint(ConstraintKind::Bind, typeVar, subst(gp), locator); + for (auto [gp, typeVar] : replacements) { + cs.addConstraint(ConstraintKind::Bind, typeVar, subst(gp), locator, + /*isFavored=*/false, preparedOverload); + } auto openType = [&](Type ty) -> Type { return cs.openType(ty, replacements, locator, preparedOverload); @@ -4325,15 +4394,9 @@ Type constraints::getConcreteReplacementForProtocolSelfType(ValueDecl *member) { if (!DC->getSelfProtocolDecl()) return Type(); - GenericSignature signature; - if (auto *genericContext = member->getAsGenericContext()) { - signature = genericContext->getGenericSignature(); - } else { - signature = DC->getGenericSignatureOfContext(); - } - + auto sig = member->getInnermostDeclContext()->getGenericSignatureOfContext(); auto selfTy = DC->getSelfInterfaceType(); - return signature->getConcreteType(selfTy); + return sig->getConcreteType(selfTy); } static bool isOperator(Expr *expr, StringRef expectedName) { diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index 0418ad790ca95..bb0e1b2d377d9 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -4005,8 +4005,7 @@ VarDeclUsageChecker::~VarDeclUsageChecker() { if (!(access & RK_Defined)) continue; - if (auto *caseStmt = - dyn_cast_or_null(var->getRecursiveParentPatternStmt())) { + if (isa_and_nonnull(var->getRecursiveParentPatternStmt())) { // Only diagnose for the parent-most VarDecl. if (var->getParentVarDecl()) continue; diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index e95f6e74831cd..3f5b32c24845b 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -1168,21 +1168,22 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache, Type selfTy = proto->getSelfInterfaceType().subst(reqSubMap); // Open up the type of the requirement. - SmallVector reqReplacements; - reqLocator = cs->getConstraintLocator(req, ConstraintLocator::ProtocolRequirement); - reqType = - cs->getTypeOfMemberReference(selfTy, req, dc, - /*isDynamicResult=*/false, - FunctionRefInfo::doubleBaseNameApply(), - reqLocator, &reqReplacements) - .adjustedReferenceType; + auto reqChoice = OverloadChoice::getDecl( + selfTy, req, FunctionRefInfo::doubleBaseNameApply()); + auto reqTypeInfo = + cs->getTypeOfMemberReference(reqChoice, dc, reqLocator, + /*preparedOverload=*/nullptr); + + reqType = reqTypeInfo.adjustedReferenceType; reqType = reqType->getRValueType(); + Type reqThrownError = reqTypeInfo.thrownErrorTypeOnAccess; + // For any type parameters we replaced in the witness, map them // to the corresponding archetypes in the witness's context. - for (const auto &replacement : reqReplacements) { + for (const auto &replacement : cs->getOpenedTypes(reqLocator)) { auto replacedInReq = Type(replacement.first).subst(reqSubMap); // If substitution failed, skip the requirement. This only occurs in @@ -1200,55 +1201,30 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache, } // Open up the witness type. - SmallVector witnessReplacements; - witnessType = witness->getInterfaceType(); witnessLocator = cs->getConstraintLocator(req, LocatorPathElt::Witness(witness)); + DeclReferenceType openWitnessTypeInfo; + if (witness->getDeclContext()->isTypeContext()) { - openWitnessType = - cs->getTypeOfMemberReference(selfTy, witness, dc, - /*isDynamicResult=*/false, - FunctionRefInfo::doubleBaseNameApply(), - witnessLocator, &witnessReplacements) - .adjustedReferenceType; + auto witnessChoice = OverloadChoice::getDecl( + selfTy, witness, FunctionRefInfo::doubleBaseNameApply()); + openWitnessTypeInfo = + cs->getTypeOfMemberReference(witnessChoice, dc, witnessLocator, + /*preparedOverload=*/nullptr); } else { - openWitnessType = + auto witnessChoice = OverloadChoice::getDecl( + witness, FunctionRefInfo::doubleBaseNameApply()); + openWitnessTypeInfo = cs->getTypeOfReference( - witness, FunctionRefInfo::doubleBaseNameApply(), witnessLocator, - /*useDC=*/nullptr, /*preparedOverload=*/nullptr) - .adjustedReferenceType; + witnessChoice, /*useDC=*/nullptr, witnessLocator, + /*preparedOverload=*/nullptr); } - openWitnessType = openWitnessType->getRValueType(); - - Type reqThrownError; - Type witnessThrownError; - if (auto *witnessASD = dyn_cast(witness)) { - auto *reqASD = cast(req); - - // Dig out the thrown error types from the getter so we can compare them - // later. - auto getThrownErrorType = [](AbstractStorageDecl *asd) -> Type { - if (auto getter = asd->getEffectfulGetAccessor()) { - if (Type thrownErrorType = getter->getThrownInterfaceType()) { - return thrownErrorType; - } else if (getter->hasThrows()) { - return asd->getASTContext().getErrorExistentialType(); - } - } - - return asd->getASTContext().getNeverType(); - }; - - reqThrownError = getThrownErrorType(reqASD); - reqThrownError = cs->openType(reqThrownError, reqReplacements, - reqLocator, /*preparedOverload=*/nullptr); + openWitnessType = openWitnessTypeInfo.adjustedReferenceType; + openWitnessType = openWitnessType->getRValueType(); - witnessThrownError = getThrownErrorType(witnessASD); - witnessThrownError = cs->openType(witnessThrownError, witnessReplacements, - witnessLocator, /*preparedOverload=*/nullptr); - } + Type witnessThrownError = openWitnessTypeInfo.thrownErrorTypeOnAccess; return std::make_tuple(std::nullopt, reqType, openWitnessType, reqThrownError, witnessThrownError); diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 78236a8c0ae3d..fbcc700b1973f 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -303,7 +303,8 @@ class InferableTypeOpener final { // an invalid AST node. if (type->hasError()) { cs.recordFix( - IgnoreInvalidASTNode::create(cs, cs.getConstraintLocator(locator))); + IgnoreInvalidASTNode::create(cs, cs.getConstraintLocator(locator)), + /*impact=*/1, preparedOverload); } return type.transformRec([&](Type type) -> std::optional { if (!type->hasUnboundGenericType() && !type->hasPlaceholder() && @@ -814,27 +815,24 @@ void ConstraintSystem::recordOpenedTypes( // If the last path element is an archetype or associated type, ignore it. SmallVector pathElts; - auto anchor = locator.getLocatorParts(pathElts); + (void) locator.getLocatorParts(pathElts); if (!pathElts.empty() && pathElts.back().getKind() == ConstraintLocator::GenericParameter) return; - // If the locator is empty, ignore it. - if (!anchor && pathElts.empty()) - return; - ConstraintLocator *locatorPtr = getConstraintLocator(locator); assert(locatorPtr && "No locator for opened types?"); - OpenedType *openedTypes - = Allocator.Allocate(replacements.size()); - std::copy(replacements.begin(), replacements.end(), openedTypes); - // FIXME: Get rid of fixmeAllowDuplicates. - if (!fixmeAllowDuplicates || OpenedTypes.count(locatorPtr) == 0) + if (!fixmeAllowDuplicates || OpenedTypes.count(locatorPtr) == 0) { + OpenedType *openedTypes + = Allocator.Allocate(replacements.size()); + std::copy(replacements.begin(), replacements.end(), openedTypes); + recordOpenedType( locatorPtr, llvm::ArrayRef(openedTypes, replacements.size()), preparedOverload); + } } /// Determine how many levels of argument labels should be removed from the @@ -956,16 +954,22 @@ static bool isRequirementOrWitness(const ConstraintLocatorBuilder &locator) { FunctionType *ConstraintSystem::adjustFunctionTypeForConcurrency( FunctionType *fnType, Type baseType, ValueDecl *decl, DeclContext *dc, - unsigned numApplies, bool isMainDispatchQueue, ArrayRef replacements, - ConstraintLocatorBuilder locator, PreparedOverloadBuilder *preparedOverload) { + unsigned numApplies, bool isMainDispatchQueue, bool openGlobalActorType, + ConstraintLocatorBuilder locator) { auto *adjustedTy = swift::adjustFunctionTypeForConcurrency( fnType, decl, dc, numApplies, isMainDispatchQueue, GetClosureType{*this}, ClosureIsolatedByPreconcurrency{*this}, [&](Type type) { - if (replacements.empty()) + if (!type->hasTypeParameter()) return type; - return openType(type, replacements, locator, preparedOverload); + // FIXME: This should be handled elsewhere. + if (!openGlobalActorType) + return type; + + auto replacements = getOpenedTypes(getConstraintLocator(locator)); + ASSERT(!replacements.empty()); + return openType(type, replacements, locator, /*preparedOverload=*/nullptr); }); // Infer @Sendable for global actor isolated function types under the @@ -1105,13 +1109,15 @@ recordFixIfNeededForPlaceholderInDecl(ConstraintSystem &cs, ValueDecl *D, cs.recordFix(IgnoreInvalidPlaceholderInDeclRef::create(cs, loc)); } -DeclReferenceType -ConstraintSystem::getTypeOfReference(ValueDecl *value, - FunctionRefInfo functionRefInfo, - ConstraintLocatorBuilder locator, - DeclContext *useDC, - PreparedOverloadBuilder *preparedOverload) { +std::pair +ConstraintSystem::getTypeOfReferencePre(OverloadChoice choice, + DeclContext *useDC, + ConstraintLocatorBuilder locator, + PreparedOverloadBuilder *preparedOverload) { + auto *value = choice.getDecl(); + ASSERT(!!preparedOverload == PreparingOverload); + recordFixIfNeededForPlaceholderInDecl(*this, value, locator); if (value->getDeclContext()->isTypeContext() && isa(value)) { @@ -1130,43 +1136,13 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // If we opened up any type variables, record the replacements. recordOpenedTypes(locator, replacements, preparedOverload); - auto origOpenedType = openedType; - if (!isRequirementOrWitness(locator)) { - unsigned numApplies = getNumApplications(/*hasAppliedSelf*/ false, - functionRefInfo); - openedType = adjustFunctionTypeForConcurrency( - origOpenedType, /*baseType=*/Type(), func, useDC, numApplies, false, - replacements, locator, preparedOverload); - } - - // If this is a method whose result type is dynamic Self, replace - // DynamicSelf with the actual object type. Repeat the adjustment - // for the original and adjusted types. - auto type = openedType; - if (openedType->hasDynamicSelfType()) { - auto params = openedType->getParams(); - assert(params.size() == 1); - Type selfTy = params.front().getPlainType()->getMetatypeInstanceType(); - type = openedType->replaceDynamicSelfType(selfTy) - ->castTo(); - } - - auto origType = origOpenedType; - if (origOpenedType->hasDynamicSelfType()) { - auto params = origOpenedType->getParams(); - assert(params.size() == 1); - Type selfTy = params.front().getPlainType()->getMetatypeInstanceType(); - origType = origOpenedType->replaceDynamicSelfType(selfTy) - ->castTo(); - } - - // The reference implicitly binds 'self'. - return {origOpenedType, openedType, - origType->getResult(), type->getResult(), Type()}; + return {openedType, Type()}; } // Unqualified reference to a local or global function. if (auto funcDecl = dyn_cast(value)) { + auto functionRefInfo = choice.getFunctionRefInfo(); + SmallVector replacements; auto funcType = funcDecl->getInterfaceType()->castTo(); @@ -1191,16 +1167,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // If we opened up any type variables, record the replacements. recordOpenedTypes(locator, replacements, preparedOverload); - auto origOpenedType = openedType; - if (!isRequirementOrWitness(locator)) { - unsigned numApplies = getNumApplications(/*hasAppliedSelf*/ false, - functionRefInfo); - openedType = adjustFunctionTypeForConcurrency( - origOpenedType->castTo(), /*baseType=*/Type(), funcDecl, - useDC, numApplies, false, replacements, locator, preparedOverload); - } - - return { origOpenedType, openedType, origOpenedType, openedType, Type() }; + return {openedType, Type()}; } // Unqualified reference to a type. @@ -1222,11 +1189,11 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // Module types are not wrapped in metatypes. if (type->is()) - return { type, type, type, type, Type() }; + return { type, Type() }; // If it's a value reference, refer to the metatype. type = MetatypeType::get(type); - return { type, type, type, type, Type() }; + return {type, Type()}; } // Unqualified reference to a macro. @@ -1245,7 +1212,7 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, // FIXME: Should we use replaceParamErrorTypeByPlaceholder() here? - return { openedType, openedType, openedType, openedType, Type() }; + return {openedType, Type()}; } // Only remaining case: unqualified reference to a property. @@ -1257,11 +1224,9 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, getUnopenedTypeOfReference(varDecl, Type(), useDC, getConstraintLocator(locator), wantInterfaceType); - // FIXME: Adjust the type for concurrency if requested. - valueType = adjustVarTypeForConcurrency( - valueType, varDecl, useDC, - GetClosureType{*this}, - ClosureIsolatedByPreconcurrency{*this}); + + ASSERT(!valueType->hasUnboundGenericType() && + !valueType->hasTypeParameter()); Type thrownErrorType; if (auto accessor = varDecl->getEffectfulGetAccessor()) { @@ -1269,9 +1234,116 @@ ConstraintSystem::getTypeOfReference(ValueDecl *value, accessor->getEffectiveThrownErrorType().value_or(Type()); } - assert(!valueType->hasUnboundGenericType() && - !valueType->hasTypeParameter()); - return { valueType, valueType, valueType, valueType, thrownErrorType }; + return {valueType, thrownErrorType}; +} + +DeclReferenceType +ConstraintSystem::getTypeOfReferencePost(OverloadChoice choice, + DeclContext *useDC, + ConstraintLocatorBuilder locator, + Type openedType, Type thrownErrorType) { + auto *value = choice.getDecl(); + + if (value->getDeclContext()->isTypeContext() && isa(value)) { + auto *openedFnType = openedType->castTo(); + + // Unqualified lookup can find operator names within nominal types. + auto func = cast(value); + assert(func->isOperator() && "Lookup should only find operators"); + + auto functionRefInfo = choice.getFunctionRefInfo(); + + auto origOpenedType = openedFnType; + if (!isRequirementOrWitness(locator)) { + unsigned numApplies = getNumApplications(/*hasAppliedSelf*/ false, + functionRefInfo); + openedFnType = adjustFunctionTypeForConcurrency( + origOpenedType, /*baseType=*/Type(), func, useDC, numApplies, + /*isMainDispatchQueue=*/false, /*openGlobalActorType=*/true, locator); + } + + // If this is a method whose result type is dynamic Self, replace + // DynamicSelf with the actual object type. Repeat the adjustment + // for the original and adjusted types. + auto type = openedFnType; + if (openedFnType->hasDynamicSelfType()) { + auto params = openedFnType->getParams(); + assert(params.size() == 1); + Type selfTy = params.front().getPlainType()->getMetatypeInstanceType(); + type = openedFnType->replaceDynamicSelfType(selfTy) + ->castTo(); + } + + auto origType = origOpenedType; + if (origOpenedType->hasDynamicSelfType()) { + auto params = origOpenedType->getParams(); + assert(params.size() == 1); + Type selfTy = params.front().getPlainType()->getMetatypeInstanceType(); + origType = origOpenedType->replaceDynamicSelfType(selfTy) + ->castTo(); + } + + // The reference implicitly binds 'self'. + return {origOpenedType, openedType, + origType->getResult(), type->getResult(), Type()}; + } + + // Unqualified reference to a local or global function. + if (auto funcDecl = dyn_cast(value)) { + auto origOpenedType = openedType; + if (!isRequirementOrWitness(locator)) { + unsigned numApplies = getNumApplications(/*hasAppliedSelf*/ false, + choice.getFunctionRefInfo()); + openedType = adjustFunctionTypeForConcurrency( + origOpenedType->castTo(), /*baseType=*/Type(), funcDecl, + useDC, numApplies, /*isMainDispatchQueue=*/false, + /*openGlobalActorType=*/true, locator); + } + + return { origOpenedType, openedType, origOpenedType, openedType, Type() }; + } + + // Unqualified reference to a type. + if (isa(value)) { + return { openedType, openedType, openedType, openedType, Type() }; + } + + // Unqualified reference to a macro. + if (isa(value)) { + return { openedType, openedType, openedType, openedType, Type() }; + } + + // Only remaining case: unqualified reference to a property. + auto *varDecl = cast(value); + + // Adjust the type for concurrency. + auto origOpenedType = openedType; + + if (!isRequirementOrWitness(locator)) { + openedType = adjustVarTypeForConcurrency( + openedType, varDecl, useDC, + GetClosureType{*this}, + ClosureIsolatedByPreconcurrency{*this}); + } + + return { origOpenedType, openedType, + origOpenedType, openedType, + thrownErrorType }; +} + +DeclReferenceType +ConstraintSystem::getTypeOfReference(OverloadChoice choice, + DeclContext *useDC, + ConstraintLocatorBuilder locator, + PreparedOverloadBuilder *preparedOverload) { + ASSERT(!!preparedOverload == PreparingOverload); + + Type openedType, thrownErrorType; + std::tie(openedType, thrownErrorType) = getTypeOfReferencePre( + choice, useDC, locator, preparedOverload); + + return getTypeOfReferencePost(choice, useDC, locator, + openedType, thrownErrorType); } /// Bind type variables for archetypes that are determined from @@ -1468,10 +1540,10 @@ void ConstraintSystem::openGenericRequirement( preparedOverload); } -DeclReferenceType ConstraintSystem::getTypeOfMemberTypeReference( +Type ConstraintSystem::getTypeOfMemberTypeReference( Type baseObjTy, TypeDecl *typeDecl, ConstraintLocator *locator, PreparedOverloadBuilder *preparedOverload) { - assert(!isa(typeDecl) && "Nested module?"); + ASSERT(!isa(typeDecl) && "Nested module?"); auto memberTy = TypeChecker::substMemberTypeWithBase(typeDecl, baseObjTy); @@ -1497,8 +1569,7 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberTypeReference( } FunctionType::Param baseObjParam(baseObjTy); - auto openedType = FunctionType::get({baseObjParam}, memberTy); - return { openedType, openedType, memberTy, memberTy, Type() }; + return FunctionType::get({baseObjParam}, memberTy); } std::pair ConstraintSystem::getOpenedStorageType( @@ -1569,8 +1640,8 @@ std::pair ConstraintSystem::getOpenedStorageType( FunctionType::Param selfParam(selfTy, Identifier(), selfFlags); FunctionType::ExtInfo info; - return std::make_pair(thrownErrorType, - FunctionType::get({selfParam}, refType, info)); + return std::make_pair(FunctionType::get({selfParam}, refType, info), + thrownErrorType); } /// Add the constraint on the type used for the 'Self' type for a member @@ -1699,8 +1770,7 @@ static bool isExistentialMemberAccessWithExplicitBaseExpression( Type ConstraintSystem::getMemberReferenceTypeFromOpenedType( Type type, Type baseObjTy, ValueDecl *value, - ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup, - ArrayRef replacements) { + ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup) { auto *outerDC = value->getDeclContext(); // Cope with dynamic 'Self'. @@ -1732,8 +1802,8 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType( baseObjTy, value, locator, isDynamicLookup) && // If there are no type variables, there were no references to 'Self'. type->hasTypeVariable()) { - auto selfGP = outerDC->getSelfInterfaceType(); - ASSERT(selfGP->isEqual(replacements[0].first)); + auto replacements = getOpenedTypes(locator); + ASSERT(replacements[0].first->isEqual(getASTContext().TheSelfType)); auto openedTypeVar = replacements[0].second; type = typeEraseOpenedExistentialReference(type, baseObjTy, openedTypeVar, @@ -1797,27 +1867,34 @@ static FunctionType *applyOptionality(ValueDecl *value, FunctionType *fnTy) { fnTy->getExtInfo()); } -DeclReferenceType ConstraintSystem::getTypeOfMemberReference( - Type baseTy, ValueDecl *value, DeclContext *useDC, bool isDynamicLookup, - FunctionRefInfo functionRefInfo, ConstraintLocator *locator, - SmallVectorImpl *replacementsPtr, +std::pair +ConstraintSystem::getTypeOfMemberReferencePre( + OverloadChoice choice, DeclContext *useDC, + ConstraintLocator *locator, PreparedOverloadBuilder *preparedOverload) { ASSERT(!!preparedOverload == PreparingOverload); + + auto *value = choice.getDecl(); + auto functionRefInfo = choice.getFunctionRefInfo(); + recordFixIfNeededForPlaceholderInDecl(*this, value, locator); // Figure out the instance type used for the base. + auto baseTy = choice.getBaseType(); Type baseRValueTy = baseTy->getRValueType(); auto baseObjTy = baseRValueTy->getMetatypeInstanceType(); - // If the base is a module type, just use the type of the decl. if (baseObjTy->is()) { - return getTypeOfReference(value, functionRefInfo, locator, useDC, - preparedOverload); + return getTypeOfReferencePre(choice, useDC, locator, preparedOverload); } + Type openedType; + Type thrownErrorType; + if (auto *typeDecl = dyn_cast(value)) { - return getTypeOfMemberTypeReference(baseObjTy, typeDecl, - locator, preparedOverload); + openedType = getTypeOfMemberTypeReference(baseObjTy, typeDecl, + locator, preparedOverload); + return {openedType, thrownErrorType}; } // Figure out the declaration context to use when opening this type. @@ -1827,40 +1904,33 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( auto genericSig = innerDC->getGenericSignatureOfContext(); // Open the type of the generic function or member of a generic type. - ArrayRef replacements; - SmallVector localReplacements; - { - auto &_replacements = replacementsPtr ? *replacementsPtr : localReplacements; - - // If we have a generic signature, open the parameters. We delay opening - // requirements to allow contextual types to affect the situation. - if (genericSig) { - openGenericParameters(outerDC, genericSig, _replacements, locator, - preparedOverload); - } + SmallVector replacements; - // If we opened up any type variables, record the replacements. We do this - // up-front to allow requirement fix coalescing logic to work correctly with - // requirements imposed on base type (since that relies on being able to - // find the recorded opened type). We then make the array immutable for the - // following logic to ensure they don't attempt to add any additional opened - // types. - recordOpenedTypes(locator, _replacements, preparedOverload); - replacements = _replacements; + // If we have a generic signature, open the parameters. We delay opening + // requirements to allow contextual types to affect the situation. + if (genericSig) { + openGenericParameters(outerDC, genericSig, replacements, locator, + preparedOverload); } + // If we opened up any type variables, record the replacements. We do this + // up-front to allow requirement fix coalescing logic to work correctly with + // requirements imposed on base type (since that relies on being able to + // find the recorded opened type). We then make the array immutable for the + // following logic to ensure they don't attempt to add any additional opened + // types. + recordOpenedTypes(locator, replacements, preparedOverload); + // Check to see if the self parameter is applied, in which case we'll want to // strip it off later. auto hasAppliedSelf = doesMemberRefApplyCurriedSelf(baseRValueTy, value); - Type openedType; - Type thrownErrorType; if (isa(value) || isa(value) || isa(value)) { auto interfaceType = value->getInterfaceType(); if (interfaceType->is() || isa(value)) - return { interfaceType, interfaceType, interfaceType, interfaceType, Type() }; + return { interfaceType, Type() }; if (outerDC->getSelfClassDecl()) { if (isa(value)) { @@ -1880,7 +1950,7 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( } else { auto *storage = cast(value); - std::tie(thrownErrorType, openedType) = getOpenedStorageType( + std::tie(openedType, thrownErrorType) = getOpenedStorageType( baseTy, storage, useDC, hasAppliedSelf, replacements, locator, preparedOverload); } @@ -1917,7 +1987,6 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( // to make sure that it's opened before use. baseOpenedTy = openType(concreteSelf, replacements, locator, preparedOverload); - baseObjTy = baseOpenedTy; } } } else { @@ -1942,7 +2011,7 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( addConstraint(ConstraintKind::Bind, baseOpenedTy, selfObjTy, getConstraintLocator(locator), /*isFavored=*/false, preparedOverload); - } else if (!isDynamicLookup) { + } else if (choice.getKind() != OverloadChoiceKind::DeclViaDynamic) { addSelfConstraint(*this, baseOpenedTy, selfObjTy, locator, preparedOverload); } @@ -1976,21 +2045,47 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( } } + return { openedType, thrownErrorType }; +} + +DeclReferenceType ConstraintSystem::getTypeOfMemberReferencePost( + OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator, + Type openedType, Type thrownErrorType) { + auto *value = choice.getDecl(); + + // Figure out the instance type used for the base. + Type baseTy = choice.getBaseType(); + Type baseRValueTy = baseTy->getRValueType(); + Type baseObjTy = baseRValueTy->getMetatypeInstanceType(); + + if (baseObjTy->is()) { + return getTypeOfReferencePost(choice, useDC, locator, + openedType, thrownErrorType); + } + + if (isa(value)) { + auto type = openedType->castTo()->getResult(); + return { openedType, openedType, type, type, Type() }; + } + + auto hasAppliedSelf = doesMemberRefApplyCurriedSelf(baseRValueTy, value); + // Adjust the opened type for concurrency. Type origOpenedType = openedType; if (isRequirementOrWitness(locator)) { // Don't adjust when doing witness matching, because that can cause cycles. } else if (isa(value) || isa(value)) { - unsigned numApplies = getNumApplications(hasAppliedSelf, functionRefInfo); + unsigned numApplies = getNumApplications( + hasAppliedSelf, choice.getFunctionRefInfo()); openedType = adjustFunctionTypeForConcurrency( - origOpenedType->castTo(), baseRValueTy, value, useDC, - numApplies, isMainDispatchQueueMember(locator), replacements, locator, - preparedOverload); + origOpenedType->castTo(), baseObjTy, value, useDC, + numApplies, isMainDispatchQueueMember(locator), + /*openGlobalActorType=*/true, locator); } else if (auto subscript = dyn_cast(value)) { openedType = adjustFunctionTypeForConcurrency( - origOpenedType->castTo(), baseRValueTy, subscript, useDC, - /*numApplies=*/2, /*isMainDispatchQueue=*/false, replacements, locator, - preparedOverload); + origOpenedType->castTo(), baseObjTy, subscript, useDC, + /*numApplies=*/2, /*isMainDispatchQueue=*/false, + /*openGlobalActorType=*/true, locator); } else if (auto var = dyn_cast(value)) { // Adjust the function's result type, since that's the Var's actual type. auto origFnType = origOpenedType->castTo(); @@ -2003,6 +2098,8 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( origFnType->getParams(), resultTy, origFnType->getExtInfo()); } + bool isDynamicLookup = (choice.getKind() == OverloadChoiceKind::DeclViaDynamic); + // Check if we need to apply a layer of optionality to the type. if (!isRequirementOrWitness(locator)) { if (isDynamicLookup || value->getAttrs().hasAttribute()) { @@ -2014,19 +2111,32 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( // Handle DynamicSelfType and a couple of other things. Type type = getMemberReferenceTypeFromOpenedType( openedType, baseObjTy, value, locator, hasAppliedSelf, - isDynamicLookup, replacements); + isDynamicLookup); // Do the same thing for the original type, if there can be any difference. Type origType = type; if (openedType.getPointer() != origOpenedType.getPointer()) { origType = getMemberReferenceTypeFromOpenedType( origOpenedType, baseObjTy, value, locator, hasAppliedSelf, - isDynamicLookup, replacements); + isDynamicLookup); } return { origOpenedType, openedType, origType, type, thrownErrorType }; } +DeclReferenceType ConstraintSystem::getTypeOfMemberReference( + OverloadChoice choice, DeclContext *useDC, ConstraintLocator *locator, + PreparedOverloadBuilder *preparedOverload) { + ASSERT(!!preparedOverload == PreparingOverload); + + Type openedType, thrownErrorType; + std::tie(openedType, thrownErrorType) + = getTypeOfMemberReferencePre(choice, useDC, locator, preparedOverload); + + return getTypeOfMemberReferencePost( + choice, useDC, locator, openedType, thrownErrorType); +} + Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator, const OverloadChoice &overload, bool allowMembers, @@ -2125,9 +2235,8 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator, FunctionType::ExtInfo info; type = adjustFunctionTypeForConcurrency( FunctionType::get(indices, elementTy, info), overload.getBaseType(), - subscript, useDC, - /*numApplies=*/1, /*isMainDispatchQueue=*/false, emptyReplacements, - locator, /*preparedOverload=*/nullptr); + subscript, useDC, /*numApplies=*/1, /*isMainDispatchQueue=*/false, + /*openGlobalActorType=*/false, locator); } else if (auto var = dyn_cast(decl)) { type = var->getValueInterfaceType(); if (doesStorageProduceLValue( @@ -2172,8 +2281,8 @@ Type ConstraintSystem::getEffectiveOverloadType(ConstraintLocator *locator, type = adjustFunctionTypeForConcurrency( type->castTo(), overload.getBaseType(), decl, useDC, numApplies, /*isMainDispatchQueue=*/false, - emptyReplacements, locator, /*preparedOverload=*/nullptr) - ->getResult(); + /*openGlobalActorType=*/false, locator) + ->getResult(); } } @@ -2522,7 +2631,7 @@ isInvalidPartialApplication(ConstraintSystem &cs, /// checking semantics, compute the type of the reference. For now, follow /// the lead of \c getTypeOfMemberReference and return a pair of /// the full opened type and the reference's type. -static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( +static Type getTypeOfReferenceWithSpecialTypeCheckingSemantics( ConstraintSystem &CS, ConstraintLocator *locator, DeclTypeCheckingSemantics semantics, PreparedOverloadBuilder *preparedOverload) { @@ -2551,8 +2660,7 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( /*isFavored=*/false, preparedOverload); // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo info; - auto refType = FunctionType::get({inputArg}, output, info); - return {refType, refType, refType, refType, Type()}; + return FunctionType::get({inputArg}, output, info); } case DeclTypeCheckingSemantics::WithoutActuallyEscaping: { // Proceed with a "WithoutActuallyEscaping" operation. The body closure @@ -2599,14 +2707,13 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( withoutEscapingIsolation = FunctionTypeIsolation::forNonIsolatedCaller(); } - auto refType = FunctionType::get(args, result, - FunctionType::ExtInfoBuilder() - .withNoEscape(false) - .withIsolation(withoutEscapingIsolation) - .withAsync(true) - .withThrows(true, thrownError) - .build()); - return {refType, refType, refType, refType, Type()}; + return FunctionType::get(args, result, + FunctionType::ExtInfoBuilder() + .withNoEscape(false) + .withIsolation(withoutEscapingIsolation) + .withAsync(true) + .withThrows(true, thrownError) + .build()); } case DeclTypeCheckingSemantics::OpenExistential: { // The body closure receives a freshly-opened archetype constrained by the @@ -2652,14 +2759,13 @@ static DeclReferenceType getTypeOfReferenceWithSpecialTypeCheckingSemantics( openExistentialIsolation = FunctionTypeIsolation::forNonIsolatedCaller(); } - auto refType = FunctionType::get(args, result, - FunctionType::ExtInfoBuilder() - .withNoEscape(false) - .withThrows(true, thrownError) - .withIsolation(openExistentialIsolation) - .withAsync(true) - .build()); - return {refType, refType, refType, refType, Type()}; + return FunctionType::get(args, result, + FunctionType::ExtInfoBuilder() + .withNoEscape(false) + .withThrows(true, thrownError) + .withIsolation(openExistentialIsolation) + .withAsync(true) + .build()); } } @@ -2729,6 +2835,10 @@ void ConstraintSystem::replayChanges( case PreparedOverload::Change::AddedFix: recordFix(change.Fix.TheFix, change.Fix.Impact); break; + + case PreparedOverload::Change::RecordedNodeType: + setType(change.Node.Node, change.Node.TheType); + break; } } } @@ -2737,43 +2847,41 @@ void ConstraintSystem::replayChanges( /// that are to be introduced into the constraint system when this choice /// is taken. /// +/// Returns a pair consisting of the opened type, and the thrown error type. +/// /// FIXME: As a transitional mechanism, if preparedOverload is nullptr, this /// immediately performs all operations. -DeclReferenceType -ConstraintSystem::prepareOverloadImpl(ConstraintLocator *locator, - OverloadChoice choice, +std::pair +ConstraintSystem::prepareOverloadImpl(OverloadChoice choice, DeclContext *useDC, + ConstraintLocator *locator, PreparedOverloadBuilder *preparedOverload) { // If we refer to a top-level decl with special type-checking semantics, // handle it now. auto semantics = TypeChecker::getDeclTypeCheckingSemantics(choice.getDecl()); if (semantics != DeclTypeCheckingSemantics::Normal) { - return getTypeOfReferenceWithSpecialTypeCheckingSemantics( + auto openedType = getTypeOfReferenceWithSpecialTypeCheckingSemantics( *this, locator, semantics, preparedOverload); - } else if (auto baseTy = choice.getBaseType()) { - // Retrieve the type of a reference to the specific declaration choice. - assert(!baseTy->hasTypeParameter()); - - return getTypeOfMemberReference( - baseTy, choice.getDecl(), useDC, - (choice.getKind() == OverloadChoiceKind::DeclViaDynamic), - choice.getFunctionRefInfo(), locator, nullptr, preparedOverload); + return {openedType, Type()}; + } else if (choice.getBaseType()) { + return getTypeOfMemberReferencePre(choice, useDC, locator, preparedOverload); } else { - return getTypeOfReference( - choice.getDecl(), choice.getFunctionRefInfo(), locator, useDC, - preparedOverload); + return getTypeOfReferencePre(choice, useDC, locator, preparedOverload); } } -PreparedOverload *ConstraintSystem::prepareOverload(ConstraintLocator *locator, - OverloadChoice choice, - DeclContext *useDC) { +PreparedOverload *ConstraintSystem::prepareOverload(OverloadChoice choice, + DeclContext *useDC, + ConstraintLocator *locator) { ASSERT(!PreparingOverload); PreparingOverload = true; PreparedOverloadBuilder builder; - auto declRefType = prepareOverloadImpl(locator, choice, useDC, &builder); + Type openedType; + Type thrownErrorType; + std::tie(openedType, thrownErrorType) = prepareOverloadImpl( + choice, useDC, locator, &builder); PreparingOverload = false; @@ -2781,19 +2889,14 @@ PreparedOverload *ConstraintSystem::prepareOverload(ConstraintLocator *locator, auto size = PreparedOverload::totalSizeToAlloc(count); auto mem = Allocator.Allocate(size, alignof(PreparedOverload)); - return new (mem) PreparedOverload(declRefType, builder.Changes); + return new (mem) PreparedOverload(openedType, thrownErrorType, builder.Changes); } -void ConstraintSystem::resolveOverload(ConstraintLocator *locator, - Type boundType, OverloadChoice choice, - DeclContext *useDC, +void ConstraintSystem::resolveOverload(OverloadChoice choice, DeclContext *useDC, + ConstraintLocator *locator, Type boundType, PreparedOverload *preparedOverload) { // Determine the type to which we'll bind the overload set's type. - Type openedType; - Type adjustedOpenedType; - Type refType; - Type adjustedRefType; - Type thrownErrorTypeOnAccess; + DeclReferenceType declRefType; switch (choice.getKind()) { case OverloadChoiceKind::Decl: @@ -2802,22 +2905,34 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, case OverloadChoiceKind::DeclViaUnwrappedOptional: case OverloadChoiceKind::DynamicMemberLookup: case OverloadChoiceKind::KeyPathDynamicMemberLookup: { + Type openedType, thrownErrorType; + if (preparedOverload) { replayChanges(locator, preparedOverload); openedType = preparedOverload->getOpenedType(); - adjustedOpenedType = preparedOverload->getAdjustedOpenedType(); - refType = preparedOverload->getReferenceType(); - adjustedRefType = preparedOverload->getAdjustedReferenceType(); - thrownErrorTypeOnAccess = preparedOverload->getThrownErrorTypeOnAccess(); + thrownErrorType = preparedOverload->getThrownErrorType(); } else { - auto declRefType = prepareOverloadImpl(locator, choice, useDC, nullptr); - - openedType = declRefType.openedType; - adjustedOpenedType = declRefType.adjustedOpenedType; - refType = declRefType.referenceType; - adjustedRefType = declRefType.adjustedReferenceType; - thrownErrorTypeOnAccess = declRefType.thrownErrorTypeOnAccess; + std::tie(openedType, thrownErrorType) = prepareOverloadImpl( + choice, useDC, locator, nullptr); + } + + auto semantics = + TypeChecker::getDeclTypeCheckingSemantics(choice.getDecl()); + if (semantics != DeclTypeCheckingSemantics::Normal) { + declRefType.openedType = openedType; + declRefType.adjustedOpenedType = openedType; + declRefType.referenceType = openedType; + declRefType.adjustedReferenceType = openedType; + declRefType.thrownErrorTypeOnAccess = thrownErrorType; + } else { + if (choice.getBaseType()) { + declRefType = getTypeOfMemberReferencePost( + choice, useDC, locator, openedType, thrownErrorType); + } else { + declRefType = getTypeOfReferencePost( + choice, useDC, locator, openedType, thrownErrorType); + } } break; @@ -2827,14 +2942,16 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, if (auto lvalueTy = choice.getBaseType()->getAs()) { // When the base of a tuple lvalue, the member is always an lvalue. auto tuple = lvalueTy->getObjectType()->castTo(); - adjustedRefType = tuple->getElementType(choice.getTupleIndex())->getRValueType(); - adjustedRefType = LValueType::get(adjustedRefType); + declRefType.adjustedReferenceType = + LValueType::get( + tuple->getElementType(choice.getTupleIndex())->getRValueType()); } else { // When the base is a tuple rvalue, the member is always an rvalue. auto tuple = choice.getBaseType()->castTo(); - adjustedRefType = tuple->getElementType(choice.getTupleIndex())->getRValueType(); + declRefType.adjustedReferenceType = + tuple->getElementType(choice.getTupleIndex())->getRValueType(); } - refType = adjustedRefType; + declRefType.referenceType = declRefType.adjustedReferenceType; break; case OverloadChoiceKind::MaterializePack: { @@ -2844,18 +2961,18 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, // In the future, _if_ the syntax allows for multiple expansions // this code would have to be adjusted to project l-value from the // base type just like TupleIndex does. - adjustedRefType = + declRefType.adjustedReferenceType = getPatternTypeOfSingleUnlabeledPackExpansionTuple(choice.getBaseType()); - refType = adjustedRefType; + declRefType.referenceType = declRefType.adjustedReferenceType; break; } case OverloadChoiceKind::ExtractFunctionIsolation: { // The type of `.isolation` is `(any Actor)?` auto actor = getASTContext().getProtocol(KnownProtocolKind::Actor); - adjustedRefType = + declRefType.adjustedReferenceType = OptionalType::get(actor->getDeclaredExistentialType()); - refType = adjustedRefType; + declRefType.referenceType = declRefType.adjustedReferenceType; break; } @@ -2886,11 +3003,11 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, // FIXME: Verify ExtInfo state is correct, not working by accident. FunctionType::ExtInfo fullInfo; auto fullTy = FunctionType::get({baseParam}, subscriptTy, fullInfo); - openedType = fullTy; - adjustedOpenedType = fullTy; + declRefType.openedType = fullTy; + declRefType.adjustedOpenedType = fullTy; // FIXME: @preconcurrency - refType = subscriptTy; - adjustedRefType = subscriptTy; + declRefType.referenceType = subscriptTy; + declRefType.adjustedReferenceType = subscriptTy; // Increase the score so that actual subscripts get preference. // ...except if we're solving for code completion and the index expression @@ -2903,8 +3020,9 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, break; } } - assert(!refType->hasTypeParameter() && "Cannot have a dependent type here"); - assert(!adjustedRefType->hasTypeParameter() && + assert(!declRefType.referenceType->hasTypeParameter() && + "Cannot have a dependent type here"); + assert(!declRefType.adjustedReferenceType->hasTypeParameter() && "Cannot have a dependent type here"); if (auto *decl = choice.getDeclOrNull()) { @@ -2924,7 +3042,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, if (locator->isResultOfKeyPathDynamicMemberLookup() || locator->isKeyPathSubscriptComponent()) { // Subscript type has a format of (Self[.Type) -> (Arg...) -> Result - auto declTy = adjustedOpenedType->castTo(); + auto declTy = declRefType.adjustedOpenedType->castTo(); auto subscriptTy = declTy->getResult()->castTo(); // If we have subscript, each of the arguments has to conform to // Hashable, because it would be used as a component inside key path. @@ -2996,7 +3114,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, // The default type of the #isolation builtin macro is `(any Actor)?` if (macro->getBuiltinKind() == BuiltinMacroKind::IsolationMacro) { - auto *fnType = openedType->getAs(); + auto *fnType = declRefType.openedType->getAs(); auto actor = getASTContext().getProtocol(KnownProtocolKind::Actor); addConstraint( ConstraintKind::Defaultable, fnType->getResult(), @@ -3008,14 +3126,20 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, // If accessing this declaration could throw an error, record this as a // potential throw site. - if (thrownErrorTypeOnAccess) { + if (declRefType.thrownErrorTypeOnAccess) { recordPotentialThrowSite( - PotentialThrowSite::PropertyAccess, thrownErrorTypeOnAccess, locator); + PotentialThrowSite::PropertyAccess, + declRefType.thrownErrorTypeOnAccess, + locator); } // Note that we have resolved this overload. auto overload = SelectedOverload{ - choice, openedType, adjustedOpenedType, refType, adjustedRefType, + choice, + declRefType.openedType, + declRefType.adjustedOpenedType, + declRefType.referenceType, + declRefType.adjustedReferenceType, boundType}; recordResolvedOverload(locator, overload); @@ -3031,7 +3155,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, log << "(overload set choice binding "; boundType->print(log, PO); log << " := "; - adjustedRefType->print(log, PO); + declRefType.adjustedReferenceType->print(log, PO); auto openedAtLoc = getOpenedTypes(locator); if (!openedAtLoc.empty()) { @@ -3063,8 +3187,9 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator, OverloadChoiceKind::DeclViaDynamic)) { // Strip curried 'self' parameters. - auto fromTy = openedType->castTo()->getResult(); - auto toTy = refType; + auto fromTy = declRefType.openedType + ->castTo()->getResult(); + auto toTy = declRefType.referenceType; if (!doesMemberRefApplyCurriedSelf(baseTy, decl)) { toTy = toTy->castTo()->getResult(); }