Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions include/swift/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 7 additions & 2 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)));
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 33 additions & 0 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines +3422 to +3429
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The alternative approach here would be adjusting getTypeOfMemberReference to avoid opening requirements that are already imposed by the base type (b4adeff), but that needs a workaround for at least LLDB, and generally seems like it could be more error prone. Given we need to fix the locators here anyway to be unique, this seems like the simplest way of avoiding the duplicate diagnostics


// 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) {
Expand Down
149 changes: 77 additions & 72 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Loading