Skip to content

Commit c3fbf54

Browse files
committed
[ConstraintSystem] Use lightweight conformance check in determining whether literal could be initialized via coercion
Currently logic to transform call into coercion uses `conformsToProtocol` to validate that type conforms to one of the ExpressibleBy*Literal protocols. That function doesn't handle unbound generic parameters and would result in an infinite loop or a crash when not all of the generic parameters were explicitly specified for one of the types in the chain e.g. `A.B(42)` where `A` has at least one generic parameter. Resolves: rdar://problem/50007727 (cherry picked from commit a80fa91)
1 parent d07ef69 commit c3fbf54

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,15 +1978,21 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
19781978
Type type;
19791979
if (typeExpr->getTypeLoc().wasValidated()) {
19801980
type = typeExpr->getTypeLoc().getType();
1981-
} else if (auto *rep = typeExpr->getTypeRepr()) {
1981+
} else {
19821982
TypeResolutionOptions options(TypeResolverContext::InExpression);
19831983
options |= TypeResolutionFlags::AllowUnboundGenerics;
1984-
auto resolution = TypeResolution::forContextual(DC);
1985-
type = resolution.resolveType(rep, options);
1986-
typeExpr->getTypeLoc().setType(type);
1984+
1985+
auto &typeLoc = typeExpr->getTypeLoc();
1986+
bool hadError =
1987+
TC.validateType(typeLoc, TypeResolution::forContextual(DC), options);
1988+
1989+
if (hadError)
1990+
return nullptr;
1991+
1992+
type = typeLoc.getType();
19871993
}
19881994

1989-
if (!type)
1995+
if (!type || !type->getAnyNominal())
19901996
return nullptr;
19911997

19921998
// Don't bother to convert deprecated selector syntax.
@@ -1995,16 +2001,13 @@ Expr *PreCheckExpression::simplifyTypeConstructionWithLiteralArg(Expr *E) {
19952001
return nullptr;
19962002
}
19972003

1998-
ConformanceCheckOptions options;
1999-
options |= ConformanceCheckFlags::InExpression;
2000-
options |= ConformanceCheckFlags::SkipConditionalRequirements;
2001-
2002-
auto result = TC.conformsToProtocol(type, protocol, DC, options);
2003-
if (!result || !result->isConcrete())
2004-
return nullptr;
2005-
2006-
return CoerceExpr::forLiteralInit(TC.Context, argExpr, call->getSourceRange(),
2007-
typeExpr->getTypeLoc());
2004+
auto *NTD = type->getAnyNominal();
2005+
SmallVector<ProtocolConformance *, 2> conformances;
2006+
return NTD->lookupConformance(DC->getParentModule(), protocol, conformances)
2007+
? CoerceExpr::forLiteralInit(TC.Context, argExpr,
2008+
call->getSourceRange(),
2009+
typeExpr->getTypeLoc())
2010+
: nullptr;
20082011
}
20092012

20102013
/// Pre-check the expression, validating any types that occur in the

test/Constraints/generics.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,3 +686,16 @@ func member_ref_with_explicit_init() {
686686
_ = S.init(42)
687687
// expected-error@-1 {{generic struct 'S' requires that 'Int' conform to 'P'}}
688688
}
689+
690+
func rdar_50007727() {
691+
struct A<T> { // expected-note {{'T' declared as parameter to type 'A'}}
692+
struct B<U> : ExpressibleByStringLiteral {
693+
init(stringLiteral value: String) {}
694+
}
695+
}
696+
697+
struct S {}
698+
let _ = A.B<S>("hello")
699+
// expected-error@-1 {{generic parameter 'T' could not be inferred in cast to 'A<_>.B<S>'}}
700+
// expected-note@-2 {{explicitly specify the generic arguments to fix this issue}} {{12-12=<Any>}}
701+
}

0 commit comments

Comments
 (0)