Skip to content

Commit 1efafbc

Browse files
committed
Fix one source of exponential behavior in the type checker.
For collection literals that contained implicitly unwrapped optionals, we were attempting three different conversions per element of the collection, resulting in exponential type checking time. We should only ever attempt one of these conversions for any pair of types where one or both is optional. We had several reports of this as it seems quite common for people to write expressions that create a collection of IUOs from class/struct elements, and then either return the collection or some variation that has been filtered and mapped. I am looking at adding the appropriate instrumentation to the type checker so that I can add a scale-test for this and other type checker test cases related to slow type checking so that we can avoid regressing in the future.
1 parent 62e825a commit 1efafbc

File tree

1 file changed

+50
-50
lines changed

1 file changed

+50
-50
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,48 @@ static bool isStringCompatiblePointerBaseType(TypeChecker &TC,
11891189
return false;
11901190
}
11911191

1192+
static Optional<ConversionRestrictionKind>
1193+
selectOptionalConversionRestriction(Type type1, Type type2,
1194+
ConstraintKind kind) {
1195+
OptionalTypeKind optionalKind1 = OTK_None;
1196+
if (auto boundGeneric1 = type1->getAs<BoundGenericType>())
1197+
optionalKind1 = boundGeneric1->getDecl()->classifyAsOptionalType();
1198+
1199+
OptionalTypeKind optionalKind2 = OTK_None;
1200+
if (auto boundGeneric2 = type2->getAs<BoundGenericType>())
1201+
optionalKind2 = boundGeneric2->getDecl()->classifyAsOptionalType();
1202+
1203+
if (optionalKind2 == OTK_None) {
1204+
if (optionalKind1 == OTK_ImplicitlyUnwrappedOptional &&
1205+
kind >= ConstraintKind::Conversion)
1206+
return ConversionRestrictionKind::ForceUnchecked;
1207+
1208+
return llvm::None;
1209+
}
1210+
1211+
if (optionalKind1 == optionalKind2)
1212+
return ConversionRestrictionKind::OptionalToOptional;
1213+
1214+
if (optionalKind1 == OTK_None)
1215+
return ConversionRestrictionKind::ValueToOptional;
1216+
1217+
if (optionalKind1 == OTK_Optional) {
1218+
if (kind >= ConstraintKind::Conversion)
1219+
return ConversionRestrictionKind::OptionalToImplicitlyUnwrappedOptional;
1220+
1221+
assert(optionalKind2 == OTK_ImplicitlyUnwrappedOptional &&
1222+
"Result has unexpected optional kind!");
1223+
1224+
return llvm::None;
1225+
}
1226+
1227+
assert(optionalKind1 == OTK_ImplicitlyUnwrappedOptional &&
1228+
"Source has unexpected optional kind!");
1229+
1230+
return ConversionRestrictionKind::ImplicitlyUnwrappedOptionalToOptional;
1231+
}
1232+
1233+
11921234
ConstraintSystem::SolutionKind
11931235
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
11941236
TypeMatchOptions flags,
@@ -1933,57 +1975,15 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
19331975
conversionsOrFixes.push_back(ConversionRestrictionKind::Existential);
19341976
}
19351977

1936-
// A value of type T can be converted to type U? if T is convertible to U.
1937-
// A value of type T? can be converted to type U? if T is convertible to U.
1938-
// The above conversions also apply to implicitly unwrapped optional types,
1939-
// except that there is no implicit conversion from T? to T!.
1940-
{
1941-
BoundGenericType *boundGenericType2;
1942-
1943-
if (concrete && kind >= ConstraintKind::Subtype &&
1944-
(boundGenericType2 = type2->getAs<BoundGenericType>())) {
1945-
auto decl2 = boundGenericType2->getDecl();
1946-
if (auto optionalKind2 = decl2->classifyAsOptionalType()) {
1947-
assert(boundGenericType2->getGenericArgs().size() == 1);
1948-
1949-
BoundGenericType *boundGenericType1 = type1->getAs<BoundGenericType>();
1950-
if (boundGenericType1) {
1951-
auto decl1 = boundGenericType1->getDecl();
1952-
if (decl1 == decl2) {
1953-
assert(boundGenericType1->getGenericArgs().size() == 1);
1954-
conversionsOrFixes.push_back(
1955-
ConversionRestrictionKind::OptionalToOptional);
1956-
} else if (optionalKind2 == OTK_Optional &&
1957-
decl1 == TC.Context.getImplicitlyUnwrappedOptionalDecl()) {
1958-
assert(boundGenericType1->getGenericArgs().size() == 1);
1959-
conversionsOrFixes.push_back(
1960-
ConversionRestrictionKind::ImplicitlyUnwrappedOptionalToOptional);
1961-
} else if (optionalKind2 == OTK_ImplicitlyUnwrappedOptional &&
1962-
kind >= ConstraintKind::Conversion &&
1963-
decl1 == TC.Context.getOptionalDecl()) {
1964-
assert(boundGenericType1->getGenericArgs().size() == 1);
1965-
conversionsOrFixes.push_back(
1966-
ConversionRestrictionKind::OptionalToImplicitlyUnwrappedOptional);
1967-
}
1968-
}
1969-
1970-
conversionsOrFixes.push_back(
1971-
ConversionRestrictionKind::ValueToOptional);
1972-
}
1973-
}
1974-
}
1978+
// A value of type T! can be converted to type U if T is convertible
1979+
// to U by force-unwrapping the source value.
1980+
// A value of type T, T?, or T! can be converted to type U? or U! if
1981+
// T is convertible to U.
1982+
if (concrete && kind >= ConstraintKind::Subtype)
1983+
if (auto restriction =
1984+
selectOptionalConversionRestriction(type1, type2, kind))
1985+
conversionsOrFixes.push_back(restriction.getValue());
19751986

1976-
// A value of type T! can be (unsafely) forced to U if T
1977-
// is convertible to U.
1978-
{
1979-
Type objectType1;
1980-
if (concrete && kind >= ConstraintKind::Conversion &&
1981-
(objectType1 = lookThroughImplicitlyUnwrappedOptionalType(type1))) {
1982-
conversionsOrFixes.push_back(
1983-
ConversionRestrictionKind::ForceUnchecked);
1984-
}
1985-
}
1986-
19871987
// Allow '() -> T' to '() -> ()' and '() -> Never' to '() -> T' for closure
19881988
// literals.
19891989
if (auto elt = locator.last()) {

0 commit comments

Comments
 (0)