Skip to content

Commit c6de808

Browse files
authored
Merge pull request swiftlang#41960 from xedin/csgen-casts-without-reprs
[CSGen/CSApply] Don't expect implicit casts to have type reprs
2 parents 1a6d7c1 + 15772e4 commit c6de808

File tree

4 files changed

+207
-51
lines changed

4 files changed

+207
-51
lines changed

lib/Sema/CSApply.cpp

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3924,15 +3924,22 @@ namespace {
39243924
}
39253925

39263926
Expr *visitCoerceExprImpl(CoerceExpr *expr) {
3927-
// Simplify and update the type we're coercing to.
3928-
assert(expr->getCastTypeRepr());
3929-
const auto toType = simplifyType(cs.getType(expr->getCastTypeRepr()));
3930-
expr->setCastType(toType);
3931-
cs.setType(expr->getCastTypeRepr(), toType);
3927+
if (auto *castTypeRepr = expr->getCastTypeRepr()) {
3928+
// Simplify and update the type we're coercing to.
3929+
auto toType = simplifyType(cs.getType(castTypeRepr));
3930+
expr->setCastType(toType);
3931+
cs.setType(castTypeRepr, toType);
3932+
} else {
3933+
assert(expr->isImplicit());
3934+
assert(expr->getCastType());
3935+
}
3936+
3937+
cs.setType(expr, expr->getCastType());
39323938

39333939
// If this is a literal that got converted into constructor call
39343940
// lets put proper source information in place.
39353941
if (expr->isLiteralInit()) {
3942+
auto toType = expr->getCastType();
39363943
auto *literalInit = expr->getSubExpr();
39373944
if (auto *call = dyn_cast<CallExpr>(literalInit)) {
39383945
cs.forEachExpr(call->getFn(), [&](Expr *subExpr) -> Expr * {
@@ -3958,7 +3965,6 @@ namespace {
39583965
literalInit->setImplicit(false);
39593966
}
39603967

3961-
cs.setType(expr, toType);
39623968
// Keep the coercion around, because it contains the source range
39633969
// for the original constructor call.
39643970
return expr;
@@ -3980,28 +3986,30 @@ namespace {
39803986
// Convert the subexpression.
39813987
Expr *sub = expr->getSubExpr();
39823988

3983-
sub = solution.coerceToType(sub, toType, cs.getConstraintLocator(sub));
3989+
sub = solution.coerceToType(sub, expr->getCastType(),
3990+
cs.getConstraintLocator(sub));
39843991
if (!sub)
39853992
return nullptr;
39863993

39873994
expr->setSubExpr(sub);
3988-
cs.setType(expr, toType);
39893995
return expr;
39903996
}
39913997

39923998
// Bridging conversion.
39933999
assert(choice == 1 && "should be bridging");
39944000

39954001
// Handle optional bindings.
3996-
Expr *sub = handleOptionalBindings(expr->getSubExpr(), toType,
3997-
OptionalBindingsCastKind::Bridged,
3998-
[&](Expr *sub, Type toInstanceType) {
3999-
return buildObjCBridgeExpr(sub, toInstanceType, locator);
4000-
});
4002+
Expr *sub = handleOptionalBindings(
4003+
expr->getSubExpr(), expr->getCastType(),
4004+
OptionalBindingsCastKind::Bridged,
4005+
[&](Expr *sub, Type toInstanceType) {
4006+
return buildObjCBridgeExpr(sub, toInstanceType, locator);
4007+
});
4008+
4009+
if (!sub)
4010+
return nullptr;
40014011

4002-
if (!sub) return nullptr;
40034012
expr->setSubExpr(sub);
4004-
cs.setType(expr, toType);
40054013
return expr;
40064014
}
40074015

@@ -4011,24 +4019,35 @@ namespace {
40114019
auto sub = cs.coerceToRValue(expr->getSubExpr());
40124020
expr->setSubExpr(sub);
40134021

4022+
const auto fromType = cs.getType(sub);
4023+
4024+
Type toType;
4025+
SourceRange castTypeRange;
4026+
40144027
// Simplify and update the type we're casting to.
4015-
auto *const castTypeRepr = expr->getCastTypeRepr();
4028+
if (auto *const castTypeRepr = expr->getCastTypeRepr()) {
4029+
toType = simplifyType(cs.getType(castTypeRepr));
4030+
castTypeRange = castTypeRepr->getSourceRange();
4031+
4032+
cs.setType(castTypeRepr, toType);
4033+
expr->setCastType(toType);
4034+
} else {
4035+
assert(expr->isImplicit());
4036+
assert(expr->getCastType());
4037+
4038+
toType = expr->getCastType();
4039+
}
40164040

4017-
const auto fromType = cs.getType(sub);
4018-
auto toType = simplifyType(cs.getType(castTypeRepr));
40194041
if (hasForcedOptionalResult(expr))
40204042
toType = toType->getOptionalObjectType();
40214043

4022-
expr->setCastType(toType);
4023-
cs.setType(castTypeRepr, toType);
4024-
4025-
auto castContextKind =
4026-
SuppressDiagnostics ? CheckedCastContextKind::None
4027-
: CheckedCastContextKind::ForcedCast;
4044+
auto castContextKind = SuppressDiagnostics || expr->isImplicit()
4045+
? CheckedCastContextKind::None
4046+
: CheckedCastContextKind::ForcedCast;
40284047

40294048
const auto castKind = TypeChecker::typeCheckCheckedCast(
4030-
fromType, toType, castContextKind, cs.DC, expr->getLoc(), sub,
4031-
castTypeRepr->getSourceRange());
4049+
fromType, toType, castContextKind, dc, expr->getLoc(), sub,
4050+
castTypeRange);
40324051
switch (castKind) {
40334052
/// Invalid cast.
40344053
case CheckedCastKind::Unresolved:
@@ -4048,16 +4067,30 @@ namespace {
40484067
expr->setCastKind(castKind);
40494068
break;
40504069
}
4051-
4070+
40524071
return handleOptionalBindingsForCast(expr, simplifyType(cs.getType(expr)),
40534072
OptionalBindingsCastKind::Forced);
40544073
}
40554074

40564075
Expr *visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) {
4057-
// Simplify and update the type we're casting to.
40584076
auto *const castTypeRepr = expr->getCastTypeRepr();
4077+
4078+
// If there is no type repr, it means this is implicit cast which
4079+
// should have a type set.
4080+
if (!castTypeRepr) {
4081+
assert(expr->isImplicit());
4082+
assert(expr->getCastType());
4083+
4084+
auto sub = cs.coerceToRValue(expr->getSubExpr());
4085+
expr->setSubExpr(sub);
4086+
4087+
return expr;
4088+
}
4089+
4090+
// Simplify and update the type we're casting to.
40594091
const auto toType = simplifyType(cs.getType(castTypeRepr));
40604092
expr->setCastType(toType);
4093+
40614094
cs.setType(castTypeRepr, toType);
40624095

40634096
// If we need to insert a force-unwrap for coercions of the form
@@ -4094,7 +4127,7 @@ namespace {
40944127
: CheckedCastContextKind::ConditionalCast;
40954128

40964129
auto castKind = TypeChecker::typeCheckCheckedCast(
4097-
fromType, toType, castContextKind, cs.DC, expr->getLoc(), sub,
4130+
fromType, toType, castContextKind, dc, expr->getLoc(), sub,
40984131
castTypeRepr->getSourceRange());
40994132
switch (castKind) {
41004133
// Invalid cast.
@@ -4107,7 +4140,7 @@ namespace {
41074140
// Special handle for literals conditional checked cast when they can
41084141
// be statically coerced to the cast type.
41094142
if (protocol && TypeChecker::conformsToProtocol(
4110-
toType, protocol, cs.DC->getParentModule())) {
4143+
toType, protocol, dc->getParentModule())) {
41114144
ctx.Diags
41124145
.diagnose(expr->getLoc(),
41134146
diag::literal_conditional_downcast_to_coercion,

lib/Sema/CSGen.cpp

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

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

2976-
auto *const repr = expr->getCastTypeRepr();
2977-
// Validate the resulting type.
2978-
const auto toType = resolveTypeReferenceInExpression(
2979-
repr, TypeResolverContext::ExplicitCastExpr,
2980-
CS.getConstraintLocator(expr));
2987+
auto toType = getTypeForCast(expr);
29812988
if (!toType)
2982-
return nullptr;
2989+
return Type();
2990+
2991+
auto *const repr = expr->getCastTypeRepr();
29832992

29842993
// Cache the type we're casting to.
29852994
if (repr) CS.setType(repr, toType);
@@ -3000,13 +3009,12 @@ namespace {
30003009

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

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

@@ -3032,13 +3040,12 @@ namespace {
30323040
return nullptr;
30333041

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

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

@@ -3057,24 +3064,22 @@ namespace {
30573064
}
30583065

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

3071+
auto *const repr = expr->getCastTypeRepr();
30693072
// Cache the type we're checking.
3070-
CS.setType(expr->getCastTypeRepr(), toType);
3073+
if (repr)
3074+
CS.setType(repr, toType);
30713075

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

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

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

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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
#include "llvm/Support/Casting.h"
16+
17+
using namespace swift;
18+
using namespace swift::unittest;
19+
using namespace swift::constraints;
20+
21+
static Expr *applySolution(ConstraintSystem &cs, Expr *expr,
22+
Solution &solution) {
23+
SolutionApplicationTarget target(expr, cs.DC, CTP_Unused, Type(),
24+
/*isDiscarded=*/false);
25+
auto result = cs.applySolution(solution, target);
26+
return result ? result->getAsExpr() : nullptr;
27+
}
28+
29+
static Type getTypeOfCoercedExpr(ExplicitCastExpr *castExpr) {
30+
return castExpr->getSubExpr()->getType();
31+
}
32+
33+
TEST_F(SemaTest, TestImplicitForceCastConstraintGeneration) {
34+
ConstraintSystem cs(DC, ConstraintSystemOptions());
35+
36+
auto *literal = IntegerLiteralExpr::createFromUnsigned(Context, 42);
37+
38+
auto *castExpr = ForcedCheckedCastExpr::createImplicit(Context, literal,
39+
Context.TheAnyType);
40+
41+
auto *expr = cs.generateConstraints(castExpr, DC, /*isInputExpression=*/true);
42+
43+
ASSERT_NE(expr, nullptr);
44+
45+
SmallVector<Solution, 2> solutions;
46+
cs.solve(solutions);
47+
48+
ASSERT_EQ(solutions.size(), (unsigned)1);
49+
50+
auto &solution = solutions.front();
51+
52+
ASSERT_TRUE(solution.getResolvedType(literal)->isEqual(getStdlibType("Int")));
53+
ASSERT_TRUE(solution.getResolvedType(castExpr)->isEqual(Context.TheAnyType));
54+
55+
auto *resultExpr = applySolution(cs, expr, solution);
56+
ASSERT_NE(resultExpr, nullptr);
57+
ASSERT_TRUE(getTypeOfCoercedExpr(cast<ForcedCheckedCastExpr>(resultExpr))
58+
->isEqual(getStdlibType("Int")));
59+
}
60+
61+
TEST_F(SemaTest, TestImplicitCoercionConstraintGeneration) {
62+
ConstraintSystem cs(DC, ConstraintSystemOptions());
63+
64+
auto *literal = IntegerLiteralExpr::createFromUnsigned(Context, 42);
65+
66+
auto *castExpr = CoerceExpr::createImplicit(Context, literal,
67+
getStdlibType("Double"));
68+
69+
auto *expr = cs.generateConstraints(castExpr, DC, /*isInputExpression=*/true);
70+
71+
ASSERT_NE(expr, nullptr);
72+
73+
SmallVector<Solution, 2> solutions;
74+
cs.solve(solutions);
75+
76+
ASSERT_EQ(solutions.size(), (unsigned)1);
77+
78+
auto &solution = solutions.front();
79+
80+
ASSERT_TRUE(solution.getResolvedType(literal)->isEqual(getStdlibType("Double")));
81+
ASSERT_TRUE(
82+
solution.getResolvedType(castExpr)->isEqual(getStdlibType("Double")));
83+
84+
auto *resultExpr = applySolution(cs, expr, solution);
85+
ASSERT_NE(resultExpr, nullptr);
86+
ASSERT_TRUE(getTypeOfCoercedExpr(cast<CoerceExpr>(resultExpr))
87+
->isEqual(getStdlibType("Double")));
88+
}
89+
90+
TEST_F(SemaTest, TestImplicitConditionalCastConstraintGeneration) {
91+
ConstraintSystem cs(DC, ConstraintSystemOptions());
92+
93+
auto *literal = IntegerLiteralExpr::createFromUnsigned(Context, 42);
94+
95+
auto *castExpr = ConditionalCheckedCastExpr::createImplicit(
96+
Context, literal, getStdlibType("Double"));
97+
98+
auto *expr = cs.generateConstraints(castExpr, DC, /*isInputExpression=*/true);
99+
100+
ASSERT_NE(expr, nullptr);
101+
102+
SmallVector<Solution, 2> solutions;
103+
cs.solve(solutions);
104+
105+
ASSERT_EQ(solutions.size(), (unsigned)1);
106+
107+
auto &solution = solutions.front();
108+
109+
ASSERT_TRUE(solution.getResolvedType(literal)->isEqual(getStdlibType("Int")));
110+
ASSERT_TRUE(solution.getResolvedType(castExpr)->isEqual(
111+
OptionalType::get(getStdlibType("Double"))));
112+
113+
auto *resultExpr = applySolution(cs, expr, solution);
114+
ASSERT_NE(resultExpr, nullptr);
115+
ASSERT_TRUE(getTypeOfCoercedExpr(cast<ConditionalCheckedCastExpr>(resultExpr))
116+
->isEqual(getStdlibType("Int")));
117+
}

0 commit comments

Comments
 (0)