Skip to content

Commit f6b6bff

Browse files
committed
[Sema] Diagnose and reject top-level placeholders
1 parent ab262b7 commit f6b6bff

File tree

10 files changed

+97
-43
lines changed

10 files changed

+97
-43
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3598,6 +3598,8 @@ ERROR(cannot_force_unwrap_nil_literal,none,
35983598

35993599
ERROR(could_not_infer_placeholder,none,
36003600
"could not infer type for placeholder", ())
3601+
ERROR(top_level_placeholder_type,none,
3602+
"placeholders are not allowed as top-level types", ())
36013603

36023604
ERROR(type_of_expression_is_ambiguous,none,
36033605
"type of expression is ambiguous without more context", ())

lib/Sema/PreCheckExpr.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,7 +1551,9 @@ TypeExpr *PreCheckExpression::simplifyNestedTypeExpr(UnresolvedDotExpr *UDE) {
15511551
},
15521552
// FIXME: Don't let placeholder types escape type resolution.
15531553
// For now, just return the placeholder type.
1554-
PlaceholderType::get);
1554+
[](auto &ctx, auto *originator) {
1555+
return Type();
1556+
});
15551557
const auto BaseTy = resolution.resolveType(InnerTypeRepr);
15561558

15571559
if (BaseTy->mayHaveMembers()) {
@@ -2095,7 +2097,9 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
20952097
},
20962098
// FIXME: Don't let placeholder types escape type resolution.
20972099
// For now, just return the placeholder type.
2098-
PlaceholderType::get);
2100+
[](auto &ctx, auto *originator) {
2101+
return Type();
2102+
});
20992103
const auto result = resolution.resolveType(typeExpr->getTypeRepr());
21002104
if (result->hasError())
21012105
return nullptr;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,7 +2126,9 @@ static Type validateParameterType(ParamDecl *decl) {
21262126
};
21272127
// FIXME: Don't let placeholder types escape type resolution.
21282128
// For now, just return the placeholder type.
2129-
placeholderHandler = PlaceholderType::get;
2129+
placeholderHandler = [](auto &ctx, auto *originator) {
2130+
return Type();
2131+
};
21302132
} else if (isa<AbstractFunctionDecl>(dc)) {
21312133
options = TypeResolutionOptions(TypeResolverContext::AbstractFunctionDecl);
21322134
} else if (isa<SubscriptDecl>(dc)) {
@@ -2760,7 +2762,9 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const {
27602762
},
27612763
// FIXME: Don't let placeholder types escape type resolution.
27622764
// For now, just return the placeholder type.
2763-
PlaceholderType::get);
2765+
[](auto &ctx, auto *originator) {
2766+
return Type();
2767+
});
27642768

27652769
const auto extendedType = resolution.resolveType(extendedRepr);
27662770

