Skip to content

Commit 37da960

Browse files
committed
[CSGen] Don't expect implicit casts to have type reprs
Implicit casts are allowed to be constructed with a type, instead of a type repr. Constraint generation should honor that, and fallback to using cast type when repr is was not given.
1 parent 7f2bde2 commit 37da960

File tree

3 files changed

+115
-21
lines changed

3 files changed

+115
-21
lines changed

lib/Sema/CSGen.cpp

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2969,18 +2969,27 @@ namespace {
29692969
return typeVar;
29702970
}
29712971

2972+
Type getTypeForCast(ExplicitCastExpr *E) {
2973+
if (auto *const repr = E->getCastTypeRepr()) {
2974+
// Validate the resulting type.
2975+
return resolveTypeReferenceInExpression(
2976+
repr, TypeResolverContext::ExplicitCastExpr,
2977+
CS.getConstraintLocator(E));
2978+
}
2979+
assert(E->isImplicit());
2980+
return E->getCastType();
2981+
}
2982+
29722983
Type visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
29732984
auto fromExpr = expr->getSubExpr();
29742985
if (!fromExpr) // Either wasn't constructed correctly or wasn't folded.
29752986
return nullptr;
29762987

2977-
auto *const repr = expr->getCastTypeRepr();
2978-
// Validate the resulting type.
2979-
const auto toType = resolveTypeReferenceInExpression(
2980-
repr, TypeResolverContext::ExplicitCastExpr,
2981-
CS.getConstraintLocator(expr));
2988+
auto toType = getTypeForCast(expr);
29822989
if (!toType)
2983-
return nullptr;
2990+
return Type();
2991+
2992+
auto *const repr = expr->getCastTypeRepr();
29842993

