Skip to content

Commit f170b94

Browse files
committed
[AST] Don't allow IUO-to-non-optional in non-parameter positions.
The previous logic accidentally propagated the "is parameter" flag into any number of nested tuples. Fix this by differentiating between "input of a function type" and "member of a tuple that's the input of a function type".
1 parent c333b0b commit f170b94

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

lib/AST/Type.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,8 +2316,16 @@ bool TypeBase::isTriviallyRepresentableIn(ForeignLanguage language,
23162316
llvm_unreachable("Unhandled ForeignRepresentableKind in switch.");
23172317
}
23182318

2319+
namespace {
2320+
enum class ParameterPosition {
2321+
NotParameter,
2322+
Parameter,
2323+
ParameterTupleElement
2324+
};
2325+
} // end anonymous namespace
2326+
23192327
static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
2320-
bool isParameter, bool insideOptional,
2328+
ParameterPosition paramPosition, bool insideOptional,
23212329
LazyResolver *resolver) {
23222330
if (t1 == t2) return true;
23232331

@@ -2329,22 +2337,22 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
23292337
// Optional-to-optional.
23302338
if (auto obj1 = t1.getAnyOptionalObjectType()) {
23312339
// Allow T? and T! to freely match one another.
2332-
return matches(obj1, obj2, matchMode, /*isParameter=*/false,
2340+
return matches(obj1, obj2, matchMode, ParameterPosition::NotParameter,
23332341
/*insideOptional=*/true, resolver);
23342342
}
23352343

23362344
// Value-to-optional.
23372345
if (matchMode.contains(TypeMatchFlags::AllowOverride) ||
23382346
matchMode.contains(TypeMatchFlags::AllowTopLevelOptionalMismatch)) {
2339-
return matches(t1, obj2, matchMode, /*isParameter=*/false,
2347+
return matches(t1, obj2, matchMode, ParameterPosition::NotParameter,
23402348
/*insideOptional=*/true, resolver);
23412349
}
23422350

23432351
} else if (matchMode.contains(
23442352
TypeMatchFlags::AllowTopLevelOptionalMismatch)) {
23452353
// Optional-to-value, normally disallowed.
23462354
if (auto obj1 = t1.getAnyOptionalObjectType()) {
2347-
return matches(obj1, t2, matchMode, /*isParameter=*/false,
2355+
return matches(obj1, t2, matchMode, ParameterPosition::NotParameter,
23482356
/*insideOptional=*/true, resolver);
23492357
}
23502358
}
@@ -2354,18 +2362,30 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
23542362
if (auto tuple2 = dyn_cast<TupleType>(t2)) {
23552363
// We only ever look into singleton tuples on the RHS if we're
23562364
// certain that the LHS isn't also a singleton tuple.
2365+
ParameterPosition elementPosition;
2366+
switch (paramPosition) {
2367+
case ParameterPosition::NotParameter:
2368+
case ParameterPosition::ParameterTupleElement:
2369+
elementPosition = ParameterPosition::NotParameter;
2370+
break;
2371+
case ParameterPosition::Parameter:
2372+
elementPosition = ParameterPosition::ParameterTupleElement;
2373+
break;
2374+
}
2375+
23572376
auto tuple1 = dyn_cast<TupleType>(t1);
23582377
if (!tuple1 || tuple1->getNumElements() != tuple2->getNumElements()) {
23592378
if (tuple2->getNumElements() == 1) {
2360-
return matches(t1, tuple2.getElementType(0), matchMode, isParameter,
2379+
return matches(t1, tuple2.getElementType(0), matchMode, elementPosition,
23612380
/*insideOptional=*/false, resolver);
23622381
}
23632382
return false;
23642383
}
23652384

23662385
for (auto i : indices(tuple1.getElementTypes())) {
23672386
if (!matches(tuple1.getElementType(i), tuple2.getElementType(i),
2368-
matchMode, isParameter, /*insideOptional=*/false, resolver)){
2387+
matchMode, elementPosition, /*insideOptional=*/false,
2388+
resolver)){
23692389
return false;
23702390
}
23712391
}
@@ -2393,13 +2413,17 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
23932413

23942414
// Inputs are contravariant, results are covariant.
23952415
return (matches(fn2.getInput(), fn1.getInput(), matchMode,
2396-
/*isParameter=*/true, /*insideOptional=*/false, resolver) &&
2416+
ParameterPosition::Parameter, /*insideOptional=*/false,
2417+
resolver) &&
23972418
matches(fn1.getResult(), fn2.getResult(), matchMode,
2398-
/*isParameter=*/false, /*insideOptional=*/false, resolver));
2419+
ParameterPosition::NotParameter, /*insideOptional=*/false,
2420+
resolver));
23992421
}
24002422