lib/Sema/TypeCheckPattern.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,9 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
477477
},
478478
// FIXME: Don't let placeholder types escape type resolution.
479479
// For now, just return the placeholder type.
480-
PlaceholderType::get);
480+
[](auto &ctx, auto *originator) {
481+
return Type();
482+
});
481483
const auto ty = resolution.resolveType(repr);
482484
auto *enumDecl = dyn_cast_or_null<EnumDecl>(ty->getAnyNominal());
483485
if (!enumDecl)
@@ -599,7 +601,9 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
599601
},
600602
// FIXME: Don't let placeholder types escape type resolution.
601603
// For now, just return the placeholder type.
602-
PlaceholderType::get)
604+
[](auto &ctx, auto *originator) {
605+
return Type();
606+
})
603607
.resolveType(prefixRepr);
604608
auto *enumDecl = dyn_cast_or_null<EnumDecl>(enumTy->getAnyNominal());
605609
if (!enumDecl)
@@ -809,7 +813,9 @@ Type PatternTypeRequest::evaluate(Evaluator &evaluator,
809813
};
810814
// FIXME: Don't let placeholder types escape type resolution.
811815
// For now, just return the placeholder type.
812-
placeholderHandler = PlaceholderType::get;
816+
placeholderHandler = [](auto &ctx, auto *originator) {
817+
return Type();
818+
};
813819
}
814820
return validateTypedPattern(
815821
cast<TypedPattern>(P),
@@ -877,7 +883,9 @@ Type PatternTypeRequest::evaluate(Evaluator &evaluator,
877883
};
878884
// FIXME: Don't let placeholder types escape type resolution.
879885
// For now, just return the placeholder type.
880-
placeholderHandler = PlaceholderType::get;
886+
placeholderHandler = [](auto &ctx, auto *originator) {
887+
return Type();
888+
};
881889
}
882890
TypedPattern *TP = cast<TypedPattern>(somePat->getSubPattern());
883891
const auto type = validateTypedPattern(

lib/Sema/TypeCheckType.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,6 +1938,31 @@ Type ResolveTypeRequest::evaluate(Evaluator &evaluator,
19381938
if (validateAutoClosureAttributeUse(ctx.Diags, TyR, result, options))
19391939
return ErrorType::get(ctx);
19401940

1941+
// Diagnose an attempt to use a placeholder at the top level.
1942+
if (result->getCanonicalType()->is<PlaceholderType>() &&
1943+
resolution->getOptions().contains(TypeResolutionFlags::Direct)) {
1944+
if (!resolution->getOptions().contains(TypeResolutionFlags::SilenceErrors))
1945+
ctx.Diags.diagnose(loc, diag::top_level_placeholder_type);
1946+
1947+
TyR->setInvalid();
1948+
return ErrorType::get(ctx);
1949+
}
1950+
1951+
// Now that top-level placeholders have been diagnosed, replace them according
1952+
// to the user-specified handler (if it exists).
1953+
if (const auto handlerFn = resolution->getPlaceholderHandler()) {
1954+
result = result.get().transform([&](Type ty) {
1955+
if (auto *oldTy = ty->getAs<PlaceholderType>()) {
1956+
auto originator = oldTy->getOriginator();
1957+
if (auto *repr = originator.dyn_cast<PlaceholderTypeRepr *>())
1958+
if (auto newTy = handlerFn(ctx, repr))
1959+
return newTy;
1960+
}
1961+
1962+
return ty;
1963+
});
1964+
}
1965+
19411966
return result;
19421967
}
19431968

@@ -2066,18 +2091,21 @@ NeverNullType TypeResolver::resolveType(TypeRepr *repr,
20662091
options);
20672092

20682093
case TypeReprKind::Placeholder: {
2069-
auto &ctx = getASTContext();
2070-
// Fill in the placeholder if there's an appropriate handler.
2071-
if (const auto handlerFn = resolution.getPlaceholderHandler())
2072-
if (const auto ty = handlerFn(ctx, cast<PlaceholderTypeRepr>(repr)))
2073-
return ty;
2074-
2075-
// Complain if we're allowed to and bail out with an error.
2094+
if (resolution.getPlaceholderHandler())
2095+
// For now, just form a `PlaceholderType` so that we can properly diagnose
2096+
// invalid top-level placeholders. `ResolveTypeRequest::evaluate` will
2097+
// take care of substituting the placeholder based on the caller-specified
2098+
// handler.
2099+
return PlaceholderType::get(getASTContext(),
2100+
cast<PlaceholderTypeRepr>(repr));
2101+
2102+
// If there's no handler, complain if we're allowed to and bail out with an
2103+
// error.
20762104
if (!options.contains(TypeResolutionFlags::SilenceErrors))
2077-
ctx.Diags.diagnose(repr->getLoc(),
2105+
getASTContext().Diags.diagnose(repr->getLoc(),
20782106
diag::placeholder_type_not_allowed);
20792107

2080-
return ErrorType::get(resolution.getASTContext());
2108+
return ErrorType::get(getASTContext());
20812109
}
20822110

20832111
case TypeReprKind::Fixed:

lib/Sema/TypeCheckType.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ class TypeResolutionOptions {
281281
/// \returns the \c null type on failure.
282282
using OpenUnboundGenericTypeFn = llvm::function_ref<Type(UnboundGenericType *)>;
283283

284-
/// A function reference used to handle a PlaceholderTypeRepr.
284+
/// A function reference used to handle a \c PlaceholderTypeRepr. If the
285+
/// function returns a null type, then the unmodified \c PlaceholderType will be
286+
/// used.
285287
using HandlePlaceholderTypeReprFn =
286288
llvm::function_ref<Type(ASTContext &, PlaceholderTypeRepr *)>;
287289

lib/Sema/TypeChecker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,9 @@ Type swift::performTypeResolution(TypeRepr *TyR, ASTContext &Ctx,
378378
},
379379
// FIXME: Don't let placeholder types escape type resolution.
380380
// For now, just return the placeholder type.
381-
PlaceholderType::get);
381+
[](auto &ctx, auto *originator) {
382+
return Type();
383+
});
382384

383385
Optional<DiagnosticSuppression> suppression;
384386
if (!ProduceDiagnostics)

test/Constraints/diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ func badTypes() {
11371137
// rdar://34357545
11381138
func unresolvedTypeExistential() -> Bool {
11391139
return (Int.self==_{})
1140-
// expected-error@-1 {{type of expression is ambiguous without more context}}
1140+
// expected-error@-1 {{placeholders are not allowed as top-level types}}
11411141
}
11421142

11431143
do {

test/Sema/placeholder_type.swift

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %target-typecheck-verify-swift
22

3-
let x: _ = 0
3+
let x: _ = 0 // expected-error {{placeholders are not allowed as top-level types}}
44
let x2 = x
55
let dict1: [_: Int] = ["hi": 0]
66
let dict2: [Character: _] = ["h": 0]
@@ -9,8 +9,8 @@ let arr = [_](repeating: "hi", count: 3)
99

1010
func foo(_ arr: [_] = [0]) {} // expected-error {{placeholder type not allowed here}}
1111

12-
let foo = _.foo // expected-error {{could not infer type for placeholder}}
13-
let zero: _ = .zero // expected-error {{cannot infer contextual base in reference to member 'zero'}}
12+
let foo = _.foo // expected-error {{placeholders are not allowed as top-level types}}
13+
let zero: _ = .zero // expected-error {{placeholders are not allowed as top-level types}}
1414

1515
struct S<T> {
1616
var x: T
@@ -48,9 +48,10 @@ func dictionary<K, V>(ofType: [K: V].Type) -> [K: V] { [:] }
4848

4949
let _: [String: _] = dictionary(ofType: [_: Int].self)
5050
let _: [_: _] = dictionary(ofType: [String: Int].self)
51-
let _: [String: Int] = dictionary(ofType: _.self)
51+
let _: [String: Int] = dictionary(ofType: _.self) // expected-error {{placeholders are not allowed as top-level types}}
5252

5353
let _: @convention(c) _ = { 0 } // expected-error {{@convention attribute only applies to function types}}
54+
// expected-error@-1 {{placeholders are not allowed as top-level types}}
5455
let _: @convention(c) (_) -> _ = { (x: Double) in 0 }
5556
let _: @convention(c) (_) -> Int = { (x: Double) in 0 }
5657

@@ -98,18 +99,18 @@ extension Bar {
9899
}
99100

100101
// FIXME: We should probably have better diagnostics for these situations--the user probably meant to use implicit member syntax
101-
let _: Int = _() // expected-error {{type of expression is ambiguous without more context}}
102-
let _: () -> Int = { _() } // expected-error {{unable to infer closure type in the current context}}
103-
let _: Int = _.init() // expected-error {{could not infer type for placeholder}}
104-
let _: () -> Int = { _.init() } // expected-error {{could not infer type for placeholder}}
102+
let _: Int = _() // expected-error {{placeholders are not allowed as top-level types}}
103+
let _: () -> Int = { _() } // expected-error {{unable to infer closure type in the current context}} expected-error {{placeholders are not allowed as top-level types}}
104+
let _: Int = _.init() // expected-error {{placeholders are not allowed as top-level types}}
105+
let _: () -> Int = { _.init() } // expected-error {{unable to infer closure type in the current context}} expected-error {{placeholders are not allowed as top-level types}}
105106

106-
func returnsInt() -> Int { _() } // expected-error {{type of expression is ambiguous without more context}}
107-
func returnsIntClosure() -> () -> Int { { _() } } // expected-error {{unable to infer closure type in the current context}}
108-
func returnsInt2() -> Int { _.init() } // expected-error {{could not infer type for placeholder}}
109-
func returnsIntClosure2() -> () -> Int { { _.init() } } // expected-error {{could not infer type for placeholder}}
107+
func returnsInt() -> Int { _() } // expected-error {{placeholders are not allowed as top-level types}}
108+
func returnsIntClosure() -> () -> Int { { _() } } // expected-error {{unable to infer closure type in the current context}} expected-error {{placeholders are not allowed as top-level types}}
109+
func returnsInt2() -> Int { _.init() } // expected-error {{placeholders are not allowed as top-level types}}
110+
func returnsIntClosure2() -> () -> Int { { _.init() } } // expected-error {{unable to infer closure type in the current context}} expected-error {{placeholders are not allowed as top-level types}}
110111

111112
let _: Int.Type = _ // expected-error {{'_' can only appear in a pattern or on the left side of an assignment}}
112-
let _: Int.Type = _.self
113+
let _: Int.Type = _.self // expected-error {{placeholders are not allowed as top-level types}}
113114

114115
struct SomeSuperLongAndComplexType {}
115116
func getSomething() -> SomeSuperLongAndComplexType? { .init() }
@@ -135,13 +136,13 @@ let _ = [_].otherStaticMember.method()
135136
func f(x: Any, arr: [Int]) {
136137
// FIXME: Better diagnostics here. Maybe we should suggest replacing placeholders with 'Any'?
137138

138-
if x is _ {} // expected-error {{type of expression is ambiguous without more context}}
139+
if x is _ {} // expected-error {{placeholders are not allowed as top-level types}}
139140
if x is [_] {} // expected-error {{type of expression is ambiguous without more context}}
140141
if x is () -> _ {} // expected-error {{type of expression is ambiguous without more context}}
141-
if let y = x as? _ {} // expected-error {{type of expression is ambiguous without more context}}
142+
if let y = x as? _ {} // expected-error {{placeholders are not allowed as top-level types}}
142143
if let y = x as? [_] {} // expected-error {{type of expression is ambiguous without more context}}
143144
if let y = x as? () -> _ {} // expected-error {{type of expression is ambiguous without more context}}
144-
let y1 = x as! _ // expected-error {{type of expression is ambiguous without more context}}
145+
let y1 = x as! _ // expected-error {{placeholders are not allowed as top-level types}}
145146
let y2 = x as! [_] // expected-error {{type of expression is ambiguous without more context}}
146147
let y3 = x as! () -> _ // expected-error {{type of expression is ambiguous without more context}}
147148

@@ -154,13 +155,13 @@ func f(x: Any, arr: [Int]) {
154155
case let y as () -> _: break // expected-error {{placeholder type not allowed here}}
155156
}
156157

157-
if arr is _ {} // expected-error {{type of expression is ambiguous without more context}}
158+
if arr is _ {} // expected-error {{placeholders are not allowed as top-level types}}
158159
if arr is [_] {} // expected-error {{type of expression is ambiguous without more context}}
159160
if arr is () -> _ {} // expected-error {{type of expression is ambiguous without more context}}
160-
if let y = arr as? _ {} // expected-error {{type of expression is ambiguous without more context}}
161+
if let y = arr as? _ {} // expected-error {{placeholders are not allowed as top-level types}}
161162
if let y = arr as? [_] {} // expected-error {{type of expression is ambiguous without more context}}
162163
if let y = arr as? () -> _ {} // expected-error {{type of expression is ambiguous without more context}}
163-
let y1 = arr as! _ // expected-error {{type of expression is ambiguous without more context}}
164+
let y1 = arr as! _ // expected-error {{placeholders are not allowed as top-level types}}
164165
let y2 = arr as! [_] // expected-error {{type of expression is ambiguous without more context}}
165166
let y3 = arr as! () -> _ // expected-error {{type of expression is ambiguous without more context}}
166167

@@ -186,15 +187,18 @@ struct Just<Output>: Publisher {
186187
struct SetFailureType<Output, Failure>: Publisher {}
187188

188189
extension Publisher {
189-
func setFailureType<T>(to: T.Type) -> SetFailureType<Output, T> { // expected-note {{in call to function 'setFailureType(to:)'}}
190+
func setFailureType<T>(to: T.Type) -> SetFailureType<Output, T> {
190191
return .init()
191192
}
192193
}
193194

194-
let _: SetFailureType<Int, String> = Just<Int>().setFailureType(to: _.self)
195+
let _: SetFailureType<Int, String> = Just<Int>().setFailureType(to: _.self) // expected-error {{placeholders are not allowed as top-level types}}
195196
let _: SetFailureType<Int, [String]> = Just<Int>().setFailureType(to: [_].self)
196197
let _: SetFailureType<Int, (String) -> Double> = Just<Int>().setFailureType(to: ((_) -> _).self)
197198
let _: SetFailureType<Int, (String, Double)> = Just<Int>().setFailureType(to: (_, _).self)
198199

199200
// TODO: Better error message here? Would be nice if we could point to the placeholder...
200-
let _: SetFailureType<Int, String> = Just<Int>().setFailureType(to: _.self).setFailureType(to: String.self) // expected-error {{generic parameter 'T' could not be inferred}}
201+
let _: SetFailureType<Int, String> = Just<Int>().setFailureType(to: _.self).setFailureType(to: String.self) // expected-error {{placeholders are not allowed as top-level types}}
202+
203+
let _: (_) = 0 as Int // expected-error {{placeholders are not allowed as top-level types}}
204+
let _: Int = 0 as (_) // expected-error {{placeholders are not allowed as top-level types}}

test/expr/expressions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ func r20802757(_ z: inout Int = &g20802757) { // expected-error {{cannot provide
865865
print(z)
866866
}
867867

868-
_ = _.foo // expected-error {{could not infer type for placeholder}}
868+
_ = _.foo // expected-error {{placeholders are not allowed as top-level types}}
869869

870870
// <rdar://problem/22211854> wrong arg list crashing sourcekit
871871
func r22211854() {

0 commit comments

Comments
 (0)