29852994
// Cache the type we're casting to.
29862995
if (repr) CS.setType(repr, toType);
@@ -3001,13 +3010,12 @@ namespace {
30013010

30023011
Type visitCoerceExpr(CoerceExpr *expr) {
30033012
// Validate the resulting type.
3004-
auto *const repr = expr->getCastTypeRepr();
3005-
const auto toType = resolveTypeReferenceInExpression(
3006-
repr, TypeResolverContext::ExplicitCastExpr,
3007-
CS.getConstraintLocator(expr));
3013+
auto toType = getTypeForCast(expr);
30083014
if (!toType)
30093015
return nullptr;
30103016

3017+
auto *const repr = expr->getCastTypeRepr();
3018+
30113019
// Cache the type we're casting to.
30123020
if (repr) CS.setType(repr, toType);
30133021

@@ -3033,13 +3041,12 @@ namespace {
30333041
return nullptr;
30343042

30353043
// Validate the resulting type.
3036-
auto *const repr = expr->getCastTypeRepr();
3037-
const auto toType = resolveTypeReferenceInExpression(
3038-
repr, TypeResolverContext::ExplicitCastExpr,
3039-
CS.getConstraintLocator(expr));
3044+
const auto toType = getTypeForCast(expr);
30403045
if (!toType)
30413046
return nullptr;
30423047

3048+
auto *const repr = expr->getCastTypeRepr();
3049+
30433050
// Cache the type we're casting to.
30443051
if (repr) CS.setType(repr, toType);
30453052

@@ -3058,24 +3065,22 @@ namespace {
30583065
}
30593066

30603067
Type visitIsExpr(IsExpr *expr) {
3061-
// Validate the type.
3062-
// FIXME: Locator for the cast type?
3063-
auto &ctx = CS.getASTContext();
3064-
const auto toType = resolveTypeReferenceInExpression(
3065-
expr->getCastTypeRepr(), TypeResolverContext::ExplicitCastExpr,
3066-
CS.getConstraintLocator(expr));
3068+
auto toType = getTypeForCast(expr);
30673069
if (!toType)
30683070
return nullptr;
30693071

3072+
auto *const repr = expr->getCastTypeRepr();
30703073
// Cache the type we're checking.
3071-
CS.setType(expr->getCastTypeRepr(), toType);
3074+
if (repr)
3075+
CS.setType(repr, toType);
30723076

30733077
// Add a checked cast constraint.
30743078
auto fromType = CS.getType(expr->getSubExpr());
30753079

30763080
CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType,
30773081
CS.getConstraintLocator(expr));
30783082

3083+
auto &ctx = CS.getASTContext();
30793084
// The result is Bool.
30803085
auto boolDecl = ctx.getBoolDecl();
30813086

unittests/Sema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
add_swift_unittest(swiftSemaTests
33
SemaFixture.cpp
44
BindingInferenceTests.cpp
5+
ConstraintGenerationTests.cpp
56
ConstraintSimplificationTests.cpp
67
UnresolvedMemberLookupTests.cpp
78
PlaceholderTypeInferenceTests.cpp
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===--- ConstraintGenerationTests.cpp ------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "SemaFixture.h"
14+
#include "swift/AST/Expr.h"
15+
16+
using namespace swift;
17+
using namespace swift::unittest;
18+
using namespace swift::constraints;
19+
20+
TEST_F(SemaTest, TestImplicitForceCastConstraintGeneration) {
21+
ConstraintSystem cs(DC, ConstraintSystemOptions());
22+
23+
auto *literal = IntegerLiteralExpr::createFromUnsigned(Context, 42);
24+
25+
auto *cast = ForcedCheckedCastExpr::createImplicit(Context, literal,
26+
getStdlibType("Double"));
27+
28+
auto *expr = cs.generateConstraints(cast, DC, /*isInputExpression=*/true);
29+
30+
ASSERT_NE(expr, nullptr);
31+
32+
SmallVector<Solution, 2> solutions;
33+
cs.solve(solutions);
34+
35+
ASSERT_EQ(solutions.size(), (unsigned)1);
36+
37+
auto &solution = solutions.front();
38+
39+
ASSERT_TRUE(solution.getResolvedType(literal)->isEqual(getStdlibType("Int")));
40+
ASSERT_TRUE(solution.getResolvedType(cast)->isEqual(getStdlibType("Double")));
41+
}
42+
43+
TEST_F(SemaTest, TestImplicitCoercionConstraintGeneration) {
44+
ConstraintSystem cs(DC, ConstraintSystemOptions());
45+
46+
auto *literal = IntegerLiteralExpr::createFromUnsigned(Context, 42);
47+
48+
auto *cast = CoerceExpr::createImplicit(Context, literal,
49+
getStdlibType("Double"));
50+
51+
auto *expr = cs.generateConstraints(cast, DC, /*isInputExpression=*/true);
52+
53+
ASSERT_NE(expr, nullptr);
54+
55+
SmallVector<Solution, 2> solutions;
56+
cs.solve(solutions);
57+
58+
ASSERT_EQ(solutions.size(), (unsigned)1);
59+
60+
auto &solution = solutions.front();
61+
62+
ASSERT_TRUE(solution.getResolvedType(literal)->isEqual(getStdlibType("Double")));
63+
ASSERT_TRUE(solution.getResolvedType(cast)->isEqual(getStdlibType("Double")));
64+
}
65+
66+
TEST_F(SemaTest, TestImplicitConditionalCastConstraintGeneration) {
67+
ConstraintSystem cs(DC, ConstraintSystemOptions());
68+
69+
auto *literal = IntegerLiteralExpr::createFromUnsigned(Context, 42);
70+
71+
auto *cast = ConditionalCheckedCastExpr::createImplicit(
72+
Context, literal, getStdlibType("Double"));
73+
74+
auto *expr = cs.generateConstraints(cast, DC, /*isInputExpression=*/true);
75+
76+
ASSERT_NE(expr, nullptr);
77+
78+
SmallVector<Solution, 2> solutions;
79+
cs.solve(solutions);
80+
81+
ASSERT_EQ(solutions.size(), (unsigned)1);
82+
83+
auto &solution = solutions.front();
84+
85+
ASSERT_TRUE(solution.getResolvedType(literal)->isEqual(getStdlibType("Int")));
86+
ASSERT_TRUE(solution.getResolvedType(cast)->isEqual(
87+
OptionalType::get(getStdlibType("Double"))));
88+
}

0 commit comments

Comments
 (0)