Skip to content

Commit f0ca515

Browse files
committed
[PreCheckExpr] Don't silence errors while resolving types for 'literal via coercion' transform
Since `resolveType` caches its results, silencing errors would mean that the error would be lost and each subsequent call to `resolveType` would get `ErrorType` back. This ultimately leads to the compiler failing to produce a diagnostic when invalid type is used in `init` call. These changes include marking IUO reprs found in incorrect positions, such as generic arguments, as invalid right before diagnosing them as errors, this helps to prevent type resolution from producing duplicate diagnostics. Resolves: rdar://94888357 (cherry picked from commit 601a1dd) (cherry picked from commit 5ac8182)
1 parent ad06e7d commit f0ca515

File tree

4 files changed

+32
-11
lines changed

4 files changed

+32
-11
lines changed

lib/Sema/PreCheckExpr.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,9 @@ namespace {
952952

953953
/// Simplify constructs like `UInt32(1)` into `1 as UInt32` if
954954
/// the type conforms to the expected literal protocol.
955+
///
956+
/// \returns Either a transformed expression, or `ErrorExpr` upon type
957+
/// resolution failure, or `nullptr` if transformation is not applicable.
955958
Expr *simplifyTypeConstructionWithLiteralArg(Expr *E);
956959

957960
/// Whether the current expression \p E is in a context that might turn out
@@ -1422,8 +1425,9 @@ namespace {
14221425
return KPE;
14231426
}
14241427

1425-
if (auto *simplified = simplifyTypeConstructionWithLiteralArg(expr))
1426-
return simplified;
1428+
if (auto *result = simplifyTypeConstructionWithLiteralArg(expr)) {
1429+
return isa<ErrorExpr>(result) ? nullptr : result;
1430+
}
14271431

14281432
// If we find an unresolved member chain, wrap it in an
14291433
// UnresolvedMemberChainResultExpr (unless this has already been done).
@@ -2077,12 +2081,8 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
20772081
if (auto precheckedTy = typeExpr->getInstanceType()) {
20782082
castTy = precheckedTy;
20792083
} else {
2080-
const auto options =
2081-
TypeResolutionOptions(TypeResolverContext::InExpression) |
2082-
TypeResolutionFlags::SilenceErrors;
2083-
20842084
const auto result = TypeResolution::resolveContextualType(
2085-
typeExpr->getTypeRepr(), DC, options,
2085+
typeExpr->getTypeRepr(), DC, TypeResolverContext::InExpression,
20862086
[](auto unboundTy) {
20872087
// FIXME: Don't let unbound generic types escape type resolution.
20882088
// For now, just return the unbound generic type.
@@ -2093,7 +2093,9 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
20932093
PlaceholderType::get);
20942094

20952095
if (result->hasError())
2096-
return nullptr;
2096+
return new (getASTContext())
2097+
ErrorExpr(typeExpr->getSourceRange(), result, typeExpr);
2098+
20972099
castTy = result;
20982100
}
20992101

lib/Sema/TypeCheckType.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3793,6 +3793,19 @@ NeverNullType TypeResolver::resolveImplicitlyUnwrappedOptionalType(
37933793
if (doDiag && !options.contains(TypeResolutionFlags::SilenceErrors)) {
37943794
// Prior to Swift 5, we allow 'as T!' and turn it into a disjunction.
37953795
if (getASTContext().isSwiftVersionAtLeast(5)) {
3796+
// Mark this repr as invalid. This is the only way to indicate that
3797+
// something went wrong without supressing checking other reprs in
3798+
// the same type. For example:
3799+
//
3800+
// struct S<T, U> { ... }
3801+
//
3802+
// _ = S<Int!, String!>(...)
3803+
//
3804+
// Compiler should diagnose both `Int!` and `String!` as invalid,
3805+
// but returning `ErrorType` from here would stop type resolution
3806+
// after `Int!`.
3807+
repr->setInvalid();
3808+
37963809
diagnose(repr->getStartLoc(),
37973810
diag::implicitly_unwrapped_optional_in_illegal_position)
37983811
.fixItReplace(repr->getExclamationLoc(), "?");

test/Sema/diag_erroneous_iuo.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,8 @@ func genericFunctionSigil<T>(
6161
}
6262

6363
func genericFunctionSigilArray<T>(
64-
// FIXME: We validate these types multiple times resulting in multiple diagnostics
6564
iuo: [T!] // expected-error {{'!' is not allowed here; perhaps '?' was intended?}}{{10-11=?}}
66-
// expected-error@-1 {{'!' is not allowed here; perhaps '?' was intended?}}{{10-11=?}}
6765
) -> [T!] { // expected-error {{'!' is not allowed here; perhaps '?' was intended?}}{{8-9=?}}
68-
// expected-error@-1 {{'!' is not allowed here; perhaps '?' was intended?}}{{8-9=?}}
6966
return iuo
7067
}
7168

test/type/types.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,12 @@ var _: sr5505 = sr5505 // expected-error {{cannot find type 'sr5505' in scope}}
194194
typealias A = (inout Int ..., Int ... = [42, 12]) -> Void // expected-error {{'inout' must not be used on variadic parameters}}
195195
// expected-error@-1 {{only a single element can be variadic}} {{35-39=}}
196196
// expected-error@-2 {{default argument not permitted in a tuple type}} {{39-49=}}
197+
198+
// rdar://94888357 - failed to produce a diagnostic when type is used incorrectly
199+
func rdar94888357() {
200+
struct S<T> { // expected-note {{generic type 'S' declared here}}
201+
init(_ str: String) {}
202+
}
203+
204+
let _ = S<String, String>("") // expected-error {{generic type 'S' specialized with too many type parameters (got 2, but expected 1)}}
205+
}

0 commit comments

Comments
 (0)