Skip to content

Commit 7d28973

Browse files
committed
Fix issue in release builds by allocating memory for captures
1 parent 9458e52 commit 7d28973

File tree

2 files changed

+139
-130
lines changed

2 files changed

+139
-130
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 138 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -6976,169 +6976,178 @@ void TypeChecker::checkExistentialTypes(
69766976
checker.checkRequirements(genericParams->getRequirements());
69776977
}
69786978

6979-
/// Retrieves the valid result types of the result builder
6980-
/// (the return types of `buildFinalResult` / `buildBlock` /
6981-
/// `buildPartialResult`).
6982-
llvm::SmallVector<Type, 4>
6983-
retrieveResultBuilderResultTypes(NominalTypeDecl *builder) {
6984-
ASTContext &ctx = builder->getASTContext();
6985-
llvm::SmallVector<Type, 4> resultTypes;
6986-
6987-
Identifier methodIds[] = {ctx.Id_buildFinalResult, ctx.Id_buildBlock,
6988-
ctx.Id_buildPartialBlock};
6989-
6990-
for (auto methodId : methodIds) {
6991-
SmallVector<ValueDecl *, 4> potentialMatches;
6992-
bool supportsMethod = TypeChecker::typeSupportsBuilderOp(
6993-
builder->getDeclaredInterfaceType(), builder, methodId,
6994-
/*argLabels=*/{}, &potentialMatches);
6995-
6996-
if (!supportsMethod)
6997-
continue;
6979+
/// Opens a result builder `UnboundGenericType` into a `BoundGenericType`
6980+
/// by creating and solving a constraint between the result builder's
6981+
/// result type and the return type of the attached declaration.
6982+
struct ResultBuilderUnboundTypeOpener {
6983+
DeclContext *dc;
6984+
CustomAttr *attr;
6985+
6986+
Type operator()(UnboundGenericType *unboundTy) const {
6987+
auto resultBuilderDecl =
6988+
dyn_cast_or_null<NominalTypeDecl>(unboundTy->getDecl());
6989+
if (!resultBuilderDecl ||
6990+
!resultBuilderDecl->getAttrs().hasAttribute<ResultBuilderAttr>()) {
6991+
return invalidResultBuilderType(unboundTy);
6992+
}
6993+
6994+
Decl *owningDecl = attr->getOwner().getAsDecl();
6995+
if (!owningDecl) {
6996+
return invalidResultBuilderType(unboundTy);
6997+
}
6998+
6999+
// Retrieve the return type of the owning declaration that
7000+
// provides type inference for the result builder type.
7001+
Type owningDeclResultType;
7002+
if (auto varDecl = dyn_cast<VarDecl>(owningDecl)) {
7003+
if (auto closureResultType =
7004+
varDecl->getInterfaceType()->getAs<FunctionType>()) {
7005+
owningDeclResultType = closureResultType->getResult();
7006+
} else {
7007+
owningDeclResultType = varDecl->getInterfaceType();
7008+
}
7009+
} else if (auto funcDecl = dyn_cast<FuncDecl>(owningDecl)) {
7010+
owningDeclResultType = funcDecl->getResultInterfaceType();
7011+
}
69987012

6999-
for (auto decl : potentialMatches) {
7000-
auto func = dyn_cast<FuncDecl>(decl);
7001-
if (!func || !func->isStatic())
7002-
continue;
7013+
if (!owningDeclResultType) {
7014+
return invalidResultBuilderType(unboundTy);
7015+
}
70037016

7004-
auto resultType = func->getResultInterfaceType();
7005-
if (!resultType || resultType->hasError())
7006-
continue;
7017+
// Retrieve the supported result types of the result builder.
7018+
auto resultTypes = retrieveResultBuilderResultTypes(resultBuilderDecl);
7019+
if (resultTypes.empty()) {
7020+
return invalidResultBuilderType(unboundTy);
7021+
}
70077022

7008-
// Add the result type if we haven't seen it before
7009-
bool isDuplicate = false;
7010-
for (auto existingType : resultTypes) {
7011-
if (existingType->isEqual(resultType)) {
7012-
isDuplicate = true;
7013-
break;
7014-
}
7015-
}
7023+
auto genericSig = resultBuilderDecl->getGenericSignature();
7024+
7025+
// Try each result type and return the first one that produces a valid
7026+
// solution
7027+
for (auto componentType : resultTypes) {
7028+
using namespace constraints;
7029+
ConstraintSystem cs(dc, std::nullopt);
70167030

7017-
if (!isDuplicate) {
7018-
resultTypes.push_back(resultType);
7031+
// Create a type variable for each of the result builder's generic params
7032+
llvm::SmallVector<Type, 8> typeVarReplacements;
7033+
llvm::SmallVector<TypeVariableType *, 8> typeVars;
7034+
for (unsigned i = 0; i < genericSig.getGenericParams().size(); ++i) {
7035+
auto locator = cs.getConstraintLocator(
7036+
resultBuilderDecl, {ConstraintLocator::GenericArgument, i});
7037+
auto typeVar = cs.createTypeVariable(locator, TVO_CanBindToHole);
7038+
typeVarReplacements.push_back(typeVar);
7039+
typeVars.push_back(typeVar);
70197040
}
7020-
}
7021-
}
70227041

7023-
return resultTypes;
7024-
}
7042+
// Replace any references to the result builder's generic params
7043+
// in the result type with the corresponding type variables.
7044+
auto subMap = SubstitutionMap::get(genericSig, typeVarReplacements,
7045+
LookUpConformanceInModule());
70257046

7026-
Type invalidResultBuilderType(UnboundGenericType* unboundTy,
7027-
CustomAttr *attr, DeclContext *dc) {
7028-
dc->getASTContext().Diags.diagnose(
7029-
attr->getTypeExpr()->getLoc(),
7030-
diag::result_builder_generic_inference_failed,
7031-
unboundTy->getDecl()->getName());
7032-
7033-
return ErrorType::get(dc->getASTContext());
7034-
}
7047+
auto componentTypeWithTypeVars = componentType.subst(subMap);
70357048

7036-
/// Opens a result builder `UnboundGenericType` into a `BoundGenericType`
7037-
/// by creating and solving a constraint between the result builder's
7038-
/// result type and the return type of the attached declaration.
7039-
Type openUnboundResultBuilderType(UnboundGenericType* unboundTy,
7040-
CustomAttr *attr, DeclContext *dc) {
7041-
auto resultBuilderDecl =
7042-
dyn_cast_or_null<NominalTypeDecl>(unboundTy->getDecl());
7043-
if (!resultBuilderDecl) {
7044-
return invalidResultBuilderType(unboundTy, attr, dc);
7045-
}
7046-
7047-
// Retrieve the return type of the owning declaration that
7048-
// provides type inference for the result builder type.
7049-
Type owningDeclResultType;
7050-
Decl *owningDecl = attr->getOwner().getAsDecl();
7051-
7052-
if (auto varDecl = dyn_cast_or_null<VarDecl>(owningDecl)) {
7053-
if (auto closureResultType = varDecl->getInterfaceType()->getAs<FunctionType>()) {
7054-
owningDeclResultType = closureResultType->getResult();
7055-
} else {
7056-
owningDeclResultType = varDecl->getInterfaceType();
7049+
// The result builder result type should be equal to the return type of
7050+
// the attached declaration.
7051+
cs.addConstraint(ConstraintKind::Equal, owningDeclResultType,
7052+
componentTypeWithTypeVars,
7053+
/*preparedOverload:*/ nullptr);
7054+
7055+
auto solution = cs.solveSingle();
7056+
7057+
// If a solution exists, bind the result builder's generic params to the
7058+
// solved types.
7059+
if (solution) {
7060+
llvm::SmallVector<Type, 8> solvedReplacements;
7061+
for (auto typeVar : typeVars) {
7062+
solvedReplacements.push_back(solution->typeBindings[typeVar]);
7063+
}
7064+
7065+
return BoundGenericType::get(resultBuilderDecl, unboundTy->getParent(),
7066+
solvedReplacements);
7067+
}
70577068
}
7058-
} else if (auto funcDecl = dyn_cast_or_null<FuncDecl>(owningDecl)) {
7059-
owningDeclResultType = funcDecl->getResultInterfaceType();
7060-
}
7061-
7062-
if (!owningDeclResultType) {
7063-
return invalidResultBuilderType(unboundTy, attr, dc);
7069+
7070+
// No result type produced a valid solution
7071+
return invalidResultBuilderType(unboundTy);
70647072
}
70657073

7066-
// Retrieve the supported result types of the result builder.
7067-
auto resultTypes = retrieveResultBuilderResultTypes(resultBuilderDecl);
7068-
if (resultTypes.empty()) {
7069-
return invalidResultBuilderType(unboundTy, attr, dc);
7074+
private:
7075+
Type invalidResultBuilderType(UnboundGenericType *unboundTy) const {
7076+
dc->getASTContext().Diags.diagnose(
7077+
attr->getTypeExpr()->getLoc(),
7078+
diag::result_builder_generic_inference_failed,
7079+
unboundTy->getDecl()->getName());
7080+
7081+
return ErrorType::get(dc->getASTContext());
70707082
}
70717083

7072-
auto genericSig = resultBuilderDecl->getGenericSignature();
7084+
/// Retrieves the valid result types of the result builder
7085+
/// (the return types of `buildFinalResult` / `buildBlock` /
7086+
/// `buildPartialBlock`).
7087+
llvm::SmallVector<Type, 4>
7088+
retrieveResultBuilderResultTypes(NominalTypeDecl *builder) const {
7089+
ASTContext &ctx = builder->getASTContext();
7090+
llvm::SmallVector<Type, 4> resultTypes;
70737091

7074-
for (auto componentType : resultTypes) {
7075-
using namespace constraints;
7076-
ConstraintSystem cs(dc, std::nullopt);
7092+
Identifier methodIds[] = {ctx.Id_buildFinalResult, ctx.Id_buildBlock,
7093+
ctx.Id_buildPartialBlock};
70777094

7078-
// Create a type variable for each of the result builder's generic params
7079-
llvm::SmallVector<Type, 8> typeVarReplacements;
7080-
llvm::SmallVector<TypeVariableType *, 8> typeVars;
7081-
for (unsigned i = 0; i < genericSig.getGenericParams().size(); ++i) {
7082-
auto locator = cs.getConstraintLocator(
7083-
resultBuilderDecl, {ConstraintLocator::GenericArgument, i});
7084-
auto typeVar = cs.createTypeVariable(locator, TVO_CanBindToHole);
7085-
typeVarReplacements.push_back(typeVar);
7086-
typeVars.push_back(typeVar);
7087-
}
7095+
for (auto methodId : methodIds) {
7096+
SmallVector<ValueDecl *, 4> potentialMatches;
7097+
bool supportsMethod = TypeChecker::typeSupportsBuilderOp(
7098+
builder->getDeclaredInterfaceType(), builder, methodId,
7099+
/*argLabels=*/{}, &potentialMatches);
70887100

7089-
// Replace any references to the result builder's generic params
7090-
// in the result type with the corresponding type variables.
7091-
auto subMap = SubstitutionMap::get(genericSig, typeVarReplacements,
7092-
LookUpConformanceInModule());
7101+
if (!supportsMethod)
7102+
continue;
70937103

7094-
auto componentTypeWithTypeVars = componentType.subst(subMap);
7104+
for (auto decl : potentialMatches) {
7105+
auto func = dyn_cast<FuncDecl>(decl);
7106+
if (!func || !func->isStatic())
7107+
continue;
70957108

7096-
// The result builder result type should be equal to the return type of the
7097-
// attached declaration.
7098-
cs.addConstraint(ConstraintKind::Equal, owningDeclResultType,
7099-
componentTypeWithTypeVars,
7100-
/*preparedOverload:*/ nullptr);
7109+
auto resultType = func->getResultInterfaceType();
7110+
if (!resultType || resultType->hasError())
7111+
continue;
71017112

7102-
auto solution = cs.solveSingle();
7113+
// Add the result type if we haven't seen it before
7114+
bool isDuplicate = false;
7115+
for (auto existingType : resultTypes) {
7116+
if (existingType->isEqual(resultType)) {
7117+
isDuplicate = true;
7118+
break;
7119+
}
7120+
}
71037121

7104-
// If a solution exists, bind the result builder's generic params to the
7105-
// solved types.
7106-
if (solution) {
7107-
llvm::SmallVector<Type, 8> solvedReplacements;
7108-
for (auto typeVar : typeVars) {
7109-
solvedReplacements.push_back(solution->typeBindings[typeVar]);
7122+
if (!isDuplicate) {
7123+
resultTypes.push_back(resultType);
7124+
}
71107125
}
7111-
7112-
return BoundGenericType::get(resultBuilderDecl, unboundTy->getParent(),
7113-
solvedReplacements);
71147126
}
7115-
}
71167127

7117-
// No result type produced a valid solution
7118-
return invalidResultBuilderType(unboundTy, attr, dc);
7119-
}
7128+
return resultTypes;
7129+
}
7130+
};
71207131

71217132
Type CustomAttrTypeRequest::evaluate(Evaluator &eval, CustomAttr *attr,
71227133
DeclContext *dc,
71237134
CustomAttrTypeKind typeKind) const {
71247135
const TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl);
71257136

71267137
OpenUnboundGenericTypeFn unboundTyOpener = nullptr;
7127-
7128-
// Property delegates allow their type to be an unbound generic.
7138+
7139+
// Property wrappers and result builders allow their type to be an unbound
7140+
// generic.
71297141
if (typeKind == CustomAttrTypeKind::PropertyWrapper) {
71307142
unboundTyOpener = TypeResolution::defaultUnboundTypeOpener;
7131-
}
7132-
7133-
/// Result builder types can have their generics parameters inferred
7134-
/// from the attached declaration.
7135-
else if (typeKind == CustomAttrTypeKind::ResultBuilder){
7136-
unboundTyOpener = [attr, dc](UnboundGenericType* unboundTy) -> Type {
7137-
return openUnboundResultBuilderType(unboundTy, attr, dc);
7138-
};
7143+
} else if (typeKind == CustomAttrTypeKind::ResultBuilder) {
7144+
auto &ctx = dc->getASTContext();
7145+
void *mem = ctx.Allocate(sizeof(ResultBuilderUnboundTypeOpener),
7146+
alignof(ResultBuilderUnboundTypeOpener));
7147+
unboundTyOpener = *new (mem) ResultBuilderUnboundTypeOpener{dc, attr};
71397148
}
71407149

7141-
const auto type = TypeResolution::resolveContextualType(
7150+
auto type = TypeResolution::resolveContextualType(
71427151
attr->getTypeRepr(), dc, options, unboundTyOpener,
71437152
/*placeholderHandler*/ nullptr, /*packElementOpener*/ nullptr);
71447153

test/decl/var/result_builders.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ struct GenericContainer<T> {
7272
struct Maker {} // expected-error {{result builder must provide at least one static 'buildBlock' method}}
7373
}
7474

75-
func makeParamUnbound(@GenericMaker // expected-error {{unable to infer generic parameters for result builder 'GenericMaker'}}
75+
func makeParamUnbound(@GenericMaker
7676
fn: () -> ()) {}
7777

7878
func makeParamBound(@GenericMaker<Int>

0 commit comments

Comments
 (0)