Skip to content

Commit 801cd64

Browse files
authored
Merge pull request #84390 from hamishknight/out-of-place
[Sema] Reject placeholders in type resolution for param and result types
2 parents ac26e28 + 0b3747d commit 801cd64

15 files changed

+53
-285
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4863,10 +4863,6 @@ NOTE(descriptive_generic_type_declared_here,none,
48634863

48644864
ERROR(placeholder_type_not_allowed,none,
48654865
"type placeholder not allowed here", ())
4866-
ERROR(placeholder_type_not_allowed_in_return_type,none,
4867-
"type placeholder may not appear in function return type", ())
4868-
ERROR(placeholder_type_not_allowed_in_parameter,none,
4869-
"type placeholder may not appear in top-level parameter", ())
48704866
ERROR(placeholder_type_not_allowed_in_pattern,none,
48714867
"placeholder type may not appear as type of a variable", ())
48724868
NOTE(replace_placeholder_with_inferred_type,none,

include/swift/AST/TypeMatcher.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,6 @@ class TypeMatcher {
117117
#define SINGLETON_TYPE(SHORT_ID, ID) TRIVIAL_CASE(ID##Type)
118118
#include "swift/AST/TypeNodes.def"
119119

120-
bool visitPlaceholderType(CanPlaceholderType firstType, Type secondType,
121-
Type sugaredFirstType) {
122-
// Placeholder types never match.
123-
return mismatch(firstType.getPointer(), secondType, sugaredFirstType);
124-
}
125-
126120
bool visitUnresolvedType(CanUnresolvedType firstType, Type secondType,
127121
Type sugaredFirstType) {
128122
// Unresolved types never match.

include/swift/Sema/CSFix.h

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,6 @@ enum class FixKind : uint8_t {
362362
/// resolved.
363363
SpecifyTypeForPlaceholder,
364364

365-
/// Ignore an invalid placeholder in a decl's interface type.
366-
IgnoreInvalidPlaceholderInDeclRef,
367-
368365
/// Allow Swift -> C pointer conversion in an argument position
369366
/// of a Swift function.
370367
AllowSwiftToCPointerConversion,
@@ -3194,30 +3191,6 @@ class SpecifyTypeForPlaceholder final : public ConstraintFix {
31943191
}
31953192
};
31963193

3197-
class IgnoreInvalidPlaceholderInDeclRef final : public ConstraintFix {
3198-
IgnoreInvalidPlaceholderInDeclRef(ConstraintSystem &cs,
3199-
ConstraintLocator *locator)
3200-
: ConstraintFix(cs, FixKind::IgnoreInvalidPlaceholderInDeclRef, locator) {}
3201-
3202-
public:
3203-
std::string getName() const override {
3204-
return "ignore invalid placeholder in decl ref";
3205-
}
3206-
3207-
bool diagnose(const Solution &solution, bool asNote = false) const override;
3208-
3209-
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3210-
return diagnose(*commonFixes.front().first);
3211-
}
3212-
3213-
static IgnoreInvalidPlaceholderInDeclRef *create(ConstraintSystem &cs,
3214-
ConstraintLocator *locator);
3215-
3216-
static bool classof(const ConstraintFix *fix) {
3217-
return fix->getKind() == FixKind::IgnoreInvalidPlaceholderInDeclRef;
3218-
}
3219-
};
3220-
32213194
class AllowRefToInvalidDecl final : public ConstraintFix {
32223195
AllowRefToInvalidDecl(ConstraintSystem &cs, ConstraintLocator *locator)
32233196
: ConstraintFix(cs, FixKind::AllowRefToInvalidDecl, locator) {}

lib/AST/TypeCheckRequests.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,11 +1222,16 @@ std::optional<Type> InterfaceTypeRequest::getCachedResult() const {
12221222
void InterfaceTypeRequest::cacheResult(Type type) const {
12231223
auto *decl = std::get<0>(getStorage());
12241224
if (type) {
1225-
assert(!type->hasTypeVariable() && "Type variable in interface type");
1226-
assert(!type->is<InOutType>() && "Interface type must be materializable");
1227-
assert(!type->hasPrimaryArchetype() && "Archetype in interface type");
1228-
assert(decl->getDeclContext()->isLocalContext() || !type->hasLocalArchetype() &&
1225+
ASSERT(!type->hasTypeVariable() && "Type variable in interface type");
1226+
ASSERT(!type->is<InOutType>() && "Interface type must be materializable");
1227+
ASSERT(!type->hasPrimaryArchetype() && "Archetype in interface type");
1228+
ASSERT(decl->getDeclContext()->isLocalContext() || !type->hasLocalArchetype() &&
12291229
"Local archetype in interface type of non-local declaration");
1230+
// Placeholders are only permitted in closure parameters.
1231+
if (!(isa<ParamDecl>(decl) &&
1232+
isa<AbstractClosureExpr>(decl->getDeclContext()))) {
1233+
ASSERT(!type->hasPlaceholder() && "Placeholder in interface type");
1234+
}
12301235
}
12311236
decl->TypeAndAccess.setPointer(type);
12321237
}

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2317,9 +2317,9 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
23172317
/// Deduce associated types from dependent member types in the witness.
23182318
bool mismatch(DependentMemberType *firstDepMember,
23192319
TypeBase *secondType, Type sugaredFirstType) {
2320-
// If the second type is an error or placeholder, don't look at it
2321-
// further, but proceed to find other matches.
2322-
if (secondType->hasError() || secondType->hasPlaceholder())
2320+
// If the second type is an error, don't look at it further, but proceed
2321+
// to find other matches.
2322+
if (secondType->hasError())
23232323
return true;
23242324

23252325
// If the second type is a generic parameter of the witness, the match

lib/Sema/CSFix.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,20 +2264,6 @@ SpecifyTypeForPlaceholder::create(ConstraintSystem &cs,
22642264
return new (cs.getAllocator()) SpecifyTypeForPlaceholder(cs, locator);
22652265
}
22662266

2267-
IgnoreInvalidPlaceholderInDeclRef *
2268-
IgnoreInvalidPlaceholderInDeclRef::create(ConstraintSystem &cs, ConstraintLocator *locator) {
2269-
return new (cs.getAllocator()) IgnoreInvalidPlaceholderInDeclRef(cs, locator);
2270-
}
2271-
2272-
bool
2273-
IgnoreInvalidPlaceholderInDeclRef::diagnose(const Solution &solution,
2274-
bool asNote) const {
2275-
// These are diagnosed separately. Unfortunately we can't enforce that a
2276-
// diagnostic has already been emitted since their diagnosis depends on e.g
2277-
// type-checking a function body for a placeholder result of a function.
2278-
return true;
2279-
}
2280-
22812267
bool AllowRefToInvalidDecl::diagnose(const Solution &solution,
22822268
bool asNote) const {
22832269
ReferenceToInvalidDeclaration failure(solution, getLocator());

lib/Sema/CSSimplify.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16099,7 +16099,6 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1609916099
case FixKind::AllowValueExpansionWithoutPackReferences:
1610016100
case FixKind::IgnoreInvalidPatternInExpr:
1610116101
case FixKind::IgnoreInvalidPlaceholder:
16102-
case FixKind::IgnoreInvalidPlaceholderInDeclRef:
1610316102
case FixKind::IgnoreOutOfPlaceThenStmt:
1610416103
case FixKind::IgnoreMissingEachKeyword:
1610516104
case FixKind::AllowInlineArrayLiteralCountMismatch:

lib/Sema/MiscDiagnostics.cpp

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3868,71 +3868,6 @@ class OpaqueUnderlyingTypeChecker : public ASTWalker {
38683868
}
38693869
};
38703870

3871-
class ReturnTypePlaceholderReplacer : public ASTWalker {
3872-
FuncDecl *Implementation;
3873-
BraceStmt *Body;
3874-
SmallVector<Type, 4> Candidates;
3875-
3876-
bool HasInvalidReturn = false;
3877-
3878-
public:
3879-
ReturnTypePlaceholderReplacer(FuncDecl *Implementation, BraceStmt *Body)
3880-
: Implementation(Implementation), Body(Body) {}
3881-
3882-
void check() {
3883-
auto *resultRepr = Implementation->getResultTypeRepr();
3884-
if (!resultRepr) {
3885-
return;
3886-
}
3887-
3888-
Implementation->getASTContext()
3889-
.Diags
3890-
.diagnose(resultRepr->getLoc(),
3891-
diag::placeholder_type_not_allowed_in_return_type)
3892-
.highlight(resultRepr->getSourceRange());
3893-
3894-
Body->walk(*this);
3895-
3896-
// If given function has any invalid returns in the body
3897-
// let's not try to validate the types, since it wouldn't
3898-
// be accurate.
3899-
if (HasInvalidReturn)
3900-
return;
3901-
3902-
auto writtenType = Implementation->getResultInterfaceType();
3903-
llvm::SmallPtrSet<TypeBase *, 8> seenTypes;
3904-
for (auto candidate : Candidates) {
3905-
if (!seenTypes.insert(candidate.getPointer()).second) {
3906-
continue;
3907-
}
3908-
TypeChecker::notePlaceholderReplacementTypes(writtenType, candidate);
3909-
}
3910-
}
3911-
3912-
MacroWalking getMacroWalkingBehavior() const override {
3913-
return MacroWalking::ArgumentsAndExpansion;
3914-
}
3915-
3916-
PreWalkResult<Expr *> walkToExprPre(Expr *E) override { return Action::Continue(E); }
3917-
3918-
PreWalkResult<Stmt *> walkToStmtPre(Stmt *S) override {
3919-
if (auto *RS = dyn_cast<ReturnStmt>(S)) {
3920-
if (RS->hasResult()) {
3921-
auto resultTy = RS->getResult()->getType();
3922-
HasInvalidReturn |= resultTy.isNull() || resultTy->hasError();
3923-
Candidates.push_back(resultTy);
3924-
}
3925-
}
3926-
3927-
return Action::Continue(S);
3928-
}
3929-
3930-
// Don't descend into nested decls.
3931-
PreWalkAction walkToDeclPre(Decl *D) override {
3932-
return Action::SkipNode();
3933-
}
3934-
};
3935-
39363871
} // end anonymous namespace
39373872

39383873
SourceLoc swift::getFixItLocForVarToLet(VarDecl *var) {
@@ -4545,13 +4480,6 @@ void swift::performAbstractFuncDeclDiagnostics(AbstractFunctionDecl *AFD) {
45454480
OpaqueUnderlyingTypeChecker(AFD, opaqueResultTy, body).check();
45464481
}
45474482
}
4548-
} else if (auto *FD = dyn_cast<FuncDecl>(AFD)) {
4549-
auto resultIFaceTy = FD->getResultInterfaceType();
4550-
// If the result has a placeholder, we need to try to use the contextual
4551-
// type inferred in the body to replace it.
4552-
if (resultIFaceTy && resultIFaceTy->hasPlaceholder()) {
4553-
ReturnTypePlaceholderReplacer(FD, body).check();
4554-
}
45554483
}
45564484
}
45574485

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2121,17 +2121,10 @@ ResultTypeRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
21212121
if (decl->preconcurrency())
21222122
options |= TypeResolutionFlags::Preconcurrency;
21232123

2124-
// Placeholders are only currently allowed for FuncDecls with bodies, which
2125-
// we diagnose in ReturnTypePlaceholderReplacer.
2126-
HandlePlaceholderTypeReprFn placeholderOpener;
2127-
if (auto *FD = dyn_cast<FuncDecl>(decl)) {
2128-
if (FD->hasBody() && !FD->isBodySkipped())
2129-
placeholderOpener = PlaceholderType::get;
2130-
}
21312124
auto *const dc = decl->getInnermostDeclContext();
21322125
return TypeResolution::forInterface(dc, options,
21332126
/*unboundTyOpener*/ nullptr,
2134-
placeholderOpener,
2127+
/*placeholderOpener*/ nullptr,
21352128
/*packElementOpener*/ nullptr)
21362129
.resolveType(resultTyRepr);
21372130
}
@@ -2259,6 +2252,7 @@ static Type validateParameterType(ParamDecl *decl) {
22592252

22602253
TypeResolutionOptions options(std::nullopt);
22612254
OpenUnboundGenericTypeFn unboundTyOpener = nullptr;
2255+
HandlePlaceholderTypeReprFn placeholderOpener = nullptr;
22622256
if (isa<AbstractClosureExpr>(dc)) {
22632257
options = TypeResolutionOptions(TypeResolverContext::ClosureExpr);
22642258
options |= TypeResolutionFlags::AllowUnspecifiedTypes;
@@ -2267,8 +2261,9 @@ static Type validateParameterType(ParamDecl *decl) {
22672261
// For now, just return the unbound generic type.
22682262
return unboundTy;
22692263
};
2270-
// FIXME: Don't let placeholder types escape type resolution.
2271-
// For now, just return the placeholder type.
2264+
// FIXME: Don't let placeholder types escape type resolution. For now, just
2265+
// return the placeholder type, which we open in `inferClosureType`.
2266+
placeholderOpener = PlaceholderType::get;
22722267
} else if (isa<AbstractFunctionDecl>(dc)) {
22732268
options = TypeResolutionOptions(TypeResolverContext::AbstractFunctionDecl);
22742269
} else if (isa<SubscriptDecl>(dc)) {
@@ -2317,14 +2312,6 @@ static Type validateParameterType(ParamDecl *decl) {
23172312
: TypeResolverContext::FunctionInput);
23182313
options |= TypeResolutionFlags::Direct;
23192314

2320-
// We allow placeholders in parameter types to improve recovery since if a
2321-
// default argument is present we can suggest the inferred type. Avoid doing
2322-
// this for protocol requirements though since those can't ever have default
2323-
// arguments anyway.
2324-
HandlePlaceholderTypeReprFn placeholderOpener;
2325-
if (!isa<ProtocolDecl>(dc->getParent()))
2326-
placeholderOpener = PlaceholderType::get;
2327-
23282315
const auto resolution =
23292316
TypeResolution::forInterface(dc, options, unboundTyOpener,
23302317
placeholderOpener,

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 2 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,73 +1193,18 @@ static bool checkExpressionMacroDefaultValueRestrictions(ParamDecl *param) {
11931193
#endif
11941194
}
11951195

1196-
void TypeChecker::notePlaceholderReplacementTypes(Type writtenType,
1197-
Type inferredType) {
1198-
assert(writtenType && inferredType &&
1199-
"Must provide both written and inferred types");
1200-
assert(writtenType->hasPlaceholder() && "Written type has no placeholder?");
1201-
1202-
class PlaceholderNotator
1203-
: public CanTypeDifferenceVisitor<PlaceholderNotator> {
1204-
public:
1205-
bool visitDifferentComponentTypes(CanType t1, CanType t2) {
1206-
// Never replace anything the user wrote with an error type.
1207-
if (t2->hasError() || t2->hasUnresolvedType()) {
1208-
return false;
1209-
}
1210-
1211-
auto *placeholder = t1->getAs<PlaceholderType>();
1212-
if (!placeholder) {
1213-
return false;
1214-
}
1215-
1216-
if (auto *origRepr =
1217-
placeholder->getOriginator().dyn_cast<TypeRepr *>()) {
1218-
assert(isa<PlaceholderTypeRepr>(origRepr));
1219-
t1->getASTContext()
1220-
.Diags
1221-
.diagnose(origRepr->getLoc(),
1222-
diag::replace_placeholder_with_inferred_type, t2)
1223-
.fixItReplace(origRepr->getSourceRange(), t2.getString());
1224-
}
1225-
return false;
1226-
}
1227-
1228-
bool check(Type t1, Type t2) {
1229-
return !visit(t1->getCanonicalType(), t2->getCanonicalType());
1230-
};
1231-
};
1232-
1233-
PlaceholderNotator().check(writtenType, inferredType);
1234-
}
1235-
12361196
/// Check the default arguments that occur within this parameter list.
12371197
static void checkDefaultArguments(ParameterList *params) {
12381198
// Force the default values in case they produce diagnostics.
12391199
for (auto *param : *params) {
1240-
auto ifacety = param->getInterfaceType();
1241-
auto *expr = param->getTypeCheckedDefaultExpr();
1200+
(void)param->getTypeCheckedDefaultExpr();
12421201

12431202
// Force captures since this can emit diagnostics.
1244-
(void) param->getDefaultArgumentCaptureInfo();
1203+
(void)param->getDefaultArgumentCaptureInfo();
12451204

12461205
// If the default argument has isolation, it must match the
12471206
// isolation of the decl context.
12481207
(void)param->getInitializerIsolation();
1249-
1250-
if (!ifacety->hasPlaceholder()) {
1251-
continue;
1252-
}
1253-
1254-
// Placeholder types are banned for all parameter decls. We try to use the
1255-
// freshly-checked default expression's contextual type to suggest a
1256-
// reasonable type to insert.
1257-
param->diagnose(diag::placeholder_type_not_allowed_in_parameter)
1258-
.highlight(param->getSourceRange());
1259-
if (expr && !expr->getType()->hasError()) {
1260-
TypeChecker::notePlaceholderReplacementTypes(
1261-
ifacety, expr->getType()->mapTypeOutOfContext());
1262-
}
12631208
}
12641209
}
12651210

0 commit comments

Comments
 (0)