mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[CS] Open generic requirements for types with unbound + placeholder types
- Introduce a generic requirements opening function for type resolution, which is used by the constraint system in cases where we need to impose requirements on opened type variables. - Refactor `replaceInferableTypesWithTypeVars` to use this function when opening generic types that contain either placeholder or unbound generic types. Together these changes ensure that we don't drop generic requirements when an unbound generic or placeholder type is used as a generic argument.
This commit is contained in:
@@ -5796,6 +5796,23 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3414,6 +3414,39 @@ bool ConstraintSystem::diagnoseAmbiguity(ArrayRef<Solution> 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<OpenedType, 4> 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) {
|
||||
|
||||
@@ -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<NominalTypeDecl>(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,
|
||||
|
||||
@@ -574,6 +574,9 @@ using HandlePlaceholderTypeReprFn =
|
||||
using OpenPackElementFn =
|
||||
llvm::function_ref<Type(Type, PackElementTypeRepr *)>;
|
||||
|
||||
using OpenRequirementFn =
|
||||
llvm::function_ref<void(GenericTypeDecl *, TypeSubstitutionFn)>;
|
||||
|
||||
/// 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 @@ private:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
public:
|
||||
InferableTypeOpener(ConstraintSystem &cs, ConstraintLocatorBuilder locator,
|
||||
PreparedOverloadBuilder *preparedOverload)
|
||||
: cs(cs), locator(locator), preparedOverload(preparedOverload) {}
|
||||
|
||||
type = type.transformRec([&](Type type) -> std::optional<Type> {
|
||||
if (auto unbound = type->getAs<UnboundGenericType>()) {
|
||||
return openUnboundGenericType(unbound->getDecl(), unbound->getParent(),
|
||||
locator, /*isTypeResolution=*/false,
|
||||
preparedOverload);
|
||||
} else if (auto *placeholderTy = type->getAs<PlaceholderType>()) {
|
||||
if (auto *typeRepr =
|
||||
placeholderTy->getOriginator().dyn_cast<TypeRepr *>()) {
|
||||
if (isa<PlaceholderTypeRepr>(typeRepr)) {
|
||||
return Type(
|
||||
createTypeVariable(
|
||||
getConstraintLocator(locator, LocatorPathElt::PlaceholderType(typeRepr)),
|
||||
flags, preparedOverload));
|
||||
}
|
||||
} else if (auto *var = placeholderTy->getOriginator().dyn_cast<VarDecl *>()) {
|
||||
if (var->getName().hasDollarPrefix()) {
|
||||
auto *repr =
|
||||
new (type->getASTContext()) PlaceholderTypeRepr(var->getLoc());
|
||||
return Type(
|
||||
createTypeVariable(
|
||||
getConstraintLocator(locator, LocatorPathElt::PlaceholderType(repr)),
|
||||
flags, 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<TypeRepr *>()) {
|
||||
if (isa<PlaceholderTypeRepr>(typeRepr)) {
|
||||
auto *loc = cs.getConstraintLocator(
|
||||
locator, LocatorPathElt::PlaceholderType(typeRepr));
|
||||
return createTypeVariable(loc);
|
||||
}
|
||||
} else if (auto *var = originator.dyn_cast<VarDecl *>()) {
|
||||
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<Type, 4> 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<Type, 4> 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<Type> {
|
||||
if (!type->hasUnboundGenericType() && !type->hasPlaceholder())
|
||||
return type;
|
||||
|
||||
auto *tyPtr = type.getPointer();
|
||||
if (auto unbound = dyn_cast<UnboundGenericType>(tyPtr))
|
||||
return transformUnboundGenericType(unbound);
|
||||
if (auto *placeholderTy = dyn_cast<PlaceholderType>(tyPtr))
|
||||
return transformPlaceholderType(placeholderTy);
|
||||
if (auto *genericTy = dyn_cast<BoundGenericType>(tyPtr))
|
||||
return transformBoundGenericType(genericTy);
|
||||
if (auto *aliasTy = dyn_cast<TypeAliasType>(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 {
|
||||
|
||||
@@ -452,6 +452,7 @@ class GenericClass<A> {}
|
||||
func genericFunc<T>(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
|
||||
|
||||
54
test/Constraints/requirement_opening.swift
Normal file
54
test/Constraints/requirement_opening.swift
Normal file
@@ -0,0 +1,54 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
struct K<U> {} // expected-note 6{{'U' declared as parameter to type 'K'}}
|
||||
protocol Q {}
|
||||
|
||||
struct S1<T: Q>: ExpressibleByArrayLiteral { // expected-note 2{{where 'T' = 'K<Int>'}}
|
||||
init(_ x: T) {}
|
||||
init(arrayLiteral: T...) {}
|
||||
}
|
||||
|
||||
typealias R1<T: Q> = S1<T> // expected-note {{where 'T' = 'K<Int>'}} expected-note 2{{where 'T' = 'K<U>'}}
|
||||
|
||||
func foo(_ x: K<Int>) {
|
||||
let _ = [x] as S1<K> // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
|
||||
let _ = [x] as R1<K> // expected-error {{generic type alias 'R1' requires that 'K<Int>' conform to 'Q'}}
|
||||
|
||||
let _: S1<K> = [x] // expected-error {{generic struct 'S1' requires that 'K<Int>' conform to 'Q'}}
|
||||
// FIXME: We ought to be able to infer 'U' here.
|
||||
let _: R1<K> = [x] // expected-error 2 {{generic type alias 'R1' requires that 'K<U>' conform to 'Q'}}
|
||||
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
|
||||
}
|
||||
|
||||
protocol P2 {
|
||||
associatedtype A
|
||||
}
|
||||
|
||||
struct S2<A: Q>: P2 {} // expected-note 3{{where 'A' = 'K<Int>'}}
|
||||
typealias R2<A: Q> = S2<A> // expected-note 2{{where 'A' = 'K<Int>'}} expected-note 2{{where 'A' = 'K<U>'}}
|
||||
|
||||
// Same as S2, but without the Q requirement.
|
||||
struct S3<A>: P2 {}
|
||||
typealias R3<A: Q> = S3<A> // expected-note {{where 'A' = 'K<Int>'}} expected-note {{where 'A' = 'K<U>'}}
|
||||
|
||||
func foo<T: P2>(_ y: T.A.Type) -> T {}
|
||||
let _ = foo(K<Int>.self) as S2<K> // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
|
||||
let _ = foo(K<Int>.self) as R2<K> // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
|
||||
let _ = foo(K<Int>.self) as R3<K> // expected-error {{generic type alias 'R3' requires that 'K<Int>' conform to 'Q'}}
|
||||
|
||||
let _: S2<K> = foo(K<Int>.self) // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
|
||||
// FIXME: We ought to be able to infer 'U' here.
|
||||
let _: R2<K> = foo(K<Int>.self) // expected-error 2{{generic type alias 'R2' requires that 'K<U>' conform to 'Q'}}
|
||||
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
|
||||
let _: R3<K> = foo(K<Int>.self) // expected-error {{generic type alias 'R3' requires that 'K<U>' conform to 'Q'}}
|
||||
// expected-error@-1 2 {{generic parameter 'U' could not be inferred}}
|
||||
|
||||
func foo<T: P2>(_ x: T.Type, _ y: T.A.Type) {}
|
||||
foo(S2<_>.self, K<Int>.self) // expected-error {{generic struct 'S2' requires that 'K<Int>' conform to 'Q'}}
|
||||
foo(R2<_>.self, K<Int>.self) // expected-error {{generic type alias 'R2' requires that 'K<Int>' conform to 'Q'}}
|
||||
|
||||
struct S4<T: Q> { // expected-note {{where 'T' = 'Int'}}
|
||||
init(_ x: T) {}
|
||||
}
|
||||
|
||||
_ = S4<_>(0) // expected-error {{generic struct 'S4' requires that 'Int' conform to 'Q'}}
|
||||
@@ -383,7 +383,7 @@ struct Kitten : ExpressibleByCatLiteral {}
|
||||
struct Puppy : ExpressibleByDogLiteral {}
|
||||
|
||||
struct Claws<A: ExpressibleByCatLiteral> { // expected-note 3 {{'A' declared as parameter to type 'Claws'}}
|
||||
struct Fangs<B: ExpressibleByDogLiteral> { } // expected-note {{where 'B' = 'NotADog'}}
|
||||
struct Fangs<B: ExpressibleByDogLiteral> { } // 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<NotADog> = 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<NotADog>()
|
||||
// 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#>>}}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user