diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 4992cfad31f81..6aab1119e1d09 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -5796,6 +5796,23 @@ class OpenUnboundGenericType { } }; +/// A function object suitable for use as an \c OpenRequirementFn that "opens" +/// the requirements for a given type's generic signature given a set of +/// argument substitutions. +class OpenGenericTypeRequirements { + ConstraintSystem &cs; + const ConstraintLocatorBuilder &locator; + PreparedOverloadBuilder *preparedOverload; + +public: + explicit OpenGenericTypeRequirements( + ConstraintSystem &cs, const ConstraintLocatorBuilder &locator, + PreparedOverloadBuilder *preparedOverload) + : cs(cs), locator(locator), preparedOverload(preparedOverload) {} + + void operator()(GenericTypeDecl *decl, TypeSubstitutionFn subst) const; +}; + class HandlePlaceholderType { ConstraintSystem &cs; ConstraintLocator *locator; diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index f6d348dea9c02..cff569091d147 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -1697,6 +1697,9 @@ namespace { // Introduce type variables for unbound generics. const auto genericOpener = OpenUnboundGenericType(CS, locator); const auto placeholderHandler = HandlePlaceholderType(CS, locator); + const auto requirementOpener = + OpenGenericTypeRequirements(CS, locator, + /*preparedOverload*/ nullptr); // Add a PackElementOf constraint for 'each T' type reprs. PackExpansionExpr *elementEnv = nullptr; @@ -1708,7 +1711,7 @@ namespace { const auto result = TypeResolution::resolveContextualType( repr, CS.DC, options, genericOpener, placeholderHandler, - packElementOpener); + packElementOpener, requirementOpener); if (result->hasError()) { CS.recordFix( IgnoreInvalidASTNode::create(CS, CS.getConstraintLocator(locator))); @@ -1973,7 +1976,9 @@ namespace { // Introduce type variables for unbound generics. OpenUnboundGenericType(CS, argLocator), HandlePlaceholderType(CS, argLocator), - OpenPackElementType(CS, argLocator, elementEnv)); + OpenPackElementType(CS, argLocator, elementEnv), + OpenGenericTypeRequirements(CS, locator, + /*preparedOverload*/ nullptr)); if (result->hasError()) { auto &ctxt = CS.getASTContext(); result = PlaceholderType::get(ctxt, specializationArg); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 97e8debcacb53..c6408b2ddb508 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -3414,6 +3414,39 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef solutions) { return false; } +void OpenGenericTypeRequirements::operator()(GenericTypeDecl *decl, + TypeSubstitutionFn subst) const { + auto *outerDC = decl->getDeclContext(); + auto sig = decl->getGenericSignature(); + + // In principle we shouldn't need to open the generic parameters here, we + // could just open the requirements using the substituted arguments directly, + // but that doesn't allow us to correctly handle requirement fix coalescing + // in `isFixedRequirement`. So instead we open the generic parameters and + // then bind the resulting type variables to the substituted args. + SmallVector replacements; + cs.openGenericParameters(outerDC, sig, replacements, locator, + preparedOverload); + + // FIXME: Get rid of fixmeAllowDuplicates. This is the same issue as in + // `openUnboundGenericType`; both `applyUnboundGenericArguments` & + // `replaceInferableTypesWithTypeVars` can open multiple different generic + // types with the same locator. For the former we ought to plumb through the + // TypeRepr and use that to distinguish the locator. For the latter we ought + // to try migrating clients off it, pushing the opening up to type resolution. + cs.recordOpenedTypes(locator, replacements, preparedOverload, + /*fixmeAllowDuplicates*/ true); + + for (auto [gp, typeVar] : replacements) + cs.addConstraint(ConstraintKind::Bind, typeVar, subst(gp), locator); + + auto openType = [&](Type ty) -> Type { + return cs.openType(ty, replacements, locator, preparedOverload); + }; + cs.openGenericRequirements(outerDC, sig, /*skipProtocolSelf*/ false, locator, + openType, preparedOverload); +} + ConstraintLocator * constraints::simplifyLocator(ConstraintSystem &cs, ConstraintLocator *locator, SourceRange &range) { diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index b3d7ff5430dad..5cc47ab8d8332 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -77,36 +77,40 @@ TypeResolution::forStructural(DeclContext *dc, TypeResolutionOptions options, HandlePlaceholderTypeReprFn placeholderHandler, OpenPackElementFn packElementOpener) { return TypeResolution(dc, {}, TypeResolutionStage::Structural, options, - unboundTyOpener, placeholderHandler, packElementOpener); + unboundTyOpener, placeholderHandler, packElementOpener, + /*requirementOpener*/ nullptr); } TypeResolution TypeResolution::forInterface(DeclContext *dc, TypeResolutionOptions options, OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener) { + OpenPackElementFn packElementOpener, + OpenRequirementFn requirementOpener) { return forInterface(dc, dc->getGenericSignatureOfContext(), options, - unboundTyOpener, placeholderHandler, packElementOpener); + unboundTyOpener, placeholderHandler, packElementOpener, + requirementOpener); } -TypeResolution -TypeResolution::forInterface(DeclContext *dc, GenericSignature genericSig, - TypeResolutionOptions options, - OpenUnboundGenericTypeFn unboundTyOpener, - HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener) { +TypeResolution TypeResolution::forInterface( + DeclContext *dc, GenericSignature genericSig, TypeResolutionOptions options, + OpenUnboundGenericTypeFn unboundTyOpener, + HandlePlaceholderTypeReprFn placeholderHandler, + OpenPackElementFn packElementOpener, OpenRequirementFn requirementOpener) { return TypeResolution(dc, genericSig, TypeResolutionStage::Interface, options, - unboundTyOpener, placeholderHandler, packElementOpener); + unboundTyOpener, placeholderHandler, packElementOpener, + requirementOpener); } TypeResolution TypeResolution::withOptions(TypeResolutionOptions opts) const { return TypeResolution(dc, genericSig, stage, opts, unboundTyOpener, - placeholderHandler, packElementOpener); + placeholderHandler, packElementOpener, + requirementOpener); } TypeResolution TypeResolution::withoutPackElementOpener() const { return TypeResolution(dc, genericSig, stage, options, unboundTyOpener, - placeholderHandler, {}); + placeholderHandler, {}, requirementOpener); } ASTContext &TypeResolution::getASTContext() const { @@ -1185,6 +1189,7 @@ Type TypeResolution::applyUnboundGenericArguments( // or unbound generics, let's skip the check here, and let the solver // do it when missing types are deduced. bool skipRequirementsCheck = false; + bool hasTypeVariables = false; if (options.contains(TypeResolutionFlags::SILType)) { if (auto nominal = dyn_cast(decl)) { if (nominal->isOptionalDecl()) { @@ -1215,7 +1220,7 @@ Type TypeResolution::applyUnboundGenericArguments( subs = parentTy->getContextSubstitutions(decl->getDeclContext()); } - skipRequirementsCheck |= parentTy->hasTypeVariable(); + hasTypeVariables |= parentTy->hasTypeVariable(); // Fill in substitutions for outer generic parameters if we have a local // type in generic context. This isn't actually supported all the way, @@ -1243,56 +1248,59 @@ Type TypeResolution::applyUnboundGenericArguments( // Enter the substitution. subs[paramTy] = substTy; - skipRequirementsCheck |= - substTy->hasTypeVariable() || substTy->hasUnboundGenericType(); + hasTypeVariables |= substTy->hasTypeVariable(); + skipRequirementsCheck |= substTy->hasUnboundGenericType(); } + const auto substitutions = [&](SubstitutableType *type) -> Type { + auto result = QueryTypeSubstitutionMap{subs}(type); + if (result->hasTypeParameter()) { + if (const auto contextSig = getGenericSignature()) { + auto *genericEnv = contextSig.getGenericEnvironment(); + // FIXME: This should just use mapTypeIntoContext(), but we can't yet + // because we sometimes have type parameters here that are invalid for + // our generic signature. This can happen if the type parameter was + // found via unqualified lookup, but the current context's + // generic signature failed to build because of circularity or + // completion failure. + return result.subst(QueryInterfaceTypeSubstitutions{genericEnv}, + LookUpConformanceInModule(), + SubstFlags::PreservePackExpansionLevel); + } + } + return result; + }; + // Check the generic arguments against the requirements of the declaration's // generic signature. if (!skipRequirementsCheck && getStage() == TypeResolutionStage::Interface) { - // Check the generic arguments against the requirements of the declaration's - // generic signature. + if (hasTypeVariables) { + ASSERT(requirementOpener && "Must have requirement opener for type vars"); + requirementOpener(decl, substitutions); + } else { + SourceLoc noteLoc = decl->getLoc(); + if (noteLoc.isInvalid()) + noteLoc = loc; - SourceLoc noteLoc = decl->getLoc(); - if (noteLoc.isInvalid()) - noteLoc = loc; + auto genericSig = decl->getGenericSignature(); - auto genericSig = decl->getGenericSignature(); - const auto substitutions = [&](SubstitutableType *type) -> Type { - auto result = QueryTypeSubstitutionMap{subs}(type); - if (result->hasTypeParameter()) { - if (const auto contextSig = getGenericSignature()) { - auto *genericEnv = contextSig.getGenericEnvironment(); - // FIXME: This should just use mapTypeIntoContext(), but we can't yet - // because we sometimes have type parameters here that are invalid for - // our generic signature. This can happen if the type parameter was - // found via unqualified lookup, but the current context's - // generic signature failed to build because of circularity or - // completion failure. - return result.subst(QueryInterfaceTypeSubstitutions{genericEnv}, - LookUpConformanceInModule(), - SubstFlags::PreservePackExpansionLevel); + const auto result = TypeChecker::checkGenericArgumentsForDiagnostics( + genericSig, substitutions); + switch (result.getKind()) { + case CheckRequirementsResult::RequirementFailure: + if (loc.isValid()) { + TypeChecker::diagnoseRequirementFailure( + result.getRequirementFailureInfo(), loc, noteLoc, + UnboundGenericType::get(decl, parentTy, ctx), + genericSig.getGenericParams(), substitutions); } - } - return result; - }; - const auto result = TypeChecker::checkGenericArgumentsForDiagnostics( - genericSig, substitutions); - switch (result.getKind()) { - case CheckRequirementsResult::RequirementFailure: - if (loc.isValid()) { - TypeChecker::diagnoseRequirementFailure( - result.getRequirementFailureInfo(), loc, noteLoc, - UnboundGenericType::get(decl, parentTy, ctx), - genericSig.getGenericParams(), substitutions); + LLVM_FALLTHROUGH; + case CheckRequirementsResult::SubstitutionFailure: + return ErrorType::get(ctx); + case CheckRequirementsResult::Success: + break; } - - LLVM_FALLTHROUGH; - case CheckRequirementsResult::SubstitutionFailure: - return ErrorType::get(ctx); - case CheckRequirementsResult::Success: - break; } } @@ -2564,22 +2572,22 @@ Type TypeResolution::resolveContextualType( TypeRepr *TyR, DeclContext *dc, TypeResolutionOptions opts, OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener, + OpenPackElementFn packElementOpener, OpenRequirementFn requirementOpener, SILTypeResolutionContext *silContext) { - return resolveContextualType(TyR, dc, dc->getGenericSignatureOfContext(), - opts, unboundTyOpener, placeholderHandler, - packElementOpener, silContext); + return resolveContextualType( + TyR, dc, dc->getGenericSignatureOfContext(), opts, unboundTyOpener, + placeholderHandler, packElementOpener, requirementOpener, silContext); } Type TypeResolution::resolveContextualType( TypeRepr *TyR, DeclContext *dc, GenericSignature genericSig, TypeResolutionOptions opts, OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener, + OpenPackElementFn packElementOpener, OpenRequirementFn requirementOpener, SILTypeResolutionContext *silContext) { const auto resolution = TypeResolution::forInterface( dc, genericSig, opts, unboundTyOpener, placeholderHandler, - packElementOpener); + packElementOpener, requirementOpener); const auto ty = resolution.resolveType(TyR, silContext); return GenericEnvironment::mapTypeIntoContext( @@ -4384,11 +4392,10 @@ NeverNullType TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr, auto *genericParams = repr->getGenericParams(); if (genericParams) { - fieldResolution = - TypeResolution::forInterface(getDeclContext(), genericSig, options, - resolution.getUnboundTypeOpener(), - resolution.getPlaceholderHandler(), - resolution.getPackElementOpener()); + fieldResolution = TypeResolution::forInterface( + getDeclContext(), genericSig, options, + resolution.getUnboundTypeOpener(), resolution.getPlaceholderHandler(), + resolution.getPackElementOpener(), resolution.getRequirementOpener()); } SILInnerGenericContextRAII scope(silContext, genericParams); @@ -4593,9 +4600,8 @@ NeverNullType TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, if (componentTypeSig) { functionResolution = TypeResolution::forInterface( getDeclContext(), componentTypeSig, options, - resolution.getUnboundTypeOpener(), - resolution.getPlaceholderHandler(), - resolution.getPackElementOpener()); + resolution.getUnboundTypeOpener(), resolution.getPlaceholderHandler(), + resolution.getPackElementOpener(), resolution.getRequirementOpener()); } SILInnerGenericContextRAII innerGenericContext(silContext, @@ -4651,11 +4657,10 @@ NeverNullType TypeResolver::resolveSILFunctionType(FunctionTypeRepr *repr, SubstitutionMap patternSubs; if (!repr->getPatternSubstitutions().empty()) { if (genericSig) { - auto resolveSILParameters = - TypeResolution::forInterface(getDeclContext(), genericSig, options, - resolution.getUnboundTypeOpener(), - resolution.getPlaceholderHandler(), - resolution.getPackElementOpener()); + auto resolveSILParameters = TypeResolution::forInterface( + getDeclContext(), genericSig, options, + resolution.getUnboundTypeOpener(), resolution.getPlaceholderHandler(), + resolution.getPackElementOpener(), resolution.getRequirementOpener()); patternSubs = resolveSubstitutions(repr->getPatternGenericSignature(), repr->getPatternSubstitutions(), TypeResolver{resolveSILParameters, diff --git a/lib/Sema/TypeCheckType.h b/lib/Sema/TypeCheckType.h index ecf18d2f05e00..dfc7ecec1426d 100644 --- a/lib/Sema/TypeCheckType.h +++ b/lib/Sema/TypeCheckType.h @@ -574,6 +574,9 @@ using HandlePlaceholderTypeReprFn = using OpenPackElementFn = llvm::function_ref; +using OpenRequirementFn = + llvm::function_ref; + /// Handles the resolution of types within a given declaration context, /// which might involve resolving generic parameters to a particular /// stage. @@ -584,6 +587,7 @@ class TypeResolution { OpenUnboundGenericTypeFn unboundTyOpener; HandlePlaceholderTypeReprFn placeholderHandler; OpenPackElementFn packElementOpener; + OpenRequirementFn requirementOpener; GenericSignature genericSig; private: @@ -591,11 +595,13 @@ class TypeResolution { TypeResolutionStage stage, TypeResolutionOptions options, OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener) + OpenPackElementFn packElementOpener, + OpenRequirementFn requirementOpener) : dc(dc), stage(stage), options(options), unboundTyOpener(unboundTyOpener), placeholderHandler(placeholderHandler), - packElementOpener(packElementOpener), genericSig(genericSig) {} + packElementOpener(packElementOpener), + requirementOpener(requirementOpener), genericSig(genericSig) {} public: /// Form a type resolution for the structure of a type, which does not @@ -613,7 +619,8 @@ class TypeResolution { forInterface(DeclContext *dc, TypeResolutionOptions opts, OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener); + OpenPackElementFn packElementOpener, + OpenRequirementFn requirementOpener = nullptr); /// Form a type resolution for an interface type, which is a complete /// description of the type using generic parameters. @@ -622,7 +629,8 @@ class TypeResolution { TypeResolutionOptions opts, OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener); + OpenPackElementFn packElementOpener, + OpenRequirementFn requirementOpener = nullptr); /// Form a type resolution for a contextual type, which is a complete /// description of the type using the archetypes of the given generic @@ -633,14 +641,17 @@ class TypeResolution { OpenUnboundGenericTypeFn unboundTyOpener, HandlePlaceholderTypeReprFn placeholderHandler, OpenPackElementFn packElementOpener, + OpenRequirementFn requirementOpener = nullptr, SILTypeResolutionContext *silContext = nullptr); - static Type resolveContextualType( - TypeRepr *TyR, DeclContext *dc, GenericSignature genericSig, - TypeResolutionOptions opts, OpenUnboundGenericTypeFn unboundTyOpener, - HandlePlaceholderTypeReprFn placeholderHandler, - OpenPackElementFn packElementOpener, - SILTypeResolutionContext *silContext = nullptr); + static Type + resolveContextualType(TypeRepr *TyR, DeclContext *dc, + GenericSignature genericSig, TypeResolutionOptions opts, + OpenUnboundGenericTypeFn unboundTyOpener, + HandlePlaceholderTypeReprFn placeholderHandler, + OpenPackElementFn packElementOpener, + OpenRequirementFn requirementOpener = nullptr, + SILTypeResolutionContext *silContext = nullptr); public: TypeResolution withOptions(TypeResolutionOptions opts) const; @@ -672,6 +683,10 @@ class TypeResolution { return packElementOpener; } + OpenRequirementFn getRequirementOpener() const { + return requirementOpener; + } + /// Retrieves the generic signature for the context, or NULL if there is /// no generic signature to resolve types. GenericSignature getGenericSignature() const; diff --git a/lib/Sema/TypeOfReference.cpp b/lib/Sema/TypeOfReference.cpp index 30fdee97131b5..9f8e4031b2868 100644 --- a/lib/Sema/TypeOfReference.cpp +++ b/lib/Sema/TypeOfReference.cpp @@ -110,7 +110,8 @@ Type ConstraintSystem::openUnboundGenericType(GenericTypeDecl *decl, DC, std::nullopt, [](auto) -> Type { llvm_unreachable("should not be used"); }, [](auto &, auto) -> Type { llvm_unreachable("should not be used"); }, - [](auto, auto) -> Type { llvm_unreachable("should not be used"); }) + [](auto, auto) -> Type { llvm_unreachable("should not be used"); }, + [](auto, auto) { /*will be called, but we already handled reqs*/ }) .applyUnboundGenericArguments(decl, parentTy, SourceLoc(), arguments); if (!parentTy && !isTypeResolution) { result = DC->mapTypeIntoContext(result); @@ -198,47 +199,111 @@ static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, checkNestedTypeConstraints(cs, parentTy, locator, preparedOverload); } -Type ConstraintSystem::replaceInferableTypesWithTypeVars( - Type type, ConstraintLocatorBuilder locator, - PreparedOverloadBuilder *preparedOverload) { - if (!type->hasUnboundGenericType() && !type->hasPlaceholder()) - return type; +namespace { +class InferableTypeOpener final { + ConstraintSystem &cs; + ConstraintLocatorBuilder locator; + PreparedOverloadBuilder *preparedOverload; - auto flags = TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding | TVO_CanBindToHole; - - type = type.transformRec([&](Type type) -> std::optional { - if (auto unbound = type->getAs()) { - return openUnboundGenericType(unbound->getDecl(), unbound->getParent(), - locator, /*isTypeResolution=*/false, - preparedOverload); - } else if (auto *placeholderTy = type->getAs()) { - if (auto *typeRepr = - placeholderTy->getOriginator().dyn_cast()) { - if (isa(typeRepr)) { - return Type( - createTypeVariable( - getConstraintLocator(locator, LocatorPathElt::PlaceholderType(typeRepr)), - flags, preparedOverload)); - } - } else if (auto *var = placeholderTy->getOriginator().dyn_cast()) { - if (var->getName().hasDollarPrefix()) { - auto *repr = - new (type->getASTContext()) PlaceholderTypeRepr(var->getLoc()); - return Type( - createTypeVariable( - getConstraintLocator(locator, LocatorPathElt::PlaceholderType(repr)), - flags, preparedOverload)); - } - } +public: + InferableTypeOpener(ConstraintSystem &cs, ConstraintLocatorBuilder locator, + PreparedOverloadBuilder *preparedOverload) + : cs(cs), locator(locator), preparedOverload(preparedOverload) {} + + TypeVariableType *createTypeVariable(ConstraintLocator *loc) { + auto flags = + TVO_CanBindToNoEscape | TVO_PrefersSubtypeBinding | TVO_CanBindToHole; + return cs.createTypeVariable(loc, flags, preparedOverload); + } + + Type transformUnboundGenericType(UnboundGenericType *unbound) { + return cs.openUnboundGenericType(unbound->getDecl(), unbound->getParent(), + locator, /*isTypeResolution=*/false, + preparedOverload); + } + + Type transformPlaceholderType(PlaceholderType *placeholderTy) { + auto originator = placeholderTy->getOriginator(); + if (auto *typeRepr = originator.dyn_cast()) { + if (isa(typeRepr)) { + auto *loc = cs.getConstraintLocator( + locator, LocatorPathElt::PlaceholderType(typeRepr)); + return createTypeVariable(loc); } + } else if (auto *var = originator.dyn_cast()) { + if (var->getName().hasDollarPrefix()) { + auto *repr = + new (cs.getASTContext()) PlaceholderTypeRepr(var->getLoc()); + auto *loc = cs.getConstraintLocator( + locator, LocatorPathElt::PlaceholderType(repr)); + return createTypeVariable(loc); + } + } + return placeholderTy; + } + + void openGenericTypeRequirements(GenericTypeDecl *D, SubstitutionMap subs) { + OpenGenericTypeRequirements openReqs(cs, locator, preparedOverload); + openReqs(D, QuerySubstitutionMap{subs}); + } + + Type transformBoundGenericType(BoundGenericType *genericTy) { + SmallVector genericArgs; + for (auto arg : genericTy->getGenericArgs()) + genericArgs.push_back(transform(arg)); + + auto substTy = BoundGenericType::get( + genericTy->getDecl(), transform(genericTy->getParent()), genericArgs); + + openGenericTypeRequirements(substTy->getDecl(), + substTy->getContextSubstitutionMap()); + return substTy; + } + + Type transformTypeAliasType(TypeAliasType *aliasTy) { + SmallVector genericArgs; + for (auto arg : aliasTy->getDirectGenericArgs()) + genericArgs.push_back(transform(arg)); + + auto substTy = TypeAliasType::get( + aliasTy->getDecl(), transform(aliasTy->getParent()), genericArgs, + transform(aliasTy->getSinglyDesugaredType())); + openGenericTypeRequirements(substTy->getDecl(), + substTy->getSubstitutionMap()); + return substTy; + } + + Type transform(Type type) { + if (!type) + return type; + if (!type->hasUnboundGenericType() && !type->hasPlaceholder()) + return type; + + return type.transformRec([&](Type type) -> std::optional { + if (!type->hasUnboundGenericType() && !type->hasPlaceholder()) + return type; + + auto *tyPtr = type.getPointer(); + if (auto unbound = dyn_cast(tyPtr)) + return transformUnboundGenericType(unbound); + if (auto *placeholderTy = dyn_cast(tyPtr)) + return transformPlaceholderType(placeholderTy); + if (auto *genericTy = dyn_cast(tyPtr)) + return transformBoundGenericType(genericTy); + if (auto *aliasTy = dyn_cast(tyPtr)) + return transformTypeAliasType(aliasTy); return std::nullopt; }); + } +}; +} // end anonymous namespace - if (!type) - return ErrorType::get(getASTContext()); - - return type; +Type ConstraintSystem::replaceInferableTypesWithTypeVars( + Type type, ConstraintLocatorBuilder locator, + PreparedOverloadBuilder *preparedOverload) { + InferableTypeOpener opener(*this, locator, preparedOverload); + return opener.transform(type); } namespace { @@ -1646,17 +1711,30 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( DeclContext *innerDC = value->getInnermostDeclContext(); DeclContext *outerDC = value->getDeclContext(); + auto genericSig = innerDC->getGenericSignatureOfContext(); + // Open the type of the generic function or member of a generic type. Type openedType; + ArrayRef replacements; SmallVector localReplacements; - auto &replacements = replacementsPtr ? *replacementsPtr : 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. - auto genericSig = innerDC->getGenericSignatureOfContext(); - if (genericSig) { - openGenericParameters(outerDC, genericSig, replacements, locator, - preparedOverload); + // 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); + replacements = _replacements; } Type thrownErrorType; @@ -1867,9 +1945,6 @@ DeclReferenceType ConstraintSystem::getTypeOfMemberReference( isDynamicLookup, replacements); } - // If we opened up any type variables, record the replacements. - recordOpenedTypes(locator, replacements, preparedOverload); - return { origOpenedType, openedType, origType, type, thrownErrorType }; } diff --git a/test/Constraints/generics.swift b/test/Constraints/generics.swift index dab4c83408cdb..27bd5dc0bf4f2 100644 --- a/test/Constraints/generics.swift +++ b/test/Constraints/generics.swift @@ -452,6 +452,7 @@ class GenericClass {} func genericFunc(t: T) { _ = [T: GenericClass] // expected-error {{generic parameter 'A' could not be inferred}} // expected-note@-1 {{explicitly specify the generic arguments to fix this issue}} + // expected-error@-2 {{generic struct 'Dictionary' requires that 'T' conform to 'Hashable'}} } // https://github.com/apple/swift/issues/46113 diff --git a/test/Constraints/requirement_opening.swift b/test/Constraints/requirement_opening.swift new file mode 100644 index 0000000000000..df1900c4ba464 --- /dev/null +++ b/test/Constraints/requirement_opening.swift @@ -0,0 +1,54 @@ +// RUN: %target-typecheck-verify-swift + +struct K {} // expected-note 6{{'U' declared as parameter to type 'K'}} +protocol Q {} + +struct S1: ExpressibleByArrayLiteral { // expected-note 2{{where 'T' = 'K'}} + init(_ x: T) {} + init(arrayLiteral: T...) {} +} + +typealias R1 = S1 // expected-note {{where 'T' = 'K'}} expected-note 2{{where 'T' = 'K'}} + +func foo(_ x: K) { + let _ = [x] as S1 // expected-error {{generic struct 'S1' requires that 'K' conform to 'Q'}} + let _ = [x] as R1 // expected-error {{generic type alias 'R1' requires that 'K' conform to 'Q'}} + + let _: S1 = [x] // expected-error {{generic struct 'S1' requires that 'K' conform to 'Q'}} + // FIXME: We ought to be able to infer 'U' here. + let _: R1 = [x] // expected-error 2 {{generic type alias 'R1' requires that 'K' conform to 'Q'}} + // expected-error@-1 2 {{generic parameter 'U' could not be inferred}} +} + +protocol P2 { + associatedtype A +} + +struct S2: P2 {} // expected-note 3{{where 'A' = 'K'}} +typealias R2 = S2 // expected-note 2{{where 'A' = 'K'}} expected-note 2{{where 'A' = 'K'}} + +// Same as S2, but without the Q requirement. +struct S3: P2 {} +typealias R3 = S3 // expected-note {{where 'A' = 'K'}} expected-note {{where 'A' = 'K'}} + +func foo(_ y: T.A.Type) -> T {} +let _ = foo(K.self) as S2 // expected-error {{generic struct 'S2' requires that 'K' conform to 'Q'}} +let _ = foo(K.self) as R2 // expected-error {{generic type alias 'R2' requires that 'K' conform to 'Q'}} +let _ = foo(K.self) as R3 // expected-error {{generic type alias 'R3' requires that 'K' conform to 'Q'}} + +let _: S2 = foo(K.self) // expected-error {{generic struct 'S2' requires that 'K' conform to 'Q'}} +// FIXME: We ought to be able to infer 'U' here. +let _: R2 = foo(K.self) // expected-error 2{{generic type alias 'R2' requires that 'K' conform to 'Q'}} +// expected-error@-1 2 {{generic parameter 'U' could not be inferred}} +let _: R3 = foo(K.self) // expected-error {{generic type alias 'R3' requires that 'K' conform to 'Q'}} +// expected-error@-1 2 {{generic parameter 'U' could not be inferred}} + +func foo(_ x: T.Type, _ y: T.A.Type) {} +foo(S2<_>.self, K.self) // expected-error {{generic struct 'S2' requires that 'K' conform to 'Q'}} +foo(R2<_>.self, K.self) // expected-error {{generic type alias 'R2' requires that 'K' conform to 'Q'}} + +struct S4 { // expected-note {{where 'T' = 'Int'}} + init(_ x: T) {} +} + +_ = S4<_>(0) // expected-error {{generic struct 'S4' requires that 'Int' conform to 'Q'}} diff --git a/test/decl/nested/type_in_type.swift b/test/decl/nested/type_in_type.swift index 530cd903f5ad2..cbfee535b778d 100644 --- a/test/decl/nested/type_in_type.swift +++ b/test/decl/nested/type_in_type.swift @@ -383,7 +383,7 @@ struct Kitten : ExpressibleByCatLiteral {} struct Puppy : ExpressibleByDogLiteral {} struct Claws { // expected-note 3 {{'A' declared as parameter to type 'Claws'}} - struct Fangs { } // expected-note {{where 'B' = 'NotADog'}} + struct Fangs { } // expected-note 3 {{where 'B' = 'NotADog'}} } struct NotADog {} @@ -407,9 +407,14 @@ do { // expected-note@-2 {{explicitly specify the generic arguments to fix this issue}} {{36-36=<<#A: ExpressibleByCatLiteral#>>}} let _: Claws.Fangs = something() // expected-error@-1 {{generic parameter 'A' could not be inferred}} + // expected-error@-2 {{generic struct 'Fangs' requires that 'NotADog' conform to 'ExpressibleByDogLiteral'}} + + // FIXME: We get a duplicate diagnostic here because we don't differentiate + // constraint locators when opening generic requirements, we just use a + // locator for the top-level TypeRepr. _ = Claws.Fangs() // expected-error@-1 {{generic parameter 'A' could not be inferred}} - // expected-error@-2 {{generic struct 'Fangs' requires that 'NotADog' conform to 'ExpressibleByDogLiteral'}} + // expected-error@-2 2{{generic struct 'Fangs' requires that 'NotADog' conform to 'ExpressibleByDogLiteral'}} // expected-note@-3 {{explicitly specify the generic arguments to fix this issue}} {{12-12=<<#A: ExpressibleByCatLiteral#>>}} } @@ -427,3 +432,17 @@ extension OuterGeneric.MidNonGeneric { } } + +protocol P {} + +struct A {} +extension A where T: P { // expected-note {{where 'T' = 'T'}} + struct B { + init(_ u: U) {} + } +} +extension A { + func bar() { + B(0) // expected-error {{referencing generic struct 'B' on 'A' requires that 'T' conform to 'P'}} + } +}