blob: ba568fe00f2d3e77ca9c9832cef284bb2128c772 [file] [log] [blame]
//===--- TypeMatchTests.cpp - Tests for TypeBase::matches -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "TestContext.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Types.h"
#include "gtest/gtest.h"
using namespace swift;
using namespace swift::unittest;
TEST(TypeMatch, IdenticalTypes) {
TestContext C;
auto check = [](Type ty) {
return ty->matches(ty, TypeMatchOptions()) &&
ty->matches(ty, TypeMatchFlags::AllowOverride);
};
EXPECT_TRUE(check(C.Ctx.TheEmptyTupleType));
EXPECT_TRUE(check(C.Ctx.TheRawPointerType));
Type voidToVoidFn = FunctionType::get(C.Ctx.TheEmptyTupleType,
C.Ctx.TheEmptyTupleType);
EXPECT_TRUE(check(voidToVoidFn));
Type ptrToPtrFn = FunctionType::get(C.Ctx.TheRawPointerType,
C.Ctx.TheRawPointerType);
EXPECT_TRUE(check(ptrToPtrFn));
auto *someStruct = C.makeNominal<StructDecl>("MyStruct");
Type structTy = someStruct->getDeclaredInterfaceType();
EXPECT_TRUE(check(structTy));
Type structToStructFn = FunctionType::get(structTy, structTy);
EXPECT_TRUE(check(structToStructFn));
}
TEST(TypeMatch, UnrelatedTypes) {
TestContext C;
auto check = [](Type base, Type derived) {
return derived->matches(base, TypeMatchOptions()) &&
derived->matches(base, TypeMatchFlags::AllowOverride);
};
EXPECT_FALSE(check(C.Ctx.TheEmptyTupleType, C.Ctx.TheRawPointerType));
EXPECT_FALSE(check(C.Ctx.TheRawPointerType, C.Ctx.TheEmptyTupleType));
Type voidToVoidFn = FunctionType::get(C.Ctx.TheEmptyTupleType,
C.Ctx.TheEmptyTupleType);
EXPECT_FALSE(check(voidToVoidFn, C.Ctx.TheEmptyTupleType));
EXPECT_FALSE(check(C.Ctx.TheEmptyTupleType, voidToVoidFn));
Type ptrToPtrFn = FunctionType::get(C.Ctx.TheRawPointerType,
C.Ctx.TheRawPointerType);
EXPECT_FALSE(check(ptrToPtrFn, voidToVoidFn));
EXPECT_FALSE(check(voidToVoidFn, ptrToPtrFn));
auto *someStruct = C.makeNominal<StructDecl>("MyStruct");
Type structTy = someStruct->getDeclaredInterfaceType();
EXPECT_FALSE(check(structTy, C.Ctx.TheEmptyTupleType));
EXPECT_FALSE(check(C.Ctx.TheEmptyTupleType, structTy));
EXPECT_FALSE(check(structTy, voidToVoidFn));
EXPECT_FALSE(check(voidToVoidFn, structTy));
Type structToStructFn = FunctionType::get(structTy, structTy);
EXPECT_FALSE(check(structToStructFn, structTy));
EXPECT_FALSE(check(structTy, structToStructFn));
EXPECT_FALSE(check(structToStructFn, voidToVoidFn));
EXPECT_FALSE(check(voidToVoidFn, structToStructFn));
auto *anotherStruct = C.makeNominal<StructDecl>("AnotherStruct");
Type anotherStructTy = anotherStruct->getDeclaredInterfaceType();
EXPECT_FALSE(check(structTy, anotherStructTy));
EXPECT_FALSE(check(anotherStructTy, structTy));
Type anotherStructToAnotherStructFn = FunctionType::get(anotherStructTy,
anotherStructTy);
EXPECT_FALSE(check(anotherStructToAnotherStructFn, structToStructFn));
EXPECT_FALSE(check(structToStructFn, anotherStructToAnotherStructFn));
Type S2ASFn = FunctionType::get(structTy, anotherStructTy);
EXPECT_FALSE(check(S2ASFn, structToStructFn));
EXPECT_FALSE(check(structToStructFn, S2ASFn));
EXPECT_FALSE(check(S2ASFn, anotherStructToAnotherStructFn));
EXPECT_FALSE(check(anotherStructToAnotherStructFn, S2ASFn));
}
TEST(TypeMatch, Classes) {
TestContext C;
auto check = [](Type base, Type derived) {
return derived->matches(base, TypeMatchFlags::AllowOverride) &&
!derived->matches(base, TypeMatchOptions());
};
auto *baseClass = C.makeNominal<ClassDecl>("Base");
Type baseTy = baseClass->getDeclaredInterfaceType();
auto *subClass = C.makeNominal<ClassDecl>("Sub");
subClass->setSuperclass(baseTy);
Type subTy = subClass->getDeclaredInterfaceType();
EXPECT_TRUE(check(baseTy, subTy));
EXPECT_FALSE(check(subTy, baseTy));
auto *otherClass = C.makeNominal<ClassDecl>("Other");
Type otherTy = otherClass->getDeclaredInterfaceType();
EXPECT_FALSE(check(otherTy, baseTy));
EXPECT_FALSE(check(baseTy, otherTy));
EXPECT_FALSE(check(otherTy, subTy));
EXPECT_FALSE(check(subTy, otherTy));
Type baseToVoid = FunctionType::get(baseTy, C.Ctx.TheEmptyTupleType);
Type subToVoid = FunctionType::get(subTy, C.Ctx.TheEmptyTupleType);
EXPECT_FALSE(check(baseToVoid, subToVoid));
EXPECT_TRUE(check(subToVoid, baseToVoid));
Type voidToBase = FunctionType::get(C.Ctx.TheEmptyTupleType, baseTy);
Type voidToSub = FunctionType::get(C.Ctx.TheEmptyTupleType, subTy);
EXPECT_FALSE(check(voidToSub, voidToBase));
EXPECT_TRUE(check(voidToBase, voidToSub));
Type baseToBase = FunctionType::get(baseTy, baseTy);
Type subToSub = FunctionType::get(subTy, subTy);
EXPECT_FALSE(check(baseToBase, subToSub));
EXPECT_FALSE(check(subToSub, baseToBase));
}
TEST(TypeMatch, Optionals) {
TestContext C{DeclareOptionalTypes};
auto check = [](Type base, Type derived) {
return derived->matches(base, TypeMatchFlags::AllowOverride) &&
!derived->matches(base, TypeMatchOptions());
};
auto *baseClass = C.makeNominal<ClassDecl>("Base");
Type baseTy = baseClass->getDeclaredInterfaceType();
Type optTy = OptionalType::get(baseTy);
EXPECT_FALSE(check(baseTy, optTy));
EXPECT_TRUE(check(optTy, baseTy));
Type baseToVoid = FunctionType::get(baseTy, C.Ctx.TheEmptyTupleType);
Type optToVoid = FunctionType::get(optTy, C.Ctx.TheEmptyTupleType);
EXPECT_TRUE(check(baseToVoid, optToVoid));
EXPECT_FALSE(check(optToVoid, baseToVoid));
Type voidToBase = FunctionType::get(C.Ctx.TheEmptyTupleType, baseTy);
Type voidToOpt = FunctionType::get(C.Ctx.TheEmptyTupleType, optTy);
EXPECT_FALSE(check(voidToBase, voidToOpt));
EXPECT_TRUE(check(voidToOpt, voidToBase));
Type baseToBase = FunctionType::get(baseTy, baseTy);
Type optToOpt = FunctionType::get(optTy, optTy);
EXPECT_FALSE(check(baseToBase, optToOpt));
EXPECT_FALSE(check(optToOpt, baseToBase));
}
TEST(TypeMatch, OptionalMismatch) {
TestContext C{DeclareOptionalTypes};
auto check = [](Type base, Type derived) {
return derived->matches(base, TypeMatchFlags::AllowOverride) &&
!derived->matches(base, TypeMatchOptions());
};
auto checkOpt = [](Type base, Type derived) {
return derived->matches(base,
TypeMatchFlags::AllowTopLevelOptionalMismatch);
};
auto checkOptOverride = [](Type base, Type derived) {
TypeMatchOptions matchMode = TypeMatchFlags::AllowOverride;
matchMode |= TypeMatchFlags::AllowTopLevelOptionalMismatch;
return derived->matches(base, matchMode);
};
auto *baseClass = C.makeNominal<ClassDecl>("Base");
Type baseTy = baseClass->getDeclaredInterfaceType();
Type optTy = OptionalType::get(baseTy);
Type baseToVoid = FunctionType::get(baseTy, C.Ctx.TheEmptyTupleType);
Type optToVoid = FunctionType::get(optTy, C.Ctx.TheEmptyTupleType);
EXPECT_TRUE(check(baseToVoid, optToVoid));
EXPECT_TRUE(checkOpt(baseToVoid, optToVoid));
EXPECT_TRUE(checkOptOverride(baseToVoid, optToVoid));
EXPECT_FALSE(check(optToVoid, baseToVoid));
EXPECT_TRUE(checkOpt(optToVoid, baseToVoid));
EXPECT_TRUE(checkOptOverride(optToVoid, baseToVoid));
Type voidToBase = FunctionType::get(C.Ctx.TheEmptyTupleType, baseTy);
Type voidToOpt = FunctionType::get(C.Ctx.TheEmptyTupleType, optTy);
EXPECT_FALSE(check(voidToBase, voidToOpt));
EXPECT_TRUE(checkOpt(voidToBase, voidToOpt));
EXPECT_TRUE(checkOptOverride(voidToBase, voidToOpt));
EXPECT_TRUE(check(voidToOpt, voidToBase));
EXPECT_TRUE(checkOpt(voidToOpt, voidToBase));
EXPECT_TRUE(checkOptOverride(voidToOpt, voidToBase));
Type baseToBase = FunctionType::get(baseTy, baseTy);
Type optToOpt = FunctionType::get(optTy, optTy);
EXPECT_FALSE(check(baseToBase, optToOpt));
EXPECT_TRUE(checkOpt(baseToBase, optToOpt));
EXPECT_TRUE(checkOptOverride(baseToBase, optToOpt));
EXPECT_FALSE(check(optToOpt, baseToBase));
EXPECT_TRUE(checkOpt(optToOpt, baseToBase));
EXPECT_TRUE(checkOptOverride(optToOpt, baseToBase));
auto *subClass = C.makeNominal<ClassDecl>("Sub");
subClass->setSuperclass(baseTy);
Type subTy = subClass->getDeclaredInterfaceType();
Type optSubTy = OptionalType::get(subTy);
EXPECT_FALSE(check(baseTy, optSubTy));
EXPECT_FALSE(checkOpt(baseTy, optSubTy));
EXPECT_TRUE(checkOptOverride(baseTy, optSubTy));
EXPECT_TRUE(check(optTy, subTy));
EXPECT_FALSE(checkOpt(optTy, subTy));
EXPECT_TRUE(checkOptOverride(optTy, subTy));
EXPECT_TRUE(check(optTy, optSubTy));
EXPECT_FALSE(checkOpt(optTy, optSubTy));
EXPECT_TRUE(checkOptOverride(optTy, optSubTy));
EXPECT_FALSE(check(optSubTy, baseTy));
EXPECT_FALSE(checkOpt(optSubTy, baseTy));
EXPECT_FALSE(checkOptOverride(optSubTy, baseTy));
EXPECT_FALSE(check(subTy, optTy));
EXPECT_FALSE(checkOpt(subTy, optTy));
EXPECT_FALSE(checkOptOverride(subTy, optTy));
EXPECT_FALSE(check(optSubTy, optTy));
EXPECT_FALSE(checkOpt(optSubTy, optTy));
EXPECT_FALSE(checkOptOverride(optSubTy, optTy));
}
TEST(TypeMatch, OptionalMismatchTuples) {
TestContext C{DeclareOptionalTypes};
auto checkOverride = [](Type base, Type derived) {
return derived->matches(base, TypeMatchFlags::AllowOverride) &&
!derived->matches(base, TypeMatchOptions());
};
auto *baseClass = C.makeNominal<ClassDecl>("Base");
Type baseTy = baseClass->getDeclaredInterfaceType();
Type optTy = OptionalType::get(baseTy);
Type baseBaseTuple = TupleType::get({baseTy, baseTy}, C.Ctx);
Type optOptTuple = TupleType::get({optTy, optTy}, C.Ctx);
Type baseOptTuple = TupleType::get({baseTy, optTy}, C.Ctx);
Type optBaseTuple = TupleType::get({optTy, baseTy}, C.Ctx);
EXPECT_FALSE(checkOverride(baseBaseTuple, optOptTuple));
EXPECT_FALSE(checkOverride(baseBaseTuple, baseOptTuple));
EXPECT_FALSE(checkOverride(baseBaseTuple, optBaseTuple));
EXPECT_TRUE(checkOverride(optOptTuple, baseBaseTuple));
EXPECT_TRUE(checkOverride(optOptTuple, baseOptTuple));
EXPECT_TRUE(checkOverride(optOptTuple, optBaseTuple));
EXPECT_TRUE(checkOverride(baseOptTuple, baseBaseTuple));
EXPECT_FALSE(checkOverride(baseOptTuple, optOptTuple));
EXPECT_FALSE(checkOverride(baseOptTuple, optBaseTuple));
EXPECT_TRUE(checkOverride(optBaseTuple, baseBaseTuple));
EXPECT_FALSE(checkOverride(optBaseTuple, optOptTuple));
EXPECT_FALSE(checkOverride(optBaseTuple, baseOptTuple));
auto checkOpt = [](Type base, Type derived) {
return derived->matches(base,
TypeMatchFlags::AllowTopLevelOptionalMismatch);
};
EXPECT_TRUE(checkOpt(baseBaseTuple, optOptTuple));
EXPECT_TRUE(checkOpt(baseBaseTuple, baseOptTuple));
EXPECT_TRUE(checkOpt(baseBaseTuple, optBaseTuple));
EXPECT_TRUE(checkOpt(optOptTuple, baseBaseTuple));
EXPECT_TRUE(checkOpt(optOptTuple, baseOptTuple));
EXPECT_TRUE(checkOpt(optOptTuple, optBaseTuple));
EXPECT_TRUE(checkOpt(baseOptTuple, baseBaseTuple));
EXPECT_TRUE(checkOpt(baseOptTuple, optOptTuple));
EXPECT_TRUE(checkOpt(baseOptTuple, optBaseTuple));
EXPECT_TRUE(checkOpt(optBaseTuple, baseBaseTuple));
EXPECT_TRUE(checkOpt(optBaseTuple, optOptTuple));
EXPECT_TRUE(checkOpt(optBaseTuple, baseOptTuple));
Type optOfTuple = OptionalType::get(baseBaseTuple);
EXPECT_TRUE(checkOverride(optOfTuple, baseBaseTuple));
EXPECT_FALSE(checkOverride(baseBaseTuple, optOfTuple));
EXPECT_TRUE(checkOpt(optOfTuple, baseBaseTuple));
EXPECT_TRUE(checkOpt(baseBaseTuple, optOfTuple));
}
TEST(TypeMatch, OptionalMismatchFunctions) {
TestContext C{DeclareOptionalTypes};
auto checkOverride = [](Type base, Type derived) {
return derived->matches(base, TypeMatchFlags::AllowOverride) &&
!derived->matches(base, TypeMatchOptions());
};
auto checkOpt = [](Type base, Type derived) {
return derived->matches(base,
TypeMatchFlags::AllowTopLevelOptionalMismatch);
};
Type voidToVoid = FunctionType::get(C.Ctx.TheEmptyTupleType,
C.Ctx.TheEmptyTupleType);
Type optVoidToVoid = OptionalType::get(voidToVoid);
EXPECT_TRUE(checkOverride(optVoidToVoid, voidToVoid));
EXPECT_TRUE(checkOpt(optVoidToVoid, voidToVoid));
EXPECT_FALSE(checkOverride(voidToVoid, optVoidToVoid));
EXPECT_TRUE(checkOpt(voidToVoid, optVoidToVoid));
}
TEST(TypeMatch, NoEscapeMismatchFunctions) {
TestContext C{DeclareOptionalTypes};
// Note the reversed names here: parameters must be contravariant for the
// functions that take them to be covariant.
auto checkOverride = [](Type paramOfDerived, Type paramOfBase) {
return paramOfBase->matches(paramOfDerived, TypeMatchFlags::AllowOverride);
};
auto checkMismatch = [](Type paramOfDerived, Type paramOfBase) {
return paramOfBase->matches(
paramOfDerived,
TypeMatchFlags::IgnoreNonEscapingForOptionalFunctionParam);
};
Type voidToVoidFn = FunctionType::get(C.Ctx.TheEmptyTupleType,
C.Ctx.TheEmptyTupleType);
Type nonescapingVoidToVoidFn =
FunctionType::get(C.Ctx.TheEmptyTupleType, C.Ctx.TheEmptyTupleType,
FunctionType::ExtInfo().withNoEscape());
Type optVoidToVoidFn = OptionalType::get(voidToVoidFn);
Type optNonescapingVoidToVoidFn = OptionalType::get(nonescapingVoidToVoidFn);
EXPECT_FALSE(checkOverride(nonescapingVoidToVoidFn, voidToVoidFn));
EXPECT_FALSE(checkMismatch(nonescapingVoidToVoidFn, voidToVoidFn));
EXPECT_FALSE(checkOverride(voidToVoidFn, nonescapingVoidToVoidFn));
EXPECT_FALSE(checkMismatch(voidToVoidFn, nonescapingVoidToVoidFn));
EXPECT_FALSE(checkOverride(nonescapingVoidToVoidFn, optVoidToVoidFn));
EXPECT_FALSE(checkMismatch(nonescapingVoidToVoidFn, optVoidToVoidFn));
EXPECT_FALSE(checkOverride(optVoidToVoidFn, nonescapingVoidToVoidFn));
EXPECT_FALSE(checkMismatch(optVoidToVoidFn, nonescapingVoidToVoidFn));
EXPECT_FALSE(checkOverride(optNonescapingVoidToVoidFn, voidToVoidFn));
EXPECT_FALSE(checkMismatch(optNonescapingVoidToVoidFn, voidToVoidFn));
EXPECT_FALSE(checkOverride(voidToVoidFn, optNonescapingVoidToVoidFn));
EXPECT_FALSE(checkMismatch(voidToVoidFn, optNonescapingVoidToVoidFn));
EXPECT_FALSE(checkOverride(optNonescapingVoidToVoidFn, optVoidToVoidFn));
EXPECT_FALSE(checkMismatch(optNonescapingVoidToVoidFn, optVoidToVoidFn));
EXPECT_FALSE(checkOverride(optVoidToVoidFn, optNonescapingVoidToVoidFn));
EXPECT_TRUE(checkMismatch(optVoidToVoidFn, optNonescapingVoidToVoidFn));
}