Skip to content

Commit b8bfd80

Browse files
authored
Merge pull request #6806 from xedin/SR-3525
[Diagnostics] Nullify contextual type if it's generic with type variables
2 parents 9bc057c + 24e8cdf commit b8bfd80

File tree

2 files changed

+85
-21
lines changed

2 files changed

+85
-21
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,20 @@ class FailureDiagnosis :public ASTVisitor<FailureDiagnosis, /*exprresult*/bool>{
20752075
bool diagnoseCalleeResultContextualConversionError();
20762076

20772077
private:
2078+
/// Validate potential contextual type for type-checking one of the
2079+
/// sub-expressions, usually correct/valid types are the ones which
2080+
/// either don't have type variables or are not generic, because
2081+
/// generic types with left-over type variables or unresolved types
2082+
/// degrade quality of diagnostics if allowed to be used as contextual.
2083+
///
2084+
/// \param contextualType The candidate contextual type.
2085+
/// \param CTP The contextual purpose attached to the given candidate.
2086+
///
2087+
/// \returns Pair of validated type and it's purpose, potentially nullified
2088+
/// if it wasn't an appropriate type to be used.
2089+
std::pair<Type, ContextualTypePurpose>
2090+
validateContextualType(Type contextualType, ContextualTypePurpose CTP);
2091+
20782092
/// Check the specified closure to see if it is a multi-statement closure with
20792093
/// an uninferred type. If so, diagnose the problem with an error and return
20802094
/// true.
@@ -3433,29 +3447,11 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
34333447

34343448
CS->TC.addExprForDiagnosis(subExpr, subExpr);
34353449
}
3436-
3437-
// If we have a conversion type, but it has type variables (from the current
3438-
// ConstraintSystem), then we can't use it.
3439-
if (convertType) {
3440-
// If we're asked to convert to an autoclosure, then we really want to
3441-
// convert to the result of it.
3442-
if (auto *FT = convertType->getAs<AnyFunctionType>())
3443-
if (FT->isAutoClosure())
3444-
convertType = FT->getResult();
34453450

3446-
// Replace archetypes and type parameters with UnresolvedType.
3447-
convertType = replaceTypeParametersWithUnresolved(convertType);
3448-
convertType = replaceTypeVariablesWithUnresolved(convertType);
3449-
3450-
// If the conversion type contains no info, drop it.
3451-
if (convertType->is<UnresolvedType>() ||
3452-
(convertType->is<MetatypeType>() && convertType->hasUnresolvedType())) {
3453-
convertType = Type();
3454-
convertTypePurpose = CTP_Unused;
3455-
}
3456-
}
3451+
// Validate contextual type before trying to use it.
3452+
std::tie(convertType, convertTypePurpose) =
3453+
validateContextualType(convertType, convertTypePurpose);
34573454

3458-
34593455
// If we have no contextual type information and the subexpr is obviously a
34603456
// overload set, don't recursively simplify this. The recursive solver will
34613457
// sometimes pick one based on arbitrary ranking behavior (e.g. like
@@ -7376,6 +7372,61 @@ static void noteArchetypeSource(const TypeLoc &loc, ArchetypeType *archetype,
73767372
}
73777373
}
73787374

7375+
std::pair<Type, ContextualTypePurpose>
7376+
FailureDiagnosis::validateContextualType(Type contextualType,
7377+
ContextualTypePurpose CTP) {
7378+
if (!contextualType)
7379+
return {contextualType, CTP};
7380+
7381+
// If we're asked to convert to an autoclosure, then we really want to
7382+
// convert to the result of it.
7383+
if (auto *FT = contextualType->getAs<AnyFunctionType>())
7384+
if (FT->isAutoClosure())
7385+
contextualType = FT->getResult();
7386+
7387+
bool shouldNullify = false;
7388+
if (auto objectType = contextualType->getLValueOrInOutObjectType()) {
7389+
// Note that simply checking for `objectType->hasUnresolvedType()` is not
7390+
// appropriate in this case standalone, because if it's in a function,
7391+
// for example, or inout type, we still want to preserve it's skeleton
7392+
/// because that helps to diagnose inout argument issues. Complete
7393+
// nullification is only appropriate for generic types with unresolved
7394+
// types or standalone archetypes because that's going to give
7395+
// sub-expression solver a chance to try and compute type as it sees fit
7396+
// and higher level code would have a chance to check it, which avoids
7397+
// diagnostic messages like `cannot convert (_) -> _ to (Int) -> Void`.
7398+
switch (objectType->getDesugaredType()->getKind()) {
7399+
case TypeKind::Archetype:
7400+
case TypeKind::Unresolved:
7401+
shouldNullify = true;
7402+
break;
7403+
7404+
case TypeKind::BoundGenericEnum:
7405+
case TypeKind::BoundGenericClass:
7406+
case TypeKind::BoundGenericStruct:
7407+
case TypeKind::UnboundGeneric:
7408+
case TypeKind::GenericFunction:
7409+
case TypeKind::Metatype:
7410+
shouldNullify = objectType->hasUnresolvedType();
7411+
break;
7412+
7413+
default:
7414+
shouldNullify = false;
7415+
break;
7416+
}
7417+
}
7418+
7419+
// If the conversion type contains no info, drop it.
7420+
if (shouldNullify)
7421+
return {Type(), CTP_Unused};
7422+
7423+
// Remove all of the potentially leftover type variables or type parameters
7424+
// from the contextual type to be used by new solver.
7425+
contextualType = replaceTypeParametersWithUnresolved(contextualType);
7426+
contextualType = replaceTypeVariablesWithUnresolved(contextualType);
7427+
7428+
return {contextualType, CTP};
7429+
}
73797430

73807431
/// Check the specified closure to see if it is a multi-statement closure with
73817432
/// an uninferred type. If so, diagnose the problem with an error and return

test/Constraints/generics.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,16 @@ func genericFunc<T>(t: T) {
426426
// expected-note@-1 {{explicitly specify the generic arguments to fix this issue}}
427427
// expected-error@-2 2 {{type 'T' does not conform to protocol 'Hashable'}}
428428
}
429+
430+
struct SR_3525<T> {}
431+
func sr3525_arg_int(_: inout SR_3525<Int>) {}
432+
func sr3525_arg_gen<T>(_: inout SR_3525<T>) {}
433+
func sr3525_1(t: SR_3525<Int>) {
434+
let _ = sr3525_arg_int(&t) // expected-error {{cannot pass immutable value as inout argument: 't' is a 'let' constant}}
435+
}
436+
func sr3525_2(t: SR_3525<Int>) {
437+
let _ = sr3525_arg_gen(&t) // expected-error {{cannot pass immutable value as inout argument: 't' is a 'let' constant}}
438+
}
439+
func sr3525_3<T>(t: SR_3525<T>) {
440+
let _ = sr3525_arg_gen(&t) // expected-error {{cannot pass immutable value as inout argument: 't' is a 'let' constant}}
441+
}

0 commit comments

Comments
 (0)