24012423
if (matchMode.contains(TypeMatchFlags::AllowNonOptionalForIUOParam) &&
2402-
isParameter && !insideOptional) {
2424+
(paramPosition == ParameterPosition::Parameter ||
2425+
paramPosition == ParameterPosition::ParameterTupleElement) &&
2426+
!insideOptional) {
24032427
// Allow T to override T! in certain cases.
24042428
if (auto obj1 = t1->getImplicitlyUnwrappedOptionalObjectType()) {
24052429
t1 = obj1->getCanonicalType();
@@ -2412,13 +2436,18 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
24122436
if (t2->isExactSuperclassOf(t1))
24132437
return true;
24142438

2439+
if (matchMode.contains(TypeMatchFlags::AllowABICompatible))
2440+
if (isABICompatibleEvenAddingOptional(t1, t2))
2441+
return true;
2442+
24152443
return false;
24162444
}
24172445

24182446
bool TypeBase::matches(Type other, TypeMatchOptions matchMode,
24192447
LazyResolver *resolver) {
24202448
return ::matches(getCanonicalType(), other->getCanonicalType(), matchMode,
2421-
/*isParameter=*/false, /*insideOptional=*/false, resolver);
2449+
ParameterPosition::NotParameter, /*insideOptional=*/false,
2450+
resolver);
24222451
}
24232452

24242453
/// getNamedElementId - If this tuple has a field with the specified name,

unittests/AST/TypeMatchTests.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,33 @@ TEST(TypeMatch, IUONearMatch) {
220220
EXPECT_FALSE(check(optToOpt, baseToBase));
221221
EXPECT_FALSE(checkIUO(optToOpt, baseToBase));
222222
EXPECT_TRUE(checkIUOOverride(optToOpt, baseToBase));
223+
224+
Type tupleOfBase = TupleType::get({baseTy, baseTy}, C.Ctx);
225+
Type tupleOfOpt = TupleType::get({optTy, optTy}, C.Ctx);
226+
227+
Type baseTupleToVoid = FunctionType::get(tupleOfBase,C.Ctx.TheEmptyTupleType);
228+
Type optTupleToVoid = FunctionType::get(tupleOfOpt, C.Ctx.TheEmptyTupleType);
229+
EXPECT_TRUE(check(baseTupleToVoid, optTupleToVoid));
230+
EXPECT_FALSE(checkIUO(baseTupleToVoid, optTupleToVoid));
231+
EXPECT_TRUE(checkIUOOverride(baseTupleToVoid, optTupleToVoid));
232+
EXPECT_FALSE(check(optTupleToVoid, baseTupleToVoid));
233+
EXPECT_TRUE(checkIUO(optTupleToVoid, baseTupleToVoid));
234+
EXPECT_TRUE(checkIUOOverride(optTupleToVoid, baseTupleToVoid));
235+
236+
Type nestedBaseTuple = TupleType::get({C.Ctx.TheEmptyTupleType, tupleOfBase},
237+
C.Ctx);
238+
Type nestedOptTuple = TupleType::get({C.Ctx.TheEmptyTupleType, tupleOfOpt},
239+
C.Ctx);
240+
Type nestedBaseTupleToVoid = FunctionType::get(nestedBaseTuple,
241+
C.Ctx.TheEmptyTupleType);
242+
Type nestedOptTupleToVoid = FunctionType::get(nestedOptTuple,
243+
C.Ctx.TheEmptyTupleType);
244+
EXPECT_TRUE(check(nestedBaseTupleToVoid, nestedOptTupleToVoid));
245+
EXPECT_FALSE(checkIUO(nestedBaseTupleToVoid, nestedOptTupleToVoid));
246+
EXPECT_TRUE(checkIUOOverride(nestedBaseTupleToVoid, nestedOptTupleToVoid));
247+
EXPECT_FALSE(check(nestedOptTupleToVoid, nestedBaseTupleToVoid));
248+
EXPECT_FALSE(checkIUO(nestedOptTupleToVoid, nestedBaseTupleToVoid));
249+
EXPECT_FALSE(checkIUOOverride(nestedOptTupleToVoid, nestedBaseTupleToVoid));
223250
}
224251

225252
TEST(TypeMatch, OptionalMismatch) {

0 commit comments

Comments
 (0)