Skip to content

[CSApply] Don't try to force propagate l-value access in "shallow" mode #15287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,9 +251,15 @@ getImplicitMemberReferenceAccessSemantics(Expr *base, VarDecl *member,
return member->getAccessSemanticsFromContext(DC);
}

void ConstraintSystem::propagateLValueAccessKind(Expr *E,
AccessKind accessKind,
void ConstraintSystem::propagateLValueAccessKind(Expr *E, AccessKind accessKind,
bool isShallow,
bool allowOverwrite) {
// If solver is set up in "shallow" mode we expect that some of the
// sub-expressions are already type-checked which means that they
// already have access kind set.
if (isShallow && E->hasLValueAccessKind() && !allowOverwrite)
return;

E->propagateLValueAccessKind(accessKind,
[&](Expr *E) -> Type {
return getType(E);
Expand Down Expand Up @@ -434,6 +440,7 @@ namespace {
DeclContext *dc;
const Solution &solution;
bool SuppressDiagnostics;
bool IsShallow;

/// Recognize used conformances from an imported type when we must emit
/// the witness table.
Expand Down Expand Up @@ -885,7 +892,8 @@ namespace {
// will handle this.
if (record.OpaqueValue && record.OpaqueValue->hasLValueAccessKind())
cs.propagateLValueAccessKind(record.ExistentialValue,
record.OpaqueValue->getLValueAccessKind());
record.OpaqueValue->getLValueAccessKind(),
IsShallow);

// Form the open-existential expression.
result = new (tc.Context) OpenExistentialExpr(
Expand Down Expand Up @@ -1846,9 +1854,9 @@ namespace {

public:
ExprRewriter(ConstraintSystem &cs, const Solution &solution,
bool suppressDiagnostics)
: cs(cs), dc(cs.DC), solution(solution),
SuppressDiagnostics(suppressDiagnostics) { }
bool suppressDiagnostics, bool shallow = false)
: cs(cs), dc(cs.DC), solution(solution),
SuppressDiagnostics(suppressDiagnostics), IsShallow(shallow) {}

ConstraintSystem &getConstraintSystem() const { return cs; }

Expand Down Expand Up @@ -3095,7 +3103,8 @@ namespace {
// case (when we turn the inout into an UnsafePointer) than to try to
// discover that we're in that case right now.
if (!cs.getType(expr->getSubExpr())->is<UnresolvedType>())
cs.propagateLValueAccessKind(expr->getSubExpr(), AccessKind::ReadWrite);
cs.propagateLValueAccessKind(expr->getSubExpr(), AccessKind::ReadWrite,
IsShallow);
auto objectTy = cs.getType(expr->getSubExpr())->getRValueType();

// The type is simply inout of whatever the lvalue's object type was.
Expand Down Expand Up @@ -3805,7 +3814,8 @@ namespace {
auto destTy = cs.computeAssignDestType(expr->getDest(), expr->getLoc());
if (!destTy)
return nullptr;
cs.propagateLValueAccessKind(expr->getDest(), AccessKind::Write);
cs.propagateLValueAccessKind(expr->getDest(), AccessKind::Write,
IsShallow);

// Convert the source to the simplified destination type.
auto locator =
Expand Down Expand Up @@ -4114,7 +4124,7 @@ namespace {

if (cs.getType(subExpr)->hasLValueType()) {
// Treat this like a read of the property.
cs.propagateLValueAccessKind(subExpr, AccessKind::Read);
cs.propagateLValueAccessKind(subExpr, AccessKind::Read, IsShallow);
}

// Check that we requested a property getter or setter.
Expand Down Expand Up @@ -6341,7 +6351,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,

// Load from the lvalue. If we're loading the result of a force,
// swap the order so that we load first and force the result.
cs.propagateLValueAccessKind(expr, AccessKind::Read);
cs.propagateLValueAccessKind(expr, AccessKind::Read, IsShallow);
if (auto *forceExpr = dyn_cast<ForceValueExpr>(expr)) {
fromType = cs.getType(forceExpr->getSubExpr())->getRValueType();
auto *loadExpr = cs.cacheType(
Expand Down Expand Up @@ -6454,8 +6464,8 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
// Overwrite the l-value access kind to be read-only if we're
// converting to a non-mutable pointer type.
auto *E = cast<InOutExpr>(expr->getValueProvidingExpr())->getSubExpr();
cs.propagateLValueAccessKind(E,
AccessKind::Read, /*overwrite*/ true);
cs.propagateLValueAccessKind(E, AccessKind::Read, IsShallow,
/*overwrite*/ true);
}

tc.requirePointerArgumentIntrinsics(expr->getLoc());
Expand Down Expand Up @@ -6558,7 +6568,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
// In an 'inout' operator like "i += 1", the operand is converted from
// an implicit lvalue to an inout argument.
assert(toIO->getObjectType()->isEqual(fromLValue->getObjectType()));
cs.propagateLValueAccessKind(expr, AccessKind::ReadWrite);
cs.propagateLValueAccessKind(expr, AccessKind::ReadWrite, IsShallow);
return cs.cacheType(new (tc.Context)
InOutExpr(expr->getStartLoc(), expr,
toIO->getObjectType(),
Expand All @@ -6577,7 +6587,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,

if (performLoad) {
// Load from the lvalue.
cs.propagateLValueAccessKind(expr, AccessKind::Read);
cs.propagateLValueAccessKind(expr, AccessKind::Read, IsShallow);
expr = cs.cacheType(new (tc.Context)
LoadExpr(expr, fromLValue->getObjectType()));

Expand Down Expand Up @@ -6834,7 +6844,7 @@ ExprRewriter::coerceObjectArgumentToType(Expr *expr,

// Use InOutExpr to convert it to an explicit inout argument for the
// receiver.
cs.propagateLValueAccessKind(expr, AccessKind::ReadWrite);
cs.propagateLValueAccessKind(expr, AccessKind::ReadWrite, IsShallow);
return cs.cacheType(new (ctx) InOutExpr(expr->getStartLoc(), expr,
toInOutTy->getInOutObjectType(),
/*isImplicit*/ true));
Expand Down Expand Up @@ -8007,7 +8017,7 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
Expr *ConstraintSystem::applySolutionShallow(const Solution &solution,
Expr *expr,
bool suppressDiagnostics) {
ExprRewriter rewriter(*this, solution, suppressDiagnostics);
ExprRewriter rewriter(*this, solution, suppressDiagnostics, true);
rewriter.walkToExprPre(expr);
Expr *result = rewriter.walkToExprPost(expr);
if (result)
Expand Down
3 changes: 1 addition & 2 deletions lib/Sema/ConstraintSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -2031,8 +2031,7 @@ class ConstraintSystem {
/// Call Expr::propagateLValueAccessKind on the given expression,
/// using a custom accessor for the type on the expression that
/// reads the type from the ConstraintSystem expression type map.
void propagateLValueAccessKind(Expr *E,
AccessKind accessKind,
void propagateLValueAccessKind(Expr *E, AccessKind accessKind, bool isShallow,
bool allowOverwrite = false);

/// Call Expr::isTypeReference on the given expression, using a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: %target-typecheck-verify-swift %s

func foo(_ msg: Int) {}
func foo(_ msg: Double) {}

func rdar38309176(_ errors: inout [String]) {
foo("error: \(errors[0])") // expected-error {{cannot invoke 'foo' with an argument list of type '(String)'}}
// expected-note@-1 {{overloads for 'foo' exist with these partially matching parameter lists: (Int), (Double)}}
}